aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatarUnit 193 <unit193@unit193.net>2021-11-10 00:54:13 -0500
committerLibravatarUnit 193 <unit193@unit193.net>2021-11-10 00:54:13 -0500
commitbeb08eb751fa8e1f72042f263316ab5e5ddb596d (patch)
tree3b00df983527648bdae610ac7b88cb639b1f1828
parentfbc30002ab3438356c0476e70c4577a0310d52c0 (diff)
downloadbarrier-beb08eb751fa8e1f72042f263316ab5e5ddb596d.tar.bz2
barrier-beb08eb751fa8e1f72042f263316ab5e5ddb596d.tar.xz
barrier-beb08eb751fa8e1f72042f263316ab5e5ddb596d.tar.zst
New upstream version 2.4.0+dfsg.upstream/2.4.0+dfsgupstream
-rw-r--r--.editorconfig9
-rw-r--r--.github/ISSUE_TEMPLATE.md30
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.yml79
-rw-r--r--.github/ISSUE_TEMPLATE/config.yml1
-rw-r--r--.gitmodules3
-rw-r--r--Build.properties6
-rw-r--r--CMakeLists.txt52
-rw-r--r--LICENSE61
-rw-r--r--README.md45
-rw-r--r--RELEASING.md59
-rw-r--r--_config.yml2
-rw-r--r--azure-pipelines.yml29
-rw-r--r--azure-pipelines/download_install_bonjour_sdk_like.ps13
-rw-r--r--azure-pipelines/download_install_qt.ps15
-rw-r--r--clean_build.bat5
-rwxr-xr-xclean_build.sh6
-rw-r--r--cmake/Version.cmake7
-rw-r--r--cmake/gtest.cmake44
-rw-r--r--doc/QtCodeStyle.xml234
-rw-r--r--doc/barrier.conf.example-advanced6
-rw-r--r--doc/barrier.conf.example-barebones17
-rw-r--r--doc/barrier.conf.example-basic4
-rw-r--r--doc/barrierc.12
-rw-r--r--doc/barriers.12
-rw-r--r--doc/newsfragments/README.md13
-rw-r--r--doc/org.barrier-foss.org.barrierc.plist18
-rw-r--r--doc/org.barrier-foss.org.barriers.plist12
-rw-r--r--doc/release_notes/index.md94
-rw-r--r--doc/release_notes/index.template.jinja37
-rw-r--r--gulrak-filesystem/.appveyor.yml85
-rwxr-xr-xgulrak-filesystem/.ci/unix-build.sh4
-rwxr-xr-xgulrak-filesystem/.ci/unix-test.sh7
-rw-r--r--gulrak-filesystem/.cirrus.yml35
-rw-r--r--gulrak-filesystem/.clang-format25
-rw-r--r--gulrak-filesystem/.clang-tidy3
-rw-r--r--gulrak-filesystem/.drone.yml43
-rw-r--r--gulrak-filesystem/.github/ISSUE_TEMPLATE/bug_report.md17
-rw-r--r--gulrak-filesystem/.github/ISSUE_TEMPLATE/feature_request.md17
-rw-r--r--gulrak-filesystem/.github/workflows/build_cmake.yml197
-rw-r--r--gulrak-filesystem/.gitignore7
-rw-r--r--gulrak-filesystem/CMakeLists.txt74
-rw-r--r--gulrak-filesystem/LICENSE19
-rw-r--r--gulrak-filesystem/README.md1062
-rw-r--r--gulrak-filesystem/cmake/GhcHelper.cmake64
-rw-r--r--gulrak-filesystem/cmake/config.cmake.in6
-rw-r--r--gulrak-filesystem/examples/CMakeLists.txt17
-rw-r--r--gulrak-filesystem/examples/dir.cpp60
-rw-r--r--gulrak-filesystem/examples/du.cpp61
-rw-r--r--gulrak-filesystem/include/ghc/filesystem.hpp6017
-rw-r--r--gulrak-filesystem/include/ghc/fs_fwd.hpp38
-rw-r--r--gulrak-filesystem/include/ghc/fs_impl.hpp35
-rw-r--r--gulrak-filesystem/include/ghc/fs_std.hpp60
-rw-r--r--gulrak-filesystem/include/ghc/fs_std_fwd.hpp63
-rw-r--r--gulrak-filesystem/include/ghc/fs_std_impl.hpp46
-rw-r--r--gulrak-filesystem/test/CMakeLists.txt91
-rw-r--r--gulrak-filesystem/test/catch.hpp13922
-rw-r--r--gulrak-filesystem/test/cmake/ParseAndAddCatchTests.cmake230
-rw-r--r--gulrak-filesystem/test/exception.cpp5
-rw-r--r--gulrak-filesystem/test/filesystem_test.cpp2956
-rw-r--r--gulrak-filesystem/test/fwd_test.cpp7
-rw-r--r--gulrak-filesystem/test/impl_test.cpp8
-rw-r--r--gulrak-filesystem/test/multi1.cpp42
-rw-r--r--gulrak-filesystem/test/multi2.cpp40
-rw-r--r--osx_environment.sh19
-rw-r--r--res/Readme.txt2
-rw-r--r--res/barrier.desktop3
-rw-r--r--res/config.h.in12
-rwxr-xr-xres/makeicon.sh8
-rw-r--r--res/openssl/barrier.conf65
-rw-r--r--snap/snapcraft.yaml2
-rw-r--r--src/CMakeLists.txt12
-rw-r--r--src/cmd/CMakeLists.txt7
-rw-r--r--src/cmd/barrierc/CMakeLists.txt16
-rw-r--r--src/cmd/barrierc/MSWindowsClientTaskBarReceiver.cpp4
-rw-r--r--src/cmd/barrierc/MSWindowsClientTaskBarReceiver.h4
-rw-r--r--src/cmd/barrierc/OSXClientTaskBarReceiver.cpp5
-rw-r--r--src/cmd/barrierc/OSXClientTaskBarReceiver.h4
-rw-r--r--src/cmd/barrierc/XWindowsClientTaskBarReceiver.cpp4
-rw-r--r--src/cmd/barrierc/XWindowsClientTaskBarReceiver.h4
-rw-r--r--src/cmd/barrierc/barrierc.cpp8
-rw-r--r--src/cmd/barrierc/barrierc.exe.manifest2
-rw-r--r--src/cmd/barrierc/barrierc.rc97
-rw-r--r--src/cmd/barrierc/resource.h2
-rw-r--r--src/cmd/barrierd/CMakeLists.txt3
-rw-r--r--src/cmd/barrierd/barrierd.cpp4
-rw-r--r--src/cmd/barrierd/barrierd.icobin0 -> 121502 bytes
-rw-r--r--src/cmd/barrierd/barrierd.rc111
-rw-r--r--src/cmd/barriers/CMakeLists.txt17
-rw-r--r--src/cmd/barriers/MSWindowsServerTaskBarReceiver.cpp4
-rw-r--r--src/cmd/barriers/MSWindowsServerTaskBarReceiver.h4
-rw-r--r--src/cmd/barriers/OSXServerTaskBarReceiver.cpp4
-rw-r--r--src/cmd/barriers/OSXServerTaskBarReceiver.h4
-rw-r--r--src/cmd/barriers/XWindowsServerTaskBarReceiver.cpp4
-rw-r--r--src/cmd/barriers/XWindowsServerTaskBarReceiver.h4
-rw-r--r--src/cmd/barriers/barriers.cpp8
-rw-r--r--src/cmd/barriers/barriers.exe.manifest2
-rw-r--r--src/cmd/barriers/barriers.rc61
-rw-r--r--src/cmd/barriers/resource.h2
-rw-r--r--src/gui/CMakeLists.txt136
-rw-r--r--src/gui/gui.pro162
-rw-r--r--src/gui/gui.ts9
-rw-r--r--src/gui/lang.cmd2
-rwxr-xr-x[-rw-r--r--]src/gui/langbuild.cmd4
-rw-r--r--src/gui/res/lang/Languages.xml92
-rw-r--r--src/gui/res/lang/gui_af-ZA.ts9
-rw-r--r--src/gui/res/lang/gui_ar.ts9
-rw-r--r--src/gui/res/lang/gui_bg-BG.qmbin21889 -> 21854 bytes
-rw-r--r--src/gui/res/lang/gui_bg-BG.ts13
-rw-r--r--src/gui/res/lang/gui_ca-AD.qmbin23086 -> 23050 bytes
-rw-r--r--src/gui/res/lang/gui_ca-AD.ts19
-rw-r--r--src/gui/res/lang/gui_cs-CZ.qmbin22897 -> 22864 bytes
-rw-r--r--src/gui/res/lang/gui_cs-CZ.ts13
-rw-r--r--src/gui/res/lang/gui_cy.qmbin15069 -> 15048 bytes
-rw-r--r--src/gui/res/lang/gui_cy.ts13
-rw-r--r--src/gui/res/lang/gui_da.qmbin22065 -> 22042 bytes
-rw-r--r--src/gui/res/lang/gui_da.ts15
-rw-r--r--src/gui/res/lang/gui_de.qmbin23631 -> 40389 bytes
-rw-r--r--src/gui/res/lang/gui_de.ts589
-rw-r--r--src/gui/res/lang/gui_es.qmbin23609 -> 23570 bytes
-rw-r--r--src/gui/res/lang/gui_es.ts13
-rw-r--r--src/gui/res/lang/gui_et-EE.qmbin21531 -> 21506 bytes
-rw-r--r--src/gui/res/lang/gui_et-EE.ts13
-rw-r--r--src/gui/res/lang/gui_fi.qmbin21785 -> 21750 bytes
-rw-r--r--src/gui/res/lang/gui_fi.ts13
-rw-r--r--src/gui/res/lang/gui_fr.qmbin23635 -> 23610 bytes
-rw-r--r--src/gui/res/lang/gui_fr.ts13
-rw-r--r--src/gui/res/lang/gui_gl.ts9
-rw-r--r--src/gui/res/lang/gui_grk.ts9
-rw-r--r--src/gui/res/lang/gui_he.qmbin13576 -> 13555 bytes
-rw-r--r--src/gui/res/lang/gui_he.ts13
-rw-r--r--src/gui/res/lang/gui_hi.ts9
-rw-r--r--src/gui/res/lang/gui_hr-HR.qmbin20504 -> 20477 bytes
-rw-r--r--src/gui/res/lang/gui_hr-HR.ts13
-rw-r--r--src/gui/res/lang/gui_hu-HU.qmbin18574 -> 18549 bytes
-rw-r--r--src/gui/res/lang/gui_hu-HU.ts13
-rw-r--r--src/gui/res/lang/gui_id.ts9
-rw-r--r--src/gui/res/lang/gui_is-IS.ts9
-rw-r--r--src/gui/res/lang/gui_it.qmbin21856 -> 21827 bytes
-rw-r--r--src/gui/res/lang/gui_it.ts13
-rw-r--r--src/gui/res/lang/gui_ja-JP.qmbin17380 -> 33285 bytes
-rw-r--r--src/gui/res/lang/gui_ja-JP.ts692
-rw-r--r--src/gui/res/lang/gui_ko.qmbin18396 -> 18383 bytes
-rw-r--r--src/gui/res/lang/gui_ko.ts23
-rw-r--r--src/gui/res/lang/gui_lt.ts9
-rw-r--r--src/gui/res/lang/gui_lv.ts9
-rw-r--r--src/gui/res/lang/gui_mr.ts9
-rw-r--r--src/gui/res/lang/gui_nl-NL.qmbin22485 -> 22454 bytes
-rw-r--r--src/gui/res/lang/gui_nl-NL.ts15
-rw-r--r--src/gui/res/lang/gui_no.qmbin21717 -> 21694 bytes
-rw-r--r--src/gui/res/lang/gui_no.ts13
-rw-r--r--src/gui/res/lang/gui_pes-IR.ts9
-rw-r--r--src/gui/res/lang/gui_pl-PL.qmbin22481 -> 22448 bytes
-rw-r--r--src/gui/res/lang/gui_pl-PL.ts17
-rw-r--r--src/gui/res/lang/gui_pt-BR.qmbin22451 -> 22414 bytes
-rw-r--r--src/gui/res/lang/gui_pt-BR.ts13
-rw-r--r--src/gui/res/lang/gui_pt-PT.qmbin21266 -> 21229 bytes
-rw-r--r--src/gui/res/lang/gui_pt-PT.ts13
-rw-r--r--src/gui/res/lang/gui_ro.qmbin19807 -> 19774 bytes
-rw-r--r--src/gui/res/lang/gui_ro.ts13
-rw-r--r--src/gui/res/lang/gui_ru.qmbin22330 -> 22309 bytes
-rw-r--r--src/gui/res/lang/gui_ru.ts17
-rw-r--r--src/gui/res/lang/gui_si.ts9
-rw-r--r--src/gui/res/lang/gui_sk-SK.qmbin1198 -> 39331 bytes
-rw-r--r--src/gui/res/lang/gui_sk-SK.ts586
-rw-r--r--src/gui/res/lang/gui_sl-SI.ts9
-rw-r--r--src/gui/res/lang/gui_sq-AL.qmbin20259 -> 20230 bytes
-rw-r--r--src/gui/res/lang/gui_sq-AL.ts13
-rw-r--r--src/gui/res/lang/gui_sr.ts9
-rw-r--r--src/gui/res/lang/gui_sv.qmbin22157 -> 37805 bytes
-rw-r--r--src/gui/res/lang/gui_sv.ts13
-rw-r--r--src/gui/res/lang/gui_th-TH.ts9
-rw-r--r--src/gui/res/lang/gui_tr-TR.ts13
-rw-r--r--src/gui/res/lang/gui_uk.qmbin22694 -> 22673 bytes
-rw-r--r--src/gui/res/lang/gui_uk.ts13
-rw-r--r--src/gui/res/lang/gui_ur.ts9
-rw-r--r--src/gui/res/lang/gui_vi.ts9
-rw-r--r--src/gui/res/lang/gui_zh-CN.qmbin16198 -> 25228 bytes
-rw-r--r--src/gui/res/lang/gui_zh-CN.ts1352
-rw-r--r--src/gui/res/lang/gui_zh-TW.qmbin16332 -> 16321 bytes
-rw-r--r--src/gui/res/lang/gui_zh-TW.ts13
-rw-r--r--src/gui/res/win/Barrier.rc113
-rw-r--r--src/gui/src/AboutDialog.cpp4
-rw-r--r--src/gui/src/AboutDialog.h5
-rw-r--r--src/gui/src/Action.cpp19
-rw-r--r--src/gui/src/Action.h35
-rw-r--r--src/gui/src/ActionDialog.cpp14
-rw-r--r--src/gui/src/ActionDialog.h4
-rw-r--r--src/gui/src/AppConfig.cpp16
-rw-r--r--src/gui/src/AppConfig.h8
-rw-r--r--src/gui/src/BaseConfig.cpp5
-rw-r--r--src/gui/src/BaseConfig.h4
-rw-r--r--src/gui/src/Fingerprint.cpp148
-rw-r--r--src/gui/src/Fingerprint.h42
-rw-r--r--src/gui/src/FingerprintAcceptDialog.cpp65
-rw-r--r--src/gui/src/FingerprintAcceptDialog.h45
-rw-r--r--src/gui/src/FingerprintAcceptDialog.ui174
-rw-r--r--src/gui/src/Hotkey.cpp36
-rw-r--r--src/gui/src/Hotkey.h27
-rw-r--r--src/gui/src/HotkeyDialog.cpp4
-rw-r--r--src/gui/src/HotkeyDialog.h4
-rw-r--r--src/gui/src/IpcClient.h2
-rw-r--r--src/gui/src/KeySequence.cpp33
-rw-r--r--src/gui/src/KeySequence.h8
-rw-r--r--src/gui/src/KeySequenceWidget.cpp4
-rw-r--r--src/gui/src/KeySequenceWidget.h5
-rw-r--r--src/gui/src/MainWindow.cpp192
-rw-r--r--src/gui/src/MainWindow.h14
-rw-r--r--src/gui/src/MainWindowBase.ui148
-rw-r--r--src/gui/src/NewScreenWidget.cpp7
-rw-r--r--src/gui/src/NewScreenWidget.h5
-rw-r--r--src/gui/src/QBarrierApplication.cpp7
-rw-r--r--src/gui/src/QBarrierApplication.h5
-rw-r--r--src/gui/src/QUtility.cpp3
-rw-r--r--src/gui/src/Screen.cpp7
-rw-r--r--src/gui/src/Screen.h7
-rw-r--r--src/gui/src/ScreenSettingsDialog.cpp5
-rw-r--r--src/gui/src/ScreenSettingsDialog.h5
-rw-r--r--src/gui/src/ScreenSetupModel.cpp14
-rw-r--r--src/gui/src/ScreenSetupModel.h9
-rw-r--r--src/gui/src/ScreenSetupView.cpp83
-rw-r--r--src/gui/src/ScreenSetupView.h9
-rw-r--r--src/gui/src/ServerConfig.cpp18
-rw-r--r--src/gui/src/ServerConfig.h21
-rw-r--r--src/gui/src/ServerConfigDialog.cpp26
-rw-r--r--src/gui/src/ServerConfigDialog.h5
-rw-r--r--src/gui/src/SettingsDialog.cpp8
-rw-r--r--src/gui/src/SettingsDialog.h4
-rw-r--r--src/gui/src/SettingsDialogBase.ui87
-rw-r--r--src/gui/src/SetupWizard.cpp10
-rw-r--r--src/gui/src/SetupWizard.h4
-rw-r--r--src/gui/src/ShutdownCh.h1
-rw-r--r--src/gui/src/SslCertificate.cpp208
-rw-r--r--src/gui/src/SslCertificate.h11
-rw-r--r--src/gui/src/TrashScreenWidget.cpp5
-rw-r--r--src/gui/src/TrashScreenWidget.h5
-rw-r--r--src/gui/src/ZeroconfService.cpp12
-rw-r--r--src/gui/src/main.cpp6
-rw-r--r--src/gui/test/HotkeyTests.cpp320
-rw-r--r--src/gui/test/KeySequenceTests.cpp145
-rw-r--r--src/gui/test/Utils.h38
-rw-r--r--src/gui/test/main.cpp23
-rw-r--r--src/lib/CMakeLists.txt4
-rw-r--r--src/lib/arch/Arch.cpp4
-rw-r--r--src/lib/arch/Arch.h4
-rw-r--r--src/lib/arch/ArchConsoleStd.cpp6
-rw-r--r--src/lib/arch/ArchConsoleStd.h4
-rw-r--r--src/lib/arch/ArchDaemonNone.cpp4
-rw-r--r--src/lib/arch/ArchDaemonNone.h4
-rw-r--r--src/lib/arch/CMakeLists.txt4
-rw-r--r--src/lib/arch/IArchConsole.h4
-rw-r--r--src/lib/arch/IArchDaemon.h8
-rw-r--r--src/lib/arch/IArchLog.h4
-rw-r--r--src/lib/arch/IArchMultithread.h30
-rw-r--r--src/lib/arch/IArchNetwork.h12
-rw-r--r--src/lib/arch/IArchSleep.h4
-rw-r--r--src/lib/arch/IArchString.cpp4
-rw-r--r--src/lib/arch/IArchString.h14
-rw-r--r--src/lib/arch/IArchSystem.h4
-rw-r--r--src/lib/arch/IArchTaskBar.h4
-rw-r--r--src/lib/arch/IArchTaskBarReceiver.h4
-rw-r--r--src/lib/arch/IArchTime.h4
-rw-r--r--src/lib/arch/XArch.h6
-rw-r--r--src/lib/arch/multibyte.h4
-rw-r--r--src/lib/arch/unix/ArchConsoleUnix.cpp4
-rw-r--r--src/lib/arch/unix/ArchConsoleUnix.h4
-rw-r--r--src/lib/arch/unix/ArchDaemonUnix.cpp20
-rw-r--r--src/lib/arch/unix/ArchDaemonUnix.h4
-rw-r--r--src/lib/arch/unix/ArchInternetUnix.cpp8
-rw-r--r--src/lib/arch/unix/ArchLogUnix.cpp4
-rw-r--r--src/lib/arch/unix/ArchLogUnix.h4
-rw-r--r--src/lib/arch/unix/ArchMultithreadPosix.cpp35
-rw-r--r--src/lib/arch/unix/ArchMultithreadPosix.h7
-rw-r--r--src/lib/arch/unix/ArchNetworkBSD.cpp4
-rw-r--r--src/lib/arch/unix/ArchNetworkBSD.h4
-rw-r--r--src/lib/arch/unix/ArchSleepUnix.cpp4
-rw-r--r--src/lib/arch/unix/ArchSleepUnix.h4
-rw-r--r--src/lib/arch/unix/ArchStringUnix.cpp5
-rw-r--r--src/lib/arch/unix/ArchStringUnix.h4
-rw-r--r--src/lib/arch/unix/ArchSystemUnix.cpp4
-rw-r--r--src/lib/arch/unix/ArchSystemUnix.h4
-rw-r--r--src/lib/arch/unix/ArchTaskBarXWindows.cpp4
-rw-r--r--src/lib/arch/unix/ArchTaskBarXWindows.h4
-rw-r--r--src/lib/arch/unix/ArchTimeUnix.cpp4
-rw-r--r--src/lib/arch/unix/ArchTimeUnix.h4
-rw-r--r--src/lib/arch/unix/XArchUnix.cpp4
-rw-r--r--src/lib/arch/unix/XArchUnix.h4
-rw-r--r--src/lib/arch/vsnprintf.h67
-rw-r--r--src/lib/arch/win32/ArchConsoleWindows.cpp4
-rw-r--r--src/lib/arch/win32/ArchConsoleWindows.h4
-rw-r--r--src/lib/arch/win32/ArchDaemonWindows.cpp10
-rw-r--r--src/lib/arch/win32/ArchDaemonWindows.h4
-rw-r--r--src/lib/arch/win32/ArchInternetWindows.cpp8
-rw-r--r--src/lib/arch/win32/ArchLogWindows.cpp4
-rw-r--r--src/lib/arch/win32/ArchLogWindows.h4
-rw-r--r--src/lib/arch/win32/ArchMiscWindows.cpp22
-rw-r--r--src/lib/arch/win32/ArchMiscWindows.h6
-rw-r--r--src/lib/arch/win32/ArchMultithreadWindows.cpp33
-rw-r--r--src/lib/arch/win32/ArchMultithreadWindows.h7
-rw-r--r--src/lib/arch/win32/ArchNetworkWinsock.cpp4
-rw-r--r--src/lib/arch/win32/ArchNetworkWinsock.h4
-rw-r--r--src/lib/arch/win32/ArchSleepWindows.cpp6
-rw-r--r--src/lib/arch/win32/ArchSleepWindows.h4
-rw-r--r--src/lib/arch/win32/ArchStringWindows.cpp9
-rw-r--r--src/lib/arch/win32/ArchStringWindows.h4
-rw-r--r--src/lib/arch/win32/ArchSystemWindows.cpp4
-rw-r--r--src/lib/arch/win32/ArchSystemWindows.h4
-rw-r--r--src/lib/arch/win32/ArchTaskBarWindows.cpp15
-rw-r--r--src/lib/arch/win32/ArchTaskBarWindows.h7
-rw-r--r--src/lib/arch/win32/ArchTimeWindows.cpp4
-rw-r--r--src/lib/arch/win32/ArchTimeWindows.h4
-rw-r--r--src/lib/arch/win32/XArchWindows.cpp80
-rw-r--r--src/lib/arch/win32/XArchWindows.h4
-rw-r--r--src/lib/barrier/App.cpp47
-rw-r--r--src/lib/barrier/App.h24
-rw-r--r--src/lib/barrier/AppUtil.cpp8
-rw-r--r--src/lib/barrier/AppUtil.h8
-rw-r--r--src/lib/barrier/ArgParser.cpp67
-rw-r--r--src/lib/barrier/ArgParser.h20
-rw-r--r--src/lib/barrier/ArgsBase.cpp9
-rw-r--r--src/lib/barrier/ArgsBase.h10
-rw-r--r--src/lib/barrier/BarrierType.h26
-rw-r--r--src/lib/barrier/CMakeLists.txt4
-rw-r--r--src/lib/barrier/Chunk.cpp4
-rw-r--r--src/lib/barrier/Chunk.h6
-rw-r--r--src/lib/barrier/ClientApp.cpp58
-rw-r--r--src/lib/barrier/ClientApp.h7
-rw-r--r--src/lib/barrier/ClientArgs.cpp4
-rw-r--r--src/lib/barrier/ClientArgs.h4
-rw-r--r--src/lib/barrier/ClientTaskBarReceiver.cpp4
-rw-r--r--src/lib/barrier/ClientTaskBarReceiver.h4
-rw-r--r--src/lib/barrier/Clipboard.cpp4
-rw-r--r--src/lib/barrier/Clipboard.h4
-rw-r--r--src/lib/barrier/ClipboardChunk.cpp8
-rw-r--r--src/lib/barrier/ClipboardChunk.h4
-rw-r--r--src/lib/barrier/DragInformation.cpp16
-rw-r--r--src/lib/barrier/DragInformation.h8
-rw-r--r--src/lib/barrier/DropHelper.cpp11
-rw-r--r--src/lib/barrier/DropHelper.h4
-rw-r--r--src/lib/barrier/FileChunk.cpp4
-rw-r--r--src/lib/barrier/FileChunk.h4
-rw-r--r--src/lib/barrier/IApp.h4
-rw-r--r--src/lib/barrier/IAppUtil.h6
-rw-r--r--src/lib/barrier/IClient.h4
-rw-r--r--src/lib/barrier/IClipboard.cpp8
-rw-r--r--src/lib/barrier/IClipboard.h4
-rw-r--r--src/lib/barrier/IKeyState.cpp4
-rw-r--r--src/lib/barrier/IKeyState.h8
-rw-r--r--src/lib/barrier/INode.h6
-rw-r--r--src/lib/barrier/IPlatformScreen.cpp4
-rw-r--r--src/lib/barrier/IPlatformScreen.h7
-rw-r--r--src/lib/barrier/IPrimaryScreen.cpp4
-rw-r--r--src/lib/barrier/IPrimaryScreen.h4
-rw-r--r--src/lib/barrier/IScreen.h6
-rw-r--r--src/lib/barrier/IScreenSaver.h6
-rw-r--r--src/lib/barrier/ISecondaryScreen.h4
-rw-r--r--src/lib/barrier/KeyMap.cpp14
-rw-r--r--src/lib/barrier/KeyMap.h12
-rw-r--r--src/lib/barrier/KeyState.cpp10
-rw-r--r--src/lib/barrier/KeyState.h8
-rw-r--r--src/lib/barrier/PacketStreamFilter.cpp26
-rw-r--r--src/lib/barrier/PacketStreamFilter.h10
-rw-r--r--src/lib/barrier/PlatformScreen.cpp4
-rw-r--r--src/lib/barrier/PlatformScreen.h1
-rw-r--r--src/lib/barrier/PortableTaskBarReceiver.cpp6
-rw-r--r--src/lib/barrier/PortableTaskBarReceiver.h4
-rw-r--r--src/lib/barrier/ProtocolUtil.cpp18
-rw-r--r--src/lib/barrier/ProtocolUtil.h10
-rw-r--r--src/lib/barrier/Screen.cpp12
-rw-r--r--src/lib/barrier/Screen.h14
-rw-r--r--src/lib/barrier/ServerApp.cpp92
-rw-r--r--src/lib/barrier/ServerApp.h8
-rw-r--r--src/lib/barrier/ServerArgs.h1
-rw-r--r--src/lib/barrier/ServerTaskBarReceiver.cpp6
-rw-r--r--src/lib/barrier/ServerTaskBarReceiver.h4
-rw-r--r--src/lib/barrier/StreamChunker.cpp27
-rw-r--r--src/lib/barrier/StreamChunker.h11
-rw-r--r--src/lib/barrier/XBarrier.cpp6
-rw-r--r--src/lib/barrier/XBarrier.h10
-rw-r--r--src/lib/barrier/XScreen.cpp4
-rw-r--r--src/lib/barrier/XScreen.h4
-rw-r--r--src/lib/barrier/clipboard_types.h4
-rw-r--r--src/lib/barrier/key_types.cpp14
-rw-r--r--src/lib/barrier/key_types.h17
-rw-r--r--src/lib/barrier/mouse_types.h4
-rw-r--r--src/lib/barrier/option_types.h4
-rw-r--r--src/lib/barrier/protocol_types.cpp4
-rw-r--r--src/lib/barrier/protocol_types.h16
-rw-r--r--src/lib/barrier/unix/AppUtilUnix.cpp4
-rw-r--r--src/lib/barrier/unix/AppUtilUnix.h6
-rw-r--r--src/lib/barrier/win32/AppUtilWindows.cpp28
-rw-r--r--src/lib/barrier/win32/AppUtilWindows.h6
-rw-r--r--src/lib/barrier/win32/DaemonApp.cpp25
-rw-r--r--src/lib/barrier/win32/DaemonApp.h6
-rw-r--r--src/lib/base/CMakeLists.txt4
-rw-r--r--src/lib/base/ELevel.h4
-rw-r--r--src/lib/base/Event.cpp4
-rw-r--r--src/lib/base/Event.h8
-rw-r--r--src/lib/base/EventQueue.cpp16
-rw-r--r--src/lib/base/EventQueue.h6
-rw-r--r--src/lib/base/EventTypes.cpp5
-rw-r--r--src/lib/base/EventTypes.h44
-rw-r--r--src/lib/base/FunctionEventJob.cpp4
-rw-r--r--src/lib/base/FunctionEventJob.h4
-rw-r--r--src/lib/base/FunctionJob.cpp43
-rw-r--r--src/lib/base/FunctionJob.h39
-rw-r--r--src/lib/base/IEventJob.h4
-rw-r--r--src/lib/base/IEventQueue.h8
-rw-r--r--src/lib/base/IEventQueueBuffer.h6
-rw-r--r--src/lib/base/IJob.h4
-rw-r--r--src/lib/base/ILogOutputter.h4
-rw-r--r--src/lib/base/Log.cpp10
-rw-r--r--src/lib/base/Log.h12
-rw-r--r--src/lib/base/PriorityQueue.h4
-rw-r--r--src/lib/base/SimpleEventQueueBuffer.cpp4
-rw-r--r--src/lib/base/SimpleEventQueueBuffer.h6
-rw-r--r--src/lib/base/Stopwatch.cpp4
-rw-r--r--src/lib/base/Stopwatch.h6
-rw-r--r--src/lib/base/String.cpp78
-rw-r--r--src/lib/base/String.h9
-rw-r--r--src/lib/base/TMethodEventJob.h4
-rw-r--r--src/lib/base/TMethodJob.h68
-rw-r--r--src/lib/base/Unicode.cpp4
-rw-r--r--src/lib/base/Unicode.h4
-rw-r--r--src/lib/base/XBase.cpp4
-rw-r--r--src/lib/base/XBase.h4
-rw-r--r--src/lib/base/finally.h61
-rw-r--r--src/lib/base/log_outputters.cpp11
-rw-r--r--src/lib/base/log_outputters.h4
-rw-r--r--src/lib/client/CMakeLists.txt4
-rw-r--r--src/lib/client/Client.cpp46
-rw-r--r--src/lib/client/Client.h16
-rw-r--r--src/lib/client/ServerProxy.cpp37
-rw-r--r--src/lib/client/ServerProxy.h8
-rw-r--r--src/lib/common/CMakeLists.txt4
-rw-r--r--src/lib/common/DataDirectories.h37
-rw-r--r--src/lib/common/DataDirectories_static.cpp41
-rw-r--r--src/lib/common/IInterface.h4
-rw-r--r--src/lib/common/MacOSXPrecomp.h23
-rw-r--r--src/lib/common/PathUtilities.cpp75
-rw-r--r--src/lib/common/PathUtilities.h31
-rw-r--r--src/lib/common/Version.cpp4
-rw-r--r--src/lib/common/Version.h4
-rw-r--r--src/lib/common/basic_types.h67
-rw-r--r--src/lib/common/common.h24
-rw-r--r--src/lib/common/stdbitset.h4
-rw-r--r--src/lib/common/stddeque.h4
-rw-r--r--src/lib/common/stdfstream.h4
-rw-r--r--src/lib/common/stdistream.h4
-rw-r--r--src/lib/common/stdlist.h4
-rw-r--r--src/lib/common/stdmap.h4
-rw-r--r--src/lib/common/stdostream.h4
-rw-r--r--src/lib/common/stdpost.h4
-rw-r--r--src/lib/common/stdpre.h4
-rw-r--r--src/lib/common/stdset.h4
-rw-r--r--src/lib/common/stdsstream.h4
-rw-r--r--src/lib/common/stdstring.h4
-rw-r--r--src/lib/common/stdvector.h4
-rw-r--r--src/lib/common/unix/DataDirectories.cpp38
-rw-r--r--src/lib/common/win32/DataDirectories.cpp36
-rw-r--r--src/lib/common/win32/encoding_utilities.cpp37
-rw-r--r--src/lib/common/win32/encoding_utilities.h28
-rw-r--r--src/lib/io/CMakeLists.txt4
-rw-r--r--src/lib/io/IStream.h4
-rw-r--r--src/lib/io/StreamBuffer.cpp6
-rw-r--r--src/lib/io/StreamBuffer.h4
-rw-r--r--src/lib/io/StreamFilter.cpp4
-rw-r--r--src/lib/io/StreamFilter.h4
-rw-r--r--src/lib/io/XIO.cpp4
-rw-r--r--src/lib/io/XIO.h4
-rw-r--r--src/lib/io/filesystem.cpp71
-rw-r--r--src/lib/io/filesystem.h41
-rw-r--r--src/lib/ipc/CMakeLists.txt4
-rw-r--r--src/lib/ipc/Ipc.h4
-rw-r--r--src/lib/ipc/IpcClient.cpp4
-rw-r--r--src/lib/ipc/IpcClient.h6
-rw-r--r--src/lib/ipc/IpcClientProxy.cpp8
-rw-r--r--src/lib/ipc/IpcClientProxy.h6
-rw-r--r--src/lib/ipc/IpcLogOutputter.cpp11
-rw-r--r--src/lib/ipc/IpcLogOutputter.h16
-rw-r--r--src/lib/ipc/IpcMessage.cpp4
-rw-r--r--src/lib/ipc/IpcMessage.h4
-rw-r--r--src/lib/ipc/IpcServer.cpp4
-rw-r--r--src/lib/ipc/IpcServer.h8
-rw-r--r--src/lib/ipc/IpcServerProxy.cpp12
-rw-r--r--src/lib/ipc/IpcServerProxy.h4
-rw-r--r--src/lib/mt/CMakeLists.txt4
-rw-r--r--src/lib/mt/CondVar.cpp6
-rw-r--r--src/lib/mt/CondVar.h6
-rw-r--r--src/lib/mt/Lock.cpp4
-rw-r--r--src/lib/mt/Lock.h4
-rw-r--r--src/lib/mt/Mutex.cpp4
-rw-r--r--src/lib/mt/Mutex.h4
-rw-r--r--src/lib/mt/Thread.cpp46
-rw-r--r--src/lib/mt/Thread.h35
-rw-r--r--src/lib/mt/XMT.cpp4
-rw-r--r--src/lib/mt/XMT.h4
-rw-r--r--src/lib/mt/XThread.h14
-rw-r--r--src/lib/net/CMakeLists.txt4
-rw-r--r--src/lib/net/ConnectionSecurityLevel.h27
-rw-r--r--src/lib/net/FingerprintData.cpp52
-rw-r--r--src/lib/net/FingerprintData.h46
-rw-r--r--src/lib/net/FingerprintDatabase.cpp135
-rw-r--r--src/lib/net/FingerprintDatabase.h53
-rw-r--r--src/lib/net/IDataSocket.cpp4
-rw-r--r--src/lib/net/IDataSocket.h4
-rw-r--r--src/lib/net/IListenSocket.h6
-rw-r--r--src/lib/net/ISocket.h4
-rw-r--r--src/lib/net/ISocketFactory.h15
-rw-r--r--src/lib/net/ISocketMultiplexerJob.h4
-rw-r--r--src/lib/net/NetworkAddress.cpp4
-rw-r--r--src/lib/net/NetworkAddress.h6
-rw-r--r--src/lib/net/SecureListenSocket.cpp36
-rw-r--r--src/lib/net/SecureListenSocket.h15
-rw-r--r--src/lib/net/SecureSocket.cpp356
-rw-r--r--src/lib/net/SecureSocket.h62
-rw-r--r--src/lib/net/SecureUtils.cpp312
-rw-r--r--src/lib/net/SecureUtils.h43
-rw-r--r--src/lib/net/SocketMultiplexer.cpp17
-rw-r--r--src/lib/net/SocketMultiplexer.h6
-rw-r--r--src/lib/net/TCPListenSocket.cpp16
-rw-r--r--src/lib/net/TCPListenSocket.h4
-rw-r--r--src/lib/net/TCPSocket.cpp42
-rw-r--r--src/lib/net/TCPSocket.h10
-rw-r--r--src/lib/net/TCPSocketFactory.cpp21
-rw-r--r--src/lib/net/TCPSocketFactory.h15
-rw-r--r--src/lib/net/TSocketMultiplexerMethodJob.h94
-rw-r--r--src/lib/net/XSocket.cpp6
-rw-r--r--src/lib/net/XSocket.h4
-rw-r--r--src/lib/platform/CMakeLists.txt4
-rw-r--r--src/lib/platform/IMSWindowsClipboardFacade.h6
-rw-r--r--src/lib/platform/IOSXKeyResource.cpp6
-rw-r--r--src/lib/platform/IOSXKeyResource.h8
-rw-r--r--src/lib/platform/IXWindowsImpl.h58
-rw-r--r--src/lib/platform/ImmuneKeysReader.cpp2
-rw-r--r--src/lib/platform/ImmuneKeysReader.h4
-rw-r--r--src/lib/platform/MSWindowsClipboard.cpp6
-rw-r--r--src/lib/platform/MSWindowsClipboard.h4
-rw-r--r--src/lib/platform/MSWindowsClipboardAnyTextConverter.cpp4
-rw-r--r--src/lib/platform/MSWindowsClipboardAnyTextConverter.h4
-rw-r--r--src/lib/platform/MSWindowsClipboardBitmapConverter.cpp4
-rw-r--r--src/lib/platform/MSWindowsClipboardBitmapConverter.h4
-rw-r--r--src/lib/platform/MSWindowsClipboardFacade.cpp4
-rw-r--r--src/lib/platform/MSWindowsClipboardFacade.h4
-rw-r--r--src/lib/platform/MSWindowsClipboardHTMLConverter.cpp4
-rw-r--r--src/lib/platform/MSWindowsClipboardHTMLConverter.h4
-rw-r--r--src/lib/platform/MSWindowsClipboardTextConverter.cpp4
-rw-r--r--src/lib/platform/MSWindowsClipboardTextConverter.h4
-rw-r--r--src/lib/platform/MSWindowsClipboardUTF16Converter.cpp4
-rw-r--r--src/lib/platform/MSWindowsClipboardUTF16Converter.h4
-rw-r--r--src/lib/platform/MSWindowsDebugOutputter.cpp4
-rw-r--r--src/lib/platform/MSWindowsDebugOutputter.h6
-rw-r--r--src/lib/platform/MSWindowsDesks.cpp25
-rw-r--r--src/lib/platform/MSWindowsDesks.h13
-rw-r--r--src/lib/platform/MSWindowsDropTarget.cpp10
-rw-r--r--src/lib/platform/MSWindowsDropTarget.h8
-rw-r--r--src/lib/platform/MSWindowsEventQueueBuffer.cpp4
-rw-r--r--src/lib/platform/MSWindowsEventQueueBuffer.h4
-rw-r--r--src/lib/platform/MSWindowsHook.cpp66
-rw-r--r--src/lib/platform/MSWindowsHook.h4
-rw-r--r--src/lib/platform/MSWindowsHookResource.cpp2
-rw-r--r--src/lib/platform/MSWindowsHookResource.h2
-rw-r--r--src/lib/platform/MSWindowsKeyState.cpp105
-rw-r--r--src/lib/platform/MSWindowsKeyState.h6
-rw-r--r--src/lib/platform/MSWindowsScreen.cpp92
-rw-r--r--src/lib/platform/MSWindowsScreen.h19
-rw-r--r--src/lib/platform/MSWindowsScreenSaver.cpp17
-rw-r--r--src/lib/platform/MSWindowsScreenSaver.h8
-rw-r--r--src/lib/platform/MSWindowsSession.cpp14
-rw-r--r--src/lib/platform/MSWindowsSession.h6
-rw-r--r--src/lib/platform/MSWindowsUtil.cpp4
-rw-r--r--src/lib/platform/MSWindowsUtil.h4
-rw-r--r--src/lib/platform/MSWindowsWatchdog.cpp60
-rw-r--r--src/lib/platform/MSWindowsWatchdog.h8
-rw-r--r--src/lib/platform/OSXClipboard.cpp14
-rw-r--r--src/lib/platform/OSXClipboard.h4
-rw-r--r--src/lib/platform/OSXClipboardAnyTextConverter.cpp4
-rw-r--r--src/lib/platform/OSXClipboardAnyTextConverter.h4
-rw-r--r--src/lib/platform/OSXClipboardHTMLConverter.cpp2
-rw-r--r--src/lib/platform/OSXClipboardTextConverter.cpp12
-rw-r--r--src/lib/platform/OSXClipboardTextConverter.h4
-rw-r--r--src/lib/platform/OSXClipboardUTF16Converter.cpp4
-rw-r--r--src/lib/platform/OSXClipboardUTF16Converter.h4
-rw-r--r--src/lib/platform/OSXDragSimulator.h2
-rw-r--r--src/lib/platform/OSXDragSimulator.mm (renamed from src/lib/platform/OSXDragSimulator.m)24
-rw-r--r--src/lib/platform/OSXDragView.mm (renamed from src/lib/platform/OSXDragView.m)0
-rw-r--r--src/lib/platform/OSXEventQueueBuffer.cpp18
-rw-r--r--src/lib/platform/OSXEventQueueBuffer.h4
-rw-r--r--src/lib/platform/OSXKeyState.cpp74
-rw-r--r--src/lib/platform/OSXKeyState.h8
-rw-r--r--src/lib/platform/OSXMediaKeySimulator.mm (renamed from src/lib/platform/OSXMediaKeySimulator.m)4
-rw-r--r--src/lib/platform/OSXMediaKeySupport.mm (renamed from src/lib/platform/OSXMediaKeySupport.m)4
-rw-r--r--src/lib/platform/OSXPasteboardPeeker.h2
-rw-r--r--src/lib/platform/OSXPasteboardPeeker.mm (renamed from src/lib/platform/OSXPasteboardPeeker.m)0
-rw-r--r--src/lib/platform/OSXScreen.h48
-rw-r--r--src/lib/platform/OSXScreen.mm218
-rw-r--r--src/lib/platform/OSXScreenSaver.cpp14
-rw-r--r--src/lib/platform/OSXScreenSaver.h8
-rw-r--r--src/lib/platform/OSXScreenSaverControl.h2
-rw-r--r--src/lib/platform/OSXScreenSaverUtil.h4
-rw-r--r--src/lib/platform/OSXScreenSaverUtil.mm (renamed from src/lib/platform/OSXScreenSaverUtil.m)0
-rw-r--r--src/lib/platform/OSXUchrKeyResource.cpp4
-rw-r--r--src/lib/platform/OSXUchrKeyResource.h12
-rw-r--r--src/lib/platform/XWindowsClipboard.cpp8
-rw-r--r--src/lib/platform/XWindowsClipboard.h10
-rw-r--r--src/lib/platform/XWindowsClipboardAnyBitmapConverter.cpp4
-rw-r--r--src/lib/platform/XWindowsClipboardAnyBitmapConverter.h4
-rw-r--r--src/lib/platform/XWindowsClipboardBMPConverter.cpp4
-rw-r--r--src/lib/platform/XWindowsClipboardBMPConverter.h4
-rw-r--r--src/lib/platform/XWindowsClipboardHTMLConverter.cpp4
-rw-r--r--src/lib/platform/XWindowsClipboardHTMLConverter.h4
-rw-r--r--src/lib/platform/XWindowsClipboardTextConverter.cpp4
-rw-r--r--src/lib/platform/XWindowsClipboardTextConverter.h4
-rw-r--r--src/lib/platform/XWindowsClipboardUCS2Converter.cpp4
-rw-r--r--src/lib/platform/XWindowsClipboardUCS2Converter.h4
-rw-r--r--src/lib/platform/XWindowsClipboardUTF8Converter.cpp4
-rw-r--r--src/lib/platform/XWindowsClipboardUTF8Converter.h4
-rw-r--r--src/lib/platform/XWindowsEventQueueBuffer.cpp8
-rw-r--r--src/lib/platform/XWindowsEventQueueBuffer.h10
-rw-r--r--src/lib/platform/XWindowsKeyState.cpp20
-rw-r--r--src/lib/platform/XWindowsKeyState.h24
-rw-r--r--src/lib/platform/XWindowsScreen.cpp12
-rw-r--r--src/lib/platform/XWindowsScreen.h10
-rw-r--r--src/lib/platform/XWindowsScreenSaver.cpp28
-rw-r--r--src/lib/platform/XWindowsScreenSaver.h12
-rw-r--r--src/lib/platform/XWindowsUtil.cpp49
-rw-r--r--src/lib/platform/XWindowsUtil.h12
-rw-r--r--src/lib/platform/synwinhk.h4
-rw-r--r--src/lib/server/BaseClientProxy.cpp4
-rw-r--r--src/lib/server/BaseClientProxy.h4
-rw-r--r--src/lib/server/CMakeLists.txt4
-rw-r--r--src/lib/server/ClientListener.cpp37
-rw-r--r--src/lib/server/ClientListener.h13
-rw-r--r--src/lib/server/ClientProxy.cpp4
-rw-r--r--src/lib/server/ClientProxy.h4
-rw-r--r--src/lib/server/ClientProxy1_0.cpp27
-rw-r--r--src/lib/server/ClientProxy1_0.h4
-rw-r--r--src/lib/server/ClientProxy1_1.cpp4
-rw-r--r--src/lib/server/ClientProxy1_1.h4
-rw-r--r--src/lib/server/ClientProxy1_2.cpp4
-rw-r--r--src/lib/server/ClientProxy1_2.h4
-rw-r--r--src/lib/server/ClientProxy1_3.cpp4
-rw-r--r--src/lib/server/ClientProxy1_3.h4
-rw-r--r--src/lib/server/ClientProxy1_4.cpp4
-rw-r--r--src/lib/server/ClientProxy1_4.h4
-rw-r--r--src/lib/server/ClientProxy1_5.cpp8
-rw-r--r--src/lib/server/ClientProxy1_5.h4
-rw-r--r--src/lib/server/ClientProxy1_6.cpp6
-rw-r--r--src/lib/server/ClientProxy1_6.h4
-rw-r--r--src/lib/server/ClientProxyUnknown.cpp10
-rw-r--r--src/lib/server/ClientProxyUnknown.h4
-rw-r--r--src/lib/server/Config.cpp38
-rw-r--r--src/lib/server/Config.h6
-rw-r--r--src/lib/server/InputFilter.cpp16
-rw-r--r--src/lib/server/InputFilter.h18
-rw-r--r--src/lib/server/PrimaryClient.cpp4
-rw-r--r--src/lib/server/PrimaryClient.h10
-rw-r--r--src/lib/server/Server.cpp32
-rw-r--r--src/lib/server/Server.h26
-rw-r--r--src/test/CMakeLists.txt33
-rw-r--r--src/test/global/TestEventQueue.cpp6
-rw-r--r--src/test/global/TestEventQueue.h4
-rw-r--r--src/test/global/TestUtils.cpp37
-rw-r--r--src/test/global/TestUtils.h30
-rw-r--r--src/test/global/gmock.h4
-rw-r--r--src/test/global/gtest.h4
-rw-r--r--src/test/guitests/src/VersionCheckerTests.cpp4
-rw-r--r--src/test/guitests/src/VersionCheckerTests.h4
-rw-r--r--src/test/guitests/src/main.cpp4
-rw-r--r--src/test/integtests/CMakeLists.txt8
-rw-r--r--src/test/integtests/Main.cpp12
-rw-r--r--src/test/integtests/ipc/IpcTests.cpp21
-rw-r--r--src/test/integtests/net/NetworkTests.cpp79
-rw-r--r--src/test/integtests/platform/MSWindowsClipboardTests.cpp6
-rw-r--r--src/test/integtests/platform/MSWindowsKeyStateTests.cpp16
-rw-r--r--src/test/integtests/platform/OSXClipboardTests.cpp56
-rw-r--r--src/test/integtests/platform/OSXScreenTests.cpp4
-rw-r--r--src/test/integtests/platform/XWindowsClipboardTests.cpp44
-rw-r--r--src/test/integtests/platform/XWindowsKeyStateTests.cpp2
-rw-r--r--src/test/integtests/platform/XWindowsScreenSaverTests.cpp8
-rw-r--r--src/test/integtests/platform/XWindowsScreenTests.cpp8
-rw-r--r--src/test/mock/barrier/MockApp.h2
-rw-r--r--src/test/mock/barrier/MockArgParser.h2
-rw-r--r--src/test/mock/barrier/MockEventQueue.h4
-rw-r--r--src/test/mock/barrier/MockKeyState.h4
-rw-r--r--src/test/mock/barrier/MockScreen.h2
-rw-r--r--src/test/mock/ipc/MockIpcServer.h2
-rw-r--r--src/test/mock/server/MockConfig.h2
-rw-r--r--src/test/mock/server/MockInputFilter.h2
-rw-r--r--src/test/mock/server/MockPrimaryClient.h2
-rw-r--r--src/test/mock/server/MockServer.h2
-rw-r--r--src/test/unittests/CMakeLists.txt8
-rw-r--r--src/test/unittests/Main.cpp8
-rw-r--r--src/test/unittests/barrier/ArgParserTests.cpp4
-rw-r--r--src/test/unittests/barrier/ClientArgsParsingTests.cpp4
-rw-r--r--src/test/unittests/barrier/ClipboardChunkTests.cpp4
-rw-r--r--src/test/unittests/barrier/ClipboardTests.cpp16
-rw-r--r--src/test/unittests/barrier/GenericArgsParsingTests.cpp36
-rw-r--r--src/test/unittests/barrier/KeyMapTests.cpp42
-rw-r--r--src/test/unittests/barrier/KeyStateTests.cpp12
-rw-r--r--src/test/unittests/base/StringTests.cpp36
-rw-r--r--src/test/unittests/ipc/IpcLogOutputterTests.cpp20
-rw-r--r--src/test/unittests/net/FingerprintDatabaseTests.cpp95
-rw-r--r--src/test/unittests/net/SecureUtilsTests.cpp73
-rw-r--r--src/test/unittests/platform/OSXKeyStateTests.cpp12
-rw-r--r--towncrier.toml39
705 files changed, 34015 insertions, 6181 deletions
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..d741e40
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,9 @@
+root = true
+
+[*]
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+indent_style = space
+indent_size = 4
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
deleted file mode 100644
index 1411b05..0000000
--- a/.github/ISSUE_TEMPLATE.md
+++ /dev/null
@@ -1,30 +0,0 @@
-### Operating Systems ###
-
-Server: microOS Tiara
-
-Client: Applesoft Windy OS 10
-
-**READ ME, DELETE ME**: On Windows, hold the Windows key and press 'r', type 'winver' and hit return to get your OS version. On Mac, hit the Apple menu (top left of the screen) and check 'About this Mac'. Linux users... you know what you're using ;)
-
-### Barrier Version ###
-
-1.9.π
-
-**READ ME, DELETE ME**: Go to the 'Help' (on Windows) or 'Barrier' (on macOS) menu and then 'About Barrier' to check your version. Verify that you are using the same version across all of your machines, and that your issue still occurs with the latest release available at https://github.com/debauchee/barrier/
-
-### Steps to reproduce bug ###
-
-**READ ME, DELETE ME**: Try to be succinct. If your bug is intermittent, try and describe what you're doing when it happens most.
-
-1. Click things.
-2. Type things.
-3. Bug occurs.
-4. ...
-
-### Other info ###
-
-* When did the problem start to occur? When I...
-* Is there a way to work around it? No/Yes, you can...
-* Does this bug prevent you from using Barrier entirely? Yes/No
-
-Put anything else you can think of here.
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
new file mode 100644
index 0000000..208e705
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -0,0 +1,79 @@
+name: Bug Report
+description: File a bug report (for questions, ideas & support, use the Discussions tab, or IRC for quick answers, but make sure to stay on the channel!)
+labels: [bug, triage]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ Thanks for taking the time to fill out this bug report!
+ - type: textarea
+ id: what-happened
+ attributes:
+ label: What happened?
+ description: Also tell us, what did you expect to happen?
+ placeholder: Tell us what you see! Screenshots are also helpful - please attach to the issue (when created), rather than linking to image hosting sites.
+ validations:
+ required: true
+ - type: dropdown
+ id: version
+ attributes:
+ label: Version
+ description: What version of Barrier are you running?
+ options:
+ - v2.0.0-RC1
+ - v2.0.0-RC2
+ - v2.0.0
+ - v2.1.1
+ - v2.1.2
+ - v2.3.0
+ - v2.3.1
+ - v2.3.2-alpha
+ - v2.3.2
+ - v2.3.3
+ - From Git HEAD or commit (specify below)
+ validations:
+ required: true
+ - type: input
+ id: git-commit-if
+ attributes:
+ label: Git commit hash (if applicable)
+ description: "When building Barrier from Git, what commit hash did you checkout from?"
+ placeholder: b0c0b42b
+ validations:
+ required: false
+ - type: textarea
+ id: pkg-mgr-origin
+ attributes:
+ label: If applicable, where did you install Barrier from?
+ description: This includes Snaps, Flatpaks, and self-built executables.
+ validations:
+ required: false
+ - type: dropdown
+ id: os
+ attributes:
+ label: What OSes are you seeing the problem on? (Check all that apply)
+ multiple: true
+ options:
+ - Linux
+ - Windows
+ - macOS
+ validations:
+ required: true
+ - type: textarea
+ id: os-version
+ attributes:
+ label: What OS versions are you using?
+ description: This applies to both client(s) and the server.
+ validations:
+ required: true
+ - type: textarea
+ id: logs
+ attributes:
+ label: Relevant log output
+ description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
+ render: shell
+ - type: textarea
+ id: misc-info
+ attributes:
+ label: Any other information
+ description: Please enter any other information we should know, if applicable.
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000..3ba13e0
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1 @@
+blank_issues_enabled: false
diff --git a/.gitmodules b/.gitmodules
index ad9a302..9a58a7e 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -4,3 +4,6 @@
[submodule "ext/gmock"]
path = ext/gmock
url = https://github.com/google/googlemock.git
+[submodule "ext/gulrak-filesystem"]
+ path = ext/gulrak-filesystem
+ url = https://github.com/gulrak/filesystem
diff --git a/Build.properties b/Build.properties
index 437beb7..07192e0 100644
--- a/Build.properties
+++ b/Build.properties
@@ -2,6 +2,6 @@
# Barrier build parameters
#
BARRIER_VERSION_MAJOR = 2
-BARRIER_VERSION_MINOR = 3
-BARRIER_VERSION_PATCH = 2
-BARRIER_VERSION_STAGE = snapshot
+BARRIER_VERSION_MINOR = 4
+BARRIER_VERSION_PATCH = 0
+BARRIER_VERSION_STAGE = release
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6a377c0..86deb4b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -20,6 +20,8 @@ project (barrier C CXX)
option (BARRIER_BUILD_GUI "Build the GUI" ON)
option (BARRIER_BUILD_INSTALLER "Build the installer" ON)
+option (BARRIER_BUILD_TESTS "Build the tests" ON)
+option (BARRIER_USE_EXTERNAL_GTEST "Use external installation of Google Test framework" OFF)
set (CMAKE_EXPORT_COMPILE_COMMANDS ON)
set (CMAKE_CXX_STANDARD 14)
@@ -49,7 +51,6 @@ else()
endif()
set (libs)
-include_directories (BEFORE SYSTEM ./ext/gtest/include)
if (UNIX)
if (NOT APPLE)
@@ -90,7 +91,6 @@ if (UNIX)
check_function_exists (poll HAVE_POLL)
check_function_exists (sigwait HAVE_POSIX_SIGWAIT)
check_function_exists (strftime HAVE_STRFTIME)
- check_function_exists (vsnprintf HAVE_VSNPRINTF)
check_function_exists (inet_aton HAVE_INET_ATON)
# For some reason, the check_function_exists macro doesn't detect
@@ -165,10 +165,10 @@ if (UNIX)
link_directories("/usr/local/lib")
endif()
- if (${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
- set (CMAKE_REQUIRED_INCLUDES "${CMAKE_REQUIRED_INCLUDES};/usr/X11R6/include;/usr/local/include;/usr/local/include/avahi-compat-libdns_sd")
+ if (${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
+ set (CMAKE_REQUIRED_INCLUDES "${CMAKE_REQUIRED_INCLUDES};/usr/X11R6/include;/usr/local/include;/usr/local/include/avahi-compat-libdns_sd")
set (CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -L/usr/local/lib -L/usr/X11R6/lib")
- include_directories("/usr/local/include" "/usr/X11R6/include" "/usr/local/include/avahi-compat-libdns_sd")
+ include_directories("/usr/local/include" "/usr/X11R6/include" "/usr/local/include/avahi-compat-libdns_sd")
link_directories("/usr/local/lib")
link_directories("/usr/X11R6/lib")
endif()
@@ -194,9 +194,8 @@ if (UNIX)
check_include_files ("X11/extensions/XInput2.h" HAVE_XI2)
check_include_files ("dns_sd.h" HAVE_DNSSD)
- if (HAVE_X11_EXTENSIONS_DPMS_H)
- # Assume that function prototypes declared, when include exists.
- set (HAVE_DPMS_PROTOTYPES 1)
+ if (NOT HAVE_X11_EXTENSIONS_XTEST_H)
+ message (FATAL_ERROR "Missing header: X11/extensions/XTest.h")
endif()
if (NOT HAVE_X11_XKBLIB_H)
@@ -292,6 +291,9 @@ elseif (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
list (APPEND libs Wtsapi32 Userenv Wininet comsuppw Shlwapi)
add_definitions (
+ /DSYSAPI_WIN32=1
+ /DWINAPI_MSWINDOWS=1
+ /D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING=1 # tr1 is used from gtest and gmock
/DWIN32
/D_WINDOWS
/D_CRT_SECURE_NO_WARNINGS
@@ -300,6 +302,8 @@ elseif (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
)
endif()
+include_directories("${CMAKE_SOURCE_DIR}/ext/gulrak-filesystem/include")
+
#
# OpenSSL
#
@@ -317,10 +321,21 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
${OPENSSL_ROOT}/lib/ssleay32.lib
)
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+ find_program(APT_PROGRAM "apt")
find_program(BREW_PROGRAM "brew")
find_program(PORT_PROGRAM "port")
-
- if (IS_DIRECTORY /opt/local AND PORT_PROGRAM)
+
+ if (IS_DIRECTORY /opt/procursus AND APT_PROGRAM)
+ # procursus/apt
+ set (OPENSSL_ROOT /opt/procursus)
+
+ include_directories (BEFORE SYSTEM ${OPENSSL_ROOT}/include)
+
+ set (OPENSSL_LIBS
+ ${OPENSSL_ROOT}/lib/libssl.a
+ ${OPENSSL_ROOT}/lib/libcrypto.a
+ )
+ elseif (IS_DIRECTORY /opt/local AND PORT_PROGRAM)
# macports
set (OPENSSL_ROOT /opt/local)
@@ -339,6 +354,16 @@ elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
${OPENSSL_ROOT}/lib/libssl.a
${OPENSSL_ROOT}/lib/libcrypto.a
)
+ elseif (IS_DIRECTORY /opt/homebrew/opt/openssl AND BREW_PROGRAM)
+ # brew
+ set (OPENSSL_ROOT /opt/homebrew/opt/openssl)
+
+ include_directories (BEFORE SYSTEM ${OPENSSL_ROOT}/include)
+
+ set (OPENSSL_LIBS
+ ${OPENSSL_ROOT}/lib/libssl.a
+ ${OPENSSL_ROOT}/lib/libcrypto.a
+ )
endif()
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
@@ -369,7 +394,7 @@ macro (configure_files srcDir destDir)
set (sourceFilePath ${srcDir}/${sourceFile})
if (IS_DIRECTORY ${sourceFilePath})
message (STATUS "Copying directory ${sourceFile}")
- make_directory (${destDir/${sourceFile})
+ make_directory (${destDir}/${sourceFile})
else()
message (STATUS "Copying file ${sourceFile}")
configure_file (${sourceFilePath} ${destDir}/${sourceFile} COPYONLY)
@@ -420,7 +445,7 @@ endif()
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
configure_files (${CMAKE_CURRENT_SOURCE_DIR}/dist/rpm ${CMAKE_BINARY_DIR}/rpm)
install(FILES res/barrier.svg DESTINATION share/icons/hicolor/scalable/apps)
- if("${VERSION_MAJOR}" STREQUAL "2")
+ if("${VERSION_MAJOR}" STREQUAL "2")
install(FILES res/barrier2.desktop DESTINATION share/applications)
else()
install(FILES res/barrier.desktop DESTINATION share/applications)
@@ -430,4 +455,7 @@ endif()
else()
message (STATUS "NOT configuring the installer")
endif()
+
+enable_testing()
+
add_subdirectory (src)
diff --git a/LICENSE b/LICENSE
index acfef1b..42498a4 100644
--- a/LICENSE
+++ b/LICENSE
@@ -3,7 +3,7 @@ Copyright (C) 2012-2016 Symless Ltd.
Copyright (C) 2008-2014 Nick Bolton
Copyright (C) 2002-2014 Chris Schoeneman
-This program is released under the GPL with the additional exemption
+This program is released under the GPL with the additional exemption
that compiling, linking, and/or using OpenSSL is allowed.
GNU GENERAL PUBLIC LICENSE
@@ -286,3 +286,62 @@ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/README.md b/README.md
index 7f380b1..3c545e9 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# Barrier
-Eliminate the barrier between your machines.
+Eliminate the barrier between your machines.
Find [releases for windows and macOS here](https://github.com/debauchee/barrier/releases).
Your distro probably already has barrier packaged for it, see [distro specific packages](#distro-specific-packages)
below for a list. Alternatively, we also provide a [flatpak](https://github.com/flathub/com.github.debauchee.barrier)
@@ -8,7 +8,7 @@ and a [snap](https://snapcraft.io/barrier).
### Contact info:
-- `#barrier` on freenode
+- `#barrier` on LiberaChat IRC network
#### CI Build Status
@@ -30,9 +30,14 @@ Barrier is software that mimics the functionality of a KVM switch, which histori
Barrier was forked from Symless's Synergy 1.9 codebase. Synergy was a commercialized reimplementation of the original CosmoSynergy written by Chris Schoeneman.
+At the moment, barrier is not compatible with synergy. Barrier needs to be installed on all machines that will share keyboard and mouse.
+
### What's different?
-Whereas Synergy has moved beyond its goals from the 1.x era, Barrier aims to maintain that simplicity. Barrier will let you use your keyboard and mouse from machine A to control machine B (or more). It's that simple.
+Whereas Synergy has moved beyond its goals from the 1.x era, Barrier aims to maintain that simplicity.
+Barrier will let you use your keyboard and mouse from one computer to control one or more other computers.
+Clipboard sharing is supported.
+That's it.
### Project goals
@@ -42,15 +47,33 @@ Compatibility. We use more than one operating system and you probably do, too. W
Communication. Everything we do is in the open. Our issue tracker will let you see if others are having the same problem you're having and will allow you to add additional information. You will also be able to see when progress is made and how the issue gets resolved.
+### Usage
+
+Install and run barrier on each machine that will be sharing.
+On the machine with the keyboard and mouse, make it the server.
+
+Click the "Configure server" button and drag a new screen onto the grid for each client machine.
+Ensure the "screen name" matches exactly (case-sensitive) for each configured screen -- the clients' barrier windows will tell you their screen names (just above the server IP).
+
+On the client(s), put in the server machine's IP address (or use Bonjour/auto configuration when prompted) and "start" them.
+You should see `Barrier is running` on both server and clients.
+You should now be able to move the mouse between all the screens as if they were the same machine.
+
+Note that if the keyboard's Scroll Lock is active then this will prevent the mouse from switching screens.
+
### Contact & support
Please be aware that the *only* way to draw our attention to a bug is to create a new issue in [the issue tracker](https://github.com/debauchee/barrier/issues). Write a clear, concise, detailed report and you will get a clear, concise, detailed response. Priority is always given to issues that affect a wider range of users.
-For short and simple questions or to just say hello find us on the Freenode IRC network in the #barrier channel.
+For short and simple questions or to just say hello find us on the LiberaChat IRC network in the #barrier channel.
### Contributions
-At this time we are looking for developers to help fix the issues found in the issue tracker. Submit pull requests once you've polished up your patch and we'll review and possibly merge it.
+At this time we are looking for developers to help fix the issues found in the issue tracker.
+Submit pull requests once you've polished up your patch and we'll review and possibly merge it.
+
+Most pull requests will need to include a release note.
+See docs/newsfragments/README.md for documentation of how to do that.
## Distro specific packages
@@ -77,3 +100,15 @@ A:
Q: Are 32-bit versions of Windows supported?
A: No
+
+Q: How do I load my configuration on startup?
+
+A: Start the binary with the argument `--config <path_to_saved_configuration>`
+
+Q: After loading my configuration on the client the field 'Server IP' is still empty!
+
+A: Edit your configuration to include the server's ip address manually with
+
+ (...)
+ section: options
+ serverhostname=<AAA.BBB.CCC.DDD>
diff --git a/RELEASING.md b/RELEASING.md
new file mode 100644
index 0000000..741f54a
--- /dev/null
+++ b/RELEASING.md
@@ -0,0 +1,59 @@
+Creating a release
+==================
+
+This document is documentation intednded for maintainers of Barrier.
+It documents the release process of Barrier.
+
+Step 1: Setup environment variables
+-----------------------------------
+
+Setup the following environment variable that will be used throughout the rest of the steps.
+
+ export VERSION=X.Y.Z
+
+Step 2: Release notes PR
+------------------------
+
+Open a new branch (e.g. `release`) and run the following:
+
+ towncrier --version ${VERSION} --date `date -u +%F`
+
+This collects the release notes using the `towncrier` tool. Please commit the collected release
+notes afterwards.
+
+Certain file names are not properly supported by the `towncrier` tool and it ignores them.
+Check `newsfragments` directory for any forgotten release notes
+
+Step 3: Merge the release notes PR
+----------------------------------
+
+Step 4: Push git tag
+--------------------
+
+Pull the merge commit created on the `master` branch during the step 2.
+
+Create a tag:
+
+ git tag -s v${VERSION} -m v${VERSION}
+
+Push the tag:
+
+ git push origin master --tags
+
+
+Step 5: Draft a new release on Github
+-------------------------------------
+
+Go to https://github.com/buildbot/buildbot/releases and draft a new release.
+
+Use git tag as the title of the release: `vX.Y.Z`.
+
+Use the release notes generated by the `towncrier` tool as the description of the releases.
+
+Upload the artifacts created by Azure pipelines as the binaries of the release. The following
+artifacts should be uploaded to Github:
+
+ - the Barrier-X.Y.Z-release.dmg created by the oldest Mac OS task (artifact name is
+ "Mac Release Disk Image and App XYZ").
+
+ - the BarrierSetup-X.Y.Z-release.exe (artifact name is Windows Release Installer).
diff --git a/_config.yml b/_config.yml
index c741881..f980e76 100644
--- a/_config.yml
+++ b/_config.yml
@@ -1 +1 @@
-theme: jekyll-theme-slate \ No newline at end of file
+theme: jekyll-theme-slate
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index e12cdd6..e34a3bc 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -63,9 +63,15 @@ jobs:
artifactName: Windows Release Installer
- job: LinuxBuild
+ strategy:
+ matrix:
+ ubuntu-18.04:
+ imageName: 'ubuntu-18.04'
+ ubuntu-20.04:
+ imageName: 'ubuntu-20.04'
displayName: Linux Build
pool:
- vmImage: 'ubuntu-16.04'
+ vmImage: $(imageName)
steps:
- script: sudo apt-get update -y
- script: sudo apt-get install -y libxtst-dev qtdeclarative5-dev libavahi-compat-libdnssd-dev libcurl4-openssl-dev
@@ -75,13 +81,22 @@ jobs:
- job: MacBuild
displayName: Mac Build
- pool:
- vmImage: 'macOS-10.14'
strategy:
matrix:
- Release:
- B_BUILD_TYPE: Release
- BARRIER_VERSION_STAGE: Release
+ big-sur-Release:
+ imageName: "macOS-11"
+ B_BUILD_TYPE: Release
+ BARRIER_VERSION_STAGE: Release
+ catalina-Release:
+ imageName: "macOS-10.15"
+ B_BUILD_TYPE: Release
+ BARRIER_VERSION_STAGE: Release
+ mojave-Release:
+ imageName: "macOS-10.14"
+ B_BUILD_TYPE: Release
+ BARRIER_VERSION_STAGE: Release
+ pool:
+ vmImage: $(imageName)
variables:
VERBOSE: 1
TERM: xterm-256color
@@ -99,4 +114,4 @@ jobs:
condition: eq(variables['B_BUILD_TYPE'], 'Release')
inputs:
pathtoPublish: build/bundle
- artifactName: Mac Release Disk Image and App
+ artifactName: Mac Release Disk Image and App $(imageName)
diff --git a/azure-pipelines/download_install_bonjour_sdk_like.ps1 b/azure-pipelines/download_install_bonjour_sdk_like.ps1
index 97bfa83..7f5fcb9 100644
--- a/azure-pipelines/download_install_bonjour_sdk_like.ps1
+++ b/azure-pipelines/download_install_bonjour_sdk_like.ps1
@@ -1,8 +1,7 @@
$ErrorActionPreference = "Stop"
New-Item -Force -ItemType Directory -Path ".\deps\"
-$Wc = New-Object System.Net.WebClient
-$Wc.DownloadFile('https://github.com/nelsonjchen/mDNSResponder/releases/download/v2019.05.08.1/x64_RelWithDebInfo.zip', 'deps\BonjourSDKLike.zip') ;
+Invoke-WebRequest 'https://github.com/nelsonjchen/mDNSResponder/releases/download/v2019.05.08.1/x64_RelWithDebInfo.zip' -OutFile 'deps\BonjourSDKLike.zip' ;
Write-Output 'Downloaded BonjourSDKLike Zip'
Write-Output 'Unzipping BonjourSDKLike Zip'
Remove-Item -Recurse -Force -ErrorAction Ignore .\deps\BonjourSDKLike
diff --git a/azure-pipelines/download_install_qt.ps1 b/azure-pipelines/download_install_qt.ps1
index c2c2322..a4b51d2 100644
--- a/azure-pipelines/download_install_qt.ps1
+++ b/azure-pipelines/download_install_qt.ps1
@@ -6,8 +6,7 @@ $qt_version = '5.13.0'
New-Item -Force -ItemType Directory -Path ".\deps\"
Write-Output 'Downloading QLI Installer'
-$Wc = New-Object System.Net.WebClient
-$Wc.DownloadFile("https://github.com/nelsonjchen/qli-installer/archive/v$qli_install_version.zip", '.\deps\qli-installer.zip') ;
+Invoke-WebRequest "https://github.com/nelsonjchen/qli-installer/archive/v$qli_install_version.zip" -OutFile '.\deps\qli-installer.zip' ;
Write-Output 'Downloaded QLI Installer'
Write-Output 'Extracting QLI Installer'
@@ -21,6 +20,6 @@ Write-Output 'Installed QLI Installer Dependencies'
Write-Output 'Starting QT Installer'
$Env:QLI_OUT_DIR = ".\deps\Qt\Qt$qt_version"
-$Env:QLI_BASE_URL = "http://mirrors.ocf.berkeley.edu/qt/online/qtsdkrepository/"
+$Env:QLI_BASE_URL = "https://download.qt.io/online/qtsdkrepository/"
python .\deps\qli-installer\qli-installer.py $qt_version windows desktop win64_msvc2017_64
Write-Output 'Installed QT Installer'
diff --git a/clean_build.bat b/clean_build.bat
index 4416a7e..6f04232 100644
--- a/clean_build.bat
+++ b/clean_build.bat
@@ -41,8 +41,7 @@ if ERRORLEVEL 1 goto failed
cd build
cmake -G "%cmake_gen%" -A x64 -D CMAKE_BUILD_TYPE=%B_BUILD_TYPE% -D CMAKE_PREFIX_PATH="%B_QT_FULLPATH%" -D DNSSD_LIB="%B_BONJOUR%\Lib\x64\dnssd.lib" -D QT_VERSION=%B_QT_VER% ..
if ERRORLEVEL 1 goto failed
-echo @msbuild barrier.sln /p:Platform="x64" /p:Configuration=%B_BUILD_TYPE% /m %B_BUILD_OPTIONS% > make.bat
-call make.bat
+cmake --build . --config %B_BUILD_TYPE%
if ERRORLEVEL 1 goto failed
if exist bin\Debug (
copy %B_QT_FULLPATH%\bin\Qt5Cored.dll bin\Debug\ > NUL
@@ -65,7 +64,7 @@ if exist bin\Debug (
mkdir bin\Release\platforms
copy %B_QT_FULLPATH%\plugins\platforms\qwindows.dll bin\Release\platforms\ > NUL
) else (
- echo Remember to copy supporting binaries and confiuration files!
+ echo Remember to copy supporting binaries and configuration files!
)
echo Build completed successfully
diff --git a/clean_build.sh b/clean_build.sh
index 3a92d8b..585ca88 100755
--- a/clean_build.sh
+++ b/clean_build.sh
@@ -1,10 +1,10 @@
#!/bin/sh
-cd "$(dirname $0)" || exit 1
+cd "$(dirname "$0")" || exit 1
# some environments have cmake v2 as 'cmake' and v3 as 'cmake3'
# check for cmake3 first then fallback to just cmake
B_CMAKE=`type cmake3 2>/dev/null`
if [ $? -eq 0 ]; then
- B_CMAKE=`echo $B_CMAKE | cut -d' ' -f3`
+ B_CMAKE=`echo "$B_CMAKE" | cut -d' ' -f3`
else
B_CMAKE=cmake
fi
@@ -26,7 +26,7 @@ B_CMAKE_FLAGS="-DCMAKE_BUILD_TYPE=$B_BUILD_TYPE $B_CMAKE_FLAGS"
rm -rf build
mkdir build || exit 1
cd build || exit 1
-echo Starting Barrier $B_BUILD_TYPE build...
+echo "Starting Barrier $B_BUILD_TYPE build..."
$B_CMAKE $B_CMAKE_FLAGS .. || exit 1
make || exit 1
echo "Build completed successfully"
diff --git a/cmake/Version.cmake b/cmake/Version.cmake
index 9683649..73524bf 100644
--- a/cmake/Version.cmake
+++ b/cmake/Version.cmake
@@ -1,8 +1,8 @@
cmake_minimum_required (VERSION 3.4)
set (BARRIER_VERSION_MAJOR 2)
-set (BARRIER_VERSION_MINOR 3)
-set (BARRIER_VERSION_PATCH 3)
+set (BARRIER_VERSION_MINOR 4)
+set (BARRIER_VERSION_PATCH 0)
set (BARRIER_VERSION_STAGE "release")
#
@@ -85,6 +85,9 @@ message (STATUS "Full Barrier version string is '" ${BARRIER_VERSION_STRING} "'"
add_definitions (-DBARRIER_VERSION="${BARRIER_VERSION}")
add_definitions (-DBARRIER_VERSION_STRING="${BARRIER_VERSION_STRING}")
+add_definitions (-DBARRIER_VERSION_MAJOR=${BARRIER_VERSION_MAJOR})
+add_definitions (-DBARRIER_VERSION_MINOR=${BARRIER_VERSION_MINOR})
+add_definitions (-DBARRIER_VERSION_PATCH=${BARRIER_VERSION_PATCH})
add_definitions (-DBARRIER_REVISION="${BARRIER_REVISION}")
add_definitions (-DBARRIER_BUILD_DATE="${BARRIER_BUILD_DATE}")
add_definitions (-DBARRIER_BUILD_NUMBER=${BARRIER_BUILD_NUMBER})
diff --git a/cmake/gtest.cmake b/cmake/gtest.cmake
new file mode 100644
index 0000000..e83491c
--- /dev/null
+++ b/cmake/gtest.cmake
@@ -0,0 +1,44 @@
+# barrier -- mouse and keyboard sharing utility
+# Copyright (C) 2012-2016 Symless Ltd.
+# Copyright (C) 2011 Nick Bolton
+#
+# This package is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# found in the file LICENSE that should have accompanied this file.
+#
+# This package is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+if (BARRIER_USE_EXTERNAL_GTEST)
+ include (FindPkgConfig)
+ find_package(GTest REQUIRED)
+ pkg_check_modules(GMOCK REQUIRED gmock)
+ include_directories(
+ ${GTEST_INCLUDE_DIRS}
+ ${GMOCK_INCLUDE_DIRS}
+ )
+else()
+ include_directories(
+ ../ext/gtest
+ ../ext/gtest/include
+ ../ext/gmock
+ ../ext/gmock/include
+ )
+
+ add_library(gtest STATIC ../ext/gtest/src/gtest-all.cc)
+ add_library(gmock STATIC ../ext/gmock/src/gmock-all.cc)
+
+ set(GTEST_LIBRARIES gtest)
+ set(GMOCK_LIBRARIES gmock)
+
+ if (UNIX)
+ # ignore warnings in gtest and gmock
+ set_target_properties(gtest PROPERTIES COMPILE_FLAGS "-w")
+ set_target_properties(gmock PROPERTIES COMPILE_FLAGS "-w")
+ endif()
+endif()
diff --git a/doc/QtCodeStyle.xml b/doc/QtCodeStyle.xml
deleted file mode 100644
index e621c4f..0000000
--- a/doc/QtCodeStyle.xml
+++ /dev/null
@@ -1,234 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE QtCreatorCodeStyle>
-<!-- Written by QtCreator 3.0.1, 2014-02-14T09:50:24. -->
-<qtcreator>
- <data>
- <variable>CodeStyleData</variable>
- <valuemap type="QVariantMap">
- <value type="bool" key="AlignAssignments">false</value>
- <value type="bool" key="AutoSpacesForTabs">false</value>
- <value type="bool" key="BindStarToIdentifier">true</value>
- <value type="bool" key="BindStarToLeftSpecifier">false</value>
- <value type="bool" key="BindStarToRightSpecifier">false</value>
- <value type="bool" key="BindStarToTypeName">false</value>
- <value type="bool" key="ExtraPaddingForConditionsIfConfusingAlign">true</value>
- <value type="bool" key="IndentAccessSpecifiers">false</value>
- <value type="bool" key="IndentBlockBody">true</value>
- <value type="bool" key="IndentBlockBraces">false</value>
- <value type="bool" key="IndentBlocksRelativeToSwitchLabels">false</value>
- <value type="bool" key="IndentClassBraces">false</value>
- <value type="bool" key="IndentControlFlowRelativeToSwitchLabels">true</value>
- <value type="bool" key="IndentDeclarationsRelativeToAccessSpecifiers">true</value>
- <value type="bool" key="IndentEnumBraces">false</value>
- <value type="bool" key="IndentFunctionBody">true</value>
- <value type="bool" key="IndentFunctionBraces">false</value>
- <value type="bool" key="IndentNamespaceBody">false</value>
- <value type="bool" key="IndentNamespaceBraces">false</value>
- <value type="int" key="IndentSize">4</value>
- <value type="bool" key="IndentStatementsRelativeToSwitchLabels">true</value>
- <value type="bool" key="IndentSwitchLabels">false</value>
- <value type="int" key="PaddingMode">2</value>
- <value type="bool" key="SpacesForTabs">false</value>
- <value type="int" key="TabSize">4</value>
- </valuemap>
- </data>
- <data>
- <variable>DisplayName</variable>
- <value type="QString">Barrier</value>
- </data>
-</qtcreator>
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE QtCreatorCodeStyle>
-<!-- Written by QtCreator 3.0.1, 2014-02-14T09:50:24. -->
-<qtcreator>
- <data>
- <variable>CodeStyleData</variable>
- <valuemap type="QVariantMap">
- <value type="bool" key="AlignAssignments">false</value>
- <value type="bool" key="AutoSpacesForTabs">false</value>
- <value type="bool" key="BindStarToIdentifier">true</value>
- <value type="bool" key="BindStarToLeftSpecifier">false</value>
- <value type="bool" key="BindStarToRightSpecifier">false</value>
- <value type="bool" key="BindStarToTypeName">false</value>
- <value type="bool" key="ExtraPaddingForConditionsIfConfusingAlign">true</value>
- <value type="bool" key="IndentAccessSpecifiers">false</value>
- <value type="bool" key="IndentBlockBody">true</value>
- <value type="bool" key="IndentBlockBraces">false</value>
- <value type="bool" key="IndentBlocksRelativeToSwitchLabels">false</value>
- <value type="bool" key="IndentClassBraces">false</value>
- <value type="bool" key="IndentControlFlowRelativeToSwitchLabels">true</value>
- <value type="bool" key="IndentDeclarationsRelativeToAccessSpecifiers">true</value>
- <value type="bool" key="IndentEnumBraces">false</value>
- <value type="bool" key="IndentFunctionBody">true</value>
- <value type="bool" key="IndentFunctionBraces">false</value>
- <value type="bool" key="IndentNamespaceBody">false</value>
- <value type="bool" key="IndentNamespaceBraces">false</value>
- <value type="int" key="IndentSize">4</value>
- <value type="bool" key="IndentStatementsRelativeToSwitchLabels">true</value>
- <value type="bool" key="IndentSwitchLabels">false</value>
- <value type="int" key="PaddingMode">2</value>
- <value type="bool" key="SpacesForTabs">false</value>
- <value type="int" key="TabSize">4</value>
- </valuemap>
- </data>
- <data>
- <variable>DisplayName</variable>
- <value type="QString">Barrier</value>
- </data>
-</qtcreator>
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE QtCreatorCodeStyle>
-<!-- Written by QtCreator 3.0.1, 2014-02-14T09:50:24. -->
-<qtcreator>
- <data>
- <variable>CodeStyleData</variable>
- <valuemap type="QVariantMap">
- <value type="bool" key="AlignAssignments">false</value>
- <value type="bool" key="AutoSpacesForTabs">false</value>
- <value type="bool" key="BindStarToIdentifier">true</value>
- <value type="bool" key="BindStarToLeftSpecifier">false</value>
- <value type="bool" key="BindStarToRightSpecifier">false</value>
- <value type="bool" key="BindStarToTypeName">false</value>
- <value type="bool" key="ExtraPaddingForConditionsIfConfusingAlign">true</value>
- <value type="bool" key="IndentAccessSpecifiers">false</value>
- <value type="bool" key="IndentBlockBody">true</value>
- <value type="bool" key="IndentBlockBraces">false</value>
- <value type="bool" key="IndentBlocksRelativeToSwitchLabels">false</value>
- <value type="bool" key="IndentClassBraces">false</value>
- <value type="bool" key="IndentControlFlowRelativeToSwitchLabels">true</value>
- <value type="bool" key="IndentDeclarationsRelativeToAccessSpecifiers">true</value>
- <value type="bool" key="IndentEnumBraces">false</value>
- <value type="bool" key="IndentFunctionBody">true</value>
- <value type="bool" key="IndentFunctionBraces">false</value>
- <value type="bool" key="IndentNamespaceBody">false</value>
- <value type="bool" key="IndentNamespaceBraces">false</value>
- <value type="int" key="IndentSize">4</value>
- <value type="bool" key="IndentStatementsRelativeToSwitchLabels">true</value>
- <value type="bool" key="IndentSwitchLabels">false</value>
- <value type="int" key="PaddingMode">2</value>
- <value type="bool" key="SpacesForTabs">false</value>
- <value type="int" key="TabSize">4</value>
- </valuemap>
- </data>
- <data>
- <variable>DisplayName</variable>
- <value type="QString">Barrier</value>
- </data>
-</qtcreator>
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE QtCreatorCodeStyle>
-<!-- Written by QtCreator 3.0.1, 2014-02-14T09:50:24. -->
-<qtcreator>
- <data>
- <variable>CodeStyleData</variable>
- <valuemap type="QVariantMap">
- <value type="bool" key="AlignAssignments">false</value>
- <value type="bool" key="AutoSpacesForTabs">false</value>
- <value type="bool" key="BindStarToIdentifier">true</value>
- <value type="bool" key="BindStarToLeftSpecifier">false</value>
- <value type="bool" key="BindStarToRightSpecifier">false</value>
- <value type="bool" key="BindStarToTypeName">false</value>
- <value type="bool" key="ExtraPaddingForConditionsIfConfusingAlign">true</value>
- <value type="bool" key="IndentAccessSpecifiers">false</value>
- <value type="bool" key="IndentBlockBody">true</value>
- <value type="bool" key="IndentBlockBraces">false</value>
- <value type="bool" key="IndentBlocksRelativeToSwitchLabels">false</value>
- <value type="bool" key="IndentClassBraces">false</value>
- <value type="bool" key="IndentControlFlowRelativeToSwitchLabels">true</value>
- <value type="bool" key="IndentDeclarationsRelativeToAccessSpecifiers">true</value>
- <value type="bool" key="IndentEnumBraces">false</value>
- <value type="bool" key="IndentFunctionBody">true</value>
- <value type="bool" key="IndentFunctionBraces">false</value>
- <value type="bool" key="IndentNamespaceBody">false</value>
- <value type="bool" key="IndentNamespaceBraces">false</value>
- <value type="int" key="IndentSize">4</value>
- <value type="bool" key="IndentStatementsRelativeToSwitchLabels">true</value>
- <value type="bool" key="IndentSwitchLabels">false</value>
- <value type="int" key="PaddingMode">2</value>
- <value type="bool" key="SpacesForTabs">false</value>
- <value type="int" key="TabSize">4</value>
- </valuemap>
- </data>
- <data>
- <variable>DisplayName</variable>
- <value type="QString">Barrier</value>
- </data>
-</qtcreator>
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE QtCreatorCodeStyle>
-<!-- Written by QtCreator 3.0.1, 2014-02-14T09:50:24. -->
-<qtcreator>
- <data>
- <variable>CodeStyleData</variable>
- <valuemap type="QVariantMap">
- <value type="bool" key="AlignAssignments">false</value>
- <value type="bool" key="AutoSpacesForTabs">false</value>
- <value type="bool" key="BindStarToIdentifier">true</value>
- <value type="bool" key="BindStarToLeftSpecifier">false</value>
- <value type="bool" key="BindStarToRightSpecifier">false</value>
- <value type="bool" key="BindStarToTypeName">false</value>
- <value type="bool" key="ExtraPaddingForConditionsIfConfusingAlign">true</value>
- <value type="bool" key="IndentAccessSpecifiers">false</value>
- <value type="bool" key="IndentBlockBody">true</value>
- <value type="bool" key="IndentBlockBraces">false</value>
- <value type="bool" key="IndentBlocksRelativeToSwitchLabels">false</value>
- <value type="bool" key="IndentClassBraces">false</value>
- <value type="bool" key="IndentControlFlowRelativeToSwitchLabels">true</value>
- <value type="bool" key="IndentDeclarationsRelativeToAccessSpecifiers">true</value>
- <value type="bool" key="IndentEnumBraces">false</value>
- <value type="bool" key="IndentFunctionBody">true</value>
- <value type="bool" key="IndentFunctionBraces">false</value>
- <value type="bool" key="IndentNamespaceBody">false</value>
- <value type="bool" key="IndentNamespaceBraces">false</value>
- <value type="int" key="IndentSize">4</value>
- <value type="bool" key="IndentStatementsRelativeToSwitchLabels">true</value>
- <value type="bool" key="IndentSwitchLabels">false</value>
- <value type="int" key="PaddingMode">2</value>
- <value type="bool" key="SpacesForTabs">false</value>
- <value type="int" key="TabSize">4</value>
- </valuemap>
- </data>
- <data>
- <variable>DisplayName</variable>
- <value type="QString">Barrier</value>
- </data>
-</qtcreator>
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE QtCreatorCodeStyle>
-<!-- Written by QtCreator 3.0.1, 2014-02-14T09:50:24. -->
-<qtcreator>
- <data>
- <variable>CodeStyleData</variable>
- <valuemap type="QVariantMap">
- <value type="bool" key="AlignAssignments">false</value>
- <value type="bool" key="AutoSpacesForTabs">false</value>
- <value type="bool" key="BindStarToIdentifier">true</value>
- <value type="bool" key="BindStarToLeftSpecifier">false</value>
- <value type="bool" key="BindStarToRightSpecifier">false</value>
- <value type="bool" key="BindStarToTypeName">false</value>
- <value type="bool" key="ExtraPaddingForConditionsIfConfusingAlign">true</value>
- <value type="bool" key="IndentAccessSpecifiers">false</value>
- <value type="bool" key="IndentBlockBody">true</value>
- <value type="bool" key="IndentBlockBraces">false</value>
- <value type="bool" key="IndentBlocksRelativeToSwitchLabels">false</value>
- <value type="bool" key="IndentClassBraces">false</value>
- <value type="bool" key="IndentControlFlowRelativeToSwitchLabels">true</value>
- <value type="bool" key="IndentDeclarationsRelativeToAccessSpecifiers">true</value>
- <value type="bool" key="IndentEnumBraces">false</value>
- <value type="bool" key="IndentFunctionBody">true</value>
- <value type="bool" key="IndentFunctionBraces">false</value>
- <value type="bool" key="IndentNamespaceBody">false</value>
- <value type="bool" key="IndentNamespaceBraces">false</value>
- <value type="int" key="IndentSize">4</value>
- <value type="bool" key="IndentStatementsRelativeToSwitchLabels">true</value>
- <value type="bool" key="IndentSwitchLabels">false</value>
- <value type="int" key="PaddingMode">2</value>
- <value type="bool" key="SpacesForTabs">false</value>
- <value type="int" key="TabSize">4</value>
- </valuemap>
- </data>
- <data>
- <variable>DisplayName</variable>
- <value type="QString">Barrier</value>
- </data>
-</qtcreator>
diff --git a/doc/barrier.conf.example-advanced b/doc/barrier.conf.example-advanced
index ad9df29..e1b2392 100644
--- a/doc/barrier.conf.example-advanced
+++ b/doc/barrier.conf.example-advanced
@@ -47,9 +47,9 @@ section: links
end
# The aliases section is to map the full names of the computers to their logical names used in the screens section
-# One way to find the actual name of a comptuer is to run hostname from a command window
+# One way to find the actual name of a computer is to run hostname from a command window
section: aliases
# Laptop is actually known as John-Smiths-MacBook-3.local
- desktop2:
- John-Smiths-MacBook-3.local
+ John-Smiths-MacBook-3.local:
+ desktop2
end
diff --git a/doc/barrier.conf.example-barebones b/doc/barrier.conf.example-barebones
new file mode 100644
index 0000000..1a4558d
--- /dev/null
+++ b/doc/barrier.conf.example-barebones
@@ -0,0 +1,17 @@
+# barebones barrier.conf example
+# for two computers side by side
+# replace screen.name.server and screen.name.client with your screen names from gui
+# there's a 50/50 chance you'll want to swap left and right
+# save this as barrier.conf in your home folder and "Use existing configuration" on server
+
+section: screens
+ screen.name.server:
+ screen.name.client:
+end
+
+section: links
+ screen.name.server:
+ left = screen.name.client
+ screen.name.client:
+ right = screen.name.server
+end
diff --git a/doc/barrier.conf.example-basic b/doc/barrier.conf.example-basic
index 39ff6d6..57d71d9 100644
--- a/doc/barrier.conf.example-basic
+++ b/doc/barrier.conf.example-basic
@@ -34,6 +34,6 @@ end
section: aliases
# The "real" name of iMac is John-Smiths-iMac-3.local. If we wanted we could remove this alias and instead use John-Smiths-iMac-3.local everywhere iMac is above. Hopefully it should be easy to see why using an alias is nicer
- iMac:
- John-Smiths-iMac-3.local
+ John-Smiths-iMac-3.local:
+ iMac
end
diff --git a/doc/barrierc.1 b/doc/barrierc.1
index 2fd882a..d470447 100644
--- a/doc/barrierc.1
+++ b/doc/barrierc.1
@@ -1,5 +1,5 @@
.\" See UpdateManpages.txt about modification of this file. Most of it was generated by help2man 1.47.8.
-.TH BARRIERC "1" "November 2019" "barrierc 2.3.3-release" "User Commands"
+.TH BARRIERC "1" "November 2019" "barrierc 2.4.0-release" "User Commands"
.SH NAME
barrierc \- Barrier Keyboard/Mouse Client
.SH SYNOPSIS
diff --git a/doc/barriers.1 b/doc/barriers.1
index 098ea84..f4a460e 100644
--- a/doc/barriers.1
+++ b/doc/barriers.1
@@ -1,5 +1,5 @@
.\" See UpdateManpages.txt about modification of this file. Most of it was generated by help2man 1.47.8.
-.TH BARRIERS "1" "November 2019" "barriers 2.3.3-release" "User Commands"
+.TH BARRIERS "1" "November 2019" "barriers 2.4.0-release" "User Commands"
.SH NAME
barriers \- Barrier Keyboard/Mouse Server
.SH SYNOPSIS
diff --git a/doc/newsfragments/README.md b/doc/newsfragments/README.md
new file mode 100644
index 0000000..0338cf8
--- /dev/null
+++ b/doc/newsfragments/README.md
@@ -0,0 +1,13 @@
+This is the directory for release note fragments processed by
+[towncrier](https://github.com/hawkowl/towncrier).
+
+When making a user-visible change create a file in this directory and it will be automatically be
+included into the release note document when the next release is published.
+
+The file extension specifies the type of a change. The following are currently supported:
+
+ - .feature: a new feature.
+ - .bugfix: a bug fix.
+ - .security: a fix for security issue.
+ - .doc: a documentation improvement.
+ - .removal: a deprecation or removal of functionality.
diff --git a/doc/org.barrier-foss.org.barrierc.plist b/doc/org.barrier-foss.org.barrierc.plist
index 31e10ba..90345c8 100644
--- a/doc/org.barrier-foss.org.barrierc.plist
+++ b/doc/org.barrier-foss.org.barrierc.plist
@@ -4,17 +4,17 @@
<plist version="1.0">
<!-- Mac OSX only: Copy this plist file into [~]/Library/LaunchAgents to start barrier client automatically. Make sure you change the IP below. -->
<dict>
- <key>Label</key>
- <string>org.debauchee.com.barrierc.plist</string>
- <key>OnDemand</key>
- <false/>
- <key>ProgramArguments</key>
- <array>
+ <key>Label</key>
+ <string>org.debauchee.com.barrierc.plist</string>
+ <key>OnDemand</key>
+ <false/>
+ <key>ProgramArguments</key>
+ <array>
<string>/usr/bin/barrierc</string>
<!-- Replace this IP with the IP of your barriers server -->
<string>192.168.0.2</string>
- </array>
- <key>RunAtLoad</key>
- <true/>
+ </array>
+ <key>RunAtLoad</key>
+ <true/>
</dict>
</plist>
diff --git a/doc/org.barrier-foss.org.barriers.plist b/doc/org.barrier-foss.org.barriers.plist
index f1ab5bf..fed7b47 100644
--- a/doc/org.barrier-foss.org.barriers.plist
+++ b/doc/org.barrier-foss.org.barriers.plist
@@ -4,12 +4,12 @@
<plist version="1.0">
<!-- Mac OSX only: Copy this plist file into [~]/Library/LaunchAgents to start barrier server automatically. Make sure you change configuration file below -->
<dict>
- <key>Label</key>
- <string>org.debauchee.com.barriers.plist</string>
- <key>OnDemand</key>
- <false/>
- <key>ProgramArguments</key>
- <array>
+ <key>Label</key>
+ <string>org.debauchee.com.barriers.plist</string>
+ <key>OnDemand</key>
+ <false/>
+ <key>ProgramArguments</key>
+ <array>
<string>/usr/bin/barriers</string>
<string>--no-daemon</string>
<string>--config</string>
diff --git a/doc/release_notes/index.md b/doc/release_notes/index.md
new file mode 100644
index 0000000..72d3a43
--- /dev/null
+++ b/doc/release_notes/index.md
@@ -0,0 +1,94 @@
+Release notes
+=============
+
+[comment]: <> (towncrier release notes start)
+
+Barrier `2.4.0` ( `2021-11-01` )
+================================
+
+Security fixes
+--------------
+
+- Barrier now supports client identity verification (fixes CVE-2021-42072, CVE-2021-42073).
+
+ Previously a malicious client could connect to Barrier server without any authentication and
+ send application-level messages. This made the attack surface of Barrier significantly larger.
+ Additionally, in case the malicious client got possession of a valid screen name by brute forcing
+ or other means it could modify the clipboard contents of the server.
+
+ To support seamless upgrades from older versions of Barrier this is currently disabled by default.
+ The feature can be enabled in the settings dialog. If enabled, older clients of Barrier will be
+ rejected.
+
+- Barrier now uses SHA256 fingerprints for establishing security of encrypted SSL connections.
+ After upgrading client to new version the existing server fingerprint will need to be approved
+ again. Client and server will show both SHA1 and SHA256 server fingerprints to allow
+ interoperability with older versions of Barrier.
+
+Bug fixes
+---------
+
+- Fixed build failure on mips*el and riscv64 architecture.
+- Fixed reading of configuration on Windows when the paths contain non-ASCII characters
+(https://github.com/debauchee/barrier/issues/976, https://github.com/debauchee/barrier/issues/974,
+ https://github.com/debauchee/barrier/issues/444).
+- Barrier no longer uses openssl CLI tool for any operations and hooks into the openssl library directly.
+- More X11 clipboard MIME types have been mapped to corresponding converters (https://github.com/debauchee/barrier/issues/344).
+- Fixed setup of multiple actions associated with a hotkey.
+- Fixed setup of hotkeys with special characters such as comma and semicolon
+ (https://github.com/debauchee/barrier/issues/778).
+- Fixed transfer of non-ASCII characters coming from a Windows server in certain cases
+ (https://github.com/debauchee/barrier/issues/527).
+- Barrier will now regenerate server certificate if it's invalid instead of failing to launch
+ (https://github.com/debauchee/barrier/issues/802)
+- Added support for additional keys on Sun Microsystems USB keyboards
+ (https://github.com/debauchee/barrier/issues/784).
+- Updated Chinese translation.
+- Updated Slovak translation.
+- Theme icons are now preferred to icons distributed together with Barrier
+ (https://github.com/debauchee/barrier/issues/471).
+- Fixed incorrect setup of Barrier service path on Windows.
+
+Features
+--------
+
+- Added `--drop-target` option that improves drag and drop support on Windows when Barrier is
+ being run as a portable app.
+- The `--enable-crypto` command line option has been made the default to reduce chances of
+ accidental security mishaps when configuring Barrier from command line.
+ A new `--disable-crypto` command line option has been added to explicitly disable encryption.
+- Added support for randomart images for easier comparison of SSL certificate fingerprints.
+ The algorithm is identical to what OpenSSH uses.
+- Implemented a configuration option for Server GUI auto-start.
+- Made it possible to use keyboard instead of mouse to modify screen layout.
+- Added support for keyboard backlight media keys
+- Added support for Eisu_toggle and Muhenkan keys
+- Added `--profile-dir` option that allows to select custom profile directory.
+
+Barrier `2.3.4` ( `2021-11-01` )
+================================
+
+Security fixes
+--------------
+
+- Barrier will now correctly close connections when the app-level handshake fails (fixes CVE-2021-42075).
+
+ Previously repeated failing connections would leak file descriptors leading to Barrier being unable
+ to receive new connections from clients.
+
+- Barrier will now enforce a maximum length of input messages (fixes CVE-2021-42076).
+
+ Previously it was possible for a malicious client or server to send excessive length messages
+ leading to denial of service by resource exhaustion.
+
+- Fixed a bug which caused Barrier to crash when disconnecting a TCP session just after sending Hello message.
+ This bug allowed an unauthenticated attacker to crash Barrier with only network access.
+
+All of the above security issues have been reported by Matthias Gerstner who was really helpful
+resolving them.
+
+Bug fixes
+---------
+
+- Fixed a bug in SSL implementation that caused invalid data occasionally being sent to clients
+ under heavy load.
diff --git a/doc/release_notes/index.template.jinja b/doc/release_notes/index.template.jinja
new file mode 100644
index 0000000..418a1d3
--- /dev/null
+++ b/doc/release_notes/index.template.jinja
@@ -0,0 +1,37 @@
+{% for section, _ in sections|dictsort(by='key') %}
+{% set underline = "-" %}
+{% if section %}
+{{section}}
+{{ underline * section|length }}{% set underline = "-" %}
+
+{% endif %}
+{% if sections[section] %}
+{% for category, val in definitions|dictsort if category in sections[section]%}
+
+{{ definitions[category]['name'] }}
+{{ underline * definitions[category]['name']|length }}
+
+{% if definitions[category]['showcontent'] %}
+{% for text, values in sections[section][category]|dictsort(by='value') %}
+- {{ text }}
+{% endfor %}
+{% else %}
+- {{ sections[section][category]['']|sort|join(', ') }}
+
+
+{% endif %}
+{% if sections[section][category]|length == 0 %}
+
+No significant changes.
+
+
+{% else %}
+{% endif %}
+{% endfor %}
+{% else %}
+
+No significant changes.
+
+
+{% endif %}
+{% endfor %}
diff --git a/gulrak-filesystem/.appveyor.yml b/gulrak-filesystem/.appveyor.yml
new file mode 100644
index 0000000..cf986f7
--- /dev/null
+++ b/gulrak-filesystem/.appveyor.yml
@@ -0,0 +1,85 @@
+environment:
+ matrix:
+ - platform: x86
+ APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
+ generator: "Visual Studio 14 2015"
+ compiler: msvc
+ configuration: Release
+
+ - platform: x64
+ APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
+ generator: "Visual Studio 14 2015 Win64"
+ compiler: msvc
+ configuration: Release
+
+ - platform: x86
+ APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+ generator: "Visual Studio 15 2017"
+ compiler: msvc
+ configuration: Release
+
+ - platform: x64
+ APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+ generator: "Visual Studio 15 2017 Win64"
+ compiler: msvc
+ configuration: Release
+
+ - platform: x86
+ APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
+ generator: "Visual Studio 16 2019"
+ compiler: msvc19
+ configuration: Release
+ arch: Win32
+
+ - platform: x64
+ APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
+ generator: "Visual Studio 16 2019"
+ compiler: msvc19
+ configuration: Release
+ arch: x64
+
+ - platform: x86
+ APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
+ generator: "MinGW Makefiles"
+ compiler: mingw
+ TOOLCHAIN_PATH: C:\mingw-w64\i686-6.3.0-posix-dwarf-rt_v5-rev1/mingw32\bin
+ CC: C:/mingw-w64/i686-6.3.0-posix-dwarf-rt_v5-rev1/mingw32/bin/gcc.exe
+ CXX: C:/mingw-w64/i686-6.3.0-posix-dwarf-rt_v5-rev1/mingw32/bin/g++.exe
+ configuration: Release
+
+ - platform: x64
+ APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
+ generator: "MinGW Makefiles"
+ compiler: mingw
+ TOOLCHAIN_PATH: C:\mingw-w64\x86_64-7.2.0-posix-seh-rt_v5-rev1\mingw64\bin
+ CC: C:/mingw-w64/x86_64-7.2.0-posix-seh-rt_v5-rev1/mingw64/bin/gcc.exe
+ CXX: C:/mingw-w64/x86_64-7.2.0-posix-seh-rt_v5-rev1/mingw64/bin/g++.exe
+ configuration: Release
+
+matrix:
+ fast_finish: false
+
+init:
+ - cmd: cmake --version
+ - cmd: msbuild /version
+
+install:
+ - cmd: reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock" /t REG_DWORD /f /v "AllowDevelopmentWithoutDevLicense" /d "1"
+ - cmd: ren "C:\Program Files\Git\usr\bin\sh.exe" _sh.exe
+
+build_script:
+ - mkdir build
+ - cd build
+ - if [%compiler%]==[msvc] cmake -G"%generator%" ..
+ - if [%compiler%]==[msvc19] cmake -G"%generator%" -A "%arch%" ..
+ - if [%compiler%]==[mingw] set PATH=%TOOLCHAIN_PATH%;%PATH%
+ - if [%compiler%]==[mingw] cmake -G"%generator%" -DCMAKE_C_COMPILER=%CC% -DCMAKE_CXX_COMPILER=%CXX% -DCMAKE_SH=CMAKE_SH-NOTFOUND -DCMAKE_BUILD_TYPE=%configuration% ..
+ - cmake --build . --config %configuration%
+
+test_script:
+ - cd %APPVEYOR_BUILD_FOLDER%\build
+ - set CTEST_OUTPUT_ON_FAILURE=1
+ - ctest -C %configuration%
+ - if exist "test\Release\std_filesystem_test.exe" test\Release\std_filesystem_test.exe & exit 0
+ - cd ..
+
diff --git a/gulrak-filesystem/.ci/unix-build.sh b/gulrak-filesystem/.ci/unix-build.sh
new file mode 100755
index 0000000..914befa
--- /dev/null
+++ b/gulrak-filesystem/.ci/unix-build.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+mkdir build && cd build
+cmake -DCMAKE_BUILD_TYPE=Release ..
+cmake --build .
diff --git a/gulrak-filesystem/.ci/unix-test.sh b/gulrak-filesystem/.ci/unix-test.sh
new file mode 100755
index 0000000..23b511f
--- /dev/null
+++ b/gulrak-filesystem/.ci/unix-test.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+cd build
+echo "Tests run as user: $USER"
+ctest -E Windows
+if [ -f "test/std_filesystem_test" ]; then
+ test/std_filesystem_test || true
+fi
diff --git a/gulrak-filesystem/.cirrus.yml b/gulrak-filesystem/.cirrus.yml
new file mode 100644
index 0000000..9766476
--- /dev/null
+++ b/gulrak-filesystem/.cirrus.yml
@@ -0,0 +1,35 @@
+freebsd_task:
+ freebsd_instance:
+ image_family: freebsd-12-1
+ install_script: |
+ pkg install -y cmake
+ pw groupadd testgrp
+ pw useradd testuser -g testgrp -w none -m
+ chown -R testuser:testgrp .
+ build_script: |
+ sudo -u testuser .ci/unix-build.sh
+ test_script: |
+ sudo -u testuser .ci/unix-test.sh
+
+centos7_task:
+ container:
+ image: centos:7
+ install_script: |
+ yum install -y centos-release-scl
+ yum install -y devtoolset-9
+ curl -L https://github.com/Kitware/CMake/releases/download/v3.16.4/cmake-3.16.4-Linux-x86_64.tar.gz | tar xzvf - -C /usr/local --strip-components 1
+ build_script: |
+ source /opt/rh/devtoolset-9/enable && PATH=$PATH:/usr/local/bin .ci/unix-build.sh
+ test_script: |
+ PATH=$PATH:/usr/local/bin .ci/unix-test.sh
+
+centos8_task:
+ container:
+ image: centos:8
+ install_script: |
+ yum group install -y "Development Tools"
+ curl -L https://github.com/Kitware/CMake/releases/download/v3.16.4/cmake-3.16.4-Linux-x86_64.tar.gz | tar xzvf - -C /usr/local --strip-components 1
+ build_script: |
+ PATH=$PATH:/usr/local/bin .ci/unix-build.sh
+ test_script: |
+ PATH=$PATH:/usr/local/bin .ci/unix-test.sh \ No newline at end of file
diff --git a/gulrak-filesystem/.clang-format b/gulrak-filesystem/.clang-format
new file mode 100644
index 0000000..b24fe34
--- /dev/null
+++ b/gulrak-filesystem/.clang-format
@@ -0,0 +1,25 @@
+---
+Language: Cpp
+BasedOnStyle: Chromium
+AccessModifierOffset: '-4'
+IndentWidth: '4'
+ColumnLimit: 256
+BreakBeforeBraces: Custom
+BraceWrapping:
+ AfterClass: true
+ AfterControlStatement: false
+ AfterFunction: true
+ AfterNamespace: false
+ AfterObjCDeclaration: true
+ AfterStruct: true
+ AfterUnion: true
+ BeforeCatch: true
+ BeforeElse: true
+ IndentBraces: false
+ SplitEmptyFunction: true
+ SplitEmptyRecord: true
+ SplitEmptyNamespace: true
+BreakConstructorInitializers: BeforeComma
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+IndentPPDirectives: None
+...
diff --git a/gulrak-filesystem/.clang-tidy b/gulrak-filesystem/.clang-tidy
new file mode 100644
index 0000000..203d506
--- /dev/null
+++ b/gulrak-filesystem/.clang-tidy
@@ -0,0 +1,3 @@
+---
+Checks: -modernize-use-nodiscard
+...
diff --git a/gulrak-filesystem/.drone.yml b/gulrak-filesystem/.drone.yml
new file mode 100644
index 0000000..da967a4
--- /dev/null
+++ b/gulrak-filesystem/.drone.yml
@@ -0,0 +1,43 @@
+kind: pipeline
+name: arm
+
+platform:
+ os: linux
+ arch: arm
+
+steps:
+- name: build
+ image: alpine
+ failure: ignore
+ commands:
+ - apk update
+ - apk add --no-cache build-base cmake sudo
+ - addgroup testgrp
+ - adduser --disabled-password testuser testgrp
+ - passwd testuser -u -d
+ - chown -R testuser:testgrp .
+ - sudo -u testuser .ci/unix-build.sh
+ - sudo -u testuser .ci/unix-test.sh
+
+---
+
+kind: pipeline
+name: arm64
+
+platform:
+ os: linux
+ arch: arm64
+
+steps:
+- name: build
+ image: alpine
+ failure: ignore
+ commands:
+ - apk update
+ - apk add --no-cache build-base cmake
+ - addgroup testgrp
+ - adduser --disabled-password testuser testgrp
+ - passwd testuser -u -d
+ - chown -R testuser:testgrp .
+ - su -c "./.ci/unix-build.sh" testuser
+ - su -c "./.ci/unix-test.sh" testuser
diff --git a/gulrak-filesystem/.github/ISSUE_TEMPLATE/bug_report.md b/gulrak-filesystem/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000..fc25aa4
--- /dev/null
+++ b/gulrak-filesystem/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,17 @@
+---
+name: Bug report
+about: Create a report to help us improve
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Detailed steps to reproduce the behavior.
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/gulrak-filesystem/.github/ISSUE_TEMPLATE/feature_request.md b/gulrak-filesystem/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000..066b2d9
--- /dev/null
+++ b/gulrak-filesystem/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,17 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/gulrak-filesystem/.github/workflows/build_cmake.yml b/gulrak-filesystem/.github/workflows/build_cmake.yml
new file mode 100644
index 0000000..783508b
--- /dev/null
+++ b/gulrak-filesystem/.github/workflows/build_cmake.yml
@@ -0,0 +1,197 @@
+name: CMake Build Matrix
+
+on: [ push, pull_request ]
+
+jobs:
+ build:
+ name: ${{ matrix.config.name }}
+ runs-on: ${{ matrix.config.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ config:
+ - name: "Ubuntu 20.04 GCC 9.3"
+ os: ubuntu-20.04
+ build_type: Release
+ packages: ninja-build
+ generator: Ninja
+ compatibility: "cxx_std_11;cxx_std_17;cxx_std_20"
+ cc: gcc
+ cxx: g++
+
+ - name: "Ubuntu 20.04 Clang 10.0"
+ os: ubuntu-20.04
+ build_type: Release
+ packages: ninja-build
+ generator: Ninja
+ compatibility: "cxx_std_11;cxx_std_17;cxx_std_20"
+ cc: clang-10
+ cxx: clang++-10
+
+ - name: "Ubuntu 20.04 Clang 11.0"
+ os: ubuntu-20.04
+ build_type: Release
+ packages: ninja-build clang-11 libc++-11-dev libc++abi-11-dev
+ generator: Ninja
+ compatibility: "cxx_std_11;cxx_std_17;cxx_std_20"
+ cc: clang-11
+ cxx: clang++-11
+
+ - name: "Ubuntu 20.04 GCC 9.3 coverage"
+ os: ubuntu-20.04
+ build_type: Debug
+ packages: ninja-build lcov
+ generator: Ninja
+ compatibility: "cxx_std_11;cxx_std_17;cxx_std_20"
+ cc: gcc
+ cxx: g++
+
+ - name: "Ubuntu 18.04 GCC 8.4"
+ os: ubuntu-18.04
+ build_type: Release
+ packages: ninja-build gcc-8 g++-8
+ generator: Ninja
+ compatibility: "cxx_std_11;cxx_std_17"
+ cc: gcc-8
+ cxx: g++-8
+
+ - name: "Ubuntu 18.04 GCC 7.5"
+ os: ubuntu-18.04
+ build_type: Release
+ packages: ninja-build
+ generator: Ninja
+ compatibility: "cxx_std_11;cxx_std_17"
+ cc: gcc-7
+ cxx: g++-7
+
+ - name: "Ubuntu 18.04 GCC 6.5"
+ os: ubuntu-18.04
+ build_type: Release
+ packages: ninja-build gcc-6 g++-6
+ generator: Ninja
+ compatibility: "cxx_std_11;cxx_std_17"
+ cc: gcc-6
+ cxx: g++-6
+
+ - name: "Ubuntu 18.04 GCC 5.5"
+ os: ubuntu-18.04
+ build_type: Release
+ packages: ninja-build gcc-5 g++-5
+ generator: Ninja
+ compatibility: "cxx_std_11;cxx_std_17"
+ cc: gcc-5
+ cxx: g++-5
+
+ - name: "Ubuntu 18.04 Clang 9.0"
+ os: ubuntu-18.04
+ build_type: Release
+ packages: ninja-build libc++-9-dev libc++abi-9-dev
+ generator: Ninja
+ compatibility: "cxx_std_11;cxx_std_17;cxx_std_20"
+ cc: clang
+ cxx: clang++
+
+ - name: "Ubuntu 18.04 Clang 6.0"
+ os: ubuntu-18.04
+ build_type: Release
+ packages: ninja-build clang-6.0
+ generator: Ninja
+ compatibility: "cxx_std_11;cxx_std_17"
+ cc: clang-6.0
+ cxx: clang++-6.0
+
+ - name: "Ubuntu 18.04 Clang 5.0"
+ os: ubuntu-18.04
+ build_type: Release
+ packages: ninja-build clang-5.0
+ generator: Ninja
+ compatibility: "cxx_std_11;cxx_std_17"
+ cc: clang-5.0
+ cxx: clang++-5.0
+
+ - name: "Windows MSVC 2019"
+ os: windows-latest
+ build_type: Release
+ packages: ninja
+ generator: "Visual Studio 16 2019"
+ compatibility: "cxx_std_11;cxx_std_17;cxx_std_20"
+ cc: cl
+ cxx: cl
+
+ - name: "macOS 10.15 AppleClang"
+ os: macos-10.15
+ build_type: Release
+ packages: ninja
+ generator: Ninja
+ compatibility: "cxx_std_11;cxx_std_17"
+ cc: clang
+ cxx: clang++
+
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: print environment
+ run: |
+ echo github.event.action: ${{ github.event.action }}
+ echo github.event_name: ${{ github.event_name }}
+
+ - name: Install dependencies on Ubuntu
+ if: startsWith(matrix.config.os, 'ubuntu')
+ shell: bash
+ run: |
+ sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
+ sudo apt update
+ sudo apt install ${{ matrix.config.packages }}
+
+ - name: Install dependencies on windows
+ if: startsWith(matrix.config.os, 'windows')
+ run: |
+ choco install ${{ matrix.config.packages }}
+
+ - name: Install dependencies on macOS
+ if: startsWith(matrix.config.os, 'macos')
+ run: |
+ brew install ${{ matrix.config.packages }}
+
+ - name: Configure project
+ shell: bash
+ run: |
+ export CC=${{ matrix.config.cc }}
+ export CXX=${{ matrix.config.cxx }}
+ ninja --version
+ cmake --version
+ mkdir build
+ mkdir install
+ if [[ "${{ matrix.config.build_type }}" == "Debug" ]]; then
+ cmake -G "${{ matrix.config.generator }}" -S . -B build -DCMAKE_BUILD_TYPE=Debug -DGHC_COVERAGE=ON -DGHC_FILESYSTEM_TEST_COMPILE_FEATURES="${{ matrix.config.compatibility }}" -DCMAKE_INSTALL_PREFIX:PATH=install
+ else
+ cmake -G "${{ matrix.config.generator }}" -S . -B build -DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} -DGHC_FILESYSTEM_TEST_COMPILE_FEATURES="${{ matrix.config.compatibility }}" -DCMAKE_INSTALL_PREFIX:PATH=install
+ fi
+
+ - name: Build project
+ shell: bash
+ run: |
+ cmake --build build --config ${{ matrix.config.build_type }}
+
+ - name: Run tests
+ run: |
+ cd build && ctest -C ${{ matrix.config.build_type }}
+
+ - name: Collect coverage info
+ if: startsWith(matrix.config.build_type, 'Debug')
+ run: |
+ cd build
+ lcov --compat-libtool --directory . --capture --output-file coverage_output.info
+ lcov --remove coverage_output.info '/usr/*' '*/c++/*' '*.h' '*/catch.hpp' -o coverage.info
+ # sed -i 's|SF:/.*/filesystem/|SF:../|g' coverage.info
+
+ - name: Upload coverage info
+ if: startsWith(matrix.config.build_type, 'Debug')
+ env:
+ COVERALLS_DEBUG: true
+ NODE_COVERALLS_DEBUG: 1
+ uses: coverallsapp/github-action@master
+ with:
+ path-to-lcov: ${{ github.workspace }}/build/coverage.info
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+
diff --git a/gulrak-filesystem/.gitignore b/gulrak-filesystem/.gitignore
new file mode 100644
index 0000000..ac7a37a
--- /dev/null
+++ b/gulrak-filesystem/.gitignore
@@ -0,0 +1,7 @@
+/*build*/
+.vs/
+.vscode/
+.idea/
+*.swp
+*~
+.DS_Store
diff --git a/gulrak-filesystem/CMakeLists.txt b/gulrak-filesystem/CMakeLists.txt
new file mode 100644
index 0000000..f6b7f54
--- /dev/null
+++ b/gulrak-filesystem/CMakeLists.txt
@@ -0,0 +1,74 @@
+cmake_minimum_required(VERSION 3.7.2)
+project(ghcfilesystem)
+
+if (POLICY CMP0077)
+ cmake_policy(SET CMP0077 NEW)
+endif()
+if(POLICY CMP0110)
+ cmake_policy(SET CMP0110 NEW)
+endif()
+
+if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
+ option(GHC_FILESYSTEM_BUILD_TESTING "Enable tests" ON)
+ option(GHC_FILESYSTEM_BUILD_EXAMPLES "Build examples" ON)
+ option(GHC_FILESYSTEM_WITH_INSTALL "With install target" ON)
+else()
+ option(GHC_FILESYSTEM_BUILD_EXAMPLES "Build examples" OFF)
+ option(GHC_FILESYSTEM_BUILD_TESTING "Enable tests" OFF)
+ option(GHC_FILESYSTEM_WITH_INSTALL "With install target" ON)
+endif()
+option(GHC_FILESYSTEM_BUILD_STD_TESTING "Enable STD tests" ${GHC_FILESYSTEM_BUILD_TESTING})
+if(NOT DEFINED GHC_FILESYSTEM_TEST_COMPILE_FEATURES)
+ set(GHC_FILESYSTEM_TEST_COMPILE_FEATURES ${CMAKE_CXX_COMPILE_FEATURES})
+endif()
+
+if(NOT DEFINED CMAKE_CXX_STANDARD)
+ set(CMAKE_CXX_STANDARD 11)
+ set(CMAKE_CXX_STANDARD_REQUIRED ON)
+ if(NOT CYGWIN)
+ set(CMAKE_CXX_EXTENSIONS OFF)
+ endif()
+endif()
+if(CMAKE_CXX_STANDARD LESS 11)
+ message(FATAL_ERROR "CMAKE_CXX_STANDARD is less than 11, ghc::filesystem only works with C++11 and above.")
+endif()
+message(STATUS "CMAKE_CXX_COMPILE_FEATURES: ${CMAKE_CXX_COMPILE_FEATURES}")
+
+add_library(ghc_filesystem INTERFACE)
+target_include_directories(ghc_filesystem INTERFACE
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
+ $<INSTALL_INTERFACE:include>)
+target_compile_options(ghc_filesystem INTERFACE "$<$<C_COMPILER_ID:MSVC>:/utf-8>")
+target_compile_options(ghc_filesystem INTERFACE "$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
+
+if(GHC_FILESYSTEM_BUILD_TESTING OR GHC_FILESYSTEM_BUILD_EXAMPLES)
+ set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
+ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")
+ include(GhcHelper)
+
+ if(GHC_FILESYSTEM_BUILD_TESTING)
+ enable_testing()
+ add_subdirectory(test)
+ endif()
+
+ if(GHC_FILESYSTEM_BUILD_EXAMPLES)
+ add_subdirectory(examples)
+ endif()
+endif()
+
+if(GHC_FILESYSTEM_WITH_INSTALL)
+ include(CMakePackageConfigHelpers)
+ include(GNUInstallDirs)
+ install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
+ install(TARGETS ghc_filesystem EXPORT ghc_filesystem-targets)
+ install(EXPORT ghc_filesystem-targets NAMESPACE ghcFilesystem:: DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/ghc_filesystem")
+ export(EXPORT ghc_filesystem-targets NAMESPACE ghcFilesystem:: FILE "${CMAKE_CURRENT_BINARY_DIR}/cmake/ghc_filesystem-targets.cmake")
+ configure_package_config_file(
+ "${CMAKE_CURRENT_SOURCE_DIR}/cmake/config.cmake.in"
+ "${PROJECT_BINARY_DIR}/cmake/ghc_filesystem-config.cmake"
+ INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/ghc_filesystem"
+ PATH_VARS CMAKE_INSTALL_INCLUDEDIR)
+ install(FILES "${PROJECT_BINARY_DIR}/cmake/ghc_filesystem-config.cmake"
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/ghc_filesystem")
+ add_library(ghcFilesystem::ghc_filesystem ALIAS ghc_filesystem)
+endif()
diff --git a/gulrak-filesystem/LICENSE b/gulrak-filesystem/LICENSE
new file mode 100644
index 0000000..8b24faa
--- /dev/null
+++ b/gulrak-filesystem/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/gulrak-filesystem/README.md b/gulrak-filesystem/README.md
new file mode 100644
index 0000000..0e8901a
--- /dev/null
+++ b/gulrak-filesystem/README.md
@@ -0,0 +1,1062 @@
+![Supported Platforms](https://img.shields.io/badge/platform-macOS%20%7C%20Linux%20%7C%20Windows%20%7C%20FreeBSD-blue.svg)
+![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)
+[![CMake Build Matrix](https://github.com/gulrak/filesystem/actions/workflows/build_cmake.yml/badge.svg?branch=master)](https://github.com/gulrak/filesystem/actions/workflows/build_cmake.yml)
+[![Build Status](https://ci.appveyor.com/api/projects/status/t07wp3k2cddo0hpo/branch/master?svg=true)](https://ci.appveyor.com/project/gulrak/filesystem)
+[![Build Status](https://api.cirrus-ci.com/github/gulrak/filesystem.svg?branch=master)](https://cirrus-ci.com/github/gulrak/filesystem)
+[![Build Status](https://cloud.drone.io/api/badges/gulrak/filesystem/status.svg?ref=refs/heads/master)](https://cloud.drone.io/gulrak/filesystem)
+[![Coverage Status](https://coveralls.io/repos/github/gulrak/filesystem/badge.svg?branch=master)](https://coveralls.io/github/gulrak/filesystem?branch=master)
+[![Latest Release Tag](https://img.shields.io/github/tag/gulrak/filesystem.svg)](https://github.com/gulrak/filesystem/tree/v1.5.10)
+
+- [Filesystem](#filesystem)
+ - [Motivation](#motivation)
+ - [Why the namespace GHC?](#why-the-namespace-ghc)
+ - [Platforms](#platforms)
+ - [Tests](#tests)
+ - [Usage](#usage)
+ - [Downloads](#downloads)
+ - [Using it as Single-File-Header](#using-it-as-single-file-header)
+ - [Using it as Forwarding-/Implementation-Header](#using-it-as-forwarding-implementation-header)
+ - [Git Submodule and CMake](#git-submodule-and-cmake)
+ - [Versioning](#versioning)
+ - [Documentation](#documentation)
+ - [`ghc::filesystem::ifstream`, `ghc::filesystem::ofstream`, `ghc::filesystem::fstream`](#ghcfilesystemifstream-ghcfilesystemofstream-ghcfilesystemfstream)
+ - [`ghc::filesystem::u8arguments`](#ghcfilesystemu8arguments)
+ - [Differences](#differences)
+ - [LWG Defects](#lwg-defects)
+ - [Not Implemented on C++ before C++17](#not-implemented-on-c-before-c17)
+ - [Differences in API](#differences-in-api)
+ - [Differences of Specific Interfaces](#differences-of-specific-interfaces)
+ - [Differences in Behavior](#differences-in-behavior)
+ - [fs.path](#fspath-refhttpsencppreferencecomwcppfilesystempath)
+ - [Open Issues](#open-issues)
+ - [Windows](#windows)
+ - [Symbolic Links on Windows](#symbolic-links-on-windows)
+ - [Permissions](#permissions)
+ - [Release Notes](#release-notes)
+
+# Filesystem
+
+This is a header-only single-file `std::filesystem` compatible helper library,
+based on the C++17 and C++20 specs, but implemented for C++11, C++14, C++17 or C++20
+(tightly following the C++17 standard with very few documented exceptions). It is currently tested on
+macOS 10.12/10.14/10.15, Windows 10, Ubuntu 18.04, Ubuntu 20.04, CentOS 7, CentOS 8, FreeBSD 12
+and Alpine ARM/ARM64 Linux but should work on other systems too, as long as you have
+at least a C++11 compatible compiler. It should work with Android NDK, Emscripten and I even
+had reports of it being used on iOS (within sandboxing constraints) and with v1.5.6 there
+is experimental support for QNX. The support of Android NDK, Emscripten and QNX is not
+backed up by automated testing but PRs and bug reports are welcome for those too.
+It is of course in its own namespace `ghc::filesystem` to not interfere with a regular `std::filesystem`
+should you use it in a mixed C++17 environment (which is possible).
+
+*Test coverage is well above 90%, and starting with v1.3.6 and in v1.5.0
+more time was invested in benchmarking and optimizing parts of the library. I'll try
+to continue to optimize some parts and refactor others, striving
+to improve it as long as it doesn't introduce additional C++17/C++20 compatibility
+issues. Feedback is always welcome. Simply open an issue if you see something missing
+or wrong or not behaving as expected and I'll comment.*
+
+
+## Motivation
+
+I'm often in need of filesystem functionality, mostly `fs::path`, but directory
+access too, and when beginning to use C++11, I used that language update
+to try to reduce my third-party dependencies. I could drop most of what
+I used, but still missed some stuff that I started implementing for the
+fun of it. Originally I based these helpers on my own coding- and naming
+conventions. When C++17 was finalized, I wanted to use that interface,
+but it took a while, to push myself to convert my classes.
+
+The implementation is closely based on chapter 30.10 from the C++17 standard
+and a draft close to that version is
+[Working Draft N4687](https://github.com/cplusplus/draft/raw/master/papers/n4687.pdf).
+It is from after the standardization of C++17 but it contains the latest filesystem
+interface changes compared to the
+[Working Draft N4659](https://github.com/cplusplus/draft/raw/master/papers/n4659.pdf).
+Staring with v1.4.0, when compiled using C++20, it adapts to the changes according to path sorting order
+and `std::u8string` handling from [Working Draft N4860](https://isocpp.org/files/papers/N4860.pdf).
+
+I want to thank the people working on improving C++, I really liked how the language
+evolved with C++11 and the following standards. Keep on the good work!
+
+## Why the namespace GHC?
+If you ask yourself, what `ghc` is standing for, it is simply
+`gulraks helper classes`, yeah, I know, not very imaginative, but I wanted a
+short namespace and I use it in some of my private classes (so **it has nothing
+to do with Haskell**, sorry for the name clash).
+
+## Platforms
+
+`ghc::filesystem` is developed on macOS but CI tested on macOS, Windows,
+various Linux Distributions and FreeBSD. It should work on any of these with a C++11-capable
+compiler. Also there are some checks to hopefully better work on Android, but
+as I currently don't test with the Android NDK, I wouldn't call it a
+supported platform yet, same is valid for using it with Emscripten. It is now
+part of the detected platforms, I fixed the obvious issues and ran some tests with
+it, so it should be fine. All in all, I don't see it replacing `std::filesystem`
+where full C++17 or C++20 is available, it doesn't try to be a "better"
+`std::filesystem`, just an almost drop-in if you can't use it (with the exception
+of the UTF-8 preference).
+
+:information_source: **Important:** _This implementation is following the ["UTF-8 Everywhere" philosophy](https://utf8everywhere.org/) in that all
+`std::string` instances will be interpreted the same as `std::u8string` encoding
+wise and as being in UTF-8. The `std::u16string` will be seen as UTF-16. See *Differences in API*
+for more information._
+
+Unit tests are currently run with:
+
+* macOS 10.12: Xcode 9.2 (clang-900.0.39.2), GCC 9.2, Clang 9.0, macOS 10.13: Xcode 10.1, macOS 10.14: Xcode 11.2, macOS 10.15: Xcode 11.6, Xcode 12.4
+* Windows: Visual Studio 2017, Visual Studio 2015, Visual Studio 2019, MinGW GCC 6.3 (Win32), GCC 7.2 (Win64), Cygwin GCC 10.2 (no CI yet)
+* Linux (Ubuntu): GCC (5.5, 6.5, 7.4, 8.3, 9.2), Clang (5.0, 6.0, 7.1, 8.0, 9.0)
+* Linux (Alpine ARM/ARM64): GCC 9.2.0
+* FreeBSD: Clang 8.0
+
+
+## Tests
+
+The header comes with a set of unit-tests and uses [CMake](https://cmake.org/)
+as a build tool and [Catch2](https://github.com/catchorg/Catch2) as test framework.
+All tests are registered with in CMake, so the [ctest](https://cmake.org/cmake/help/latest/manual/ctest.1.html)
+commando can be used to run the tests.
+
+All tests against this implementation should succeed, depending on your environment
+it might be that there are some warnings, e.g. if you have no rights to create
+Symlinks on Windows or at least the test thinks so, but these are just informative.
+
+To build the tests from inside the project directory under macOS or Linux just:
+
+```cpp
+mkdir build
+cd build
+cmake -DCMAKE_BUILD_TYPE=Debug ..
+make
+ctest
+```
+
+This generates the test binaries that run the tests and the last command executes
+them.
+
+If the default compiler is a GCC 8 or newer, or Clang 7 or newer, it
+additionally tries to build a version of the test binary compiled against GCCs/Clangs
+`std::filesystem` implementation, named `std_filesystem_test`
+as an additional test of conformance. Ideally all tests should compile and
+succeed with all filesystem implementations, but in reality, there are
+some differences in behavior, sometimes due to room for interpretation in
+in the standard, and there might be issues in these implementations too.
+
+
+## Usage
+
+### Downloads
+
+The latest release version is [v1.5.10](https://github.com/gulrak/filesystem/tree/v1.5.10) and
+source archives can be found [here](https://github.com/gulrak/filesystem/releases/tag/v1.5.10).
+
+The latest pre-native-backend version is [v1.4.0](https://github.com/gulrak/filesystem/tree/v1.4.0) and
+source archives can be found [here](https://github.com/gulrak/filesystem/releases/tag/v1.4.0).
+
+The latest pre-C++20-support release version is [v1.3.10](https://github.com/gulrak/filesystem/tree/v1.3.10) and
+source archives can be found [here](https://github.com/gulrak/filesystem/releases/tag/v1.3.10).
+
+Currently only the latest minor release version receives bugfixes, so if possible,
+you should use the latest release.
+
+### Using it as Single-File-Header
+
+As `ghc::filesystem` is at first a header-only library, it should be enough to copy the header
+or the `include/ghc` directory into your project folder or point your include path to this place and
+simply include the `filesystem.hpp` header (or `ghc/filesystem.hpp` if you use the subdirectory).
+
+Everything is in the namespace `ghc::filesystem`, so one way to use it only as
+a fallback could be:
+
+```cpp
+#ifdef __APPLE__
+#include <Availability.h> // for deployment target to support pre-catalina targets without std::fs
+#endif
+#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
+#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
+#define GHC_USE_STD_FS
+#include <filesystem>
+namespace fs = std::filesystem;
+#endif
+#endif
+#ifndef GHC_USE_STD_FS
+#include <ghc/filesystem.hpp>
+namespace fs = ghc::filesystem;
+#endif
+```
+
+**Note that this code uses a two-stage preprocessor condition because Visual Studio 2015
+doesn't like the `(<...>)` syntax, even if it could cut evaluation early before. This code also
+used the minimum deployment target to detect if `std::filesystem` really is available on macOS
+compilation.**
+
+**Note also, this detection now works on MSVC versions prior to 15.7 on, or without setting
+the `/Zc:__cplusplus` compile switch that would fix `__cplusplus` on MSVC. (Without the switch
+the compiler always reports `199711L`
+([see](https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/)),
+but `_MSVC_LANG` works without it.**
+
+If you want to also use the `fstream` wrapper with `path` support as fallback,
+you might use:
+
+```cpp
+#ifdef __APPLE__
+#include <Availability.h> // for deployment target to support pre-catalina targets without std::fs
+#endif
+#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
+#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
+#define GHC_USE_STD_FS
+#include <filesystem>
+namespace fs {
+using namespace std::filesystem;
+using ifstream = std::ifstream;
+using ofstream = std::ofstream;
+using fstream = std::fstream;
+}
+#endif
+#endif
+#ifndef GHC_USE_STD_FS
+#include <ghc/filesystem.hpp>
+namespace fs {
+using namespace ghc::filesystem;
+using ifstream = ghc::filesystem::ifstream;
+using ofstream = ghc::filesystem::ofstream;
+using fstream = ghc::filesystem::fstream;
+}
+#endif
+```
+
+Now you have e.g. `fs::ofstream out(somePath);` and it is either the wrapper or
+the C++17 `std::ofstream`.
+
+:information_source: **Be aware, as a header-only library, it is not hiding the fact, that it
+uses system includes, so they "pollute" your global namespace. Use the
+forwarding-/implementation-header based approach (see below) to avoid this.
+For Windows it needs `Windows.h` and it might be a good idea to define
+`WIN32_LEAN_AND_MEAN` or `NOMINMAX` prior to including `filesystem.hpp` or
+`fs_std.hpp` headers to reduce pollution of your global namespace and compile
+time. They are not defined by `ghc::filesystem` to allow combination with contexts
+where the full `Windows.h`is needed, e.g. for UI elements.**
+
+:information_source: **Hint:** There is an additional header named `ghc/fs_std.hpp` that implements this
+dynamic selection of a filesystem implementation, that you can include
+instead of `ghc/filesystem.hpp` when you want `std::filesystem` where
+available and `ghc::filesystem` where not.
+
+
+### Using it as Forwarding-/Implementation-Header
+
+Alternatively, starting from v1.1.0 `ghc::filesystem` can also be used by
+including one of two additional wrapper headers. These allow to include
+a forwarded version in most places (`ghc/fs_fwd.hpp`) while hiding the
+implementation details in a single cpp file that includes `ghc/fs_impl.hpp` to
+implement the needed code. Using `ghc::filesystem` this way makes sure
+system includes are only visible from inside the cpp file, all other places are clean.
+
+Be aware, that it is currently not supported to hide the implementation
+into a Windows-DLL, as a DLL interface with C++ standard templates in interfaces
+is a different beast. If someone is willing to give it a try, I might integrate
+a PR but currently working on that myself is not a priority.
+
+If you use the forwarding/implementation approach, you can still use the dynamic
+switching like this:
+
+```cpp
+#ifdef __APPLE__
+#include <Availability.h> // for deployment target to support pre-catalina targets without std::fs
+#endif
+#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
+#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
+#define GHC_USE_STD_FS
+#include <filesystem>
+namespace fs {
+using namespace std::filesystem;
+using ifstream = std::ifstream;
+using ofstream = std::ofstream;
+using fstream = std::fstream;
+}
+#endif
+#endif
+#ifndef GHC_USE_STD_FS
+#include <ghc/fs-fwd.hpp>
+namespace fs {
+using namespace ghc::filesystem;
+using ifstream = ghc::filesystem::ifstream;
+using ofstream = ghc::filesystem::ofstream;
+using fstream = ghc::filesystem::fstream;
+}
+#endif
+```
+
+and in the implementation hiding cpp, you might use (before any include that includes `ghc/fs_fwd.hpp`
+to take precedence:
+
+```cpp
+#ifdef __APPLE__ // for deployment target to support pre-catalina targets without std::fs
+#include <Availability.h>
+#endif
+#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
+#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
+#define GHC_USE_STD_FS
+#endif
+#endif
+#ifndef GHC_USE_STD_FS
+#define GHC_FILESYSTEM_IMPLEMENTATION
+#include <ghc/filesystem.hpp>
+#endif
+```
+
+:information_source: **Hint:** There are additional helper headers, named `ghc/fs_std_fwd.hpp` and
+`ghc/fs_std_impl.hpp` that use this technique, so you can simply include them
+if you want to dynamically select the filesystem implementation. they also
+enable the `wchar_t` support on `ghc::filesystem` on Windows, so the resulting
+implementation in the `fs` namespace will be compatible.
+
+
+
+### Git Submodule and CMake
+
+Starting from v1.1.0, it is possible to add `ghc::filesystem`
+as a git submodule, add the directory to your `CMakeLists.txt` with
+`add_subdirectory()` and then simply use `target_link_libraries(your-target ghc_filesystem)`
+to ensure correct include path that allow `#include <ghc/filesystem.hpp>`
+to work.
+
+The `CMakeLists.txt` offers a few options to customize its behavior:
+
+* `GHC_FILESYSTEM_BUILD_TESTING` - Compile tests, default is `OFF` when used as
+ a submodule, else `ON`.
+* `GHC_FILESYSTEM_BUILD_EXAMPLES` - Compile the examples, default is `OFF` when used as
+ a submodule, else `ON`.
+* `GHC_FILESYSTEM_WITH_INSTALL` - Add install target to build, default is `OFF` when used as
+ a submodule, else `ON`.
+* `GHC_FILESYSTEM_BUILD_STD_TESTING` - Compile `std_filesystem_test`, the variant of
+ the test suite running against `std::filesystem`, defaulting to `GHC_FILESYSTEM_BUILD_TESTING`.
+ This is only done if the compiler is detected as being able to do it.
+* `GHC_FILESYSTEM_TEST_COMPILE_FEATURES` can be set to a list of features to override
+ `CMAKE_CXX_COMPILE_FEATURES` when the detection of C++17 or C++20 for additional tests
+ is not working (e.g. `cxx_std_20` to enforce building a `filesystem_test_cpp20` with C++20).
+
+### Versioning
+
+There is a version macro `GHC_FILESYSTEM_VERSION` defined in case future changes
+might make it needed to react on the version, but I don't plan to break anything.
+It's the version as decimal number `(major * 10000 + minor * 100 + patch)`.
+
+:information_source: **Note:** Only even patch versions will be used for releases
+and odd patch version will only be used for in between commits while working on
+the next version.
+
+
+## Documentation
+
+There is almost no documentation in this release, as any `std::filesystem`
+documentation would work, besides the few differences explained in the next
+section. So you might head over to https://en.cppreference.com/w/cpp/filesystem
+for a description of the components of this library.
+
+When compiling with C++11, C++14 or C++17, the API is following the C++17
+standard, where possible, with the exception that `std::string_view` parameters
+are only supported on C++17. When Compiling with C++20, `ghc::filesysytem`
+defaults to the C++20 API, with the `char8_t` and `std::u8string` interfaces
+and the deprecated `fs::u8path` factory method.
+
+:information_source: **Note:** If the C++17 API should be enforced even in C++20 mode,
+use the define `GHC_FILESYSTEM_ENFORCE_CPP17_API`.
+Even then it is possible to create `fws::path` from `std::u8string` but
+`fs::path::u8string()` and `fs::path::generic_u8string()` return normal
+UTF-8 encoded `std::string` instances, so code written for C++17 could
+still work with `ghc::filesystem` when compiled with C++20.
+
+The only additions to the standard are documented here:
+
+
+### `ghc::filesystem::ifstream`, `ghc::filesystem::ofstream`, `ghc::filesystem::fstream`
+
+These are simple wrappers around `std::ifstream`, `std::ofstream` and `std::fstream`.
+They simply add an `open()` method and a constructor with an `ghc::filesystem::path`
+argument as the `fstream` variants in C++17 have them.
+
+### `ghc::filesystem::u8arguments`
+
+This is a helper class that currently checks for UTF-8 encoding on non-Windows platforms but on Windows it
+fetches the command line arguments as Unicode strings from the OS with
+
+```cpp
+::CommandLineToArgvW(::GetCommandLineW(), &argc)
+```
+
+and then converts them to UTF-8, and replaces `argc` and `argv`. It is a guard-like
+class that reverts its changes when going out of scope.
+
+So basic usage is:
+
+```cpp
+namespace fs = ghc::filesystem;
+
+int main(int argc, char* argv[])
+{
+ fs::u8arguments u8guard(argc, argv);
+ if(!u8guard.valid()) {
+ std::cerr << "Bad encoding, needs UTF-8." << std::endl;
+ exit(EXIT_FAILURE);
+ }
+
+ // now use argc/argv as usual, they have utf-8 enconding on windows
+ // ...
+
+ return 0;
+}
+```
+
+That way `argv` is UTF-8 encoded as long as the scope from `main` is valid.
+
+**Note:** On macOS, while debugging under Xcode the code currently will return
+`false` as Xcode starts the application with `US-ASCII` as encoding, no matter what
+encoding is actually used and even setting `LC_ALL` in the product scheme doesn't
+change anything. I still need to investigate this.
+
+
+## Differences
+
+As this implementation is based on existing code from my private helper
+classes, it derived some constraints of it. Starting from v1.5.0 most of the
+differences between this and the standard C++17/C++20 API where removed.
+
+
+### LWG Defects
+
+This implementation has switchable behavior for the LWG defects
+[#2682](https://wg21.cmeerw.net/lwg/issue2682),
+[#2935](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2935),
+[#2936](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2936) and
+[#2937](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2937).
+The currently selected behavior (starting from v1.4.0) is following
+[#2682](https://wg21.cmeerw.net/lwg/issue2682), [#2936](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2936),
+[#2937](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2937) but
+not following [#2935](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2935),
+as I feel it is a bug to report no error on a `create_directory()` or `create_directories()`
+where a regular file of the same name prohibits the creation of a directory and forces
+the user of those functions to double-check via `fs::is_directory` if it really worked.
+The more intuitive approach to directory creation of treating a file with that name as an
+error is also advocated by the newer paper
+[WG21 P1164R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1164r0.pdf), the revision
+P1161R1 was agreed upon on Kona 2019 meeting [see merge](https://github.com/cplusplus/draft/issues/2703)
+and GCC by now switched to following its proposal
+([GCC #86910](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86910)).
+
+### Not Implemented on C++ before C++17
+
+```cpp
+// methods in ghc::filesystem::path:
+path& operator+=(basic_string_view<value_type> x);
+int compare(basic_string_view<value_type> s) const;
+```
+
+These are not implemented under C++11 and C++14, as there is no
+`std::basic_string_view` available and I did want to keep this
+implementation self-contained and not write a full C++17-upgrade for
+C++11/14. Starting with v1.1.0 these are supported when compiling
+`ghc::filesystem` under C++17 of C++20.
+
+Starting with v1.5.2 `ghc::filesystem` will try to allow the use of
+`std::experimental::basic_string_view` where it detects is availability.
+Additionally if you have a `basic_string_view` compatible c++11
+implementation it can be used instead of `std::basic_string_view`
+by defining `GHC_HAS_CUSTOM_STRING_VIEW` and importing the
+implementation into the `ghc::filesystem` namespace with:
+
+```cpp
+namespace ghc {
+ namespace filesystem {
+ using my::basic_string_view;
+ }
+}
+```
+
+before including the filesystem header.
+
+### Differences in API
+
+To not depend on any external third party libraries and still stay portable and
+compact, this implementation is following the ["UTF-8 Everywhere" philosophy](https://utf8everywhere.org/) in that all
+`std::string` instances will be interpreted the same as `std::u8string` encoding
+wise and as being in UTF-8. The `std::u16string` will be seen as UTF-16 and `std::u32string` will be
+seen as Unicode codepoints. Depending on the size of `std::wstring` characters, it will handle
+`std::wstring` as being UTF-16 (e.g. Windows) or `char32_t` Unicode codepoints
+(currently all other platforms).
+
+#### Differences of Specific Interfaces
+
+Starting with v1.5.0 `ghc::filesystem` is following the C++17 standard in
+using `wchar_t` and `std::wstring` on Windows as the types internally used
+for path representation. It is still possible to get the old behavior by defining
+`GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE` and get `filesystem::path::string_type` as
+`std::string` and `filesystem::path::value_type` as `wchar_t`.
+
+If you need to call some Windows API, with v1.5.0 and above, simply
+use the W-variant of the Windows-API call (e.g. `GetFileAttributesW(p.c_str())`).
+
+:information_source: **Note:** _When using the old behavior by defining
+`GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE`, use the `path::wstring()` member
+(e.g. `GetFileAttributesW(p.wstring().c_str())`). This gives you the
+Unicode variant independent of the `UNICODE` macro and makes sharing code
+between Windows, Linux and macOS easier and works with `std::filesystem` and
+`ghc::filesystem`._
+
+```cpp
+std::string path::u8string() const;
+std::string path::generic_u8string() const;
+vs.
+std::u8string path::u8string() const;
+std::u8string path::generic_u8string() const;
+```
+
+The return type of these two methods is depending on the used C++ standard
+and if `GHC_FILESYSTEM_ENFORCE_CPP17_API` is defined. On C++11, C++14 and
+C++17 or when `GHC_FILESYSTEM_ENFORCE_CPP17_API` is defined, the return
+type is `std::string`, and on C++20 without the define it is `std::u8string`.
+
+### Differences in Behavior
+
+I created a wiki entry about quite a lot of [behavioral differences](https://github.com/gulrak/filesystem/wiki/Differences-to-Standard-Filesystem-Implementations)
+between different `std::filesystem` implementations that could result in a
+mention here, but this readme only tries to address the design choice
+differences between `ghc::filesystem` and those. I try to update the wiki page
+from time to time.
+
+Any additional observations are welcome!
+
+#### fs.path ([ref](https://en.cppreference.com/w/cpp/filesystem/path))
+
+Since v1.5.0 the complete inner mechanics of this implementations `fs::path`
+where changed to the _native_ format as the internal representation.
+Creating any mixed slash `fs::path` object under Windows (e.g. with `"C:\foo/bar"`)
+will lead clean path with `"C:\foo\bar"` via `native()` and `"C:/foo/bar"` via
+`generic_string()` API. On all platforms redundant additional separators are
+removed, even if this is not enforced by the standard and other implementations
+mostly not do this.
+
+Additionally this implementation follows the standards suggestion to handle
+posix paths of the form `"//host/path"` and USC path on windows also as having
+a root-name (e.g. `"//host"`). The GCC implementation didn't choose to do that
+while testing on Ubuntu 18.04 and macOS with GCC 8.1.0 or Clang 7.0.0. This difference
+will show as warnings under `std::filesystem`. This leads to a change in the
+algorithm described in the standard for `operator/=(path& p)` where any path
+`p` with `p.is_absolute()` will degrade to an assignment, while this implementation
+has the exception where `*this == *this.root_name()` and `p == preferred_separator`
+a normal append will be done, to allow:
+
+```cpp
+fs::path p1 = "//host/foo/bar/file.txt";
+fs::path p2;
+for (auto p : p1) p2 /= p;
+ASSERT(p1 == p2);
+```
+
+For all non-host-leading paths the behavior will match the one described by
+the standard.
+
+
+## Open Issues
+
+### Windows
+
+#### Symbolic Links on Windows
+
+As symbolic links on Windows, while being supported more or less since
+Windows Vista (with some strict security constraints) and fully since some earlier
+build of Windows 10, when "Developer Mode" is activated, are at time of writing
+(2018) rarely used, still they are supported wiit th this implementation.
+
+#### Permissions
+
+The Windows ACL permission feature translates badly to the POSIX permission
+bit mask used in the interface of C++17 filesystem. The permissions returned
+in the `file_status` are therefore currently synthesized for the `user`-level
+and copied to the `group`- and `other`-level. There is still some potential
+for more interaction with the Windows permission system, but currently setting
+or reading permissions with this implementation will most certainly not lead
+to the expected behavior.
+
+
+## Release Notes
+
+### [v1.5.10](https://github.com/gulrak/filesystem/releases/tag/v1.5.10)
+
+* Pull request [#136](https://github.com/gulrak/filesystem/pull/136), the Windows
+ implementation used some unnecessary expensive shared pointer for resource
+ management and these where replaced by a dedicated code.
+* Fix for [#132](https://github.com/gulrak/filesystem/issues/132), pull request
+ [#135](https://github.com/gulrak/filesystem/pull/135), `fs::remove_all` now
+ just deletes symbolic links instead of following them.
+* Pull request [#133](https://github.com/gulrak/filesystem/pull/133), fix for
+ `fs::space` where a numerical overflow could happen in a multiplication.
+* Replaced _travis-ci.org_ with GitHub Workflow for the configurations:
+ Ubuntu 20.04: GCC 9.3, Ubuntu 18.04: GCC 7.5, GCC 8.4, macOS 10.15: Xcode 12.4,
+ Windows 10: Visual Studio 2019
+
+### [v1.5.8](https://github.com/gulrak/filesystem/releases/tag/v1.5.8)
+
+* Fix for [#125]((https://github.com/gulrak/filesystem/issues/124), where
+ `fs::create_directories` on Windows no longer breaks on long filenames.
+
+### [v1.5.6](https://github.com/gulrak/filesystem/releases/tag/v1.5.6)
+
+* Fix for [#124](https://github.com/gulrak/filesystem/issues/124),
+ `ghc::filesystem` treated mounted folder/volumes erroneously as symlinks,
+ leading `fs::canonical` to fail on paths containing those.
+* Fix for [#122](https://github.com/gulrak/filesystem/issues/122), incrementing
+ the `recursive_directory_iterator` will not try to enter dead symlinks.
+* Fix for [#121](https://github.com/gulrak/filesystem/issues/121), on Windows
+ backend the `fs::remove` failed when the path pointed to a read-only entry,
+ see also ([microsoft/STL#1511](https://github.com/microsoft/STL/issues/1511))
+ for the corresponding issue in `std::fs` on windows.
+* Fix for [#119](https://github.com/gulrak/filesystem/issues/119), added missing
+ support for char16_t and char32_t and on C++20 char8_t literals.
+* Pull request [#118](https://github.com/gulrak/filesystem/pull/118), when
+ running tests as root, disable tests that would not work.
+* Pull request [#117](https://github.com/gulrak/filesystem/pull/117), added
+ checks to tests to detect the clang/libstdc++ combination.
+* Fix for [#116](https://github.com/gulrak/filesystem/issues/116), internal
+ macro `GHC_NO_DIRENT_D_TYPE` allows os detection to support systems without
+ the `dirent.d_type` member, experimental first QNX compile support as
+ initial use case, fixed issue with filesystems returning DT_UNKNOWN
+ (e.g. reiserfs).
+* Pull request [#115](https://github.com/gulrak/filesystem/pull/115), added
+ `string_view` support when clang with libstdc++ is detected.
+* Fix for [#114](https://github.com/gulrak/filesystem/issues/114), for macOS
+ the pre-Catalina deployment target detection worked only if `<Availability.h>`
+ was included before `<ghc/fs_std.hpp>` or `<ghc/fs_std_fwd.hpp>`/`<ghc/fs_std_impl.hpp>`.
+* Fix for [#113](https://github.com/gulrak/filesystem/issues/113), the use of
+ standard chapter numbers was misleading since C++17 and C++20 `std::filesystem`
+ features are supported, and was replaced by the tag-like chapter names that
+ stay (mostly) consistent over the versions.
+
+### [v1.5.4](https://github.com/gulrak/filesystem/releases/tag/v1.5.4)
+
+* Pull request [#112](https://github.com/gulrak/filesystem/pull/112), lots
+ of cleanup work on the readme, thanks!
+* Enhancement for [#111](https://github.com/gulrak/filesystem/issues/111),
+ further optimization of directory iteration, performance for
+ `recursive_directory_iterator` over large trees now somewhere between
+ libc++ and libstdc++.
+* Enhancement for [#110](https://github.com/gulrak/filesystem/issues/110),
+ `ghc::filesystem` now has preliminary support for Cygwin. Changes where
+ made to allow the tests to compile and run successfully (tested with GCC
+ 10.2.0), feedback and additional PRs welcome as it is currently not
+ part of the CI configuration.
+* Pull request [#109](https://github.com/gulrak/filesystem/pull/109), various
+ spelling errors in error messages and comments fixed.
+* Pull request [#108](https://github.com/gulrak/filesystem/pull/108), old
+ style casts removed.
+* Fix for [#107](https://github.com/gulrak/filesystem/issues/107), the error
+ handling for status calls was suppressing errors on symlink targets.
+* Pull request [#106](https://github.com/gulrak/filesystem/pull/106), fixed
+ detection of AppleClang for compile options.
+* Pull request [#105](https://github.com/gulrak/filesystem/pull/105), added
+ option `GHC_FILESYSTEM_BUILD_STD_TESTING` to override additional build of
+ `std::filesystem` versions of the tests for comparison and the possibility
+ to use `GHC_FILESYSTEM_TEST_COMPILE_FEATURES` to prefill the used compile
+ features defaulting to `CMAKE_CXX_COMPILE_FEATURES` when not given.
+
+### [v1.5.2](https://github.com/gulrak/filesystem/releases/tag/v1.5.2)
+
+* Enhancement [#104](https://github.com/gulrak/filesystem/issues/104),
+ on POSIX backend: optimized reuse of status information and reduced
+ `directory_entry` creation leads to about 20%-25% in tests with
+ `recursive_directory_iterator` over a larger directory tree.
+* Pull request [#103](https://github.com/gulrak/filesystem/pull/103), `wchar_t`
+ was not in the list of supported char types on non-Windows backends.
+* Pull request [#102](https://github.com/gulrak/filesystem/pull/102), improved
+ `string_view` support makes use of `<string_view>` or `<experimental/string_view>`
+ when available, and allows use of custom `basic_string_view` implementation
+ when defining `GHC_HAS_CUSTOM_STRING_VIEW` and importing the string view
+ into the `ghc::filesystem` namespace before including filesystem header.
+* Pull request [#101](https://github.com/gulrak/filesystem/pull/101), fix for
+ [#100](https://github.com/gulrak/filesystem/issues/100), append and concat
+ type of operations on path called redundant conversions.
+* Pull request [#98](https://github.com/gulrak/filesystem/pull/98), on older
+ linux variants (GCC 7/8), the comparison `std::filesystem` tests now link
+ with `-lrt` to avoid issues.
+* Fix for [#97](https://github.com/gulrak/filesystem/issues/97), on BTRFS the
+ test case for `fs::hard_link_count` failed due to the filesystems behavior,
+ the test case was adapted to take that into account.
+* Pull request [#96](https://github.com/gulrak/filesystem/pull/96), the export
+ attribute defines `GHC_FS_API` and `GHC_FS_API_CLASS` are now honored when when
+ set from outside to allow override of behavior.
+* Fix for [#95](https://github.com/gulrak/filesystem/issues/95), the syntax for
+ disabling the deprecated warning in tests in MSVC was wrong.
+* Pull request [#93](https://github.com/gulrak/filesystem/pull/93), now the
+ CMake configuration file is configured and part of the `make install` files.
+
+### [v1.5.0](https://github.com/gulrak/filesystem/releases/tag/v1.5.0)
+
+* Fix for [#91](https://github.com/gulrak/filesystem/issues/91), the way
+ the CMake build options `GHC_FILESYSTEM_BUILD_TESTING`, `GHC_FILESYSTEM_BUILD_EXAMPLES`
+ and `GHC_FILESYSTEM_WITH_INSTALL` where implemented, prohibited setting them
+ from a parent project when using this via `add_subdirectory`, this fix
+ allows to set them again.
+* Major refactoring for [#90](https://github.com/gulrak/filesystem/issues/90),
+ the way, the Windows version of `fs::path` was originally created from the
+ POSIX based implementation was, by adaption of the incoming and outgoing
+ strings. This resulted in a mutable cache inside `fs::path`on Windows, that
+ was inherently not thread-safe, even for `const` methods.
+ To not add additional patches to a suboptimal solution, this time I reworked
+ the `path` code to now store _native_ path-representation. This changed a
+ lot of code, but when combined with `wchar_t` as `value_type` helped to avoid
+ lots of conversion for calls to Win-API.<br>
+ As interfaces where changed, it had to be released in a new minor version.
+ The set of refactorings resulted in the following changes:
+ * `fs::path::native()` and `fs::path::c_str()` can now be `noexcept` as the
+ standard mandates
+ * On Windows `wchar_t` is now the default for `fs::path::value_type` and
+ `std::wstring` is the default for `fs::path::string_type`.
+ * This allows the implementation to call Win-API without allocating
+ conversions
+ * Thread-safety on `const` methods of `fs::path` is no longer an issue
+ * Some code could be simplified during this refactoring
+ * Automatic prefixing of long path on Windows can now be disabled with
+ defining `GHC_WIN_DISABLE_AUTO_PREFIXES`, for all other types of prefixes
+ or namespaces the behavior follows that of MSVC `std::filesystem::path`
+ * In case the old `char`/`std::string` based approach for Windows is still
+ needed, it can be activated with `GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE`
+* Enhancement for [#89](https://github.com/gulrak/filesystem/issues/89), `fs::file_status`
+ now supports `operator==` introduced in `std::filesystem` with C++20.
+* Refactoring for [#88](https://github.com/gulrak/filesystem/issues/88), `fs::path::parent_path()`
+ had a performance issue, as it was still using a loop based approach to recreate
+ the parent from elements. This created lots of temporaries and was too slow
+ especially on long paths.
+
+### [v1.4.0](https://github.com/gulrak/filesystem/releases/tag/v1.4.0)
+
+* Enhancements for [#71](https://github.com/gulrak/filesystem/issues/71), when compiled with C++20:
+ * `char8_t` and `std::u8string` are supported where `Source` is the parameter type
+ * `fs::path::u8string()` and `fs::path::generic_u8string()` now return a `std::u8string`
+ * The _spaceship operator_ `<=>` is now supported for `fs::path`
+ * With the define `GHC_FILESYSTEM_ENFORCE_CPP17_API` `ghc::filesystem` will fall back
+ to the old `fs::path::u8string()` and `fs::path::generic_u8string()` API if preferred
+* Bugfix for `fs::proximate(p, ec)` where the internal call to `fs::current_path()` was not
+ using the `error_code` variant, throwing possible exceptions instead of setting `ec`.
+* Enhancement `LWG_2936_BEHAVIOUR` is now on by default.
+* Some cleanup work to reduce preprocessor directives for better readability and remove unneeded
+ template specializations.
+
+### [v1.3.10](https://github.com/gulrak/filesystem/releases/tag/v1.3.10)
+
+* Fix for [#81](https://github.com/gulrak/filesystem/issues/81), fixed issues with
+ handling `Source` parameters that are string views.
+* Fix for [#79](https://github.com/gulrak/filesystem/issues/79), the bit operations
+ for filesystem bitmasks that should be are now `constexpr`.
+
+### [v1.3.8](https://github.com/gulrak/filesystem/releases/tag/v1.3.8)
+
+* Refactoring for [#78](https://github.com/gulrak/filesystem/issues/78), the dynamic
+ switching helper includes are now using `__MAC_OS_X_VERSION_MIN_REQUIRED` to
+ ensure that `std::filesystem` is only selected on macOS if the deployment target is
+ at least Catalina.
+* Bugfix for [#77](https://github.com/gulrak/filesystem/issues/77), the `directory_iterator`
+ and the `recursive_directory_iterator` had an issue with the `skip_permission_denied`
+ option, that leads to the inability to skip SIP protected folders on macOS.
+* Enhancement for [#76](https://github.com/gulrak/filesystem/issues/76), `_MSVC_LANG` is
+ now used when available, additionally to `__cplusplus`, in the helping headers to
+ allow them to work even when `/Zc:__cplusplus` is not used.
+* Bugfix for [#75](https://github.com/gulrak/filesystem/issues/75), NTFS reparse points
+ to mapped volumes where handled incorrect, leading to `false` on `fs::exists` or
+ not-found-errors on `fs::status`. Namespaced paths are not filtered anymore.
+
+### [v1.3.6](https://github.com/gulrak/filesystem/releases/tag/v1.3.6)
+
+* Pull request [#74](https://github.com/gulrak/filesystem/pull/74), on Windows symlink
+ evaluation used the wrong reparse struct information and was not handling the case
+ of relative paths well, thanks for the contribution.
+* Refactoring for [#73](https://github.com/gulrak/filesystem/issues/73), enhanced performance
+ in path handling. the changes lead to much fewer path/string creations or copies, speeding
+ up large directory iteration or operations on many path instances.
+* Bugfix for [#72](https://github.com/gulrak/filesystem/issues/72), the `TestAllocator` in
+ `filesystem_test.cpp` was completed to fulfill the requirements to build on CentOS 7 with
+ `devtoolset-9`. CentOS 7 and CentOS 8 are now part of the CI builds.
+* Bugfix for [#70](https://github.com/gulrak/filesystem/issues/70), root names are now case
+ insensitive on Windows. This fix also adds the new behavior switch `LWG_2936_BEHAVIOUR`
+ that allows to enable post C++17 `fs::path::compare` behavior, where the comparison is as
+ if it was an element wise path comparison as described in
+ [LWG 2936](https://cplusplus.github.io/LWG/issue2936) and C++20 `[fs.path.compare]`.
+ It is default off in v1.3.6 and will be default starting from v1.4.0 as it changes ordering.
+
+### [v1.3.4](https://github.com/gulrak/filesystem/releases/tag/v1.3.4)
+
+* Pull request [#69](https://github.com/gulrak/filesystem/pull/69), use `wchar_t` versions of
+ `std::fstream` from `ghc::filesystem::fstream` wrappers on Windows if using GCC with libc++.
+* Bugfix for [#68](https://github.com/gulrak/filesystem/issues/68), better handling of
+ permission issues for directory iterators when using `fs::directory_options::skip_permission_denied`
+ and initial support for compilation with emscripten.
+* Refactoring for [#66](https://github.com/gulrak/filesystem/issues/63), unneeded shared_ptr guards
+ where removed and the file handles closed where needed to avoid unnecessary allocations.
+* Bugfix for [#63](https://github.com/gulrak/filesystem/issues/63), fixed issues on Windows
+ with clang++ and C++17.
+* Pull request [#62](https://github.com/gulrak/filesystem/pull/62), various fixes for
+ better Android support, thanks for the PR
+* Pull request [#61](https://github.com/gulrak/filesystem/pull/61), `ghc::filesystem` now
+ supports use in projects with disabled exceptions. API signatures using exceptions for
+ error handling are not available in this mode, thanks for the PR (this resolves
+ [#60](https://github.com/gulrak/filesystem/issues/60) and
+ [#43](https://github.com/gulrak/filesystem/issues/43))
+
+### [v1.3.2](https://github.com/gulrak/filesystem/releases/tag/v1.3.2)
+
+* Bugfix for [#58](https://github.com/gulrak/filesystem/issues/58), on MinGW the
+ compilation could fail with an error about an undefined `ERROR_FILE_TOO_LARGE`
+ constant.
+* Bugfix for [#56](https://github.com/gulrak/filesystem/issues/58), `fs::lexically_relative`
+ didn't ignore trailing slash on the base parameter, thanks for PR
+ [#57](https://github.com/gulrak/filesystem/pull/57).
+* Bugfix for [#55](https://github.com/gulrak/filesystem/issues/55), `fs::create_directories`
+ returned `true` when nothing needed to be created, because the directory already existed.
+* Bugfix for [#54](https://github.com/gulrak/filesystem/issues/54), `error_code`
+ was not reset, if cached result was returned.
+* Pull request [#53](https://github.com/gulrak/filesystem/pull/53), fix for wrong
+ handling of leading whitespace when reading `fs::path` from a stream.
+* Pull request [#52](https://github.com/gulrak/filesystem/pull/52), an ARM Linux
+ target is now part of the CI infrastructure with the service of Drone CI.
+* Pull request [#51](https://github.com/gulrak/filesystem/pull/51), FreeBSD is now
+ part of the CI infrastructure with the service of Cirrus CI.
+* Pull request [#50](https://github.com/gulrak/filesystem/pull/50), adaptive cast to
+ `timespec` fields to avoid warnings.
+
+### [v1.3.0](https://github.com/gulrak/filesystem/releases/tag/v1.3.0)
+
+* **Important: `ghc::filesystem` is re-licensed from BSD-3-Clause to MIT license.** (see
+ [#47](https://github.com/gulrak/filesystem/issues/47))
+* Pull request [#46](https://github.com/gulrak/filesystem/pull/46), suppresses
+ unused parameter warning on Android.
+* Bugfix for [#44](https://github.com/gulrak/filesystem/issues/44), fixes
+ for warnings from newer Xcode versions.
+
+### [v1.2.10](https://github.com/gulrak/filesystem/releases/tag/v1.2.10)
+
+* The Visual Studio 2019 compiler, GCC 9.2 and Clang 9.0 where added to the
+ CI configuration.
+* Bugfix for [#41](https://github.com/gulrak/filesystem/issues/41), `fs::rename`
+ on Windows didn't replace an existing regular file as required by the standard,
+ but gave an error. New tests and a fix as provided in the issue was implemented.
+* Bugfix for [#39](https://github.com/gulrak/filesystem/issues/39), for the
+ forwarding use via `fs_fwd.hpp` or `fs_std_fwd.hpp` there was a use of
+ `DWORD` in the forwarding part leading to an error if `Windows.h` was not
+ included before the header. The tests were changed to give an error in that
+ case too and the useage of `DWORD` was removed.
+* Bugfix for [#38](https://github.com/gulrak/filesystem/issues/38), casting the
+ return value of `GetProcAddress` gave a warning with `-Wcast-function-type`
+ on MSYS2 and MinGW GCC 9 builds.
+
+### [v1.2.8](https://github.com/gulrak/filesystem/releases/tag/v1.2.8)
+
+* Pull request [#30](https://github.com/gulrak/filesystem/pull/30), the
+ `CMakeLists.txt` will automatically exclude building examples and tests when
+ used as submodule, the configuration options now use a prefixed name to
+ reduce risk of conflicts.
+* Pull request [#24](https://github.com/gulrak/filesystem/pull/24), install
+ target now creates a `ghcFilesystemConfig.cmake` in
+ `${CMAKE_INSTALL_LIBDIR}/cmake/ghcFilesystem` for `find_package` that
+ exports a target as `ghcFilesystem::ghc_filesystem`.
+* Pull request [#31](https://github.com/gulrak/filesystem/pull/31), fixes
+ `error: redundant redeclaration of 'constexpr' static data member` deprecation
+ warning in C++17 mode.
+* Pull request [#32](https://github.com/gulrak/filesystem/pull/32), fixes
+ old-style-cast warnings.
+* Pull request [#34](https://github.com/gulrak/filesystem/pull/34), fixes
+ [TOCTOU](https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use) situation
+ on `fs::create_directories`, thanks for the PR!
+* Feature [#35](https://github.com/gulrak/filesystem/issues/35), new CMake
+ option to add an install target `GHC_FILESYSTEM_WITH_INSTALL` that is
+ defaulted to OFF if `ghc::filesystem` is used via `add_subdirectory`.
+* Bugfix for [#33](https://github.com/gulrak/filesystem/issues/33), fixes
+ an issue with `fs::path::lexically_normal()` that leaves a trailing separator
+ in case of a resulting path ending with `..` as last element.
+* Bugfix for [#36](https://github.com/gulrak/filesystem/issues/36), warnings
+ on Xcode 11.2 due to unhelpful references in path element iteration.
+
+### [v1.2.6](https://github.com/gulrak/filesystem/releases/tag/v1.2.6)
+
+* Pull request [#23](https://github.com/gulrak/filesystem/pull/23), tests and
+ examples can now be disabled in CMake via setting `BUILD_TESTING` and
+ `BUILD_EXAMPLES` to `NO`, `OFF` or `FALSE`.
+* Pull request [#25](https://github.com/gulrak/filesystem/pull/25),
+ missing specialization for construction from `std::string_view` when
+ available was added.
+* Additional test case when `std::string_view` is available.
+* Bugfix for [#27](https://github.com/gulrak/filesystem/issues/27), the
+ `fs::path::preferred_separator` declaration was not compiling on pre
+ C++17 compilers and no test accessed it, to show the problem. Fixed
+ it to an construction C++11 compiler should accept and added a test that
+ is successful on all combinations tested.
+* Bugfix for [#29](https://github.com/gulrak/filesystem/issues/29), stricter
+ warning settings where chosen and resulting warnings where fixed.
+
+### [v1.2.4](https://github.com/gulrak/filesystem/releases/tag/v1.2.4)
+
+* Enabled stronger warning switches and resulting fixed issues on GCC and MinGW
+* Bugfix for #22, the `fs::copy_options` where not forwarded from `fs::copy` to
+ `fs::copy_file` in one of the cases.
+
+### [v1.2.2](https://github.com/gulrak/filesystem/releases/tag/v1.2.2)
+
+* Fix for ([#21](https://github.com/gulrak/filesystem/pull/21)), when compiling
+ on Alpine Linux with musl instead of glibc, the wrong `strerror_r` signature
+ was expected. The complex preprocessor define mix was dropped in favor of
+ the usual dispatch by overloading a unifying wrapper.
+
+### [v1.2.0](https://github.com/gulrak/filesystem/releases/tag/v1.2.0)
+
+* Added MinGW 32/64 and Visual Studio 2015 builds to the CI configuration.
+* Fixed additional compilation issues on MinGW.
+* Pull request ([#13](https://github.com/gulrak/filesystem/pull/13)), set
+ minimum required CMake version to 3.7.2 (as in Debian 8).
+* Pull request ([#14](https://github.com/gulrak/filesystem/pull/14)), added
+ support for a make install target.
+* Bugfix for ([#15](https://github.com/gulrak/filesystem/issues/15)), the
+ forward/impl way of using `ghc::filesystem` missed a `<vector>` include
+ in the windows case.
+* Bugfix for ([#16](https://github.com/gulrak/filesystem/issues/16)),
+ VS2019 didn't like the old size dispatching in the utf8 decoder, so it
+ was changed to a sfinae based approach.
+* New feature ([#17](https://github.com/gulrak/filesystem/issues/17)), optional
+ support for standard conforming `wchar_t/std::wstring` interface when
+ compiling on Windows with defined `GHC_WIN_WSTRING_STRING_TYPE`, this is
+ default when using the `ghc/fs_std*.hpp` header, to enhance compatibility.
+* New feature ([#18](https://github.com/gulrak/filesystem/issues/18)), optional
+ filesystem exceptions/errors on Unicode errors with defined
+ `GHC_RAISE_UNICODE_ERRORS` (instead of replacing invalid code points or
+ UTF-8 encoding errors with the replacement character `U+FFFD`).
+* Pull request ([#20](https://github.com/gulrak/filesystem/pull/20)), fix for
+ file handle leak in `fs::copy_file`.
+* Coverage now checked in CI (~95% line coverage).
+
+### [v1.1.4](https://github.com/gulrak/filesystem/releases/tag/v1.1.4)
+
+* Additional Bugfix for ([#12](https://github.com/gulrak/filesystem/issues/12)),
+ error in old unified `readdir/readdir_r` code of `fs::directory_iterator`;
+ as `readdir_r` is now deprecated, I decided to drop it and the resulting
+ code is much easier, shorter and due to more refactoring faster
+* Fix for crashing unit tests against MSVC C++17 `std::filesystem`
+* Travis-CI now additionally test with Xcode 10.2 on macOS
+* Some minor refactorings
+
+### [v1.1.2](https://github.com/gulrak/filesystem/releases/tag/v1.1.2)
+
+* Bugfix for ([#11](https://github.com/gulrak/filesystem/issues/11)),
+ `fs::path::lexically_normal()` had some issues with `".."`-sequences.
+* Bugfix for ([#12](https://github.com/gulrak/filesystem/issues/12)),
+ `fs::recursive_directory_iterator` could run into endless loops,
+ the methods depth() and pop() had issues and the copy behavior and
+ `input_iterator_tag` conformance was broken, added tests
+* Restructured some CMake code into a macro to ease the support for
+ C++17 `std::filesystem` builds of tests and examples for interoperability
+ checks.
+* Some fixes on Windows tests to ease interoperability test runs.
+* Reduced noise on `fs::weakly_canonical()` tests against `std::fs`
+* Added simple `du` example showing the `recursive_directory_iterator`
+ used to add the sizes of files in a directory tree.
+* Added error checking in `fs::file_time_type` test helpers
+* `fs::copy()` now conforms LWG #2682, disallowing the use of
+ `copy_option::create_symlinks' to be used on directories
+
+### [v1.1.0](https://github.com/gulrak/filesystem/releases/tag/v1.1.0)
+
+* Restructuring of the project directory. The header files are now using
+ `hpp` as extension to be marked as c++ and they where moved to
+ `include/ghc/` to be able to include by `<ghc/filesystem.hpp>` as the
+ former include name might have been to generic and conflict with other
+ files.
+* Better CMake support: `ghc::filesystem` now can be used as a submodul
+ and added with `add_subdirectory` and will export itself as `ghc_filesystem`
+ target. To use it, only `target_link_libraries(your-target ghc_filesystem)`
+ is needed and the include directories will be set so `#include <ghc/filesystem.hpp>`
+ will be a valid directive.
+ Still you can simply only add the header file to you project and include it
+ from there.
+* Enhancement ([#10](https://github.com/gulrak/filesystem/issues/10)),
+ support for separation of implementation and forwarded api: Two
+ additional simple includes are added, that can be used to forward
+ `ghc::filesystem` declarations (`fs_fwd.hpp`) and to wrap the
+ implementation into a single cpp (`fs_impl.hpp`)
+* The `std::basic_string_view` variants of the `fs::path` api are
+ now supported when compiling with C++17.
+* Added CI integration for Travis-CI and Appveyor.
+* Fixed MinGW compilation issues.
+* Added long filename support for Windows.
+
+### [v1.0.10](https://github.com/gulrak/filesystem/releases/tag/v1.0.10)
+
+* Bugfix for ([#9](https://github.com/gulrak/filesystem/issues/9)), added
+ missing return statement to `ghc::filesystem::path::generic_string()`
+* Added checks to hopefully better compile against Android NDK. There where
+ no tests run yet, so feedback is needed to actually call this supported.
+* `filesystem.h` was renamed `filesystem.hpp` to better reflect that it is
+ a c++ language header.
+
+### [v1.0.8](https://github.com/gulrak/filesystem/releases/tag/v1.0.8)
+
+* Bugfix for ([#6](https://github.com/gulrak/filesystem/issues/6)), where
+ `ghc::filesystem::remove()` and `ghc::filesystem::remove_all()` both are
+ now able to remove a single file and both will not raise an error if the
+ path doesn't exist.
+* Merged pull request ([#7](https://github.com/gulrak/filesystem/pull/7)),
+ a typo leading to setting error code instead of comparing it in
+ `ghc::filesystem::remove()` under Windows.
+* Bugfix for (([#8](https://github.com/gulrak/filesystem/issues/8)), the
+ Windows version of `ghc::filesystem::directory_iterator` now releases
+ resources when reaching `end()` like the POSIX one does.
+
+
+### [v1.0.6](https://github.com/gulrak/filesystem/releases/tag/v1.0.6)
+
+* Bugfix for ([#4](https://github.com/gulrak/filesystem/issues/4)), missing error_code
+ propagation in `ghc::filesystem::copy()` and `ghc::filesystem::remove_all` fixed.
+* Bugfix for ([#5](https://github.com/gulrak/filesystem/issues/5)), added missing std
+ namespace in `ghc::filesystem::recursive_directory_iterator::difference_type`.
+
+### [v1.0.4](https://github.com/gulrak/filesystem/releases/tag/v1.0.4)
+
+* Bugfix for ([#3](https://github.com/gulrak/filesystem/issues/3)), fixed missing inlines
+ and added test to ensure including into multiple implementation files works as expected.
+* Building tests with `-Wall -Wextra -Werror` and fixed resulting issues.
+
+### [v1.0.2](https://github.com/gulrak/filesystem/releases/tag/v1.0.2)
+
+* Updated catch2 to v2.4.0.
+* Refactored `fs.op.permissions` test to work with all tested `std::filesystem`
+ implementations (gcc, clang, msvc++).
+* Added helper class `ghc::filesystem::u8arguments` as `argv` converter, to
+ help follow the UTF-8 path on windows. Simply instantiate it with `argc` and
+ `argv` and it will fetch the Unicode version of the command line and convert
+ it to UTF-8. The destructor reverts the change.
+* Added `examples` folder with hopefully some usefull example usage. Examples are
+ tested (and build) with `ghc::filesystem` and C++17 `std::filesystem` when
+ available.
+* Starting with this version, only even patch level versions will be tagged and
+ odd patch levels mark in-between non-stable wip states.
+* Tests can now also be run against MS version of `std::filesystem` for comparison.
+* Added missing `fstream` include.
+* Removed non-conforming C99 `timespec`/`timeval` usage.
+* Fixed some integer type mismatches that could lead to warnings.
+* Fixed `chrono` conversion issues in test and example on clang 7.0.0.
+
+### [v1.0.1](https://github.com/gulrak/filesystem/releases/tag/v1.0.1)
+
+* Bugfix: `ghc::filesystem::canonical` now sees empty path as non-existant and reports
+ an error. Due to this `ghc::filesystem::weakly_canonical` now returns relative
+ paths for non-existant argument paths. ([#1](https://github.com/gulrak/filesystem/issues/1))
+* Bugfix: `ghc::filesystem::remove_all` now also counts directories removed ([#2](https://github.com/gulrak/filesystem/issues/2))
+* Bugfix: `recursive_directory_iterator` tests didn't respect equality domain issues
+ and dereferencapable constraints, leading to fails on `std::filesystem` tests.
+* Bugfix: Some `noexcept` tagged methods and functions could indirectly throw exceptions
+ due to UFT-8 decoding issues.
+* `std_filesystem_test` is now also generated if LLVM/clang 7.0.0 is found.
+
+
+### [v1.0.0](https://github.com/gulrak/filesystem/releases/tag/v1.0.0)
+
+This was the first public release version. It implements the full range of
+C++17 `std::filesystem`, as far as possible without other C++17 dependencies.
+
diff --git a/gulrak-filesystem/cmake/GhcHelper.cmake b/gulrak-filesystem/cmake/GhcHelper.cmake
new file mode 100644
index 0000000..8fffae9
--- /dev/null
+++ b/gulrak-filesystem/cmake/GhcHelper.cmake
@@ -0,0 +1,64 @@
+macro(AddExecutableWithStdFS targetName)
+
+if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 7.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0))
+ if(APPLE)
+ include_directories(/usr/local/opt/llvm/include)
+ link_directories(/usr/local/opt/llvm/lib)
+ endif()
+ add_executable(${targetName} ${ARGN})
+ set_property(TARGET ${targetName} PROPERTY CXX_STANDARD 17)
+ if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0)
+ if(APPLE)
+ target_link_libraries(${targetName} -lc++fs)
+ else()
+ target_compile_options(${targetName} PRIVATE "-stdlib=libc++")
+ target_link_libraries(${targetName} -stdlib=libc++ -lc++fs $<$<PLATFORM_ID:Linux>:rt>)
+ endif()
+ else()
+ if(NOT APPLE)
+ target_compile_options(${targetName} PRIVATE "-stdlib=libc++")
+ target_link_libraries(${targetName} -stdlib=libc++)
+ endif()
+ endif()
+ target_compile_definitions(${targetName} PRIVATE USE_STD_FS)
+endif()
+
+if (CMAKE_COMPILER_IS_GNUCXX AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 8.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 8.0))
+ add_executable(${targetName} ${ARGN})
+ set_property(TARGET ${targetName} PROPERTY CXX_STANDARD 17)
+ if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0)
+ target_link_libraries(${targetName} -lstdc++fs)
+ endif()
+ target_compile_options(${targetName} PRIVATE $<$<BOOL:${CYGWIN}>:-Wa,-mbig-obj>)
+ target_compile_definitions(${targetName} PRIVATE USE_STD_FS)
+endif()
+
+if(CMAKE_CXX_COMPILER_ID MATCHES MSVC AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 19.15 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 19.15))
+ add_executable(${targetName} ${ARGN})
+ set_property(TARGET ${targetName} PROPERTY CXX_STANDARD 17)
+ set_property(TARGET ${targetName} PROPERTY CXX_STANDARD_REQUIRED ON)
+ target_compile_options(${targetName} PRIVATE "/Zc:__cplusplus")
+ target_compile_definitions(${targetName} PRIVATE USE_STD_FS _CRT_SECURE_NO_WARNINGS)
+endif()
+
+endmacro()
+
+macro(AddTestExecutableWithStdCpp cppStd)
+ add_executable(filesystem_test_cpp${cppStd} ${ARGN})
+ set_property(TARGET filesystem_test_cpp${cppStd} PROPERTY CXX_STANDARD ${cppStd})
+ target_link_libraries(filesystem_test_cpp${cppStd} ghc_filesystem)
+ target_compile_options(filesystem_test_cpp${cppStd} PRIVATE
+ $<$<BOOL:${EMSCRIPTEN}>:-s DISABLE_EXCEPTION_CATCHING=0>
+ $<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>>:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Werror -Wno-error=deprecated-declarations>
+ $<$<CXX_COMPILER_ID:GNU>:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Wno-psabi -Werror -Wno-error=deprecated-declarations>
+ $<$<CXX_COMPILER_ID:MSVC>:/WX /wd4996>
+ $<$<BOOL:${CYGWIN}>:-Wa,-mbig-obj>
+ $<$<BOOL:${GHC_COVERAGE}>:--coverage>)
+ if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
+ target_compile_definitions(filesystem_test_cpp${cppStd} PRIVATE _CRT_SECURE_NO_WARNINGS)
+ endif()
+ if(EMSCRIPTEN)
+ set_target_properties(filesystem_test_cpp${cppStd} PROPERTIES LINK_FLAGS "-g4 -s DISABLE_EXCEPTION_CATCHING=0 -s ALLOW_MEMORY_GROWTH=1")
+ endif()
+ ParseAndAddCatchTests(filesystem_test_cpp${cppStd})
+endmacro()
diff --git a/gulrak-filesystem/cmake/config.cmake.in b/gulrak-filesystem/cmake/config.cmake.in
new file mode 100644
index 0000000..ace9761
--- /dev/null
+++ b/gulrak-filesystem/cmake/config.cmake.in
@@ -0,0 +1,6 @@
+@PACKAGE_INIT@
+
+# import targets
+include("${CMAKE_CURRENT_LIST_DIR}/ghc_filesystem-targets.cmake")
+
+check_required_components(ghcfilesystem) \ No newline at end of file
diff --git a/gulrak-filesystem/examples/CMakeLists.txt b/gulrak-filesystem/examples/CMakeLists.txt
new file mode 100644
index 0000000..17bb3d6
--- /dev/null
+++ b/gulrak-filesystem/examples/CMakeLists.txt
@@ -0,0 +1,17 @@
+
+add_executable(fs_dir dir.cpp)
+target_link_libraries(fs_dir ghc_filesystem)
+if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
+ target_compile_definitions(fs_dir PRIVATE _CRT_SECURE_NO_WARNINGS)
+endif()
+AddExecutableWithStdFS(std_fs_dir dir.cpp)
+
+add_executable(fs_du du.cpp)
+target_link_libraries(fs_du ghc_filesystem)
+AddExecutableWithStdFS(std_fs_du du.cpp)
+
+if(EXISTS "${PROJECT_SOURCE_DIR}/examples/benchmark.cpp")
+ add_executable(fs_benchmark benchmark.cpp)
+ set_property(TARGET fs_benchmark PROPERTY CXX_STANDARD 17)
+ target_link_libraries(fs_benchmark ghc_filesystem)
+endif() \ No newline at end of file
diff --git a/gulrak-filesystem/examples/dir.cpp b/gulrak-filesystem/examples/dir.cpp
new file mode 100644
index 0000000..abd4cc6
--- /dev/null
+++ b/gulrak-filesystem/examples/dir.cpp
@@ -0,0 +1,60 @@
+#include <chrono>
+#include <iomanip>
+#include <iostream>
+#include <string>
+
+#if defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include)
+#if __has_include(<filesystem>)
+#define GHC_USE_STD_FS
+#include <filesystem>
+namespace fs = std::filesystem;
+#endif
+#endif
+#ifndef GHC_USE_STD_FS
+#include <ghc/filesystem.hpp>
+namespace fs = ghc::filesystem;
+#endif
+
+template <typename TP>
+std::time_t to_time_t(TP tp)
+{
+ // Based on trick from: Nico Josuttis, C++17 - The Complete Guide
+ std::chrono::system_clock::duration dt = std::chrono::duration_cast<std::chrono::system_clock::duration>(tp - TP::clock::now());
+ return std::chrono::system_clock::to_time_t(std::chrono::system_clock::now() + dt);
+}
+
+static std::string perm_to_str(fs::perms prms)
+{
+ std::string result;
+ result.reserve(9);
+ for (int i = 0; i < 9; ++i) {
+ result = ((static_cast<int>(prms) & (1 << i)) ? "xwrxwrxwr"[i] : '-') + result;
+ }
+ return result;
+}
+
+int main(int argc, char* argv[])
+{
+#ifdef GHC_FILESYSTEM_VERSION
+ fs::u8arguments u8guard(argc, argv);
+ if (!u8guard.valid()) {
+ std::cerr << "Invalid character encoding, UTF-8 based encoding needed." << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+#endif
+ if (argc > 2) {
+ std::cerr << "USAGE: dir <path>" << std::endl;
+ exit(1);
+ }
+ fs::path dir{"."};
+ if (argc == 2) {
+ dir = fs::u8path(argv[1]);
+ }
+ for (auto de : fs::directory_iterator(dir)) {
+ auto ft = to_time_t(de.last_write_time());
+ auto ftm = *std::localtime(&ft);
+ std::cout << (de.is_directory() ? "d" : "-") << perm_to_str(de.symlink_status().permissions()) << " " << std::setw(8) << (de.is_directory() ? "-" : std::to_string(de.file_size())) << " " << std::put_time(&ftm, "%Y-%m-%d %H:%M:%S") << " "
+ << de.path().filename().string() << std::endl;
+ }
+ return 0;
+}
diff --git a/gulrak-filesystem/examples/du.cpp b/gulrak-filesystem/examples/du.cpp
new file mode 100644
index 0000000..929b809
--- /dev/null
+++ b/gulrak-filesystem/examples/du.cpp
@@ -0,0 +1,61 @@
+#include <iostream>
+#include <iomanip>
+#include <chrono>
+
+#if defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include)
+#if __has_include(<filesystem>)
+#define GHC_USE_STD_FS
+#include <filesystem>
+namespace fs = std::filesystem;
+#endif
+#endif
+#ifndef GHC_USE_STD_FS
+#include <ghc/filesystem.hpp>
+namespace fs = ghc::filesystem;
+#endif
+
+int main(int argc, char* argv[])
+{
+#ifdef GHC_FILESYSTEM_VERSION
+ fs::u8arguments u8guard(argc, argv);
+ if(!u8guard.valid()) {
+ std::cerr << "Invalid character encoding, UTF-8 based encoding needed." << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+#endif
+ if(argc > 2) {
+ std::cerr << "USAGE: du <path>" << std::endl;
+ exit(1);
+ }
+ fs::path dir{"."};
+ if(argc == 2) {
+ dir = fs::u8path(argv[1]);
+ }
+
+ uint64_t totalSize = 0;
+ int totalDirs = 0;
+ int totalFiles = 0;
+ int maxDepth = 0;
+
+ try {
+ auto rdi = fs::recursive_directory_iterator(dir);
+ for(auto de : rdi) {
+ if(rdi.depth() > maxDepth) {
+ maxDepth = rdi.depth();
+ }
+ if(de.is_regular_file()) {
+ totalSize += de.file_size();
+ ++totalFiles;
+ }
+ else if(de.is_directory()) {
+ ++totalDirs;
+ }
+ }
+ }
+ catch(fs::filesystem_error fe) {
+ std::cerr << "Error: " << fe.what() << std::endl;
+ exit(1);
+ }
+ std::cout << totalSize << " bytes in " << totalFiles << " files and " << totalDirs << " directories, maximum depth: " << maxDepth << std::endl;
+ return 0;
+}
diff --git a/gulrak-filesystem/include/ghc/filesystem.hpp b/gulrak-filesystem/include/ghc/filesystem.hpp
new file mode 100644
index 0000000..a319def
--- /dev/null
+++ b/gulrak-filesystem/include/ghc/filesystem.hpp
@@ -0,0 +1,6017 @@
+//---------------------------------------------------------------------------------------
+//
+// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14/C++17/C++20
+//
+//---------------------------------------------------------------------------------------
+//
+// Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+//---------------------------------------------------------------------------------------
+//
+// To dynamically select std::filesystem where available on most platforms,
+// you could use:
+//
+// #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
+// #if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
+// #define GHC_USE_STD_FS
+// #include <filesystem>
+// namespace fs = std::filesystem;
+// #endif
+// #endif
+// #ifndef GHC_USE_STD_FS
+// #include <ghc/filesystem.hpp>
+// namespace fs = ghc::filesystem;
+// #endif
+//
+//---------------------------------------------------------------------------------------
+#ifndef GHC_FILESYSTEM_H
+#define GHC_FILESYSTEM_H
+
+// #define BSD manifest constant only in
+// sys/param.h
+#ifndef _WIN32
+#include <sys/param.h>
+#endif
+
+#ifndef GHC_OS_DETECTED
+#if defined(__APPLE__) && defined(__MACH__)
+#define GHC_OS_MACOS
+#elif defined(__linux__)
+#define GHC_OS_LINUX
+#if defined(__ANDROID__)
+#define GHC_OS_ANDROID
+#endif
+#elif defined(_WIN64)
+#define GHC_OS_WINDOWS
+#define GHC_OS_WIN64
+#elif defined(_WIN32)
+#define GHC_OS_WINDOWS
+#define GHC_OS_WIN32
+#elif defined(__CYGWIN__)
+#define GHC_OS_CYGWIN
+#elif defined(__svr4__)
+#define GHC_OS_SYS5R4
+#elif defined(BSD)
+#define GHC_OS_BSD
+#elif defined(__EMSCRIPTEN__)
+#define GHC_OS_WEB
+#include <wasi/api.h>
+#elif defined(__QNX__)
+#define GHC_OS_QNX
+#define GHC_NO_DIRENT_D_TYPE
+#else
+#error "Operating system currently not supported!"
+#endif
+#define GHC_OS_DETECTED
+#if (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
+#if _MSVC_LANG == 201703L
+#define GHC_FILESYSTEM_RUNNING_CPP17
+#else
+#define GHC_FILESYSTEM_RUNNING_CPP20
+#endif
+#elif (defined(__cplusplus) && __cplusplus >= 201703L)
+#if __cplusplus == 201703L
+#define GHC_FILESYSTEM_RUNNING_CPP17
+#else
+#define GHC_FILESYSTEM_RUNNING_CPP20
+#endif
+#endif
+#endif
+
+#if defined(GHC_FILESYSTEM_IMPLEMENTATION)
+#define GHC_EXPAND_IMPL
+#define GHC_INLINE
+#ifdef GHC_OS_WINDOWS
+#ifndef GHC_FS_API
+#define GHC_FS_API
+#endif
+#ifndef GHC_FS_API_CLASS
+#define GHC_FS_API_CLASS
+#endif
+#else
+#ifndef GHC_FS_API
+#define GHC_FS_API __attribute__((visibility("default")))
+#endif
+#ifndef GHC_FS_API_CLASS
+#define GHC_FS_API_CLASS __attribute__((visibility("default")))
+#endif
+#endif
+#elif defined(GHC_FILESYSTEM_FWD)
+#define GHC_INLINE
+#ifdef GHC_OS_WINDOWS
+#ifndef GHC_FS_API
+#define GHC_FS_API extern
+#endif
+#ifndef GHC_FS_API_CLASS
+#define GHC_FS_API_CLASS
+#endif
+#else
+#ifndef GHC_FS_API
+#define GHC_FS_API extern
+#endif
+#ifndef GHC_FS_API_CLASS
+#define GHC_FS_API_CLASS
+#endif
+#endif
+#else
+#define GHC_EXPAND_IMPL
+#define GHC_INLINE inline
+#ifndef GHC_FS_API
+#define GHC_FS_API
+#endif
+#ifndef GHC_FS_API_CLASS
+#define GHC_FS_API_CLASS
+#endif
+#endif
+
+#ifdef GHC_EXPAND_IMPL
+
+#ifdef GHC_OS_WINDOWS
+#include <windows.h>
+// additional includes
+#include <shellapi.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <wchar.h>
+#include <winioctl.h>
+#else
+#include <dirent.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#ifdef GHC_OS_ANDROID
+#include <android/api-level.h>
+#if __ANDROID_API__ < 12
+#include <sys/syscall.h>
+#endif
+#include <sys/vfs.h>
+#define statvfs statfs
+#else
+#include <sys/statvfs.h>
+#endif
+#ifdef GHC_OS_CYGWIN
+#include <strings.h>
+#endif
+#if !defined(__ANDROID__) || __ANDROID_API__ >= 26
+#include <langinfo.h>
+#endif
+#endif
+#ifdef GHC_OS_MACOS
+#include <Availability.h>
+#endif
+
+#if defined(__cpp_impl_three_way_comparison) && defined(__has_include)
+#if __has_include(<compare>)
+#define GHC_HAS_THREEWAY_COMP
+#include <compare>
+#endif
+#endif
+
+#include <algorithm>
+#include <cctype>
+#include <chrono>
+#include <clocale>
+#include <cstdlib>
+#include <cstring>
+#include <fstream>
+#include <functional>
+#include <memory>
+#include <stack>
+#include <stdexcept>
+#include <string>
+#include <system_error>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#else // GHC_EXPAND_IMPL
+
+#if defined(__cpp_impl_three_way_comparison) && defined(__has_include)
+#if __has_include(<compare>)
+#define GHC_HAS_THREEWAY_COMP
+#include <compare>
+#endif
+#endif
+#include <chrono>
+#include <fstream>
+#include <memory>
+#include <stack>
+#include <stdexcept>
+#include <string>
+#include <system_error>
+#ifdef GHC_OS_WINDOWS
+#include <vector>
+#endif
+#endif // GHC_EXPAND_IMPL
+
+// After standard library includes.
+// Standard library support for std::string_view.
+#if defined(__cpp_lib_string_view)
+#define GHC_HAS_STD_STRING_VIEW
+#elif defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 4000) && (__cplusplus >= 201402)
+#define GHC_HAS_STD_STRING_VIEW
+#elif defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE >= 7) && (__cplusplus >= 201703)
+#define GHC_HAS_STD_STRING_VIEW
+#elif defined(_MSC_VER) && (_MSC_VER >= 1910 && _MSVC_LANG >= 201703)
+#define GHC_HAS_STD_STRING_VIEW
+#endif
+
+// Standard library support for std::experimental::string_view.
+#if defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 3700 && _LIBCPP_VERSION < 7000) && (__cplusplus >= 201402)
+#define GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW
+#elif defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4)) && (__cplusplus >= 201402)
+#define GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW
+#elif defined(__GLIBCXX__) && defined(_GLIBCXX_USE_DUAL_ABI) && (__cplusplus >= 201402)
+// macro _GLIBCXX_USE_DUAL_ABI is always defined in libstdc++ from gcc-5 and newer
+#define GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW
+#endif
+
+#if defined(GHC_HAS_STD_STRING_VIEW)
+#include <string_view>
+#elif defined(GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW)
+#include <experimental/string_view>
+#endif
+
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// Behaviour Switches (see README.md, should match the config in test/filesystem_test.cpp):
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// Enforce C++17 API where possible when compiling for C++20, handles the following cases:
+// * fs::path::u8string() returns std::string instead of std::u8string
+// #define GHC_FILESYSTEM_ENFORCE_CPP17_API
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// LWG #2682 disables the since then invalid use of the copy option create_symlinks on directories
+// configure LWG conformance ()
+#define LWG_2682_BEHAVIOUR
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// LWG #2395 makes crate_directory/create_directories not emit an error if there is a regular
+// file with that name, it is superseded by P1164R1, so only activate if really needed
+// #define LWG_2935_BEHAVIOUR
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// LWG #2936 enables new element wise (more expensive) path comparison
+// * if this->root_name().native().compare(p.root_name().native()) != 0 return result
+// * if this->has_root_directory() and !p.has_root_directory() return -1
+// * if !this->has_root_directory() and p.has_root_directory() return -1
+// * else result of element wise comparison of path iteration where first comparison is != 0 or 0
+// if all comparisons are 0 (on Windows this implementation does case insensitive root_name()
+// comparison)
+#define LWG_2936_BEHAVIOUR
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// LWG #2937 enforces that fs::equivalent emits an error, if !fs::exists(p1)||!exists(p2)
+#define LWG_2937_BEHAVIOUR
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// UTF8-Everywhere is the original behaviour of ghc::filesystem. But since v1.5 the windows
+// version defaults to std::wstring storage backend. Still all std::string will be interpreted
+// as UTF-8 encoded. With this define you can enfoce the old behavior on Windows, using
+// std::string as backend and for fs::path::native() and char for fs::path::c_str(). This
+// needs more conversions so it is (an was before v1.5) slower, bot might help keeping source
+// homogeneous in a multi platform project.
+// #define GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// Raise errors/exceptions when invalid unicode codepoints or UTF-8 sequences are found,
+// instead of replacing them with the unicode replacement character (U+FFFD).
+// #define GHC_RAISE_UNICODE_ERRORS
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// Automatic prefix windows path with "\\?\" if they would break the MAX_PATH length.
+// instead of replacing them with the unicode replacement character (U+FFFD).
+#ifndef GHC_WIN_DISABLE_AUTO_PREFIXES
+#define GHC_WIN_AUTO_PREFIX_LONG_PATH
+#endif // GHC_WIN_DISABLE_AUTO_PREFIXES
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+// ghc::filesystem version in decimal (major * 10000 + minor * 100 + patch)
+#define GHC_FILESYSTEM_VERSION 10510L
+
+#if !defined(GHC_WITH_EXCEPTIONS) && (defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND))
+#define GHC_WITH_EXCEPTIONS
+#endif
+#if !defined(GHC_WITH_EXCEPTIONS) && defined(GHC_RAISE_UNICODE_ERRORS)
+#error "Can't raise unicode errors with exception support disabled"
+#endif
+
+namespace ghc {
+namespace filesystem {
+
+#if defined(GHC_HAS_CUSTOM_STRING_VIEW)
+#define GHC_WITH_STRING_VIEW
+#elif defined(GHC_HAS_STD_STRING_VIEW)
+#define GHC_WITH_STRING_VIEW
+using std::basic_string_view;
+#elif defined(GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW)
+#define GHC_WITH_STRING_VIEW
+using std::experimental::basic_string_view;
+#endif
+
+// temporary existing exception type for yet unimplemented parts
+class GHC_FS_API_CLASS not_implemented_exception : public std::logic_error
+{
+public:
+ not_implemented_exception()
+ : std::logic_error("function not implemented yet.")
+ {
+ }
+};
+
+template <typename char_type>
+class path_helper_base
+{
+public:
+ using value_type = char_type;
+#ifdef GHC_OS_WINDOWS
+ static constexpr value_type preferred_separator = '\\';
+#else
+ static constexpr value_type preferred_separator = '/';
+#endif
+};
+
+#if __cplusplus < 201703L
+template <typename char_type>
+constexpr char_type path_helper_base<char_type>::preferred_separator;
+#endif
+
+#ifdef GHC_OS_WINDOWS
+class path;
+namespace detail {
+bool has_executable_extension(const path& p);
+}
+#endif
+
+// [fs.class.path] class path
+class GHC_FS_API_CLASS path
+#if defined(GHC_OS_WINDOWS) && !defined(GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE)
+#define GHC_USE_WCHAR_T
+#define GHC_NATIVEWP(p) p.c_str()
+#define GHC_PLATFORM_LITERAL(str) L##str
+ : private path_helper_base<std::wstring::value_type>
+{
+public:
+ using path_helper_base<std::wstring::value_type>::value_type;
+#else
+#define GHC_NATIVEWP(p) p.wstring().c_str()
+#define GHC_PLATFORM_LITERAL(str) str
+ : private path_helper_base<std::string::value_type>
+{
+public:
+ using path_helper_base<std::string::value_type>::value_type;
+#endif
+ using string_type = std::basic_string<value_type>;
+ using path_helper_base<value_type>::preferred_separator;
+
+ // [fs.enum.path.format] enumeration format
+ /// The path format in which the constructor argument is given.
+ enum format {
+ generic_format, ///< The generic format, internally used by
+ ///< ghc::filesystem::path with slashes
+ native_format, ///< The format native to the current platform this code
+ ///< is build for
+ auto_format, ///< Try to auto-detect the format, fallback to native
+ };
+
+ template <class T>
+ struct _is_basic_string : std::false_type
+ {
+ };
+ template <class CharT, class Traits, class Alloc>
+ struct _is_basic_string<std::basic_string<CharT, Traits, Alloc>> : std::true_type
+ {
+ };
+ template <class CharT>
+ struct _is_basic_string<std::basic_string<CharT, std::char_traits<CharT>, std::allocator<CharT>>> : std::true_type
+ {
+ };
+#ifdef GHC_WITH_STRING_VIEW
+ template <class CharT, class Traits>
+ struct _is_basic_string<basic_string_view<CharT, Traits>> : std::true_type
+ {
+ };
+ template <class CharT>
+ struct _is_basic_string<basic_string_view<CharT, std::char_traits<CharT>>> : std::true_type
+ {
+ };
+#endif
+
+ template <typename T1, typename T2 = void>
+ using path_type = typename std::enable_if<!std::is_same<path, T1>::value, path>::type;
+ template <typename T>
+#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)
+ using path_from_string =
+ typename std::enable_if<_is_basic_string<T>::value || std::is_same<char const*, typename std::decay<T>::type>::value || std::is_same<char*, typename std::decay<T>::type>::value || std::is_same<char8_t const*, typename std::decay<T>::type>::value ||
+ std::is_same<char8_t*, typename std::decay<T>::type>::value || std::is_same<char16_t const*, typename std::decay<T>::type>::value || std::is_same<char16_t*, typename std::decay<T>::type>::value ||
+ std::is_same<char32_t const*, typename std::decay<T>::type>::value || std::is_same<char32_t*, typename std::decay<T>::type>::value || std::is_same<wchar_t const*, typename std::decay<T>::type>::value ||
+ std::is_same<wchar_t*, typename std::decay<T>::type>::value,
+ path>::type;
+ template <typename T>
+ using path_type_EcharT = typename std::enable_if<std::is_same<T, char>::value || std::is_same<T, char8_t>::value || std::is_same<T, char16_t>::value || std::is_same<T, char32_t>::value || std::is_same<T, wchar_t>::value, path>::type;
+#else
+ using path_from_string =
+ typename std::enable_if<_is_basic_string<T>::value || std::is_same<char const*, typename std::decay<T>::type>::value || std::is_same<char*, typename std::decay<T>::type>::value ||
+ std::is_same<char16_t const*, typename std::decay<T>::type>::value || std::is_same<char16_t*, typename std::decay<T>::type>::value || std::is_same<char32_t const*, typename std::decay<T>::type>::value ||
+ std::is_same<char32_t*, typename std::decay<T>::type>::value || std::is_same<wchar_t const*, typename std::decay<T>::type>::value || std::is_same<wchar_t*, typename std::decay<T>::type>::value,
+ path>::type;
+ template <typename T>
+ using path_type_EcharT = typename std::enable_if<std::is_same<T, char>::value || std::is_same<T, char16_t>::value || std::is_same<T, char32_t>::value || std::is_same<T, wchar_t>::value, path>::type;
+#endif
+ // [fs.path.construct] constructors and destructor
+ path() noexcept;
+ path(const path& p);
+ path(path&& p) noexcept;
+ path(string_type&& source, format fmt = auto_format);
+ template <class Source, typename = path_from_string<Source>>
+ path(const Source& source, format fmt = auto_format);
+ template <class InputIterator>
+ path(InputIterator first, InputIterator last, format fmt = auto_format);
+#ifdef GHC_WITH_EXCEPTIONS
+ template <class Source, typename = path_from_string<Source>>
+ path(const Source& source, const std::locale& loc, format fmt = auto_format);
+ template <class InputIterator>
+ path(InputIterator first, InputIterator last, const std::locale& loc, format fmt = auto_format);
+#endif
+ ~path();
+
+ // [fs.path.assign] assignments
+ path& operator=(const path& p);
+ path& operator=(path&& p) noexcept;
+ path& operator=(string_type&& source);
+ path& assign(string_type&& source);
+ template <class Source>
+ path& operator=(const Source& source);
+ template <class Source>
+ path& assign(const Source& source);
+ template <class InputIterator>
+ path& assign(InputIterator first, InputIterator last);
+
+ // [fs.path.append] appends
+ path& operator/=(const path& p);
+ template <class Source>
+ path& operator/=(const Source& source);
+ template <class Source>
+ path& append(const Source& source);
+ template <class InputIterator>
+ path& append(InputIterator first, InputIterator last);
+
+ // [fs.path.concat] concatenation
+ path& operator+=(const path& x);
+ path& operator+=(const string_type& x);
+#ifdef GHC_WITH_STRING_VIEW
+ path& operator+=(basic_string_view<value_type> x);
+#endif
+ path& operator+=(const value_type* x);
+ path& operator+=(value_type x);
+ template <class Source>
+ path_from_string<Source>& operator+=(const Source& x);
+ template <class EcharT>
+ path_type_EcharT<EcharT>& operator+=(EcharT x);
+ template <class Source>
+ path& concat(const Source& x);
+ template <class InputIterator>
+ path& concat(InputIterator first, InputIterator last);
+
+ // [fs.path.modifiers] modifiers
+ void clear() noexcept;
+ path& make_preferred();
+ path& remove_filename();
+ path& replace_filename(const path& replacement);
+ path& replace_extension(const path& replacement = path());
+ void swap(path& rhs) noexcept;
+
+ // [fs.path.native.obs] native format observers
+ const string_type& native() const noexcept;
+ const value_type* c_str() const noexcept;
+ operator string_type() const;
+ template <class EcharT, class traits = std::char_traits<EcharT>, class Allocator = std::allocator<EcharT>>
+ std::basic_string<EcharT, traits, Allocator> string(const Allocator& a = Allocator()) const;
+ std::string string() const;
+ std::wstring wstring() const;
+#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)
+ std::u8string u8string() const;
+#else
+ std::string u8string() const;
+#endif
+ std::u16string u16string() const;
+ std::u32string u32string() const;
+
+ // [fs.path.generic.obs] generic format observers
+ template <class EcharT, class traits = std::char_traits<EcharT>, class Allocator = std::allocator<EcharT>>
+ std::basic_string<EcharT, traits, Allocator> generic_string(const Allocator& a = Allocator()) const;
+ std::string generic_string() const;
+ std::wstring generic_wstring() const;
+#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)
+ std::u8string generic_u8string() const;
+#else
+ std::string generic_u8string() const;
+#endif
+ std::u16string generic_u16string() const;
+ std::u32string generic_u32string() const;
+
+ // [fs.path.compare] compare
+ int compare(const path& p) const noexcept;
+ int compare(const string_type& s) const;
+#ifdef GHC_WITH_STRING_VIEW
+ int compare(basic_string_view<value_type> s) const;
+#endif
+ int compare(const value_type* s) const;
+
+ // [fs.path.decompose] decomposition
+ path root_name() const;
+ path root_directory() const;
+ path root_path() const;
+ path relative_path() const;
+ path parent_path() const;
+ path filename() const;
+ path stem() const;
+ path extension() const;
+
+ // [fs.path.query] query
+ bool empty() const noexcept;
+ bool has_root_name() const;
+ bool has_root_directory() const;
+ bool has_root_path() const;
+ bool has_relative_path() const;
+ bool has_parent_path() const;
+ bool has_filename() const;
+ bool has_stem() const;
+ bool has_extension() const;
+ bool is_absolute() const;
+ bool is_relative() const;
+
+ // [fs.path.gen] generation
+ path lexically_normal() const;
+ path lexically_relative(const path& base) const;
+ path lexically_proximate(const path& base) const;
+
+ // [fs.path.itr] iterators
+ class iterator;
+ using const_iterator = iterator;
+ iterator begin() const;
+ iterator end() const;
+
+private:
+ using impl_value_type = value_type;
+ using impl_string_type = std::basic_string<impl_value_type>;
+ friend class directory_iterator;
+ void append_name(const value_type* name);
+ static constexpr impl_value_type generic_separator = '/';
+ template <typename InputIterator>
+ class input_iterator_range
+ {
+ public:
+ typedef InputIterator iterator;
+ typedef InputIterator const_iterator;
+ typedef typename InputIterator::difference_type difference_type;
+
+ input_iterator_range(const InputIterator& first, const InputIterator& last)
+ : _first(first)
+ , _last(last)
+ {
+ }
+
+ InputIterator begin() const { return _first; }
+ InputIterator end() const { return _last; }
+
+ private:
+ InputIterator _first;
+ InputIterator _last;
+ };
+ friend void swap(path& lhs, path& rhs) noexcept;
+ friend size_t hash_value(const path& p) noexcept;
+ friend path canonical(const path& p, std::error_code& ec);
+ friend bool create_directories(const path& p, std::error_code& ec) noexcept;
+ string_type::size_type root_name_length() const noexcept;
+ void postprocess_path_with_format(format fmt);
+ void check_long_path();
+ impl_string_type _path;
+#ifdef GHC_OS_WINDOWS
+ void handle_prefixes();
+ friend bool detail::has_executable_extension(const path& p);
+#ifdef GHC_WIN_AUTO_PREFIX_LONG_PATH
+ string_type::size_type _prefixLength{0};
+#else // GHC_WIN_AUTO_PREFIX_LONG_PATH
+ static const string_type::size_type _prefixLength{0};
+#endif // GHC_WIN_AUTO_PREFIX_LONG_PATH
+#else
+ static const string_type::size_type _prefixLength{0};
+#endif
+};
+
+// [fs.path.nonmember] path non-member functions
+GHC_FS_API void swap(path& lhs, path& rhs) noexcept;
+GHC_FS_API size_t hash_value(const path& p) noexcept;
+#ifdef GHC_HAS_THREEWAY_COMP
+GHC_FS_API std::strong_ordering operator<=>(const path& lhs, const path& rhs) noexcept;
+#endif
+GHC_FS_API bool operator==(const path& lhs, const path& rhs) noexcept;
+GHC_FS_API bool operator!=(const path& lhs, const path& rhs) noexcept;
+GHC_FS_API bool operator<(const path& lhs, const path& rhs) noexcept;
+GHC_FS_API bool operator<=(const path& lhs, const path& rhs) noexcept;
+GHC_FS_API bool operator>(const path& lhs, const path& rhs) noexcept;
+GHC_FS_API bool operator>=(const path& lhs, const path& rhs) noexcept;
+GHC_FS_API path operator/(const path& lhs, const path& rhs);
+
+// [fs.path.io] path inserter and extractor
+template <class charT, class traits>
+std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& os, const path& p);
+template <class charT, class traits>
+std::basic_istream<charT, traits>& operator>>(std::basic_istream<charT, traits>& is, path& p);
+
+// [pfs.path.factory] path factory functions
+template <class Source, typename = path::path_from_string<Source>>
+#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)
+[[deprecated("use ghc::filesystem::path::path() with std::u8string instead")]]
+#endif
+path u8path(const Source& source);
+template <class InputIterator>
+#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)
+[[deprecated("use ghc::filesystem::path::path() with std::u8string instead")]]
+#endif
+path u8path(InputIterator first, InputIterator last);
+
+// [fs.class.filesystem_error] class filesystem_error
+class GHC_FS_API_CLASS filesystem_error : public std::system_error
+{
+public:
+ filesystem_error(const std::string& what_arg, std::error_code ec);
+ filesystem_error(const std::string& what_arg, const path& p1, std::error_code ec);
+ filesystem_error(const std::string& what_arg, const path& p1, const path& p2, std::error_code ec);
+ const path& path1() const noexcept;
+ const path& path2() const noexcept;
+ const char* what() const noexcept override;
+
+private:
+ std::string _what_arg;
+ std::error_code _ec;
+ path _p1, _p2;
+};
+
+class GHC_FS_API_CLASS path::iterator
+{
+public:
+ using value_type = const path;
+ using difference_type = std::ptrdiff_t;
+ using pointer = const path*;
+ using reference = const path&;
+ using iterator_category = std::bidirectional_iterator_tag;
+
+ iterator();
+ iterator(const path& p, const impl_string_type::const_iterator& pos);
+ iterator& operator++();
+ iterator operator++(int);
+ iterator& operator--();
+ iterator operator--(int);
+ bool operator==(const iterator& other) const;
+ bool operator!=(const iterator& other) const;
+ reference operator*() const;
+ pointer operator->() const;
+
+private:
+ friend class path;
+ impl_string_type::const_iterator increment(const impl_string_type::const_iterator& pos) const;
+ impl_string_type::const_iterator decrement(const impl_string_type::const_iterator& pos) const;
+ void updateCurrent();
+ impl_string_type::const_iterator _first;
+ impl_string_type::const_iterator _last;
+ impl_string_type::const_iterator _prefix;
+ impl_string_type::const_iterator _root;
+ impl_string_type::const_iterator _iter;
+ path _current;
+};
+
+struct space_info
+{
+ uintmax_t capacity;
+ uintmax_t free;
+ uintmax_t available;
+};
+
+// [fs.enum] enumerations
+// [fs.enum.file_type]
+enum class file_type {
+ none,
+ not_found,
+ regular,
+ directory,
+ symlink,
+ block,
+ character,
+ fifo,
+ socket,
+ unknown,
+};
+
+// [fs.enum.perms]
+enum class perms : uint16_t {
+ none = 0,
+
+ owner_read = 0400,
+ owner_write = 0200,
+ owner_exec = 0100,
+ owner_all = 0700,
+
+ group_read = 040,
+ group_write = 020,
+ group_exec = 010,
+ group_all = 070,
+
+ others_read = 04,
+ others_write = 02,
+ others_exec = 01,
+ others_all = 07,
+
+ all = 0777,
+ set_uid = 04000,
+ set_gid = 02000,
+ sticky_bit = 01000,
+
+ mask = 07777,
+ unknown = 0xffff
+};
+
+// [fs.enum.perm.opts]
+enum class perm_options : uint16_t {
+ replace = 3,
+ add = 1,
+ remove = 2,
+ nofollow = 4,
+};
+
+// [fs.enum.copy.opts]
+enum class copy_options : uint16_t {
+ none = 0,
+
+ skip_existing = 1,
+ overwrite_existing = 2,
+ update_existing = 4,
+
+ recursive = 8,
+
+ copy_symlinks = 0x10,
+ skip_symlinks = 0x20,
+
+ directories_only = 0x40,
+ create_symlinks = 0x80,
+#ifndef GHC_OS_WEB
+ create_hard_links = 0x100
+#endif
+};
+
+// [fs.enum.dir.opts]
+enum class directory_options : uint16_t {
+ none = 0,
+ follow_directory_symlink = 1,
+ skip_permission_denied = 2,
+};
+
+// [fs.class.file_status] class file_status
+class GHC_FS_API_CLASS file_status
+{
+public:
+ // [fs.file_status.cons] constructors and destructor
+ file_status() noexcept;
+ explicit file_status(file_type ft, perms prms = perms::unknown) noexcept;
+ file_status(const file_status&) noexcept;
+ file_status(file_status&&) noexcept;
+ ~file_status();
+ // assignments:
+ file_status& operator=(const file_status&) noexcept;
+ file_status& operator=(file_status&&) noexcept;
+ // [fs.file_status.mods] modifiers
+ void type(file_type ft) noexcept;
+ void permissions(perms prms) noexcept;
+ // [fs.file_status.obs] observers
+ file_type type() const noexcept;
+ perms permissions() const noexcept;
+ friend bool operator==(const file_status& lhs, const file_status& rhs) noexcept { return lhs.type() == rhs.type() && lhs.permissions() == rhs.permissions(); }
+
+private:
+ file_type _type;
+ perms _perms;
+};
+
+using file_time_type = std::chrono::time_point<std::chrono::system_clock>;
+
+// [fs.class.directory_entry] Class directory_entry
+class GHC_FS_API_CLASS directory_entry
+{
+public:
+ // [fs.dir.entry.cons] constructors and destructor
+ directory_entry() noexcept = default;
+ directory_entry(const directory_entry&) = default;
+ directory_entry(directory_entry&&) noexcept = default;
+#ifdef GHC_WITH_EXCEPTIONS
+ explicit directory_entry(const path& p);
+#endif
+ directory_entry(const path& p, std::error_code& ec);
+ ~directory_entry();
+
+ // assignments:
+ directory_entry& operator=(const directory_entry&) = default;
+ directory_entry& operator=(directory_entry&&) noexcept = default;
+
+ // [fs.dir.entry.mods] modifiers
+#ifdef GHC_WITH_EXCEPTIONS
+ void assign(const path& p);
+ void replace_filename(const path& p);
+ void refresh();
+#endif
+ void assign(const path& p, std::error_code& ec);
+ void replace_filename(const path& p, std::error_code& ec);
+ void refresh(std::error_code& ec) noexcept;
+
+ // [fs.dir.entry.obs] observers
+ const filesystem::path& path() const noexcept;
+ operator const filesystem::path&() const noexcept;
+#ifdef GHC_WITH_EXCEPTIONS
+ bool exists() const;
+ bool is_block_file() const;
+ bool is_character_file() const;
+ bool is_directory() const;
+ bool is_fifo() const;
+ bool is_other() const;
+ bool is_regular_file() const;
+ bool is_socket() const;
+ bool is_symlink() const;
+ uintmax_t file_size() const;
+ file_time_type last_write_time() const;
+ file_status status() const;
+ file_status symlink_status() const;
+#endif
+ bool exists(std::error_code& ec) const noexcept;
+ bool is_block_file(std::error_code& ec) const noexcept;
+ bool is_character_file(std::error_code& ec) const noexcept;
+ bool is_directory(std::error_code& ec) const noexcept;
+ bool is_fifo(std::error_code& ec) const noexcept;
+ bool is_other(std::error_code& ec) const noexcept;
+ bool is_regular_file(std::error_code& ec) const noexcept;
+ bool is_socket(std::error_code& ec) const noexcept;
+ bool is_symlink(std::error_code& ec) const noexcept;
+ uintmax_t file_size(std::error_code& ec) const noexcept;
+ file_time_type last_write_time(std::error_code& ec) const noexcept;
+ file_status status(std::error_code& ec) const noexcept;
+ file_status symlink_status(std::error_code& ec) const noexcept;
+
+#ifndef GHC_OS_WEB
+#ifdef GHC_WITH_EXCEPTIONS
+ uintmax_t hard_link_count() const;
+#endif
+ uintmax_t hard_link_count(std::error_code& ec) const noexcept;
+#endif
+
+#ifdef GHC_HAS_THREEWAY_COMP
+ std::strong_ordering operator<=>(const directory_entry& rhs) const noexcept;
+#endif
+ bool operator<(const directory_entry& rhs) const noexcept;
+ bool operator==(const directory_entry& rhs) const noexcept;
+ bool operator!=(const directory_entry& rhs) const noexcept;
+ bool operator<=(const directory_entry& rhs) const noexcept;
+ bool operator>(const directory_entry& rhs) const noexcept;
+ bool operator>=(const directory_entry& rhs) const noexcept;
+
+private:
+ friend class directory_iterator;
+#ifdef GHC_WITH_EXCEPTIONS
+ file_type status_file_type() const;
+#endif
+ file_type status_file_type(std::error_code& ec) const noexcept;
+ filesystem::path _path;
+ file_status _status;
+ file_status _symlink_status;
+ uintmax_t _file_size = static_cast<uintmax_t>(-1);
+#ifndef GHC_OS_WINDOWS
+ uintmax_t _hard_link_count = static_cast<uintmax_t>(-1);
+#endif
+ time_t _last_write_time = 0;
+};
+
+// [fs.class.directory.iterator] Class directory_iterator
+class GHC_FS_API_CLASS directory_iterator
+{
+public:
+ class GHC_FS_API_CLASS proxy
+ {
+ public:
+ const directory_entry& operator*() const& noexcept { return _dir_entry; }
+ directory_entry operator*() && noexcept { return std::move(_dir_entry); }
+
+ private:
+ explicit proxy(const directory_entry& dir_entry)
+ : _dir_entry(dir_entry)
+ {
+ }
+ friend class directory_iterator;
+ friend class recursive_directory_iterator;
+ directory_entry _dir_entry;
+ };
+ using iterator_category = std::input_iterator_tag;
+ using value_type = directory_entry;
+ using difference_type = std::ptrdiff_t;
+ using pointer = const directory_entry*;
+ using reference = const directory_entry&;
+
+ // [fs.dir.itr.members] member functions
+ directory_iterator() noexcept;
+#ifdef GHC_WITH_EXCEPTIONS
+ explicit directory_iterator(const path& p);
+ directory_iterator(const path& p, directory_options options);
+#endif
+ directory_iterator(const path& p, std::error_code& ec) noexcept;
+ directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept;
+ directory_iterator(const directory_iterator& rhs);
+ directory_iterator(directory_iterator&& rhs) noexcept;
+ ~directory_iterator();
+ directory_iterator& operator=(const directory_iterator& rhs);
+ directory_iterator& operator=(directory_iterator&& rhs) noexcept;
+ const directory_entry& operator*() const;
+ const directory_entry* operator->() const;
+#ifdef GHC_WITH_EXCEPTIONS
+ directory_iterator& operator++();
+#endif
+ directory_iterator& increment(std::error_code& ec) noexcept;
+
+ // other members as required by [input.iterators]
+#ifdef GHC_WITH_EXCEPTIONS
+ proxy operator++(int)
+ {
+ proxy p{**this};
+ ++*this;
+ return p;
+ }
+#endif
+ bool operator==(const directory_iterator& rhs) const;
+ bool operator!=(const directory_iterator& rhs) const;
+
+private:
+ friend class recursive_directory_iterator;
+ class impl;
+ std::shared_ptr<impl> _impl;
+};
+
+// [fs.dir.itr.nonmembers] directory_iterator non-member functions
+GHC_FS_API directory_iterator begin(directory_iterator iter) noexcept;
+GHC_FS_API directory_iterator end(const directory_iterator&) noexcept;
+
+// [fs.class.re.dir.itr] class recursive_directory_iterator
+class GHC_FS_API_CLASS recursive_directory_iterator
+{
+public:
+ using iterator_category = std::input_iterator_tag;
+ using value_type = directory_entry;
+ using difference_type = std::ptrdiff_t;
+ using pointer = const directory_entry*;
+ using reference = const directory_entry&;
+
+ // [fs.rec.dir.itr.members] constructors and destructor
+ recursive_directory_iterator() noexcept;
+#ifdef GHC_WITH_EXCEPTIONS
+ explicit recursive_directory_iterator(const path& p);
+ recursive_directory_iterator(const path& p, directory_options options);
+#endif
+ recursive_directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept;
+ recursive_directory_iterator(const path& p, std::error_code& ec) noexcept;
+ recursive_directory_iterator(const recursive_directory_iterator& rhs);
+ recursive_directory_iterator(recursive_directory_iterator&& rhs) noexcept;
+ ~recursive_directory_iterator();
+
+ // [fs.rec.dir.itr.members] observers
+ directory_options options() const;
+ int depth() const;
+ bool recursion_pending() const;
+
+ const directory_entry& operator*() const;
+ const directory_entry* operator->() const;
+
+ // [fs.rec.dir.itr.members] modifiers recursive_directory_iterator&
+ recursive_directory_iterator& operator=(const recursive_directory_iterator& rhs);
+ recursive_directory_iterator& operator=(recursive_directory_iterator&& rhs) noexcept;
+#ifdef GHC_WITH_EXCEPTIONS
+ recursive_directory_iterator& operator++();
+#endif
+ recursive_directory_iterator& increment(std::error_code& ec) noexcept;
+
+#ifdef GHC_WITH_EXCEPTIONS
+ void pop();
+#endif
+ void pop(std::error_code& ec);
+ void disable_recursion_pending();
+
+ // other members as required by [input.iterators]
+#ifdef GHC_WITH_EXCEPTIONS
+ directory_iterator::proxy operator++(int)
+ {
+ directory_iterator::proxy proxy{**this};
+ ++*this;
+ return proxy;
+ }
+#endif
+ bool operator==(const recursive_directory_iterator& rhs) const;
+ bool operator!=(const recursive_directory_iterator& rhs) const;
+
+private:
+ struct recursive_directory_iterator_impl
+ {
+ directory_options _options;
+ bool _recursion_pending;
+ std::stack<directory_iterator> _dir_iter_stack;
+ recursive_directory_iterator_impl(directory_options options, bool recursion_pending)
+ : _options(options)
+ , _recursion_pending(recursion_pending)
+ {
+ }
+ };
+ std::shared_ptr<recursive_directory_iterator_impl> _impl;
+};
+
+// [fs.rec.dir.itr.nonmembers] directory_iterator non-member functions
+GHC_FS_API recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept;
+GHC_FS_API recursive_directory_iterator end(const recursive_directory_iterator&) noexcept;
+
+// [fs.op.funcs] filesystem operations
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_FS_API path absolute(const path& p);
+GHC_FS_API path canonical(const path& p);
+GHC_FS_API void copy(const path& from, const path& to);
+GHC_FS_API void copy(const path& from, const path& to, copy_options options);
+GHC_FS_API bool copy_file(const path& from, const path& to);
+GHC_FS_API bool copy_file(const path& from, const path& to, copy_options option);
+GHC_FS_API void copy_symlink(const path& existing_symlink, const path& new_symlink);
+GHC_FS_API bool create_directories(const path& p);
+GHC_FS_API bool create_directory(const path& p);
+GHC_FS_API bool create_directory(const path& p, const path& attributes);
+GHC_FS_API void create_directory_symlink(const path& to, const path& new_symlink);
+GHC_FS_API void create_symlink(const path& to, const path& new_symlink);
+GHC_FS_API path current_path();
+GHC_FS_API void current_path(const path& p);
+GHC_FS_API bool exists(const path& p);
+GHC_FS_API bool equivalent(const path& p1, const path& p2);
+GHC_FS_API uintmax_t file_size(const path& p);
+GHC_FS_API bool is_block_file(const path& p);
+GHC_FS_API bool is_character_file(const path& p);
+GHC_FS_API bool is_directory(const path& p);
+GHC_FS_API bool is_empty(const path& p);
+GHC_FS_API bool is_fifo(const path& p);
+GHC_FS_API bool is_other(const path& p);
+GHC_FS_API bool is_regular_file(const path& p);
+GHC_FS_API bool is_socket(const path& p);
+GHC_FS_API bool is_symlink(const path& p);
+GHC_FS_API file_time_type last_write_time(const path& p);
+GHC_FS_API void last_write_time(const path& p, file_time_type new_time);
+GHC_FS_API void permissions(const path& p, perms prms, perm_options opts = perm_options::replace);
+GHC_FS_API path proximate(const path& p, const path& base = current_path());
+GHC_FS_API path read_symlink(const path& p);
+GHC_FS_API path relative(const path& p, const path& base = current_path());
+GHC_FS_API bool remove(const path& p);
+GHC_FS_API uintmax_t remove_all(const path& p);
+GHC_FS_API void rename(const path& from, const path& to);
+GHC_FS_API void resize_file(const path& p, uintmax_t size);
+GHC_FS_API space_info space(const path& p);
+GHC_FS_API file_status status(const path& p);
+GHC_FS_API file_status symlink_status(const path& p);
+GHC_FS_API path temp_directory_path();
+GHC_FS_API path weakly_canonical(const path& p);
+#endif
+GHC_FS_API path absolute(const path& p, std::error_code& ec);
+GHC_FS_API path canonical(const path& p, std::error_code& ec);
+GHC_FS_API void copy(const path& from, const path& to, std::error_code& ec) noexcept;
+GHC_FS_API void copy(const path& from, const path& to, copy_options options, std::error_code& ec) noexcept;
+GHC_FS_API bool copy_file(const path& from, const path& to, std::error_code& ec) noexcept;
+GHC_FS_API bool copy_file(const path& from, const path& to, copy_options option, std::error_code& ec) noexcept;
+GHC_FS_API void copy_symlink(const path& existing_symlink, const path& new_symlink, std::error_code& ec) noexcept;
+GHC_FS_API bool create_directories(const path& p, std::error_code& ec) noexcept;
+GHC_FS_API bool create_directory(const path& p, std::error_code& ec) noexcept;
+GHC_FS_API bool create_directory(const path& p, const path& attributes, std::error_code& ec) noexcept;
+GHC_FS_API void create_directory_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept;
+GHC_FS_API void create_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept;
+GHC_FS_API path current_path(std::error_code& ec);
+GHC_FS_API void current_path(const path& p, std::error_code& ec) noexcept;
+GHC_FS_API bool exists(file_status s) noexcept;
+GHC_FS_API bool exists(const path& p, std::error_code& ec) noexcept;
+GHC_FS_API bool equivalent(const path& p1, const path& p2, std::error_code& ec) noexcept;
+GHC_FS_API uintmax_t file_size(const path& p, std::error_code& ec) noexcept;
+GHC_FS_API bool is_block_file(file_status s) noexcept;
+GHC_FS_API bool is_block_file(const path& p, std::error_code& ec) noexcept;
+GHC_FS_API bool is_character_file(file_status s) noexcept;
+GHC_FS_API bool is_character_file(const path& p, std::error_code& ec) noexcept;
+GHC_FS_API bool is_directory(file_status s) noexcept;
+GHC_FS_API bool is_directory(const path& p, std::error_code& ec) noexcept;
+GHC_FS_API bool is_empty(const path& p, std::error_code& ec) noexcept;
+GHC_FS_API bool is_fifo(file_status s) noexcept;
+GHC_FS_API bool is_fifo(const path& p, std::error_code& ec) noexcept;
+GHC_FS_API bool is_other(file_status s) noexcept;
+GHC_FS_API bool is_other(const path& p, std::error_code& ec) noexcept;
+GHC_FS_API bool is_regular_file(file_status s) noexcept;
+GHC_FS_API bool is_regular_file(const path& p, std::error_code& ec) noexcept;
+GHC_FS_API bool is_socket(file_status s) noexcept;
+GHC_FS_API bool is_socket(const path& p, std::error_code& ec) noexcept;
+GHC_FS_API bool is_symlink(file_status s) noexcept;
+GHC_FS_API bool is_symlink(const path& p, std::error_code& ec) noexcept;
+GHC_FS_API file_time_type last_write_time(const path& p, std::error_code& ec) noexcept;
+GHC_FS_API void last_write_time(const path& p, file_time_type new_time, std::error_code& ec) noexcept;
+GHC_FS_API void permissions(const path& p, perms prms, std::error_code& ec) noexcept;
+GHC_FS_API void permissions(const path& p, perms prms, perm_options opts, std::error_code& ec) noexcept;
+GHC_FS_API path proximate(const path& p, std::error_code& ec);
+GHC_FS_API path proximate(const path& p, const path& base, std::error_code& ec);
+GHC_FS_API path read_symlink(const path& p, std::error_code& ec);
+GHC_FS_API path relative(const path& p, std::error_code& ec);
+GHC_FS_API path relative(const path& p, const path& base, std::error_code& ec);
+GHC_FS_API bool remove(const path& p, std::error_code& ec) noexcept;
+GHC_FS_API uintmax_t remove_all(const path& p, std::error_code& ec) noexcept;
+GHC_FS_API void rename(const path& from, const path& to, std::error_code& ec) noexcept;
+GHC_FS_API void resize_file(const path& p, uintmax_t size, std::error_code& ec) noexcept;
+GHC_FS_API space_info space(const path& p, std::error_code& ec) noexcept;
+GHC_FS_API file_status status(const path& p, std::error_code& ec) noexcept;
+GHC_FS_API bool status_known(file_status s) noexcept;
+GHC_FS_API file_status symlink_status(const path& p, std::error_code& ec) noexcept;
+GHC_FS_API path temp_directory_path(std::error_code& ec) noexcept;
+GHC_FS_API path weakly_canonical(const path& p, std::error_code& ec) noexcept;
+
+#ifndef GHC_OS_WEB
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_FS_API void create_hard_link(const path& to, const path& new_hard_link);
+GHC_FS_API uintmax_t hard_link_count(const path& p);
+#endif
+GHC_FS_API void create_hard_link(const path& to, const path& new_hard_link, std::error_code& ec) noexcept;
+GHC_FS_API uintmax_t hard_link_count(const path& p, std::error_code& ec) noexcept;
+#endif
+
+// Non-C++17 add-on std::fstream wrappers with path
+template <class charT, class traits = std::char_traits<charT>>
+class basic_filebuf : public std::basic_filebuf<charT, traits>
+{
+public:
+ basic_filebuf() {}
+ ~basic_filebuf() override {}
+ basic_filebuf(const basic_filebuf&) = delete;
+ const basic_filebuf& operator=(const basic_filebuf&) = delete;
+ basic_filebuf<charT, traits>* open(const path& p, std::ios_base::openmode mode)
+ {
+#if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__)
+ return std::basic_filebuf<charT, traits>::open(p.wstring().c_str(), mode) ? this : 0;
+#else
+ return std::basic_filebuf<charT, traits>::open(p.string().c_str(), mode) ? this : 0;
+#endif
+ }
+};
+
+template <class charT, class traits = std::char_traits<charT>>
+class basic_ifstream : public std::basic_ifstream<charT, traits>
+{
+public:
+ basic_ifstream() {}
+#if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__)
+ explicit basic_ifstream(const path& p, std::ios_base::openmode mode = std::ios_base::in)
+ : std::basic_ifstream<charT, traits>(p.wstring().c_str(), mode)
+ {
+ }
+ void open(const path& p, std::ios_base::openmode mode = std::ios_base::in) { std::basic_ifstream<charT, traits>::open(p.wstring().c_str(), mode); }
+#else
+ explicit basic_ifstream(const path& p, std::ios_base::openmode mode = std::ios_base::in)
+ : std::basic_ifstream<charT, traits>(p.string().c_str(), mode)
+ {
+ }
+ void open(const path& p, std::ios_base::openmode mode = std::ios_base::in) { std::basic_ifstream<charT, traits>::open(p.string().c_str(), mode); }
+#endif
+ basic_ifstream(const basic_ifstream&) = delete;
+ const basic_ifstream& operator=(const basic_ifstream&) = delete;
+ ~basic_ifstream() override {}
+};
+
+template <class charT, class traits = std::char_traits<charT>>
+class basic_ofstream : public std::basic_ofstream<charT, traits>
+{
+public:
+ basic_ofstream() {}
+#if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__)
+ explicit basic_ofstream(const path& p, std::ios_base::openmode mode = std::ios_base::out)
+ : std::basic_ofstream<charT, traits>(p.wstring().c_str(), mode)
+ {
+ }
+ void open(const path& p, std::ios_base::openmode mode = std::ios_base::out) { std::basic_ofstream<charT, traits>::open(p.wstring().c_str(), mode); }
+#else
+ explicit basic_ofstream(const path& p, std::ios_base::openmode mode = std::ios_base::out)
+ : std::basic_ofstream<charT, traits>(p.string().c_str(), mode)
+ {
+ }
+ void open(const path& p, std::ios_base::openmode mode = std::ios_base::out) { std::basic_ofstream<charT, traits>::open(p.string().c_str(), mode); }
+#endif
+ basic_ofstream(const basic_ofstream&) = delete;
+ const basic_ofstream& operator=(const basic_ofstream&) = delete;
+ ~basic_ofstream() override {}
+};
+
+template <class charT, class traits = std::char_traits<charT>>
+class basic_fstream : public std::basic_fstream<charT, traits>
+{
+public:
+ basic_fstream() {}
+#if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__)
+ explicit basic_fstream(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out)
+ : std::basic_fstream<charT, traits>(p.wstring().c_str(), mode)
+ {
+ }
+ void open(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) { std::basic_fstream<charT, traits>::open(p.wstring().c_str(), mode); }
+#else
+ explicit basic_fstream(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out)
+ : std::basic_fstream<charT, traits>(p.string().c_str(), mode)
+ {
+ }
+ void open(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) { std::basic_fstream<charT, traits>::open(p.string().c_str(), mode); }
+#endif
+ basic_fstream(const basic_fstream&) = delete;
+ const basic_fstream& operator=(const basic_fstream&) = delete;
+ ~basic_fstream() override {}
+};
+
+typedef basic_filebuf<char> filebuf;
+typedef basic_filebuf<wchar_t> wfilebuf;
+typedef basic_ifstream<char> ifstream;
+typedef basic_ifstream<wchar_t> wifstream;
+typedef basic_ofstream<char> ofstream;
+typedef basic_ofstream<wchar_t> wofstream;
+typedef basic_fstream<char> fstream;
+typedef basic_fstream<wchar_t> wfstream;
+
+class GHC_FS_API_CLASS u8arguments
+{
+public:
+ u8arguments(int& argc, char**& argv);
+ ~u8arguments()
+ {
+ _refargc = _argc;
+ _refargv = _argv;
+ }
+
+ bool valid() const { return _isvalid; }
+
+private:
+ int _argc;
+ char** _argv;
+ int& _refargc;
+ char**& _refargv;
+ bool _isvalid;
+#ifdef GHC_OS_WINDOWS
+ std::vector<std::string> _args;
+ std::vector<char*> _argp;
+#endif
+};
+
+//-------------------------------------------------------------------------------------------------
+// Implementation
+//-------------------------------------------------------------------------------------------------
+
+namespace detail {
+enum utf8_states_t { S_STRT = 0, S_RJCT = 8 };
+GHC_FS_API void appendUTF8(std::string& str, uint32_t unicode);
+GHC_FS_API bool is_surrogate(uint32_t c);
+GHC_FS_API bool is_high_surrogate(uint32_t c);
+GHC_FS_API bool is_low_surrogate(uint32_t c);
+GHC_FS_API unsigned consumeUtf8Fragment(const unsigned state, const uint8_t fragment, uint32_t& codepoint);
+enum class portable_error {
+ none = 0,
+ exists,
+ not_found,
+ not_supported,
+ not_implemented,
+ invalid_argument,
+ is_a_directory,
+};
+GHC_FS_API std::error_code make_error_code(portable_error err);
+#ifdef GHC_OS_WINDOWS
+GHC_FS_API std::error_code make_system_error(uint32_t err = 0);
+#else
+GHC_FS_API std::error_code make_system_error(int err = 0);
+#endif
+} // namespace detail
+
+namespace detail {
+
+#ifdef GHC_EXPAND_IMPL
+
+GHC_INLINE std::error_code make_error_code(portable_error err)
+{
+#ifdef GHC_OS_WINDOWS
+ switch (err) {
+ case portable_error::none:
+ return std::error_code();
+ case portable_error::exists:
+ return std::error_code(ERROR_ALREADY_EXISTS, std::system_category());
+ case portable_error::not_found:
+ return std::error_code(ERROR_PATH_NOT_FOUND, std::system_category());
+ case portable_error::not_supported:
+ return std::error_code(ERROR_NOT_SUPPORTED, std::system_category());
+ case portable_error::not_implemented:
+ return std::error_code(ERROR_CALL_NOT_IMPLEMENTED, std::system_category());
+ case portable_error::invalid_argument:
+ return std::error_code(ERROR_INVALID_PARAMETER, std::system_category());
+ case portable_error::is_a_directory:
+#ifdef ERROR_DIRECTORY_NOT_SUPPORTED
+ return std::error_code(ERROR_DIRECTORY_NOT_SUPPORTED, std::system_category());
+#else
+ return std::error_code(ERROR_NOT_SUPPORTED, std::system_category());
+#endif
+ }
+#else
+ switch (err) {
+ case portable_error::none:
+ return std::error_code();
+ case portable_error::exists:
+ return std::error_code(EEXIST, std::system_category());
+ case portable_error::not_found:
+ return std::error_code(ENOENT, std::system_category());
+ case portable_error::not_supported:
+ return std::error_code(ENOTSUP, std::system_category());
+ case portable_error::not_implemented:
+ return std::error_code(ENOSYS, std::system_category());
+ case portable_error::invalid_argument:
+ return std::error_code(EINVAL, std::system_category());
+ case portable_error::is_a_directory:
+ return std::error_code(EISDIR, std::system_category());
+ }
+#endif
+ return std::error_code();
+}
+
+#ifdef GHC_OS_WINDOWS
+GHC_INLINE std::error_code make_system_error(uint32_t err)
+{
+ return std::error_code(err ? static_cast<int>(err) : static_cast<int>(::GetLastError()), std::system_category());
+}
+#else
+GHC_INLINE std::error_code make_system_error(int err)
+{
+ return std::error_code(err ? err : errno, std::system_category());
+}
+#endif
+
+#endif // GHC_EXPAND_IMPL
+
+template <typename Enum>
+using EnableBitmask = typename std::enable_if<std::is_same<Enum, perms>::value || std::is_same<Enum, perm_options>::value || std::is_same<Enum, copy_options>::value || std::is_same<Enum, directory_options>::value, Enum>::type;
+} // namespace detail
+
+template <typename Enum>
+constexpr detail::EnableBitmask<Enum> operator&(Enum X, Enum Y)
+{
+ using underlying = typename std::underlying_type<Enum>::type;
+ return static_cast<Enum>(static_cast<underlying>(X) & static_cast<underlying>(Y));
+}
+
+template <typename Enum>
+constexpr detail::EnableBitmask<Enum> operator|(Enum X, Enum Y)
+{
+ using underlying = typename std::underlying_type<Enum>::type;
+ return static_cast<Enum>(static_cast<underlying>(X) | static_cast<underlying>(Y));
+}
+
+template <typename Enum>
+constexpr detail::EnableBitmask<Enum> operator^(Enum X, Enum Y)
+{
+ using underlying = typename std::underlying_type<Enum>::type;
+ return static_cast<Enum>(static_cast<underlying>(X) ^ static_cast<underlying>(Y));
+}
+
+template <typename Enum>
+constexpr detail::EnableBitmask<Enum> operator~(Enum X)
+{
+ using underlying = typename std::underlying_type<Enum>::type;
+ return static_cast<Enum>(~static_cast<underlying>(X));
+}
+
+template <typename Enum>
+detail::EnableBitmask<Enum>& operator&=(Enum& X, Enum Y)
+{
+ X = X & Y;
+ return X;
+}
+
+template <typename Enum>
+detail::EnableBitmask<Enum>& operator|=(Enum& X, Enum Y)
+{
+ X = X | Y;
+ return X;
+}
+
+template <typename Enum>
+detail::EnableBitmask<Enum>& operator^=(Enum& X, Enum Y)
+{
+ X = X ^ Y;
+ return X;
+}
+
+#ifdef GHC_EXPAND_IMPL
+
+namespace detail {
+
+GHC_INLINE bool in_range(uint32_t c, uint32_t lo, uint32_t hi)
+{
+ return (static_cast<uint32_t>(c - lo) < (hi - lo + 1));
+}
+
+GHC_INLINE bool is_surrogate(uint32_t c)
+{
+ return in_range(c, 0xd800, 0xdfff);
+}
+
+GHC_INLINE bool is_high_surrogate(uint32_t c)
+{
+ return (c & 0xfffffc00) == 0xd800;
+}
+
+GHC_INLINE bool is_low_surrogate(uint32_t c)
+{
+ return (c & 0xfffffc00) == 0xdc00;
+}
+
+GHC_INLINE void appendUTF8(std::string& str, uint32_t unicode)
+{
+ if (unicode <= 0x7f) {
+ str.push_back(static_cast<char>(unicode));
+ }
+ else if (unicode >= 0x80 && unicode <= 0x7ff) {
+ str.push_back(static_cast<char>((unicode >> 6) + 192));
+ str.push_back(static_cast<char>((unicode & 0x3f) + 128));
+ }
+ else if ((unicode >= 0x800 && unicode <= 0xd7ff) || (unicode >= 0xe000 && unicode <= 0xffff)) {
+ str.push_back(static_cast<char>((unicode >> 12) + 224));
+ str.push_back(static_cast<char>(((unicode & 0xfff) >> 6) + 128));
+ str.push_back(static_cast<char>((unicode & 0x3f) + 128));
+ }
+ else if (unicode >= 0x10000 && unicode <= 0x10ffff) {
+ str.push_back(static_cast<char>((unicode >> 18) + 240));
+ str.push_back(static_cast<char>(((unicode & 0x3ffff) >> 12) + 128));
+ str.push_back(static_cast<char>(((unicode & 0xfff) >> 6) + 128));
+ str.push_back(static_cast<char>((unicode & 0x3f) + 128));
+ }
+ else {
+#ifdef GHC_RAISE_UNICODE_ERRORS
+ throw filesystem_error("Illegal code point for unicode character.", str, std::make_error_code(std::errc::illegal_byte_sequence));
+#else
+ appendUTF8(str, 0xfffd);
+#endif
+ }
+}
+
+// Thanks to Bjoern Hoehrmann (https://bjoern.hoehrmann.de/utf-8/decoder/dfa/)
+// and Taylor R Campbell for the ideas to this DFA approach of UTF-8 decoding;
+// Generating debugging and shrinking my own DFA from scratch was a day of fun!
+GHC_INLINE unsigned consumeUtf8Fragment(const unsigned state, const uint8_t fragment, uint32_t& codepoint)
+{
+ static const uint32_t utf8_state_info[] = {
+ // encoded states
+ 0x11111111u, 0x11111111u, 0x77777777u, 0x77777777u, 0x88888888u, 0x88888888u, 0x88888888u, 0x88888888u, 0x22222299u, 0x22222222u, 0x22222222u, 0x22222222u, 0x3333333au, 0x33433333u, 0x9995666bu, 0x99999999u,
+ 0x88888880u, 0x22818108u, 0x88888881u, 0x88888882u, 0x88888884u, 0x88888887u, 0x88888886u, 0x82218108u, 0x82281108u, 0x88888888u, 0x88888883u, 0x88888885u, 0u, 0u, 0u, 0u,
+ };
+ uint8_t category = fragment < 128 ? 0 : (utf8_state_info[(fragment >> 3) & 0xf] >> ((fragment & 7) << 2)) & 0xf;
+ codepoint = (state ? (codepoint << 6) | (fragment & 0x3fu) : (0xffu >> category) & fragment);
+ return state == S_RJCT ? static_cast<unsigned>(S_RJCT) : static_cast<unsigned>((utf8_state_info[category + 16] >> (state << 2)) & 0xf);
+}
+
+GHC_INLINE bool validUtf8(const std::string& utf8String)
+{
+ std::string::const_iterator iter = utf8String.begin();
+ unsigned utf8_state = S_STRT;
+ std::uint32_t codepoint = 0;
+ while (iter < utf8String.end()) {
+ if ((utf8_state = consumeUtf8Fragment(utf8_state, static_cast<uint8_t>(*iter++), codepoint)) == S_RJCT) {
+ return false;
+ }
+ }
+ if (utf8_state) {
+ return false;
+ }
+ return true;
+}
+
+} // namespace detail
+
+#endif
+
+namespace detail {
+
+template <class StringType, class Utf8String, typename std::enable_if<path::_is_basic_string<Utf8String>::value && (sizeof(typename Utf8String::value_type) == 1) && (sizeof(typename StringType::value_type) == 1)>::type* = nullptr>
+inline StringType fromUtf8(const Utf8String& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type())
+{
+ return StringType(utf8String.begin(), utf8String.end(), alloc);
+}
+
+template <class StringType, class Utf8String, typename std::enable_if<path::_is_basic_string<Utf8String>::value && (sizeof(typename Utf8String::value_type) == 1) && (sizeof(typename StringType::value_type) == 2)>::type* = nullptr>
+inline StringType fromUtf8(const Utf8String& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type())
+{
+ StringType result(alloc);
+ result.reserve(utf8String.length());
+ auto iter = utf8String.cbegin();
+ unsigned utf8_state = S_STRT;
+ std::uint32_t codepoint = 0;
+ while (iter < utf8String.cend()) {
+ if ((utf8_state = consumeUtf8Fragment(utf8_state, static_cast<uint8_t>(*iter++), codepoint)) == S_STRT) {
+ if (codepoint <= 0xffff) {
+ result += static_cast<typename StringType::value_type>(codepoint);
+ }
+ else {
+ codepoint -= 0x10000;
+ result += static_cast<typename StringType::value_type>((codepoint >> 10) + 0xd800);
+ result += static_cast<typename StringType::value_type>((codepoint & 0x3ff) + 0xdc00);
+ }
+ codepoint = 0;
+ }
+ else if (utf8_state == S_RJCT) {
+#ifdef GHC_RAISE_UNICODE_ERRORS
+ throw filesystem_error("Illegal byte sequence for unicode character.", utf8String, std::make_error_code(std::errc::illegal_byte_sequence));
+#else
+ result += static_cast<typename StringType::value_type>(0xfffd);
+ utf8_state = S_STRT;
+ codepoint = 0;
+#endif
+ }
+ }
+ if (utf8_state) {
+#ifdef GHC_RAISE_UNICODE_ERRORS
+ throw filesystem_error("Illegal byte sequence for unicode character.", utf8String, std::make_error_code(std::errc::illegal_byte_sequence));
+#else
+ result += static_cast<typename StringType::value_type>(0xfffd);
+#endif
+ }
+ return result;
+}
+
+template <class StringType, class Utf8String, typename std::enable_if<path::_is_basic_string<Utf8String>::value && (sizeof(typename Utf8String::value_type) == 1) && (sizeof(typename StringType::value_type) == 4)>::type* = nullptr>
+inline StringType fromUtf8(const Utf8String& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type())
+{
+ StringType result(alloc);
+ result.reserve(utf8String.length());
+ auto iter = utf8String.cbegin();
+ unsigned utf8_state = S_STRT;
+ std::uint32_t codepoint = 0;
+ while (iter < utf8String.cend()) {
+ if ((utf8_state = consumeUtf8Fragment(utf8_state, static_cast<uint8_t>(*iter++), codepoint)) == S_STRT) {
+ result += static_cast<typename StringType::value_type>(codepoint);
+ codepoint = 0;
+ }
+ else if (utf8_state == S_RJCT) {
+#ifdef GHC_RAISE_UNICODE_ERRORS
+ throw filesystem_error("Illegal byte sequence for unicode character.", utf8String, std::make_error_code(std::errc::illegal_byte_sequence));
+#else
+ result += static_cast<typename StringType::value_type>(0xfffd);
+ utf8_state = S_STRT;
+ codepoint = 0;
+#endif
+ }
+ }
+ if (utf8_state) {
+#ifdef GHC_RAISE_UNICODE_ERRORS
+ throw filesystem_error("Illegal byte sequence for unicode character.", utf8String, std::make_error_code(std::errc::illegal_byte_sequence));
+#else
+ result += static_cast<typename StringType::value_type>(0xfffd);
+#endif
+ }
+ return result;
+}
+
+template <class StringType, typename charT, std::size_t N>
+inline StringType fromUtf8(const charT (&utf8String)[N])
+{
+#ifdef GHC_WITH_STRING_VIEW
+ return fromUtf8<StringType>(basic_string_view<charT>(utf8String, N - 1));
+#else
+ return fromUtf8<StringType>(std::basic_string<charT>(utf8String, N - 1));
+#endif
+}
+
+template <typename strT, typename std::enable_if<path::_is_basic_string<strT>::value && (sizeof(typename strT::value_type) == 1), int>::type size = 1>
+inline std::string toUtf8(const strT& unicodeString)
+{
+ return std::string(unicodeString.begin(), unicodeString.end());
+}
+
+template <typename strT, typename std::enable_if<path::_is_basic_string<strT>::value && (sizeof(typename strT::value_type) == 2), int>::type size = 2>
+inline std::string toUtf8(const strT& unicodeString)
+{
+ std::string result;
+ for (auto iter = unicodeString.begin(); iter != unicodeString.end(); ++iter) {
+ char32_t c = *iter;
+ if (is_surrogate(c)) {
+ ++iter;
+ if (iter != unicodeString.end() && is_high_surrogate(c) && is_low_surrogate(*iter)) {
+ appendUTF8(result, (char32_t(c) << 10) + *iter - 0x35fdc00);
+ }
+ else {
+#ifdef GHC_RAISE_UNICODE_ERRORS
+ throw filesystem_error("Illegal code point for unicode character.", result, std::make_error_code(std::errc::illegal_byte_sequence));
+#else
+ appendUTF8(result, 0xfffd);
+ if (iter == unicodeString.end()) {
+ break;
+ }
+#endif
+ }
+ }
+ else {
+ appendUTF8(result, c);
+ }
+ }
+ return result;
+}
+
+template <typename strT, typename std::enable_if<path::_is_basic_string<strT>::value && (sizeof(typename strT::value_type) == 4), int>::type size = 4>
+inline std::string toUtf8(const strT& unicodeString)
+{
+ std::string result;
+ for (auto c : unicodeString) {
+ appendUTF8(result, static_cast<uint32_t>(c));
+ }
+ return result;
+}
+
+template <typename charT>
+inline std::string toUtf8(const charT* unicodeString)
+{
+#ifdef GHC_WITH_STRING_VIEW
+ return toUtf8(basic_string_view<charT, std::char_traits<charT>>(unicodeString));
+#else
+ return toUtf8(std::basic_string<charT, std::char_traits<charT>>(unicodeString));
+#endif
+}
+
+#ifdef GHC_USE_WCHAR_T
+template <class StringType, class WString, typename std::enable_if<path::_is_basic_string<WString>::value && (sizeof(typename WString::value_type) == 2) && (sizeof(typename StringType::value_type) == 1), bool>::type = false>
+inline StringType fromWChar(const WString& wString, const typename StringType::allocator_type& alloc = typename StringType::allocator_type())
+{
+ auto temp = toUtf8(wString);
+ return StringType(temp.begin(), temp.end(), alloc);
+}
+
+template <class StringType, class WString, typename std::enable_if<path::_is_basic_string<WString>::value && (sizeof(typename WString::value_type) == 2) && (sizeof(typename StringType::value_type) == 2), bool>::type = false>
+inline StringType fromWChar(const WString& wString, const typename StringType::allocator_type& alloc = typename StringType::allocator_type())
+{
+ return StringType(wString.begin(), wString.end(), alloc);
+}
+
+template <class StringType, class WString, typename std::enable_if<path::_is_basic_string<WString>::value && (sizeof(typename WString::value_type) == 2) && (sizeof(typename StringType::value_type) == 4), bool>::type = false>
+inline StringType fromWChar(const WString& wString, const typename StringType::allocator_type& alloc = typename StringType::allocator_type())
+{
+ auto temp = toUtf8(wString);
+ return fromUtf8<StringType>(temp, alloc);
+}
+
+template <typename strT, typename std::enable_if<path::_is_basic_string<strT>::value && (sizeof(typename strT::value_type) == 1), bool>::type = false>
+inline std::wstring toWChar(const strT& unicodeString)
+{
+ return fromUtf8<std::wstring>(unicodeString);
+}
+
+template <typename strT, typename std::enable_if<path::_is_basic_string<strT>::value && (sizeof(typename strT::value_type) == 2), bool>::type = false>
+inline std::wstring toWChar(const strT& unicodeString)
+{
+ return std::wstring(unicodeString.begin(), unicodeString.end());
+}
+
+template <typename strT, typename std::enable_if<path::_is_basic_string<strT>::value && (sizeof(typename strT::value_type) == 4), bool>::type = false>
+inline std::wstring toWChar(const strT& unicodeString)
+{
+ auto temp = toUtf8(unicodeString);
+ return fromUtf8<std::wstring>(temp);
+}
+
+template <typename charT>
+inline std::wstring toWChar(const charT* unicodeString)
+{
+#ifdef GHC_WITH_STRING_VIEW
+ return toWChar(basic_string_view<charT, std::char_traits<charT>>(unicodeString));
+#else
+ return toWChar(std::basic_string<charT, std::char_traits<charT>>(unicodeString));
+#endif
+}
+#endif // GHC_USE_WCHAR_T
+
+} // namespace detail
+
+#ifdef GHC_EXPAND_IMPL
+
+namespace detail {
+
+template <typename strT, typename std::enable_if<path::_is_basic_string<strT>::value, bool>::type = true>
+GHC_INLINE bool startsWith(const strT& what, const strT& with)
+{
+ return with.length() <= what.length() && equal(with.begin(), with.end(), what.begin());
+}
+
+template <typename strT, typename std::enable_if<path::_is_basic_string<strT>::value, bool>::type = true>
+GHC_INLINE bool endsWith(const strT& what, const strT& with)
+{
+ return with.length() <= what.length() && what.compare(what.length() - with.length(), with.size(), with) == 0;
+}
+
+} // namespace detail
+
+GHC_INLINE void path::check_long_path()
+{
+#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH)
+ if (is_absolute() && _path.length() >= MAX_PATH - 12 && !detail::startsWith(_path, impl_string_type(GHC_PLATFORM_LITERAL("\\\\?\\")))) {
+ postprocess_path_with_format(native_format);
+ }
+#endif
+}
+
+GHC_INLINE void path::postprocess_path_with_format(path::format fmt)
+{
+#ifdef GHC_RAISE_UNICODE_ERRORS
+ if (!detail::validUtf8(_path)) {
+ path t;
+ t._path = _path;
+ throw filesystem_error("Illegal byte sequence for unicode character.", t, std::make_error_code(std::errc::illegal_byte_sequence));
+ }
+#endif
+ switch (fmt) {
+#ifdef GHC_OS_WINDOWS
+ case path::native_format:
+ case path::auto_format:
+ case path::generic_format:
+ for (auto& c : _path) {
+ if (c == generic_separator) {
+ c = preferred_separator;
+ }
+ }
+#ifdef GHC_WIN_AUTO_PREFIX_LONG_PATH
+ if (is_absolute() && _path.length() >= MAX_PATH - 12 && !detail::startsWith(_path, impl_string_type(GHC_PLATFORM_LITERAL("\\\\?\\")))) {
+ _path = GHC_PLATFORM_LITERAL("\\\\?\\") + _path;
+ }
+#endif
+ handle_prefixes();
+ break;
+#else
+ case path::auto_format:
+ case path::native_format:
+ case path::generic_format:
+ // nothing to do
+ break;
+#endif
+ }
+ if (_path.length() > _prefixLength + 2 && _path[_prefixLength] == preferred_separator && _path[_prefixLength + 1] == preferred_separator && _path[_prefixLength + 2] != preferred_separator) {
+ impl_string_type::iterator new_end = std::unique(_path.begin() + static_cast<string_type::difference_type>(_prefixLength) + 2, _path.end(), [](path::value_type lhs, path::value_type rhs) { return lhs == rhs && lhs == preferred_separator; });
+ _path.erase(new_end, _path.end());
+ }
+ else {
+ impl_string_type::iterator new_end = std::unique(_path.begin() + static_cast<string_type::difference_type>(_prefixLength), _path.end(), [](path::value_type lhs, path::value_type rhs) { return lhs == rhs && lhs == preferred_separator; });
+ _path.erase(new_end, _path.end());
+ }
+}
+
+#endif // GHC_EXPAND_IMPL
+
+template <class Source, typename>
+inline path::path(const Source& source, format fmt)
+#ifdef GHC_USE_WCHAR_T
+ : _path(detail::toWChar(source))
+#else
+ : _path(detail::toUtf8(source))
+#endif
+{
+ postprocess_path_with_format(fmt);
+}
+
+template <class Source, typename>
+inline path u8path(const Source& source)
+{
+ return path(source);
+}
+template <class InputIterator>
+inline path u8path(InputIterator first, InputIterator last)
+{
+ return path(first, last);
+}
+
+template <class InputIterator>
+inline path::path(InputIterator first, InputIterator last, format fmt)
+ : path(std::basic_string<typename std::iterator_traits<InputIterator>::value_type>(first, last), fmt)
+{
+ // delegated
+}
+
+#ifdef GHC_EXPAND_IMPL
+
+namespace detail {
+
+GHC_INLINE bool equals_simple_insensitive(const path::value_type* str1, const path::value_type* str2)
+{
+#ifdef GHC_OS_WINDOWS
+#ifdef __GNUC__
+ while (::tolower((unsigned char)*str1) == ::tolower((unsigned char)*str2++)) {
+ if (*str1++ == 0)
+ return true;
+ }
+ return false;
+#else // __GNUC__
+#ifdef GHC_USE_WCHAR_T
+ return 0 == ::_wcsicmp(str1, str2);
+#else // GHC_USE_WCHAR_T
+ return 0 == ::_stricmp(str1, str2);
+#endif // GHC_USE_WCHAR_T
+#endif // __GNUC__
+#else // GHC_OS_WINDOWS
+ return 0 == ::strcasecmp(str1, str2);
+#endif // GHC_OS_WINDOWS
+}
+
+GHC_INLINE int compare_simple_insensitive(const path::value_type* str1, size_t len1, const path::value_type* str2, size_t len2)
+{
+ while (len1 > 0 && len2 > 0 && ::tolower(static_cast<unsigned char>(*str1)) == ::tolower(static_cast<unsigned char>(*str2))) {
+ --len1;
+ --len2;
+ ++str1;
+ ++str2;
+ }
+ if (len1 && len2) {
+ return *str1 < *str2 ? -1 : 1;
+ }
+ if (len1 == 0 && len2 == 0) {
+ return 0;
+ }
+ return len1 == 0 ? -1 : 1;
+}
+
+GHC_INLINE const char* strerror_adapter(char* gnu, char*)
+{
+ return gnu;
+}
+
+GHC_INLINE const char* strerror_adapter(int posix, char* buffer)
+{
+ if (posix) {
+ return "Error in strerror_r!";
+ }
+ return buffer;
+}
+
+template <typename ErrorNumber>
+GHC_INLINE std::string systemErrorText(ErrorNumber code = 0)
+{
+#if defined(GHC_OS_WINDOWS)
+ LPVOID msgBuf;
+ DWORD dw = code ? static_cast<DWORD>(code) : ::GetLastError();
+ FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&msgBuf, 0, NULL);
+ std::string msg = toUtf8(std::wstring((LPWSTR)msgBuf));
+ LocalFree(msgBuf);
+ return msg;
+#else
+ char buffer[512];
+ return strerror_adapter(strerror_r(code ? code : errno, buffer, sizeof(buffer)), buffer);
+#endif
+}
+
+#ifdef GHC_OS_WINDOWS
+using CreateSymbolicLinkW_fp = BOOLEAN(WINAPI*)(LPCWSTR, LPCWSTR, DWORD);
+using CreateHardLinkW_fp = BOOLEAN(WINAPI*)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES);
+
+GHC_INLINE void create_symlink(const path& target_name, const path& new_symlink, bool to_directory, std::error_code& ec)
+{
+ std::error_code tec;
+ auto fs = status(target_name, tec);
+ if ((fs.type() == file_type::directory && !to_directory) || (fs.type() == file_type::regular && to_directory)) {
+ ec = detail::make_error_code(detail::portable_error::not_supported);
+ return;
+ }
+#if defined(__GNUC__) && __GNUC__ >= 8
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-function-type"
+#endif
+ static CreateSymbolicLinkW_fp api_call = reinterpret_cast<CreateSymbolicLinkW_fp>(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "CreateSymbolicLinkW"));
+#if defined(__GNUC__) && __GNUC__ >= 8
+#pragma GCC diagnostic pop
+#endif
+ if (api_call) {
+ if (api_call(GHC_NATIVEWP(new_symlink), GHC_NATIVEWP(target_name), to_directory ? 1 : 0) == 0) {
+ auto result = ::GetLastError();
+ if (result == ERROR_PRIVILEGE_NOT_HELD && api_call(GHC_NATIVEWP(new_symlink), GHC_NATIVEWP(target_name), to_directory ? 3 : 2) != 0) {
+ return;
+ }
+ ec = detail::make_system_error(result);
+ }
+ }
+ else {
+ ec = detail::make_system_error(ERROR_NOT_SUPPORTED);
+ }
+}
+
+GHC_INLINE void create_hardlink(const path& target_name, const path& new_hardlink, std::error_code& ec)
+{
+#if defined(__GNUC__) && __GNUC__ >= 8
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-function-type"
+#endif
+ static CreateHardLinkW_fp api_call = reinterpret_cast<CreateHardLinkW_fp>(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "CreateHardLinkW"));
+#if defined(__GNUC__) && __GNUC__ >= 8
+#pragma GCC diagnostic pop
+#endif
+ if (api_call) {
+ if (api_call(GHC_NATIVEWP(new_hardlink), GHC_NATIVEWP(target_name), NULL) == 0) {
+ ec = detail::make_system_error();
+ }
+ }
+ else {
+ ec = detail::make_system_error(ERROR_NOT_SUPPORTED);
+ }
+}
+
+GHC_INLINE path getFullPathName(const wchar_t* p, std::error_code& ec)
+{
+ ULONG size = ::GetFullPathNameW(p, 0, 0, 0);
+ if (size) {
+ std::vector<wchar_t> buf(size, 0);
+ ULONG s2 = GetFullPathNameW(p, size, buf.data(), nullptr);
+ if (s2 && s2 < size) {
+ return path(std::wstring(buf.data(), s2));
+ }
+ }
+ ec = detail::make_system_error();
+ return path();
+}
+
+#else
+GHC_INLINE void create_symlink(const path& target_name, const path& new_symlink, bool, std::error_code& ec)
+{
+ if (::symlink(target_name.c_str(), new_symlink.c_str()) != 0) {
+ ec = detail::make_system_error();
+ }
+}
+
+#ifndef GHC_OS_WEB
+GHC_INLINE void create_hardlink(const path& target_name, const path& new_hardlink, std::error_code& ec)
+{
+ if (::link(target_name.c_str(), new_hardlink.c_str()) != 0) {
+ ec = detail::make_system_error();
+ }
+}
+#endif
+#endif
+
+template <typename T>
+GHC_INLINE file_status file_status_from_st_mode(T mode)
+{
+#ifdef GHC_OS_WINDOWS
+ file_type ft = file_type::unknown;
+ if ((mode & _S_IFDIR) == _S_IFDIR) {
+ ft = file_type::directory;
+ }
+ else if ((mode & _S_IFREG) == _S_IFREG) {
+ ft = file_type::regular;
+ }
+ else if ((mode & _S_IFCHR) == _S_IFCHR) {
+ ft = file_type::character;
+ }
+ perms prms = static_cast<perms>(mode & 0xfff);
+ return file_status(ft, prms);
+#else
+ file_type ft = file_type::unknown;
+ if (S_ISDIR(mode)) {
+ ft = file_type::directory;
+ }
+ else if (S_ISREG(mode)) {
+ ft = file_type::regular;
+ }
+ else if (S_ISCHR(mode)) {
+ ft = file_type::character;
+ }
+ else if (S_ISBLK(mode)) {
+ ft = file_type::block;
+ }
+ else if (S_ISFIFO(mode)) {
+ ft = file_type::fifo;
+ }
+ else if (S_ISLNK(mode)) {
+ ft = file_type::symlink;
+ }
+ else if (S_ISSOCK(mode)) {
+ ft = file_type::socket;
+ }
+ perms prms = static_cast<perms>(mode & 0xfff);
+ return file_status(ft, prms);
+#endif
+}
+
+#ifdef GHC_OS_WINDOWS
+
+class unique_handle
+{
+public:
+ typedef HANDLE element_type;
+
+ unique_handle() noexcept
+ : _handle(INVALID_HANDLE_VALUE)
+ {
+ }
+ explicit unique_handle(element_type h) noexcept
+ : _handle(h)
+ {
+ }
+ unique_handle(unique_handle&& u) noexcept
+ : _handle(u.release())
+ {
+ }
+ ~unique_handle() { reset(); }
+ unique_handle& operator=(unique_handle&& u) noexcept
+ {
+ reset(u.release());
+ return *this;
+ }
+ element_type get() const noexcept { return _handle; }
+ explicit operator bool() const noexcept { return _handle != INVALID_HANDLE_VALUE; }
+ element_type release() noexcept
+ {
+ element_type tmp = _handle;
+ _handle = INVALID_HANDLE_VALUE;
+ return tmp;
+ }
+ void reset(element_type h = INVALID_HANDLE_VALUE) noexcept
+ {
+ element_type tmp = _handle;
+ _handle = h;
+ if (tmp != INVALID_HANDLE_VALUE) {
+ CloseHandle(tmp);
+ }
+ }
+ void swap(unique_handle& u) noexcept { std::swap(_handle, u._handle); }
+
+private:
+ element_type _handle;
+};
+
+#ifndef REPARSE_DATA_BUFFER_HEADER_SIZE
+typedef struct _REPARSE_DATA_BUFFER
+{
+ ULONG ReparseTag;
+ USHORT ReparseDataLength;
+ USHORT Reserved;
+ union
+ {
+ struct
+ {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ ULONG Flags;
+ WCHAR PathBuffer[1];
+ } SymbolicLinkReparseBuffer;
+ struct
+ {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ WCHAR PathBuffer[1];
+ } MountPointReparseBuffer;
+ struct
+ {
+ UCHAR DataBuffer[1];
+ } GenericReparseBuffer;
+ } DUMMYUNIONNAME;
+} REPARSE_DATA_BUFFER;
+#ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE
+#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE (16 * 1024)
+#endif
+#endif
+
+template <class T>
+struct free_deleter
+{
+ void operator()(T* p) const { std::free(p); }
+};
+
+GHC_INLINE std::unique_ptr<REPARSE_DATA_BUFFER, free_deleter<REPARSE_DATA_BUFFER>> getReparseData(const path& p, std::error_code& ec)
+{
+ unique_handle file(CreateFileW(GHC_NATIVEWP(p), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 0));
+ if (!file) {
+ ec = detail::make_system_error();
+ return nullptr;
+ }
+
+ std::unique_ptr<REPARSE_DATA_BUFFER, free_deleter<REPARSE_DATA_BUFFER>> reparseData(reinterpret_cast<REPARSE_DATA_BUFFER*>(std::calloc(1, MAXIMUM_REPARSE_DATA_BUFFER_SIZE)));
+ ULONG bufferUsed;
+ if (DeviceIoControl(file.get(), FSCTL_GET_REPARSE_POINT, 0, 0, reparseData.get(), MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bufferUsed, 0)) {
+ return reparseData;
+ }
+ else {
+ ec = detail::make_system_error();
+ }
+ return nullptr;
+}
+#endif
+
+GHC_INLINE path resolveSymlink(const path& p, std::error_code& ec)
+{
+#ifdef GHC_OS_WINDOWS
+ path result;
+ auto reparseData = detail::getReparseData(p, ec);
+ if (!ec) {
+ if (reparseData && IsReparseTagMicrosoft(reparseData->ReparseTag)) {
+ switch (reparseData->ReparseTag) {
+ case IO_REPARSE_TAG_SYMLINK: {
+ auto printName = std::wstring(&reparseData->SymbolicLinkReparseBuffer.PathBuffer[reparseData->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(WCHAR)], reparseData->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(WCHAR));
+ auto substituteName =
+ std::wstring(&reparseData->SymbolicLinkReparseBuffer.PathBuffer[reparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)], reparseData->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(WCHAR));
+ if (detail::endsWith(substituteName, printName) && detail::startsWith(substituteName, std::wstring(L"\\??\\"))) {
+ result = printName;
+ }
+ else {
+ result = substituteName;
+ }
+ if (reparseData->SymbolicLinkReparseBuffer.Flags & 0x1 /*SYMLINK_FLAG_RELATIVE*/) {
+ result = p.parent_path() / result;
+ }
+ break;
+ }
+ case IO_REPARSE_TAG_MOUNT_POINT:
+ result = detail::getFullPathName(GHC_NATIVEWP(p), ec);
+ // result = std::wstring(&reparseData->MountPointReparseBuffer.PathBuffer[reparseData->MountPointReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)], reparseData->MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR));
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ return result;
+#else
+ size_t bufferSize = 256;
+ while (true) {
+ std::vector<char> buffer(bufferSize, static_cast<char>(0));
+ auto rc = ::readlink(p.c_str(), buffer.data(), buffer.size());
+ if (rc < 0) {
+ ec = detail::make_system_error();
+ return path();
+ }
+ else if (rc < static_cast<int>(bufferSize)) {
+ return path(std::string(buffer.data(), static_cast<std::string::size_type>(rc)));
+ }
+ bufferSize *= 2;
+ }
+ return path();
+#endif
+}
+
+#ifdef GHC_OS_WINDOWS
+GHC_INLINE time_t timeFromFILETIME(const FILETIME& ft)
+{
+ ULARGE_INTEGER ull;
+ ull.LowPart = ft.dwLowDateTime;
+ ull.HighPart = ft.dwHighDateTime;
+ return static_cast<time_t>(ull.QuadPart / 10000000ULL - 11644473600ULL);
+}
+
+GHC_INLINE void timeToFILETIME(time_t t, FILETIME& ft)
+{
+ LONGLONG ll;
+ ll = Int32x32To64(t, 10000000) + 116444736000000000;
+ ft.dwLowDateTime = static_cast<DWORD>(ll);
+ ft.dwHighDateTime = static_cast<DWORD>(ll >> 32);
+}
+
+template <typename INFO>
+GHC_INLINE uintmax_t hard_links_from_INFO(const INFO* info)
+{
+ return static_cast<uintmax_t>(-1);
+}
+
+template <>
+GHC_INLINE uintmax_t hard_links_from_INFO<BY_HANDLE_FILE_INFORMATION>(const BY_HANDLE_FILE_INFORMATION* info)
+{
+ return info->nNumberOfLinks;
+}
+
+template <typename INFO>
+GHC_INLINE DWORD reparse_tag_from_INFO(const INFO*)
+{
+ return 0;
+}
+
+template <>
+GHC_INLINE DWORD reparse_tag_from_INFO(const WIN32_FIND_DATAW* info)
+{
+ return info->dwReserved0;
+}
+
+template <typename INFO>
+GHC_INLINE file_status status_from_INFO(const path& p, const INFO* info, std::error_code& ec, uintmax_t* sz = nullptr, time_t* lwt = nullptr)
+{
+ file_type ft = file_type::unknown;
+ if (sizeof(INFO) == sizeof(WIN32_FIND_DATAW)) {
+ if (detail::reparse_tag_from_INFO(info) == IO_REPARSE_TAG_SYMLINK) {
+ ft = file_type::symlink;
+ }
+ }
+ else {
+ if ((info->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
+ auto reparseData = detail::getReparseData(p, ec);
+ if (!ec && reparseData && IsReparseTagMicrosoft(reparseData->ReparseTag) && reparseData->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
+ ft = file_type::symlink;
+ }
+ }
+ }
+ if (ft == file_type::unknown) {
+ if ((info->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
+ ft = file_type::directory;
+ }
+ else {
+ ft = file_type::regular;
+ }
+ }
+ perms prms = perms::owner_read | perms::group_read | perms::others_read;
+ if (!(info->dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
+ prms = prms | perms::owner_write | perms::group_write | perms::others_write;
+ }
+ if (has_executable_extension(p)) {
+ prms = prms | perms::owner_exec | perms::group_exec | perms::others_exec;
+ }
+ if (sz) {
+ *sz = static_cast<uintmax_t>(info->nFileSizeHigh) << (sizeof(info->nFileSizeHigh) * 8) | info->nFileSizeLow;
+ }
+ if (lwt) {
+ *lwt = detail::timeFromFILETIME(info->ftLastWriteTime);
+ }
+ return file_status(ft, prms);
+}
+
+#endif
+
+GHC_INLINE bool is_not_found_error(std::error_code& ec)
+{
+#ifdef GHC_OS_WINDOWS
+ return ec.value() == ERROR_FILE_NOT_FOUND || ec.value() == ERROR_PATH_NOT_FOUND || ec.value() == ERROR_INVALID_NAME;
+#else
+ return ec.value() == ENOENT || ec.value() == ENOTDIR;
+#endif
+}
+
+GHC_INLINE file_status symlink_status_ex(const path& p, std::error_code& ec, uintmax_t* sz = nullptr, uintmax_t* nhl = nullptr, time_t* lwt = nullptr) noexcept
+{
+#ifdef GHC_OS_WINDOWS
+ file_status fs;
+ WIN32_FILE_ATTRIBUTE_DATA attr;
+ if (!GetFileAttributesExW(GHC_NATIVEWP(p), GetFileExInfoStandard, &attr)) {
+ ec = detail::make_system_error();
+ }
+ else {
+ ec.clear();
+ fs = detail::status_from_INFO(p, &attr, ec, sz, lwt);
+ if (nhl) {
+ *nhl = 0;
+ }
+ }
+ if (detail::is_not_found_error(ec)) {
+ return file_status(file_type::not_found);
+ }
+ return ec ? file_status(file_type::none) : fs;
+#else
+ (void)sz;
+ (void)nhl;
+ (void)lwt;
+ struct ::stat fs;
+ auto result = ::lstat(p.c_str(), &fs);
+ if (result == 0) {
+ ec.clear();
+ file_status f_s = detail::file_status_from_st_mode(fs.st_mode);
+ return f_s;
+ }
+ ec = detail::make_system_error();
+ if (detail::is_not_found_error(ec)) {
+ return file_status(file_type::not_found, perms::unknown);
+ }
+ return file_status(file_type::none);
+#endif
+}
+
+GHC_INLINE file_status status_ex(const path& p, std::error_code& ec, file_status* sls = nullptr, uintmax_t* sz = nullptr, uintmax_t* nhl = nullptr, time_t* lwt = nullptr, int recurse_count = 0) noexcept
+{
+ ec.clear();
+#ifdef GHC_OS_WINDOWS
+ if (recurse_count > 16) {
+ ec = detail::make_system_error(0x2A9 /*ERROR_STOPPED_ON_SYMLINK*/);
+ return file_status(file_type::unknown);
+ }
+ WIN32_FILE_ATTRIBUTE_DATA attr;
+ if (!::GetFileAttributesExW(GHC_NATIVEWP(p), GetFileExInfoStandard, &attr)) {
+ ec = detail::make_system_error();
+ }
+ else if (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+ auto reparseData = detail::getReparseData(p, ec);
+ if (!ec && reparseData && IsReparseTagMicrosoft(reparseData->ReparseTag) && reparseData->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
+ path target = resolveSymlink(p, ec);
+ file_status result;
+ if (!ec && !target.empty()) {
+ if (sls) {
+ *sls = status_from_INFO(p, &attr, ec);
+ }
+ return detail::status_ex(target, ec, nullptr, sz, nhl, lwt, recurse_count + 1);
+ }
+ return file_status(file_type::unknown);
+ }
+ }
+ if (ec) {
+ if (detail::is_not_found_error(ec)) {
+ return file_status(file_type::not_found);
+ }
+ return file_status(file_type::none);
+ }
+ if (nhl) {
+ *nhl = 0;
+ }
+ return detail::status_from_INFO(p, &attr, ec, sz, lwt);
+#else
+ (void)recurse_count;
+ struct ::stat st;
+ auto result = ::lstat(p.c_str(), &st);
+ if (result == 0) {
+ ec.clear();
+ file_status fs = detail::file_status_from_st_mode(st.st_mode);
+ if (sls) {
+ *sls = fs;
+ }
+ if (fs.type() == file_type::symlink) {
+ result = ::stat(p.c_str(), &st);
+ if (result == 0) {
+ fs = detail::file_status_from_st_mode(st.st_mode);
+ }
+ else {
+ ec = detail::make_system_error();
+ if (detail::is_not_found_error(ec)) {
+ return file_status(file_type::not_found, perms::unknown);
+ }
+ return file_status(file_type::none);
+ }
+ }
+ if (sz) {
+ *sz = static_cast<uintmax_t>(st.st_size);
+ }
+ if (nhl) {
+ *nhl = st.st_nlink;
+ }
+ if (lwt) {
+ *lwt = st.st_mtime;
+ }
+ return fs;
+ }
+ else {
+ ec = detail::make_system_error();
+ if (detail::is_not_found_error(ec)) {
+ return file_status(file_type::not_found, perms::unknown);
+ }
+ return file_status(file_type::none);
+ }
+#endif
+}
+
+} // namespace detail
+
+GHC_INLINE u8arguments::u8arguments(int& argc, char**& argv)
+ : _argc(argc)
+ , _argv(argv)
+ , _refargc(argc)
+ , _refargv(argv)
+ , _isvalid(false)
+{
+#ifdef GHC_OS_WINDOWS
+ LPWSTR* p;
+ p = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
+ _args.reserve(static_cast<size_t>(argc));
+ _argp.reserve(static_cast<size_t>(argc));
+ for (size_t i = 0; i < static_cast<size_t>(argc); ++i) {
+ _args.push_back(detail::toUtf8(std::wstring(p[i])));
+ _argp.push_back((char*)_args[i].data());
+ }
+ argv = _argp.data();
+ ::LocalFree(p);
+ _isvalid = true;
+#else
+ std::setlocale(LC_ALL, "");
+#if defined(__ANDROID__) && __ANDROID_API__ < 26
+ _isvalid = true;
+#else
+ if (detail::equals_simple_insensitive(::nl_langinfo(CODESET), "UTF-8")) {
+ _isvalid = true;
+ }
+#endif
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// [fs.path.construct] constructors and destructor
+
+GHC_INLINE path::path() noexcept {}
+
+GHC_INLINE path::path(const path& p)
+ : _path(p._path)
+#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH)
+ , _prefixLength(p._prefixLength)
+#endif
+{
+}
+
+GHC_INLINE path::path(path&& p) noexcept
+ : _path(std::move(p._path))
+#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH)
+ , _prefixLength(p._prefixLength)
+#endif
+{
+}
+
+GHC_INLINE path::path(string_type&& source, format fmt)
+ : _path(std::move(source))
+{
+ postprocess_path_with_format(fmt);
+}
+
+#endif // GHC_EXPAND_IMPL
+
+#ifdef GHC_WITH_EXCEPTIONS
+template <class Source, typename>
+inline path::path(const Source& source, const std::locale& loc, format fmt)
+ : path(source, fmt)
+{
+ std::string locName = loc.name();
+ if (!(locName.length() >= 5 && (locName.substr(locName.length() - 5) == "UTF-8" || locName.substr(locName.length() - 5) == "utf-8"))) {
+ throw filesystem_error("This implementation only supports UTF-8 locales!", path(_path), detail::make_error_code(detail::portable_error::not_supported));
+ }
+}
+
+template <class InputIterator>
+inline path::path(InputIterator first, InputIterator last, const std::locale& loc, format fmt)
+ : path(std::basic_string<typename std::iterator_traits<InputIterator>::value_type>(first, last), fmt)
+{
+ std::string locName = loc.name();
+ if (!(locName.length() >= 5 && (locName.substr(locName.length() - 5) == "UTF-8" || locName.substr(locName.length() - 5) == "utf-8"))) {
+ throw filesystem_error("This implementation only supports UTF-8 locales!", path(_path), detail::make_error_code(detail::portable_error::not_supported));
+ }
+}
+#endif
+
+#ifdef GHC_EXPAND_IMPL
+
+GHC_INLINE path::~path() {}
+
+//-----------------------------------------------------------------------------
+// [fs.path.assign] assignments
+
+GHC_INLINE path& path::operator=(const path& p)
+{
+ _path = p._path;
+#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH)
+ _prefixLength = p._prefixLength;
+#endif
+ return *this;
+}
+
+GHC_INLINE path& path::operator=(path&& p) noexcept
+{
+ _path = std::move(p._path);
+#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH)
+ _prefixLength = p._prefixLength;
+#endif
+ return *this;
+}
+
+GHC_INLINE path& path::operator=(path::string_type&& source)
+{
+ return assign(source);
+}
+
+GHC_INLINE path& path::assign(path::string_type&& source)
+{
+ _path = std::move(source);
+ postprocess_path_with_format(native_format);
+ return *this;
+}
+
+#endif // GHC_EXPAND_IMPL
+
+template <class Source>
+inline path& path::operator=(const Source& source)
+{
+ return assign(source);
+}
+
+template <class Source>
+inline path& path::assign(const Source& source)
+{
+#ifdef GHC_USE_WCHAR_T
+ _path.assign(detail::toWChar(source));
+#else
+ _path.assign(detail::toUtf8(source));
+#endif
+ postprocess_path_with_format(native_format);
+ return *this;
+}
+
+template <>
+inline path& path::assign<path>(const path& source)
+{
+ _path = source._path;
+#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH)
+ _prefixLength = source._prefixLength;
+#endif
+ return *this;
+}
+
+template <class InputIterator>
+inline path& path::assign(InputIterator first, InputIterator last)
+{
+ _path.assign(first, last);
+ postprocess_path_with_format(native_format);
+ return *this;
+}
+
+#ifdef GHC_EXPAND_IMPL
+
+//-----------------------------------------------------------------------------
+// [fs.path.append] appends
+
+GHC_INLINE path& path::operator/=(const path& p)
+{
+ if (p.empty()) {
+ // was: if ((!has_root_directory() && is_absolute()) || has_filename())
+ if (!_path.empty() && _path[_path.length() - 1] != preferred_separator && _path[_path.length() - 1] != ':') {
+ _path += preferred_separator;
+ }
+ return *this;
+ }
+ if ((p.is_absolute() && (_path != root_name()._path || p._path != "/")) || (p.has_root_name() && p.root_name() != root_name())) {
+ assign(p);
+ return *this;
+ }
+ if (p.has_root_directory()) {
+ assign(root_name());
+ }
+ else if ((!has_root_directory() && is_absolute()) || has_filename()) {
+ _path += preferred_separator;
+ }
+ auto iter = p.begin();
+ bool first = true;
+ if (p.has_root_name()) {
+ ++iter;
+ }
+ while (iter != p.end()) {
+ if (!first && !(!_path.empty() && _path[_path.length() - 1] == preferred_separator)) {
+ _path += preferred_separator;
+ }
+ first = false;
+ _path += (*iter++).native();
+ }
+ check_long_path();
+ return *this;
+}
+
+GHC_INLINE void path::append_name(const value_type* name)
+{
+ if (_path.empty()) {
+ this->operator/=(path(name));
+ }
+ else {
+ if (_path.back() != path::preferred_separator) {
+ _path.push_back(path::preferred_separator);
+ }
+ _path += name;
+ check_long_path();
+ }
+}
+
+#endif // GHC_EXPAND_IMPL
+
+template <class Source>
+inline path& path::operator/=(const Source& source)
+{
+ return append(source);
+}
+
+template <class Source>
+inline path& path::append(const Source& source)
+{
+ return this->operator/=(path(source));
+}
+
+template <>
+inline path& path::append<path>(const path& p)
+{
+ return this->operator/=(p);
+}
+
+template <class InputIterator>
+inline path& path::append(InputIterator first, InputIterator last)
+{
+ std::basic_string<typename std::iterator_traits<InputIterator>::value_type> part(first, last);
+ return append(part);
+}
+
+#ifdef GHC_EXPAND_IMPL
+
+//-----------------------------------------------------------------------------
+// [fs.path.concat] concatenation
+
+GHC_INLINE path& path::operator+=(const path& x)
+{
+ return concat(x._path);
+}
+
+GHC_INLINE path& path::operator+=(const string_type& x)
+{
+ return concat(x);
+}
+
+#ifdef GHC_WITH_STRING_VIEW
+GHC_INLINE path& path::operator+=(basic_string_view<value_type> x)
+{
+ return concat(x);
+}
+#endif
+
+GHC_INLINE path& path::operator+=(const value_type* x)
+{
+#ifdef GHC_WITH_STRING_VIEW
+ basic_string_view<value_type> part(x);
+#else
+ string_type part(x);
+#endif
+ return concat(part);
+}
+
+GHC_INLINE path& path::operator+=(value_type x)
+{
+#ifdef GHC_OS_WINDOWS
+ if (x == generic_separator) {
+ x = preferred_separator;
+ }
+#endif
+ if (_path.empty() || _path.back() != preferred_separator) {
+ _path += x;
+ }
+ check_long_path();
+ return *this;
+}
+
+#endif // GHC_EXPAND_IMPL
+
+template <class Source>
+inline path::path_from_string<Source>& path::operator+=(const Source& x)
+{
+ return concat(x);
+}
+
+template <class EcharT>
+inline path::path_type_EcharT<EcharT>& path::operator+=(EcharT x)
+{
+#ifdef GHC_WITH_STRING_VIEW
+ basic_string_view<EcharT> part(&x, 1);
+#else
+ std::basic_string<EcharT> part(1, x);
+#endif
+ concat(part);
+ return *this;
+}
+
+template <class Source>
+inline path& path::concat(const Source& x)
+{
+ path p(x);
+ _path += p._path;
+ postprocess_path_with_format(native_format);
+ return *this;
+}
+template <class InputIterator>
+inline path& path::concat(InputIterator first, InputIterator last)
+{
+ _path.append(first, last);
+ postprocess_path_with_format(native_format);
+ return *this;
+}
+
+#ifdef GHC_EXPAND_IMPL
+
+//-----------------------------------------------------------------------------
+// [fs.path.modifiers] modifiers
+GHC_INLINE void path::clear() noexcept
+{
+ _path.clear();
+#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH)
+ _prefixLength = 0;
+#endif
+}
+
+GHC_INLINE path& path::make_preferred()
+{
+ // as this filesystem implementation only uses generic_format
+ // internally, this must be a no-op
+ return *this;
+}
+
+GHC_INLINE path& path::remove_filename()
+{
+ if (has_filename()) {
+ _path.erase(_path.size() - filename()._path.size());
+ }
+ return *this;
+}
+
+GHC_INLINE path& path::replace_filename(const path& replacement)
+{
+ remove_filename();
+ return append(replacement);
+}
+
+GHC_INLINE path& path::replace_extension(const path& replacement)
+{
+ if (has_extension()) {
+ _path.erase(_path.size() - extension()._path.size());
+ }
+ if (!replacement.empty() && replacement._path[0] != '.') {
+ _path += '.';
+ }
+ return concat(replacement);
+}
+
+GHC_INLINE void path::swap(path& rhs) noexcept
+{
+ _path.swap(rhs._path);
+#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH)
+ std::swap(_prefixLength, rhs._prefixLength);
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// [fs.path.native.obs] native format observers
+GHC_INLINE const path::string_type& path::native() const noexcept
+{
+ return _path;
+}
+
+GHC_INLINE const path::value_type* path::c_str() const noexcept
+{
+ return native().c_str();
+}
+
+GHC_INLINE path::operator path::string_type() const
+{
+ return native();
+}
+
+#endif // GHC_EXPAND_IMPL
+
+template <class EcharT, class traits, class Allocator>
+inline std::basic_string<EcharT, traits, Allocator> path::string(const Allocator& a) const
+{
+#ifdef GHC_USE_WCHAR_T
+ return detail::fromWChar<std::basic_string<EcharT, traits, Allocator>>(_path, a);
+#else
+ return detail::fromUtf8<std::basic_string<EcharT, traits, Allocator>>(_path, a);
+#endif
+}
+
+#ifdef GHC_EXPAND_IMPL
+
+GHC_INLINE std::string path::string() const
+{
+#ifdef GHC_USE_WCHAR_T
+ return detail::toUtf8(native());
+#else
+ return native();
+#endif
+}
+
+GHC_INLINE std::wstring path::wstring() const
+{
+#ifdef GHC_USE_WCHAR_T
+ return native();
+#else
+ return detail::fromUtf8<std::wstring>(native());
+#endif
+}
+
+#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)
+GHC_INLINE std::u8string path::u8string() const
+{
+#ifdef GHC_USE_WCHAR_T
+ return std::u8string(reinterpret_cast<const char8_t*>(detail::toUtf8(native()).c_str()));
+#else
+ return std::u8string(reinterpret_cast<const char8_t*>(c_str()));
+#endif
+}
+#else
+GHC_INLINE std::string path::u8string() const
+{
+#ifdef GHC_USE_WCHAR_T
+ return detail::toUtf8(native());
+#else
+ return native();
+#endif
+}
+#endif
+
+GHC_INLINE std::u16string path::u16string() const
+{
+ // TODO: optimize
+ return detail::fromUtf8<std::u16string>(string());
+}
+
+GHC_INLINE std::u32string path::u32string() const
+{
+ // TODO: optimize
+ return detail::fromUtf8<std::u32string>(string());
+}
+
+#endif // GHC_EXPAND_IMPL
+
+//-----------------------------------------------------------------------------
+// [fs.path.generic.obs] generic format observers
+template <class EcharT, class traits, class Allocator>
+inline std::basic_string<EcharT, traits, Allocator> path::generic_string(const Allocator& a) const
+{
+#ifdef GHC_OS_WINDOWS
+#ifdef GHC_USE_WCHAR_T
+ auto result = detail::fromWChar<std::basic_string<EcharT, traits, Allocator>, path::string_type>(_path, a);
+#else
+ auto result = detail::fromUtf8<std::basic_string<EcharT, traits, Allocator>>(_path, a);
+#endif
+ for (auto& c : result) {
+ if (c == preferred_separator) {
+ c = generic_separator;
+ }
+ }
+ return result;
+#else
+ return detail::fromUtf8<std::basic_string<EcharT, traits, Allocator>>(_path, a);
+#endif
+}
+
+#ifdef GHC_EXPAND_IMPL
+
+GHC_INLINE std::string path::generic_string() const
+{
+#ifdef GHC_OS_WINDOWS
+ return generic_string<std::string::value_type, std::string::traits_type, std::string::allocator_type>();
+#else
+ return _path;
+#endif
+}
+
+GHC_INLINE std::wstring path::generic_wstring() const
+{
+#ifdef GHC_OS_WINDOWS
+ return generic_string<std::wstring::value_type, std::wstring::traits_type, std::wstring::allocator_type>();
+#else
+ return detail::fromUtf8<std::wstring>(_path);
+#endif
+} // namespace filesystem
+
+#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)
+GHC_INLINE std::u8string path::generic_u8string() const
+{
+#ifdef GHC_OS_WINDOWS
+ return generic_string<std::u8string::value_type, std::u8string::traits_type, std::u8string::allocator_type>();
+#else
+ return std::u8string(reinterpret_cast<const char8_t*>(_path.c_str()));
+#endif
+}
+#else
+GHC_INLINE std::string path::generic_u8string() const
+{
+#ifdef GHC_OS_WINDOWS
+ return generic_string<std::string::value_type, std::string::traits_type, std::string::allocator_type>();
+#else
+ return _path;
+#endif
+}
+#endif
+
+GHC_INLINE std::u16string path::generic_u16string() const
+{
+#ifdef GHC_OS_WINDOWS
+ return generic_string<std::u16string::value_type, std::u16string::traits_type, std::u16string::allocator_type>();
+#else
+ return detail::fromUtf8<std::u16string>(_path);
+#endif
+}
+
+GHC_INLINE std::u32string path::generic_u32string() const
+{
+#ifdef GHC_OS_WINDOWS
+ return generic_string<std::u32string::value_type, std::u32string::traits_type, std::u32string::allocator_type>();
+#else
+ return detail::fromUtf8<std::u32string>(_path);
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// [fs.path.compare] compare
+GHC_INLINE int path::compare(const path& p) const noexcept
+{
+#ifdef LWG_2936_BEHAVIOUR
+ auto rnl1 = root_name_length();
+ auto rnl2 = p.root_name_length();
+#ifdef GHC_OS_WINDOWS
+ auto rnc = detail::compare_simple_insensitive(_path.c_str(), rnl1, p._path.c_str(), rnl2);
+#else
+ auto rnc = _path.compare(0, rnl1, p._path, 0, (std::min(rnl1, rnl2)));
+#endif
+ if (rnc) {
+ return rnc;
+ }
+ bool hrd1 = has_root_directory(), hrd2 = p.has_root_directory();
+ if (hrd1 != hrd2) {
+ return hrd1 ? 1 : -1;
+ }
+ if (hrd1) {
+ ++rnl1;
+ ++rnl2;
+ }
+ auto iter1 = _path.begin() + static_cast<int>(rnl1);
+ auto iter2 = p._path.begin() + static_cast<int>(rnl2);
+ while (iter1 != _path.end() && iter2 != p._path.end() && *iter1 == *iter2) {
+ ++iter1;
+ ++iter2;
+ }
+ if (iter1 == _path.end()) {
+ return iter2 == p._path.end() ? 0 : -1;
+ }
+ if (iter2 == p._path.end()) {
+ return 1;
+ }
+ if (*iter1 == preferred_separator) {
+ return -1;
+ }
+ if (*iter2 == preferred_separator) {
+ return 1;
+ }
+ return *iter1 < *iter2 ? -1 : 1;
+#else // LWG_2936_BEHAVIOUR
+#ifdef GHC_OS_WINDOWS
+ auto rnl1 = root_name_length();
+ auto rnl2 = p.root_name_length();
+ auto rnc = detail::compare_simple_insensitive(_path.c_str(), rnl1, p._path.c_str(), rnl2);
+ if (rnc) {
+ return rnc;
+ }
+ return _path.compare(rnl1, std::string::npos, p._path, rnl2, std::string::npos);
+#else
+ return _path.compare(p._path);
+#endif
+#endif
+}
+
+GHC_INLINE int path::compare(const string_type& s) const
+{
+ return compare(path(s));
+}
+
+#ifdef GHC_WITH_STRING_VIEW
+GHC_INLINE int path::compare(basic_string_view<value_type> s) const
+{
+ return compare(path(s));
+}
+#endif
+
+GHC_INLINE int path::compare(const value_type* s) const
+{
+ return compare(path(s));
+}
+
+//-----------------------------------------------------------------------------
+// [fs.path.decompose] decomposition
+#ifdef GHC_OS_WINDOWS
+GHC_INLINE void path::handle_prefixes()
+{
+#if defined(GHC_WIN_AUTO_PREFIX_LONG_PATH)
+ _prefixLength = 0;
+ if (_path.length() >= 6 && _path[2] == '?' && std::toupper(static_cast<unsigned char>(_path[4])) >= 'A' && std::toupper(static_cast<unsigned char>(_path[4])) <= 'Z' && _path[5] == ':') {
+ if (detail::startsWith(_path, impl_string_type(GHC_PLATFORM_LITERAL("\\\\?\\"))) || detail::startsWith(_path, impl_string_type(GHC_PLATFORM_LITERAL("\\??\\")))) {
+ _prefixLength = 4;
+ }
+ }
+#endif // GHC_WIN_AUTO_PREFIX_LONG_PATH
+}
+#endif
+
+GHC_INLINE path::string_type::size_type path::root_name_length() const noexcept
+{
+#ifdef GHC_OS_WINDOWS
+ if (_path.length() >= _prefixLength + 2 && std::toupper(static_cast<unsigned char>(_path[_prefixLength])) >= 'A' && std::toupper(static_cast<unsigned char>(_path[_prefixLength])) <= 'Z' && _path[_prefixLength + 1] == ':') {
+ return 2;
+ }
+#endif
+ if (_path.length() > _prefixLength + 2 && _path[_prefixLength] == preferred_separator && _path[_prefixLength + 1] == preferred_separator && _path[_prefixLength + 2] != preferred_separator && std::isprint(_path[_prefixLength + 2])) {
+ impl_string_type::size_type pos = _path.find(preferred_separator, _prefixLength + 3);
+ if (pos == impl_string_type::npos) {
+ return _path.length();
+ }
+ else {
+ return pos;
+ }
+ }
+ return 0;
+}
+
+GHC_INLINE path path::root_name() const
+{
+ return path(_path.substr(_prefixLength, root_name_length()), native_format);
+}
+
+GHC_INLINE path path::root_directory() const
+{
+ if (has_root_directory()) {
+ static const path _root_dir(std::string(1, preferred_separator), native_format);
+ return _root_dir;
+ }
+ return path();
+}
+
+GHC_INLINE path path::root_path() const
+{
+ return path(root_name().string() + root_directory().string(), native_format);
+}
+
+GHC_INLINE path path::relative_path() const
+{
+ auto rootPathLen = _prefixLength + root_name_length() + (has_root_directory() ? 1 : 0);
+ return path(_path.substr((std::min)(rootPathLen, _path.length())), generic_format);
+}
+
+GHC_INLINE path path::parent_path() const
+{
+ auto rootPathLen = _prefixLength + root_name_length() + (has_root_directory() ? 1 : 0);
+ if (rootPathLen < _path.length()) {
+ if (empty()) {
+ return path();
+ }
+ else {
+ auto piter = end();
+ auto iter = piter.decrement(_path.end());
+ if (iter > _path.begin() + static_cast<long>(rootPathLen) && *iter != preferred_separator) {
+ --iter;
+ }
+ return path(_path.begin(), iter, native_format);
+ }
+ }
+ else {
+ return *this;
+ }
+}
+
+GHC_INLINE path path::filename() const
+{
+ return !has_relative_path() ? path() : path(*--end());
+}
+
+GHC_INLINE path path::stem() const
+{
+ impl_string_type fn = filename().native();
+ if (fn != "." && fn != "..") {
+ impl_string_type::size_type pos = fn.rfind('.');
+ if (pos != impl_string_type::npos && pos > 0) {
+ return path{fn.substr(0, pos), native_format};
+ }
+ }
+ return path{fn, native_format};
+}
+
+GHC_INLINE path path::extension() const
+{
+ if (has_relative_path()) {
+ auto iter = end();
+ const auto& fn = *--iter;
+ impl_string_type::size_type pos = fn._path.rfind('.');
+ if (pos != std::string::npos && pos > 0) {
+ return path(fn._path.substr(pos), native_format);
+ }
+ }
+ return path();
+}
+
+#ifdef GHC_OS_WINDOWS
+namespace detail {
+GHC_INLINE bool has_executable_extension(const path& p)
+{
+ if (p.has_relative_path()) {
+ auto iter = p.end();
+ const auto& fn = *--iter;
+ auto pos = fn._path.find_last_of('.');
+ if (pos == std::string::npos || pos == 0 || fn._path.length() - pos != 3) {
+ return false;
+ }
+ const path::value_type* ext = fn._path.c_str() + pos + 1;
+ if (detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("exe")) || detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("cmd")) || detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("bat")) ||
+ detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("com"))) {
+ return true;
+ }
+ }
+ return false;
+}
+} // namespace detail
+#endif
+
+//-----------------------------------------------------------------------------
+// [fs.path.query] query
+GHC_INLINE bool path::empty() const noexcept
+{
+ return _path.empty();
+}
+
+GHC_INLINE bool path::has_root_name() const
+{
+ return root_name_length() > 0;
+}
+
+GHC_INLINE bool path::has_root_directory() const
+{
+ auto rootLen = _prefixLength + root_name_length();
+ return (_path.length() > rootLen && _path[rootLen] == preferred_separator);
+}
+
+GHC_INLINE bool path::has_root_path() const
+{
+ return has_root_name() || has_root_directory();
+}
+
+GHC_INLINE bool path::has_relative_path() const
+{
+ auto rootPathLen = _prefixLength + root_name_length() + (has_root_directory() ? 1 : 0);
+ return rootPathLen < _path.length();
+}
+
+GHC_INLINE bool path::has_parent_path() const
+{
+ return !parent_path().empty();
+}
+
+GHC_INLINE bool path::has_filename() const
+{
+ return has_relative_path() && !filename().empty();
+}
+
+GHC_INLINE bool path::has_stem() const
+{
+ return !stem().empty();
+}
+
+GHC_INLINE bool path::has_extension() const
+{
+ return !extension().empty();
+}
+
+GHC_INLINE bool path::is_absolute() const
+{
+#ifdef GHC_OS_WINDOWS
+ return has_root_name() && has_root_directory();
+#else
+ return has_root_directory();
+#endif
+}
+
+GHC_INLINE bool path::is_relative() const
+{
+ return !is_absolute();
+}
+
+//-----------------------------------------------------------------------------
+// [fs.path.gen] generation
+GHC_INLINE path path::lexically_normal() const
+{
+ path dest;
+ bool lastDotDot = false;
+ for (string_type s : *this) {
+ if (s == ".") {
+ dest /= "";
+ continue;
+ }
+ else if (s == ".." && !dest.empty()) {
+ auto root = root_path();
+ if (dest == root) {
+ continue;
+ }
+ else if (*(--dest.end()) != "..") {
+ if (dest._path.back() == preferred_separator) {
+ dest._path.pop_back();
+ }
+ dest.remove_filename();
+ continue;
+ }
+ }
+ if (!(s.empty() && lastDotDot)) {
+ dest /= s;
+ }
+ lastDotDot = s == "..";
+ }
+ if (dest.empty()) {
+ dest = ".";
+ }
+ return dest;
+}
+
+GHC_INLINE path path::lexically_relative(const path& base) const
+{
+ if (root_name() != base.root_name() || is_absolute() != base.is_absolute() || (!has_root_directory() && base.has_root_directory())) {
+ return path();
+ }
+ const_iterator a = begin(), b = base.begin();
+ while (a != end() && b != base.end() && *a == *b) {
+ ++a;
+ ++b;
+ }
+ if (a == end() && b == base.end()) {
+ return path(".");
+ }
+ int count = 0;
+ for (const auto& element : input_iterator_range<const_iterator>(b, base.end())) {
+ if (element != "." && element != "" && element != "..") {
+ ++count;
+ }
+ else if (element == "..") {
+ --count;
+ }
+ }
+ if (count < 0) {
+ return path();
+ }
+ path result;
+ for (int i = 0; i < count; ++i) {
+ result /= "..";
+ }
+ for (const auto& element : input_iterator_range<const_iterator>(a, end())) {
+ result /= element;
+ }
+ return result;
+}
+
+GHC_INLINE path path::lexically_proximate(const path& base) const
+{
+ path result = lexically_relative(base);
+ return result.empty() ? *this : result;
+}
+
+//-----------------------------------------------------------------------------
+// [fs.path.itr] iterators
+GHC_INLINE path::iterator::iterator() {}
+
+GHC_INLINE path::iterator::iterator(const path& p, const impl_string_type::const_iterator& pos)
+ : _first(p._path.begin())
+ , _last(p._path.end())
+ , _prefix(_first + static_cast<string_type::difference_type>(p._prefixLength))
+ , _root(p.has_root_directory() ? _first + static_cast<string_type::difference_type>(p._prefixLength + p.root_name_length()) : _last)
+ , _iter(pos)
+{
+ if (pos != _last) {
+ updateCurrent();
+ }
+}
+
+GHC_INLINE path::impl_string_type::const_iterator path::iterator::increment(const path::impl_string_type::const_iterator& pos) const
+{
+ path::impl_string_type::const_iterator i = pos;
+ bool fromStart = i == _first || i == _prefix;
+ if (i != _last) {
+ if (fromStart && i == _first && _prefix > _first) {
+ i = _prefix;
+ }
+ else if (*i++ == preferred_separator) {
+ // we can only sit on a slash if it is a network name or a root
+ if (i != _last && *i == preferred_separator) {
+ if (fromStart && !(i + 1 != _last && *(i + 1) == preferred_separator)) {
+ // leadind double slashes detected, treat this and the
+ // following until a slash as one unit
+ i = std::find(++i, _last, preferred_separator);
+ }
+ else {
+ // skip redundant slashes
+ while (i != _last && *i == preferred_separator) {
+ ++i;
+ }
+ }
+ }
+ }
+ else {
+ if (fromStart && i != _last && *i == ':') {
+ ++i;
+ }
+ else {
+ i = std::find(i, _last, preferred_separator);
+ }
+ }
+ }
+ return i;
+}
+
+GHC_INLINE path::impl_string_type::const_iterator path::iterator::decrement(const path::impl_string_type::const_iterator& pos) const
+{
+ path::impl_string_type::const_iterator i = pos;
+ if (i != _first) {
+ --i;
+ // if this is now the root slash or the trailing slash, we are done,
+ // else check for network name
+ if (i != _root && (pos != _last || *i != preferred_separator)) {
+#ifdef GHC_OS_WINDOWS
+ static const impl_string_type seps = GHC_PLATFORM_LITERAL("\\:");
+ i = std::find_first_of(std::reverse_iterator<path::impl_string_type::const_iterator>(i), std::reverse_iterator<path::impl_string_type::const_iterator>(_first), seps.begin(), seps.end()).base();
+ if (i > _first && *i == ':') {
+ i++;
+ }
+#else
+ i = std::find(std::reverse_iterator<path::impl_string_type::const_iterator>(i), std::reverse_iterator<path::impl_string_type::const_iterator>(_first), preferred_separator).base();
+#endif
+ // Now we have to check if this is a network name
+ if (i - _first == 2 && *_first == preferred_separator && *(_first + 1) == preferred_separator) {
+ i -= 2;
+ }
+ }
+ }
+ return i;
+}
+
+GHC_INLINE void path::iterator::updateCurrent()
+{
+ if ((_iter == _last) || (_iter != _first && _iter != _last && (*_iter == preferred_separator && _iter != _root) && (_iter + 1 == _last))) {
+ _current.clear();
+ }
+ else {
+ _current.assign(_iter, increment(_iter));
+ }
+}
+
+GHC_INLINE path::iterator& path::iterator::operator++()
+{
+ _iter = increment(_iter);
+ while (_iter != _last && // we didn't reach the end
+ _iter != _root && // this is not a root position
+ *_iter == preferred_separator && // we are on a separator
+ (_iter + 1) != _last // the slash is not the last char
+ ) {
+ ++_iter;
+ }
+ updateCurrent();
+ return *this;
+}
+
+GHC_INLINE path::iterator path::iterator::operator++(int)
+{
+ path::iterator i{*this};
+ ++(*this);
+ return i;
+}
+
+GHC_INLINE path::iterator& path::iterator::operator--()
+{
+ _iter = decrement(_iter);
+ updateCurrent();
+ return *this;
+}
+
+GHC_INLINE path::iterator path::iterator::operator--(int)
+{
+ auto i = *this;
+ --(*this);
+ return i;
+}
+
+GHC_INLINE bool path::iterator::operator==(const path::iterator& other) const
+{
+ return _iter == other._iter;
+}
+
+GHC_INLINE bool path::iterator::operator!=(const path::iterator& other) const
+{
+ return _iter != other._iter;
+}
+
+GHC_INLINE path::iterator::reference path::iterator::operator*() const
+{
+ return _current;
+}
+
+GHC_INLINE path::iterator::pointer path::iterator::operator->() const
+{
+ return &_current;
+}
+
+GHC_INLINE path::iterator path::begin() const
+{
+ return iterator(*this, _path.begin());
+}
+
+GHC_INLINE path::iterator path::end() const
+{
+ return iterator(*this, _path.end());
+}
+
+//-----------------------------------------------------------------------------
+// [fs.path.nonmember] path non-member functions
+GHC_INLINE void swap(path& lhs, path& rhs) noexcept
+{
+ swap(lhs._path, rhs._path);
+}
+
+GHC_INLINE size_t hash_value(const path& p) noexcept
+{
+ return std::hash<std::string>()(p.generic_string());
+}
+
+#ifdef GHC_HAS_THREEWAY_COMP
+GHC_INLINE std::strong_ordering operator<=>(const path& lhs, const path& rhs) noexcept
+{
+ return lhs.compare(rhs) <=> 0;
+}
+#endif
+
+GHC_INLINE bool operator==(const path& lhs, const path& rhs) noexcept
+{
+ return lhs.compare(rhs) == 0;
+}
+
+GHC_INLINE bool operator!=(const path& lhs, const path& rhs) noexcept
+{
+ return !(lhs == rhs);
+}
+
+GHC_INLINE bool operator<(const path& lhs, const path& rhs) noexcept
+{
+ return lhs.compare(rhs) < 0;
+}
+
+GHC_INLINE bool operator<=(const path& lhs, const path& rhs) noexcept
+{
+ return lhs.compare(rhs) <= 0;
+}
+
+GHC_INLINE bool operator>(const path& lhs, const path& rhs) noexcept
+{
+ return lhs.compare(rhs) > 0;
+}
+
+GHC_INLINE bool operator>=(const path& lhs, const path& rhs) noexcept
+{
+ return lhs.compare(rhs) >= 0;
+}
+
+GHC_INLINE path operator/(const path& lhs, const path& rhs)
+{
+ path result(lhs);
+ result /= rhs;
+ return result;
+}
+
+#endif // GHC_EXPAND_IMPL
+
+//-----------------------------------------------------------------------------
+// [fs.path.io] path inserter and extractor
+template <class charT, class traits>
+inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& os, const path& p)
+{
+ os << "\"";
+ auto ps = p.string<charT, traits>();
+ for (auto c : ps) {
+ if (c == '"' || c == '\\') {
+ os << '\\';
+ }
+ os << c;
+ }
+ os << "\"";
+ return os;
+}
+
+template <class charT, class traits>
+inline std::basic_istream<charT, traits>& operator>>(std::basic_istream<charT, traits>& is, path& p)
+{
+ std::basic_string<charT, traits> tmp;
+ charT c;
+ is >> c;
+ if (c == '"') {
+ auto sf = is.flags();
+ is >> std::noskipws;
+ while (is) {
+ auto c2 = is.get();
+ if (is) {
+ if (c2 == '\\') {
+ c2 = is.get();
+ if (is) {
+ tmp += static_cast<charT>(c2);
+ }
+ }
+ else if (c2 == '"') {
+ break;
+ }
+ else {
+ tmp += static_cast<charT>(c2);
+ }
+ }
+ }
+ if ((sf & std::ios_base::skipws) == std::ios_base::skipws) {
+ is >> std::skipws;
+ }
+ p = path(tmp);
+ }
+ else {
+ is >> tmp;
+ p = path(static_cast<charT>(c) + tmp);
+ }
+ return is;
+}
+
+#ifdef GHC_EXPAND_IMPL
+
+//-----------------------------------------------------------------------------
+// [fs.class.filesystem_error] Class filesystem_error
+GHC_INLINE filesystem_error::filesystem_error(const std::string& what_arg, std::error_code ec)
+ : std::system_error(ec, what_arg)
+ , _what_arg(what_arg)
+ , _ec(ec)
+{
+}
+
+GHC_INLINE filesystem_error::filesystem_error(const std::string& what_arg, const path& p1, std::error_code ec)
+ : std::system_error(ec, what_arg)
+ , _what_arg(what_arg)
+ , _ec(ec)
+ , _p1(p1)
+{
+ if (!_p1.empty()) {
+ _what_arg += ": '" + _p1.string() + "'";
+ }
+}
+
+GHC_INLINE filesystem_error::filesystem_error(const std::string& what_arg, const path& p1, const path& p2, std::error_code ec)
+ : std::system_error(ec, what_arg)
+ , _what_arg(what_arg)
+ , _ec(ec)
+ , _p1(p1)
+ , _p2(p2)
+{
+ if (!_p1.empty()) {
+ _what_arg += ": '" + _p1.string() + "'";
+ }
+ if (!_p2.empty()) {
+ _what_arg += ", '" + _p2.string() + "'";
+ }
+}
+
+GHC_INLINE const path& filesystem_error::path1() const noexcept
+{
+ return _p1;
+}
+
+GHC_INLINE const path& filesystem_error::path2() const noexcept
+{
+ return _p2;
+}
+
+GHC_INLINE const char* filesystem_error::what() const noexcept
+{
+ return _what_arg.c_str();
+}
+
+//-----------------------------------------------------------------------------
+// [fs.op.funcs] filesystem operations
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE path absolute(const path& p)
+{
+ std::error_code ec;
+ path result = absolute(p, ec);
+ if (ec) {
+ throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
+ }
+ return result;
+}
+#endif
+
+GHC_INLINE path absolute(const path& p, std::error_code& ec)
+{
+ ec.clear();
+#ifdef GHC_OS_WINDOWS
+ if (p.empty()) {
+ return absolute(current_path(ec), ec) / "";
+ }
+ ULONG size = ::GetFullPathNameW(GHC_NATIVEWP(p), 0, 0, 0);
+ if (size) {
+ std::vector<wchar_t> buf(size, 0);
+ ULONG s2 = GetFullPathNameW(GHC_NATIVEWP(p), size, buf.data(), nullptr);
+ if (s2 && s2 < size) {
+ path result = path(std::wstring(buf.data(), s2));
+ if (p.filename() == ".") {
+ result /= ".";
+ }
+ return result;
+ }
+ }
+ ec = detail::make_system_error();
+ return path();
+#else
+ path base = current_path(ec);
+ if (!ec) {
+ if (p.empty()) {
+ return base / p;
+ }
+ if (p.has_root_name()) {
+ if (p.has_root_directory()) {
+ return p;
+ }
+ else {
+ return p.root_name() / base.root_directory() / base.relative_path() / p.relative_path();
+ }
+ }
+ else {
+ if (p.has_root_directory()) {
+ return base.root_name() / p;
+ }
+ else {
+ return base / p;
+ }
+ }
+ }
+ ec = detail::make_system_error();
+ return path();
+#endif
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE path canonical(const path& p)
+{
+ std::error_code ec;
+ auto result = canonical(p, ec);
+ if (ec) {
+ throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
+ }
+ return result;
+}
+#endif
+
+GHC_INLINE path canonical(const path& p, std::error_code& ec)
+{
+ if (p.empty()) {
+ ec = detail::make_error_code(detail::portable_error::not_found);
+ return path();
+ }
+ path work = p.is_absolute() ? p : absolute(p, ec);
+ path result;
+
+ auto fs = status(work, ec);
+ if (ec) {
+ return path();
+ }
+ if (fs.type() == file_type::not_found) {
+ ec = detail::make_error_code(detail::portable_error::not_found);
+ return path();
+ }
+ bool redo;
+ do {
+ auto rootPathLen = work._prefixLength + work.root_name_length() + (work.has_root_directory() ? 1 : 0);
+ redo = false;
+ result.clear();
+ for (auto pe : work) {
+ if (pe.empty() || pe == ".") {
+ continue;
+ }
+ else if (pe == "..") {
+ result = result.parent_path();
+ continue;
+ }
+ else if ((result / pe).string().length() <= rootPathLen) {
+ result /= pe;
+ continue;
+ }
+ auto sls = symlink_status(result / pe, ec);
+ if (ec) {
+ return path();
+ }
+ if (is_symlink(sls)) {
+ redo = true;
+ auto target = read_symlink(result / pe, ec);
+ if (ec) {
+ return path();
+ }
+ if (target.is_absolute()) {
+ result = target;
+ continue;
+ }
+ else {
+ result /= target;
+ continue;
+ }
+ }
+ else {
+ result /= pe;
+ }
+ }
+ work = result;
+ } while (redo);
+ ec.clear();
+ return result;
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE void copy(const path& from, const path& to)
+{
+ copy(from, to, copy_options::none);
+}
+
+GHC_INLINE void copy(const path& from, const path& to, copy_options options)
+{
+ std::error_code ec;
+ copy(from, to, options, ec);
+ if (ec) {
+ throw filesystem_error(detail::systemErrorText(ec.value()), from, to, ec);
+ }
+}
+#endif
+
+GHC_INLINE void copy(const path& from, const path& to, std::error_code& ec) noexcept
+{
+ copy(from, to, copy_options::none, ec);
+}
+
+GHC_INLINE void copy(const path& from, const path& to, copy_options options, std::error_code& ec) noexcept
+{
+ std::error_code tec;
+ file_status fs_from, fs_to;
+ ec.clear();
+ if ((options & (copy_options::skip_symlinks | copy_options::copy_symlinks | copy_options::create_symlinks)) != copy_options::none) {
+ fs_from = symlink_status(from, ec);
+ }
+ else {
+ fs_from = status(from, ec);
+ }
+ if (!exists(fs_from)) {
+ if (!ec) {
+ ec = detail::make_error_code(detail::portable_error::not_found);
+ }
+ return;
+ }
+ if ((options & (copy_options::skip_symlinks | copy_options::create_symlinks)) != copy_options::none) {
+ fs_to = symlink_status(to, tec);
+ }
+ else {
+ fs_to = status(to, tec);
+ }
+ if (is_other(fs_from) || is_other(fs_to) || (is_directory(fs_from) && is_regular_file(fs_to)) || (exists(fs_to) && equivalent(from, to, ec))) {
+ ec = detail::make_error_code(detail::portable_error::invalid_argument);
+ }
+ else if (is_symlink(fs_from)) {
+ if ((options & copy_options::skip_symlinks) == copy_options::none) {
+ if (!exists(fs_to) && (options & copy_options::copy_symlinks) != copy_options::none) {
+ copy_symlink(from, to, ec);
+ }
+ else {
+ ec = detail::make_error_code(detail::portable_error::invalid_argument);
+ }
+ }
+ }
+ else if (is_regular_file(fs_from)) {
+ if ((options & copy_options::directories_only) == copy_options::none) {
+ if ((options & copy_options::create_symlinks) != copy_options::none) {
+ create_symlink(from.is_absolute() ? from : canonical(from, ec), to, ec);
+ }
+#ifndef GHC_OS_WEB
+ else if ((options & copy_options::create_hard_links) != copy_options::none) {
+ create_hard_link(from, to, ec);
+ }
+#endif
+ else if (is_directory(fs_to)) {
+ copy_file(from, to / from.filename(), options, ec);
+ }
+ else {
+ copy_file(from, to, options, ec);
+ }
+ }
+ }
+#ifdef LWG_2682_BEHAVIOUR
+ else if (is_directory(fs_from) && (options & copy_options::create_symlinks) != copy_options::none) {
+ ec = detail::make_error_code(detail::portable_error::is_a_directory);
+ }
+#endif
+ else if (is_directory(fs_from) && (options == copy_options::none || (options & copy_options::recursive) != copy_options::none)) {
+ if (!exists(fs_to)) {
+ create_directory(to, from, ec);
+ if (ec) {
+ return;
+ }
+ }
+ for (auto iter = directory_iterator(from, ec); iter != directory_iterator(); iter.increment(ec)) {
+ if (!ec) {
+ copy(iter->path(), to / iter->path().filename(), options | static_cast<copy_options>(0x8000), ec);
+ }
+ if (ec) {
+ return;
+ }
+ }
+ }
+ return;
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE bool copy_file(const path& from, const path& to)
+{
+ return copy_file(from, to, copy_options::none);
+}
+
+GHC_INLINE bool copy_file(const path& from, const path& to, copy_options option)
+{
+ std::error_code ec;
+ auto result = copy_file(from, to, option, ec);
+ if (ec) {
+ throw filesystem_error(detail::systemErrorText(ec.value()), from, to, ec);
+ }
+ return result;
+}
+#endif
+
+GHC_INLINE bool copy_file(const path& from, const path& to, std::error_code& ec) noexcept
+{
+ return copy_file(from, to, copy_options::none, ec);
+}
+
+GHC_INLINE bool copy_file(const path& from, const path& to, copy_options options, std::error_code& ec) noexcept
+{
+ std::error_code tecf, tect;
+ auto sf = status(from, tecf);
+ auto st = status(to, tect);
+ bool overwrite = false;
+ ec.clear();
+ if (!is_regular_file(sf)) {
+ ec = tecf;
+ return false;
+ }
+ if (exists(st) && (!is_regular_file(st) || equivalent(from, to, ec) || (options & (copy_options::skip_existing | copy_options::overwrite_existing | copy_options::update_existing)) == copy_options::none)) {
+ ec = tect ? tect : detail::make_error_code(detail::portable_error::exists);
+ return false;
+ }
+ if (exists(st)) {
+ if ((options & copy_options::update_existing) == copy_options::update_existing) {
+ auto from_time = last_write_time(from, ec);
+ if (ec) {
+ ec = detail::make_system_error();
+ return false;
+ }
+ auto to_time = last_write_time(to, ec);
+ if (ec) {
+ ec = detail::make_system_error();
+ return false;
+ }
+ if (from_time <= to_time) {
+ return false;
+ }
+ }
+ overwrite = true;
+ }
+#ifdef GHC_OS_WINDOWS
+ if (!::CopyFileW(GHC_NATIVEWP(from), GHC_NATIVEWP(to), !overwrite)) {
+ ec = detail::make_system_error();
+ return false;
+ }
+ return true;
+#else
+ std::vector<char> buffer(16384, '\0');
+ int in = -1, out = -1;
+ if ((in = ::open(from.c_str(), O_RDONLY)) < 0) {
+ ec = detail::make_system_error();
+ return false;
+ }
+ int mode = O_CREAT | O_WRONLY | O_TRUNC;
+ if (!overwrite) {
+ mode |= O_EXCL;
+ }
+ if ((out = ::open(to.c_str(), mode, static_cast<int>(sf.permissions() & perms::all))) < 0) {
+ ec = detail::make_system_error();
+ ::close(in);
+ return false;
+ }
+ ssize_t br, bw;
+ while ((br = ::read(in, buffer.data(), buffer.size())) > 0) {
+ ssize_t offset = 0;
+ do {
+ if ((bw = ::write(out, buffer.data() + offset, static_cast<size_t>(br))) > 0) {
+ br -= bw;
+ offset += bw;
+ }
+ else if (bw < 0) {
+ ec = detail::make_system_error();
+ ::close(in);
+ ::close(out);
+ return false;
+ }
+ } while (br);
+ }
+ ::close(in);
+ ::close(out);
+ return true;
+#endif
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE void copy_symlink(const path& existing_symlink, const path& new_symlink)
+{
+ std::error_code ec;
+ copy_symlink(existing_symlink, new_symlink, ec);
+ if (ec) {
+ throw filesystem_error(detail::systemErrorText(ec.value()), existing_symlink, new_symlink, ec);
+ }
+}
+#endif
+
+GHC_INLINE void copy_symlink(const path& existing_symlink, const path& new_symlink, std::error_code& ec) noexcept
+{
+ ec.clear();
+ auto to = read_symlink(existing_symlink, ec);
+ if (!ec) {
+ if (exists(to, ec) && is_directory(to, ec)) {
+ create_directory_symlink(to, new_symlink, ec);
+ }
+ else {
+ create_symlink(to, new_symlink, ec);
+ }
+ }
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE bool create_directories(const path& p)
+{
+ std::error_code ec;
+ auto result = create_directories(p, ec);
+ if (ec) {
+ throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
+ }
+ return result;
+}
+#endif
+
+GHC_INLINE bool create_directories(const path& p, std::error_code& ec) noexcept
+{
+ path current;
+ ec.clear();
+ bool didCreate = false;
+ auto rootPathLen = p._prefixLength + p.root_name_length() + (p.has_root_directory() ? 1 : 0);
+ current = p.native().substr(0, rootPathLen);
+ path folders(p._path.substr(rootPathLen));
+ for (path::string_type part : folders) {
+ current /= part;
+ std::error_code tec;
+ auto fs = status(current, tec);
+ if (tec && fs.type() != file_type::not_found) {
+ ec = tec;
+ return false;
+ }
+ if (!exists(fs)) {
+ create_directory(current, ec);
+ if (ec) {
+ std::error_code tmp_ec;
+ if (is_directory(current, tmp_ec)) {
+ ec.clear();
+ }
+ else {
+ return false;
+ }
+ }
+ didCreate = true;
+ }
+#ifndef LWG_2935_BEHAVIOUR
+ else if (!is_directory(fs)) {
+ ec = detail::make_error_code(detail::portable_error::exists);
+ return false;
+ }
+#endif
+ }
+ return didCreate;
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE bool create_directory(const path& p)
+{
+ std::error_code ec;
+ auto result = create_directory(p, path(), ec);
+ if (ec) {
+ throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
+ }
+ return result;
+}
+#endif
+
+GHC_INLINE bool create_directory(const path& p, std::error_code& ec) noexcept
+{
+ return create_directory(p, path(), ec);
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE bool create_directory(const path& p, const path& attributes)
+{
+ std::error_code ec;
+ auto result = create_directory(p, attributes, ec);
+ if (ec) {
+ throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
+ }
+ return result;
+}
+#endif
+
+GHC_INLINE bool create_directory(const path& p, const path& attributes, std::error_code& ec) noexcept
+{
+ std::error_code tec;
+ ec.clear();
+ auto fs = status(p, tec);
+#ifdef LWG_2935_BEHAVIOUR
+ if (status_known(fs) && exists(fs)) {
+ return false;
+ }
+#else
+ if (status_known(fs) && exists(fs) && is_directory(fs)) {
+ return false;
+ }
+#endif
+#ifdef GHC_OS_WINDOWS
+ if (!attributes.empty()) {
+ if (!::CreateDirectoryExW(GHC_NATIVEWP(attributes), GHC_NATIVEWP(p), NULL)) {
+ ec = detail::make_system_error();
+ return false;
+ }
+ }
+ else if (!::CreateDirectoryW(GHC_NATIVEWP(p), NULL)) {
+ ec = detail::make_system_error();
+ return false;
+ }
+#else
+ ::mode_t attribs = static_cast<mode_t>(perms::all);
+ if (!attributes.empty()) {
+ struct ::stat fileStat;
+ if (::stat(attributes.c_str(), &fileStat) != 0) {
+ ec = detail::make_system_error();
+ return false;
+ }
+ attribs = fileStat.st_mode;
+ }
+ if (::mkdir(p.c_str(), attribs) != 0) {
+ ec = detail::make_system_error();
+ return false;
+ }
+#endif
+ return true;
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE void create_directory_symlink(const path& to, const path& new_symlink)
+{
+ std::error_code ec;
+ create_directory_symlink(to, new_symlink, ec);
+ if (ec) {
+ throw filesystem_error(detail::systemErrorText(ec.value()), to, new_symlink, ec);
+ }
+}
+#endif
+
+GHC_INLINE void create_directory_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept
+{
+ detail::create_symlink(to, new_symlink, true, ec);
+}
+
+#ifndef GHC_OS_WEB
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE void create_hard_link(const path& to, const path& new_hard_link)
+{
+ std::error_code ec;
+ create_hard_link(to, new_hard_link, ec);
+ if (ec) {
+ throw filesystem_error(detail::systemErrorText(ec.value()), to, new_hard_link, ec);
+ }
+}
+#endif
+
+GHC_INLINE void create_hard_link(const path& to, const path& new_hard_link, std::error_code& ec) noexcept
+{
+ detail::create_hardlink(to, new_hard_link, ec);
+}
+#endif
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE void create_symlink(const path& to, const path& new_symlink)
+{
+ std::error_code ec;
+ create_symlink(to, new_symlink, ec);
+ if (ec) {
+ throw filesystem_error(detail::systemErrorText(ec.value()), to, new_symlink, ec);
+ }
+}
+#endif
+
+GHC_INLINE void create_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept
+{
+ detail::create_symlink(to, new_symlink, false, ec);
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE path current_path()
+{
+ std::error_code ec;
+ auto result = current_path(ec);
+ if (ec) {
+ throw filesystem_error(detail::systemErrorText(ec.value()), ec);
+ }
+ return result;
+}
+#endif
+
+GHC_INLINE path current_path(std::error_code& ec)
+{
+ ec.clear();
+#ifdef GHC_OS_WINDOWS
+ DWORD pathlen = ::GetCurrentDirectoryW(0, 0);
+ std::unique_ptr<wchar_t[]> buffer(new wchar_t[size_t(pathlen) + 1]);
+ if (::GetCurrentDirectoryW(pathlen, buffer.get()) == 0) {
+ ec = detail::make_system_error();
+ return path();
+ }
+ return path(std::wstring(buffer.get()), path::native_format);
+#else
+ size_t pathlen = static_cast<size_t>(std::max(int(::pathconf(".", _PC_PATH_MAX)), int(PATH_MAX)));
+ std::unique_ptr<char[]> buffer(new char[pathlen + 1]);
+ if (::getcwd(buffer.get(), pathlen) == nullptr) {
+ ec = detail::make_system_error();
+ return path();
+ }
+ return path(buffer.get());
+#endif
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE void current_path(const path& p)
+{
+ std::error_code ec;
+ current_path(p, ec);
+ if (ec) {
+ throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
+ }
+}
+#endif
+
+GHC_INLINE void current_path(const path& p, std::error_code& ec) noexcept
+{
+ ec.clear();
+#ifdef GHC_OS_WINDOWS
+ if (!::SetCurrentDirectoryW(GHC_NATIVEWP(p))) {
+ ec = detail::make_system_error();
+ }
+#else
+ if (::chdir(p.string().c_str()) == -1) {
+ ec = detail::make_system_error();
+ }
+#endif
+}
+
+GHC_INLINE bool exists(file_status s) noexcept
+{
+ return status_known(s) && s.type() != file_type::not_found;
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE bool exists(const path& p)
+{
+ return exists(status(p));
+}
+#endif
+
+GHC_INLINE bool exists(const path& p, std::error_code& ec) noexcept
+{
+ file_status s = status(p, ec);
+ if (status_known(s)) {
+ ec.clear();
+ }
+ return exists(s);
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE bool equivalent(const path& p1, const path& p2)
+{
+ std::error_code ec;
+ bool result = equivalent(p1, p2, ec);
+ if (ec) {
+ throw filesystem_error(detail::systemErrorText(ec.value()), p1, p2, ec);
+ }
+ return result;
+}
+#endif
+
+GHC_INLINE bool equivalent(const path& p1, const path& p2, std::error_code& ec) noexcept
+{
+ ec.clear();
+#ifdef GHC_OS_WINDOWS
+ detail::unique_handle file1(::CreateFileW(GHC_NATIVEWP(p1), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0));
+ auto e1 = ::GetLastError();
+ detail::unique_handle file2(::CreateFileW(GHC_NATIVEWP(p2), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0));
+ if (!file1 || !file2) {
+#ifdef LWG_2937_BEHAVIOUR
+ ec = detail::make_system_error(e1 ? e1 : ::GetLastError());
+#else
+ if (file1 == file2) {
+ ec = detail::make_system_error(e1 ? e1 : ::GetLastError());
+ }
+#endif
+ return false;
+ }
+ BY_HANDLE_FILE_INFORMATION inf1, inf2;
+ if (!::GetFileInformationByHandle(file1.get(), &inf1)) {
+ ec = detail::make_system_error();
+ return false;
+ }
+ if (!::GetFileInformationByHandle(file2.get(), &inf2)) {
+ ec = detail::make_system_error();
+ return false;
+ }
+ return inf1.ftLastWriteTime.dwLowDateTime == inf2.ftLastWriteTime.dwLowDateTime && inf1.ftLastWriteTime.dwHighDateTime == inf2.ftLastWriteTime.dwHighDateTime && inf1.nFileIndexHigh == inf2.nFileIndexHigh && inf1.nFileIndexLow == inf2.nFileIndexLow &&
+ inf1.nFileSizeHigh == inf2.nFileSizeHigh && inf1.nFileSizeLow == inf2.nFileSizeLow && inf1.dwVolumeSerialNumber == inf2.dwVolumeSerialNumber;
+#else
+ struct ::stat s1, s2;
+ auto rc1 = ::stat(p1.c_str(), &s1);
+ auto e1 = errno;
+ auto rc2 = ::stat(p2.c_str(), &s2);
+ if (rc1 || rc2) {
+#ifdef LWG_2937_BEHAVIOUR
+ ec = detail::make_system_error(e1 ? e1 : errno);
+#else
+ if (rc1 && rc2) {
+ ec = detail::make_system_error(e1 ? e1 : errno);
+ }
+#endif
+ return false;
+ }
+ return s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino && s1.st_size == s2.st_size && s1.st_mtime == s2.st_mtime;
+#endif
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE uintmax_t file_size(const path& p)
+{
+ std::error_code ec;
+ auto result = file_size(p, ec);
+ if (ec) {
+ throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
+ }
+ return result;
+}
+#endif
+
+GHC_INLINE uintmax_t file_size(const path& p, std::error_code& ec) noexcept
+{
+ ec.clear();
+#ifdef GHC_OS_WINDOWS
+ WIN32_FILE_ATTRIBUTE_DATA attr;
+ if (!GetFileAttributesExW(GHC_NATIVEWP(p), GetFileExInfoStandard, &attr)) {
+ ec = detail::make_system_error();
+ return static_cast<uintmax_t>(-1);
+ }
+ return static_cast<uintmax_t>(attr.nFileSizeHigh) << (sizeof(attr.nFileSizeHigh) * 8) | attr.nFileSizeLow;
+#else
+ struct ::stat fileStat;
+ if (::stat(p.c_str(), &fileStat) == -1) {
+ ec = detail::make_system_error();
+ return static_cast<uintmax_t>(-1);
+ }
+ return static_cast<uintmax_t>(fileStat.st_size);
+#endif
+}
+
+#ifndef GHC_OS_WEB
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE uintmax_t hard_link_count(const path& p)
+{
+ std::error_code ec;
+ auto result = hard_link_count(p, ec);
+ if (ec) {
+ throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
+ }
+ return result;
+}
+#endif
+
+GHC_INLINE uintmax_t hard_link_count(const path& p, std::error_code& ec) noexcept
+{
+ ec.clear();
+#ifdef GHC_OS_WINDOWS
+ uintmax_t result = static_cast<uintmax_t>(-1);
+ detail::unique_handle file(::CreateFileW(GHC_NATIVEWP(p), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0));
+ BY_HANDLE_FILE_INFORMATION inf;
+ if (!file) {
+ ec = detail::make_system_error();
+ }
+ else {
+ if (!::GetFileInformationByHandle(file.get(), &inf)) {
+ ec = detail::make_system_error();
+ }
+ else {
+ result = inf.nNumberOfLinks;
+ }
+ }
+ return result;
+#else
+ uintmax_t result = 0;
+ file_status fs = detail::status_ex(p, ec, nullptr, nullptr, &result, nullptr);
+ if (fs.type() == file_type::not_found) {
+ ec = detail::make_error_code(detail::portable_error::not_found);
+ }
+ return ec ? static_cast<uintmax_t>(-1) : result;
+#endif
+}
+#endif
+
+GHC_INLINE bool is_block_file(file_status s) noexcept
+{
+ return s.type() == file_type::block;
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE bool is_block_file(const path& p)
+{
+ return is_block_file(status(p));
+}
+#endif
+
+GHC_INLINE bool is_block_file(const path& p, std::error_code& ec) noexcept
+{
+ return is_block_file(status(p, ec));
+}
+
+GHC_INLINE bool is_character_file(file_status s) noexcept
+{
+ return s.type() == file_type::character;
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE bool is_character_file(const path& p)
+{
+ return is_character_file(status(p));
+}
+#endif
+
+GHC_INLINE bool is_character_file(const path& p, std::error_code& ec) noexcept
+{
+ return is_character_file(status(p, ec));
+}
+
+GHC_INLINE bool is_directory(file_status s) noexcept
+{
+ return s.type() == file_type::directory;
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE bool is_directory(const path& p)
+{
+ return is_directory(status(p));
+}
+#endif
+
+GHC_INLINE bool is_directory(const path& p, std::error_code& ec) noexcept
+{
+ return is_directory(status(p, ec));
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE bool is_empty(const path& p)
+{
+ if (is_directory(p)) {
+ return directory_iterator(p) == directory_iterator();
+ }
+ else {
+ return file_size(p) == 0;
+ }
+}
+#endif
+
+GHC_INLINE bool is_empty(const path& p, std::error_code& ec) noexcept
+{
+ auto fs = status(p, ec);
+ if (ec) {
+ return false;
+ }
+ if (is_directory(fs)) {
+ directory_iterator iter(p, ec);
+ if (ec) {
+ return false;
+ }
+ return iter == directory_iterator();
+ }
+ else {
+ auto sz = file_size(p, ec);
+ if (ec) {
+ return false;
+ }
+ return sz == 0;
+ }
+}
+
+GHC_INLINE bool is_fifo(file_status s) noexcept
+{
+ return s.type() == file_type::fifo;
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE bool is_fifo(const path& p)
+{
+ return is_fifo(status(p));
+}
+#endif
+
+GHC_INLINE bool is_fifo(const path& p, std::error_code& ec) noexcept
+{
+ return is_fifo(status(p, ec));
+}
+
+GHC_INLINE bool is_other(file_status s) noexcept
+{
+ return exists(s) && !is_regular_file(s) && !is_directory(s) && !is_symlink(s);
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE bool is_other(const path& p)
+{
+ return is_other(status(p));
+}
+#endif
+
+GHC_INLINE bool is_other(const path& p, std::error_code& ec) noexcept
+{
+ return is_other(status(p, ec));
+}
+
+GHC_INLINE bool is_regular_file(file_status s) noexcept
+{
+ return s.type() == file_type::regular;
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE bool is_regular_file(const path& p)
+{
+ return is_regular_file(status(p));
+}
+#endif
+
+GHC_INLINE bool is_regular_file(const path& p, std::error_code& ec) noexcept
+{
+ return is_regular_file(status(p, ec));
+}
+
+GHC_INLINE bool is_socket(file_status s) noexcept
+{
+ return s.type() == file_type::socket;
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE bool is_socket(const path& p)
+{
+ return is_socket(status(p));
+}
+#endif
+
+GHC_INLINE bool is_socket(const path& p, std::error_code& ec) noexcept
+{
+ return is_socket(status(p, ec));
+}
+
+GHC_INLINE bool is_symlink(file_status s) noexcept
+{
+ return s.type() == file_type::symlink;
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE bool is_symlink(const path& p)
+{
+ return is_symlink(symlink_status(p));
+}
+#endif
+
+GHC_INLINE bool is_symlink(const path& p, std::error_code& ec) noexcept
+{
+ return is_symlink(symlink_status(p, ec));
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE file_time_type last_write_time(const path& p)
+{
+ std::error_code ec;
+ auto result = last_write_time(p, ec);
+ if (ec) {
+ throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
+ }
+ return result;
+}
+#endif
+
+GHC_INLINE file_time_type last_write_time(const path& p, std::error_code& ec) noexcept
+{
+ time_t result = 0;
+ ec.clear();
+ file_status fs = detail::status_ex(p, ec, nullptr, nullptr, nullptr, &result);
+ return ec ? (file_time_type::min)() : std::chrono::system_clock::from_time_t(result);
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE void last_write_time(const path& p, file_time_type new_time)
+{
+ std::error_code ec;
+ last_write_time(p, new_time, ec);
+ if (ec) {
+ throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
+ }
+}
+#endif
+
+GHC_INLINE void last_write_time(const path& p, file_time_type new_time, std::error_code& ec) noexcept
+{
+ ec.clear();
+ auto d = new_time.time_since_epoch();
+#ifdef GHC_OS_WINDOWS
+ detail::unique_handle file(::CreateFileW(GHC_NATIVEWP(p), FILE_WRITE_ATTRIBUTES, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL));
+ FILETIME ft;
+ auto tt = std::chrono::duration_cast<std::chrono::microseconds>(d).count() * 10 + 116444736000000000;
+ ft.dwLowDateTime = static_cast<DWORD>(tt);
+ ft.dwHighDateTime = static_cast<DWORD>(tt >> 32);
+ if (!::SetFileTime(file.get(), 0, 0, &ft)) {
+ ec = detail::make_system_error();
+ }
+#elif defined(GHC_OS_MACOS)
+#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED
+#if __MAC_OS_X_VERSION_MIN_REQUIRED < 101300
+ struct ::stat fs;
+ if (::stat(p.c_str(), &fs) == 0) {
+ struct ::timeval tv[2];
+ tv[0].tv_sec = fs.st_atimespec.tv_sec;
+ tv[0].tv_usec = static_cast<int>(fs.st_atimespec.tv_nsec / 1000);
+ tv[1].tv_sec = std::chrono::duration_cast<std::chrono::seconds>(d).count();
+ tv[1].tv_usec = static_cast<int>(std::chrono::duration_cast<std::chrono::microseconds>(d).count() % 1000000);
+ if (::utimes(p.c_str(), tv) == 0) {
+ return;
+ }
+ }
+ ec = detail::make_system_error();
+ return;
+#else
+ struct ::timespec times[2];
+ times[0].tv_sec = 0;
+ times[0].tv_nsec = UTIME_OMIT;
+ times[1].tv_sec = std::chrono::duration_cast<std::chrono::seconds>(d).count();
+ times[1].tv_nsec = 0; // std::chrono::duration_cast<std::chrono::nanoseconds>(d).count() % 1000000000;
+ if (::utimensat(AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) {
+ ec = detail::make_system_error();
+ }
+ return;
+#endif
+#endif
+#else
+#ifndef UTIME_OMIT
+#define UTIME_OMIT ((1l << 30) - 2l)
+#endif
+ struct ::timespec times[2];
+ times[0].tv_sec = 0;
+ times[0].tv_nsec = UTIME_OMIT;
+ times[1].tv_sec = static_cast<decltype(times[1].tv_sec)>(std::chrono::duration_cast<std::chrono::seconds>(d).count());
+ times[1].tv_nsec = static_cast<decltype(times[1].tv_nsec)>(std::chrono::duration_cast<std::chrono::nanoseconds>(d).count() % 1000000000);
+#if defined(__ANDROID_API__) && __ANDROID_API__ < 12
+ if (syscall(__NR_utimensat, AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) {
+#else
+ if (::utimensat(AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) {
+#endif
+ ec = detail::make_system_error();
+ }
+ return;
+#endif
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE void permissions(const path& p, perms prms, perm_options opts)
+{
+ std::error_code ec;
+ permissions(p, prms, opts, ec);
+ if (ec) {
+ throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
+ }
+}
+#endif
+
+GHC_INLINE void permissions(const path& p, perms prms, std::error_code& ec) noexcept
+{
+ permissions(p, prms, perm_options::replace, ec);
+}
+
+GHC_INLINE void permissions(const path& p, perms prms, perm_options opts, std::error_code& ec) noexcept
+{
+ if (static_cast<int>(opts & (perm_options::replace | perm_options::add | perm_options::remove)) == 0) {
+ ec = detail::make_error_code(detail::portable_error::invalid_argument);
+ return;
+ }
+ auto fs = symlink_status(p, ec);
+ if ((opts & perm_options::replace) != perm_options::replace) {
+ if ((opts & perm_options::add) == perm_options::add) {
+ prms = fs.permissions() | prms;
+ }
+ else {
+ prms = fs.permissions() & ~prms;
+ }
+ }
+#ifdef GHC_OS_WINDOWS
+#ifdef __GNUC__
+ auto oldAttr = GetFileAttributesW(GHC_NATIVEWP(p));
+ if (oldAttr != INVALID_FILE_ATTRIBUTES) {
+ DWORD newAttr = ((prms & perms::owner_write) == perms::owner_write) ? oldAttr & ~(static_cast<DWORD>(FILE_ATTRIBUTE_READONLY)) : oldAttr | FILE_ATTRIBUTE_READONLY;
+ if (oldAttr == newAttr || SetFileAttributesW(GHC_NATIVEWP(p), newAttr)) {
+ return;
+ }
+ }
+ ec = detail::make_system_error();
+#else
+ int mode = 0;
+ if ((prms & perms::owner_read) == perms::owner_read) {
+ mode |= _S_IREAD;
+ }
+ if ((prms & perms::owner_write) == perms::owner_write) {
+ mode |= _S_IWRITE;
+ }
+ if (::_wchmod(p.wstring().c_str(), mode) != 0) {
+ ec = detail::make_system_error();
+ }
+#endif
+#else
+ if ((opts & perm_options::nofollow) != perm_options::nofollow) {
+ if (::chmod(p.c_str(), static_cast<mode_t>(prms)) != 0) {
+ ec = detail::make_system_error();
+ }
+ }
+#endif
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE path proximate(const path& p, std::error_code& ec)
+{
+ auto cp = current_path(ec);
+ if (!ec) {
+ return proximate(p, cp, ec);
+ }
+ return path();
+}
+#endif
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE path proximate(const path& p, const path& base)
+{
+ return weakly_canonical(p).lexically_proximate(weakly_canonical(base));
+}
+#endif
+
+GHC_INLINE path proximate(const path& p, const path& base, std::error_code& ec)
+{
+ return weakly_canonical(p, ec).lexically_proximate(weakly_canonical(base, ec));
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE path read_symlink(const path& p)
+{
+ std::error_code ec;
+ auto result = read_symlink(p, ec);
+ if (ec) {
+ throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
+ }
+ return result;
+}
+#endif
+
+GHC_INLINE path read_symlink(const path& p, std::error_code& ec)
+{
+ file_status fs = symlink_status(p, ec);
+ if (fs.type() != file_type::symlink) {
+ ec = detail::make_error_code(detail::portable_error::invalid_argument);
+ return path();
+ }
+ auto result = detail::resolveSymlink(p, ec);
+ return ec ? path() : result;
+}
+
+GHC_INLINE path relative(const path& p, std::error_code& ec)
+{
+ return relative(p, current_path(ec), ec);
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE path relative(const path& p, const path& base)
+{
+ return weakly_canonical(p).lexically_relative(weakly_canonical(base));
+}
+#endif
+
+GHC_INLINE path relative(const path& p, const path& base, std::error_code& ec)
+{
+ return weakly_canonical(p, ec).lexically_relative(weakly_canonical(base, ec));
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE bool remove(const path& p)
+{
+ std::error_code ec;
+ auto result = remove(p, ec);
+ if (ec) {
+ throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
+ }
+ return result;
+}
+#endif
+
+GHC_INLINE bool remove(const path& p, std::error_code& ec) noexcept
+{
+ ec.clear();
+#ifdef GHC_OS_WINDOWS
+#ifdef GHC_USE_WCHAR_T
+ auto cstr = p.c_str();
+#else
+ std::wstring np = detail::fromUtf8<std::wstring>(p.u8string());
+ auto cstr = np.c_str();
+#endif
+ DWORD attr = GetFileAttributesW(cstr);
+ if (attr == INVALID_FILE_ATTRIBUTES) {
+ auto error = ::GetLastError();
+ if (error == ERROR_FILE_NOT_FOUND || error == ERROR_PATH_NOT_FOUND) {
+ return false;
+ }
+ ec = detail::make_system_error(error);
+ }
+ else if (attr & FILE_ATTRIBUTE_READONLY) {
+ auto new_attr = attr & ~static_cast<DWORD>(FILE_ATTRIBUTE_READONLY);
+ if (!SetFileAttributesW(cstr, new_attr)) {
+ auto error = ::GetLastError();
+ ec = detail::make_system_error(error);
+ }
+ }
+ if (!ec) {
+ if (attr & FILE_ATTRIBUTE_DIRECTORY) {
+ if (!RemoveDirectoryW(cstr)) {
+ ec = detail::make_system_error();
+ }
+ }
+ else {
+ if (!DeleteFileW(cstr)) {
+ ec = detail::make_system_error();
+ }
+ }
+ }
+#else
+ if (::remove(p.c_str()) == -1) {
+ auto error = errno;
+ if (error == ENOENT) {
+ return false;
+ }
+ ec = detail::make_system_error();
+ }
+#endif
+ return ec ? false : true;
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE uintmax_t remove_all(const path& p)
+{
+ std::error_code ec;
+ auto result = remove_all(p, ec);
+ if (ec) {
+ throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
+ }
+ return result;
+}
+#endif
+
+GHC_INLINE uintmax_t remove_all(const path& p, std::error_code& ec) noexcept
+{
+ ec.clear();
+ uintmax_t count = 0;
+ if (p == "/") {
+ ec = detail::make_error_code(detail::portable_error::not_supported);
+ return static_cast<uintmax_t>(-1);
+ }
+ std::error_code tec;
+ auto fs = symlink_status(p, tec);
+ if (exists(fs) && is_directory(fs)) {
+ for (auto iter = directory_iterator(p, ec); iter != directory_iterator(); iter.increment(ec)) {
+ if (ec && !detail::is_not_found_error(ec)) {
+ break;
+ }
+ bool is_symlink_result = iter->is_symlink(ec);
+ if (ec)
+ return static_cast<uintmax_t>(-1);
+ if (!is_symlink_result && iter->is_directory(ec)) {
+ count += remove_all(iter->path(), ec);
+ if (ec) {
+ return static_cast<uintmax_t>(-1);
+ }
+ }
+ else {
+ if (!ec) {
+ remove(iter->path(), ec);
+ }
+ if (ec) {
+ return static_cast<uintmax_t>(-1);
+ }
+ ++count;
+ }
+ }
+ }
+ if (!ec) {
+ if (remove(p, ec)) {
+ ++count;
+ }
+ }
+ if (ec) {
+ return static_cast<uintmax_t>(-1);
+ }
+ return count;
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE void rename(const path& from, const path& to)
+{
+ std::error_code ec;
+ rename(from, to, ec);
+ if (ec) {
+ throw filesystem_error(detail::systemErrorText(ec.value()), from, to, ec);
+ }
+}
+#endif
+
+GHC_INLINE void rename(const path& from, const path& to, std::error_code& ec) noexcept
+{
+ ec.clear();
+#ifdef GHC_OS_WINDOWS
+ if (from != to) {
+ if (!MoveFileExW(GHC_NATIVEWP(from), GHC_NATIVEWP(to), (DWORD)MOVEFILE_REPLACE_EXISTING)) {
+ ec = detail::make_system_error();
+ }
+ }
+#else
+ if (from != to) {
+ if (::rename(from.c_str(), to.c_str()) != 0) {
+ ec = detail::make_system_error();
+ }
+ }
+#endif
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE void resize_file(const path& p, uintmax_t size)
+{
+ std::error_code ec;
+ resize_file(p, size, ec);
+ if (ec) {
+ throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
+ }
+}
+#endif
+
+GHC_INLINE void resize_file(const path& p, uintmax_t size, std::error_code& ec) noexcept
+{
+ ec.clear();
+#ifdef GHC_OS_WINDOWS
+ LARGE_INTEGER lisize;
+ lisize.QuadPart = static_cast<LONGLONG>(size);
+ if (lisize.QuadPart < 0) {
+#ifdef ERROR_FILE_TOO_LARGE
+ ec = detail::make_system_error(ERROR_FILE_TOO_LARGE);
+#else
+ ec = detail::make_system_error(223);
+#endif
+ return;
+ }
+ detail::unique_handle file(CreateFileW(GHC_NATIVEWP(p), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL));
+ if (!file) {
+ ec = detail::make_system_error();
+ }
+ else if (SetFilePointerEx(file.get(), lisize, NULL, FILE_BEGIN) == 0 || SetEndOfFile(file.get()) == 0) {
+ ec = detail::make_system_error();
+ }
+#else
+ if (::truncate(p.c_str(), static_cast<off_t>(size)) != 0) {
+ ec = detail::make_system_error();
+ }
+#endif
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE space_info space(const path& p)
+{
+ std::error_code ec;
+ auto result = space(p, ec);
+ if (ec) {
+ throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
+ }
+ return result;
+}
+#endif
+
+GHC_INLINE space_info space(const path& p, std::error_code& ec) noexcept
+{
+ ec.clear();
+#ifdef GHC_OS_WINDOWS
+ ULARGE_INTEGER freeBytesAvailableToCaller = {{ 0, 0 }};
+ ULARGE_INTEGER totalNumberOfBytes = {{ 0, 0 }};
+ ULARGE_INTEGER totalNumberOfFreeBytes = {{ 0, 0 }};
+ if (!GetDiskFreeSpaceExW(GHC_NATIVEWP(p), &freeBytesAvailableToCaller, &totalNumberOfBytes, &totalNumberOfFreeBytes)) {
+ ec = detail::make_system_error();
+ return {static_cast<uintmax_t>(-1), static_cast<uintmax_t>(-1), static_cast<uintmax_t>(-1)};
+ }
+ return {static_cast<uintmax_t>(totalNumberOfBytes.QuadPart), static_cast<uintmax_t>(totalNumberOfFreeBytes.QuadPart), static_cast<uintmax_t>(freeBytesAvailableToCaller.QuadPart)};
+#else
+ struct ::statvfs sfs;
+ if (::statvfs(p.c_str(), &sfs) != 0) {
+ ec = detail::make_system_error();
+ return {static_cast<uintmax_t>(-1), static_cast<uintmax_t>(-1), static_cast<uintmax_t>(-1)};
+ }
+ return {static_cast<uintmax_t>(sfs.f_blocks) * static_cast<uintmax_t>(sfs.f_frsize), static_cast<uintmax_t>(sfs.f_bfree) * static_cast<uintmax_t>(sfs.f_frsize), static_cast<uintmax_t>(sfs.f_bavail) * static_cast<uintmax_t>(sfs.f_frsize)};
+#endif
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE file_status status(const path& p)
+{
+ std::error_code ec;
+ auto result = status(p, ec);
+ if (result.type() == file_type::none) {
+ throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
+ }
+ return result;
+}
+#endif
+
+GHC_INLINE file_status status(const path& p, std::error_code& ec) noexcept
+{
+ return detail::status_ex(p, ec);
+}
+
+GHC_INLINE bool status_known(file_status s) noexcept
+{
+ return s.type() != file_type::none;
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE file_status symlink_status(const path& p)
+{
+ std::error_code ec;
+ auto result = symlink_status(p, ec);
+ if (result.type() == file_type::none) {
+ throw filesystem_error(detail::systemErrorText(ec.value()), ec);
+ }
+ return result;
+}
+#endif
+
+GHC_INLINE file_status symlink_status(const path& p, std::error_code& ec) noexcept
+{
+ return detail::symlink_status_ex(p, ec);
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE path temp_directory_path()
+{
+ std::error_code ec;
+ path result = temp_directory_path(ec);
+ if (ec) {
+ throw filesystem_error(detail::systemErrorText(ec.value()), ec);
+ }
+ return result;
+}
+#endif
+
+GHC_INLINE path temp_directory_path(std::error_code& ec) noexcept
+{
+ ec.clear();
+#ifdef GHC_OS_WINDOWS
+ wchar_t buffer[512];
+ auto rc = GetTempPathW(511, buffer);
+ if (!rc || rc > 511) {
+ ec = detail::make_system_error();
+ return path();
+ }
+ return path(std::wstring(buffer));
+#else
+ static const char* temp_vars[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr};
+ const char* temp_path = nullptr;
+ for (auto temp_name = temp_vars; *temp_name != nullptr; ++temp_name) {
+ temp_path = std::getenv(*temp_name);
+ if (temp_path) {
+ return path(temp_path);
+ }
+ }
+ return path("/tmp");
+#endif
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE path weakly_canonical(const path& p)
+{
+ std::error_code ec;
+ auto result = weakly_canonical(p, ec);
+ if (ec) {
+ throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
+ }
+ return result;
+}
+#endif
+
+GHC_INLINE path weakly_canonical(const path& p, std::error_code& ec) noexcept
+{
+ path result;
+ ec.clear();
+ bool scan = true;
+ for (auto pe : p) {
+ if (scan) {
+ std::error_code tec;
+ if (exists(result / pe, tec)) {
+ result /= pe;
+ }
+ else {
+ if (ec) {
+ return path();
+ }
+ scan = false;
+ if (!result.empty()) {
+ result = canonical(result, ec) / pe;
+ if (ec) {
+ break;
+ }
+ }
+ else {
+ result /= pe;
+ }
+ }
+ }
+ else {
+ result /= pe;
+ }
+ }
+ if (scan) {
+ if (!result.empty()) {
+ result = canonical(result, ec);
+ }
+ }
+ return ec ? path() : result.lexically_normal();
+}
+
+//-----------------------------------------------------------------------------
+// [fs.class.file_status] class file_status
+// [fs.file_status.cons] constructors and destructor
+GHC_INLINE file_status::file_status() noexcept
+ : file_status(file_type::none)
+{
+}
+
+GHC_INLINE file_status::file_status(file_type ft, perms prms) noexcept
+ : _type(ft)
+ , _perms(prms)
+{
+}
+
+GHC_INLINE file_status::file_status(const file_status& other) noexcept
+ : _type(other._type)
+ , _perms(other._perms)
+{
+}
+
+GHC_INLINE file_status::file_status(file_status&& other) noexcept
+ : _type(other._type)
+ , _perms(other._perms)
+{
+}
+
+GHC_INLINE file_status::~file_status() {}
+
+// assignments:
+GHC_INLINE file_status& file_status::operator=(const file_status& rhs) noexcept
+{
+ _type = rhs._type;
+ _perms = rhs._perms;
+ return *this;
+}
+
+GHC_INLINE file_status& file_status::operator=(file_status&& rhs) noexcept
+{
+ _type = rhs._type;
+ _perms = rhs._perms;
+ return *this;
+}
+
+// [fs.file_status.mods] modifiers
+GHC_INLINE void file_status::type(file_type ft) noexcept
+{
+ _type = ft;
+}
+
+GHC_INLINE void file_status::permissions(perms prms) noexcept
+{
+ _perms = prms;
+}
+
+// [fs.file_status.obs] observers
+GHC_INLINE file_type file_status::type() const noexcept
+{
+ return _type;
+}
+
+GHC_INLINE perms file_status::permissions() const noexcept
+{
+ return _perms;
+}
+
+//-----------------------------------------------------------------------------
+// [fs.class.directory_entry] class directory_entry
+// [fs.dir.entry.cons] constructors and destructor
+// directory_entry::directory_entry() noexcept = default;
+// directory_entry::directory_entry(const directory_entry&) = default;
+// directory_entry::directory_entry(directory_entry&&) noexcept = default;
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE directory_entry::directory_entry(const filesystem::path& p)
+ : _path(p)
+ , _file_size(static_cast<uintmax_t>(-1))
+#ifndef GHC_OS_WINDOWS
+ , _hard_link_count(static_cast<uintmax_t>(-1))
+#endif
+ , _last_write_time(0)
+{
+ refresh();
+}
+#endif
+
+GHC_INLINE directory_entry::directory_entry(const filesystem::path& p, std::error_code& ec)
+ : _path(p)
+ , _file_size(static_cast<uintmax_t>(-1))
+#ifndef GHC_OS_WINDOWS
+ , _hard_link_count(static_cast<uintmax_t>(-1))
+#endif
+ , _last_write_time(0)
+{
+ refresh(ec);
+}
+
+GHC_INLINE directory_entry::~directory_entry() {}
+
+// assignments:
+// directory_entry& directory_entry::operator=(const directory_entry&) = default;
+// directory_entry& directory_entry::operator=(directory_entry&&) noexcept = default;
+
+// [fs.dir.entry.mods] directory_entry modifiers
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE void directory_entry::assign(const filesystem::path& p)
+{
+ _path = p;
+ refresh();
+}
+#endif
+
+GHC_INLINE void directory_entry::assign(const filesystem::path& p, std::error_code& ec)
+{
+ _path = p;
+ refresh(ec);
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE void directory_entry::replace_filename(const filesystem::path& p)
+{
+ _path.replace_filename(p);
+ refresh();
+}
+#endif
+
+GHC_INLINE void directory_entry::replace_filename(const filesystem::path& p, std::error_code& ec)
+{
+ _path.replace_filename(p);
+ refresh(ec);
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE void directory_entry::refresh()
+{
+ std::error_code ec;
+ refresh(ec);
+ if (ec) {
+ throw filesystem_error(detail::systemErrorText(ec.value()), _path, ec);
+ }
+}
+#endif
+
+GHC_INLINE void directory_entry::refresh(std::error_code& ec) noexcept
+{
+#ifdef GHC_OS_WINDOWS
+ _status = detail::status_ex(_path, ec, &_symlink_status, &_file_size, nullptr, &_last_write_time);
+#else
+ _status = detail::status_ex(_path, ec, &_symlink_status, &_file_size, &_hard_link_count, &_last_write_time);
+#endif
+}
+
+// [fs.dir.entry.obs] directory_entry observers
+GHC_INLINE const filesystem::path& directory_entry::path() const noexcept
+{
+ return _path;
+}
+
+GHC_INLINE directory_entry::operator const filesystem::path&() const noexcept
+{
+ return _path;
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE file_type directory_entry::status_file_type() const
+{
+ return _status.type() != file_type::none ? _status.type() : filesystem::status(path()).type();
+}
+#endif
+
+GHC_INLINE file_type directory_entry::status_file_type(std::error_code& ec) const noexcept
+{
+ if (_status.type() != file_type::none) {
+ ec.clear();
+ return _status.type();
+ }
+ return filesystem::status(path(), ec).type();
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE bool directory_entry::exists() const
+{
+ return status_file_type() != file_type::not_found;
+}
+#endif
+
+GHC_INLINE bool directory_entry::exists(std::error_code& ec) const noexcept
+{
+ return status_file_type(ec) != file_type::not_found;
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE bool directory_entry::is_block_file() const
+{
+ return status_file_type() == file_type::block;
+}
+#endif
+GHC_INLINE bool directory_entry::is_block_file(std::error_code& ec) const noexcept
+{
+ return status_file_type(ec) == file_type::block;
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE bool directory_entry::is_character_file() const
+{
+ return status_file_type() == file_type::character;
+}
+#endif
+
+GHC_INLINE bool directory_entry::is_character_file(std::error_code& ec) const noexcept
+{
+ return status_file_type(ec) == file_type::character;
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE bool directory_entry::is_directory() const
+{
+ return status_file_type() == file_type::directory;
+}
+#endif
+
+GHC_INLINE bool directory_entry::is_directory(std::error_code& ec) const noexcept
+{
+ return status_file_type(ec) == file_type::directory;
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE bool directory_entry::is_fifo() const
+{
+ return status_file_type() == file_type::fifo;
+}
+#endif
+
+GHC_INLINE bool directory_entry::is_fifo(std::error_code& ec) const noexcept
+{
+ return status_file_type(ec) == file_type::fifo;
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE bool directory_entry::is_other() const
+{
+ auto ft = status_file_type();
+ return ft != file_type::none && ft != file_type::not_found && ft != file_type::regular && ft != file_type::directory && !is_symlink();
+}
+#endif
+
+GHC_INLINE bool directory_entry::is_other(std::error_code& ec) const noexcept
+{
+ auto ft = status_file_type(ec);
+ bool other = ft != file_type::none && ft != file_type::not_found && ft != file_type::regular && ft != file_type::directory && !is_symlink(ec);
+ return !ec && other;
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE bool directory_entry::is_regular_file() const
+{
+ return status_file_type() == file_type::regular;
+}
+#endif
+
+GHC_INLINE bool directory_entry::is_regular_file(std::error_code& ec) const noexcept
+{
+ return status_file_type(ec) == file_type::regular;
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE bool directory_entry::is_socket() const
+{
+ return status_file_type() == file_type::socket;
+}
+#endif
+
+GHC_INLINE bool directory_entry::is_socket(std::error_code& ec) const noexcept
+{
+ return status_file_type(ec) == file_type::socket;
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE bool directory_entry::is_symlink() const
+{
+ return _symlink_status.type() != file_type::none ? _symlink_status.type() == file_type::symlink : filesystem::is_symlink(symlink_status());
+}
+#endif
+
+GHC_INLINE bool directory_entry::is_symlink(std::error_code& ec) const noexcept
+{
+ if (_symlink_status.type() != file_type::none) {
+ ec.clear();
+ return _symlink_status.type() == file_type::symlink;
+ }
+ return filesystem::is_symlink(symlink_status(ec));
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE uintmax_t directory_entry::file_size() const
+{
+ if (_file_size != static_cast<uintmax_t>(-1)) {
+ return _file_size;
+ }
+ return filesystem::file_size(path());
+}
+#endif
+
+GHC_INLINE uintmax_t directory_entry::file_size(std::error_code& ec) const noexcept
+{
+ if (_file_size != static_cast<uintmax_t>(-1)) {
+ ec.clear();
+ return _file_size;
+ }
+ return filesystem::file_size(path(), ec);
+}
+
+#ifndef GHC_OS_WEB
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE uintmax_t directory_entry::hard_link_count() const
+{
+#ifndef GHC_OS_WINDOWS
+ if (_hard_link_count != static_cast<uintmax_t>(-1)) {
+ return _hard_link_count;
+ }
+#endif
+ return filesystem::hard_link_count(path());
+}
+#endif
+
+GHC_INLINE uintmax_t directory_entry::hard_link_count(std::error_code& ec) const noexcept
+{
+#ifndef GHC_OS_WINDOWS
+ if (_hard_link_count != static_cast<uintmax_t>(-1)) {
+ ec.clear();
+ return _hard_link_count;
+ }
+#endif
+ return filesystem::hard_link_count(path(), ec);
+}
+#endif
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE file_time_type directory_entry::last_write_time() const
+{
+ if (_last_write_time != 0) {
+ return std::chrono::system_clock::from_time_t(_last_write_time);
+ }
+ return filesystem::last_write_time(path());
+}
+#endif
+
+GHC_INLINE file_time_type directory_entry::last_write_time(std::error_code& ec) const noexcept
+{
+ if (_last_write_time != 0) {
+ ec.clear();
+ return std::chrono::system_clock::from_time_t(_last_write_time);
+ }
+ return filesystem::last_write_time(path(), ec);
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE file_status directory_entry::status() const
+{
+ if (_status.type() != file_type::none && _status.permissions() != perms::unknown) {
+ return _status;
+ }
+ return filesystem::status(path());
+}
+#endif
+
+GHC_INLINE file_status directory_entry::status(std::error_code& ec) const noexcept
+{
+ if (_status.type() != file_type::none && _status.permissions() != perms::unknown) {
+ ec.clear();
+ return _status;
+ }
+ return filesystem::status(path(), ec);
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE file_status directory_entry::symlink_status() const
+{
+ if (_symlink_status.type() != file_type::none && _symlink_status.permissions() != perms::unknown) {
+ return _symlink_status;
+ }
+ return filesystem::symlink_status(path());
+}
+#endif
+
+GHC_INLINE file_status directory_entry::symlink_status(std::error_code& ec) const noexcept
+{
+ if (_symlink_status.type() != file_type::none && _symlink_status.permissions() != perms::unknown) {
+ ec.clear();
+ return _symlink_status;
+ }
+ return filesystem::symlink_status(path(), ec);
+}
+
+#ifdef GHC_HAS_THREEWAY_COMP
+GHC_INLINE std::strong_ordering directory_entry::operator<=>(const directory_entry& rhs) const noexcept
+{
+ return _path <=> rhs._path;
+}
+#endif
+
+GHC_INLINE bool directory_entry::operator<(const directory_entry& rhs) const noexcept
+{
+ return _path < rhs._path;
+}
+
+GHC_INLINE bool directory_entry::operator==(const directory_entry& rhs) const noexcept
+{
+ return _path == rhs._path;
+}
+
+GHC_INLINE bool directory_entry::operator!=(const directory_entry& rhs) const noexcept
+{
+ return _path != rhs._path;
+}
+
+GHC_INLINE bool directory_entry::operator<=(const directory_entry& rhs) const noexcept
+{
+ return _path <= rhs._path;
+}
+
+GHC_INLINE bool directory_entry::operator>(const directory_entry& rhs) const noexcept
+{
+ return _path > rhs._path;
+}
+
+GHC_INLINE bool directory_entry::operator>=(const directory_entry& rhs) const noexcept
+{
+ return _path >= rhs._path;
+}
+
+//-----------------------------------------------------------------------------
+// [fs.class.directory_iterator] class directory_iterator
+
+#ifdef GHC_OS_WINDOWS
+class directory_iterator::impl
+{
+public:
+ impl(const path& p, directory_options options)
+ : _base(p)
+ , _options(options)
+ , _dirHandle(INVALID_HANDLE_VALUE)
+ {
+ if (!_base.empty()) {
+ ZeroMemory(&_findData, sizeof(WIN32_FIND_DATAW));
+ if ((_dirHandle = FindFirstFileW(GHC_NATIVEWP((_base / "*")), &_findData)) != INVALID_HANDLE_VALUE) {
+ if (std::wstring(_findData.cFileName) == L"." || std::wstring(_findData.cFileName) == L"..") {
+ increment(_ec);
+ }
+ else {
+ _dir_entry._path = _base / std::wstring(_findData.cFileName);
+ copyToDirEntry(_ec);
+ }
+ }
+ else {
+ auto error = ::GetLastError();
+ _base = filesystem::path();
+ if (error != ERROR_ACCESS_DENIED || (options & directory_options::skip_permission_denied) == directory_options::none) {
+ _ec = detail::make_system_error();
+ }
+ }
+ }
+ }
+ impl(const impl& other) = delete;
+ ~impl()
+ {
+ if (_dirHandle != INVALID_HANDLE_VALUE) {
+ FindClose(_dirHandle);
+ _dirHandle = INVALID_HANDLE_VALUE;
+ }
+ }
+ void increment(std::error_code& ec)
+ {
+ if (_dirHandle != INVALID_HANDLE_VALUE) {
+ do {
+ if (FindNextFileW(_dirHandle, &_findData)) {
+ _dir_entry._path = _base;
+#ifdef GHC_USE_WCHAR_T
+ _dir_entry._path.append_name(_findData.cFileName);
+#else
+#ifdef GHC_RAISE_UNICODE_ERRORS
+ try {
+ _dir_entry._path.append_name(detail::toUtf8(_findData.cFileName).c_str());
+ }
+ catch (filesystem_error& fe) {
+ ec = fe.code();
+ return;
+ }
+#else
+ _dir_entry._path.append_name(detail::toUtf8(_findData.cFileName).c_str());
+#endif
+#endif
+ copyToDirEntry(ec);
+ }
+ else {
+ auto err = ::GetLastError();
+ if (err != ERROR_NO_MORE_FILES) {
+ _ec = ec = detail::make_system_error(err);
+ }
+ FindClose(_dirHandle);
+ _dirHandle = INVALID_HANDLE_VALUE;
+ _dir_entry._path.clear();
+ break;
+ }
+ } while (std::wstring(_findData.cFileName) == L"." || std::wstring(_findData.cFileName) == L"..");
+ }
+ else {
+ ec = _ec;
+ }
+ }
+ void copyToDirEntry(std::error_code& ec)
+ {
+ if (_findData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+ _dir_entry._status = detail::status_ex(_dir_entry._path, ec, &_dir_entry._symlink_status, &_dir_entry._file_size, nullptr, &_dir_entry._last_write_time);
+ }
+ else {
+ _dir_entry._status = detail::status_from_INFO(_dir_entry._path, &_findData, ec, &_dir_entry._file_size, &_dir_entry._last_write_time);
+ _dir_entry._symlink_status = _dir_entry._status;
+ }
+ if (ec) {
+ if (_dir_entry._status.type() != file_type::none && _dir_entry._symlink_status.type() != file_type::none) {
+ ec.clear();
+ }
+ else {
+ _dir_entry._file_size = static_cast<uintmax_t>(-1);
+ _dir_entry._last_write_time = 0;
+ }
+ }
+ }
+ path _base;
+ directory_options _options;
+ WIN32_FIND_DATAW _findData;
+ HANDLE _dirHandle;
+ directory_entry _dir_entry;
+ std::error_code _ec;
+};
+#else
+// POSIX implementation
+class directory_iterator::impl
+{
+public:
+ impl(const path& path, directory_options options)
+ : _base(path)
+ , _options(options)
+ , _dir(nullptr)
+ , _entry(nullptr)
+ {
+ if (!path.empty()) {
+ _dir = ::opendir(path.native().c_str());
+ if (!_dir) {
+ auto error = errno;
+ _base = filesystem::path();
+ if ((error != EACCES && error != EPERM) || (options & directory_options::skip_permission_denied) == directory_options::none) {
+ _ec = detail::make_system_error();
+ }
+ }
+ else {
+ increment(_ec);
+ }
+ }
+ }
+ impl(const impl& other) = delete;
+ ~impl()
+ {
+ if (_dir) {
+ ::closedir(_dir);
+ }
+ }
+ void increment(std::error_code& ec)
+ {
+ if (_dir) {
+ bool skip;
+ do {
+ skip = false;
+ errno = 0;
+ _entry = ::readdir(_dir);
+ if (_entry) {
+ _dir_entry._path = _base;
+ _dir_entry._path.append_name(_entry->d_name);
+ copyToDirEntry();
+ if (ec && (ec.value() == EACCES || ec.value() == EPERM) && (_options & directory_options::skip_permission_denied) == directory_options::skip_permission_denied) {
+ ec.clear();
+ skip = true;
+ }
+ }
+ else {
+ ::closedir(_dir);
+ _dir = nullptr;
+ _dir_entry._path.clear();
+ if (errno) {
+ ec = detail::make_system_error();
+ }
+ break;
+ }
+ } while (skip || std::strcmp(_entry->d_name, ".") == 0 || std::strcmp(_entry->d_name, "..") == 0);
+ }
+ }
+
+ void copyToDirEntry()
+ {
+#ifdef GHC_NO_DIRENT_D_TYPE
+ _dir_entry._symlink_status = file_status();
+ _dir_entry._status = file_status();
+#else
+ _dir_entry._symlink_status.permissions(perms::unknown);
+ switch (_entry->d_type) {
+ case DT_BLK:
+ _dir_entry._symlink_status.type(file_type::block);
+ break;
+ case DT_CHR:
+ _dir_entry._symlink_status.type(file_type::character);
+ break;
+ case DT_DIR:
+ _dir_entry._symlink_status.type(file_type::directory);
+ break;
+ case DT_FIFO:
+ _dir_entry._symlink_status.type(file_type::fifo);
+ break;
+ case DT_LNK:
+ _dir_entry._symlink_status.type(file_type::symlink);
+ break;
+ case DT_REG:
+ _dir_entry._symlink_status.type(file_type::regular);
+ break;
+ case DT_SOCK:
+ _dir_entry._symlink_status.type(file_type::socket);
+ break;
+ case DT_UNKNOWN:
+ _dir_entry._symlink_status.type(file_type::none);
+ break;
+ default:
+ _dir_entry._symlink_status.type(file_type::unknown);
+ break;
+ }
+ if (_entry->d_type != DT_LNK) {
+ _dir_entry._status = _dir_entry._symlink_status;
+ }
+ else {
+ _dir_entry._status.type(file_type::none);
+ _dir_entry._status.permissions(perms::unknown);
+ }
+#endif
+ _dir_entry._file_size = static_cast<uintmax_t>(-1);
+ _dir_entry._hard_link_count = static_cast<uintmax_t>(-1);
+ _dir_entry._last_write_time = 0;
+ }
+ path _base;
+ directory_options _options;
+ DIR* _dir;
+ struct ::dirent* _entry;
+ directory_entry _dir_entry;
+ std::error_code _ec;
+};
+#endif
+
+// [fs.dir.itr.members] member functions
+GHC_INLINE directory_iterator::directory_iterator() noexcept
+ : _impl(new impl(path(), directory_options::none))
+{
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE directory_iterator::directory_iterator(const path& p)
+ : _impl(new impl(p, directory_options::none))
+{
+ if (_impl->_ec) {
+ throw filesystem_error(detail::systemErrorText(_impl->_ec.value()), p, _impl->_ec);
+ }
+ _impl->_ec.clear();
+}
+
+GHC_INLINE directory_iterator::directory_iterator(const path& p, directory_options options)
+ : _impl(new impl(p, options))
+{
+ if (_impl->_ec) {
+ throw filesystem_error(detail::systemErrorText(_impl->_ec.value()), p, _impl->_ec);
+ }
+}
+#endif
+
+GHC_INLINE directory_iterator::directory_iterator(const path& p, std::error_code& ec) noexcept
+ : _impl(new impl(p, directory_options::none))
+{
+ if (_impl->_ec) {
+ ec = _impl->_ec;
+ }
+}
+
+GHC_INLINE directory_iterator::directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept
+ : _impl(new impl(p, options))
+{
+ if (_impl->_ec) {
+ ec = _impl->_ec;
+ }
+}
+
+GHC_INLINE directory_iterator::directory_iterator(const directory_iterator& rhs)
+ : _impl(rhs._impl)
+{
+}
+
+GHC_INLINE directory_iterator::directory_iterator(directory_iterator&& rhs) noexcept
+ : _impl(std::move(rhs._impl))
+{
+}
+
+GHC_INLINE directory_iterator::~directory_iterator() {}
+
+GHC_INLINE directory_iterator& directory_iterator::operator=(const directory_iterator& rhs)
+{
+ _impl = rhs._impl;
+ return *this;
+}
+
+GHC_INLINE directory_iterator& directory_iterator::operator=(directory_iterator&& rhs) noexcept
+{
+ _impl = std::move(rhs._impl);
+ return *this;
+}
+
+GHC_INLINE const directory_entry& directory_iterator::operator*() const
+{
+ return _impl->_dir_entry;
+}
+
+GHC_INLINE const directory_entry* directory_iterator::operator->() const
+{
+ return &_impl->_dir_entry;
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE directory_iterator& directory_iterator::operator++()
+{
+ std::error_code ec;
+ _impl->increment(ec);
+ if (ec) {
+ throw filesystem_error(detail::systemErrorText(ec.value()), _impl->_dir_entry._path, ec);
+ }
+ return *this;
+}
+#endif
+
+GHC_INLINE directory_iterator& directory_iterator::increment(std::error_code& ec) noexcept
+{
+ _impl->increment(ec);
+ return *this;
+}
+
+GHC_INLINE bool directory_iterator::operator==(const directory_iterator& rhs) const
+{
+ return _impl->_dir_entry._path == rhs._impl->_dir_entry._path;
+}
+
+GHC_INLINE bool directory_iterator::operator!=(const directory_iterator& rhs) const
+{
+ return _impl->_dir_entry._path != rhs._impl->_dir_entry._path;
+}
+
+// [fs.dir.itr.nonmembers] directory_iterator non-member functions
+
+GHC_INLINE directory_iterator begin(directory_iterator iter) noexcept
+{
+ return iter;
+}
+
+GHC_INLINE directory_iterator end(const directory_iterator&) noexcept
+{
+ return directory_iterator();
+}
+
+//-----------------------------------------------------------------------------
+// [fs.class.rec.dir.itr] class recursive_directory_iterator
+
+GHC_INLINE recursive_directory_iterator::recursive_directory_iterator() noexcept
+ : _impl(new recursive_directory_iterator_impl(directory_options::none, true))
+{
+ _impl->_dir_iter_stack.push(directory_iterator());
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p)
+ : _impl(new recursive_directory_iterator_impl(directory_options::none, true))
+{
+ _impl->_dir_iter_stack.push(directory_iterator(p));
+}
+
+GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p, directory_options options)
+ : _impl(new recursive_directory_iterator_impl(options, true))
+{
+ _impl->_dir_iter_stack.push(directory_iterator(p, options));
+}
+#endif
+
+GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept
+ : _impl(new recursive_directory_iterator_impl(options, true))
+{
+ _impl->_dir_iter_stack.push(directory_iterator(p, options, ec));
+}
+
+GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p, std::error_code& ec) noexcept
+ : _impl(new recursive_directory_iterator_impl(directory_options::none, true))
+{
+ _impl->_dir_iter_stack.push(directory_iterator(p, ec));
+}
+
+GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const recursive_directory_iterator& rhs)
+ : _impl(rhs._impl)
+{
+}
+
+GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(recursive_directory_iterator&& rhs) noexcept
+ : _impl(std::move(rhs._impl))
+{
+}
+
+GHC_INLINE recursive_directory_iterator::~recursive_directory_iterator() {}
+
+// [fs.rec.dir.itr.members] observers
+GHC_INLINE directory_options recursive_directory_iterator::options() const
+{
+ return _impl->_options;
+}
+
+GHC_INLINE int recursive_directory_iterator::depth() const
+{
+ return static_cast<int>(_impl->_dir_iter_stack.size() - 1);
+}
+
+GHC_INLINE bool recursive_directory_iterator::recursion_pending() const
+{
+ return _impl->_recursion_pending;
+}
+
+GHC_INLINE const directory_entry& recursive_directory_iterator::operator*() const
+{
+ return *(_impl->_dir_iter_stack.top());
+}
+
+GHC_INLINE const directory_entry* recursive_directory_iterator::operator->() const
+{
+ return &(*(_impl->_dir_iter_stack.top()));
+}
+
+// [fs.rec.dir.itr.members] modifiers recursive_directory_iterator&
+GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator=(const recursive_directory_iterator& rhs)
+{
+ _impl = rhs._impl;
+ return *this;
+}
+
+GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator=(recursive_directory_iterator&& rhs) noexcept
+{
+ _impl = std::move(rhs._impl);
+ return *this;
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator++()
+{
+ std::error_code ec;
+ increment(ec);
+ if (ec) {
+ throw filesystem_error(detail::systemErrorText(ec.value()), _impl->_dir_iter_stack.empty() ? path() : _impl->_dir_iter_stack.top()->path(), ec);
+ }
+ return *this;
+}
+#endif
+
+GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::increment(std::error_code& ec) noexcept
+{
+ bool isSymLink = (*this)->is_symlink(ec);
+ bool isDir = !ec && (*this)->is_directory(ec);
+ if (isSymLink && detail::is_not_found_error(ec)) {
+ ec.clear();
+ }
+ if (!ec) {
+ if (recursion_pending() && isDir && (!isSymLink || (options() & directory_options::follow_directory_symlink) != directory_options::none)) {
+ _impl->_dir_iter_stack.push(directory_iterator((*this)->path(), _impl->_options, ec));
+ }
+ else {
+ _impl->_dir_iter_stack.top().increment(ec);
+ }
+ if (!ec) {
+ while (depth() && _impl->_dir_iter_stack.top() == directory_iterator()) {
+ _impl->_dir_iter_stack.pop();
+ _impl->_dir_iter_stack.top().increment(ec);
+ }
+ }
+ else if (!_impl->_dir_iter_stack.empty()) {
+ _impl->_dir_iter_stack.pop();
+ }
+ _impl->_recursion_pending = true;
+ }
+ return *this;
+}
+
+#ifdef GHC_WITH_EXCEPTIONS
+GHC_INLINE void recursive_directory_iterator::pop()
+{
+ std::error_code ec;
+ pop(ec);
+ if (ec) {
+ throw filesystem_error(detail::systemErrorText(ec.value()), _impl->_dir_iter_stack.empty() ? path() : _impl->_dir_iter_stack.top()->path(), ec);
+ }
+}
+#endif
+
+GHC_INLINE void recursive_directory_iterator::pop(std::error_code& ec)
+{
+ if (depth() == 0) {
+ *this = recursive_directory_iterator();
+ }
+ else {
+ do {
+ _impl->_dir_iter_stack.pop();
+ _impl->_dir_iter_stack.top().increment(ec);
+ } while (depth() && _impl->_dir_iter_stack.top() == directory_iterator());
+ }
+}
+
+GHC_INLINE void recursive_directory_iterator::disable_recursion_pending()
+{
+ _impl->_recursion_pending = false;
+}
+
+// other members as required by [input.iterators]
+GHC_INLINE bool recursive_directory_iterator::operator==(const recursive_directory_iterator& rhs) const
+{
+ return _impl->_dir_iter_stack.top() == rhs._impl->_dir_iter_stack.top();
+}
+
+GHC_INLINE bool recursive_directory_iterator::operator!=(const recursive_directory_iterator& rhs) const
+{
+ return _impl->_dir_iter_stack.top() != rhs._impl->_dir_iter_stack.top();
+}
+
+// [fs.rec.dir.itr.nonmembers] directory_iterator non-member functions
+GHC_INLINE recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept
+{
+ return iter;
+}
+
+GHC_INLINE recursive_directory_iterator end(const recursive_directory_iterator&) noexcept
+{
+ return recursive_directory_iterator();
+}
+
+#endif // GHC_EXPAND_IMPL
+
+} // namespace filesystem
+} // namespace ghc
+
+// cleanup some macros
+#undef GHC_INLINE
+#undef GHC_EXPAND_IMPL
+
+#endif // GHC_FILESYSTEM_H
diff --git a/gulrak-filesystem/include/ghc/fs_fwd.hpp b/gulrak-filesystem/include/ghc/fs_fwd.hpp
new file mode 100644
index 0000000..31188d1
--- /dev/null
+++ b/gulrak-filesystem/include/ghc/fs_fwd.hpp
@@ -0,0 +1,38 @@
+//---------------------------------------------------------------------------------------
+//
+// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14
+//
+//---------------------------------------------------------------------------------------
+//
+// Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+//---------------------------------------------------------------------------------------
+// fs_fwd.hpp - The forwarding header for the header/implementation seperated usage of
+// ghc::filesystem.
+// This file can be include at any place, where ghc::filesystem api is needed while
+// not bleeding implementation details (e.g. system includes) into the global namespace,
+// as long as one cpp includes fs_impl.hpp to deliver the matching implementations.
+//---------------------------------------------------------------------------------------
+#ifndef GHC_FILESYSTEM_FWD_H
+#define GHC_FILESYSTEM_FWD_H
+#define GHC_FILESYSTEM_FWD
+#include <ghc/filesystem.hpp>
+#endif // GHC_FILESYSTEM_FWD_H
diff --git a/gulrak-filesystem/include/ghc/fs_impl.hpp b/gulrak-filesystem/include/ghc/fs_impl.hpp
new file mode 100644
index 0000000..92e3eae
--- /dev/null
+++ b/gulrak-filesystem/include/ghc/fs_impl.hpp
@@ -0,0 +1,35 @@
+//---------------------------------------------------------------------------------------
+//
+// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14
+//
+//---------------------------------------------------------------------------------------
+//
+// Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+//---------------------------------------------------------------------------------------
+// fs_impl.hpp - The implementation header for the header/implementation seperated usage of
+// ghc::filesystem.
+// This file can be used to hide the implementation of ghc::filesystem into a single cpp.
+// The cpp has to include this before including fs_fwd.hpp directly or via a different
+// header to work.
+//---------------------------------------------------------------------------------------
+#define GHC_FILESYSTEM_IMPLEMENTATION
+#include <ghc/filesystem.hpp>
diff --git a/gulrak-filesystem/include/ghc/fs_std.hpp b/gulrak-filesystem/include/ghc/fs_std.hpp
new file mode 100644
index 0000000..c9492fd
--- /dev/null
+++ b/gulrak-filesystem/include/ghc/fs_std.hpp
@@ -0,0 +1,60 @@
+//---------------------------------------------------------------------------------------
+//
+// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14
+//
+//---------------------------------------------------------------------------------------
+//
+// Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+//---------------------------------------------------------------------------------------
+// fs_std.hpp - The dynamic switching header that includes std::filesystem if detected
+// or ghc::filesystem if not, and makes the resulting API available in the
+// namespace fs.
+//---------------------------------------------------------------------------------------
+#ifndef GHC_FILESYSTEM_STD_H
+#define GHC_FILESYSTEM_STD_H
+#if defined(__APPLE__)
+#include <Availability.h>
+#endif
+#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
+#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
+#define GHC_USE_STD_FS
+#include <filesystem>
+namespace fs {
+using namespace std::filesystem;
+using ifstream = std::ifstream;
+using ofstream = std::ofstream;
+using fstream = std::fstream;
+}
+#endif
+#endif
+#ifndef GHC_USE_STD_FS
+//#define GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE
+#include <ghc/filesystem.hpp>
+namespace fs {
+using namespace ghc::filesystem;
+using ifstream = ghc::filesystem::ifstream;
+using ofstream = ghc::filesystem::ofstream;
+using fstream = ghc::filesystem::fstream;
+}
+#endif
+#endif // GHC_FILESYSTEM_STD_H
+
diff --git a/gulrak-filesystem/include/ghc/fs_std_fwd.hpp b/gulrak-filesystem/include/ghc/fs_std_fwd.hpp
new file mode 100644
index 0000000..163c956
--- /dev/null
+++ b/gulrak-filesystem/include/ghc/fs_std_fwd.hpp
@@ -0,0 +1,63 @@
+//---------------------------------------------------------------------------------------
+//
+// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14
+//
+//---------------------------------------------------------------------------------------
+//
+// Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+//---------------------------------------------------------------------------------------
+// fs_std_fwd.hpp - The forwarding header for the header/implementation seperated usage of
+// ghc::filesystem that uses std::filesystem if it detects it.
+// This file can be include at any place, where fs::filesystem api is needed while
+// not bleeding implementation details (e.g. system includes) into the global namespace,
+// as long as one cpp includes fs_std_impl.hpp to deliver the matching implementations.
+//---------------------------------------------------------------------------------------
+#ifndef GHC_FILESYSTEM_STD_FWD_H
+#define GHC_FILESYSTEM_STD_FWD_H
+#if defined(__APPLE__)
+#include <Availability.h>
+#endif
+#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
+#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
+#define GHC_USE_STD_FS
+#include <filesystem>
+namespace fs {
+using namespace std::filesystem;
+using ifstream = std::ifstream;
+using ofstream = std::ofstream;
+using fstream = std::fstream;
+}
+#endif
+#endif
+#ifndef GHC_USE_STD_FS
+//#define GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE
+#define GHC_FILESYSTEM_FWD
+#include <ghc/filesystem.hpp>
+namespace fs {
+using namespace ghc::filesystem;
+using ifstream = ghc::filesystem::ifstream;
+using ofstream = ghc::filesystem::ofstream;
+using fstream = ghc::filesystem::fstream;
+}
+#endif
+#endif // GHC_FILESYSTEM_STD_FWD_H
+
diff --git a/gulrak-filesystem/include/ghc/fs_std_impl.hpp b/gulrak-filesystem/include/ghc/fs_std_impl.hpp
new file mode 100644
index 0000000..7042edc
--- /dev/null
+++ b/gulrak-filesystem/include/ghc/fs_std_impl.hpp
@@ -0,0 +1,46 @@
+//---------------------------------------------------------------------------------------
+//
+// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14
+//
+//---------------------------------------------------------------------------------------
+//
+// Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+//---------------------------------------------------------------------------------------
+// fs_std_impl.hpp - The implementation header for the header/implementation seperated usage of
+// ghc::filesystem that does nothing if std::filesystem is detected.
+// This file can be used to hide the implementation of ghc::filesystem into a single cpp.
+// The cpp has to include this before including fs_std_fwd.hpp directly or via a different
+// header to work.
+//---------------------------------------------------------------------------------------
+#if defined(__APPLE__)
+#include <Availability.h>
+#endif
+#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
+#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
+#define GHC_USE_STD_FS
+#endif
+#endif
+#ifndef GHC_USE_STD_FS
+//#define GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE
+#define GHC_FILESYSTEM_IMPLEMENTATION
+#include <ghc/filesystem.hpp>
+#endif
diff --git a/gulrak-filesystem/test/CMakeLists.txt b/gulrak-filesystem/test/CMakeLists.txt
new file mode 100644
index 0000000..f9fdd18
--- /dev/null
+++ b/gulrak-filesystem/test/CMakeLists.txt
@@ -0,0 +1,91 @@
+
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")
+set(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS ON)
+include(ParseAndAddCatchTests)
+
+if(GHC_COVERAGE)
+ message("Generating test runner for coverage run...")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMCMAKE_EXE_LINKER_FLAGS} --coverage")
+ add_executable(filesystem_test filesystem_test.cpp catch.hpp)
+ if(MINGW)
+ target_compile_options(filesystem_test PUBLIC --coverage "-Wa,-mbig-obj")
+ else()
+ target_compile_options(filesystem_test PUBLIC --coverage)
+ endif()
+ target_link_libraries(filesystem_test PUBLIC ghc_filesystem --coverage)
+ if("cxx_std_17" IN_LIST GHC_FILESYSTEM_TEST_COMPILE_FEATURES)
+ AddTestExecutableWithStdCpp(17 filesystem_test.cpp catch.hpp)
+ endif()
+ if("cxx_std_20" IN_LIST GHC_FILESYSTEM_TEST_COMPILE_FEATURES)
+ AddTestExecutableWithStdCpp(20 filesystem_test.cpp catch.hpp)
+ endif()
+else()
+ message("Generating test runner for normal test...")
+ add_executable(filesystem_test filesystem_test.cpp catch.hpp)
+ target_link_libraries(filesystem_test ghc_filesystem)
+ target_compile_options(filesystem_test PRIVATE
+ $<$<BOOL:${EMSCRIPTEN}>:-s DISABLE_EXCEPTION_CATCHING=0>
+ $<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>>:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Werror>
+ $<$<CXX_COMPILER_ID:GNU>:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Wno-psabi -Werror>
+ $<$<CXX_COMPILER_ID:MSVC>:/WX>
+ $<$<BOOL:${CYGWIN}>:-Wa,-mbig-obj>)
+ if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
+ target_compile_definitions(filesystem_test PRIVATE _CRT_SECURE_NO_WARNINGS WIN32_LEAN_AND_MEAN NOMINMAX)
+ endif()
+ if(EMSCRIPTEN)
+ set_target_properties(filesystem_test PROPERTIES LINK_FLAGS "-g4 -s DISABLE_EXCEPTION_CATCHING=0 -s ALLOW_MEMORY_GROWTH=1")
+ endif()
+ ParseAndAddCatchTests(filesystem_test)
+ if(GHC_FILESYSTEM_BUILD_STD_TESTING)
+ AddExecutableWithStdFS(std_filesystem_test filesystem_test.cpp catch.hpp)
+ endif()
+ if(WIN32)
+ add_executable(filesystem_test_char filesystem_test.cpp catch.hpp)
+ target_link_libraries(filesystem_test_char ghc_filesystem)
+ target_compile_options(filesystem_test_char PRIVATE
+ $<$<CXX_COMPILER_ID:Clang>:-Wall -Wextra -Werror>
+ $<$<CXX_COMPILER_ID:GNU>:-Wall -Werror>
+ $<$<CXX_COMPILER_ID:MSVC>:/WX>)
+ if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
+ target_compile_definitions(filesystem_test_char PRIVATE _CRT_SECURE_NO_WARNINGS GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE)
+ else()
+ target_compile_definitions(filesystem_test_char PRIVATE GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE)
+ endif()
+ ParseAndAddCatchTests(filesystem_test_char)
+ endif()
+ if("cxx_std_17" IN_LIST GHC_FILESYSTEM_TEST_COMPILE_FEATURES)
+ AddTestExecutableWithStdCpp(17 filesystem_test.cpp catch.hpp)
+ endif()
+ if("cxx_std_20" IN_LIST GHC_FILESYSTEM_TEST_COMPILE_FEATURES)
+ AddTestExecutableWithStdCpp(20 filesystem_test.cpp catch.hpp)
+ endif()
+endif()
+
+add_executable(multifile_test multi1.cpp multi2.cpp catch.hpp)
+target_link_libraries(multifile_test ghc_filesystem)
+add_test(multifile_test multifile_test)
+
+add_executable(fwd_impl_test fwd_test.cpp impl_test.cpp)
+target_link_libraries(fwd_impl_test ghc_filesystem)
+target_compile_options(fwd_impl_test PRIVATE
+ $<$<BOOL:${EMSCRIPTEN}>:-s DISABLE_EXCEPTION_CATCHING=0>
+ $<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>>:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Werror>
+ $<$<CXX_COMPILER_ID:GNU>:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Wno-psabi -Werror>
+ $<$<CXX_COMPILER_ID:MSVC>:/WX>
+ $<$<BOOL:${CYGWIN}>:-Wa,-mbig-obj>)
+if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
+ target_compile_definitions(fwd_impl_test PRIVATE _CRT_SECURE_NO_WARNINGS WIN32_LEAN_AND_MEAN NOMINMAX)
+endif()
+add_test(fwd_impl_test fwd_impl_test)
+
+add_executable(exception exception.cpp)
+if(NOT MSVC)
+ target_compile_options(exception PRIVATE -fno-exceptions)
+endif()
+target_include_directories(exception PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../include)
+target_compile_options(exception PRIVATE
+ $<$<BOOL:${EMSCRIPTEN}>:-s DISABLE_EXCEPTION_CATCHING=0>
+ $<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>>:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Werror>
+ $<$<CXX_COMPILER_ID:GNU>:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Wno-psabi -Werror>
+ $<$<CXX_COMPILER_ID:MSVC>:/WX>
+ $<$<BOOL:${CYGWIN}>:-Wa,-mbig-obj>)
diff --git a/gulrak-filesystem/test/catch.hpp b/gulrak-filesystem/test/catch.hpp
new file mode 100644
index 0000000..b0fa641
--- /dev/null
+++ b/gulrak-filesystem/test/catch.hpp
@@ -0,0 +1,13922 @@
+/*
+ * Catch v2.4.0
+ * Generated: 2018-09-04 11:55:01.682061
+ * ----------------------------------------------------------
+ * This file has been merged from multiple headers. Please don't edit it directly
+ * Copyright (c) 2018 Two Blue Cubes Ltd. All rights reserved.
+ *
+ * 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)
+ */
+#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
+#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
+// start catch.hpp
+
+
+#define CATCH_VERSION_MAJOR 2
+#define CATCH_VERSION_MINOR 4
+#define CATCH_VERSION_PATCH 0
+
+#ifdef __clang__
+# pragma clang system_header
+#elif defined __GNUC__
+# pragma GCC system_header
+#endif
+
+// start catch_suppress_warnings.h
+
+#ifdef __clang__
+# ifdef __ICC // icpc defines the __clang__ macro
+# pragma warning(push)
+# pragma warning(disable: 161 1682)
+# else // __ICC
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wpadded"
+# pragma clang diagnostic ignored "-Wswitch-enum"
+# pragma clang diagnostic ignored "-Wcovered-switch-default"
+# endif
+#elif defined __GNUC__
+ // GCC likes to warn on REQUIREs, and we cannot suppress them
+ // locally because g++'s support for _Pragma is lacking in older,
+ // still supported, versions
+# pragma GCC diagnostic ignored "-Wparentheses"
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wunused-variable"
+# pragma GCC diagnostic ignored "-Wpadded"
+#endif
+// end catch_suppress_warnings.h
+#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER)
+# define CATCH_IMPL
+# define CATCH_CONFIG_ALL_PARTS
+#endif
+
+// In the impl file, we want to have access to all parts of the headers
+// Can also be used to sanely support PCHs
+#if defined(CATCH_CONFIG_ALL_PARTS)
+# define CATCH_CONFIG_EXTERNAL_INTERFACES
+# if defined(CATCH_CONFIG_DISABLE_MATCHERS)
+# undef CATCH_CONFIG_DISABLE_MATCHERS
+# endif
+# if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER)
+# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
+# endif
+#endif
+
+#if !defined(CATCH_CONFIG_IMPL_ONLY)
+// start catch_platform.h
+
+#ifdef __APPLE__
+# include <TargetConditionals.h>
+# if TARGET_OS_OSX == 1
+# define CATCH_PLATFORM_MAC
+# elif TARGET_OS_IPHONE == 1
+# define CATCH_PLATFORM_IPHONE
+# endif
+
+#elif defined(linux) || defined(__linux) || defined(__linux__)
+# define CATCH_PLATFORM_LINUX
+
+#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__)
+# define CATCH_PLATFORM_WINDOWS
+#endif
+
+// end catch_platform.h
+
+#ifdef CATCH_IMPL
+# ifndef CLARA_CONFIG_MAIN
+# define CLARA_CONFIG_MAIN_NOT_DEFINED
+# define CLARA_CONFIG_MAIN
+# endif
+#endif
+
+// start catch_user_interfaces.h
+
+namespace Catch {
+ unsigned int rngSeed();
+}
+
+// end catch_user_interfaces.h
+// start catch_tag_alias_autoregistrar.h
+
+// start catch_common.h
+
+// start catch_compiler_capabilities.h
+
+// Detect a number of compiler features - by compiler
+// The following features are defined:
+//
+// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported?
+// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported?
+// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported?
+// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled?
+// ****************
+// Note to maintainers: if new toggles are added please document them
+// in configuration.md, too
+// ****************
+
+// In general each macro has a _NO_<feature name> form
+// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature.
+// Many features, at point of detection, define an _INTERNAL_ macro, so they
+// can be combined, en-mass, with the _NO_ forms later.
+
+#ifdef __cplusplus
+
+# if __cplusplus >= 201402L
+# define CATCH_CPP14_OR_GREATER
+# endif
+
+# if __cplusplus >= 201703L
+# define CATCH_CPP17_OR_GREATER
+# endif
+
+#endif
+
+#if defined(CATCH_CPP17_OR_GREATER)
+# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
+#endif
+
+#ifdef __clang__
+
+# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ _Pragma( "clang diagnostic push" ) \
+ _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \
+ _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"")
+# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
+ _Pragma( "clang diagnostic pop" )
+
+# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
+ _Pragma( "clang diagnostic push" ) \
+ _Pragma( "clang diagnostic ignored \"-Wparentheses\"" )
+# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
+ _Pragma( "clang diagnostic pop" )
+
+# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
+ _Pragma( "clang diagnostic push" ) \
+ _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" )
+# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS \
+ _Pragma( "clang diagnostic pop" )
+
+#endif // __clang__
+
+////////////////////////////////////////////////////////////////////////////////
+// Assume that non-Windows platforms support posix signals by default
+#if !defined(CATCH_PLATFORM_WINDOWS)
+ #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// We know some environments not to support full POSIX signals
+#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__)
+ #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS
+#endif
+
+#ifdef __OS400__
+# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS
+# define CATCH_CONFIG_COLOUR_NONE
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Android somehow still does not support std::to_string
+#if defined(__ANDROID__)
+# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Not all Windows environments support SEH properly
+#if defined(__MINGW32__)
+# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// PS4
+#if defined(__ORBIS__)
+# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Cygwin
+#ifdef __CYGWIN__
+
+// Required for some versions of Cygwin to declare gettimeofday
+// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin
+# define _BSD_SOURCE
+
+#endif // __CYGWIN__
+
+////////////////////////////////////////////////////////////////////////////////
+// Visual C++
+#ifdef _MSC_VER
+
+# if _MSC_VER >= 1900 // Visual Studio 2015 or newer
+# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
+# endif
+
+// Universal Windows platform does not support SEH
+// Or console colours (or console at all...)
+# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
+# define CATCH_CONFIG_COLOUR_NONE
+# else
+# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH
+# endif
+
+#endif // _MSC_VER
+
+////////////////////////////////////////////////////////////////////////////////
+// Check if we are compiled with -fno-exceptions or equivalent
+#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND)
+# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// DJGPP
+#ifdef __DJGPP__
+# define CATCH_INTERNAL_CONFIG_NO_WCHAR
+#endif // __DJGPP__
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Use of __COUNTER__ is suppressed during code analysis in
+// CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly
+// handled by it.
+// Otherwise all supported compilers support COUNTER macro,
+// but user still might want to turn it off
+#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L )
+ #define CATCH_INTERNAL_CONFIG_COUNTER
+#endif
+
+#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER)
+# define CATCH_CONFIG_COUNTER
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH)
+# define CATCH_CONFIG_WINDOWS_SEH
+#endif
+// This is set by default, because we assume that unix compilers are posix-signal-compatible by default.
+#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS)
+# define CATCH_CONFIG_POSIX_SIGNALS
+#endif
+// This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions.
+#if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR)
+# define CATCH_CONFIG_WCHAR
+#endif
+
+#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING)
+# define CATCH_CONFIG_CPP11_TO_STRING
+#endif
+
+#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
+# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
+#endif
+
+#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
+# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE
+#endif
+
+#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE)
+# define CATCH_CONFIG_NEW_CAPTURE
+#endif
+
+#if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+# define CATCH_CONFIG_DISABLE_EXCEPTIONS
+#endif
+
+#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)
+# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
+# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS
+#endif
+#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS)
+# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
+# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
+#endif
+#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS)
+# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS
+# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS
+#endif
+
+#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+#define CATCH_TRY if ((true))
+#define CATCH_CATCH_ALL if ((false))
+#define CATCH_CATCH_ANON(type) if ((false))
+#else
+#define CATCH_TRY try
+#define CATCH_CATCH_ALL catch (...)
+#define CATCH_CATCH_ANON(type) catch (type)
+#endif
+
+// end catch_compiler_capabilities.h
+#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line
+#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line )
+#ifdef CATCH_CONFIG_COUNTER
+# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ )
+#else
+# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ )
+#endif
+
+#include <iosfwd>
+#include <string>
+#include <cstdint>
+
+namespace Catch {
+
+ struct CaseSensitive { enum Choice {
+ Yes,
+ No
+ }; };
+
+ class NonCopyable {
+ NonCopyable( NonCopyable const& ) = delete;
+ NonCopyable( NonCopyable && ) = delete;
+ NonCopyable& operator = ( NonCopyable const& ) = delete;
+ NonCopyable& operator = ( NonCopyable && ) = delete;
+
+ protected:
+ NonCopyable();
+ virtual ~NonCopyable();
+ };
+
+ struct SourceLineInfo {
+
+ SourceLineInfo() = delete;
+ SourceLineInfo( char const* _file, std::size_t _line ) noexcept
+ : file( _file ),
+ line( _line )
+ {}
+
+ SourceLineInfo( SourceLineInfo const& other ) = default;
+ SourceLineInfo( SourceLineInfo && ) = default;
+ SourceLineInfo& operator = ( SourceLineInfo const& ) = default;
+ SourceLineInfo& operator = ( SourceLineInfo && ) = default;
+
+ bool empty() const noexcept;
+ bool operator == ( SourceLineInfo const& other ) const noexcept;
+ bool operator < ( SourceLineInfo const& other ) const noexcept;
+
+ char const* file;
+ std::size_t line;
+ };
+
+ std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info );
+
+ // Use this in variadic streaming macros to allow
+ // >> +StreamEndStop
+ // as well as
+ // >> stuff +StreamEndStop
+ struct StreamEndStop {
+ std::string operator+() const;
+ };
+ template<typename T>
+ T const& operator + ( T const& value, StreamEndStop ) {
+ return value;
+ }
+}
+
+#define CATCH_INTERNAL_LINEINFO \
+ ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) )
+
+// end catch_common.h
+namespace Catch {
+
+ struct RegistrarForTagAliases {
+ RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo );
+ };
+
+} // end namespace Catch
+
+#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \
+ CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
+
+// end catch_tag_alias_autoregistrar.h
+// start catch_test_registry.h
+
+// start catch_interfaces_testcase.h
+
+#include <vector>
+#include <memory>
+
+namespace Catch {
+
+ class TestSpec;
+
+ struct ITestInvoker {
+ virtual void invoke () const = 0;
+ virtual ~ITestInvoker();
+ };
+
+ using ITestCasePtr = std::shared_ptr<ITestInvoker>;
+
+ class TestCase;
+ struct IConfig;
+
+ struct ITestCaseRegistry {
+ virtual ~ITestCaseRegistry();
+ virtual std::vector<TestCase> const& getAllTests() const = 0;
+ virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const = 0;
+ };
+
+ bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );
+ std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config );
+ std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config );
+
+}
+
+// end catch_interfaces_testcase.h
+// start catch_stringref.h
+
+#include <cstddef>
+#include <string>
+#include <iosfwd>
+
+namespace Catch {
+
+ class StringData;
+
+ /// A non-owning string class (similar to the forthcoming std::string_view)
+ /// Note that, because a StringRef may be a substring of another string,
+ /// it may not be null terminated. c_str() must return a null terminated
+ /// string, however, and so the StringRef will internally take ownership
+ /// (taking a copy), if necessary. In theory this ownership is not externally
+ /// visible - but it does mean (substring) StringRefs should not be shared between
+ /// threads.
+ class StringRef {
+ public:
+ using size_type = std::size_t;
+
+ private:
+ friend struct StringRefTestAccess;
+
+ char const* m_start;
+ size_type m_size;
+
+ char* m_data = nullptr;
+
+ void takeOwnership();
+
+ static constexpr char const* const s_empty = "";
+
+ public: // construction/ assignment
+ StringRef() noexcept
+ : StringRef( s_empty, 0 )
+ {}
+
+ StringRef( StringRef const& other ) noexcept
+ : m_start( other.m_start ),
+ m_size( other.m_size )
+ {}
+
+ StringRef( StringRef&& other ) noexcept
+ : m_start( other.m_start ),
+ m_size( other.m_size ),
+ m_data( other.m_data )
+ {
+ other.m_data = nullptr;
+ }
+
+ StringRef( char const* rawChars ) noexcept;
+
+ StringRef( char const* rawChars, size_type size ) noexcept
+ : m_start( rawChars ),
+ m_size( size )
+ {}
+
+ StringRef( std::string const& stdString ) noexcept
+ : m_start( stdString.c_str() ),
+ m_size( stdString.size() )
+ {}
+
+ ~StringRef() noexcept {
+ delete[] m_data;
+ }
+
+ auto operator = ( StringRef const &other ) noexcept -> StringRef& {
+ delete[] m_data;
+ m_data = nullptr;
+ m_start = other.m_start;
+ m_size = other.m_size;
+ return *this;
+ }
+
+ operator std::string() const;
+
+ void swap( StringRef& other ) noexcept;
+
+ public: // operators
+ auto operator == ( StringRef const& other ) const noexcept -> bool;
+ auto operator != ( StringRef const& other ) const noexcept -> bool;
+
+ auto operator[] ( size_type index ) const noexcept -> char;
+
+ public: // named queries
+ auto empty() const noexcept -> bool {
+ return m_size == 0;
+ }
+ auto size() const noexcept -> size_type {
+ return m_size;
+ }
+
+ auto numberOfCharacters() const noexcept -> size_type;
+ auto c_str() const -> char const*;
+
+ public: // substrings and searches
+ auto substr( size_type start, size_type size ) const noexcept -> StringRef;
+
+ // Returns the current start pointer.
+ // Note that the pointer can change when if the StringRef is a substring
+ auto currentData() const noexcept -> char const*;
+
+ private: // ownership queries - may not be consistent between calls
+ auto isOwned() const noexcept -> bool;
+ auto isSubstring() const noexcept -> bool;
+ };
+
+ auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string;
+ auto operator + ( StringRef const& lhs, char const* rhs ) -> std::string;
+ auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string;
+
+ auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&;
+ auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&;
+
+ inline auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef {
+ return StringRef( rawChars, size );
+ }
+
+} // namespace Catch
+
+inline auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef {
+ return Catch::StringRef( rawChars, size );
+}
+
+// end catch_stringref.h
+namespace Catch {
+
+template<typename C>
+class TestInvokerAsMethod : public ITestInvoker {
+ void (C::*m_testAsMethod)();
+public:
+ TestInvokerAsMethod( void (C::*testAsMethod)() ) noexcept : m_testAsMethod( testAsMethod ) {}
+
+ void invoke() const override {
+ C obj;
+ (obj.*m_testAsMethod)();
+ }
+};
+
+auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker*;
+
+template<typename C>
+auto makeTestInvoker( void (C::*testAsMethod)() ) noexcept -> ITestInvoker* {
+ return new(std::nothrow) TestInvokerAsMethod<C>( testAsMethod );
+}
+
+struct NameAndTags {
+ NameAndTags( StringRef const& name_ = StringRef(), StringRef const& tags_ = StringRef() ) noexcept;
+ StringRef name;
+ StringRef tags;
+};
+
+struct AutoReg : NonCopyable {
+ AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept;
+ ~AutoReg();
+};
+
+} // end namespace Catch
+
+#define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param)
+#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__
+#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__
+#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF
+
+#if defined(CATCH_CONFIG_DISABLE)
+ #define INTERNAL_CATCH_TESTCASE_NO_REGISTRATION( TestName, ... ) \
+ static void TestName()
+ #define INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \
+ namespace{ \
+ struct TestName : INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF ClassName) { \
+ void test(); \
+ }; \
+ } \
+ void TestName::test()
+
+#endif
+
+ ///////////////////////////////////////////////////////////////////////////////
+ #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \
+ static void TestName(); \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \
+ CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
+ static void TestName()
+ #define INTERNAL_CATCH_TESTCASE( ... ) \
+ INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ )
+
+ ///////////////////////////////////////////////////////////////////////////////
+ #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \
+ CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
+
+ ///////////////////////////////////////////////////////////////////////////////
+ #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ namespace{ \
+ struct TestName : INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF ClassName) { \
+ void test(); \
+ }; \
+ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
+ } \
+ CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
+ void TestName::test()
+ #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \
+ INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ )
+
+ ///////////////////////////////////////////////////////////////////////////////
+ #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
+ CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
+
+// end catch_test_registry.h
+// start catch_capture.hpp
+
+// start catch_assertionhandler.h
+
+// start catch_assertioninfo.h
+
+// start catch_result_type.h
+
+namespace Catch {
+
+ // ResultWas::OfType enum
+ struct ResultWas { enum OfType {
+ Unknown = -1,
+ Ok = 0,
+ Info = 1,
+ Warning = 2,
+
+ FailureBit = 0x10,
+
+ ExpressionFailed = FailureBit | 1,
+ ExplicitFailure = FailureBit | 2,
+
+ Exception = 0x100 | FailureBit,
+
+ ThrewException = Exception | 1,
+ DidntThrowException = Exception | 2,
+
+ FatalErrorCondition = 0x200 | FailureBit
+
+ }; };
+
+ bool isOk( ResultWas::OfType resultType );
+ bool isJustInfo( int flags );
+
+ // ResultDisposition::Flags enum
+ struct ResultDisposition { enum Flags {
+ Normal = 0x01,
+
+ ContinueOnFailure = 0x02, // Failures fail test, but execution continues
+ FalseTest = 0x04, // Prefix expression with !
+ SuppressFail = 0x08 // Failures are reported but do not fail the test
+ }; };
+
+ ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs );
+
+ bool shouldContinueOnFailure( int flags );
+ inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; }
+ bool shouldSuppressFailure( int flags );
+
+} // end namespace Catch
+
+// end catch_result_type.h
+namespace Catch {
+
+ struct AssertionInfo
+ {
+ StringRef macroName;
+ SourceLineInfo lineInfo;
+ StringRef capturedExpression;
+ ResultDisposition::Flags resultDisposition;
+
+ // We want to delete this constructor but a compiler bug in 4.8 means
+ // the struct is then treated as non-aggregate
+ //AssertionInfo() = delete;
+ };
+
+} // end namespace Catch
+
+// end catch_assertioninfo.h
+// start catch_decomposer.h
+
+// start catch_tostring.h
+
+#include <vector>
+#include <cstddef>
+#include <type_traits>
+#include <string>
+// start catch_stream.h
+
+#include <iosfwd>
+#include <cstddef>
+#include <ostream>
+
+namespace Catch {
+
+ std::ostream& cout();
+ std::ostream& cerr();
+ std::ostream& clog();
+
+ class StringRef;
+
+ struct IStream {
+ virtual ~IStream();
+ virtual std::ostream& stream() const = 0;
+ };
+
+ auto makeStream( StringRef const &filename ) -> IStream const*;
+
+ class ReusableStringStream {
+ std::size_t m_index;
+ std::ostream* m_oss;
+ public:
+ ReusableStringStream();
+ ~ReusableStringStream();
+
+ auto str() const -> std::string;
+
+ template<typename T>
+ auto operator << ( T const& value ) -> ReusableStringStream& {
+ *m_oss << value;
+ return *this;
+ }
+ auto get() -> std::ostream& { return *m_oss; }
+ };
+}
+
+// end catch_stream.h
+
+#ifdef __OBJC__
+// start catch_objc_arc.hpp
+
+#import <Foundation/Foundation.h>
+
+#ifdef __has_feature
+#define CATCH_ARC_ENABLED __has_feature(objc_arc)
+#else
+#define CATCH_ARC_ENABLED 0
+#endif
+
+void arcSafeRelease( NSObject* obj );
+id performOptionalSelector( id obj, SEL sel );
+
+#if !CATCH_ARC_ENABLED
+inline void arcSafeRelease( NSObject* obj ) {
+ [obj release];
+}
+inline id performOptionalSelector( id obj, SEL sel ) {
+ if( [obj respondsToSelector: sel] )
+ return [obj performSelector: sel];
+ return nil;
+}
+#define CATCH_UNSAFE_UNRETAINED
+#define CATCH_ARC_STRONG
+#else
+inline void arcSafeRelease( NSObject* ){}
+inline id performOptionalSelector( id obj, SEL sel ) {
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+#endif
+ if( [obj respondsToSelector: sel] )
+ return [obj performSelector: sel];
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+ return nil;
+}
+#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained
+#define CATCH_ARC_STRONG __strong
+#endif
+
+// end catch_objc_arc.hpp
+#endif
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable:4180) // We attempt to stream a function (address) by const&, which MSVC complains about but is harmless
+#endif
+
+// We need a dummy global operator<< so we can bring it into Catch namespace later
+struct Catch_global_namespace_dummy {};
+std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy);
+
+namespace Catch {
+ // Bring in operator<< from global namespace into Catch namespace
+ using ::operator<<;
+
+ namespace Detail {
+
+ extern const std::string unprintableString;
+
+ std::string rawMemoryToString( const void *object, std::size_t size );
+
+ template<typename T>
+ std::string rawMemoryToString( const T& object ) {
+ return rawMemoryToString( &object, sizeof(object) );
+ }
+
+ template<typename T>
+ class IsStreamInsertable {
+ template<typename SS, typename TT>
+ static auto test(int)
+ -> decltype(std::declval<SS&>() << std::declval<TT>(), std::true_type());
+
+ template<typename, typename>
+ static auto test(...)->std::false_type;
+
+ public:
+ static const bool value = decltype(test<std::ostream, const T&>(0))::value;
+ };
+
+ template<typename E>
+ std::string convertUnknownEnumToString( E e );
+
+ template<typename T>
+ typename std::enable_if<
+ !std::is_enum<T>::value && !std::is_base_of<std::exception, T>::value,
+ std::string>::type convertUnstreamable( T const& ) {
+ return Detail::unprintableString;
+ }
+ template<typename T>
+ typename std::enable_if<
+ !std::is_enum<T>::value && std::is_base_of<std::exception, T>::value,
+ std::string>::type convertUnstreamable(T const& ex) {
+ return ex.what();
+ }
+
+ template<typename T>
+ typename std::enable_if<
+ std::is_enum<T>::value
+ , std::string>::type convertUnstreamable( T const& value ) {
+ return convertUnknownEnumToString( value );
+ }
+
+#if defined(_MANAGED)
+ //! Convert a CLR string to a utf8 std::string
+ template<typename T>
+ std::string clrReferenceToString( T^ ref ) {
+ if (ref == nullptr)
+ return std::string("null");
+ auto bytes = System::Text::Encoding::UTF8->GetBytes(ref->ToString());
+ cli::pin_ptr<System::Byte> p = &bytes[0];
+ return std::string(reinterpret_cast<char const *>(p), bytes->Length);
+ }
+#endif
+
+ } // namespace Detail
+
+ // If we decide for C++14, change these to enable_if_ts
+ template <typename T, typename = void>
+ struct StringMaker {
+ template <typename Fake = T>
+ static
+ typename std::enable_if<::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type
+ convert(const Fake& value) {
+ ReusableStringStream rss;
+ // NB: call using the function-like syntax to avoid ambiguity with
+ // user-defined templated operator<< under clang.
+ rss.operator<<(value);
+ return rss.str();
+ }
+
+ template <typename Fake = T>
+ static
+ typename std::enable_if<!::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type
+ convert( const Fake& value ) {
+#if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER)
+ return Detail::convertUnstreamable(value);
+#else
+ return CATCH_CONFIG_FALLBACK_STRINGIFIER(value);
+#endif
+ }
+ };
+
+ namespace Detail {
+
+ // This function dispatches all stringification requests inside of Catch.
+ // Should be preferably called fully qualified, like ::Catch::Detail::stringify
+ template <typename T>
+ std::string stringify(const T& e) {
+ return ::Catch::StringMaker<typename std::remove_cv<typename std::remove_reference<T>::type>::type>::convert(e);
+ }
+
+ template<typename E>
+ std::string convertUnknownEnumToString( E e ) {
+ return ::Catch::Detail::stringify(static_cast<typename std::underlying_type<E>::type>(e));
+ }
+
+#if defined(_MANAGED)
+ template <typename T>
+ std::string stringify( T^ e ) {
+ return ::Catch::StringMaker<T^>::convert(e);
+ }
+#endif
+
+ } // namespace Detail
+
+ // Some predefined specializations
+
+ template<>
+ struct StringMaker<std::string> {
+ static std::string convert(const std::string& str);
+ };
+#ifdef CATCH_CONFIG_WCHAR
+ template<>
+ struct StringMaker<std::wstring> {
+ static std::string convert(const std::wstring& wstr);
+ };
+#endif
+
+ template<>
+ struct StringMaker<char const *> {
+ static std::string convert(char const * str);
+ };
+ template<>
+ struct StringMaker<char *> {
+ static std::string convert(char * str);
+ };
+
+#ifdef CATCH_CONFIG_WCHAR
+ template<>
+ struct StringMaker<wchar_t const *> {
+ static std::string convert(wchar_t const * str);
+ };
+ template<>
+ struct StringMaker<wchar_t *> {
+ static std::string convert(wchar_t * str);
+ };
+#endif
+
+ // TBD: Should we use `strnlen` to ensure that we don't go out of the buffer,
+ // while keeping string semantics?
+ template<int SZ>
+ struct StringMaker<char[SZ]> {
+ static std::string convert(char const* str) {
+ return ::Catch::Detail::stringify(std::string{ str });
+ }
+ };
+ template<int SZ>
+ struct StringMaker<signed char[SZ]> {
+ static std::string convert(signed char const* str) {
+ return ::Catch::Detail::stringify(std::string{ reinterpret_cast<char const *>(str) });
+ }
+ };
+ template<int SZ>
+ struct StringMaker<unsigned char[SZ]> {
+ static std::string convert(unsigned char const* str) {
+ return ::Catch::Detail::stringify(std::string{ reinterpret_cast<char const *>(str) });
+ }
+ };
+
+ template<>
+ struct StringMaker<int> {
+ static std::string convert(int value);
+ };
+ template<>
+ struct StringMaker<long> {
+ static std::string convert(long value);
+ };
+ template<>
+ struct StringMaker<long long> {
+ static std::string convert(long long value);
+ };
+ template<>
+ struct StringMaker<unsigned int> {
+ static std::string convert(unsigned int value);
+ };
+ template<>
+ struct StringMaker<unsigned long> {
+ static std::string convert(unsigned long value);
+ };
+ template<>
+ struct StringMaker<unsigned long long> {
+ static std::string convert(unsigned long long value);
+ };
+
+ template<>
+ struct StringMaker<bool> {
+ static std::string convert(bool b);
+ };
+
+ template<>
+ struct StringMaker<char> {
+ static std::string convert(char c);
+ };
+ template<>
+ struct StringMaker<signed char> {
+ static std::string convert(signed char c);
+ };
+ template<>
+ struct StringMaker<unsigned char> {
+ static std::string convert(unsigned char c);
+ };
+
+ template<>
+ struct StringMaker<std::nullptr_t> {
+ static std::string convert(std::nullptr_t);
+ };
+
+ template<>
+ struct StringMaker<float> {
+ static std::string convert(float value);
+ };
+ template<>
+ struct StringMaker<double> {
+ static std::string convert(double value);
+ };
+
+ template <typename T>
+ struct StringMaker<T*> {
+ template <typename U>
+ static std::string convert(U* p) {
+ if (p) {
+ return ::Catch::Detail::rawMemoryToString(p);
+ } else {
+ return "nullptr";
+ }
+ }
+ };
+
+ template <typename R, typename C>
+ struct StringMaker<R C::*> {
+ static std::string convert(R C::* p) {
+ if (p) {
+ return ::Catch::Detail::rawMemoryToString(p);
+ } else {
+ return "nullptr";
+ }
+ }
+ };
+
+#if defined(_MANAGED)
+ template <typename T>
+ struct StringMaker<T^> {
+ static std::string convert( T^ ref ) {
+ return ::Catch::Detail::clrReferenceToString(ref);
+ }
+ };
+#endif
+
+ namespace Detail {
+ template<typename InputIterator>
+ std::string rangeToString(InputIterator first, InputIterator last) {
+ ReusableStringStream rss;
+ rss << "{ ";
+ if (first != last) {
+ rss << ::Catch::Detail::stringify(*first);
+ for (++first; first != last; ++first)
+ rss << ", " << ::Catch::Detail::stringify(*first);
+ }
+ rss << " }";
+ return rss.str();
+ }
+ }
+
+#ifdef __OBJC__
+ template<>
+ struct StringMaker<NSString*> {
+ static std::string convert(NSString * nsstring) {
+ if (!nsstring)
+ return "nil";
+ return std::string("@") + [nsstring UTF8String];
+ }
+ };
+ template<>
+ struct StringMaker<NSObject*> {
+ static std::string convert(NSObject* nsObject) {
+ return ::Catch::Detail::stringify([nsObject description]);
+ }
+
+ };
+ namespace Detail {
+ inline std::string stringify( NSString* nsstring ) {
+ return StringMaker<NSString*>::convert( nsstring );
+ }
+
+ } // namespace Detail
+#endif // __OBJC__
+
+} // namespace Catch
+
+//////////////////////////////////////////////////////
+// Separate std-lib types stringification, so it can be selectively enabled
+// This means that we do not bring in
+
+#if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS)
+# define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
+# define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
+# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
+#endif
+
+// Separate std::pair specialization
+#if defined(CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER)
+#include <utility>
+namespace Catch {
+ template<typename T1, typename T2>
+ struct StringMaker<std::pair<T1, T2> > {
+ static std::string convert(const std::pair<T1, T2>& pair) {
+ ReusableStringStream rss;
+ rss << "{ "
+ << ::Catch::Detail::stringify(pair.first)
+ << ", "
+ << ::Catch::Detail::stringify(pair.second)
+ << " }";
+ return rss.str();
+ }
+ };
+}
+#endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
+
+// Separate std::tuple specialization
+#if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER)
+#include <tuple>
+namespace Catch {
+ namespace Detail {
+ template<
+ typename Tuple,
+ std::size_t N = 0,
+ bool = (N < std::tuple_size<Tuple>::value)
+ >
+ struct TupleElementPrinter {
+ static void print(const Tuple& tuple, std::ostream& os) {
+ os << (N ? ", " : " ")
+ << ::Catch::Detail::stringify(std::get<N>(tuple));
+ TupleElementPrinter<Tuple, N + 1>::print(tuple, os);
+ }
+ };
+
+ template<
+ typename Tuple,
+ std::size_t N
+ >
+ struct TupleElementPrinter<Tuple, N, false> {
+ static void print(const Tuple&, std::ostream&) {}
+ };
+
+ }
+
+ template<typename ...Types>
+ struct StringMaker<std::tuple<Types...>> {
+ static std::string convert(const std::tuple<Types...>& tuple) {
+ ReusableStringStream rss;
+ rss << '{';
+ Detail::TupleElementPrinter<std::tuple<Types...>>::print(tuple, rss.get());
+ rss << " }";
+ return rss.str();
+ }
+ };
+}
+#endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
+
+namespace Catch {
+ struct not_this_one {}; // Tag type for detecting which begin/ end are being selected
+
+ // Import begin/ end from std here so they are considered alongside the fallback (...) overloads in this namespace
+ using std::begin;
+ using std::end;
+
+ not_this_one begin( ... );
+ not_this_one end( ... );
+
+ template <typename T>
+ struct is_range {
+ static const bool value =
+ !std::is_same<decltype(begin(std::declval<T>())), not_this_one>::value &&
+ !std::is_same<decltype(end(std::declval<T>())), not_this_one>::value;
+ };
+
+#if defined(_MANAGED) // Managed types are never ranges
+ template <typename T>
+ struct is_range<T^> {
+ static const bool value = false;
+ };
+#endif
+
+ template<typename Range>
+ std::string rangeToString( Range const& range ) {
+ return ::Catch::Detail::rangeToString( begin( range ), end( range ) );
+ }
+
+ // Handle vector<bool> specially
+ template<typename Allocator>
+ std::string rangeToString( std::vector<bool, Allocator> const& v ) {
+ ReusableStringStream rss;
+ rss << "{ ";
+ bool first = true;
+ for( bool b : v ) {
+ if( first )
+ first = false;
+ else
+ rss << ", ";
+ rss << ::Catch::Detail::stringify( b );
+ }
+ rss << " }";
+ return rss.str();
+ }
+
+ template<typename R>
+ struct StringMaker<R, typename std::enable_if<is_range<R>::value && !::Catch::Detail::IsStreamInsertable<R>::value>::type> {
+ static std::string convert( R const& range ) {
+ return rangeToString( range );
+ }
+ };
+
+ template <typename T, int SZ>
+ struct StringMaker<T[SZ]> {
+ static std::string convert(T const(&arr)[SZ]) {
+ return rangeToString(arr);
+ }
+ };
+
+} // namespace Catch
+
+// Separate std::chrono::duration specialization
+#if defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER)
+#include <ctime>
+#include <ratio>
+#include <chrono>
+
+namespace Catch {
+
+template <class Ratio>
+struct ratio_string {
+ static std::string symbol();
+};
+
+template <class Ratio>
+std::string ratio_string<Ratio>::symbol() {
+ Catch::ReusableStringStream rss;
+ rss << '[' << Ratio::num << '/'
+ << Ratio::den << ']';
+ return rss.str();
+}
+template <>
+struct ratio_string<std::atto> {
+ static std::string symbol();
+};
+template <>
+struct ratio_string<std::femto> {
+ static std::string symbol();
+};
+template <>
+struct ratio_string<std::pico> {
+ static std::string symbol();
+};
+template <>
+struct ratio_string<std::nano> {
+ static std::string symbol();
+};
+template <>
+struct ratio_string<std::micro> {
+ static std::string symbol();
+};
+template <>
+struct ratio_string<std::milli> {
+ static std::string symbol();
+};
+
+ ////////////
+ // std::chrono::duration specializations
+ template<typename Value, typename Ratio>
+ struct StringMaker<std::chrono::duration<Value, Ratio>> {
+ static std::string convert(std::chrono::duration<Value, Ratio> const& duration) {
+ ReusableStringStream rss;
+ rss << duration.count() << ' ' << ratio_string<Ratio>::symbol() << 's';
+ return rss.str();
+ }
+ };
+ template<typename Value>
+ struct StringMaker<std::chrono::duration<Value, std::ratio<1>>> {
+ static std::string convert(std::chrono::duration<Value, std::ratio<1>> const& duration) {
+ ReusableStringStream rss;
+ rss << duration.count() << " s";
+ return rss.str();
+ }
+ };
+ template<typename Value>
+ struct StringMaker<std::chrono::duration<Value, std::ratio<60>>> {
+ static std::string convert(std::chrono::duration<Value, std::ratio<60>> const& duration) {
+ ReusableStringStream rss;
+ rss << duration.count() << " m";
+ return rss.str();
+ }
+ };
+ template<typename Value>
+ struct StringMaker<std::chrono::duration<Value, std::ratio<3600>>> {
+ static std::string convert(std::chrono::duration<Value, std::ratio<3600>> const& duration) {
+ ReusableStringStream rss;
+ rss << duration.count() << " h";
+ return rss.str();
+ }
+ };
+
+ ////////////
+ // std::chrono::time_point specialization
+ // Generic time_point cannot be specialized, only std::chrono::time_point<system_clock>
+ template<typename Clock, typename Duration>
+ struct StringMaker<std::chrono::time_point<Clock, Duration>> {
+ static std::string convert(std::chrono::time_point<Clock, Duration> const& time_point) {
+ return ::Catch::Detail::stringify(time_point.time_since_epoch()) + " since epoch";
+ }
+ };
+ // std::chrono::time_point<system_clock> specialization
+ template<typename Duration>
+ struct StringMaker<std::chrono::time_point<std::chrono::system_clock, Duration>> {
+ static std::string convert(std::chrono::time_point<std::chrono::system_clock, Duration> const& time_point) {
+ auto converted = std::chrono::system_clock::to_time_t(time_point);
+
+#ifdef _MSC_VER
+ std::tm timeInfo = {};
+ gmtime_s(&timeInfo, &converted);
+#else
+ std::tm* timeInfo = std::gmtime(&converted);
+#endif
+
+ auto const timeStampSize = sizeof("2017-01-16T17:06:45Z");
+ char timeStamp[timeStampSize];
+ const char * const fmt = "%Y-%m-%dT%H:%M:%SZ";
+
+#ifdef _MSC_VER
+ std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);
+#else
+ std::strftime(timeStamp, timeStampSize, fmt, timeInfo);
+#endif
+ return std::string(timeStamp);
+ }
+ };
+}
+#endif // CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+// end catch_tostring.h
+#include <iosfwd>
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable:4389) // '==' : signed/unsigned mismatch
+#pragma warning(disable:4018) // more "signed/unsigned mismatch"
+#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform)
+#pragma warning(disable:4180) // qualifier applied to function type has no meaning
+#endif
+
+namespace Catch {
+
+ struct ITransientExpression {
+ auto isBinaryExpression() const -> bool { return m_isBinaryExpression; }
+ auto getResult() const -> bool { return m_result; }
+ virtual void streamReconstructedExpression( std::ostream &os ) const = 0;
+
+ ITransientExpression( bool isBinaryExpression, bool result )
+ : m_isBinaryExpression( isBinaryExpression ),
+ m_result( result )
+ {}
+
+ // We don't actually need a virtual destructor, but many static analysers
+ // complain if it's not here :-(
+ virtual ~ITransientExpression();
+
+ bool m_isBinaryExpression;
+ bool m_result;
+
+ };
+
+ void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs );
+
+ template<typename LhsT, typename RhsT>
+ class BinaryExpr : public ITransientExpression {
+ LhsT m_lhs;
+ StringRef m_op;
+ RhsT m_rhs;
+
+ void streamReconstructedExpression( std::ostream &os ) const override {
+ formatReconstructedExpression
+ ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) );
+ }
+
+ public:
+ BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs )
+ : ITransientExpression{ true, comparisonResult },
+ m_lhs( lhs ),
+ m_op( op ),
+ m_rhs( rhs )
+ {}
+ };
+
+ template<typename LhsT>
+ class UnaryExpr : public ITransientExpression {
+ LhsT m_lhs;
+
+ void streamReconstructedExpression( std::ostream &os ) const override {
+ os << Catch::Detail::stringify( m_lhs );
+ }
+
+ public:
+ explicit UnaryExpr( LhsT lhs )
+ : ITransientExpression{ false, lhs ? true : false },
+ m_lhs( lhs )
+ {}
+ };
+
+ // Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int)
+ template<typename LhsT, typename RhsT>
+ auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return static_cast<bool>(lhs == rhs); }
+ template<typename T>
+ auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); }
+ template<typename T>
+ auto compareEqual( T* const& lhs, long rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); }
+ template<typename T>
+ auto compareEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; }
+ template<typename T>
+ auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; }
+
+ template<typename LhsT, typename RhsT>
+ auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return static_cast<bool>(lhs != rhs); }
+ template<typename T>
+ auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); }
+ template<typename T>
+ auto compareNotEqual( T* const& lhs, long rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); }
+ template<typename T>
+ auto compareNotEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) != rhs; }
+ template<typename T>
+ auto compareNotEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) != rhs; }
+
+ template<typename LhsT>
+ class ExprLhs {
+ LhsT m_lhs;
+ public:
+ explicit ExprLhs( LhsT lhs ) : m_lhs( lhs ) {}
+
+ template<typename RhsT>
+ auto operator == ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
+ return { compareEqual( m_lhs, rhs ), m_lhs, "==", rhs };
+ }
+ auto operator == ( bool rhs ) -> BinaryExpr<LhsT, bool> const {
+ return { m_lhs == rhs, m_lhs, "==", rhs };
+ }
+
+ template<typename RhsT>
+ auto operator != ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
+ return { compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs };
+ }
+ auto operator != ( bool rhs ) -> BinaryExpr<LhsT, bool> const {
+ return { m_lhs != rhs, m_lhs, "!=", rhs };
+ }
+
+ template<typename RhsT>
+ auto operator > ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
+ return { static_cast<bool>(m_lhs > rhs), m_lhs, ">", rhs };
+ }
+ template<typename RhsT>
+ auto operator < ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
+ return { static_cast<bool>(m_lhs < rhs), m_lhs, "<", rhs };
+ }
+ template<typename RhsT>
+ auto operator >= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
+ return { static_cast<bool>(m_lhs >= rhs), m_lhs, ">=", rhs };
+ }
+ template<typename RhsT>
+ auto operator <= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
+ return { static_cast<bool>(m_lhs <= rhs), m_lhs, "<=", rhs };
+ }
+
+ auto makeUnaryExpr() const -> UnaryExpr<LhsT> {
+ return UnaryExpr<LhsT>{ m_lhs };
+ }
+ };
+
+ void handleExpression( ITransientExpression const& expr );
+
+ template<typename T>
+ void handleExpression( ExprLhs<T> const& expr ) {
+ handleExpression( expr.makeUnaryExpr() );
+ }
+
+ struct Decomposer {
+ template<typename T>
+ auto operator <= ( T const& lhs ) -> ExprLhs<T const&> {
+ return ExprLhs<T const&>{ lhs };
+ }
+
+ auto operator <=( bool value ) -> ExprLhs<bool> {
+ return ExprLhs<bool>{ value };
+ }
+ };
+
+} // end namespace Catch
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+// end catch_decomposer.h
+// start catch_interfaces_capture.h
+
+#include <string>
+
+namespace Catch {
+
+ class AssertionResult;
+ struct AssertionInfo;
+ struct SectionInfo;
+ struct SectionEndInfo;
+ struct MessageInfo;
+ struct Counts;
+ struct BenchmarkInfo;
+ struct BenchmarkStats;
+ struct AssertionReaction;
+ struct SourceLineInfo;
+
+ struct ITransientExpression;
+ struct IGeneratorTracker;
+
+ struct IResultCapture {
+
+ virtual ~IResultCapture();
+
+ virtual bool sectionStarted( SectionInfo const& sectionInfo,
+ Counts& assertions ) = 0;
+ virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0;
+ virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0;
+
+ virtual auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0;
+
+ virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0;
+ virtual void benchmarkEnded( BenchmarkStats const& stats ) = 0;
+
+ virtual void pushScopedMessage( MessageInfo const& message ) = 0;
+ virtual void popScopedMessage( MessageInfo const& message ) = 0;
+
+ virtual void handleFatalErrorCondition( StringRef message ) = 0;
+
+ virtual void handleExpr
+ ( AssertionInfo const& info,
+ ITransientExpression const& expr,
+ AssertionReaction& reaction ) = 0;
+ virtual void handleMessage
+ ( AssertionInfo const& info,
+ ResultWas::OfType resultType,
+ StringRef const& message,
+ AssertionReaction& reaction ) = 0;
+ virtual void handleUnexpectedExceptionNotThrown
+ ( AssertionInfo const& info,
+ AssertionReaction& reaction ) = 0;
+ virtual void handleUnexpectedInflightException
+ ( AssertionInfo const& info,
+ std::string const& message,
+ AssertionReaction& reaction ) = 0;
+ virtual void handleIncomplete
+ ( AssertionInfo const& info ) = 0;
+ virtual void handleNonExpr
+ ( AssertionInfo const &info,
+ ResultWas::OfType resultType,
+ AssertionReaction &reaction ) = 0;
+
+ virtual bool lastAssertionPassed() = 0;
+ virtual void assertionPassed() = 0;
+
+ // Deprecated, do not use:
+ virtual std::string getCurrentTestName() const = 0;
+ virtual const AssertionResult* getLastResult() const = 0;
+ virtual void exceptionEarlyReported() = 0;
+ };
+
+ IResultCapture& getResultCapture();
+}
+
+// end catch_interfaces_capture.h
+namespace Catch {
+
+ struct TestFailureException{};
+ struct AssertionResultData;
+ struct IResultCapture;
+ class RunContext;
+
+ class LazyExpression {
+ friend class AssertionHandler;
+ friend struct AssertionStats;
+ friend class RunContext;
+
+ ITransientExpression const* m_transientExpression = nullptr;
+ bool m_isNegated;
+ public:
+ LazyExpression( bool isNegated );
+ LazyExpression( LazyExpression const& other );
+ LazyExpression& operator = ( LazyExpression const& ) = delete;
+
+ explicit operator bool() const;
+
+ friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&;
+ };
+
+ struct AssertionReaction {
+ bool shouldDebugBreak = false;
+ bool shouldThrow = false;
+ };
+
+ class AssertionHandler {
+ AssertionInfo m_assertionInfo;
+ AssertionReaction m_reaction;
+ bool m_completed = false;
+ IResultCapture& m_resultCapture;
+
+ public:
+ AssertionHandler
+ ( StringRef const& macroName,
+ SourceLineInfo const& lineInfo,
+ StringRef capturedExpression,
+ ResultDisposition::Flags resultDisposition );
+ ~AssertionHandler() {
+ if ( !m_completed ) {
+ m_resultCapture.handleIncomplete( m_assertionInfo );
+ }
+ }
+
+ template<typename T>
+ void handleExpr( ExprLhs<T> const& expr ) {
+ handleExpr( expr.makeUnaryExpr() );
+ }
+ void handleExpr( ITransientExpression const& expr );
+
+ void handleMessage(ResultWas::OfType resultType, StringRef const& message);
+
+ void handleExceptionThrownAsExpected();
+ void handleUnexpectedExceptionNotThrown();
+ void handleExceptionNotThrownAsExpected();
+ void handleThrowingCallSkipped();
+ void handleUnexpectedInflightException();
+
+ void complete();
+ void setCompleted();
+
+ // query
+ auto allowThrows() const -> bool;
+ };
+
+ void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString );
+
+} // namespace Catch
+
+// end catch_assertionhandler.h
+// start catch_message.h
+
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+ struct MessageInfo {
+ MessageInfo( StringRef const& _macroName,
+ SourceLineInfo const& _lineInfo,
+ ResultWas::OfType _type );
+
+ StringRef macroName;
+ std::string message;
+ SourceLineInfo lineInfo;
+ ResultWas::OfType type;
+ unsigned int sequence;
+
+ bool operator == ( MessageInfo const& other ) const;
+ bool operator < ( MessageInfo const& other ) const;
+ private:
+ static unsigned int globalCount;
+ };
+
+ struct MessageStream {
+
+ template<typename T>
+ MessageStream& operator << ( T const& value ) {
+ m_stream << value;
+ return *this;
+ }
+
+ ReusableStringStream m_stream;
+ };
+
+ struct MessageBuilder : MessageStream {
+ MessageBuilder( StringRef const& macroName,
+ SourceLineInfo const& lineInfo,
+ ResultWas::OfType type );
+
+ template<typename T>
+ MessageBuilder& operator << ( T const& value ) {
+ m_stream << value;
+ return *this;
+ }
+
+ MessageInfo m_info;
+ };
+
+ class ScopedMessage {
+ public:
+ explicit ScopedMessage( MessageBuilder const& builder );
+ ~ScopedMessage();
+
+ MessageInfo m_info;
+ };
+
+ class Capturer {
+ std::vector<MessageInfo> m_messages;
+ IResultCapture& m_resultCapture = getResultCapture();
+ size_t m_captured = 0;
+ public:
+ Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names );
+ ~Capturer();
+
+ void captureValue( size_t index, StringRef value );
+
+ template<typename T>
+ void captureValues( size_t index, T&& value ) {
+ captureValue( index, Catch::Detail::stringify( value ) );
+ }
+
+ template<typename T, typename... Ts>
+ void captureValues( size_t index, T&& value, Ts&&... values ) {
+ captureValues( index, value );
+ captureValues( index+1, values... );
+ }
+ };
+
+} // end namespace Catch
+
+// end catch_message.h
+#if !defined(CATCH_CONFIG_DISABLE)
+
+#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION)
+ #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__
+#else
+ #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"
+#endif
+
+#if defined(CATCH_CONFIG_FAST_COMPILE) || defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+
+///////////////////////////////////////////////////////////////////////////////
+// Another way to speed-up compilation is to omit local try-catch for REQUIRE*
+// macros.
+#define INTERNAL_CATCH_TRY
+#define INTERNAL_CATCH_CATCH( capturer )
+
+#else // CATCH_CONFIG_FAST_COMPILE
+
+#define INTERNAL_CATCH_TRY try
+#define INTERNAL_CATCH_CATCH( handler ) catch(...) { handler.handleUnexpectedInflightException(); }
+
+#endif
+
+#define INTERNAL_CATCH_REACT( handler ) handler.complete();
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \
+ do { \
+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
+ INTERNAL_CATCH_TRY { \
+ CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
+ catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \
+ CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
+ } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
+ INTERNAL_CATCH_REACT( catchAssertionHandler ) \
+ } while( (void)0, false && static_cast<bool>( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look
+ // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \
+ INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \
+ if( Catch::getResultCapture().lastAssertionPassed() )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, ... ) \
+ INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \
+ if( !Catch::getResultCapture().lastAssertionPassed() )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \
+ do { \
+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
+ try { \
+ static_cast<void>(__VA_ARGS__); \
+ catchAssertionHandler.handleExceptionNotThrownAsExpected(); \
+ } \
+ catch( ... ) { \
+ catchAssertionHandler.handleUnexpectedInflightException(); \
+ } \
+ INTERNAL_CATCH_REACT( catchAssertionHandler ) \
+ } while( false )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \
+ do { \
+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \
+ if( catchAssertionHandler.allowThrows() ) \
+ try { \
+ static_cast<void>(__VA_ARGS__); \
+ catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
+ } \
+ catch( ... ) { \
+ catchAssertionHandler.handleExceptionThrownAsExpected(); \
+ } \
+ else \
+ catchAssertionHandler.handleThrowingCallSkipped(); \
+ INTERNAL_CATCH_REACT( catchAssertionHandler ) \
+ } while( false )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \
+ do { \
+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \
+ if( catchAssertionHandler.allowThrows() ) \
+ try { \
+ static_cast<void>(expr); \
+ catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
+ } \
+ catch( exceptionType const& ) { \
+ catchAssertionHandler.handleExceptionThrownAsExpected(); \
+ } \
+ catch( ... ) { \
+ catchAssertionHandler.handleUnexpectedInflightException(); \
+ } \
+ else \
+ catchAssertionHandler.handleThrowingCallSkipped(); \
+ INTERNAL_CATCH_REACT( catchAssertionHandler ) \
+ } while( false )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \
+ do { \
+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), resultDisposition ); \
+ catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \
+ INTERNAL_CATCH_REACT( catchAssertionHandler ) \
+ } while( false )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \
+ auto varName = Catch::Capturer( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info, #__VA_ARGS__ ); \
+ varName.captureValues( 0, __VA_ARGS__ )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_INFO( macroName, log ) \
+ Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log );
+
+///////////////////////////////////////////////////////////////////////////////
+// Although this is matcher-based, it can be used with just a string
+#define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \
+ do { \
+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
+ if( catchAssertionHandler.allowThrows() ) \
+ try { \
+ static_cast<void>(__VA_ARGS__); \
+ catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
+ } \
+ catch( ... ) { \
+ Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher##_catch_sr ); \
+ } \
+ else \
+ catchAssertionHandler.handleThrowingCallSkipped(); \
+ INTERNAL_CATCH_REACT( catchAssertionHandler ) \
+ } while( false )
+
+#endif // CATCH_CONFIG_DISABLE
+
+// end catch_capture.hpp
+// start catch_section.h
+
+// start catch_section_info.h
+
+// start catch_totals.h
+
+#include <cstddef>
+
+namespace Catch {
+
+ struct Counts {
+ Counts operator - ( Counts const& other ) const;
+ Counts& operator += ( Counts const& other );
+
+ std::size_t total() const;
+ bool allPassed() const;
+ bool allOk() const;
+
+ std::size_t passed = 0;
+ std::size_t failed = 0;
+ std::size_t failedButOk = 0;
+ };
+
+ struct Totals {
+
+ Totals operator - ( Totals const& other ) const;
+ Totals& operator += ( Totals const& other );
+
+ Totals delta( Totals const& prevTotals ) const;
+
+ int error = 0;
+ Counts assertions;
+ Counts testCases;
+ };
+}
+
+// end catch_totals.h
+#include <string>
+
+namespace Catch {
+
+ struct SectionInfo {
+ SectionInfo
+ ( SourceLineInfo const& _lineInfo,
+ std::string const& _name );
+
+ // Deprecated
+ SectionInfo
+ ( SourceLineInfo const& _lineInfo,
+ std::string const& _name,
+ std::string const& ) : SectionInfo( _lineInfo, _name ) {}
+
+ std::string name;
+ std::string description; // !Deprecated: this will always be empty
+ SourceLineInfo lineInfo;
+ };
+
+ struct SectionEndInfo {
+ SectionInfo sectionInfo;
+ Counts prevAssertions;
+ double durationInSeconds;
+ };
+
+} // end namespace Catch
+
+// end catch_section_info.h
+// start catch_timer.h
+
+#include <cstdint>
+
+namespace Catch {
+
+ auto getCurrentNanosecondsSinceEpoch() -> uint64_t;
+ auto getEstimatedClockResolution() -> uint64_t;
+
+ class Timer {
+ uint64_t m_nanoseconds = 0;
+ public:
+ void start();
+ auto getElapsedNanoseconds() const -> uint64_t;
+ auto getElapsedMicroseconds() const -> uint64_t;
+ auto getElapsedMilliseconds() const -> unsigned int;
+ auto getElapsedSeconds() const -> double;
+ };
+
+} // namespace Catch
+
+// end catch_timer.h
+#include <string>
+
+namespace Catch {
+
+ class Section : NonCopyable {
+ public:
+ Section( SectionInfo const& info );
+ ~Section();
+
+ // This indicates whether the section should be executed or not
+ explicit operator bool() const;
+
+ private:
+ SectionInfo m_info;
+
+ std::string m_name;
+ Counts m_assertions;
+ bool m_sectionIncluded;
+ Timer m_timer;
+ };
+
+} // end namespace Catch
+
+#define INTERNAL_CATCH_SECTION( ... ) \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
+ if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \
+ CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS
+
+#define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
+ if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, (Catch::ReusableStringStream() << __VA_ARGS__).str() ) ) \
+ CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS
+
+// end catch_section.h
+// start catch_benchmark.h
+
+#include <cstdint>
+#include <string>
+
+namespace Catch {
+
+ class BenchmarkLooper {
+
+ std::string m_name;
+ std::size_t m_count = 0;
+ std::size_t m_iterationsToRun = 1;
+ uint64_t m_resolution;
+ Timer m_timer;
+
+ static auto getResolution() -> uint64_t;
+ public:
+ // Keep most of this inline as it's on the code path that is being timed
+ BenchmarkLooper( StringRef name )
+ : m_name( name ),
+ m_resolution( getResolution() )
+ {
+ reportStart();
+ m_timer.start();
+ }
+
+ explicit operator bool() {
+ if( m_count < m_iterationsToRun )
+ return true;
+ return needsMoreIterations();
+ }
+
+ void increment() {
+ ++m_count;
+ }
+
+ void reportStart();
+ auto needsMoreIterations() -> bool;
+ };
+
+} // end namespace Catch
+
+#define BENCHMARK( name ) \
+ for( Catch::BenchmarkLooper looper( name ); looper; looper.increment() )
+
+// end catch_benchmark.h
+// start catch_interfaces_exception.h
+
+// start catch_interfaces_registry_hub.h
+
+#include <string>
+#include <memory>
+
+namespace Catch {
+
+ class TestCase;
+ struct ITestCaseRegistry;
+ struct IExceptionTranslatorRegistry;
+ struct IExceptionTranslator;
+ struct IReporterRegistry;
+ struct IReporterFactory;
+ struct ITagAliasRegistry;
+ class StartupExceptionRegistry;
+
+ using IReporterFactoryPtr = std::shared_ptr<IReporterFactory>;
+
+ struct IRegistryHub {
+ virtual ~IRegistryHub();
+
+ virtual IReporterRegistry const& getReporterRegistry() const = 0;
+ virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
+ virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0;
+
+ virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0;
+
+ virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0;
+ };
+
+ struct IMutableRegistryHub {
+ virtual ~IMutableRegistryHub();
+ virtual void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) = 0;
+ virtual void registerListener( IReporterFactoryPtr const& factory ) = 0;
+ virtual void registerTest( TestCase const& testInfo ) = 0;
+ virtual void registerTranslator( const IExceptionTranslator* translator ) = 0;
+ virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0;
+ virtual void registerStartupException() noexcept = 0;
+ };
+
+ IRegistryHub const& getRegistryHub();
+ IMutableRegistryHub& getMutableRegistryHub();
+ void cleanUp();
+ std::string translateActiveException();
+
+}
+
+// end catch_interfaces_registry_hub.h
+#if defined(CATCH_CONFIG_DISABLE)
+ #define INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( translatorName, signature) \
+ static std::string translatorName( signature )
+#endif
+
+#include <exception>
+#include <string>
+#include <vector>
+
+namespace Catch {
+ using exceptionTranslateFunction = std::string(*)();
+
+ struct IExceptionTranslator;
+ using ExceptionTranslators = std::vector<std::unique_ptr<IExceptionTranslator const>>;
+
+ struct IExceptionTranslator {
+ virtual ~IExceptionTranslator();
+ virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0;
+ };
+
+ struct IExceptionTranslatorRegistry {
+ virtual ~IExceptionTranslatorRegistry();
+
+ virtual std::string translateActiveException() const = 0;
+ };
+
+ class ExceptionTranslatorRegistrar {
+ template<typename T>
+ class ExceptionTranslator : public IExceptionTranslator {
+ public:
+
+ ExceptionTranslator( std::string(*translateFunction)( T& ) )
+ : m_translateFunction( translateFunction )
+ {}
+
+ std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override {
+ try {
+ if( it == itEnd )
+ std::rethrow_exception(std::current_exception());
+ else
+ return (*it)->translate( it+1, itEnd );
+ }
+ catch( T& ex ) {
+ return m_translateFunction( ex );
+ }
+ }
+
+ protected:
+ std::string(*m_translateFunction)( T& );
+ };
+
+ public:
+ template<typename T>
+ ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) {
+ getMutableRegistryHub().registerTranslator
+ ( new ExceptionTranslator<T>( translateFunction ) );
+ }
+ };
+}
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \
+ static std::string translatorName( signature ); \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \
+ CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
+ static std::string translatorName( signature )
+
+#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
+
+// end catch_interfaces_exception.h
+// start catch_approx.h
+
+#include <type_traits>
+
+namespace Catch {
+namespace Detail {
+
+ class Approx {
+ private:
+ bool equalityComparisonImpl(double other) const;
+ // Validates the new margin (margin >= 0)
+ // out-of-line to avoid including stdexcept in the header
+ void setMargin(double margin);
+ // Validates the new epsilon (0 < epsilon < 1)
+ // out-of-line to avoid including stdexcept in the header
+ void setEpsilon(double epsilon);
+
+ public:
+ explicit Approx ( double value );
+
+ static Approx custom();
+
+ Approx operator-() const;
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ Approx operator()( T const& value ) {
+ Approx approx( static_cast<double>(value) );
+ approx.m_epsilon = m_epsilon;
+ approx.m_margin = m_margin;
+ approx.m_scale = m_scale;
+ return approx;
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ explicit Approx( T const& value ): Approx(static_cast<double>(value))
+ {}
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ friend bool operator == ( const T& lhs, Approx const& rhs ) {
+ auto lhs_v = static_cast<double>(lhs);
+ return rhs.equalityComparisonImpl(lhs_v);
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ friend bool operator == ( Approx const& lhs, const T& rhs ) {
+ return operator==( rhs, lhs );
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ friend bool operator != ( T const& lhs, Approx const& rhs ) {
+ return !operator==( lhs, rhs );
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ friend bool operator != ( Approx const& lhs, T const& rhs ) {
+ return !operator==( rhs, lhs );
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ friend bool operator <= ( T const& lhs, Approx const& rhs ) {
+ return static_cast<double>(lhs) < rhs.m_value || lhs == rhs;
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ friend bool operator <= ( Approx const& lhs, T const& rhs ) {
+ return lhs.m_value < static_cast<double>(rhs) || lhs == rhs;
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ friend bool operator >= ( T const& lhs, Approx const& rhs ) {
+ return static_cast<double>(lhs) > rhs.m_value || lhs == rhs;
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ friend bool operator >= ( Approx const& lhs, T const& rhs ) {
+ return lhs.m_value > static_cast<double>(rhs) || lhs == rhs;
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ Approx& epsilon( T const& newEpsilon ) {
+ double epsilonAsDouble = static_cast<double>(newEpsilon);
+ setEpsilon(epsilonAsDouble);
+ return *this;
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ Approx& margin( T const& newMargin ) {
+ double marginAsDouble = static_cast<double>(newMargin);
+ setMargin(marginAsDouble);
+ return *this;
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ Approx& scale( T const& newScale ) {
+ m_scale = static_cast<double>(newScale);
+ return *this;
+ }
+
+ std::string toString() const;
+
+ private:
+ double m_epsilon;
+ double m_margin;
+ double m_scale;
+ double m_value;
+ };
+} // end namespace Detail
+
+namespace literals {
+ Detail::Approx operator "" _a(long double val);
+ Detail::Approx operator "" _a(unsigned long long val);
+} // end namespace literals
+
+template<>
+struct StringMaker<Catch::Detail::Approx> {
+ static std::string convert(Catch::Detail::Approx const& value);
+};
+
+} // end namespace Catch
+
+// end catch_approx.h
+// start catch_string_manip.h
+
+#include <string>
+#include <iosfwd>
+
+namespace Catch {
+
+ bool startsWith( std::string const& s, std::string const& prefix );
+ bool startsWith( std::string const& s, char prefix );
+ bool endsWith( std::string const& s, std::string const& suffix );
+ bool endsWith( std::string const& s, char suffix );
+ bool contains( std::string const& s, std::string const& infix );
+ void toLowerInPlace( std::string& s );
+ std::string toLower( std::string const& s );
+ std::string trim( std::string const& str );
+ bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis );
+
+ struct pluralise {
+ pluralise( std::size_t count, std::string const& label );
+
+ friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser );
+
+ std::size_t m_count;
+ std::string m_label;
+ };
+}
+
+// end catch_string_manip.h
+#ifndef CATCH_CONFIG_DISABLE_MATCHERS
+// start catch_capture_matchers.h
+
+// start catch_matchers.h
+
+#include <string>
+#include <vector>
+
+namespace Catch {
+namespace Matchers {
+ namespace Impl {
+
+ template<typename ArgT> struct MatchAllOf;
+ template<typename ArgT> struct MatchAnyOf;
+ template<typename ArgT> struct MatchNotOf;
+
+ class MatcherUntypedBase {
+ public:
+ MatcherUntypedBase() = default;
+ MatcherUntypedBase ( MatcherUntypedBase const& ) = default;
+ MatcherUntypedBase& operator = ( MatcherUntypedBase const& ) = delete;
+ std::string toString() const;
+
+ protected:
+ virtual ~MatcherUntypedBase();
+ virtual std::string describe() const = 0;
+ mutable std::string m_cachedToString;
+ };
+
+#ifdef __clang__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wnon-virtual-dtor"
+#endif
+
+ template<typename ObjectT>
+ struct MatcherMethod {
+ virtual bool match( ObjectT const& arg ) const = 0;
+ };
+ template<typename PtrT>
+ struct MatcherMethod<PtrT*> {
+ virtual bool match( PtrT* arg ) const = 0;
+ };
+
+#ifdef __clang__
+# pragma clang diagnostic pop
+#endif
+
+ template<typename T>
+ struct MatcherBase : MatcherUntypedBase, MatcherMethod<T> {
+
+ MatchAllOf<T> operator && ( MatcherBase const& other ) const;
+ MatchAnyOf<T> operator || ( MatcherBase const& other ) const;
+ MatchNotOf<T> operator ! () const;
+ };
+
+ template<typename ArgT>
+ struct MatchAllOf : MatcherBase<ArgT> {
+ bool match( ArgT const& arg ) const override {
+ for( auto matcher : m_matchers ) {
+ if (!matcher->match(arg))
+ return false;
+ }
+ return true;
+ }
+ std::string describe() const override {
+ std::string description;
+ description.reserve( 4 + m_matchers.size()*32 );
+ description += "( ";
+ bool first = true;
+ for( auto matcher : m_matchers ) {
+ if( first )
+ first = false;
+ else
+ description += " and ";
+ description += matcher->toString();
+ }
+ description += " )";
+ return description;
+ }
+
+ MatchAllOf<ArgT>& operator && ( MatcherBase<ArgT> const& other ) {
+ m_matchers.push_back( &other );
+ return *this;
+ }
+
+ std::vector<MatcherBase<ArgT> const*> m_matchers;
+ };
+ template<typename ArgT>
+ struct MatchAnyOf : MatcherBase<ArgT> {
+
+ bool match( ArgT const& arg ) const override {
+ for( auto matcher : m_matchers ) {
+ if (matcher->match(arg))
+ return true;
+ }
+ return false;
+ }
+ std::string describe() const override {
+ std::string description;
+ description.reserve( 4 + m_matchers.size()*32 );
+ description += "( ";
+ bool first = true;
+ for( auto matcher : m_matchers ) {
+ if( first )
+ first = false;
+ else
+ description += " or ";
+ description += matcher->toString();
+ }
+ description += " )";
+ return description;
+ }
+
+ MatchAnyOf<ArgT>& operator || ( MatcherBase<ArgT> const& other ) {
+ m_matchers.push_back( &other );
+ return *this;
+ }
+
+ std::vector<MatcherBase<ArgT> const*> m_matchers;
+ };
+
+ template<typename ArgT>
+ struct MatchNotOf : MatcherBase<ArgT> {
+
+ MatchNotOf( MatcherBase<ArgT> const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {}
+
+ bool match( ArgT const& arg ) const override {
+ return !m_underlyingMatcher.match( arg );
+ }
+
+ std::string describe() const override {
+ return "not " + m_underlyingMatcher.toString();
+ }
+ MatcherBase<ArgT> const& m_underlyingMatcher;
+ };
+
+ template<typename T>
+ MatchAllOf<T> MatcherBase<T>::operator && ( MatcherBase const& other ) const {
+ return MatchAllOf<T>() && *this && other;
+ }
+ template<typename T>
+ MatchAnyOf<T> MatcherBase<T>::operator || ( MatcherBase const& other ) const {
+ return MatchAnyOf<T>() || *this || other;
+ }
+ template<typename T>
+ MatchNotOf<T> MatcherBase<T>::operator ! () const {
+ return MatchNotOf<T>( *this );
+ }
+
+ } // namespace Impl
+
+} // namespace Matchers
+
+using namespace Matchers;
+using Matchers::Impl::MatcherBase;
+
+} // namespace Catch
+
+// end catch_matchers.h
+// start catch_matchers_floating.h
+
+#include <type_traits>
+#include <cmath>
+
+namespace Catch {
+namespace Matchers {
+
+ namespace Floating {
+
+ enum class FloatingPointKind : uint8_t;
+
+ struct WithinAbsMatcher : MatcherBase<double> {
+ WithinAbsMatcher(double target, double margin);
+ bool match(double const& matchee) const override;
+ std::string describe() const override;
+ private:
+ double m_target;
+ double m_margin;
+ };
+
+ struct WithinUlpsMatcher : MatcherBase<double> {
+ WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType);
+ bool match(double const& matchee) const override;
+ std::string describe() const override;
+ private:
+ double m_target;
+ int m_ulps;
+ FloatingPointKind m_type;
+ };
+
+ } // namespace Floating
+
+ // The following functions create the actual matcher objects.
+ // This allows the types to be inferred
+ Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff);
+ Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff);
+ Floating::WithinAbsMatcher WithinAbs(double target, double margin);
+
+} // namespace Matchers
+} // namespace Catch
+
+// end catch_matchers_floating.h
+// start catch_matchers_generic.hpp
+
+#include <functional>
+#include <string>
+
+namespace Catch {
+namespace Matchers {
+namespace Generic {
+
+namespace Detail {
+ std::string finalizeDescription(const std::string& desc);
+}
+
+template <typename T>
+class PredicateMatcher : public MatcherBase<T> {
+ std::function<bool(T const&)> m_predicate;
+ std::string m_description;
+public:
+
+ PredicateMatcher(std::function<bool(T const&)> const& elem, std::string const& descr)
+ :m_predicate(std::move(elem)),
+ m_description(Detail::finalizeDescription(descr))
+ {}
+
+ bool match( T const& item ) const override {
+ return m_predicate(item);
+ }
+
+ std::string describe() const override {
+ return m_description;
+ }
+};
+
+} // namespace Generic
+
+ // The following functions create the actual matcher objects.
+ // The user has to explicitly specify type to the function, because
+ // infering std::function<bool(T const&)> is hard (but possible) and
+ // requires a lot of TMP.
+ template<typename T>
+ Generic::PredicateMatcher<T> Predicate(std::function<bool(T const&)> const& predicate, std::string const& description = "") {
+ return Generic::PredicateMatcher<T>(predicate, description);
+ }
+
+} // namespace Matchers
+} // namespace Catch
+
+// end catch_matchers_generic.hpp
+// start catch_matchers_string.h
+
+#include <string>
+
+namespace Catch {
+namespace Matchers {
+
+ namespace StdString {
+
+ struct CasedString
+ {
+ CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity );
+ std::string adjustString( std::string const& str ) const;
+ std::string caseSensitivitySuffix() const;
+
+ CaseSensitive::Choice m_caseSensitivity;
+ std::string m_str;
+ };
+
+ struct StringMatcherBase : MatcherBase<std::string> {
+ StringMatcherBase( std::string const& operation, CasedString const& comparator );
+ std::string describe() const override;
+
+ CasedString m_comparator;
+ std::string m_operation;
+ };
+
+ struct EqualsMatcher : StringMatcherBase {
+ EqualsMatcher( CasedString const& comparator );
+ bool match( std::string const& source ) const override;
+ };
+ struct ContainsMatcher : StringMatcherBase {
+ ContainsMatcher( CasedString const& comparator );
+ bool match( std::string const& source ) const override;
+ };
+ struct StartsWithMatcher : StringMatcherBase {
+ StartsWithMatcher( CasedString const& comparator );
+ bool match( std::string const& source ) const override;
+ };
+ struct EndsWithMatcher : StringMatcherBase {
+ EndsWithMatcher( CasedString const& comparator );
+ bool match( std::string const& source ) const override;
+ };
+
+ struct RegexMatcher : MatcherBase<std::string> {
+ RegexMatcher( std::string regex, CaseSensitive::Choice caseSensitivity );
+ bool match( std::string const& matchee ) const override;
+ std::string describe() const override;
+
+ private:
+ std::string m_regex;
+ CaseSensitive::Choice m_caseSensitivity;
+ };
+
+ } // namespace StdString
+
+ // The following functions create the actual matcher objects.
+ // This allows the types to be inferred
+
+ StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
+ StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
+ StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
+ StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
+ StdString::RegexMatcher Matches( std::string const& regex, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
+
+} // namespace Matchers
+} // namespace Catch
+
+// end catch_matchers_string.h
+// start catch_matchers_vector.h
+
+#include <algorithm>
+
+namespace Catch {
+namespace Matchers {
+
+ namespace Vector {
+ namespace Detail {
+ template <typename InputIterator, typename T>
+ size_t count(InputIterator first, InputIterator last, T const& item) {
+ size_t cnt = 0;
+ for (; first != last; ++first) {
+ if (*first == item) {
+ ++cnt;
+ }
+ }
+ return cnt;
+ }
+ template <typename InputIterator, typename T>
+ bool contains(InputIterator first, InputIterator last, T const& item) {
+ for (; first != last; ++first) {
+ if (*first == item) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ template<typename T>
+ struct ContainsElementMatcher : MatcherBase<std::vector<T>> {
+
+ ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {}
+
+ bool match(std::vector<T> const &v) const override {
+ for (auto const& el : v) {
+ if (el == m_comparator) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ std::string describe() const override {
+ return "Contains: " + ::Catch::Detail::stringify( m_comparator );
+ }
+
+ T const& m_comparator;
+ };
+
+ template<typename T>
+ struct ContainsMatcher : MatcherBase<std::vector<T>> {
+
+ ContainsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}
+
+ bool match(std::vector<T> const &v) const override {
+ // !TBD: see note in EqualsMatcher
+ if (m_comparator.size() > v.size())
+ return false;
+ for (auto const& comparator : m_comparator) {
+ auto present = false;
+ for (const auto& el : v) {
+ if (el == comparator) {
+ present = true;
+ break;
+ }
+ }
+ if (!present) {
+ return false;
+ }
+ }
+ return true;
+ }
+ std::string describe() const override {
+ return "Contains: " + ::Catch::Detail::stringify( m_comparator );
+ }
+
+ std::vector<T> const& m_comparator;
+ };
+
+ template<typename T>
+ struct EqualsMatcher : MatcherBase<std::vector<T>> {
+
+ EqualsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}
+
+ bool match(std::vector<T> const &v) const override {
+ // !TBD: This currently works if all elements can be compared using !=
+ // - a more general approach would be via a compare template that defaults
+ // to using !=. but could be specialised for, e.g. std::vector<T> etc
+ // - then just call that directly
+ if (m_comparator.size() != v.size())
+ return false;
+ for (std::size_t i = 0; i < v.size(); ++i)
+ if (m_comparator[i] != v[i])
+ return false;
+ return true;
+ }
+ std::string describe() const override {
+ return "Equals: " + ::Catch::Detail::stringify( m_comparator );
+ }
+ std::vector<T> const& m_comparator;
+ };
+
+ template<typename T>
+ struct UnorderedEqualsMatcher : MatcherBase<std::vector<T>> {
+ UnorderedEqualsMatcher(std::vector<T> const& target) : m_target(target) {}
+ bool match(std::vector<T> const& vec) const override {
+ // Note: This is a reimplementation of std::is_permutation,
+ // because I don't want to include <algorithm> inside the common path
+ if (m_target.size() != vec.size()) {
+ return false;
+ }
+ auto lfirst = m_target.begin(), llast = m_target.end();
+ auto rfirst = vec.begin(), rlast = vec.end();
+ // Cut common prefix to optimize checking of permuted parts
+ while (lfirst != llast && *lfirst != *rfirst) {
+ ++lfirst; ++rfirst;
+ }
+ if (lfirst == llast) {
+ return true;
+ }
+
+ for (auto mid = lfirst; mid != llast; ++mid) {
+ // Skip already counted items
+ if (Detail::contains(lfirst, mid, *mid)) {
+ continue;
+ }
+ size_t num_vec = Detail::count(rfirst, rlast, *mid);
+ if (num_vec == 0 || Detail::count(lfirst, llast, *mid) != num_vec) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ std::string describe() const override {
+ return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target);
+ }
+ private:
+ std::vector<T> const& m_target;
+ };
+
+ } // namespace Vector
+
+ // The following functions create the actual matcher objects.
+ // This allows the types to be inferred
+
+ template<typename T>
+ Vector::ContainsMatcher<T> Contains( std::vector<T> const& comparator ) {
+ return Vector::ContainsMatcher<T>( comparator );
+ }
+
+ template<typename T>
+ Vector::ContainsElementMatcher<T> VectorContains( T const& comparator ) {
+ return Vector::ContainsElementMatcher<T>( comparator );
+ }
+
+ template<typename T>
+ Vector::EqualsMatcher<T> Equals( std::vector<T> const& comparator ) {
+ return Vector::EqualsMatcher<T>( comparator );
+ }
+
+ template<typename T>
+ Vector::UnorderedEqualsMatcher<T> UnorderedEquals(std::vector<T> const& target) {
+ return Vector::UnorderedEqualsMatcher<T>(target);
+ }
+
+} // namespace Matchers
+} // namespace Catch
+
+// end catch_matchers_vector.h
+namespace Catch {
+
+ template<typename ArgT, typename MatcherT>
+ class MatchExpr : public ITransientExpression {
+ ArgT const& m_arg;
+ MatcherT m_matcher;
+ StringRef m_matcherString;
+ public:
+ MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString )
+ : ITransientExpression{ true, matcher.match( arg ) },
+ m_arg( arg ),
+ m_matcher( matcher ),
+ m_matcherString( matcherString )
+ {}
+
+ void streamReconstructedExpression( std::ostream &os ) const override {
+ auto matcherAsString = m_matcher.toString();
+ os << Catch::Detail::stringify( m_arg ) << ' ';
+ if( matcherAsString == Detail::unprintableString )
+ os << m_matcherString;
+ else
+ os << matcherAsString;
+ }
+ };
+
+ using StringMatcher = Matchers::Impl::MatcherBase<std::string>;
+
+ void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString );
+
+ template<typename ArgT, typename MatcherT>
+ auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString ) -> MatchExpr<ArgT, MatcherT> {
+ return MatchExpr<ArgT, MatcherT>( arg, matcher, matcherString );
+ }
+
+} // namespace Catch
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \
+ do { \
+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
+ INTERNAL_CATCH_TRY { \
+ catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher, #matcher##_catch_sr ) ); \
+ } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
+ INTERNAL_CATCH_REACT( catchAssertionHandler ) \
+ } while( false )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \
+ do { \
+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
+ if( catchAssertionHandler.allowThrows() ) \
+ try { \
+ static_cast<void>(__VA_ARGS__ ); \
+ catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
+ } \
+ catch( exceptionType const& ex ) { \
+ catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher, #matcher##_catch_sr ) ); \
+ } \
+ catch( ... ) { \
+ catchAssertionHandler.handleUnexpectedInflightException(); \
+ } \
+ else \
+ catchAssertionHandler.handleThrowingCallSkipped(); \
+ INTERNAL_CATCH_REACT( catchAssertionHandler ) \
+ } while( false )
+
+// end catch_capture_matchers.h
+#endif
+// start catch_generators.hpp
+
+// start catch_interfaces_generatortracker.h
+
+
+#include <memory>
+
+namespace Catch {
+
+ namespace Generators {
+ class GeneratorBase {
+ protected:
+ size_t m_size = 0;
+
+ public:
+ GeneratorBase( size_t size ) : m_size( size ) {}
+ virtual ~GeneratorBase();
+ auto size() const -> size_t { return m_size; }
+ };
+ using GeneratorBasePtr = std::unique_ptr<GeneratorBase>;
+
+ } // namespace Generators
+
+ struct IGeneratorTracker {
+ virtual ~IGeneratorTracker();
+ virtual auto hasGenerator() const -> bool = 0;
+ virtual auto getGenerator() const -> Generators::GeneratorBasePtr const& = 0;
+ virtual void setGenerator( Generators::GeneratorBasePtr&& generator ) = 0;
+ virtual auto getIndex() const -> std::size_t = 0;
+ };
+
+} // namespace Catch
+
+// end catch_interfaces_generatortracker.h
+// start catch_enforce.h
+
+#include <stdexcept>
+
+namespace Catch {
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+ template <typename Ex>
+ [[noreturn]]
+ void throw_exception(Ex const& e) {
+ throw e;
+ }
+#else // ^^ Exceptions are enabled // Exceptions are disabled vv
+ [[noreturn]]
+ void throw_exception(std::exception const& e);
+#endif
+} // namespace Catch;
+
+#define CATCH_PREPARE_EXCEPTION( type, msg ) \
+ type( ( Catch::ReusableStringStream() << msg ).str() )
+#define CATCH_INTERNAL_ERROR( msg ) \
+ Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg))
+#define CATCH_ERROR( msg ) \
+ Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::domain_error, msg ))
+#define CATCH_RUNTIME_ERROR( msg ) \
+ Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::runtime_error, msg ))
+#define CATCH_ENFORCE( condition, msg ) \
+ do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false)
+
+// end catch_enforce.h
+#include <memory>
+#include <vector>
+#include <cassert>
+
+#include <utility>
+
+namespace Catch {
+namespace Generators {
+
+ // !TBD move this into its own location?
+ namespace pf{
+ template<typename T, typename... Args>
+ std::unique_ptr<T> make_unique( Args&&... args ) {
+ return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+ }
+ }
+
+ template<typename T>
+ struct IGenerator {
+ virtual ~IGenerator() {}
+ virtual auto get( size_t index ) const -> T = 0;
+ };
+
+ template<typename T>
+ class SingleValueGenerator : public IGenerator<T> {
+ T m_value;
+ public:
+ SingleValueGenerator( T const& value ) : m_value( value ) {}
+
+ auto get( size_t ) const -> T override {
+ return m_value;
+ }
+ };
+
+ template<typename T>
+ class FixedValuesGenerator : public IGenerator<T> {
+ std::vector<T> m_values;
+
+ public:
+ FixedValuesGenerator( std::initializer_list<T> values ) : m_values( values ) {}
+
+ auto get( size_t index ) const -> T override {
+ return m_values[index];
+ }
+ };
+
+ template<typename T>
+ class RangeGenerator : public IGenerator<T> {
+ T const m_first;
+ T const m_last;
+
+ public:
+ RangeGenerator( T const& first, T const& last ) : m_first( first ), m_last( last ) {
+ assert( m_last > m_first );
+ }
+
+ auto get( size_t index ) const -> T override {
+ // ToDo:: introduce a safe cast to catch potential overflows
+ return static_cast<T>(m_first+index);
+ }
+ };
+
+ template<typename T>
+ struct NullGenerator : IGenerator<T> {
+ auto get( size_t ) const -> T override {
+ CATCH_INTERNAL_ERROR("A Null Generator is always empty");
+ }
+ };
+
+ template<typename T>
+ class Generator {
+ std::unique_ptr<IGenerator<T>> m_generator;
+ size_t m_size;
+
+ public:
+ Generator( size_t size, std::unique_ptr<IGenerator<T>> generator )
+ : m_generator( std::move( generator ) ),
+ m_size( size )
+ {}
+
+ auto size() const -> size_t { return m_size; }
+ auto operator[]( size_t index ) const -> T {
+ assert( index < m_size );
+ return m_generator->get( index );
+ }
+ };
+
+ std::vector<size_t> randomiseIndices( size_t selectionSize, size_t sourceSize );
+
+ template<typename T>
+ class GeneratorRandomiser : public IGenerator<T> {
+ Generator<T> m_baseGenerator;
+
+ std::vector<size_t> m_indices;
+ public:
+ GeneratorRandomiser( Generator<T>&& baseGenerator, size_t numberOfItems )
+ : m_baseGenerator( std::move( baseGenerator ) ),
+ m_indices( randomiseIndices( numberOfItems, m_baseGenerator.size() ) )
+ {}
+
+ auto get( size_t index ) const -> T override {
+ return m_baseGenerator[m_indices[index]];
+ }
+ };
+
+ template<typename T>
+ struct RequiresASpecialisationFor;
+
+ template<typename T>
+ auto all() -> Generator<T> { return RequiresASpecialisationFor<T>(); }
+
+ template<>
+ auto all<int>() -> Generator<int>;
+
+ template<typename T>
+ auto range( T const& first, T const& last ) -> Generator<T> {
+ return Generator<T>( (last-first), pf::make_unique<RangeGenerator<T>>( first, last ) );
+ }
+
+ template<typename T>
+ auto random( T const& first, T const& last ) -> Generator<T> {
+ auto gen = range( first, last );
+ auto size = gen.size();
+
+ return Generator<T>( size, pf::make_unique<GeneratorRandomiser<T>>( std::move( gen ), size ) );
+ }
+ template<typename T>
+ auto random( size_t size ) -> Generator<T> {
+ return Generator<T>( size, pf::make_unique<GeneratorRandomiser<T>>( all<T>(), size ) );
+ }
+
+ template<typename T>
+ auto values( std::initializer_list<T> values ) -> Generator<T> {
+ return Generator<T>( values.size(), pf::make_unique<FixedValuesGenerator<T>>( values ) );
+ }
+ template<typename T>
+ auto value( T const& val ) -> Generator<T> {
+ return Generator<T>( 1, pf::make_unique<SingleValueGenerator<T>>( val ) );
+ }
+
+ template<typename T>
+ auto as() -> Generator<T> {
+ return Generator<T>( 0, pf::make_unique<NullGenerator<T>>() );
+ }
+
+ template<typename... Ts>
+ auto table( std::initializer_list<std::tuple<Ts...>>&& tuples ) -> Generator<std::tuple<Ts...>> {
+ return values<std::tuple<Ts...>>( std::forward<std::initializer_list<std::tuple<Ts...>>>( tuples ) );
+ }
+
+ template<typename T>
+ struct Generators : GeneratorBase {
+ std::vector<Generator<T>> m_generators;
+
+ using type = T;
+
+ Generators() : GeneratorBase( 0 ) {}
+
+ void populate( T&& val ) {
+ m_size += 1;
+ m_generators.emplace_back( value( std::move( val ) ) );
+ }
+ template<typename U>
+ void populate( U&& val ) {
+ populate( T( std::move( val ) ) );
+ }
+ void populate( Generator<T>&& generator ) {
+ m_size += generator.size();
+ m_generators.emplace_back( std::move( generator ) );
+ }
+
+ template<typename U, typename... Gs>
+ void populate( U&& valueOrGenerator, Gs... moreGenerators ) {
+ populate( std::forward<U>( valueOrGenerator ) );
+ populate( std::forward<Gs>( moreGenerators )... );
+ }
+
+ auto operator[]( size_t index ) const -> T {
+ size_t sizes = 0;
+ for( auto const& gen : m_generators ) {
+ auto localIndex = index-sizes;
+ sizes += gen.size();
+ if( index < sizes )
+ return gen[localIndex];
+ }
+ CATCH_INTERNAL_ERROR("Index '" << index << "' is out of range (" << sizes << ')');
+ }
+ };
+
+ template<typename T, typename... Gs>
+ auto makeGenerators( Generator<T>&& generator, Gs... moreGenerators ) -> Generators<T> {
+ Generators<T> generators;
+ generators.m_generators.reserve( 1+sizeof...(Gs) );
+ generators.populate( std::move( generator ), std::forward<Gs>( moreGenerators )... );
+ return generators;
+ }
+ template<typename T>
+ auto makeGenerators( Generator<T>&& generator ) -> Generators<T> {
+ Generators<T> generators;
+ generators.populate( std::move( generator ) );
+ return generators;
+ }
+ template<typename T, typename... Gs>
+ auto makeGenerators( T&& val, Gs... moreGenerators ) -> Generators<T> {
+ return makeGenerators( value( std::forward<T>( val ) ), std::forward<Gs>( moreGenerators )... );
+ }
+ template<typename T, typename U, typename... Gs>
+ auto makeGenerators( U&& val, Gs... moreGenerators ) -> Generators<T> {
+ return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... );
+ }
+
+ auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&;
+
+ template<typename L>
+ // Note: The type after -> is weird, because VS2015 cannot parse
+ // the expression used in the typedef inside, when it is in
+ // return type. Yeah, ¯\_(ツ)_/¯
+ auto generate( SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>()[0]) {
+ using UnderlyingType = typename decltype(generatorExpression())::type;
+
+ IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo );
+ if( !tracker.hasGenerator() )
+ tracker.setGenerator( pf::make_unique<Generators<UnderlyingType>>( generatorExpression() ) );
+
+ auto const& generator = static_cast<Generators<UnderlyingType> const&>( *tracker.getGenerator() );
+ return generator[tracker.getIndex()];
+ }
+
+} // namespace Generators
+} // namespace Catch
+
+#define GENERATE( ... ) \
+ Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, []{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } )
+
+// end catch_generators.hpp
+
+// These files are included here so the single_include script doesn't put them
+// in the conditionally compiled sections
+// start catch_test_case_info.h
+
+#include <string>
+#include <vector>
+#include <memory>
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+namespace Catch {
+
+ struct ITestInvoker;
+
+ struct TestCaseInfo {
+ enum SpecialProperties{
+ None = 0,
+ IsHidden = 1 << 1,
+ ShouldFail = 1 << 2,
+ MayFail = 1 << 3,
+ Throws = 1 << 4,
+ NonPortable = 1 << 5,
+ Benchmark = 1 << 6
+ };
+
+ TestCaseInfo( std::string const& _name,
+ std::string const& _className,
+ std::string const& _description,
+ std::vector<std::string> const& _tags,
+ SourceLineInfo const& _lineInfo );
+
+ friend void setTags( TestCaseInfo& testCaseInfo, std::vector<std::string> tags );
+
+ bool isHidden() const;
+ bool throws() const;
+ bool okToFail() const;
+ bool expectedToFail() const;
+
+ std::string tagsAsString() const;
+
+ std::string name;
+ std::string className;
+ std::string description;
+ std::vector<std::string> tags;
+ std::vector<std::string> lcaseTags;
+ SourceLineInfo lineInfo;
+ SpecialProperties properties;
+ };
+
+ class TestCase : public TestCaseInfo {
+ public:
+
+ TestCase( ITestInvoker* testCase, TestCaseInfo&& info );
+
+ TestCase withName( std::string const& _newName ) const;
+
+ void invoke() const;
+
+ TestCaseInfo const& getTestCaseInfo() const;
+
+ bool operator == ( TestCase const& other ) const;
+ bool operator < ( TestCase const& other ) const;
+
+ private:
+ std::shared_ptr<ITestInvoker> test;
+ };
+
+ TestCase makeTestCase( ITestInvoker* testCase,
+ std::string const& className,
+ NameAndTags const& nameAndTags,
+ SourceLineInfo const& lineInfo );
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+// end catch_test_case_info.h
+// start catch_interfaces_runner.h
+
+namespace Catch {
+
+ struct IRunner {
+ virtual ~IRunner();
+ virtual bool aborting() const = 0;
+ };
+}
+
+// end catch_interfaces_runner.h
+
+#ifdef __OBJC__
+// start catch_objc.hpp
+
+#import <objc/runtime.h>
+
+#include <string>
+
+// NB. Any general catch headers included here must be included
+// in catch.hpp first to make sure they are included by the single
+// header for non obj-usage
+
+///////////////////////////////////////////////////////////////////////////////
+// This protocol is really only here for (self) documenting purposes, since
+// all its methods are optional.
+@protocol OcFixture
+
+@optional
+
+-(void) setUp;
+-(void) tearDown;
+
+@end
+
+namespace Catch {
+
+ class OcMethod : public ITestInvoker {
+
+ public:
+ OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {}
+
+ virtual void invoke() const {
+ id obj = [[m_cls alloc] init];
+
+ performOptionalSelector( obj, @selector(setUp) );
+ performOptionalSelector( obj, m_sel );
+ performOptionalSelector( obj, @selector(tearDown) );
+
+ arcSafeRelease( obj );
+ }
+ private:
+ virtual ~OcMethod() {}
+
+ Class m_cls;
+ SEL m_sel;
+ };
+
+ namespace Detail{
+
+ inline std::string getAnnotation( Class cls,
+ std::string const& annotationName,
+ std::string const& testCaseName ) {
+ NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()];
+ SEL sel = NSSelectorFromString( selStr );
+ arcSafeRelease( selStr );
+ id value = performOptionalSelector( cls, sel );
+ if( value )
+ return [(NSString*)value UTF8String];
+ return "";
+ }
+ }
+
+ inline std::size_t registerTestMethods() {
+ std::size_t noTestMethods = 0;
+ int noClasses = objc_getClassList( nullptr, 0 );
+
+ Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses);
+ objc_getClassList( classes, noClasses );
+
+ for( int c = 0; c < noClasses; c++ ) {
+ Class cls = classes[c];
+ {
+ u_int count;
+ Method* methods = class_copyMethodList( cls, &count );
+ for( u_int m = 0; m < count ; m++ ) {
+ SEL selector = method_getName(methods[m]);
+ std::string methodName = sel_getName(selector);
+ if( startsWith( methodName, "Catch_TestCase_" ) ) {
+ std::string testCaseName = methodName.substr( 15 );
+ std::string name = Detail::getAnnotation( cls, "Name", testCaseName );
+ std::string desc = Detail::getAnnotation( cls, "Description", testCaseName );
+ const char* className = class_getName( cls );
+
+ getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, NameAndTags( name.c_str(), desc.c_str() ), SourceLineInfo("",0) ) );
+ noTestMethods++;
+ }
+ }
+ free(methods);
+ }
+ }
+ return noTestMethods;
+ }
+
+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
+
+ namespace Matchers {
+ namespace Impl {
+ namespace NSStringMatchers {
+
+ struct StringHolder : MatcherBase<NSString*>{
+ StringHolder( NSString* substr ) : m_substr( [substr copy] ){}
+ StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){}
+ StringHolder() {
+ arcSafeRelease( m_substr );
+ }
+
+ bool match( NSString* arg ) const override {
+ return false;
+ }
+
+ NSString* CATCH_ARC_STRONG m_substr;
+ };
+
+ struct Equals : StringHolder {
+ Equals( NSString* substr ) : StringHolder( substr ){}
+
+ bool match( NSString* str ) const override {
+ return (str != nil || m_substr == nil ) &&
+ [str isEqualToString:m_substr];
+ }
+
+ std::string describe() const override {
+ return "equals string: " + Catch::Detail::stringify( m_substr );
+ }
+ };
+
+ struct Contains : StringHolder {
+ Contains( NSString* substr ) : StringHolder( substr ){}
+
+ bool match( NSString* str ) const {
+ return (str != nil || m_substr == nil ) &&
+ [str rangeOfString:m_substr].location != NSNotFound;
+ }
+
+ std::string describe() const override {
+ return "contains string: " + Catch::Detail::stringify( m_substr );
+ }
+ };
+
+ struct StartsWith : StringHolder {
+ StartsWith( NSString* substr ) : StringHolder( substr ){}
+
+ bool match( NSString* str ) const override {
+ return (str != nil || m_substr == nil ) &&
+ [str rangeOfString:m_substr].location == 0;
+ }
+
+ std::string describe() const override {
+ return "starts with: " + Catch::Detail::stringify( m_substr );
+ }
+ };
+ struct EndsWith : StringHolder {
+ EndsWith( NSString* substr ) : StringHolder( substr ){}
+
+ bool match( NSString* str ) const override {
+ return (str != nil || m_substr == nil ) &&
+ [str rangeOfString:m_substr].location == [str length] - [m_substr length];
+ }
+
+ std::string describe() const override {
+ return "ends with: " + Catch::Detail::stringify( m_substr );
+ }
+ };
+
+ } // namespace NSStringMatchers
+ } // namespace Impl
+
+ inline Impl::NSStringMatchers::Equals
+ Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); }
+
+ inline Impl::NSStringMatchers::Contains
+ Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); }
+
+ inline Impl::NSStringMatchers::StartsWith
+ StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); }
+
+ inline Impl::NSStringMatchers::EndsWith
+ EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); }
+
+ } // namespace Matchers
+
+ using namespace Matchers;
+
+#endif // CATCH_CONFIG_DISABLE_MATCHERS
+
+} // namespace Catch
+
+///////////////////////////////////////////////////////////////////////////////
+#define OC_MAKE_UNIQUE_NAME( root, uniqueSuffix ) root##uniqueSuffix
+#define OC_TEST_CASE2( name, desc, uniqueSuffix ) \
++(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Name_test_, uniqueSuffix ) \
+{ \
+return @ name; \
+} \
++(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Description_test_, uniqueSuffix ) \
+{ \
+return @ desc; \
+} \
+-(void) OC_MAKE_UNIQUE_NAME( Catch_TestCase_test_, uniqueSuffix )
+
+#define OC_TEST_CASE( name, desc ) OC_TEST_CASE2( name, desc, __LINE__ )
+
+// end catch_objc.hpp
+#endif
+
+#ifdef CATCH_CONFIG_EXTERNAL_INTERFACES
+// start catch_external_interfaces.h
+
+// start catch_reporter_bases.hpp
+
+// start catch_interfaces_reporter.h
+
+// start catch_config.hpp
+
+// start catch_test_spec_parser.h
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+// start catch_test_spec.h
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+// start catch_wildcard_pattern.h
+
+namespace Catch
+{
+ class WildcardPattern {
+ enum WildcardPosition {
+ NoWildcard = 0,
+ WildcardAtStart = 1,
+ WildcardAtEnd = 2,
+ WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd
+ };
+
+ public:
+
+ WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity );
+ virtual ~WildcardPattern() = default;
+ virtual bool matches( std::string const& str ) const;
+
+ private:
+ std::string adjustCase( std::string const& str ) const;
+ CaseSensitive::Choice m_caseSensitivity;
+ WildcardPosition m_wildcard = NoWildcard;
+ std::string m_pattern;
+ };
+}
+
+// end catch_wildcard_pattern.h
+#include <string>
+#include <vector>
+#include <memory>
+
+namespace Catch {
+
+ class TestSpec {
+ struct Pattern {
+ virtual ~Pattern();
+ virtual bool matches( TestCaseInfo const& testCase ) const = 0;
+ };
+ using PatternPtr = std::shared_ptr<Pattern>;
+
+ class NamePattern : public Pattern {
+ public:
+ NamePattern( std::string const& name );
+ virtual ~NamePattern();
+ virtual bool matches( TestCaseInfo const& testCase ) const override;
+ private:
+ WildcardPattern m_wildcardPattern;
+ };
+
+ class TagPattern : public Pattern {
+ public:
+ TagPattern( std::string const& tag );
+ virtual ~TagPattern();
+ virtual bool matches( TestCaseInfo const& testCase ) const override;
+ private:
+ std::string m_tag;
+ };
+
+ class ExcludedPattern : public Pattern {
+ public:
+ ExcludedPattern( PatternPtr const& underlyingPattern );
+ virtual ~ExcludedPattern();
+ virtual bool matches( TestCaseInfo const& testCase ) const override;
+ private:
+ PatternPtr m_underlyingPattern;
+ };
+
+ struct Filter {
+ std::vector<PatternPtr> m_patterns;
+
+ bool matches( TestCaseInfo const& testCase ) const;
+ };
+
+ public:
+ bool hasFilters() const;
+ bool matches( TestCaseInfo const& testCase ) const;
+
+ private:
+ std::vector<Filter> m_filters;
+
+ friend class TestSpecParser;
+ };
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+// end catch_test_spec.h
+// start catch_interfaces_tag_alias_registry.h
+
+#include <string>
+
+namespace Catch {
+
+ struct TagAlias;
+
+ struct ITagAliasRegistry {
+ virtual ~ITagAliasRegistry();
+ // Nullptr if not present
+ virtual TagAlias const* find( std::string const& alias ) const = 0;
+ virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0;
+
+ static ITagAliasRegistry const& get();
+ };
+
+} // end namespace Catch
+
+// end catch_interfaces_tag_alias_registry.h
+namespace Catch {
+
+ class TestSpecParser {
+ enum Mode{ None, Name, QuotedName, Tag, EscapedName };
+ Mode m_mode = None;
+ bool m_exclusion = false;
+ std::size_t m_start = std::string::npos, m_pos = 0;
+ std::string m_arg;
+ std::vector<std::size_t> m_escapeChars;
+ TestSpec::Filter m_currentFilter;
+ TestSpec m_testSpec;
+ ITagAliasRegistry const* m_tagAliases = nullptr;
+
+ public:
+ TestSpecParser( ITagAliasRegistry const& tagAliases );
+
+ TestSpecParser& parse( std::string const& arg );
+ TestSpec testSpec();
+
+ private:
+ void visitChar( char c );
+ void startNewMode( Mode mode, std::size_t start );
+ void escape();
+ std::string subString() const;
+
+ template<typename T>
+ void addPattern() {
+ std::string token = subString();
+ for( std::size_t i = 0; i < m_escapeChars.size(); ++i )
+ token = token.substr( 0, m_escapeChars[i]-m_start-i ) + token.substr( m_escapeChars[i]-m_start-i+1 );
+ m_escapeChars.clear();
+ if( startsWith( token, "exclude:" ) ) {
+ m_exclusion = true;
+ token = token.substr( 8 );
+ }
+ if( !token.empty() ) {
+ TestSpec::PatternPtr pattern = std::make_shared<T>( token );
+ if( m_exclusion )
+ pattern = std::make_shared<TestSpec::ExcludedPattern>( pattern );
+ m_currentFilter.m_patterns.push_back( pattern );
+ }
+ m_exclusion = false;
+ m_mode = None;
+ }
+
+ void addFilter();
+ };
+ TestSpec parseTestSpec( std::string const& arg );
+
+} // namespace Catch
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+// end catch_test_spec_parser.h
+// start catch_interfaces_config.h
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+#include <memory>
+
+namespace Catch {
+
+ enum class Verbosity {
+ Quiet = 0,
+ Normal,
+ High
+ };
+
+ struct WarnAbout { enum What {
+ Nothing = 0x00,
+ NoAssertions = 0x01,
+ NoTests = 0x02
+ }; };
+
+ struct ShowDurations { enum OrNot {
+ DefaultForReporter,
+ Always,
+ Never
+ }; };
+ struct RunTests { enum InWhatOrder {
+ InDeclarationOrder,
+ InLexicographicalOrder,
+ InRandomOrder
+ }; };
+ struct UseColour { enum YesOrNo {
+ Auto,
+ Yes,
+ No
+ }; };
+ struct WaitForKeypress { enum When {
+ Never,
+ BeforeStart = 1,
+ BeforeExit = 2,
+ BeforeStartAndExit = BeforeStart | BeforeExit
+ }; };
+
+ class TestSpec;
+
+ struct IConfig : NonCopyable {
+
+ virtual ~IConfig();
+
+ virtual bool allowThrows() const = 0;
+ virtual std::ostream& stream() const = 0;
+ virtual std::string name() const = 0;
+ virtual bool includeSuccessfulResults() const = 0;
+ virtual bool shouldDebugBreak() const = 0;
+ virtual bool warnAboutMissingAssertions() const = 0;
+ virtual bool warnAboutNoTests() const = 0;
+ virtual int abortAfter() const = 0;
+ virtual bool showInvisibles() const = 0;
+ virtual ShowDurations::OrNot showDurations() const = 0;
+ virtual TestSpec const& testSpec() const = 0;
+ virtual bool hasTestFilters() const = 0;
+ virtual RunTests::InWhatOrder runOrder() const = 0;
+ virtual unsigned int rngSeed() const = 0;
+ virtual int benchmarkResolutionMultiple() const = 0;
+ virtual UseColour::YesOrNo useColour() const = 0;
+ virtual std::vector<std::string> const& getSectionsToRun() const = 0;
+ virtual Verbosity verbosity() const = 0;
+ };
+
+ using IConfigPtr = std::shared_ptr<IConfig const>;
+}
+
+// end catch_interfaces_config.h
+// Libstdc++ doesn't like incomplete classes for unique_ptr
+
+#include <memory>
+#include <vector>
+#include <string>
+
+#ifndef CATCH_CONFIG_CONSOLE_WIDTH
+#define CATCH_CONFIG_CONSOLE_WIDTH 80
+#endif
+
+namespace Catch {
+
+ struct IStream;
+
+ struct ConfigData {
+ bool listTests = false;
+ bool listTags = false;
+ bool listReporters = false;
+ bool listTestNamesOnly = false;
+
+ bool showSuccessfulTests = false;
+ bool shouldDebugBreak = false;
+ bool noThrow = false;
+ bool showHelp = false;
+ bool showInvisibles = false;
+ bool filenamesAsTags = false;
+ bool libIdentify = false;
+
+ int abortAfter = -1;
+ unsigned int rngSeed = 0;
+ int benchmarkResolutionMultiple = 100;
+
+ Verbosity verbosity = Verbosity::Normal;
+ WarnAbout::What warnings = WarnAbout::Nothing;
+ ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter;
+ RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder;
+ UseColour::YesOrNo useColour = UseColour::Auto;
+ WaitForKeypress::When waitForKeypress = WaitForKeypress::Never;
+
+ std::string outputFilename;
+ std::string name;
+ std::string processName;
+#ifndef CATCH_CONFIG_DEFAULT_REPORTER
+#define CATCH_CONFIG_DEFAULT_REPORTER "console"
+#endif
+ std::string reporterName = CATCH_CONFIG_DEFAULT_REPORTER;
+#undef CATCH_CONFIG_DEFAULT_REPORTER
+
+ std::vector<std::string> testsOrTags;
+ std::vector<std::string> sectionsToRun;
+ };
+
+ class Config : public IConfig {
+ public:
+
+ Config() = default;
+ Config( ConfigData const& data );
+ virtual ~Config() = default;
+
+ std::string const& getFilename() const;
+
+ bool listTests() const;
+ bool listTestNamesOnly() const;
+ bool listTags() const;
+ bool listReporters() const;
+
+ std::string getProcessName() const;
+ std::string const& getReporterName() const;
+
+ std::vector<std::string> const& getTestsOrTags() const;
+ std::vector<std::string> const& getSectionsToRun() const override;
+
+ virtual TestSpec const& testSpec() const override;
+ bool hasTestFilters() const override;
+
+ bool showHelp() const;
+
+ // IConfig interface
+ bool allowThrows() const override;
+ std::ostream& stream() const override;
+ std::string name() const override;
+ bool includeSuccessfulResults() const override;
+ bool warnAboutMissingAssertions() const override;
+ bool warnAboutNoTests() const override;
+ ShowDurations::OrNot showDurations() const override;
+ RunTests::InWhatOrder runOrder() const override;
+ unsigned int rngSeed() const override;
+ int benchmarkResolutionMultiple() const override;
+ UseColour::YesOrNo useColour() const override;
+ bool shouldDebugBreak() const override;
+ int abortAfter() const override;
+ bool showInvisibles() const override;
+ Verbosity verbosity() const override;
+
+ private:
+
+ IStream const* openStream();
+ ConfigData m_data;
+
+ std::unique_ptr<IStream const> m_stream;
+ TestSpec m_testSpec;
+ bool m_hasTestFilters = false;
+ };
+
+} // end namespace Catch
+
+// end catch_config.hpp
+// start catch_assertionresult.h
+
+#include <string>
+
+namespace Catch {
+
+ struct AssertionResultData
+ {
+ AssertionResultData() = delete;
+
+ AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression );
+
+ std::string message;
+ mutable std::string reconstructedExpression;
+ LazyExpression lazyExpression;
+ ResultWas::OfType resultType;
+
+ std::string reconstructExpression() const;
+ };
+
+ class AssertionResult {
+ public:
+ AssertionResult() = delete;
+ AssertionResult( AssertionInfo const& info, AssertionResultData const& data );
+
+ bool isOk() const;
+ bool succeeded() const;
+ ResultWas::OfType getResultType() const;
+ bool hasExpression() const;
+ bool hasMessage() const;
+ std::string getExpression() const;
+ std::string getExpressionInMacro() const;
+ bool hasExpandedExpression() const;
+ std::string getExpandedExpression() const;
+ std::string getMessage() const;
+ SourceLineInfo getSourceInfo() const;
+ StringRef getTestMacroName() const;
+
+ //protected:
+ AssertionInfo m_info;
+ AssertionResultData m_resultData;
+ };
+
+} // end namespace Catch
+
+// end catch_assertionresult.h
+// start catch_option.hpp
+
+namespace Catch {
+
+ // An optional type
+ template<typename T>
+ class Option {
+ public:
+ Option() : nullableValue( nullptr ) {}
+ Option( T const& _value )
+ : nullableValue( new( storage ) T( _value ) )
+ {}
+ Option( Option const& _other )
+ : nullableValue( _other ? new( storage ) T( *_other ) : nullptr )
+ {}
+
+ ~Option() {
+ reset();
+ }
+
+ Option& operator= ( Option const& _other ) {
+ if( &_other != this ) {
+ reset();
+ if( _other )
+ nullableValue = new( storage ) T( *_other );
+ }
+ return *this;
+ }
+ Option& operator = ( T const& _value ) {
+ reset();
+ nullableValue = new( storage ) T( _value );
+ return *this;
+ }
+
+ void reset() {
+ if( nullableValue )
+ nullableValue->~T();
+ nullableValue = nullptr;
+ }
+
+ T& operator*() { return *nullableValue; }
+ T const& operator*() const { return *nullableValue; }
+ T* operator->() { return nullableValue; }
+ const T* operator->() const { return nullableValue; }
+
+ T valueOr( T const& defaultValue ) const {
+ return nullableValue ? *nullableValue : defaultValue;
+ }
+
+ bool some() const { return nullableValue != nullptr; }
+ bool none() const { return nullableValue == nullptr; }
+
+ bool operator !() const { return nullableValue == nullptr; }
+ explicit operator bool() const {
+ return some();
+ }
+
+ private:
+ T *nullableValue;
+ alignas(alignof(T)) char storage[sizeof(T)];
+ };
+
+} // end namespace Catch
+
+// end catch_option.hpp
+#include <string>
+#include <iosfwd>
+#include <map>
+#include <set>
+#include <memory>
+
+namespace Catch {
+
+ struct ReporterConfig {
+ explicit ReporterConfig( IConfigPtr const& _fullConfig );
+
+ ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream );
+
+ std::ostream& stream() const;
+ IConfigPtr fullConfig() const;
+
+ private:
+ std::ostream* m_stream;
+ IConfigPtr m_fullConfig;
+ };
+
+ struct ReporterPreferences {
+ bool shouldRedirectStdOut = false;
+ bool shouldReportAllAssertions = false;
+ };
+
+ template<typename T>
+ struct LazyStat : Option<T> {
+ LazyStat& operator=( T const& _value ) {
+ Option<T>::operator=( _value );
+ used = false;
+ return *this;
+ }
+ void reset() {
+ Option<T>::reset();
+ used = false;
+ }
+ bool used = false;
+ };
+
+ struct TestRunInfo {
+ TestRunInfo( std::string const& _name );
+ std::string name;
+ };
+ struct GroupInfo {
+ GroupInfo( std::string const& _name,
+ std::size_t _groupIndex,
+ std::size_t _groupsCount );
+
+ std::string name;
+ std::size_t groupIndex;
+ std::size_t groupsCounts;
+ };
+
+ struct AssertionStats {
+ AssertionStats( AssertionResult const& _assertionResult,
+ std::vector<MessageInfo> const& _infoMessages,
+ Totals const& _totals );
+
+ AssertionStats( AssertionStats const& ) = default;
+ AssertionStats( AssertionStats && ) = default;
+ AssertionStats& operator = ( AssertionStats const& ) = default;
+ AssertionStats& operator = ( AssertionStats && ) = default;
+ virtual ~AssertionStats();
+
+ AssertionResult assertionResult;
+ std::vector<MessageInfo> infoMessages;
+ Totals totals;
+ };
+
+ struct SectionStats {
+ SectionStats( SectionInfo const& _sectionInfo,
+ Counts const& _assertions,
+ double _durationInSeconds,
+ bool _missingAssertions );
+ SectionStats( SectionStats const& ) = default;
+ SectionStats( SectionStats && ) = default;
+ SectionStats& operator = ( SectionStats const& ) = default;
+ SectionStats& operator = ( SectionStats && ) = default;
+ virtual ~SectionStats();
+
+ SectionInfo sectionInfo;
+ Counts assertions;
+ double durationInSeconds;
+ bool missingAssertions;
+ };
+
+ struct TestCaseStats {
+ TestCaseStats( TestCaseInfo const& _testInfo,
+ Totals const& _totals,
+ std::string const& _stdOut,
+ std::string const& _stdErr,
+ bool _aborting );
+
+ TestCaseStats( TestCaseStats const& ) = default;
+ TestCaseStats( TestCaseStats && ) = default;
+ TestCaseStats& operator = ( TestCaseStats const& ) = default;
+ TestCaseStats& operator = ( TestCaseStats && ) = default;
+ virtual ~TestCaseStats();
+
+ TestCaseInfo testInfo;
+ Totals totals;
+ std::string stdOut;
+ std::string stdErr;
+ bool aborting;
+ };
+
+ struct TestGroupStats {
+ TestGroupStats( GroupInfo const& _groupInfo,
+ Totals const& _totals,
+ bool _aborting );
+ TestGroupStats( GroupInfo const& _groupInfo );
+
+ TestGroupStats( TestGroupStats const& ) = default;
+ TestGroupStats( TestGroupStats && ) = default;
+ TestGroupStats& operator = ( TestGroupStats const& ) = default;
+ TestGroupStats& operator = ( TestGroupStats && ) = default;
+ virtual ~TestGroupStats();
+
+ GroupInfo groupInfo;
+ Totals totals;
+ bool aborting;
+ };
+
+ struct TestRunStats {
+ TestRunStats( TestRunInfo const& _runInfo,
+ Totals const& _totals,
+ bool _aborting );
+
+ TestRunStats( TestRunStats const& ) = default;
+ TestRunStats( TestRunStats && ) = default;
+ TestRunStats& operator = ( TestRunStats const& ) = default;
+ TestRunStats& operator = ( TestRunStats && ) = default;
+ virtual ~TestRunStats();
+
+ TestRunInfo runInfo;
+ Totals totals;
+ bool aborting;
+ };
+
+ struct BenchmarkInfo {
+ std::string name;
+ };
+ struct BenchmarkStats {
+ BenchmarkInfo info;
+ std::size_t iterations;
+ uint64_t elapsedTimeInNanoseconds;
+ };
+
+ struct IStreamingReporter {
+ virtual ~IStreamingReporter() = default;
+
+ // Implementing class must also provide the following static methods:
+ // static std::string getDescription();
+ // static std::set<Verbosity> getSupportedVerbosities()
+
+ virtual ReporterPreferences getPreferences() const = 0;
+
+ virtual void noMatchingTestCases( std::string const& spec ) = 0;
+
+ virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0;
+ virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0;
+
+ virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0;
+ virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0;
+
+ // *** experimental ***
+ virtual void benchmarkStarting( BenchmarkInfo const& ) {}
+
+ virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0;
+
+ // The return value indicates if the messages buffer should be cleared:
+ virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0;
+
+ // *** experimental ***
+ virtual void benchmarkEnded( BenchmarkStats const& ) {}
+
+ virtual void sectionEnded( SectionStats const& sectionStats ) = 0;
+ virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0;
+ virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0;
+ virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
+
+ virtual void skipTest( TestCaseInfo const& testInfo ) = 0;
+
+ // Default empty implementation provided
+ virtual void fatalErrorEncountered( StringRef name );
+
+ virtual bool isMulti() const;
+ };
+ using IStreamingReporterPtr = std::unique_ptr<IStreamingReporter>;
+
+ struct IReporterFactory {
+ virtual ~IReporterFactory();
+ virtual IStreamingReporterPtr create( ReporterConfig const& config ) const = 0;
+ virtual std::string getDescription() const = 0;
+ };
+ using IReporterFactoryPtr = std::shared_ptr<IReporterFactory>;
+
+ struct IReporterRegistry {
+ using FactoryMap = std::map<std::string, IReporterFactoryPtr>;
+ using Listeners = std::vector<IReporterFactoryPtr>;
+
+ virtual ~IReporterRegistry();
+ virtual IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const = 0;
+ virtual FactoryMap const& getFactories() const = 0;
+ virtual Listeners const& getListeners() const = 0;
+ };
+
+} // end namespace Catch
+
+// end catch_interfaces_reporter.h
+#include <algorithm>
+#include <cstring>
+#include <cfloat>
+#include <cstdio>
+#include <cassert>
+#include <memory>
+#include <ostream>
+
+namespace Catch {
+ void prepareExpandedExpression(AssertionResult& result);
+
+ // Returns double formatted as %.3f (format expected on output)
+ std::string getFormattedDuration( double duration );
+
+ template<typename DerivedT>
+ struct StreamingReporterBase : IStreamingReporter {
+
+ StreamingReporterBase( ReporterConfig const& _config )
+ : m_config( _config.fullConfig() ),
+ stream( _config.stream() )
+ {
+ m_reporterPrefs.shouldRedirectStdOut = false;
+ if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) )
+ CATCH_ERROR( "Verbosity level not supported by this reporter" );
+ }
+
+ ReporterPreferences getPreferences() const override {
+ return m_reporterPrefs;
+ }
+
+ static std::set<Verbosity> getSupportedVerbosities() {
+ return { Verbosity::Normal };
+ }
+
+ ~StreamingReporterBase() override = default;
+
+ void noMatchingTestCases(std::string const&) override {}
+
+ void testRunStarting(TestRunInfo const& _testRunInfo) override {
+ currentTestRunInfo = _testRunInfo;
+ }
+ void testGroupStarting(GroupInfo const& _groupInfo) override {
+ currentGroupInfo = _groupInfo;
+ }
+
+ void testCaseStarting(TestCaseInfo const& _testInfo) override {
+ currentTestCaseInfo = _testInfo;
+ }
+ void sectionStarting(SectionInfo const& _sectionInfo) override {
+ m_sectionStack.push_back(_sectionInfo);
+ }
+
+ void sectionEnded(SectionStats const& /* _sectionStats */) override {
+ m_sectionStack.pop_back();
+ }
+ void testCaseEnded(TestCaseStats const& /* _testCaseStats */) override {
+ currentTestCaseInfo.reset();
+ }
+ void testGroupEnded(TestGroupStats const& /* _testGroupStats */) override {
+ currentGroupInfo.reset();
+ }
+ void testRunEnded(TestRunStats const& /* _testRunStats */) override {
+ currentTestCaseInfo.reset();
+ currentGroupInfo.reset();
+ currentTestRunInfo.reset();
+ }
+
+ void skipTest(TestCaseInfo const&) override {
+ // Don't do anything with this by default.
+ // It can optionally be overridden in the derived class.
+ }
+
+ IConfigPtr m_config;
+ std::ostream& stream;
+
+ LazyStat<TestRunInfo> currentTestRunInfo;
+ LazyStat<GroupInfo> currentGroupInfo;
+ LazyStat<TestCaseInfo> currentTestCaseInfo;
+
+ std::vector<SectionInfo> m_sectionStack;
+ ReporterPreferences m_reporterPrefs;
+ };
+
+ template<typename DerivedT>
+ struct CumulativeReporterBase : IStreamingReporter {
+ template<typename T, typename ChildNodeT>
+ struct Node {
+ explicit Node( T const& _value ) : value( _value ) {}
+ virtual ~Node() {}
+
+ using ChildNodes = std::vector<std::shared_ptr<ChildNodeT>>;
+ T value;
+ ChildNodes children;
+ };
+ struct SectionNode {
+ explicit SectionNode(SectionStats const& _stats) : stats(_stats) {}
+ virtual ~SectionNode() = default;
+
+ bool operator == (SectionNode const& other) const {
+ return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo;
+ }
+ bool operator == (std::shared_ptr<SectionNode> const& other) const {
+ return operator==(*other);
+ }
+
+ SectionStats stats;
+ using ChildSections = std::vector<std::shared_ptr<SectionNode>>;
+ using Assertions = std::vector<AssertionStats>;
+ ChildSections childSections;
+ Assertions assertions;
+ std::string stdOut;
+ std::string stdErr;
+ };
+
+ struct BySectionInfo {
+ BySectionInfo( SectionInfo const& other ) : m_other( other ) {}
+ BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {}
+ bool operator() (std::shared_ptr<SectionNode> const& node) const {
+ return ((node->stats.sectionInfo.name == m_other.name) &&
+ (node->stats.sectionInfo.lineInfo == m_other.lineInfo));
+ }
+ void operator=(BySectionInfo const&) = delete;
+
+ private:
+ SectionInfo const& m_other;
+ };
+
+ using TestCaseNode = Node<TestCaseStats, SectionNode>;
+ using TestGroupNode = Node<TestGroupStats, TestCaseNode>;
+ using TestRunNode = Node<TestRunStats, TestGroupNode>;
+
+ CumulativeReporterBase( ReporterConfig const& _config )
+ : m_config( _config.fullConfig() ),
+ stream( _config.stream() )
+ {
+ m_reporterPrefs.shouldRedirectStdOut = false;
+ if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) )
+ CATCH_ERROR( "Verbosity level not supported by this reporter" );
+ }
+ ~CumulativeReporterBase() override = default;
+
+ ReporterPreferences getPreferences() const override {
+ return m_reporterPrefs;
+ }
+
+ static std::set<Verbosity> getSupportedVerbosities() {
+ return { Verbosity::Normal };
+ }
+
+ void testRunStarting( TestRunInfo const& ) override {}
+ void testGroupStarting( GroupInfo const& ) override {}
+
+ void testCaseStarting( TestCaseInfo const& ) override {}
+
+ void sectionStarting( SectionInfo const& sectionInfo ) override {
+ SectionStats incompleteStats( sectionInfo, Counts(), 0, false );
+ std::shared_ptr<SectionNode> node;
+ if( m_sectionStack.empty() ) {
+ if( !m_rootSection )
+ m_rootSection = std::make_shared<SectionNode>( incompleteStats );
+ node = m_rootSection;
+ }
+ else {
+ SectionNode& parentNode = *m_sectionStack.back();
+ auto it =
+ std::find_if( parentNode.childSections.begin(),
+ parentNode.childSections.end(),
+ BySectionInfo( sectionInfo ) );
+ if( it == parentNode.childSections.end() ) {
+ node = std::make_shared<SectionNode>( incompleteStats );
+ parentNode.childSections.push_back( node );
+ }
+ else
+ node = *it;
+ }
+ m_sectionStack.push_back( node );
+ m_deepestSection = std::move(node);
+ }
+
+ void assertionStarting(AssertionInfo const&) override {}
+
+ bool assertionEnded(AssertionStats const& assertionStats) override {
+ assert(!m_sectionStack.empty());
+ // AssertionResult holds a pointer to a temporary DecomposedExpression,
+ // which getExpandedExpression() calls to build the expression string.
+ // Our section stack copy of the assertionResult will likely outlive the
+ // temporary, so it must be expanded or discarded now to avoid calling
+ // a destroyed object later.
+ prepareExpandedExpression(const_cast<AssertionResult&>( assertionStats.assertionResult ) );
+ SectionNode& sectionNode = *m_sectionStack.back();
+ sectionNode.assertions.push_back(assertionStats);
+ return true;
+ }
+ void sectionEnded(SectionStats const& sectionStats) override {
+ assert(!m_sectionStack.empty());
+ SectionNode& node = *m_sectionStack.back();
+ node.stats = sectionStats;
+ m_sectionStack.pop_back();
+ }
+ void testCaseEnded(TestCaseStats const& testCaseStats) override {
+ auto node = std::make_shared<TestCaseNode>(testCaseStats);
+ assert(m_sectionStack.size() == 0);
+ node->children.push_back(m_rootSection);
+ m_testCases.push_back(node);
+ m_rootSection.reset();
+
+ assert(m_deepestSection);
+ m_deepestSection->stdOut = testCaseStats.stdOut;
+ m_deepestSection->stdErr = testCaseStats.stdErr;
+ }
+ void testGroupEnded(TestGroupStats const& testGroupStats) override {
+ auto node = std::make_shared<TestGroupNode>(testGroupStats);
+ node->children.swap(m_testCases);
+ m_testGroups.push_back(node);
+ }
+ void testRunEnded(TestRunStats const& testRunStats) override {
+ auto node = std::make_shared<TestRunNode>(testRunStats);
+ node->children.swap(m_testGroups);
+ m_testRuns.push_back(node);
+ testRunEndedCumulative();
+ }
+ virtual void testRunEndedCumulative() = 0;
+
+ void skipTest(TestCaseInfo const&) override {}
+
+ IConfigPtr m_config;
+ std::ostream& stream;
+ std::vector<AssertionStats> m_assertions;
+ std::vector<std::vector<std::shared_ptr<SectionNode>>> m_sections;
+ std::vector<std::shared_ptr<TestCaseNode>> m_testCases;
+ std::vector<std::shared_ptr<TestGroupNode>> m_testGroups;
+
+ std::vector<std::shared_ptr<TestRunNode>> m_testRuns;
+
+ std::shared_ptr<SectionNode> m_rootSection;
+ std::shared_ptr<SectionNode> m_deepestSection;
+ std::vector<std::shared_ptr<SectionNode>> m_sectionStack;
+ ReporterPreferences m_reporterPrefs;
+ };
+
+ template<char C>
+ char const* getLineOfChars() {
+ static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0};
+ if( !*line ) {
+ std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 );
+ line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0;
+ }
+ return line;
+ }
+
+ struct TestEventListenerBase : StreamingReporterBase<TestEventListenerBase> {
+ TestEventListenerBase( ReporterConfig const& _config );
+
+ void assertionStarting(AssertionInfo const&) override;
+ bool assertionEnded(AssertionStats const&) override;
+ };
+
+} // end namespace Catch
+
+// end catch_reporter_bases.hpp
+// start catch_console_colour.h
+
+namespace Catch {
+
+ struct Colour {
+ enum Code {
+ None = 0,
+
+ White,
+ Red,
+ Green,
+ Blue,
+ Cyan,
+ Yellow,
+ Grey,
+
+ Bright = 0x10,
+
+ BrightRed = Bright | Red,
+ BrightGreen = Bright | Green,
+ LightGrey = Bright | Grey,
+ BrightWhite = Bright | White,
+ BrightYellow = Bright | Yellow,
+
+ // By intention
+ FileName = LightGrey,
+ Warning = BrightYellow,
+ ResultError = BrightRed,
+ ResultSuccess = BrightGreen,
+ ResultExpectedFailure = Warning,
+
+ Error = BrightRed,
+ Success = Green,
+
+ OriginalExpression = Cyan,
+ ReconstructedExpression = BrightYellow,
+
+ SecondaryText = LightGrey,
+ Headers = White
+ };
+
+ // Use constructed object for RAII guard
+ Colour( Code _colourCode );
+ Colour( Colour&& other ) noexcept;
+ Colour& operator=( Colour&& other ) noexcept;
+ ~Colour();
+
+ // Use static method for one-shot changes
+ static void use( Code _colourCode );
+
+ private:
+ bool m_moved = false;
+ };
+
+ std::ostream& operator << ( std::ostream& os, Colour const& );
+
+} // end namespace Catch
+
+// end catch_console_colour.h
+// start catch_reporter_registrars.hpp
+
+
+namespace Catch {
+
+ template<typename T>
+ class ReporterRegistrar {
+
+ class ReporterFactory : public IReporterFactory {
+
+ virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override {
+ return std::unique_ptr<T>( new T( config ) );
+ }
+
+ virtual std::string getDescription() const override {
+ return T::getDescription();
+ }
+ };
+
+ public:
+
+ explicit ReporterRegistrar( std::string const& name ) {
+ getMutableRegistryHub().registerReporter( name, std::make_shared<ReporterFactory>() );
+ }
+ };
+
+ template<typename T>
+ class ListenerRegistrar {
+
+ class ListenerFactory : public IReporterFactory {
+
+ virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override {
+ return std::unique_ptr<T>( new T( config ) );
+ }
+ virtual std::string getDescription() const override {
+ return std::string();
+ }
+ };
+
+ public:
+
+ ListenerRegistrar() {
+ getMutableRegistryHub().registerListener( std::make_shared<ListenerFactory>() );
+ }
+ };
+}
+
+#if !defined(CATCH_CONFIG_DISABLE)
+
+#define CATCH_REGISTER_REPORTER( name, reporterType ) \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); } \
+ CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
+
+#define CATCH_REGISTER_LISTENER( listenerType ) \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; } \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
+#else // CATCH_CONFIG_DISABLE
+
+#define CATCH_REGISTER_REPORTER(name, reporterType)
+#define CATCH_REGISTER_LISTENER(listenerType)
+
+#endif // CATCH_CONFIG_DISABLE
+
+// end catch_reporter_registrars.hpp
+// Allow users to base their work off existing reporters
+// start catch_reporter_compact.h
+
+namespace Catch {
+
+ struct CompactReporter : StreamingReporterBase<CompactReporter> {
+
+ using StreamingReporterBase::StreamingReporterBase;
+
+ ~CompactReporter() override;
+
+ static std::string getDescription();
+
+ ReporterPreferences getPreferences() const override;
+
+ void noMatchingTestCases(std::string const& spec) override;
+
+ void assertionStarting(AssertionInfo const&) override;
+
+ bool assertionEnded(AssertionStats const& _assertionStats) override;
+
+ void sectionEnded(SectionStats const& _sectionStats) override;
+
+ void testRunEnded(TestRunStats const& _testRunStats) override;
+
+ };
+
+} // end namespace Catch
+
+// end catch_reporter_compact.h
+// start catch_reporter_console.h
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch
+ // Note that 4062 (not all labels are handled
+ // and default is missing) is enabled
+#endif
+
+namespace Catch {
+ // Fwd decls
+ struct SummaryColumn;
+ class TablePrinter;
+
+ struct ConsoleReporter : StreamingReporterBase<ConsoleReporter> {
+ std::unique_ptr<TablePrinter> m_tablePrinter;
+
+ ConsoleReporter(ReporterConfig const& config);
+ ~ConsoleReporter() override;
+ static std::string getDescription();
+
+ void noMatchingTestCases(std::string const& spec) override;
+
+ void assertionStarting(AssertionInfo const&) override;
+
+ bool assertionEnded(AssertionStats const& _assertionStats) override;
+
+ void sectionStarting(SectionInfo const& _sectionInfo) override;
+ void sectionEnded(SectionStats const& _sectionStats) override;
+
+ void benchmarkStarting(BenchmarkInfo const& info) override;
+ void benchmarkEnded(BenchmarkStats const& stats) override;
+
+ void testCaseEnded(TestCaseStats const& _testCaseStats) override;
+ void testGroupEnded(TestGroupStats const& _testGroupStats) override;
+ void testRunEnded(TestRunStats const& _testRunStats) override;
+
+ private:
+
+ void lazyPrint();
+
+ void lazyPrintWithoutClosingBenchmarkTable();
+ void lazyPrintRunInfo();
+ void lazyPrintGroupInfo();
+ void printTestCaseAndSectionHeader();
+
+ void printClosedHeader(std::string const& _name);
+ void printOpenHeader(std::string const& _name);
+
+ // if string has a : in first line will set indent to follow it on
+ // subsequent lines
+ void printHeaderString(std::string const& _string, std::size_t indent = 0);
+
+ void printTotals(Totals const& totals);
+ void printSummaryRow(std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row);
+
+ void printTotalsDivider(Totals const& totals);
+ void printSummaryDivider();
+
+ private:
+ bool m_headerPrinted = false;
+ };
+
+} // end namespace Catch
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+// end catch_reporter_console.h
+// start catch_reporter_junit.h
+
+// start catch_xmlwriter.h
+
+#include <vector>
+
+namespace Catch {
+
+ class XmlEncode {
+ public:
+ enum ForWhat { ForTextNodes, ForAttributes };
+
+ XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes );
+
+ void encodeTo( std::ostream& os ) const;
+
+ friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode );
+
+ private:
+ std::string m_str;
+ ForWhat m_forWhat;
+ };
+
+ class XmlWriter {
+ public:
+
+ class ScopedElement {
+ public:
+ ScopedElement( XmlWriter* writer );
+
+ ScopedElement( ScopedElement&& other ) noexcept;
+ ScopedElement& operator=( ScopedElement&& other ) noexcept;
+
+ ~ScopedElement();
+
+ ScopedElement& writeText( std::string const& text, bool indent = true );
+
+ template<typename T>
+ ScopedElement& writeAttribute( std::string const& name, T const& attribute ) {
+ m_writer->writeAttribute( name, attribute );
+ return *this;
+ }
+
+ private:
+ mutable XmlWriter* m_writer = nullptr;
+ };
+
+ XmlWriter( std::ostream& os = Catch::cout() );
+ ~XmlWriter();
+
+ XmlWriter( XmlWriter const& ) = delete;
+ XmlWriter& operator=( XmlWriter const& ) = delete;
+
+ XmlWriter& startElement( std::string const& name );
+
+ ScopedElement scopedElement( std::string const& name );
+
+ XmlWriter& endElement();
+
+ XmlWriter& writeAttribute( std::string const& name, std::string const& attribute );
+
+ XmlWriter& writeAttribute( std::string const& name, bool attribute );
+
+ template<typename T>
+ XmlWriter& writeAttribute( std::string const& name, T const& attribute ) {
+ ReusableStringStream rss;
+ rss << attribute;
+ return writeAttribute( name, rss.str() );
+ }
+
+ XmlWriter& writeText( std::string const& text, bool indent = true );
+
+ XmlWriter& writeComment( std::string const& text );
+
+ void writeStylesheetRef( std::string const& url );
+
+ XmlWriter& writeBlankLine();
+
+ void ensureTagClosed();
+
+ private:
+
+ void writeDeclaration();
+
+ void newlineIfNecessary();
+
+ bool m_tagIsOpen = false;
+ bool m_needsNewline = false;
+ std::vector<std::string> m_tags;
+ std::string m_indent;
+ std::ostream& m_os;
+ };
+
+}
+
+// end catch_xmlwriter.h
+namespace Catch {
+
+ class JunitReporter : public CumulativeReporterBase<JunitReporter> {
+ public:
+ JunitReporter(ReporterConfig const& _config);
+
+ ~JunitReporter() override;
+
+ static std::string getDescription();
+
+ void noMatchingTestCases(std::string const& /*spec*/) override;
+
+ void testRunStarting(TestRunInfo const& runInfo) override;
+
+ void testGroupStarting(GroupInfo const& groupInfo) override;
+
+ void testCaseStarting(TestCaseInfo const& testCaseInfo) override;
+ bool assertionEnded(AssertionStats const& assertionStats) override;
+
+ void testCaseEnded(TestCaseStats const& testCaseStats) override;
+
+ void testGroupEnded(TestGroupStats const& testGroupStats) override;
+
+ void testRunEndedCumulative() override;
+
+ void writeGroup(TestGroupNode const& groupNode, double suiteTime);
+
+ void writeTestCase(TestCaseNode const& testCaseNode);
+
+ void writeSection(std::string const& className,
+ std::string const& rootName,
+ SectionNode const& sectionNode);
+
+ void writeAssertions(SectionNode const& sectionNode);
+ void writeAssertion(AssertionStats const& stats);
+
+ XmlWriter xml;
+ Timer suiteTimer;
+ std::string stdOutForSuite;
+ std::string stdErrForSuite;
+ unsigned int unexpectedExceptions = 0;
+ bool m_okToFail = false;
+ };
+
+} // end namespace Catch
+
+// end catch_reporter_junit.h
+// start catch_reporter_xml.h
+
+namespace Catch {
+ class XmlReporter : public StreamingReporterBase<XmlReporter> {
+ public:
+ XmlReporter(ReporterConfig const& _config);
+
+ ~XmlReporter() override;
+
+ static std::string getDescription();
+
+ virtual std::string getStylesheetRef() const;
+
+ void writeSourceInfo(SourceLineInfo const& sourceInfo);
+
+ public: // StreamingReporterBase
+
+ void noMatchingTestCases(std::string const& s) override;
+
+ void testRunStarting(TestRunInfo const& testInfo) override;
+
+ void testGroupStarting(GroupInfo const& groupInfo) override;
+
+ void testCaseStarting(TestCaseInfo const& testInfo) override;
+
+ void sectionStarting(SectionInfo const& sectionInfo) override;
+
+ void assertionStarting(AssertionInfo const&) override;
+
+ bool assertionEnded(AssertionStats const& assertionStats) override;
+
+ void sectionEnded(SectionStats const& sectionStats) override;
+
+ void testCaseEnded(TestCaseStats const& testCaseStats) override;
+
+ void testGroupEnded(TestGroupStats const& testGroupStats) override;
+
+ void testRunEnded(TestRunStats const& testRunStats) override;
+
+ private:
+ Timer m_testCaseTimer;
+ XmlWriter m_xml;
+ int m_sectionDepth = 0;
+ };
+
+} // end namespace Catch
+
+// end catch_reporter_xml.h
+
+// end catch_external_interfaces.h
+#endif
+
+#endif // ! CATCH_CONFIG_IMPL_ONLY
+
+#ifdef CATCH_IMPL
+// start catch_impl.hpp
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wweak-vtables"
+#endif
+
+// Keep these here for external reporters
+// start catch_test_case_tracker.h
+
+#include <string>
+#include <vector>
+#include <memory>
+
+namespace Catch {
+namespace TestCaseTracking {
+
+ struct NameAndLocation {
+ std::string name;
+ SourceLineInfo location;
+
+ NameAndLocation( std::string const& _name, SourceLineInfo const& _location );
+ };
+
+ struct ITracker;
+
+ using ITrackerPtr = std::shared_ptr<ITracker>;
+
+ struct ITracker {
+ virtual ~ITracker();
+
+ // static queries
+ virtual NameAndLocation const& nameAndLocation() const = 0;
+
+ // dynamic queries
+ virtual bool isComplete() const = 0; // Successfully completed or failed
+ virtual bool isSuccessfullyCompleted() const = 0;
+ virtual bool isOpen() const = 0; // Started but not complete
+ virtual bool hasChildren() const = 0;
+
+ virtual ITracker& parent() = 0;
+
+ // actions
+ virtual void close() = 0; // Successfully complete
+ virtual void fail() = 0;
+ virtual void markAsNeedingAnotherRun() = 0;
+
+ virtual void addChild( ITrackerPtr const& child ) = 0;
+ virtual ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) = 0;
+ virtual void openChild() = 0;
+
+ // Debug/ checking
+ virtual bool isSectionTracker() const = 0;
+ virtual bool isIndexTracker() const = 0;
+ };
+
+ class TrackerContext {
+
+ enum RunState {
+ NotStarted,
+ Executing,
+ CompletedCycle
+ };
+
+ ITrackerPtr m_rootTracker;
+ ITracker* m_currentTracker = nullptr;
+ RunState m_runState = NotStarted;
+
+ public:
+
+ static TrackerContext& instance();
+
+ ITracker& startRun();
+ void endRun();
+
+ void startCycle();
+ void completeCycle();
+
+ bool completedCycle() const;
+ ITracker& currentTracker();
+ void setCurrentTracker( ITracker* tracker );
+ };
+
+ class TrackerBase : public ITracker {
+ protected:
+ enum CycleState {
+ NotStarted,
+ Executing,
+ ExecutingChildren,
+ NeedsAnotherRun,
+ CompletedSuccessfully,
+ Failed
+ };
+
+ using Children = std::vector<ITrackerPtr>;
+ NameAndLocation m_nameAndLocation;
+ TrackerContext& m_ctx;
+ ITracker* m_parent;
+ Children m_children;
+ CycleState m_runState = NotStarted;
+
+ public:
+ TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent );
+
+ NameAndLocation const& nameAndLocation() const override;
+ bool isComplete() const override;
+ bool isSuccessfullyCompleted() const override;
+ bool isOpen() const override;
+ bool hasChildren() const override;
+
+ void addChild( ITrackerPtr const& child ) override;
+
+ ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) override;
+ ITracker& parent() override;
+
+ void openChild() override;
+
+ bool isSectionTracker() const override;
+ bool isIndexTracker() const override;
+
+ void open();
+
+ void close() override;
+ void fail() override;
+ void markAsNeedingAnotherRun() override;
+
+ private:
+ void moveToParent();
+ void moveToThis();
+ };
+
+ class SectionTracker : public TrackerBase {
+ std::vector<std::string> m_filters;
+ public:
+ SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent );
+
+ bool isSectionTracker() const override;
+
+ static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation );
+
+ void tryOpen();
+
+ void addInitialFilters( std::vector<std::string> const& filters );
+ void addNextFilters( std::vector<std::string> const& filters );
+ };
+
+ class IndexTracker : public TrackerBase {
+ int m_size;
+ int m_index = -1;
+ public:
+ IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size );
+
+ bool isIndexTracker() const override;
+ void close() override;
+
+ static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size );
+
+ int index() const;
+
+ void moveNext();
+ };
+
+} // namespace TestCaseTracking
+
+using TestCaseTracking::ITracker;
+using TestCaseTracking::TrackerContext;
+using TestCaseTracking::SectionTracker;
+using TestCaseTracking::IndexTracker;
+
+} // namespace Catch
+
+// end catch_test_case_tracker.h
+
+// start catch_leak_detector.h
+
+namespace Catch {
+
+ struct LeakDetector {
+ LeakDetector();
+ };
+
+}
+// end catch_leak_detector.h
+// Cpp files will be included in the single-header file here
+// start catch_approx.cpp
+
+#include <cmath>
+#include <limits>
+
+namespace {
+
+// Performs equivalent check of std::fabs(lhs - rhs) <= margin
+// But without the subtraction to allow for INFINITY in comparison
+bool marginComparison(double lhs, double rhs, double margin) {
+ return (lhs + margin >= rhs) && (rhs + margin >= lhs);
+}
+
+}
+
+namespace Catch {
+namespace Detail {
+
+ Approx::Approx ( double value )
+ : m_epsilon( std::numeric_limits<float>::epsilon()*100 ),
+ m_margin( 0.0 ),
+ m_scale( 0.0 ),
+ m_value( value )
+ {}
+
+ Approx Approx::custom() {
+ return Approx( 0 );
+ }
+
+ Approx Approx::operator-() const {
+ auto temp(*this);
+ temp.m_value = -temp.m_value;
+ return temp;
+ }
+
+ std::string Approx::toString() const {
+ ReusableStringStream rss;
+ rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )";
+ return rss.str();
+ }
+
+ bool Approx::equalityComparisonImpl(const double other) const {
+ // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value
+ // Thanks to Richard Harris for his help refining the scaled margin value
+ return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(m_value)));
+ }
+
+ void Approx::setMargin(double margin) {
+ CATCH_ENFORCE(margin >= 0,
+ "Invalid Approx::margin: " << margin << '.'
+ << " Approx::Margin has to be non-negative.");
+ m_margin = margin;
+ }
+
+ void Approx::setEpsilon(double epsilon) {
+ CATCH_ENFORCE(epsilon >= 0 && epsilon <= 1.0,
+ "Invalid Approx::epsilon: " << epsilon << '.'
+ << " Approx::epsilon has to be in [0, 1]");
+ m_epsilon = epsilon;
+ }
+
+} // end namespace Detail
+
+namespace literals {
+ Detail::Approx operator "" _a(long double val) {
+ return Detail::Approx(val);
+ }
+ Detail::Approx operator "" _a(unsigned long long val) {
+ return Detail::Approx(val);
+ }
+} // end namespace literals
+
+std::string StringMaker<Catch::Detail::Approx>::convert(Catch::Detail::Approx const& value) {
+ return value.toString();
+}
+
+} // end namespace Catch
+// end catch_approx.cpp
+// start catch_assertionhandler.cpp
+
+// start catch_context.h
+
+#include <memory>
+
+namespace Catch {
+
+ struct IResultCapture;
+ struct IRunner;
+ struct IConfig;
+ struct IMutableContext;
+
+ using IConfigPtr = std::shared_ptr<IConfig const>;
+
+ struct IContext
+ {
+ virtual ~IContext();
+
+ virtual IResultCapture* getResultCapture() = 0;
+ virtual IRunner* getRunner() = 0;
+ virtual IConfigPtr const& getConfig() const = 0;
+ };
+
+ struct IMutableContext : IContext
+ {
+ virtual ~IMutableContext();
+ virtual void setResultCapture( IResultCapture* resultCapture ) = 0;
+ virtual void setRunner( IRunner* runner ) = 0;
+ virtual void setConfig( IConfigPtr const& config ) = 0;
+
+ private:
+ static IMutableContext *currentContext;
+ friend IMutableContext& getCurrentMutableContext();
+ friend void cleanUpContext();
+ static void createContext();
+ };
+
+ inline IMutableContext& getCurrentMutableContext()
+ {
+ if( !IMutableContext::currentContext )
+ IMutableContext::createContext();
+ return *IMutableContext::currentContext;
+ }
+
+ inline IContext& getCurrentContext()
+ {
+ return getCurrentMutableContext();
+ }
+
+ void cleanUpContext();
+}
+
+// end catch_context.h
+// start catch_debugger.h
+
+namespace Catch {
+ bool isDebuggerActive();
+}
+
+#ifdef CATCH_PLATFORM_MAC
+
+ #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */
+
+#elif defined(CATCH_PLATFORM_LINUX)
+ // If we can use inline assembler, do it because this allows us to break
+ // directly at the location of the failing check instead of breaking inside
+ // raise() called from it, i.e. one stack frame below.
+ #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64))
+ #define CATCH_TRAP() asm volatile ("int $3") /* NOLINT */
+ #else // Fall back to the generic way.
+ #include <signal.h>
+
+ #define CATCH_TRAP() raise(SIGTRAP)
+ #endif
+#elif defined(_MSC_VER)
+ #define CATCH_TRAP() __debugbreak()
+#elif defined(__MINGW32__)
+ extern "C" __declspec(dllimport) void __stdcall DebugBreak();
+ #define CATCH_TRAP() DebugBreak()
+#endif
+
+#ifdef CATCH_TRAP
+ #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); }
+#else
+ namespace Catch {
+ inline void doNothing() {}
+ }
+ #define CATCH_BREAK_INTO_DEBUGGER() Catch::doNothing()
+#endif
+
+// end catch_debugger.h
+// start catch_run_context.h
+
+// start catch_fatal_condition.h
+
+// start catch_windows_h_proxy.h
+
+
+#if defined(CATCH_PLATFORM_WINDOWS)
+
+#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX)
+# define CATCH_DEFINED_NOMINMAX
+# define NOMINMAX
+#endif
+#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN)
+# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+
+#ifdef __AFXDLL
+#include <AfxWin.h>
+#else
+#include <windows.h>
+#endif
+
+#ifdef CATCH_DEFINED_NOMINMAX
+# undef NOMINMAX
+#endif
+#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN
+# undef WIN32_LEAN_AND_MEAN
+#endif
+
+#endif // defined(CATCH_PLATFORM_WINDOWS)
+
+// end catch_windows_h_proxy.h
+#if defined( CATCH_CONFIG_WINDOWS_SEH )
+
+namespace Catch {
+
+ struct FatalConditionHandler {
+
+ static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo);
+ FatalConditionHandler();
+ static void reset();
+ ~FatalConditionHandler();
+
+ private:
+ static bool isSet;
+ static ULONG guaranteeSize;
+ static PVOID exceptionHandlerHandle;
+ };
+
+} // namespace Catch
+
+#elif defined ( CATCH_CONFIG_POSIX_SIGNALS )
+
+#include <signal.h>
+
+namespace Catch {
+
+ struct FatalConditionHandler {
+
+ static bool isSet;
+ static struct sigaction oldSigActions[];
+ static stack_t oldSigStack;
+ static char altStackMem[];
+
+ static void handleSignal( int sig );
+
+ FatalConditionHandler();
+ ~FatalConditionHandler();
+ static void reset();
+ };
+
+} // namespace Catch
+
+#else
+
+namespace Catch {
+ struct FatalConditionHandler {
+ void reset();
+ };
+}
+
+#endif
+
+// end catch_fatal_condition.h
+#include <string>
+
+namespace Catch {
+
+ struct IMutableContext;
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ class RunContext : public IResultCapture, public IRunner {
+
+ public:
+ RunContext( RunContext const& ) = delete;
+ RunContext& operator =( RunContext const& ) = delete;
+
+ explicit RunContext( IConfigPtr const& _config, IStreamingReporterPtr&& reporter );
+
+ ~RunContext() override;
+
+ void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount );
+ void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount );
+
+ Totals runTest(TestCase const& testCase);
+
+ IConfigPtr config() const;
+ IStreamingReporter& reporter() const;
+
+ public: // IResultCapture
+
+ // Assertion handlers
+ void handleExpr
+ ( AssertionInfo const& info,
+ ITransientExpression const& expr,
+ AssertionReaction& reaction ) override;
+ void handleMessage
+ ( AssertionInfo const& info,
+ ResultWas::OfType resultType,
+ StringRef const& message,
+ AssertionReaction& reaction ) override;
+ void handleUnexpectedExceptionNotThrown
+ ( AssertionInfo const& info,
+ AssertionReaction& reaction ) override;
+ void handleUnexpectedInflightException
+ ( AssertionInfo const& info,
+ std::string const& message,
+ AssertionReaction& reaction ) override;
+ void handleIncomplete
+ ( AssertionInfo const& info ) override;
+ void handleNonExpr
+ ( AssertionInfo const &info,
+ ResultWas::OfType resultType,
+ AssertionReaction &reaction ) override;
+
+ bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override;
+
+ void sectionEnded( SectionEndInfo const& endInfo ) override;
+ void sectionEndedEarly( SectionEndInfo const& endInfo ) override;
+
+ auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override;
+
+ void benchmarkStarting( BenchmarkInfo const& info ) override;
+ void benchmarkEnded( BenchmarkStats const& stats ) override;
+
+ void pushScopedMessage( MessageInfo const& message ) override;
+ void popScopedMessage( MessageInfo const& message ) override;
+
+ std::string getCurrentTestName() const override;
+
+ const AssertionResult* getLastResult() const override;
+
+ void exceptionEarlyReported() override;
+
+ void handleFatalErrorCondition( StringRef message ) override;
+
+ bool lastAssertionPassed() override;
+
+ void assertionPassed() override;
+
+ public:
+ // !TBD We need to do this another way!
+ bool aborting() const final;
+
+ private:
+
+ void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr );
+ void invokeActiveTestCase();
+
+ void resetAssertionInfo();
+ bool testForMissingAssertions( Counts& assertions );
+
+ void assertionEnded( AssertionResult const& result );
+ void reportExpr
+ ( AssertionInfo const &info,
+ ResultWas::OfType resultType,
+ ITransientExpression const *expr,
+ bool negated );
+
+ void populateReaction( AssertionReaction& reaction );
+
+ private:
+
+ void handleUnfinishedSections();
+
+ TestRunInfo m_runInfo;
+ IMutableContext& m_context;
+ TestCase const* m_activeTestCase = nullptr;
+ ITracker* m_testCaseTracker;
+ Option<AssertionResult> m_lastResult;
+
+ IConfigPtr m_config;
+ Totals m_totals;
+ IStreamingReporterPtr m_reporter;
+ std::vector<MessageInfo> m_messages;
+ AssertionInfo m_lastAssertionInfo;
+ std::vector<SectionEndInfo> m_unfinishedSections;
+ std::vector<ITracker*> m_activeSections;
+ TrackerContext m_trackerContext;
+ bool m_lastAssertionPassed = false;
+ bool m_shouldReportUnexpected = true;
+ bool m_includeSuccessfulResults;
+ };
+
+} // end namespace Catch
+
+// end catch_run_context.h
+namespace Catch {
+
+ namespace {
+ auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& {
+ expr.streamReconstructedExpression( os );
+ return os;
+ }
+ }
+
+ LazyExpression::LazyExpression( bool isNegated )
+ : m_isNegated( isNegated )
+ {}
+
+ LazyExpression::LazyExpression( LazyExpression const& other ) : m_isNegated( other.m_isNegated ) {}
+
+ LazyExpression::operator bool() const {
+ return m_transientExpression != nullptr;
+ }
+
+ auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream& {
+ if( lazyExpr.m_isNegated )
+ os << "!";
+
+ if( lazyExpr ) {
+ if( lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression() )
+ os << "(" << *lazyExpr.m_transientExpression << ")";
+ else
+ os << *lazyExpr.m_transientExpression;
+ }
+ else {
+ os << "{** error - unchecked empty expression requested **}";
+ }
+ return os;
+ }
+
+ AssertionHandler::AssertionHandler
+ ( StringRef const& macroName,
+ SourceLineInfo const& lineInfo,
+ StringRef capturedExpression,
+ ResultDisposition::Flags resultDisposition )
+ : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition },
+ m_resultCapture( getResultCapture() )
+ {}
+
+ void AssertionHandler::handleExpr( ITransientExpression const& expr ) {
+ m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction );
+ }
+ void AssertionHandler::handleMessage(ResultWas::OfType resultType, StringRef const& message) {
+ m_resultCapture.handleMessage( m_assertionInfo, resultType, message, m_reaction );
+ }
+
+ auto AssertionHandler::allowThrows() const -> bool {
+ return getCurrentContext().getConfig()->allowThrows();
+ }
+
+ void AssertionHandler::complete() {
+ setCompleted();
+ if( m_reaction.shouldDebugBreak ) {
+
+ // If you find your debugger stopping you here then go one level up on the
+ // call-stack for the code that caused it (typically a failed assertion)
+
+ // (To go back to the test and change execution, jump over the throw, next)
+ CATCH_BREAK_INTO_DEBUGGER();
+ }
+ if (m_reaction.shouldThrow) {
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+ throw Catch::TestFailureException();
+#else
+ CATCH_ERROR( "Test failure requires aborting test!" );
+#endif
+ }
+ }
+ void AssertionHandler::setCompleted() {
+ m_completed = true;
+ }
+
+ void AssertionHandler::handleUnexpectedInflightException() {
+ m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction );
+ }
+
+ void AssertionHandler::handleExceptionThrownAsExpected() {
+ m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
+ }
+ void AssertionHandler::handleExceptionNotThrownAsExpected() {
+ m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
+ }
+
+ void AssertionHandler::handleUnexpectedExceptionNotThrown() {
+ m_resultCapture.handleUnexpectedExceptionNotThrown( m_assertionInfo, m_reaction );
+ }
+
+ void AssertionHandler::handleThrowingCallSkipped() {
+ m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
+ }
+
+ // This is the overload that takes a string and infers the Equals matcher from it
+ // The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp
+ void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString ) {
+ handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString );
+ }
+
+} // namespace Catch
+// end catch_assertionhandler.cpp
+// start catch_assertionresult.cpp
+
+namespace Catch {
+ AssertionResultData::AssertionResultData(ResultWas::OfType _resultType, LazyExpression const & _lazyExpression):
+ lazyExpression(_lazyExpression),
+ resultType(_resultType) {}
+
+ std::string AssertionResultData::reconstructExpression() const {
+
+ if( reconstructedExpression.empty() ) {
+ if( lazyExpression ) {
+ ReusableStringStream rss;
+ rss << lazyExpression;
+ reconstructedExpression = rss.str();
+ }
+ }
+ return reconstructedExpression;
+ }
+
+ AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data )
+ : m_info( info ),
+ m_resultData( data )
+ {}
+
+ // Result was a success
+ bool AssertionResult::succeeded() const {
+ return Catch::isOk( m_resultData.resultType );
+ }
+
+ // Result was a success, or failure is suppressed
+ bool AssertionResult::isOk() const {
+ return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition );
+ }
+
+ ResultWas::OfType AssertionResult::getResultType() const {
+ return m_resultData.resultType;
+ }
+
+ bool AssertionResult::hasExpression() const {
+ return m_info.capturedExpression[0] != 0;
+ }
+
+ bool AssertionResult::hasMessage() const {
+ return !m_resultData.message.empty();
+ }
+
+ std::string AssertionResult::getExpression() const {
+ if( isFalseTest( m_info.resultDisposition ) )
+ return "!(" + m_info.capturedExpression + ")";
+ else
+ return m_info.capturedExpression;
+ }
+
+ std::string AssertionResult::getExpressionInMacro() const {
+ std::string expr;
+ if( m_info.macroName[0] == 0 )
+ expr = m_info.capturedExpression;
+ else {
+ expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
+ expr += m_info.macroName;
+ expr += "( ";
+ expr += m_info.capturedExpression;
+ expr += " )";
+ }
+ return expr;
+ }
+
+ bool AssertionResult::hasExpandedExpression() const {
+ return hasExpression() && getExpandedExpression() != getExpression();
+ }
+
+ std::string AssertionResult::getExpandedExpression() const {
+ std::string expr = m_resultData.reconstructExpression();
+ return expr.empty()
+ ? getExpression()
+ : expr;
+ }
+
+ std::string AssertionResult::getMessage() const {
+ return m_resultData.message;
+ }
+ SourceLineInfo AssertionResult::getSourceInfo() const {
+ return m_info.lineInfo;
+ }
+
+ StringRef AssertionResult::getTestMacroName() const {
+ return m_info.macroName;
+ }
+
+} // end namespace Catch
+// end catch_assertionresult.cpp
+// start catch_benchmark.cpp
+
+namespace Catch {
+
+ auto BenchmarkLooper::getResolution() -> uint64_t {
+ return getEstimatedClockResolution() * getCurrentContext().getConfig()->benchmarkResolutionMultiple();
+ }
+
+ void BenchmarkLooper::reportStart() {
+ getResultCapture().benchmarkStarting( { m_name } );
+ }
+ auto BenchmarkLooper::needsMoreIterations() -> bool {
+ auto elapsed = m_timer.getElapsedNanoseconds();
+
+ // Exponentially increasing iterations until we're confident in our timer resolution
+ if( elapsed < m_resolution ) {
+ m_iterationsToRun *= 10;
+ return true;
+ }
+
+ getResultCapture().benchmarkEnded( { { m_name }, m_count, elapsed } );
+ return false;
+ }
+
+} // end namespace Catch
+// end catch_benchmark.cpp
+// start catch_capture_matchers.cpp
+
+namespace Catch {
+
+ using StringMatcher = Matchers::Impl::MatcherBase<std::string>;
+
+ // This is the general overload that takes a any string matcher
+ // There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers
+ // the Equals matcher (so the header does not mention matchers)
+ void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString ) {
+ std::string exceptionMessage = Catch::translateActiveException();
+ MatchExpr<std::string, StringMatcher const&> expr( exceptionMessage, matcher, matcherString );
+ handler.handleExpr( expr );
+ }
+
+} // namespace Catch
+// end catch_capture_matchers.cpp
+// start catch_commandline.cpp
+
+// start catch_commandline.h
+
+// start catch_clara.h
+
+// Use Catch's value for console width (store Clara's off to the side, if present)
+#ifdef CLARA_CONFIG_CONSOLE_WIDTH
+#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH
+#undef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH
+#endif
+#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH-1
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wweak-vtables"
+#pragma clang diagnostic ignored "-Wexit-time-destructors"
+#pragma clang diagnostic ignored "-Wshadow"
+#endif
+
+// start clara.hpp
+// Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
+//
+// 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 https://github.com/philsquared/Clara for more details
+
+// Clara v1.1.4
+
+
+#ifndef CATCH_CLARA_CONFIG_CONSOLE_WIDTH
+#define CATCH_CLARA_CONFIG_CONSOLE_WIDTH 80
+#endif
+
+#ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH
+#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CLARA_CONFIG_CONSOLE_WIDTH
+#endif
+
+#ifndef CLARA_CONFIG_OPTIONAL_TYPE
+#ifdef __has_include
+#if __has_include(<optional>) && __cplusplus >= 201703L
+#include <optional>
+#define CLARA_CONFIG_OPTIONAL_TYPE std::optional
+#endif
+#endif
+#endif
+
+// ----------- #included from clara_textflow.hpp -----------
+
+// TextFlowCpp
+//
+// A single-header library for wrapping and laying out basic text, by Phil Nash
+//
+// This work is licensed under the BSD 2-Clause license.
+// See the accompanying LICENSE file, or the one at https://opensource.org/licenses/BSD-2-Clause
+//
+// This project is hosted at https://github.com/philsquared/textflowcpp
+
+
+#include <cassert>
+#include <ostream>
+#include <sstream>
+#include <vector>
+
+#ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH
+#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH 80
+#endif
+
+namespace Catch { namespace clara { namespace TextFlow {
+
+ inline auto isWhitespace( char c ) -> bool {
+ static std::string chars = " \t\n\r";
+ return chars.find( c ) != std::string::npos;
+ }
+ inline auto isBreakableBefore( char c ) -> bool {
+ static std::string chars = "[({<|";
+ return chars.find( c ) != std::string::npos;
+ }
+ inline auto isBreakableAfter( char c ) -> bool {
+ static std::string chars = "])}>.,:;*+-=&/\\";
+ return chars.find( c ) != std::string::npos;
+ }
+
+ class Columns;
+
+ class Column {
+ std::vector<std::string> m_strings;
+ size_t m_width = CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH;
+ size_t m_indent = 0;
+ size_t m_initialIndent = std::string::npos;
+
+ public:
+ class iterator {
+ friend Column;
+
+ Column const& m_column;
+ size_t m_stringIndex = 0;
+ size_t m_pos = 0;
+
+ size_t m_len = 0;
+ size_t m_end = 0;
+ bool m_suffix = false;
+
+ iterator( Column const& column, size_t stringIndex )
+ : m_column( column ),
+ m_stringIndex( stringIndex )
+ {}
+
+ auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; }
+
+ auto isBoundary( size_t at ) const -> bool {
+ assert( at > 0 );
+ assert( at <= line().size() );
+
+ return at == line().size() ||
+ ( isWhitespace( line()[at] ) && !isWhitespace( line()[at-1] ) ) ||
+ isBreakableBefore( line()[at] ) ||
+ isBreakableAfter( line()[at-1] );
+ }
+
+ void calcLength() {
+ assert( m_stringIndex < m_column.m_strings.size() );
+
+ m_suffix = false;
+ auto width = m_column.m_width-indent();
+ m_end = m_pos;
+ while( m_end < line().size() && line()[m_end] != '\n' )
+ ++m_end;
+
+ if( m_end < m_pos + width ) {
+ m_len = m_end - m_pos;
+ }
+ else {
+ size_t len = width;
+ while (len > 0 && !isBoundary(m_pos + len))
+ --len;
+ while (len > 0 && isWhitespace( line()[m_pos + len - 1] ))
+ --len;
+
+ if (len > 0) {
+ m_len = len;
+ } else {
+ m_suffix = true;
+ m_len = width - 1;
+ }
+ }
+ }
+
+ auto indent() const -> size_t {
+ auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos;
+ return initial == std::string::npos ? m_column.m_indent : initial;
+ }
+
+ auto addIndentAndSuffix(std::string const &plain) const -> std::string {
+ return std::string( indent(), ' ' ) + (m_suffix ? plain + "-" : plain);
+ }
+
+ public:
+ explicit iterator( Column const& column ) : m_column( column ) {
+ assert( m_column.m_width > m_column.m_indent );
+ assert( m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent );
+ calcLength();
+ if( m_len == 0 )
+ m_stringIndex++; // Empty string
+ }
+
+ auto operator *() const -> std::string {
+ assert( m_stringIndex < m_column.m_strings.size() );
+ assert( m_pos <= m_end );
+ if( m_pos + m_column.m_width < m_end )
+ return addIndentAndSuffix(line().substr(m_pos, m_len));
+ else
+ return addIndentAndSuffix(line().substr(m_pos, m_end - m_pos));
+ }
+
+ auto operator ++() -> iterator& {
+ m_pos += m_len;
+ if( m_pos < line().size() && line()[m_pos] == '\n' )
+ m_pos += 1;
+ else
+ while( m_pos < line().size() && isWhitespace( line()[m_pos] ) )
+ ++m_pos;
+
+ if( m_pos == line().size() ) {
+ m_pos = 0;
+ ++m_stringIndex;
+ }
+ if( m_stringIndex < m_column.m_strings.size() )
+ calcLength();
+ return *this;
+ }
+ auto operator ++(int) -> iterator {
+ iterator prev( *this );
+ operator++();
+ return prev;
+ }
+
+ auto operator ==( iterator const& other ) const -> bool {
+ return
+ m_pos == other.m_pos &&
+ m_stringIndex == other.m_stringIndex &&
+ &m_column == &other.m_column;
+ }
+ auto operator !=( iterator const& other ) const -> bool {
+ return !operator==( other );
+ }
+ };
+ using const_iterator = iterator;
+
+ explicit Column( std::string const& text ) { m_strings.push_back( text ); }
+
+ auto width( size_t newWidth ) -> Column& {
+ assert( newWidth > 0 );
+ m_width = newWidth;
+ return *this;
+ }
+ auto indent( size_t newIndent ) -> Column& {
+ m_indent = newIndent;
+ return *this;
+ }
+ auto initialIndent( size_t newIndent ) -> Column& {
+ m_initialIndent = newIndent;
+ return *this;
+ }
+
+ auto width() const -> size_t { return m_width; }
+ auto begin() const -> iterator { return iterator( *this ); }
+ auto end() const -> iterator { return { *this, m_strings.size() }; }
+
+ inline friend std::ostream& operator << ( std::ostream& os, Column const& col ) {
+ bool first = true;
+ for( auto line : col ) {
+ if( first )
+ first = false;
+ else
+ os << "\n";
+ os << line;
+ }
+ return os;
+ }
+
+ auto operator + ( Column const& other ) -> Columns;
+
+ auto toString() const -> std::string {
+ std::ostringstream oss;
+ oss << *this;
+ return oss.str();
+ }
+ };
+
+ class Spacer : public Column {
+
+ public:
+ explicit Spacer( size_t spaceWidth ) : Column( "" ) {
+ width( spaceWidth );
+ }
+ };
+
+ class Columns {
+ std::vector<Column> m_columns;
+
+ public:
+
+ class iterator {
+ friend Columns;
+ struct EndTag {};
+
+ std::vector<Column> const& m_columns;
+ std::vector<Column::iterator> m_iterators;
+ size_t m_activeIterators;
+
+ iterator( Columns const& columns, EndTag )
+ : m_columns( columns.m_columns ),
+ m_activeIterators( 0 )
+ {
+ m_iterators.reserve( m_columns.size() );
+
+ for( auto const& col : m_columns )
+ m_iterators.push_back( col.end() );
+ }
+
+ public:
+ explicit iterator( Columns const& columns )
+ : m_columns( columns.m_columns ),
+ m_activeIterators( m_columns.size() )
+ {
+ m_iterators.reserve( m_columns.size() );
+
+ for( auto const& col : m_columns )
+ m_iterators.push_back( col.begin() );
+ }
+
+ auto operator ==( iterator const& other ) const -> bool {
+ return m_iterators == other.m_iterators;
+ }
+ auto operator !=( iterator const& other ) const -> bool {
+ return m_iterators != other.m_iterators;
+ }
+ auto operator *() const -> std::string {
+ std::string row, padding;
+
+ for( size_t i = 0; i < m_columns.size(); ++i ) {
+ auto width = m_columns[i].width();
+ if( m_iterators[i] != m_columns[i].end() ) {
+ std::string col = *m_iterators[i];
+ row += padding + col;
+ if( col.size() < width )
+ padding = std::string( width - col.size(), ' ' );
+ else
+ padding = "";
+ }
+ else {
+ padding += std::string( width, ' ' );
+ }
+ }
+ return row;
+ }
+ auto operator ++() -> iterator& {
+ for( size_t i = 0; i < m_columns.size(); ++i ) {
+ if (m_iterators[i] != m_columns[i].end())
+ ++m_iterators[i];
+ }
+ return *this;
+ }
+ auto operator ++(int) -> iterator {
+ iterator prev( *this );
+ operator++();
+ return prev;
+ }
+ };
+ using const_iterator = iterator;
+
+ auto begin() const -> iterator { return iterator( *this ); }
+ auto end() const -> iterator { return { *this, iterator::EndTag() }; }
+
+ auto operator += ( Column const& col ) -> Columns& {
+ m_columns.push_back( col );
+ return *this;
+ }
+ auto operator + ( Column const& col ) -> Columns {
+ Columns combined = *this;
+ combined += col;
+ return combined;
+ }
+
+ inline friend std::ostream& operator << ( std::ostream& os, Columns const& cols ) {
+
+ bool first = true;
+ for( auto line : cols ) {
+ if( first )
+ first = false;
+ else
+ os << "\n";
+ os << line;
+ }
+ return os;
+ }
+
+ auto toString() const -> std::string {
+ std::ostringstream oss;
+ oss << *this;
+ return oss.str();
+ }
+ };
+
+ inline auto Column::operator + ( Column const& other ) -> Columns {
+ Columns cols;
+ cols += *this;
+ cols += other;
+ return cols;
+ }
+}}} // namespace Catch::clara::TextFlow
+
+// ----------- end of #include from clara_textflow.hpp -----------
+// ........... back in clara.hpp
+
+#include <memory>
+#include <set>
+#include <algorithm>
+
+#if !defined(CATCH_PLATFORM_WINDOWS) && ( defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) )
+#define CATCH_PLATFORM_WINDOWS
+#endif
+
+namespace Catch { namespace clara {
+namespace detail {
+
+ // Traits for extracting arg and return type of lambdas (for single argument lambdas)
+ template<typename L>
+ struct UnaryLambdaTraits : UnaryLambdaTraits<decltype( &L::operator() )> {};
+
+ template<typename ClassT, typename ReturnT, typename... Args>
+ struct UnaryLambdaTraits<ReturnT( ClassT::* )( Args... ) const> {
+ static const bool isValid = false;
+ };
+
+ template<typename ClassT, typename ReturnT, typename ArgT>
+ struct UnaryLambdaTraits<ReturnT( ClassT::* )( ArgT ) const> {
+ static const bool isValid = true;
+ using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type;
+ using ReturnType = ReturnT;
+ };
+
+ class TokenStream;
+
+ // Transport for raw args (copied from main args, or supplied via init list for testing)
+ class Args {
+ friend TokenStream;
+ std::string m_exeName;
+ std::vector<std::string> m_args;
+
+ public:
+ Args( int argc, char const* const* argv )
+ : m_exeName(argv[0]),
+ m_args(argv + 1, argv + argc) {}
+
+ Args( std::initializer_list<std::string> args )
+ : m_exeName( *args.begin() ),
+ m_args( args.begin()+1, args.end() )
+ {}
+
+ auto exeName() const -> std::string {
+ return m_exeName;
+ }
+ };
+
+ // Wraps a token coming from a token stream. These may not directly correspond to strings as a single string
+ // may encode an option + its argument if the : or = form is used
+ enum class TokenType {
+ Option, Argument
+ };
+ struct Token {
+ TokenType type;
+ std::string token;
+ };
+
+ inline auto isOptPrefix( char c ) -> bool {
+ return c == '-'
+#ifdef CATCH_PLATFORM_WINDOWS
+ || c == '/'
+#endif
+ ;
+ }
+
+ // Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled
+ class TokenStream {
+ using Iterator = std::vector<std::string>::const_iterator;
+ Iterator it;
+ Iterator itEnd;
+ std::vector<Token> m_tokenBuffer;
+
+ void loadBuffer() {
+ m_tokenBuffer.resize( 0 );
+
+ // Skip any empty strings
+ while( it != itEnd && it->empty() )
+ ++it;
+
+ if( it != itEnd ) {
+ auto const &next = *it;
+ if( isOptPrefix( next[0] ) ) {
+ auto delimiterPos = next.find_first_of( " :=" );
+ if( delimiterPos != std::string::npos ) {
+ m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } );
+ m_tokenBuffer.push_back( { TokenType::Argument, next.substr( delimiterPos + 1 ) } );
+ } else {
+ if( next[1] != '-' && next.size() > 2 ) {
+ std::string opt = "- ";
+ for( size_t i = 1; i < next.size(); ++i ) {
+ opt[1] = next[i];
+ m_tokenBuffer.push_back( { TokenType::Option, opt } );
+ }
+ } else {
+ m_tokenBuffer.push_back( { TokenType::Option, next } );
+ }
+ }
+ } else {
+ m_tokenBuffer.push_back( { TokenType::Argument, next } );
+ }
+ }
+ }
+
+ public:
+ explicit TokenStream( Args const &args ) : TokenStream( args.m_args.begin(), args.m_args.end() ) {}
+
+ TokenStream( Iterator it, Iterator itEnd ) : it( it ), itEnd( itEnd ) {
+ loadBuffer();
+ }
+
+ explicit operator bool() const {
+ return !m_tokenBuffer.empty() || it != itEnd;
+ }
+
+ auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); }
+
+ auto operator*() const -> Token {
+ assert( !m_tokenBuffer.empty() );
+ return m_tokenBuffer.front();
+ }
+
+ auto operator->() const -> Token const * {
+ assert( !m_tokenBuffer.empty() );
+ return &m_tokenBuffer.front();
+ }
+
+ auto operator++() -> TokenStream & {
+ if( m_tokenBuffer.size() >= 2 ) {
+ m_tokenBuffer.erase( m_tokenBuffer.begin() );
+ } else {
+ if( it != itEnd )
+ ++it;
+ loadBuffer();
+ }
+ return *this;
+ }
+ };
+
+ class ResultBase {
+ public:
+ enum Type {
+ Ok, LogicError, RuntimeError
+ };
+
+ protected:
+ ResultBase( Type type ) : m_type( type ) {}
+ virtual ~ResultBase() = default;
+
+ virtual void enforceOk() const = 0;
+
+ Type m_type;
+ };
+
+ template<typename T>
+ class ResultValueBase : public ResultBase {
+ public:
+ auto value() const -> T const & {
+ enforceOk();
+ return m_value;
+ }
+
+ protected:
+ ResultValueBase( Type type ) : ResultBase( type ) {}
+
+ ResultValueBase( ResultValueBase const &other ) : ResultBase( other ) {
+ if( m_type == ResultBase::Ok )
+ new( &m_value ) T( other.m_value );
+ }
+
+ ResultValueBase( Type, T const &value ) : ResultBase( Ok ) {
+ new( &m_value ) T( value );
+ }
+
+ auto operator=( ResultValueBase const &other ) -> ResultValueBase & {
+ if( m_type == ResultBase::Ok )
+ m_value.~T();
+ ResultBase::operator=(other);
+ if( m_type == ResultBase::Ok )
+ new( &m_value ) T( other.m_value );
+ return *this;
+ }
+
+ ~ResultValueBase() override {
+ if( m_type == Ok )
+ m_value.~T();
+ }
+
+ union {
+ T m_value;
+ };
+ };
+
+ template<>
+ class ResultValueBase<void> : public ResultBase {
+ protected:
+ using ResultBase::ResultBase;
+ };
+
+ template<typename T = void>
+ class BasicResult : public ResultValueBase<T> {
+ public:
+ template<typename U>
+ explicit BasicResult( BasicResult<U> const &other )
+ : ResultValueBase<T>( other.type() ),
+ m_errorMessage( other.errorMessage() )
+ {
+ assert( type() != ResultBase::Ok );
+ }
+
+ template<typename U>
+ static auto ok( U const &value ) -> BasicResult { return { ResultBase::Ok, value }; }
+ static auto ok() -> BasicResult { return { ResultBase::Ok }; }
+ static auto logicError( std::string const &message ) -> BasicResult { return { ResultBase::LogicError, message }; }
+ static auto runtimeError( std::string const &message ) -> BasicResult { return { ResultBase::RuntimeError, message }; }
+
+ explicit operator bool() const { return m_type == ResultBase::Ok; }
+ auto type() const -> ResultBase::Type { return m_type; }
+ auto errorMessage() const -> std::string { return m_errorMessage; }
+
+ protected:
+ void enforceOk() const override {
+
+ // Errors shouldn't reach this point, but if they do
+ // the actual error message will be in m_errorMessage
+ assert( m_type != ResultBase::LogicError );
+ assert( m_type != ResultBase::RuntimeError );
+ if( m_type != ResultBase::Ok )
+ std::abort();
+ }
+
+ std::string m_errorMessage; // Only populated if resultType is an error
+
+ BasicResult( ResultBase::Type type, std::string const &message )
+ : ResultValueBase<T>(type),
+ m_errorMessage(message)
+ {
+ assert( m_type != ResultBase::Ok );
+ }
+
+ using ResultValueBase<T>::ResultValueBase;
+ using ResultBase::m_type;
+ };
+
+ enum class ParseResultType {
+ Matched, NoMatch, ShortCircuitAll, ShortCircuitSame
+ };
+
+ class ParseState {
+ public:
+
+ ParseState( ParseResultType type, TokenStream const &remainingTokens )
+ : m_type(type),
+ m_remainingTokens( remainingTokens )
+ {}
+
+ auto type() const -> ParseResultType { return m_type; }
+ auto remainingTokens() const -> TokenStream { return m_remainingTokens; }
+
+ private:
+ ParseResultType m_type;
+ TokenStream m_remainingTokens;
+ };
+
+ using Result = BasicResult<void>;
+ using ParserResult = BasicResult<ParseResultType>;
+ using InternalParseResult = BasicResult<ParseState>;
+
+ struct HelpColumns {
+ std::string left;
+ std::string right;
+ };
+
+ template<typename T>
+ inline auto convertInto( std::string const &source, T& target ) -> ParserResult {
+ std::stringstream ss;
+ ss << source;
+ ss >> target;
+ if( ss.fail() )
+ return ParserResult::runtimeError( "Unable to convert '" + source + "' to destination type" );
+ else
+ return ParserResult::ok( ParseResultType::Matched );
+ }
+ inline auto convertInto( std::string const &source, std::string& target ) -> ParserResult {
+ target = source;
+ return ParserResult::ok( ParseResultType::Matched );
+ }
+ inline auto convertInto( std::string const &source, bool &target ) -> ParserResult {
+ std::string srcLC = source;
+ std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast<char>( ::tolower(c) ); } );
+ if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on")
+ target = true;
+ else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off")
+ target = false;
+ else
+ return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" );
+ return ParserResult::ok( ParseResultType::Matched );
+ }
+#ifdef CLARA_CONFIG_OPTIONAL_TYPE
+ template<typename T>
+ inline auto convertInto( std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE<T>& target ) -> ParserResult {
+ T temp;
+ auto result = convertInto( source, temp );
+ if( result )
+ target = std::move(temp);
+ return result;
+ }
+#endif // CLARA_CONFIG_OPTIONAL_TYPE
+
+ struct NonCopyable {
+ NonCopyable() = default;
+ NonCopyable( NonCopyable const & ) = delete;
+ NonCopyable( NonCopyable && ) = delete;
+ NonCopyable &operator=( NonCopyable const & ) = delete;
+ NonCopyable &operator=( NonCopyable && ) = delete;
+ };
+
+ struct BoundRef : NonCopyable {
+ virtual ~BoundRef() = default;
+ virtual auto isContainer() const -> bool { return false; }
+ virtual auto isFlag() const -> bool { return false; }
+ };
+ struct BoundValueRefBase : BoundRef {
+ virtual auto setValue( std::string const &arg ) -> ParserResult = 0;
+ };
+ struct BoundFlagRefBase : BoundRef {
+ virtual auto setFlag( bool flag ) -> ParserResult = 0;
+ virtual auto isFlag() const -> bool { return true; }
+ };
+
+ template<typename T>
+ struct BoundValueRef : BoundValueRefBase {
+ T &m_ref;
+
+ explicit BoundValueRef( T &ref ) : m_ref( ref ) {}
+
+ auto setValue( std::string const &arg ) -> ParserResult override {
+ return convertInto( arg, m_ref );
+ }
+ };
+
+ template<typename T>
+ struct BoundValueRef<std::vector<T>> : BoundValueRefBase {
+ std::vector<T> &m_ref;
+
+ explicit BoundValueRef( std::vector<T> &ref ) : m_ref( ref ) {}
+
+ auto isContainer() const -> bool override { return true; }
+
+ auto setValue( std::string const &arg ) -> ParserResult override {
+ T temp;
+ auto result = convertInto( arg, temp );
+ if( result )
+ m_ref.push_back( temp );
+ return result;
+ }
+ };
+
+ struct BoundFlagRef : BoundFlagRefBase {
+ bool &m_ref;
+
+ explicit BoundFlagRef( bool &ref ) : m_ref( ref ) {}
+
+ auto setFlag( bool flag ) -> ParserResult override {
+ m_ref = flag;
+ return ParserResult::ok( ParseResultType::Matched );
+ }
+ };
+
+ template<typename ReturnType>
+ struct LambdaInvoker {
+ static_assert( std::is_same<ReturnType, ParserResult>::value, "Lambda must return void or clara::ParserResult" );
+
+ template<typename L, typename ArgType>
+ static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult {
+ return lambda( arg );
+ }
+ };
+
+ template<>
+ struct LambdaInvoker<void> {
+ template<typename L, typename ArgType>
+ static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult {
+ lambda( arg );
+ return ParserResult::ok( ParseResultType::Matched );
+ }
+ };
+
+ template<typename ArgType, typename L>
+ inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult {
+ ArgType temp{};
+ auto result = convertInto( arg, temp );
+ return !result
+ ? result
+ : LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( lambda, temp );
+ }
+
+ template<typename L>
+ struct BoundLambda : BoundValueRefBase {
+ L m_lambda;
+
+ static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" );
+ explicit BoundLambda( L const &lambda ) : m_lambda( lambda ) {}
+
+ auto setValue( std::string const &arg ) -> ParserResult override {
+ return invokeLambda<typename UnaryLambdaTraits<L>::ArgType>( m_lambda, arg );
+ }
+ };
+
+ template<typename L>
+ struct BoundFlagLambda : BoundFlagRefBase {
+ L m_lambda;
+
+ static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" );
+ static_assert( std::is_same<typename UnaryLambdaTraits<L>::ArgType, bool>::value, "flags must be boolean" );
+
+ explicit BoundFlagLambda( L const &lambda ) : m_lambda( lambda ) {}
+
+ auto setFlag( bool flag ) -> ParserResult override {
+ return LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( m_lambda, flag );
+ }
+ };
+
+ enum class Optionality { Optional, Required };
+
+ struct Parser;
+
+ class ParserBase {
+ public:
+ virtual ~ParserBase() = default;
+ virtual auto validate() const -> Result { return Result::ok(); }
+ virtual auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult = 0;
+ virtual auto cardinality() const -> size_t { return 1; }
+
+ auto parse( Args const &args ) const -> InternalParseResult {
+ return parse( args.exeName(), TokenStream( args ) );
+ }
+ };
+
+ template<typename DerivedT>
+ class ComposableParserImpl : public ParserBase {
+ public:
+ template<typename T>
+ auto operator|( T const &other ) const -> Parser;
+
+ template<typename T>
+ auto operator+( T const &other ) const -> Parser;
+ };
+
+ // Common code and state for Args and Opts
+ template<typename DerivedT>
+ class ParserRefImpl : public ComposableParserImpl<DerivedT> {
+ protected:
+ Optionality m_optionality = Optionality::Optional;
+ std::shared_ptr<BoundRef> m_ref;
+ std::string m_hint;
+ std::string m_description;
+
+ explicit ParserRefImpl( std::shared_ptr<BoundRef> const &ref ) : m_ref( ref ) {}
+
+ public:
+ template<typename T>
+ ParserRefImpl( T &ref, std::string const &hint )
+ : m_ref( std::make_shared<BoundValueRef<T>>( ref ) ),
+ m_hint( hint )
+ {}
+
+ template<typename LambdaT>
+ ParserRefImpl( LambdaT const &ref, std::string const &hint )
+ : m_ref( std::make_shared<BoundLambda<LambdaT>>( ref ) ),
+ m_hint(hint)
+ {}
+
+ auto operator()( std::string const &description ) -> DerivedT & {
+ m_description = description;
+ return static_cast<DerivedT &>( *this );
+ }
+
+ auto optional() -> DerivedT & {
+ m_optionality = Optionality::Optional;
+ return static_cast<DerivedT &>( *this );
+ };
+
+ auto required() -> DerivedT & {
+ m_optionality = Optionality::Required;
+ return static_cast<DerivedT &>( *this );
+ };
+
+ auto isOptional() const -> bool {
+ return m_optionality == Optionality::Optional;
+ }
+
+ auto cardinality() const -> size_t override {
+ if( m_ref->isContainer() )
+ return 0;
+ else
+ return 1;
+ }
+
+ auto hint() const -> std::string { return m_hint; }
+ };
+
+ class ExeName : public ComposableParserImpl<ExeName> {
+ std::shared_ptr<std::string> m_name;
+ std::shared_ptr<BoundValueRefBase> m_ref;
+
+ template<typename LambdaT>
+ static auto makeRef(LambdaT const &lambda) -> std::shared_ptr<BoundValueRefBase> {
+ return std::make_shared<BoundLambda<LambdaT>>( lambda) ;
+ }
+
+ public:
+ ExeName() : m_name( std::make_shared<std::string>( "<executable>" ) ) {}
+
+ explicit ExeName( std::string &ref ) : ExeName() {
+ m_ref = std::make_shared<BoundValueRef<std::string>>( ref );
+ }
+
+ template<typename LambdaT>
+ explicit ExeName( LambdaT const& lambda ) : ExeName() {
+ m_ref = std::make_shared<BoundLambda<LambdaT>>( lambda );
+ }
+
+ // The exe name is not parsed out of the normal tokens, but is handled specially
+ auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override {
+ return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) );
+ }
+
+ auto name() const -> std::string { return *m_name; }
+ auto set( std::string const& newName ) -> ParserResult {
+
+ auto lastSlash = newName.find_last_of( "\\/" );
+ auto filename = ( lastSlash == std::string::npos )
+ ? newName
+ : newName.substr( lastSlash+1 );
+
+ *m_name = filename;
+ if( m_ref )
+ return m_ref->setValue( filename );
+ else
+ return ParserResult::ok( ParseResultType::Matched );
+ }
+ };
+
+ class Arg : public ParserRefImpl<Arg> {
+ public:
+ using ParserRefImpl::ParserRefImpl;
+
+ auto parse( std::string const &, TokenStream const &tokens ) const -> InternalParseResult override {
+ auto validationResult = validate();
+ if( !validationResult )
+ return InternalParseResult( validationResult );
+
+ auto remainingTokens = tokens;
+ auto const &token = *remainingTokens;
+ if( token.type != TokenType::Argument )
+ return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) );
+
+ assert( !m_ref->isFlag() );
+ auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );
+
+ auto result = valueRef->setValue( remainingTokens->token );
+ if( !result )
+ return InternalParseResult( result );
+ else
+ return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) );
+ }
+ };
+
+ inline auto normaliseOpt( std::string const &optName ) -> std::string {
+#ifdef CATCH_PLATFORM_WINDOWS
+ if( optName[0] == '/' )
+ return "-" + optName.substr( 1 );
+ else
+#endif
+ return optName;
+ }
+
+ class Opt : public ParserRefImpl<Opt> {
+ protected:
+ std::vector<std::string> m_optNames;
+
+ public:
+ template<typename LambdaT>
+ explicit Opt( LambdaT const &ref ) : ParserRefImpl( std::make_shared<BoundFlagLambda<LambdaT>>( ref ) ) {}
+
+ explicit Opt( bool &ref ) : ParserRefImpl( std::make_shared<BoundFlagRef>( ref ) ) {}
+
+ template<typename LambdaT>
+ Opt( LambdaT const &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {}
+
+ template<typename T>
+ Opt( T &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {}
+
+ auto operator[]( std::string const &optName ) -> Opt & {
+ m_optNames.push_back( optName );
+ return *this;
+ }
+
+ auto getHelpColumns() const -> std::vector<HelpColumns> {
+ std::ostringstream oss;
+ bool first = true;
+ for( auto const &opt : m_optNames ) {
+ if (first)
+ first = false;
+ else
+ oss << ", ";
+ oss << opt;
+ }
+ if( !m_hint.empty() )
+ oss << " <" << m_hint << ">";
+ return { { oss.str(), m_description } };
+ }
+
+ auto isMatch( std::string const &optToken ) const -> bool {
+ auto normalisedToken = normaliseOpt( optToken );
+ for( auto const &name : m_optNames ) {
+ if( normaliseOpt( name ) == normalisedToken )
+ return true;
+ }
+ return false;
+ }
+
+ using ParserBase::parse;
+
+ auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override {
+ auto validationResult = validate();
+ if( !validationResult )
+ return InternalParseResult( validationResult );
+
+ auto remainingTokens = tokens;
+ if( remainingTokens && remainingTokens->type == TokenType::Option ) {
+ auto const &token = *remainingTokens;
+ if( isMatch(token.token ) ) {
+ if( m_ref->isFlag() ) {
+ auto flagRef = static_cast<detail::BoundFlagRefBase*>( m_ref.get() );
+ auto result = flagRef->setFlag( true );
+ if( !result )
+ return InternalParseResult( result );
+ if( result.value() == ParseResultType::ShortCircuitAll )
+ return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );
+ } else {
+ auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );
+ ++remainingTokens;
+ if( !remainingTokens )
+ return InternalParseResult::runtimeError( "Expected argument following " + token.token );
+ auto const &argToken = *remainingTokens;
+ if( argToken.type != TokenType::Argument )
+ return InternalParseResult::runtimeError( "Expected argument following " + token.token );
+ auto result = valueRef->setValue( argToken.token );
+ if( !result )
+ return InternalParseResult( result );
+ if( result.value() == ParseResultType::ShortCircuitAll )
+ return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );
+ }
+ return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) );
+ }
+ }
+ return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) );
+ }
+
+ auto validate() const -> Result override {
+ if( m_optNames.empty() )
+ return Result::logicError( "No options supplied to Opt" );
+ for( auto const &name : m_optNames ) {
+ if( name.empty() )
+ return Result::logicError( "Option name cannot be empty" );
+#ifdef CATCH_PLATFORM_WINDOWS
+ if( name[0] != '-' && name[0] != '/' )
+ return Result::logicError( "Option name must begin with '-' or '/'" );
+#else
+ if( name[0] != '-' )
+ return Result::logicError( "Option name must begin with '-'" );
+#endif
+ }
+ return ParserRefImpl::validate();
+ }
+ };
+
+ struct Help : Opt {
+ Help( bool &showHelpFlag )
+ : Opt([&]( bool flag ) {
+ showHelpFlag = flag;
+ return ParserResult::ok( ParseResultType::ShortCircuitAll );
+ })
+ {
+ static_cast<Opt &>( *this )
+ ("display usage information")
+ ["-?"]["-h"]["--help"]
+ .optional();
+ }
+ };
+
+ struct Parser : ParserBase {
+
+ mutable ExeName m_exeName;
+ std::vector<Opt> m_options;
+ std::vector<Arg> m_args;
+
+ auto operator|=( ExeName const &exeName ) -> Parser & {
+ m_exeName = exeName;
+ return *this;
+ }
+
+ auto operator|=( Arg const &arg ) -> Parser & {
+ m_args.push_back(arg);
+ return *this;
+ }
+
+ auto operator|=( Opt const &opt ) -> Parser & {
+ m_options.push_back(opt);
+ return *this;
+ }
+
+ auto operator|=( Parser const &other ) -> Parser & {
+ m_options.insert(m_options.end(), other.m_options.begin(), other.m_options.end());
+ m_args.insert(m_args.end(), other.m_args.begin(), other.m_args.end());
+ return *this;
+ }
+
+ template<typename T>
+ auto operator|( T const &other ) const -> Parser {
+ return Parser( *this ) |= other;
+ }
+
+ // Forward deprecated interface with '+' instead of '|'
+ template<typename T>
+ auto operator+=( T const &other ) -> Parser & { return operator|=( other ); }
+ template<typename T>
+ auto operator+( T const &other ) const -> Parser { return operator|( other ); }
+
+ auto getHelpColumns() const -> std::vector<HelpColumns> {
+ std::vector<HelpColumns> cols;
+ for (auto const &o : m_options) {
+ auto childCols = o.getHelpColumns();
+ cols.insert( cols.end(), childCols.begin(), childCols.end() );
+ }
+ return cols;
+ }
+
+ void writeToStream( std::ostream &os ) const {
+ if (!m_exeName.name().empty()) {
+ os << "usage:\n" << " " << m_exeName.name() << " ";
+ bool required = true, first = true;
+ for( auto const &arg : m_args ) {
+ if (first)
+ first = false;
+ else
+ os << " ";
+ if( arg.isOptional() && required ) {
+ os << "[";
+ required = false;
+ }
+ os << "<" << arg.hint() << ">";
+ if( arg.cardinality() == 0 )
+ os << " ... ";
+ }
+ if( !required )
+ os << "]";
+ if( !m_options.empty() )
+ os << " options";
+ os << "\n\nwhere options are:" << std::endl;
+ }
+
+ auto rows = getHelpColumns();
+ size_t consoleWidth = CATCH_CLARA_CONFIG_CONSOLE_WIDTH;
+ size_t optWidth = 0;
+ for( auto const &cols : rows )
+ optWidth = (std::max)(optWidth, cols.left.size() + 2);
+
+ optWidth = (std::min)(optWidth, consoleWidth/2);
+
+ for( auto const &cols : rows ) {
+ auto row =
+ TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) +
+ TextFlow::Spacer(4) +
+ TextFlow::Column( cols.right ).width( consoleWidth - 7 - optWidth );
+ os << row << std::endl;
+ }
+ }
+
+ friend auto operator<<( std::ostream &os, Parser const &parser ) -> std::ostream& {
+ parser.writeToStream( os );
+ return os;
+ }
+
+ auto validate() const -> Result override {
+ for( auto const &opt : m_options ) {
+ auto result = opt.validate();
+ if( !result )
+ return result;
+ }
+ for( auto const &arg : m_args ) {
+ auto result = arg.validate();
+ if( !result )
+ return result;
+ }
+ return Result::ok();
+ }
+
+ using ParserBase::parse;
+
+ auto parse( std::string const& exeName, TokenStream const &tokens ) const -> InternalParseResult override {
+
+ struct ParserInfo {
+ ParserBase const* parser = nullptr;
+ size_t count = 0;
+ };
+ const size_t totalParsers = m_options.size() + m_args.size();
+ assert( totalParsers < 512 );
+ // ParserInfo parseInfos[totalParsers]; // <-- this is what we really want to do
+ ParserInfo parseInfos[512];
+
+ {
+ size_t i = 0;
+ for (auto const &opt : m_options) parseInfos[i++].parser = &opt;
+ for (auto const &arg : m_args) parseInfos[i++].parser = &arg;
+ }
+
+ m_exeName.set( exeName );
+
+ auto result = InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) );
+ while( result.value().remainingTokens() ) {
+ bool tokenParsed = false;
+
+ for( size_t i = 0; i < totalParsers; ++i ) {
+ auto& parseInfo = parseInfos[i];
+ if( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) {
+ result = parseInfo.parser->parse(exeName, result.value().remainingTokens());
+ if (!result)
+ return result;
+ if (result.value().type() != ParseResultType::NoMatch) {
+ tokenParsed = true;
+ ++parseInfo.count;
+ break;
+ }
+ }
+ }
+
+ if( result.value().type() == ParseResultType::ShortCircuitAll )
+ return result;
+ if( !tokenParsed )
+ return InternalParseResult::runtimeError( "Unrecognised token: " + result.value().remainingTokens()->token );
+ }
+ // !TBD Check missing required options
+ return result;
+ }
+ };
+
+ template<typename DerivedT>
+ template<typename T>
+ auto ComposableParserImpl<DerivedT>::operator|( T const &other ) const -> Parser {
+ return Parser() | static_cast<DerivedT const &>( *this ) | other;
+ }
+} // namespace detail
+
+// A Combined parser
+using detail::Parser;
+
+// A parser for options
+using detail::Opt;
+
+// A parser for arguments
+using detail::Arg;
+
+// Wrapper for argc, argv from main()
+using detail::Args;
+
+// Specifies the name of the executable
+using detail::ExeName;
+
+// Convenience wrapper for option parser that specifies the help option
+using detail::Help;
+
+// enum of result types from a parse
+using detail::ParseResultType;
+
+// Result type for parser operation
+using detail::ParserResult;
+
+}} // namespace Catch::clara
+
+// end clara.hpp
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+// Restore Clara's value for console width, if present
+#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
+#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
+#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
+#endif
+
+// end catch_clara.h
+namespace Catch {
+
+ clara::Parser makeCommandLineParser( ConfigData& config );
+
+} // end namespace Catch
+
+// end catch_commandline.h
+#include <fstream>
+#include <ctime>
+
+namespace Catch {
+
+ clara::Parser makeCommandLineParser( ConfigData& config ) {
+
+ using namespace clara;
+
+ auto const setWarning = [&]( std::string const& warning ) {
+ auto warningSet = [&]() {
+ if( warning == "NoAssertions" )
+ return WarnAbout::NoAssertions;
+
+ if ( warning == "NoTests" )
+ return WarnAbout::NoTests;
+
+ return WarnAbout::Nothing;
+ }();
+
+ if (warningSet == WarnAbout::Nothing)
+ return ParserResult::runtimeError( "Unrecognised warning: '" + warning + "'" );
+ config.warnings = static_cast<WarnAbout::What>( config.warnings | warningSet );
+ return ParserResult::ok( ParseResultType::Matched );
+ };
+ auto const loadTestNamesFromFile = [&]( std::string const& filename ) {
+ std::ifstream f( filename.c_str() );
+ if( !f.is_open() )
+ return ParserResult::runtimeError( "Unable to load input file: '" + filename + "'" );
+
+ std::string line;
+ while( std::getline( f, line ) ) {
+ line = trim(line);
+ if( !line.empty() && !startsWith( line, '#' ) ) {
+ if( !startsWith( line, '"' ) )
+ line = '"' + line + '"';
+ config.testsOrTags.push_back( line + ',' );
+ }
+ }
+ return ParserResult::ok( ParseResultType::Matched );
+ };
+ auto const setTestOrder = [&]( std::string const& order ) {
+ if( startsWith( "declared", order ) )
+ config.runOrder = RunTests::InDeclarationOrder;
+ else if( startsWith( "lexical", order ) )
+ config.runOrder = RunTests::InLexicographicalOrder;
+ else if( startsWith( "random", order ) )
+ config.runOrder = RunTests::InRandomOrder;
+ else
+ return clara::ParserResult::runtimeError( "Unrecognised ordering: '" + order + "'" );
+ return ParserResult::ok( ParseResultType::Matched );
+ };
+ auto const setRngSeed = [&]( std::string const& seed ) {
+ if( seed != "time" )
+ return clara::detail::convertInto( seed, config.rngSeed );
+ config.rngSeed = static_cast<unsigned int>( std::time(nullptr) );
+ return ParserResult::ok( ParseResultType::Matched );
+ };
+ auto const setColourUsage = [&]( std::string const& useColour ) {
+ auto mode = toLower( useColour );
+
+ if( mode == "yes" )
+ config.useColour = UseColour::Yes;
+ else if( mode == "no" )
+ config.useColour = UseColour::No;
+ else if( mode == "auto" )
+ config.useColour = UseColour::Auto;
+ else
+ return ParserResult::runtimeError( "colour mode must be one of: auto, yes or no. '" + useColour + "' not recognised" );
+ return ParserResult::ok( ParseResultType::Matched );
+ };
+ auto const setWaitForKeypress = [&]( std::string const& keypress ) {
+ auto keypressLc = toLower( keypress );
+ if( keypressLc == "start" )
+ config.waitForKeypress = WaitForKeypress::BeforeStart;
+ else if( keypressLc == "exit" )
+ config.waitForKeypress = WaitForKeypress::BeforeExit;
+ else if( keypressLc == "both" )
+ config.waitForKeypress = WaitForKeypress::BeforeStartAndExit;
+ else
+ return ParserResult::runtimeError( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" );
+ return ParserResult::ok( ParseResultType::Matched );
+ };
+ auto const setVerbosity = [&]( std::string const& verbosity ) {
+ auto lcVerbosity = toLower( verbosity );
+ if( lcVerbosity == "quiet" )
+ config.verbosity = Verbosity::Quiet;
+ else if( lcVerbosity == "normal" )
+ config.verbosity = Verbosity::Normal;
+ else if( lcVerbosity == "high" )
+ config.verbosity = Verbosity::High;
+ else
+ return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + "'" );
+ return ParserResult::ok( ParseResultType::Matched );
+ };
+
+ auto cli
+ = ExeName( config.processName )
+ | Help( config.showHelp )
+ | Opt( config.listTests )
+ ["-l"]["--list-tests"]
+ ( "list all/matching test cases" )
+ | Opt( config.listTags )
+ ["-t"]["--list-tags"]
+ ( "list all/matching tags" )
+ | Opt( config.showSuccessfulTests )
+ ["-s"]["--success"]
+ ( "include successful tests in output" )
+ | Opt( config.shouldDebugBreak )
+ ["-b"]["--break"]
+ ( "break into debugger on failure" )
+ | Opt( config.noThrow )
+ ["-e"]["--nothrow"]
+ ( "skip exception tests" )
+ | Opt( config.showInvisibles )
+ ["-i"]["--invisibles"]
+ ( "show invisibles (tabs, newlines)" )
+ | Opt( config.outputFilename, "filename" )
+ ["-o"]["--out"]
+ ( "output filename" )
+ | Opt( config.reporterName, "name" )
+ ["-r"]["--reporter"]
+ ( "reporter to use (defaults to console)" )
+ | Opt( config.name, "name" )
+ ["-n"]["--name"]
+ ( "suite name" )
+ | Opt( [&]( bool ){ config.abortAfter = 1; } )
+ ["-a"]["--abort"]
+ ( "abort at first failure" )
+ | Opt( [&]( int x ){ config.abortAfter = x; }, "no. failures" )
+ ["-x"]["--abortx"]
+ ( "abort after x failures" )
+ | Opt( setWarning, "warning name" )
+ ["-w"]["--warn"]
+ ( "enable warnings" )
+ | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" )
+ ["-d"]["--durations"]
+ ( "show test durations" )
+ | Opt( loadTestNamesFromFile, "filename" )
+ ["-f"]["--input-file"]
+ ( "load test names to run from a file" )
+ | Opt( config.filenamesAsTags )
+ ["-#"]["--filenames-as-tags"]
+ ( "adds a tag for the filename" )
+ | Opt( config.sectionsToRun, "section name" )
+ ["-c"]["--section"]
+ ( "specify section to run" )
+ | Opt( setVerbosity, "quiet|normal|high" )
+ ["-v"]["--verbosity"]
+ ( "set output verbosity" )
+ | Opt( config.listTestNamesOnly )
+ ["--list-test-names-only"]
+ ( "list all/matching test cases names only" )
+ | Opt( config.listReporters )
+ ["--list-reporters"]
+ ( "list all reporters" )
+ | Opt( setTestOrder, "decl|lex|rand" )
+ ["--order"]
+ ( "test case order (defaults to decl)" )
+ | Opt( setRngSeed, "'time'|number" )
+ ["--rng-seed"]
+ ( "set a specific seed for random numbers" )
+ | Opt( setColourUsage, "yes|no" )
+ ["--use-colour"]
+ ( "should output be colourised" )
+ | Opt( config.libIdentify )
+ ["--libidentify"]
+ ( "report name and version according to libidentify standard" )
+ | Opt( setWaitForKeypress, "start|exit|both" )
+ ["--wait-for-keypress"]
+ ( "waits for a keypress before exiting" )
+ | Opt( config.benchmarkResolutionMultiple, "multiplier" )
+ ["--benchmark-resolution-multiple"]
+ ( "multiple of clock resolution to run benchmarks" )
+
+ | Arg( config.testsOrTags, "test name|pattern|tags" )
+ ( "which test or tests to use" );
+
+ return cli;
+ }
+
+} // end namespace Catch
+// end catch_commandline.cpp
+// start catch_common.cpp
+
+#include <cstring>
+#include <ostream>
+
+namespace Catch {
+
+ bool SourceLineInfo::empty() const noexcept {
+ return file[0] == '\0';
+ }
+ bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept {
+ return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0);
+ }
+ bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept {
+ // We can assume that the same file will usually have the same pointer.
+ // Thus, if the pointers are the same, there is no point in calling the strcmp
+ return line < other.line || ( line == other.line && file != other.file && (std::strcmp(file, other.file) < 0));
+ }
+
+ std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
+#ifndef __GNUG__
+ os << info.file << '(' << info.line << ')';
+#else
+ os << info.file << ':' << info.line;
+#endif
+ return os;
+ }
+
+ std::string StreamEndStop::operator+() const {
+ return std::string();
+ }
+
+ NonCopyable::NonCopyable() = default;
+ NonCopyable::~NonCopyable() = default;
+
+}
+// end catch_common.cpp
+// start catch_config.cpp
+
+namespace Catch {
+
+ Config::Config( ConfigData const& data )
+ : m_data( data ),
+ m_stream( openStream() )
+ {
+ TestSpecParser parser(ITagAliasRegistry::get());
+ if (data.testsOrTags.empty()) {
+ parser.parse("~[.]"); // All not hidden tests
+ }
+ else {
+ m_hasTestFilters = true;
+ for( auto const& testOrTags : data.testsOrTags )
+ parser.parse( testOrTags );
+ }
+ m_testSpec = parser.testSpec();
+ }
+
+ std::string const& Config::getFilename() const {
+ return m_data.outputFilename ;
+ }
+
+ bool Config::listTests() const { return m_data.listTests; }
+ bool Config::listTestNamesOnly() const { return m_data.listTestNamesOnly; }
+ bool Config::listTags() const { return m_data.listTags; }
+ bool Config::listReporters() const { return m_data.listReporters; }
+
+ std::string Config::getProcessName() const { return m_data.processName; }
+ std::string const& Config::getReporterName() const { return m_data.reporterName; }
+
+ std::vector<std::string> const& Config::getTestsOrTags() const { return m_data.testsOrTags; }
+ std::vector<std::string> const& Config::getSectionsToRun() const { return m_data.sectionsToRun; }
+
+ TestSpec const& Config::testSpec() const { return m_testSpec; }
+ bool Config::hasTestFilters() const { return m_hasTestFilters; }
+
+ bool Config::showHelp() const { return m_data.showHelp; }
+
+ // IConfig interface
+ bool Config::allowThrows() const { return !m_data.noThrow; }
+ std::ostream& Config::stream() const { return m_stream->stream(); }
+ std::string Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; }
+ bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; }
+ bool Config::warnAboutMissingAssertions() const { return !!(m_data.warnings & WarnAbout::NoAssertions); }
+ bool Config::warnAboutNoTests() const { return !!(m_data.warnings & WarnAbout::NoTests); }
+ ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; }
+ RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; }
+ unsigned int Config::rngSeed() const { return m_data.rngSeed; }
+ int Config::benchmarkResolutionMultiple() const { return m_data.benchmarkResolutionMultiple; }
+ UseColour::YesOrNo Config::useColour() const { return m_data.useColour; }
+ bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; }
+ int Config::abortAfter() const { return m_data.abortAfter; }
+ bool Config::showInvisibles() const { return m_data.showInvisibles; }
+ Verbosity Config::verbosity() const { return m_data.verbosity; }
+
+ IStream const* Config::openStream() {
+ return Catch::makeStream(m_data.outputFilename);
+ }
+
+} // end namespace Catch
+// end catch_config.cpp
+// start catch_console_colour.cpp
+
+#if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wexit-time-destructors"
+#endif
+
+// start catch_errno_guard.h
+
+namespace Catch {
+
+ class ErrnoGuard {
+ public:
+ ErrnoGuard();
+ ~ErrnoGuard();
+ private:
+ int m_oldErrno;
+ };
+
+}
+
+// end catch_errno_guard.h
+#include <sstream>
+
+namespace Catch {
+ namespace {
+
+ struct IColourImpl {
+ virtual ~IColourImpl() = default;
+ virtual void use( Colour::Code _colourCode ) = 0;
+ };
+
+ struct NoColourImpl : IColourImpl {
+ void use( Colour::Code ) {}
+
+ static IColourImpl* instance() {
+ static NoColourImpl s_instance;
+ return &s_instance;
+ }
+ };
+
+ } // anon namespace
+} // namespace Catch
+
+#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI )
+# ifdef CATCH_PLATFORM_WINDOWS
+# define CATCH_CONFIG_COLOUR_WINDOWS
+# else
+# define CATCH_CONFIG_COLOUR_ANSI
+# endif
+#endif
+
+#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) /////////////////////////////////////////
+
+namespace Catch {
+namespace {
+
+ class Win32ColourImpl : public IColourImpl {
+ public:
+ Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) )
+ {
+ CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
+ GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo );
+ originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY );
+ originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY );
+ }
+
+ virtual void use( Colour::Code _colourCode ) override {
+ switch( _colourCode ) {
+ case Colour::None: return setTextAttribute( originalForegroundAttributes );
+ case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
+ case Colour::Red: return setTextAttribute( FOREGROUND_RED );
+ case Colour::Green: return setTextAttribute( FOREGROUND_GREEN );
+ case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE );
+ case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN );
+ case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN );
+ case Colour::Grey: return setTextAttribute( 0 );
+
+ case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY );
+ case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED );
+ case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN );
+ case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
+ case Colour::BrightYellow: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN );
+
+ case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" );
+
+ default:
+ CATCH_ERROR( "Unknown colour requested" );
+ }
+ }
+
+ private:
+ void setTextAttribute( WORD _textAttribute ) {
+ SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes );
+ }
+ HANDLE stdoutHandle;
+ WORD originalForegroundAttributes;
+ WORD originalBackgroundAttributes;
+ };
+
+ IColourImpl* platformColourInstance() {
+ static Win32ColourImpl s_instance;
+
+ IConfigPtr config = getCurrentContext().getConfig();
+ UseColour::YesOrNo colourMode = config
+ ? config->useColour()
+ : UseColour::Auto;
+ if( colourMode == UseColour::Auto )
+ colourMode = UseColour::Yes;
+ return colourMode == UseColour::Yes
+ ? &s_instance
+ : NoColourImpl::instance();
+ }
+
+} // end anon namespace
+} // end namespace Catch
+
+#elif defined( CATCH_CONFIG_COLOUR_ANSI ) //////////////////////////////////////
+
+#include <unistd.h>
+
+namespace Catch {
+namespace {
+
+ // use POSIX/ ANSI console terminal codes
+ // Thanks to Adam Strzelecki for original contribution
+ // (http://github.com/nanoant)
+ // https://github.com/philsquared/Catch/pull/131
+ class PosixColourImpl : public IColourImpl {
+ public:
+ virtual void use( Colour::Code _colourCode ) override {
+ switch( _colourCode ) {
+ case Colour::None:
+ case Colour::White: return setColour( "[0m" );
+ case Colour::Red: return setColour( "[0;31m" );
+ case Colour::Green: return setColour( "[0;32m" );
+ case Colour::Blue: return setColour( "[0;34m" );
+ case Colour::Cyan: return setColour( "[0;36m" );
+ case Colour::Yellow: return setColour( "[0;33m" );
+ case Colour::Grey: return setColour( "[1;30m" );
+
+ case Colour::LightGrey: return setColour( "[0;37m" );
+ case Colour::BrightRed: return setColour( "[1;31m" );
+ case Colour::BrightGreen: return setColour( "[1;32m" );
+ case Colour::BrightWhite: return setColour( "[1;37m" );
+ case Colour::BrightYellow: return setColour( "[1;33m" );
+
+ case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" );
+ default: CATCH_INTERNAL_ERROR( "Unknown colour requested" );
+ }
+ }
+ static IColourImpl* instance() {
+ static PosixColourImpl s_instance;
+ return &s_instance;
+ }
+
+ private:
+ void setColour( const char* _escapeCode ) {
+ Catch::cout() << '\033' << _escapeCode;
+ }
+ };
+
+ bool useColourOnPlatform() {
+ return
+#ifdef CATCH_PLATFORM_MAC
+ !isDebuggerActive() &&
+#endif
+#if !(defined(__DJGPP__) && defined(__STRICT_ANSI__))
+ isatty(STDOUT_FILENO)
+#else
+ false
+#endif
+ ;
+ }
+ IColourImpl* platformColourInstance() {
+ ErrnoGuard guard;
+ IConfigPtr config = getCurrentContext().getConfig();
+ UseColour::YesOrNo colourMode = config
+ ? config->useColour()
+ : UseColour::Auto;
+ if( colourMode == UseColour::Auto )
+ colourMode = useColourOnPlatform()
+ ? UseColour::Yes
+ : UseColour::No;
+ return colourMode == UseColour::Yes
+ ? PosixColourImpl::instance()
+ : NoColourImpl::instance();
+ }
+
+} // end anon namespace
+} // end namespace Catch
+
+#else // not Windows or ANSI ///////////////////////////////////////////////
+
+namespace Catch {
+
+ static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); }
+
+} // end namespace Catch
+
+#endif // Windows/ ANSI/ None
+
+namespace Catch {
+
+ Colour::Colour( Code _colourCode ) { use( _colourCode ); }
+ Colour::Colour( Colour&& rhs ) noexcept {
+ m_moved = rhs.m_moved;
+ rhs.m_moved = true;
+ }
+ Colour& Colour::operator=( Colour&& rhs ) noexcept {
+ m_moved = rhs.m_moved;
+ rhs.m_moved = true;
+ return *this;
+ }
+
+ Colour::~Colour(){ if( !m_moved ) use( None ); }
+
+ void Colour::use( Code _colourCode ) {
+ static IColourImpl* impl = platformColourInstance();
+ impl->use( _colourCode );
+ }
+
+ std::ostream& operator << ( std::ostream& os, Colour const& ) {
+ return os;
+ }
+
+} // end namespace Catch
+
+#if defined(__clang__)
+# pragma clang diagnostic pop
+#endif
+
+// end catch_console_colour.cpp
+// start catch_context.cpp
+
+namespace Catch {
+
+ class Context : public IMutableContext, NonCopyable {
+
+ public: // IContext
+ virtual IResultCapture* getResultCapture() override {
+ return m_resultCapture;
+ }
+ virtual IRunner* getRunner() override {
+ return m_runner;
+ }
+
+ virtual IConfigPtr const& getConfig() const override {
+ return m_config;
+ }
+
+ virtual ~Context() override;
+
+ public: // IMutableContext
+ virtual void setResultCapture( IResultCapture* resultCapture ) override {
+ m_resultCapture = resultCapture;
+ }
+ virtual void setRunner( IRunner* runner ) override {
+ m_runner = runner;
+ }
+ virtual void setConfig( IConfigPtr const& config ) override {
+ m_config = config;
+ }
+
+ friend IMutableContext& getCurrentMutableContext();
+
+ private:
+ IConfigPtr m_config;
+ IRunner* m_runner = nullptr;
+ IResultCapture* m_resultCapture = nullptr;
+ };
+
+ IMutableContext *IMutableContext::currentContext = nullptr;
+
+ void IMutableContext::createContext()
+ {
+ currentContext = new Context();
+ }
+
+ void cleanUpContext() {
+ delete IMutableContext::currentContext;
+ IMutableContext::currentContext = nullptr;
+ }
+ IContext::~IContext() = default;
+ IMutableContext::~IMutableContext() = default;
+ Context::~Context() = default;
+}
+// end catch_context.cpp
+// start catch_debug_console.cpp
+
+// start catch_debug_console.h
+
+#include <string>
+
+namespace Catch {
+ void writeToDebugConsole( std::string const& text );
+}
+
+// end catch_debug_console.h
+#ifdef CATCH_PLATFORM_WINDOWS
+
+ namespace Catch {
+ void writeToDebugConsole( std::string const& text ) {
+ ::OutputDebugStringA( text.c_str() );
+ }
+ }
+
+#else
+
+ namespace Catch {
+ void writeToDebugConsole( std::string const& text ) {
+ // !TBD: Need a version for Mac/ XCode and other IDEs
+ Catch::cout() << text;
+ }
+ }
+
+#endif // Platform
+// end catch_debug_console.cpp
+// start catch_debugger.cpp
+
+#ifdef CATCH_PLATFORM_MAC
+
+# include <assert.h>
+# include <stdbool.h>
+# include <sys/types.h>
+# include <unistd.h>
+# include <sys/sysctl.h>
+# include <cstddef>
+# include <ostream>
+
+namespace Catch {
+
+ // The following function is taken directly from the following technical note:
+ // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html
+
+ // Returns true if the current process is being debugged (either
+ // running under the debugger or has a debugger attached post facto).
+ bool isDebuggerActive(){
+
+ int mib[4];
+ struct kinfo_proc info;
+ std::size_t size;
+
+ // Initialize the flags so that, if sysctl fails for some bizarre
+ // reason, we get a predictable result.
+
+ info.kp_proc.p_flag = 0;
+
+ // Initialize mib, which tells sysctl the info we want, in this case
+ // we're looking for information about a specific process ID.
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PID;
+ mib[3] = getpid();
+
+ // Call sysctl.
+
+ size = sizeof(info);
+ if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0) != 0 ) {
+ Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl;
+ return false;
+ }
+
+ // We're being debugged if the P_TRACED flag is set.
+
+ return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
+ }
+ } // namespace Catch
+
+#elif defined(CATCH_PLATFORM_LINUX)
+ #include <fstream>
+ #include <string>
+
+ namespace Catch{
+ // The standard POSIX way of detecting a debugger is to attempt to
+ // ptrace() the process, but this needs to be done from a child and not
+ // this process itself to still allow attaching to this process later
+ // if wanted, so is rather heavy. Under Linux we have the PID of the
+ // "debugger" (which doesn't need to be gdb, of course, it could also
+ // be strace, for example) in /proc/$PID/status, so just get it from
+ // there instead.
+ bool isDebuggerActive(){
+ // Libstdc++ has a bug, where std::ifstream sets errno to 0
+ // This way our users can properly assert over errno values
+ ErrnoGuard guard;
+ std::ifstream in("/proc/self/status");
+ for( std::string line; std::getline(in, line); ) {
+ static const int PREFIX_LEN = 11;
+ if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) {
+ // We're traced if the PID is not 0 and no other PID starts
+ // with 0 digit, so it's enough to check for just a single
+ // character.
+ return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0';
+ }
+ }
+
+ return false;
+ }
+ } // namespace Catch
+#elif defined(_MSC_VER)
+ extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
+ namespace Catch {
+ bool isDebuggerActive() {
+ return IsDebuggerPresent() != 0;
+ }
+ }
+#elif defined(__MINGW32__)
+ extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
+ namespace Catch {
+ bool isDebuggerActive() {
+ return IsDebuggerPresent() != 0;
+ }
+ }
+#else
+ namespace Catch {
+ bool isDebuggerActive() { return false; }
+ }
+#endif // Platform
+// end catch_debugger.cpp
+// start catch_decomposer.cpp
+
+namespace Catch {
+
+ ITransientExpression::~ITransientExpression() = default;
+
+ void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ) {
+ if( lhs.size() + rhs.size() < 40 &&
+ lhs.find('\n') == std::string::npos &&
+ rhs.find('\n') == std::string::npos )
+ os << lhs << " " << op << " " << rhs;
+ else
+ os << lhs << "\n" << op << "\n" << rhs;
+ }
+}
+// end catch_decomposer.cpp
+// start catch_enforce.cpp
+
+namespace Catch {
+#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER)
+ [[noreturn]]
+ void throw_exception(std::exception const& e) {
+ Catch::cerr() << "Catch will terminate because it needed to throw an exception.\n"
+ << "The message was: " << e.what() << '\n';
+ std::terminate();
+ }
+#endif
+} // namespace Catch;
+// end catch_enforce.cpp
+// start catch_errno_guard.cpp
+
+#include <cerrno>
+
+namespace Catch {
+ ErrnoGuard::ErrnoGuard():m_oldErrno(errno){}
+ ErrnoGuard::~ErrnoGuard() { errno = m_oldErrno; }
+}
+// end catch_errno_guard.cpp
+// start catch_exception_translator_registry.cpp
+
+// start catch_exception_translator_registry.h
+
+#include <vector>
+#include <string>
+#include <memory>
+
+namespace Catch {
+
+ class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry {
+ public:
+ ~ExceptionTranslatorRegistry();
+ virtual void registerTranslator( const IExceptionTranslator* translator );
+ virtual std::string translateActiveException() const override;
+ std::string tryTranslators() const;
+
+ private:
+ std::vector<std::unique_ptr<IExceptionTranslator const>> m_translators;
+ };
+}
+
+// end catch_exception_translator_registry.h
+#ifdef __OBJC__
+#import "Foundation/Foundation.h"
+#endif
+
+namespace Catch {
+
+ ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() {
+ }
+
+ void ExceptionTranslatorRegistry::registerTranslator( const IExceptionTranslator* translator ) {
+ m_translators.push_back( std::unique_ptr<const IExceptionTranslator>( translator ) );
+ }
+
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+ std::string ExceptionTranslatorRegistry::translateActiveException() const {
+ try {
+#ifdef __OBJC__
+ // In Objective-C try objective-c exceptions first
+ @try {
+ return tryTranslators();
+ }
+ @catch (NSException *exception) {
+ return Catch::Detail::stringify( [exception description] );
+ }
+#else
+ // Compiling a mixed mode project with MSVC means that CLR
+ // exceptions will be caught in (...) as well. However, these
+ // do not fill-in std::current_exception and thus lead to crash
+ // when attempting rethrow.
+ // /EHa switch also causes structured exceptions to be caught
+ // here, but they fill-in current_exception properly, so
+ // at worst the output should be a little weird, instead of
+ // causing a crash.
+ if (std::current_exception() == nullptr) {
+ return "Non C++ exception. Possibly a CLR exception.";
+ }
+ return tryTranslators();
+#endif
+ }
+ catch( TestFailureException& ) {
+ std::rethrow_exception(std::current_exception());
+ }
+ catch( std::exception& ex ) {
+ return ex.what();
+ }
+ catch( std::string& msg ) {
+ return msg;
+ }
+ catch( const char* msg ) {
+ return msg;
+ }
+ catch(...) {
+ return "Unknown exception";
+ }
+ }
+
+#else // ^^ Exceptions are enabled // Exceptions are disabled vv
+ std::string ExceptionTranslatorRegistry::translateActiveException() const {
+ CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
+ }
+#endif
+
+ std::string ExceptionTranslatorRegistry::tryTranslators() const {
+ if( m_translators.empty() )
+ std::rethrow_exception(std::current_exception());
+ else
+ return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() );
+ }
+}
+// end catch_exception_translator_registry.cpp
+// start catch_fatal_condition.cpp
+
+#if defined(__GNUC__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+#endif
+
+#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS )
+
+namespace {
+ // Report the error condition
+ void reportFatal( char const * const message ) {
+ Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message );
+ }
+}
+
+#endif // signals/SEH handling
+
+#if defined( CATCH_CONFIG_WINDOWS_SEH )
+
+namespace Catch {
+ struct SignalDefs { DWORD id; const char* name; };
+
+ // There is no 1-1 mapping between signals and windows exceptions.
+ // Windows can easily distinguish between SO and SigSegV,
+ // but SigInt, SigTerm, etc are handled differently.
+ static SignalDefs signalDefs[] = {
+ { EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" },
+ { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" },
+ { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" },
+ { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" },
+ };
+
+ LONG CALLBACK FatalConditionHandler::handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {
+ for (auto const& def : signalDefs) {
+ if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) {
+ reportFatal(def.name);
+ }
+ }
+ // If its not an exception we care about, pass it along.
+ // This stops us from eating debugger breaks etc.
+ return EXCEPTION_CONTINUE_SEARCH;
+ }
+
+ FatalConditionHandler::FatalConditionHandler() {
+ isSet = true;
+ // 32k seems enough for Catch to handle stack overflow,
+ // but the value was found experimentally, so there is no strong guarantee
+ guaranteeSize = 32 * 1024;
+ exceptionHandlerHandle = nullptr;
+ // Register as first handler in current chain
+ exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException);
+ // Pass in guarantee size to be filled
+ SetThreadStackGuarantee(&guaranteeSize);
+ }
+
+ void FatalConditionHandler::reset() {
+ if (isSet) {
+ RemoveVectoredExceptionHandler(exceptionHandlerHandle);
+ SetThreadStackGuarantee(&guaranteeSize);
+ exceptionHandlerHandle = nullptr;
+ isSet = false;
+ }
+ }
+
+ FatalConditionHandler::~FatalConditionHandler() {
+ reset();
+ }
+
+bool FatalConditionHandler::isSet = false;
+ULONG FatalConditionHandler::guaranteeSize = 0;
+PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr;
+
+} // namespace Catch
+
+#elif defined( CATCH_CONFIG_POSIX_SIGNALS )
+
+namespace Catch {
+
+ struct SignalDefs {
+ int id;
+ const char* name;
+ };
+
+ // 32kb for the alternate stack seems to be sufficient. However, this value
+ // is experimentally determined, so that's not guaranteed.
+ constexpr static std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ;
+
+ static SignalDefs signalDefs[] = {
+ { SIGINT, "SIGINT - Terminal interrupt signal" },
+ { SIGILL, "SIGILL - Illegal instruction signal" },
+ { SIGFPE, "SIGFPE - Floating point error signal" },
+ { SIGSEGV, "SIGSEGV - Segmentation violation signal" },
+ { SIGTERM, "SIGTERM - Termination request signal" },
+ { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
+ };
+
+ void FatalConditionHandler::handleSignal( int sig ) {
+ char const * name = "<unknown signal>";
+ for (auto const& def : signalDefs) {
+ if (sig == def.id) {
+ name = def.name;
+ break;
+ }
+ }
+ reset();
+ reportFatal(name);
+ raise( sig );
+ }
+
+ FatalConditionHandler::FatalConditionHandler() {
+ isSet = true;
+ stack_t sigStack;
+ sigStack.ss_sp = altStackMem;
+ sigStack.ss_size = sigStackSize;
+ sigStack.ss_flags = 0;
+ sigaltstack(&sigStack, &oldSigStack);
+ struct sigaction sa = { };
+
+ sa.sa_handler = handleSignal;
+ sa.sa_flags = SA_ONSTACK;
+ for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) {
+ sigaction(signalDefs[i].id, &sa, &oldSigActions[i]);
+ }
+ }
+
+ FatalConditionHandler::~FatalConditionHandler() {
+ reset();
+ }
+
+ void FatalConditionHandler::reset() {
+ if( isSet ) {
+ // Set signals back to previous values -- hopefully nobody overwrote them in the meantime
+ for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) {
+ sigaction(signalDefs[i].id, &oldSigActions[i], nullptr);
+ }
+ // Return the old stack
+ sigaltstack(&oldSigStack, nullptr);
+ isSet = false;
+ }
+ }
+
+ bool FatalConditionHandler::isSet = false;
+ struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {};
+ stack_t FatalConditionHandler::oldSigStack = {};
+ char FatalConditionHandler::altStackMem[sigStackSize] = {};
+
+} // namespace Catch
+
+#else
+
+namespace Catch {
+ void FatalConditionHandler::reset() {}
+}
+
+#endif // signals/SEH handling
+
+#if defined(__GNUC__)
+# pragma GCC diagnostic pop
+#endif
+// end catch_fatal_condition.cpp
+// start catch_generators.cpp
+
+// start catch_random_number_generator.h
+
+#include <algorithm>
+#include <random>
+
+namespace Catch {
+
+ struct IConfig;
+
+ std::mt19937& rng();
+ void seedRng( IConfig const& config );
+ unsigned int rngSeed();
+
+}
+
+// end catch_random_number_generator.h
+#include <limits>
+#include <set>
+
+namespace Catch {
+
+IGeneratorTracker::~IGeneratorTracker() {}
+
+namespace Generators {
+
+ GeneratorBase::~GeneratorBase() {}
+
+ std::vector<size_t> randomiseIndices( size_t selectionSize, size_t sourceSize ) {
+
+ assert( selectionSize <= sourceSize );
+ std::vector<size_t> indices;
+ indices.reserve( selectionSize );
+ std::uniform_int_distribution<size_t> uid( 0, sourceSize-1 );
+
+ std::set<size_t> seen;
+ // !TBD: improve this algorithm
+ while( indices.size() < selectionSize ) {
+ auto index = uid( rng() );
+ if( seen.insert( index ).second )
+ indices.push_back( index );
+ }
+ return indices;
+ }
+
+ auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
+ return getResultCapture().acquireGeneratorTracker( lineInfo );
+ }
+
+ template<>
+ auto all<int>() -> Generator<int> {
+ return range( std::numeric_limits<int>::min(), std::numeric_limits<int>::max() );
+ }
+
+} // namespace Generators
+} // namespace Catch
+// end catch_generators.cpp
+// start catch_interfaces_capture.cpp
+
+namespace Catch {
+ IResultCapture::~IResultCapture() = default;
+}
+// end catch_interfaces_capture.cpp
+// start catch_interfaces_config.cpp
+
+namespace Catch {
+ IConfig::~IConfig() = default;
+}
+// end catch_interfaces_config.cpp
+// start catch_interfaces_exception.cpp
+
+namespace Catch {
+ IExceptionTranslator::~IExceptionTranslator() = default;
+ IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() = default;
+}
+// end catch_interfaces_exception.cpp
+// start catch_interfaces_registry_hub.cpp
+
+namespace Catch {
+ IRegistryHub::~IRegistryHub() = default;
+ IMutableRegistryHub::~IMutableRegistryHub() = default;
+}
+// end catch_interfaces_registry_hub.cpp
+// start catch_interfaces_reporter.cpp
+
+// start catch_reporter_listening.h
+
+namespace Catch {
+
+ class ListeningReporter : public IStreamingReporter {
+ using Reporters = std::vector<IStreamingReporterPtr>;
+ Reporters m_listeners;
+ IStreamingReporterPtr m_reporter = nullptr;
+ ReporterPreferences m_preferences;
+
+ public:
+ ListeningReporter();
+
+ void addListener( IStreamingReporterPtr&& listener );
+ void addReporter( IStreamingReporterPtr&& reporter );
+
+ public: // IStreamingReporter
+
+ ReporterPreferences getPreferences() const override;
+
+ void noMatchingTestCases( std::string const& spec ) override;
+
+ static std::set<Verbosity> getSupportedVerbosities();
+
+ void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override;
+ void benchmarkEnded( BenchmarkStats const& benchmarkStats ) override;
+
+ void testRunStarting( TestRunInfo const& testRunInfo ) override;
+ void testGroupStarting( GroupInfo const& groupInfo ) override;
+ void testCaseStarting( TestCaseInfo const& testInfo ) override;
+ void sectionStarting( SectionInfo const& sectionInfo ) override;
+ void assertionStarting( AssertionInfo const& assertionInfo ) override;
+
+ // The return value indicates if the messages buffer should be cleared:
+ bool assertionEnded( AssertionStats const& assertionStats ) override;
+ void sectionEnded( SectionStats const& sectionStats ) override;
+ void testCaseEnded( TestCaseStats const& testCaseStats ) override;
+ void testGroupEnded( TestGroupStats const& testGroupStats ) override;
+ void testRunEnded( TestRunStats const& testRunStats ) override;
+
+ void skipTest( TestCaseInfo const& testInfo ) override;
+ bool isMulti() const override;
+
+ };
+
+} // end namespace Catch
+
+// end catch_reporter_listening.h
+namespace Catch {
+
+ ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig )
+ : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {}
+
+ ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream )
+ : m_stream( &_stream ), m_fullConfig( _fullConfig ) {}
+
+ std::ostream& ReporterConfig::stream() const { return *m_stream; }
+ IConfigPtr ReporterConfig::fullConfig() const { return m_fullConfig; }
+
+ TestRunInfo::TestRunInfo( std::string const& _name ) : name( _name ) {}
+
+ GroupInfo::GroupInfo( std::string const& _name,
+ std::size_t _groupIndex,
+ std::size_t _groupsCount )
+ : name( _name ),
+ groupIndex( _groupIndex ),
+ groupsCounts( _groupsCount )
+ {}
+
+ AssertionStats::AssertionStats( AssertionResult const& _assertionResult,
+ std::vector<MessageInfo> const& _infoMessages,
+ Totals const& _totals )
+ : assertionResult( _assertionResult ),
+ infoMessages( _infoMessages ),
+ totals( _totals )
+ {
+ assertionResult.m_resultData.lazyExpression.m_transientExpression = _assertionResult.m_resultData.lazyExpression.m_transientExpression;
+
+ if( assertionResult.hasMessage() ) {
+ // Copy message into messages list.
+ // !TBD This should have been done earlier, somewhere
+ MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() );
+ builder << assertionResult.getMessage();
+ builder.m_info.message = builder.m_stream.str();
+
+ infoMessages.push_back( builder.m_info );
+ }
+ }
+
+ AssertionStats::~AssertionStats() = default;
+
+ SectionStats::SectionStats( SectionInfo const& _sectionInfo,
+ Counts const& _assertions,
+ double _durationInSeconds,
+ bool _missingAssertions )
+ : sectionInfo( _sectionInfo ),
+ assertions( _assertions ),
+ durationInSeconds( _durationInSeconds ),
+ missingAssertions( _missingAssertions )
+ {}
+
+ SectionStats::~SectionStats() = default;
+
+ TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo,
+ Totals const& _totals,
+ std::string const& _stdOut,
+ std::string const& _stdErr,
+ bool _aborting )
+ : testInfo( _testInfo ),
+ totals( _totals ),
+ stdOut( _stdOut ),
+ stdErr( _stdErr ),
+ aborting( _aborting )
+ {}
+
+ TestCaseStats::~TestCaseStats() = default;
+
+ TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo,
+ Totals const& _totals,
+ bool _aborting )
+ : groupInfo( _groupInfo ),
+ totals( _totals ),
+ aborting( _aborting )
+ {}
+
+ TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo )
+ : groupInfo( _groupInfo ),
+ aborting( false )
+ {}
+
+ TestGroupStats::~TestGroupStats() = default;
+
+ TestRunStats::TestRunStats( TestRunInfo const& _runInfo,
+ Totals const& _totals,
+ bool _aborting )
+ : runInfo( _runInfo ),
+ totals( _totals ),
+ aborting( _aborting )
+ {}
+
+ TestRunStats::~TestRunStats() = default;
+
+ void IStreamingReporter::fatalErrorEncountered( StringRef ) {}
+ bool IStreamingReporter::isMulti() const { return false; }
+
+ IReporterFactory::~IReporterFactory() = default;
+ IReporterRegistry::~IReporterRegistry() = default;
+
+} // end namespace Catch
+// end catch_interfaces_reporter.cpp
+// start catch_interfaces_runner.cpp
+
+namespace Catch {
+ IRunner::~IRunner() = default;
+}
+// end catch_interfaces_runner.cpp
+// start catch_interfaces_testcase.cpp
+
+namespace Catch {
+ ITestInvoker::~ITestInvoker() = default;
+ ITestCaseRegistry::~ITestCaseRegistry() = default;
+}
+// end catch_interfaces_testcase.cpp
+// start catch_leak_detector.cpp
+
+#ifdef CATCH_CONFIG_WINDOWS_CRTDBG
+#include <crtdbg.h>
+
+namespace Catch {
+
+ LeakDetector::LeakDetector() {
+ int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
+ flag |= _CRTDBG_LEAK_CHECK_DF;
+ flag |= _CRTDBG_ALLOC_MEM_DF;
+ _CrtSetDbgFlag(flag);
+ _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+ _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
+ // Change this to leaking allocation's number to break there
+ _CrtSetBreakAlloc(-1);
+ }
+}
+
+#else
+
+ Catch::LeakDetector::LeakDetector() {}
+
+#endif
+// end catch_leak_detector.cpp
+// start catch_list.cpp
+
+// start catch_list.h
+
+#include <set>
+
+namespace Catch {
+
+ std::size_t listTests( Config const& config );
+
+ std::size_t listTestsNamesOnly( Config const& config );
+
+ struct TagInfo {
+ void add( std::string const& spelling );
+ std::string all() const;
+
+ std::set<std::string> spellings;
+ std::size_t count = 0;
+ };
+
+ std::size_t listTags( Config const& config );
+
+ std::size_t listReporters( Config const& /*config*/ );
+
+ Option<std::size_t> list( Config const& config );
+
+} // end namespace Catch
+
+// end catch_list.h
+// start catch_text.h
+
+namespace Catch {
+ using namespace clara::TextFlow;
+}
+
+// end catch_text.h
+#include <limits>
+#include <algorithm>
+#include <iomanip>
+
+namespace Catch {
+
+ std::size_t listTests( Config const& config ) {
+ TestSpec testSpec = config.testSpec();
+ if( config.hasTestFilters() )
+ Catch::cout() << "Matching test cases:\n";
+ else {
+ Catch::cout() << "All available test cases:\n";
+ }
+
+ auto matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
+ for( auto const& testCaseInfo : matchedTestCases ) {
+ Colour::Code colour = testCaseInfo.isHidden()
+ ? Colour::SecondaryText
+ : Colour::None;
+ Colour colourGuard( colour );
+
+ Catch::cout() << Column( testCaseInfo.name ).initialIndent( 2 ).indent( 4 ) << "\n";
+ if( config.verbosity() >= Verbosity::High ) {
+ Catch::cout() << Column( Catch::Detail::stringify( testCaseInfo.lineInfo ) ).indent(4) << std::endl;
+ std::string description = testCaseInfo.description;
+ if( description.empty() )
+ description = "(NO DESCRIPTION)";
+ Catch::cout() << Column( description ).indent(4) << std::endl;
+ }
+ if( !testCaseInfo.tags.empty() )
+ Catch::cout() << Column( testCaseInfo.tagsAsString() ).indent( 6 ) << "\n";
+ }
+
+ if( !config.hasTestFilters() )
+ Catch::cout() << pluralise( matchedTestCases.size(), "test case" ) << '\n' << std::endl;
+ else
+ Catch::cout() << pluralise( matchedTestCases.size(), "matching test case" ) << '\n' << std::endl;
+ return matchedTestCases.size();
+ }
+
+ std::size_t listTestsNamesOnly( Config const& config ) {
+ TestSpec testSpec = config.testSpec();
+ std::size_t matchedTests = 0;
+ std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
+ for( auto const& testCaseInfo : matchedTestCases ) {
+ matchedTests++;
+ if( startsWith( testCaseInfo.name, '#' ) )
+ Catch::cout() << '"' << testCaseInfo.name << '"';
+ else
+ Catch::cout() << testCaseInfo.name;
+ if ( config.verbosity() >= Verbosity::High )
+ Catch::cout() << "\t@" << testCaseInfo.lineInfo;
+ Catch::cout() << std::endl;
+ }
+ return matchedTests;
+ }
+
+ void TagInfo::add( std::string const& spelling ) {
+ ++count;
+ spellings.insert( spelling );
+ }
+
+ std::string TagInfo::all() const {
+ std::string out;
+ for( auto const& spelling : spellings )
+ out += "[" + spelling + "]";
+ return out;
+ }
+
+ std::size_t listTags( Config const& config ) {
+ TestSpec testSpec = config.testSpec();
+ if( config.hasTestFilters() )
+ Catch::cout() << "Tags for matching test cases:\n";
+ else {
+ Catch::cout() << "All available tags:\n";
+ }
+
+ std::map<std::string, TagInfo> tagCounts;
+
+ std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
+ for( auto const& testCase : matchedTestCases ) {
+ for( auto const& tagName : testCase.getTestCaseInfo().tags ) {
+ std::string lcaseTagName = toLower( tagName );
+ auto countIt = tagCounts.find( lcaseTagName );
+ if( countIt == tagCounts.end() )
+ countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first;
+ countIt->second.add( tagName );
+ }
+ }
+
+ for( auto const& tagCount : tagCounts ) {
+ ReusableStringStream rss;
+ rss << " " << std::setw(2) << tagCount.second.count << " ";
+ auto str = rss.str();
+ auto wrapper = Column( tagCount.second.all() )
+ .initialIndent( 0 )
+ .indent( str.size() )
+ .width( CATCH_CONFIG_CONSOLE_WIDTH-10 );
+ Catch::cout() << str << wrapper << '\n';
+ }
+ Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl;
+ return tagCounts.size();
+ }
+
+ std::size_t listReporters( Config const& /*config*/ ) {
+ Catch::cout() << "Available reporters:\n";
+ IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
+ std::size_t maxNameLen = 0;
+ for( auto const& factoryKvp : factories )
+ maxNameLen = (std::max)( maxNameLen, factoryKvp.first.size() );
+
+ for( auto const& factoryKvp : factories ) {
+ Catch::cout()
+ << Column( factoryKvp.first + ":" )
+ .indent(2)
+ .width( 5+maxNameLen )
+ + Column( factoryKvp.second->getDescription() )
+ .initialIndent(0)
+ .indent(2)
+ .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 )
+ << "\n";
+ }
+ Catch::cout() << std::endl;
+ return factories.size();
+ }
+
+ Option<std::size_t> list( Config const& config ) {
+ Option<std::size_t> listedCount;
+ if( config.listTests() )
+ listedCount = listedCount.valueOr(0) + listTests( config );
+ if( config.listTestNamesOnly() )
+ listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config );
+ if( config.listTags() )
+ listedCount = listedCount.valueOr(0) + listTags( config );
+ if( config.listReporters() )
+ listedCount = listedCount.valueOr(0) + listReporters( config );
+ return listedCount;
+ }
+
+} // end namespace Catch
+// end catch_list.cpp
+// start catch_matchers.cpp
+
+namespace Catch {
+namespace Matchers {
+ namespace Impl {
+
+ std::string MatcherUntypedBase::toString() const {
+ if( m_cachedToString.empty() )
+ m_cachedToString = describe();
+ return m_cachedToString;
+ }
+
+ MatcherUntypedBase::~MatcherUntypedBase() = default;
+
+ } // namespace Impl
+} // namespace Matchers
+
+using namespace Matchers;
+using Matchers::Impl::MatcherBase;
+
+} // namespace Catch
+// end catch_matchers.cpp
+// start catch_matchers_floating.cpp
+
+// start catch_to_string.hpp
+
+#include <string>
+
+namespace Catch {
+ template <typename T>
+ std::string to_string(T const& t) {
+#if defined(CATCH_CONFIG_CPP11_TO_STRING)
+ return std::to_string(t);
+#else
+ ReusableStringStream rss;
+ rss << t;
+ return rss.str();
+#endif
+ }
+} // end namespace Catch
+
+// end catch_to_string.hpp
+#include <cstdlib>
+#include <cstdint>
+#include <cstring>
+
+namespace Catch {
+namespace Matchers {
+namespace Floating {
+enum class FloatingPointKind : uint8_t {
+ Float,
+ Double
+};
+}
+}
+}
+
+namespace {
+
+template <typename T>
+struct Converter;
+
+template <>
+struct Converter<float> {
+ static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated");
+ Converter(float f) {
+ std::memcpy(&i, &f, sizeof(f));
+ }
+ int32_t i;
+};
+
+template <>
+struct Converter<double> {
+ static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated");
+ Converter(double d) {
+ std::memcpy(&i, &d, sizeof(d));
+ }
+ int64_t i;
+};
+
+template <typename T>
+auto convert(T t) -> Converter<T> {
+ return Converter<T>(t);
+}
+
+template <typename FP>
+bool almostEqualUlps(FP lhs, FP rhs, int maxUlpDiff) {
+ // Comparison with NaN should always be false.
+ // This way we can rule it out before getting into the ugly details
+ if (std::isnan(lhs) || std::isnan(rhs)) {
+ return false;
+ }
+
+ auto lc = convert(lhs);
+ auto rc = convert(rhs);
+
+ if ((lc.i < 0) != (rc.i < 0)) {
+ // Potentially we can have +0 and -0
+ return lhs == rhs;
+ }
+
+ auto ulpDiff = std::abs(lc.i - rc.i);
+ return ulpDiff <= maxUlpDiff;
+}
+
+}
+
+namespace Catch {
+namespace Matchers {
+namespace Floating {
+ WithinAbsMatcher::WithinAbsMatcher(double target, double margin)
+ :m_target{ target }, m_margin{ margin } {
+ CATCH_ENFORCE(margin >= 0, "Invalid margin: " << margin << '.'
+ << " Margin has to be non-negative.");
+ }
+
+ // Performs equivalent check of std::fabs(lhs - rhs) <= margin
+ // But without the subtraction to allow for INFINITY in comparison
+ bool WithinAbsMatcher::match(double const& matchee) const {
+ return (matchee + m_margin >= m_target) && (m_target + m_margin >= matchee);
+ }
+
+ std::string WithinAbsMatcher::describe() const {
+ return "is within " + ::Catch::Detail::stringify(m_margin) + " of " + ::Catch::Detail::stringify(m_target);
+ }
+
+ WithinUlpsMatcher::WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType)
+ :m_target{ target }, m_ulps{ ulps }, m_type{ baseType } {
+ CATCH_ENFORCE(ulps >= 0, "Invalid ULP setting: " << ulps << '.'
+ << " ULPs have to be non-negative.");
+ }
+
+#if defined(__clang__)
+#pragma clang diagnostic push
+// Clang <3.5 reports on the default branch in the switch below
+#pragma clang diagnostic ignored "-Wunreachable-code"
+#endif
+
+ bool WithinUlpsMatcher::match(double const& matchee) const {
+ switch (m_type) {
+ case FloatingPointKind::Float:
+ return almostEqualUlps<float>(static_cast<float>(matchee), static_cast<float>(m_target), m_ulps);
+ case FloatingPointKind::Double:
+ return almostEqualUlps<double>(matchee, m_target, m_ulps);
+ default:
+ CATCH_INTERNAL_ERROR( "Unknown FloatingPointKind value" );
+ }
+ }
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
+ std::string WithinUlpsMatcher::describe() const {
+ return "is within " + Catch::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : "");
+ }
+
+}// namespace Floating
+
+Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff) {
+ return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Double);
+}
+
+Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff) {
+ return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Float);
+}
+
+Floating::WithinAbsMatcher WithinAbs(double target, double margin) {
+ return Floating::WithinAbsMatcher(target, margin);
+}
+
+} // namespace Matchers
+} // namespace Catch
+
+// end catch_matchers_floating.cpp
+// start catch_matchers_generic.cpp
+
+std::string Catch::Matchers::Generic::Detail::finalizeDescription(const std::string& desc) {
+ if (desc.empty()) {
+ return "matches undescribed predicate";
+ } else {
+ return "matches predicate: \"" + desc + '"';
+ }
+}
+// end catch_matchers_generic.cpp
+// start catch_matchers_string.cpp
+
+#include <regex>
+
+namespace Catch {
+namespace Matchers {
+
+ namespace StdString {
+
+ CasedString::CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity )
+ : m_caseSensitivity( caseSensitivity ),
+ m_str( adjustString( str ) )
+ {}
+ std::string CasedString::adjustString( std::string const& str ) const {
+ return m_caseSensitivity == CaseSensitive::No
+ ? toLower( str )
+ : str;
+ }
+ std::string CasedString::caseSensitivitySuffix() const {
+ return m_caseSensitivity == CaseSensitive::No
+ ? " (case insensitive)"
+ : std::string();
+ }
+
+ StringMatcherBase::StringMatcherBase( std::string const& operation, CasedString const& comparator )
+ : m_comparator( comparator ),
+ m_operation( operation ) {
+ }
+
+ std::string StringMatcherBase::describe() const {
+ std::string description;
+ description.reserve(5 + m_operation.size() + m_comparator.m_str.size() +
+ m_comparator.caseSensitivitySuffix().size());
+ description += m_operation;
+ description += ": \"";
+ description += m_comparator.m_str;
+ description += "\"";
+ description += m_comparator.caseSensitivitySuffix();
+ return description;
+ }
+
+ EqualsMatcher::EqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals", comparator ) {}
+
+ bool EqualsMatcher::match( std::string const& source ) const {
+ return m_comparator.adjustString( source ) == m_comparator.m_str;
+ }
+
+ ContainsMatcher::ContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains", comparator ) {}
+
+ bool ContainsMatcher::match( std::string const& source ) const {
+ return contains( m_comparator.adjustString( source ), m_comparator.m_str );
+ }
+
+ StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with", comparator ) {}
+
+ bool StartsWithMatcher::match( std::string const& source ) const {
+ return startsWith( m_comparator.adjustString( source ), m_comparator.m_str );
+ }
+
+ EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with", comparator ) {}
+
+ bool EndsWithMatcher::match( std::string const& source ) const {
+ return endsWith( m_comparator.adjustString( source ), m_comparator.m_str );
+ }
+
+ RegexMatcher::RegexMatcher(std::string regex, CaseSensitive::Choice caseSensitivity): m_regex(std::move(regex)), m_caseSensitivity(caseSensitivity) {}
+
+ bool RegexMatcher::match(std::string const& matchee) const {
+ auto flags = std::regex::ECMAScript; // ECMAScript is the default syntax option anyway
+ if (m_caseSensitivity == CaseSensitive::Choice::No) {
+ flags |= std::regex::icase;
+ }
+ auto reg = std::regex(m_regex, flags);
+ return std::regex_match(matchee, reg);
+ }
+
+ std::string RegexMatcher::describe() const {
+ return "matches " + ::Catch::Detail::stringify(m_regex) + ((m_caseSensitivity == CaseSensitive::Choice::Yes)? " case sensitively" : " case insensitively");
+ }
+
+ } // namespace StdString
+
+ StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
+ return StdString::EqualsMatcher( StdString::CasedString( str, caseSensitivity) );
+ }
+ StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
+ return StdString::ContainsMatcher( StdString::CasedString( str, caseSensitivity) );
+ }
+ StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
+ return StdString::EndsWithMatcher( StdString::CasedString( str, caseSensitivity) );
+ }
+ StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
+ return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) );
+ }
+
+ StdString::RegexMatcher Matches(std::string const& regex, CaseSensitive::Choice caseSensitivity) {
+ return StdString::RegexMatcher(regex, caseSensitivity);
+ }
+
+} // namespace Matchers
+} // namespace Catch
+// end catch_matchers_string.cpp
+// start catch_message.cpp
+
+// start catch_uncaught_exceptions.h
+
+namespace Catch {
+ bool uncaught_exceptions();
+} // end namespace Catch
+
+// end catch_uncaught_exceptions.h
+#include <cassert>
+
+namespace Catch {
+
+ MessageInfo::MessageInfo( StringRef const& _macroName,
+ SourceLineInfo const& _lineInfo,
+ ResultWas::OfType _type )
+ : macroName( _macroName ),
+ lineInfo( _lineInfo ),
+ type( _type ),
+ sequence( ++globalCount )
+ {}
+
+ bool MessageInfo::operator==( MessageInfo const& other ) const {
+ return sequence == other.sequence;
+ }
+
+ bool MessageInfo::operator<( MessageInfo const& other ) const {
+ return sequence < other.sequence;
+ }
+
+ // This may need protecting if threading support is added
+ unsigned int MessageInfo::globalCount = 0;
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ Catch::MessageBuilder::MessageBuilder( StringRef const& macroName,
+ SourceLineInfo const& lineInfo,
+ ResultWas::OfType type )
+ :m_info(macroName, lineInfo, type) {}
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ ScopedMessage::ScopedMessage( MessageBuilder const& builder )
+ : m_info( builder.m_info )
+ {
+ m_info.message = builder.m_stream.str();
+ getResultCapture().pushScopedMessage( m_info );
+ }
+
+ ScopedMessage::~ScopedMessage() {
+ if ( !uncaught_exceptions() ){
+ getResultCapture().popScopedMessage(m_info);
+ }
+ }
+
+ Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) {
+ auto start = std::string::npos;
+ for( size_t pos = 0; pos <= names.size(); ++pos ) {
+ char c = names[pos];
+ if( pos == names.size() || c == ' ' || c == '\t' || c == ',' || c == ']' ) {
+ if( start != std::string::npos ) {
+ m_messages.push_back( MessageInfo( macroName, lineInfo, resultType ) );
+ m_messages.back().message = names.substr( start, pos-start) + " := ";
+ start = std::string::npos;
+ }
+ }
+ else if( c != '[' && c != ']' && start == std::string::npos )
+ start = pos;
+ }
+ }
+ Capturer::~Capturer() {
+ if ( !uncaught_exceptions() ){
+ assert( m_captured == m_messages.size() );
+ for( size_t i = 0; i < m_captured; ++i )
+ m_resultCapture.popScopedMessage( m_messages[i] );
+ }
+ }
+
+ void Capturer::captureValue( size_t index, StringRef value ) {
+ assert( index < m_messages.size() );
+ m_messages[index].message += value;
+ m_resultCapture.pushScopedMessage( m_messages[index] );
+ m_captured++;
+ }
+
+} // end namespace Catch
+// end catch_message.cpp
+// start catch_output_redirect.cpp
+
+// start catch_output_redirect.h
+#ifndef TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H
+#define TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H
+
+#include <cstdio>
+#include <iosfwd>
+#include <string>
+
+namespace Catch {
+
+ class RedirectedStream {
+ std::ostream& m_originalStream;
+ std::ostream& m_redirectionStream;
+ std::streambuf* m_prevBuf;
+
+ public:
+ RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream );
+ ~RedirectedStream();
+ };
+
+ class RedirectedStdOut {
+ ReusableStringStream m_rss;
+ RedirectedStream m_cout;
+ public:
+ RedirectedStdOut();
+ auto str() const -> std::string;
+ };
+
+ // StdErr has two constituent streams in C++, std::cerr and std::clog
+ // This means that we need to redirect 2 streams into 1 to keep proper
+ // order of writes
+ class RedirectedStdErr {
+ ReusableStringStream m_rss;
+ RedirectedStream m_cerr;
+ RedirectedStream m_clog;
+ public:
+ RedirectedStdErr();
+ auto str() const -> std::string;
+ };
+
+#if defined(CATCH_CONFIG_NEW_CAPTURE)
+
+ // Windows's implementation of std::tmpfile is terrible (it tries
+ // to create a file inside system folder, thus requiring elevated
+ // privileges for the binary), so we have to use tmpnam(_s) and
+ // create the file ourselves there.
+ class TempFile {
+ public:
+ TempFile(TempFile const&) = delete;
+ TempFile& operator=(TempFile const&) = delete;
+ TempFile(TempFile&&) = delete;
+ TempFile& operator=(TempFile&&) = delete;
+
+ TempFile();
+ ~TempFile();
+
+ std::FILE* getFile();
+ std::string getContents();
+
+ private:
+ std::FILE* m_file = nullptr;
+ #if defined(_MSC_VER)
+ char m_buffer[L_tmpnam] = { 0 };
+ #endif
+ };
+
+ class OutputRedirect {
+ public:
+ OutputRedirect(OutputRedirect const&) = delete;
+ OutputRedirect& operator=(OutputRedirect const&) = delete;
+ OutputRedirect(OutputRedirect&&) = delete;
+ OutputRedirect& operator=(OutputRedirect&&) = delete;
+
+ OutputRedirect(std::string& stdout_dest, std::string& stderr_dest);
+ ~OutputRedirect();
+
+ private:
+ int m_originalStdout = -1;
+ int m_originalStderr = -1;
+ TempFile m_stdoutFile;
+ TempFile m_stderrFile;
+ std::string& m_stdoutDest;
+ std::string& m_stderrDest;
+ };
+
+#endif
+
+} // end namespace Catch
+
+#endif // TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H
+// end catch_output_redirect.h
+#include <cstdio>
+#include <cstring>
+#include <fstream>
+#include <sstream>
+#include <stdexcept>
+
+#if defined(CATCH_CONFIG_NEW_CAPTURE)
+ #if defined(_MSC_VER)
+ #include <io.h> //_dup and _dup2
+ #define dup _dup
+ #define dup2 _dup2
+ #define fileno _fileno
+ #else
+ #include <unistd.h> // dup and dup2
+ #endif
+#endif
+
+namespace Catch {
+
+ RedirectedStream::RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream )
+ : m_originalStream( originalStream ),
+ m_redirectionStream( redirectionStream ),
+ m_prevBuf( m_originalStream.rdbuf() )
+ {
+ m_originalStream.rdbuf( m_redirectionStream.rdbuf() );
+ }
+
+ RedirectedStream::~RedirectedStream() {
+ m_originalStream.rdbuf( m_prevBuf );
+ }
+
+ RedirectedStdOut::RedirectedStdOut() : m_cout( Catch::cout(), m_rss.get() ) {}
+ auto RedirectedStdOut::str() const -> std::string { return m_rss.str(); }
+
+ RedirectedStdErr::RedirectedStdErr()
+ : m_cerr( Catch::cerr(), m_rss.get() ),
+ m_clog( Catch::clog(), m_rss.get() )
+ {}
+ auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); }
+
+#if defined(CATCH_CONFIG_NEW_CAPTURE)
+
+#if defined(_MSC_VER)
+ TempFile::TempFile() {
+ if (tmpnam_s(m_buffer)) {
+ CATCH_RUNTIME_ERROR("Could not get a temp filename");
+ }
+ if (fopen_s(&m_file, m_buffer, "w")) {
+ char buffer[100];
+ if (strerror_s(buffer, errno)) {
+ CATCH_RUNTIME_ERROR("Could not translate errno to a string");
+ }
+ CATCH_RUNTIME_ERROR("Coul dnot open the temp file: '" << m_buffer << "' because: " << buffer);
+ }
+ }
+#else
+ TempFile::TempFile() {
+ m_file = std::tmpfile();
+ if (!m_file) {
+ CATCH_RUNTIME_ERROR("Could not create a temp file.");
+ }
+ }
+
+#endif
+
+ TempFile::~TempFile() {
+ // TBD: What to do about errors here?
+ std::fclose(m_file);
+ // We manually create the file on Windows only, on Linux
+ // it will be autodeleted
+#if defined(_MSC_VER)
+ std::remove(m_buffer);
+#endif
+ }
+
+ FILE* TempFile::getFile() {
+ return m_file;
+ }
+
+ std::string TempFile::getContents() {
+ std::stringstream sstr;
+ char buffer[100] = {};
+ std::rewind(m_file);
+ while (std::fgets(buffer, sizeof(buffer), m_file)) {
+ sstr << buffer;
+ }
+ return sstr.str();
+ }
+
+ OutputRedirect::OutputRedirect(std::string& stdout_dest, std::string& stderr_dest) :
+ m_originalStdout(dup(1)),
+ m_originalStderr(dup(2)),
+ m_stdoutDest(stdout_dest),
+ m_stderrDest(stderr_dest) {
+ dup2(fileno(m_stdoutFile.getFile()), 1);
+ dup2(fileno(m_stderrFile.getFile()), 2);
+ }
+
+ OutputRedirect::~OutputRedirect() {
+ Catch::cout() << std::flush;
+ fflush(stdout);
+ // Since we support overriding these streams, we flush cerr
+ // even though std::cerr is unbuffered
+ Catch::cerr() << std::flush;
+ Catch::clog() << std::flush;
+ fflush(stderr);
+
+ dup2(m_originalStdout, 1);
+ dup2(m_originalStderr, 2);
+
+ m_stdoutDest += m_stdoutFile.getContents();
+ m_stderrDest += m_stderrFile.getContents();
+ }
+
+#endif // CATCH_CONFIG_NEW_CAPTURE
+
+} // namespace Catch
+
+#if defined(CATCH_CONFIG_NEW_CAPTURE)
+ #if defined(_MSC_VER)
+ #undef dup
+ #undef dup2
+ #undef fileno
+ #endif
+#endif
+// end catch_output_redirect.cpp
+// start catch_random_number_generator.cpp
+
+namespace Catch {
+
+ std::mt19937& rng() {
+ static std::mt19937 s_rng;
+ return s_rng;
+ }
+
+ void seedRng( IConfig const& config ) {
+ if( config.rngSeed() != 0 ) {
+ std::srand( config.rngSeed() );
+ rng().seed( config.rngSeed() );
+ }
+ }
+
+ unsigned int rngSeed() {
+ return getCurrentContext().getConfig()->rngSeed();
+ }
+}
+// end catch_random_number_generator.cpp
+// start catch_registry_hub.cpp
+
+// start catch_test_case_registry_impl.h
+
+#include <vector>
+#include <set>
+#include <algorithm>
+#include <ios>
+
+namespace Catch {
+
+ class TestCase;
+ struct IConfig;
+
+ std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases );
+ bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );
+
+ void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions );
+
+ std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config );
+ std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config );
+
+ class TestRegistry : public ITestCaseRegistry {
+ public:
+ virtual ~TestRegistry() = default;
+
+ virtual void registerTest( TestCase const& testCase );
+
+ std::vector<TestCase> const& getAllTests() const override;
+ std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const override;
+
+ private:
+ std::vector<TestCase> m_functions;
+ mutable RunTests::InWhatOrder m_currentSortOrder = RunTests::InDeclarationOrder;
+ mutable std::vector<TestCase> m_sortedFunctions;
+ std::size_t m_unnamedCount = 0;
+ std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ class TestInvokerAsFunction : public ITestInvoker {
+ void(*m_testAsFunction)();
+ public:
+ TestInvokerAsFunction( void(*testAsFunction)() ) noexcept;
+
+ void invoke() const override;
+ };
+
+ std::string extractClassName( StringRef const& classOrQualifiedMethodName );
+
+ ///////////////////////////////////////////////////////////////////////////
+
+} // end namespace Catch
+
+// end catch_test_case_registry_impl.h
+// start catch_reporter_registry.h
+
+#include <map>
+
+namespace Catch {
+
+ class ReporterRegistry : public IReporterRegistry {
+
+ public:
+
+ ~ReporterRegistry() override;
+
+ IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const override;
+
+ void registerReporter( std::string const& name, IReporterFactoryPtr const& factory );
+ void registerListener( IReporterFactoryPtr const& factory );
+
+ FactoryMap const& getFactories() const override;
+ Listeners const& getListeners() const override;
+
+ private:
+ FactoryMap m_factories;
+ Listeners m_listeners;
+ };
+}
+
+// end catch_reporter_registry.h
+// start catch_tag_alias_registry.h
+
+// start catch_tag_alias.h
+
+#include <string>
+
+namespace Catch {
+
+ struct TagAlias {
+ TagAlias(std::string const& _tag, SourceLineInfo _lineInfo);
+
+ std::string tag;
+ SourceLineInfo lineInfo;
+ };
+
+} // end namespace Catch
+
+// end catch_tag_alias.h
+#include <map>
+
+namespace Catch {
+
+ class TagAliasRegistry : public ITagAliasRegistry {
+ public:
+ ~TagAliasRegistry() override;
+ TagAlias const* find( std::string const& alias ) const override;
+ std::string expandAliases( std::string const& unexpandedTestSpec ) const override;
+ void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo );
+
+ private:
+ std::map<std::string, TagAlias> m_registry;
+ };
+
+} // end namespace Catch
+
+// end catch_tag_alias_registry.h
+// start catch_startup_exception_registry.h
+
+#include <vector>
+#include <exception>
+
+namespace Catch {
+
+ class StartupExceptionRegistry {
+ public:
+ void add(std::exception_ptr const& exception) noexcept;
+ std::vector<std::exception_ptr> const& getExceptions() const noexcept;
+ private:
+ std::vector<std::exception_ptr> m_exceptions;
+ };
+
+} // end namespace Catch
+
+// end catch_startup_exception_registry.h
+// start catch_singletons.hpp
+
+namespace Catch {
+
+ struct ISingleton {
+ virtual ~ISingleton();
+ };
+
+ void addSingleton( ISingleton* singleton );
+ void cleanupSingletons();
+
+ template<typename SingletonImplT, typename InterfaceT = SingletonImplT, typename MutableInterfaceT = InterfaceT>
+ class Singleton : SingletonImplT, public ISingleton {
+
+ static auto getInternal() -> Singleton* {
+ static Singleton* s_instance = nullptr;
+ if( !s_instance ) {
+ s_instance = new Singleton;
+ addSingleton( s_instance );
+ }
+ return s_instance;
+ }
+
+ public:
+ static auto get() -> InterfaceT const& {
+ return *getInternal();
+ }
+ static auto getMutable() -> MutableInterfaceT& {
+ return *getInternal();
+ }
+ };
+
+} // namespace Catch
+
+// end catch_singletons.hpp
+namespace Catch {
+
+ namespace {
+
+ class RegistryHub : public IRegistryHub, public IMutableRegistryHub,
+ private NonCopyable {
+
+ public: // IRegistryHub
+ RegistryHub() = default;
+ IReporterRegistry const& getReporterRegistry() const override {
+ return m_reporterRegistry;
+ }
+ ITestCaseRegistry const& getTestCaseRegistry() const override {
+ return m_testCaseRegistry;
+ }
+ IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const override {
+ return m_exceptionTranslatorRegistry;
+ }
+ ITagAliasRegistry const& getTagAliasRegistry() const override {
+ return m_tagAliasRegistry;
+ }
+ StartupExceptionRegistry const& getStartupExceptionRegistry() const override {
+ return m_exceptionRegistry;
+ }
+
+ public: // IMutableRegistryHub
+ void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) override {
+ m_reporterRegistry.registerReporter( name, factory );
+ }
+ void registerListener( IReporterFactoryPtr const& factory ) override {
+ m_reporterRegistry.registerListener( factory );
+ }
+ void registerTest( TestCase const& testInfo ) override {
+ m_testCaseRegistry.registerTest( testInfo );
+ }
+ void registerTranslator( const IExceptionTranslator* translator ) override {
+ m_exceptionTranslatorRegistry.registerTranslator( translator );
+ }
+ void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) override {
+ m_tagAliasRegistry.add( alias, tag, lineInfo );
+ }
+ void registerStartupException() noexcept override {
+ m_exceptionRegistry.add(std::current_exception());
+ }
+
+ private:
+ TestRegistry m_testCaseRegistry;
+ ReporterRegistry m_reporterRegistry;
+ ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
+ TagAliasRegistry m_tagAliasRegistry;
+ StartupExceptionRegistry m_exceptionRegistry;
+ };
+ }
+
+ using RegistryHubSingleton = Singleton<RegistryHub, IRegistryHub, IMutableRegistryHub>;
+
+ IRegistryHub const& getRegistryHub() {
+ return RegistryHubSingleton::get();
+ }
+ IMutableRegistryHub& getMutableRegistryHub() {
+ return RegistryHubSingleton::getMutable();
+ }
+ void cleanUp() {
+ cleanupSingletons();
+ cleanUpContext();
+ }
+ std::string translateActiveException() {
+ return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
+ }
+
+} // end namespace Catch
+// end catch_registry_hub.cpp
+// start catch_reporter_registry.cpp
+
+namespace Catch {
+
+ ReporterRegistry::~ReporterRegistry() = default;
+
+ IStreamingReporterPtr ReporterRegistry::create( std::string const& name, IConfigPtr const& config ) const {
+ auto it = m_factories.find( name );
+ if( it == m_factories.end() )
+ return nullptr;
+ return it->second->create( ReporterConfig( config ) );
+ }
+
+ void ReporterRegistry::registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) {
+ m_factories.emplace(name, factory);
+ }
+ void ReporterRegistry::registerListener( IReporterFactoryPtr const& factory ) {
+ m_listeners.push_back( factory );
+ }
+
+ IReporterRegistry::FactoryMap const& ReporterRegistry::getFactories() const {
+ return m_factories;
+ }
+ IReporterRegistry::Listeners const& ReporterRegistry::getListeners() const {
+ return m_listeners;
+ }
+
+}
+// end catch_reporter_registry.cpp
+// start catch_result_type.cpp
+
+namespace Catch {
+
+ bool isOk( ResultWas::OfType resultType ) {
+ return ( resultType & ResultWas::FailureBit ) == 0;
+ }
+ bool isJustInfo( int flags ) {
+ return flags == ResultWas::Info;
+ }
+
+ ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) {
+ return static_cast<ResultDisposition::Flags>( static_cast<int>( lhs ) | static_cast<int>( rhs ) );
+ }
+
+ bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; }
+ bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; }
+
+} // end namespace Catch
+// end catch_result_type.cpp
+// start catch_run_context.cpp
+
+#include <cassert>
+#include <algorithm>
+#include <sstream>
+
+namespace Catch {
+
+ namespace Generators {
+ struct GeneratorTracker : TestCaseTracking::TrackerBase, IGeneratorTracker {
+ size_t m_index = static_cast<size_t>( -1 );
+ GeneratorBasePtr m_generator;
+
+ GeneratorTracker( TestCaseTracking::NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
+ : TrackerBase( nameAndLocation, ctx, parent )
+ {}
+ ~GeneratorTracker();
+
+ static GeneratorTracker& acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocation const& nameAndLocation ) {
+ std::shared_ptr<GeneratorTracker> tracker;
+
+ ITracker& currentTracker = ctx.currentTracker();
+ if( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {
+ assert( childTracker );
+ assert( childTracker->isIndexTracker() );
+ tracker = std::static_pointer_cast<GeneratorTracker>( childTracker );
+ }
+ else {
+ tracker = std::make_shared<GeneratorTracker>( nameAndLocation, ctx, &currentTracker );
+ currentTracker.addChild( tracker );
+ }
+
+ if( !ctx.completedCycle() && !tracker->isComplete() ) {
+ if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun )
+ tracker->moveNext();
+ tracker->open();
+ }
+
+ return *tracker;
+ }
+
+ void moveNext() {
+ m_index++;
+ m_children.clear();
+ }
+
+ // TrackerBase interface
+ bool isIndexTracker() const override { return true; }
+ auto hasGenerator() const -> bool override {
+ return !!m_generator;
+ }
+ void close() override {
+ TrackerBase::close();
+ if( m_runState == CompletedSuccessfully && m_index < m_generator->size()-1 )
+ m_runState = Executing;
+ }
+
+ // IGeneratorTracker interface
+ auto getGenerator() const -> GeneratorBasePtr const& override {
+ return m_generator;
+ }
+ void setGenerator( GeneratorBasePtr&& generator ) override {
+ m_generator = std::move( generator );
+ }
+ auto getIndex() const -> size_t override {
+ return m_index;
+ }
+ };
+ GeneratorTracker::~GeneratorTracker() {}
+ }
+
+ RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter)
+ : m_runInfo(_config->name()),
+ m_context(getCurrentMutableContext()),
+ m_config(_config),
+ m_reporter(std::move(reporter)),
+ m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal },
+ m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions )
+ {
+ m_context.setRunner(this);
+ m_context.setConfig(m_config);
+ m_context.setResultCapture(this);
+ m_reporter->testRunStarting(m_runInfo);
+ }
+
+ RunContext::~RunContext() {
+ m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting()));
+ }
+
+ void RunContext::testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount) {
+ m_reporter->testGroupStarting(GroupInfo(testSpec, groupIndex, groupsCount));
+ }
+
+ void RunContext::testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount) {
+ m_reporter->testGroupEnded(TestGroupStats(GroupInfo(testSpec, groupIndex, groupsCount), totals, aborting()));
+ }
+
+ Totals RunContext::runTest(TestCase const& testCase) {
+ Totals prevTotals = m_totals;
+
+ std::string redirectedCout;
+ std::string redirectedCerr;
+
+ auto const& testInfo = testCase.getTestCaseInfo();
+
+ m_reporter->testCaseStarting(testInfo);
+
+ m_activeTestCase = &testCase;
+
+ ITracker& rootTracker = m_trackerContext.startRun();
+ assert(rootTracker.isSectionTracker());
+ static_cast<SectionTracker&>(rootTracker).addInitialFilters(m_config->getSectionsToRun());
+ do {
+ m_trackerContext.startCycle();
+ m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(testInfo.name, testInfo.lineInfo));
+ runCurrentTest(redirectedCout, redirectedCerr);
+ } while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting());
+
+ Totals deltaTotals = m_totals.delta(prevTotals);
+ if (testInfo.expectedToFail() && deltaTotals.testCases.passed > 0) {
+ deltaTotals.assertions.failed++;
+ deltaTotals.testCases.passed--;
+ deltaTotals.testCases.failed++;
+ }
+ m_totals.testCases += deltaTotals.testCases;
+ m_reporter->testCaseEnded(TestCaseStats(testInfo,
+ deltaTotals,
+ redirectedCout,
+ redirectedCerr,
+ aborting()));
+
+ m_activeTestCase = nullptr;
+ m_testCaseTracker = nullptr;
+
+ return deltaTotals;
+ }
+
+ IConfigPtr RunContext::config() const {
+ return m_config;
+ }
+
+ IStreamingReporter& RunContext::reporter() const {
+ return *m_reporter;
+ }
+
+ void RunContext::assertionEnded(AssertionResult const & result) {
+ if (result.getResultType() == ResultWas::Ok) {
+ m_totals.assertions.passed++;
+ m_lastAssertionPassed = true;
+ } else if (!result.isOk()) {
+ m_lastAssertionPassed = false;
+ if( m_activeTestCase->getTestCaseInfo().okToFail() )
+ m_totals.assertions.failedButOk++;
+ else
+ m_totals.assertions.failed++;
+ }
+ else {
+ m_lastAssertionPassed = true;
+ }
+
+ // We have no use for the return value (whether messages should be cleared), because messages were made scoped
+ // and should be let to clear themselves out.
+ static_cast<void>(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals)));
+
+ // Reset working state
+ resetAssertionInfo();
+ m_lastResult = result;
+ }
+ void RunContext::resetAssertionInfo() {
+ m_lastAssertionInfo.macroName = StringRef();
+ m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr;
+ }
+
+ bool RunContext::sectionStarted(SectionInfo const & sectionInfo, Counts & assertions) {
+ ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(sectionInfo.name, sectionInfo.lineInfo));
+ if (!sectionTracker.isOpen())
+ return false;
+ m_activeSections.push_back(&sectionTracker);
+
+ m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
+
+ m_reporter->sectionStarting(sectionInfo);
+
+ assertions = m_totals.assertions;
+
+ return true;
+ }
+ auto RunContext::acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
+ using namespace Generators;
+ GeneratorTracker& tracker = GeneratorTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( "generator", lineInfo ) );
+ assert( tracker.isOpen() );
+ m_lastAssertionInfo.lineInfo = lineInfo;
+ return tracker;
+ }
+
+ bool RunContext::testForMissingAssertions(Counts& assertions) {
+ if (assertions.total() != 0)
+ return false;
+ if (!m_config->warnAboutMissingAssertions())
+ return false;
+ if (m_trackerContext.currentTracker().hasChildren())
+ return false;
+ m_totals.assertions.failed++;
+ assertions.failed++;
+ return true;
+ }
+
+ void RunContext::sectionEnded(SectionEndInfo const & endInfo) {
+ Counts assertions = m_totals.assertions - endInfo.prevAssertions;
+ bool missingAssertions = testForMissingAssertions(assertions);
+
+ if (!m_activeSections.empty()) {
+ m_activeSections.back()->close();
+ m_activeSections.pop_back();
+ }
+
+ m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions));
+ m_messages.clear();
+ }
+
+ void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) {
+ if (m_unfinishedSections.empty())
+ m_activeSections.back()->fail();
+ else
+ m_activeSections.back()->close();
+ m_activeSections.pop_back();
+
+ m_unfinishedSections.push_back(endInfo);
+ }
+ void RunContext::benchmarkStarting( BenchmarkInfo const& info ) {
+ m_reporter->benchmarkStarting( info );
+ }
+ void RunContext::benchmarkEnded( BenchmarkStats const& stats ) {
+ m_reporter->benchmarkEnded( stats );
+ }
+
+ void RunContext::pushScopedMessage(MessageInfo const & message) {
+ m_messages.push_back(message);
+ }
+
+ void RunContext::popScopedMessage(MessageInfo const & message) {
+ m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end());
+ }
+
+ std::string RunContext::getCurrentTestName() const {
+ return m_activeTestCase
+ ? m_activeTestCase->getTestCaseInfo().name
+ : std::string();
+ }
+
+ const AssertionResult * RunContext::getLastResult() const {
+ return &(*m_lastResult);
+ }
+
+ void RunContext::exceptionEarlyReported() {
+ m_shouldReportUnexpected = false;
+ }
+
+ void RunContext::handleFatalErrorCondition( StringRef message ) {
+ // First notify reporter that bad things happened
+ m_reporter->fatalErrorEncountered(message);
+
+ // Don't rebuild the result -- the stringification itself can cause more fatal errors
+ // Instead, fake a result data.
+ AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } );
+ tempResult.message = message;
+ AssertionResult result(m_lastAssertionInfo, tempResult);
+
+ assertionEnded(result);
+
+ handleUnfinishedSections();
+
+ // Recreate section for test case (as we will lose the one that was in scope)
+ auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
+ SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name);
+
+ Counts assertions;
+ assertions.failed = 1;
+ SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false);
+ m_reporter->sectionEnded(testCaseSectionStats);
+
+ auto const& testInfo = m_activeTestCase->getTestCaseInfo();
+
+ Totals deltaTotals;
+ deltaTotals.testCases.failed = 1;
+ deltaTotals.assertions.failed = 1;
+ m_reporter->testCaseEnded(TestCaseStats(testInfo,
+ deltaTotals,
+ std::string(),
+ std::string(),
+ false));
+ m_totals.testCases.failed++;
+ testGroupEnded(std::string(), m_totals, 1, 1);
+ m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false));
+ }
+
+ bool RunContext::lastAssertionPassed() {
+ return m_lastAssertionPassed;
+ }
+
+ void RunContext::assertionPassed() {
+ m_lastAssertionPassed = true;
+ ++m_totals.assertions.passed;
+ resetAssertionInfo();
+ }
+
+ bool RunContext::aborting() const {
+ return m_totals.assertions.failed == static_cast<std::size_t>(m_config->abortAfter());
+ }
+
+ void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) {
+ auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
+ SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name);
+ m_reporter->sectionStarting(testCaseSection);
+ Counts prevAssertions = m_totals.assertions;
+ double duration = 0;
+ m_shouldReportUnexpected = true;
+ m_lastAssertionInfo = { "TEST_CASE"_sr, testCaseInfo.lineInfo, StringRef(), ResultDisposition::Normal };
+
+ seedRng(*m_config);
+
+ Timer timer;
+ CATCH_TRY {
+ if (m_reporter->getPreferences().shouldRedirectStdOut) {
+#if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
+ RedirectedStdOut redirectedStdOut;
+ RedirectedStdErr redirectedStdErr;
+
+ timer.start();
+ invokeActiveTestCase();
+ redirectedCout += redirectedStdOut.str();
+ redirectedCerr += redirectedStdErr.str();
+#else
+ OutputRedirect r(redirectedCout, redirectedCerr);
+ timer.start();
+ invokeActiveTestCase();
+#endif
+ } else {
+ timer.start();
+ invokeActiveTestCase();
+ }
+ duration = timer.getElapsedSeconds();
+ } CATCH_CATCH_ANON (TestFailureException&) {
+ // This just means the test was aborted due to failure
+ } CATCH_CATCH_ALL {
+ // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions
+ // are reported without translation at the point of origin.
+ if( m_shouldReportUnexpected ) {
+ AssertionReaction dummyReaction;
+ handleUnexpectedInflightException( m_lastAssertionInfo, translateActiveException(), dummyReaction );
+ }
+ }
+ Counts assertions = m_totals.assertions - prevAssertions;
+ bool missingAssertions = testForMissingAssertions(assertions);
+
+ m_testCaseTracker->close();
+ handleUnfinishedSections();
+ m_messages.clear();
+
+ SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions);
+ m_reporter->sectionEnded(testCaseSectionStats);
+ }
+
+ void RunContext::invokeActiveTestCase() {
+ FatalConditionHandler fatalConditionHandler; // Handle signals
+ m_activeTestCase->invoke();
+ fatalConditionHandler.reset();
+ }
+
+ void RunContext::handleUnfinishedSections() {
+ // If sections ended prematurely due to an exception we stored their
+ // infos here so we can tear them down outside the unwind process.
+ for (auto it = m_unfinishedSections.rbegin(),
+ itEnd = m_unfinishedSections.rend();
+ it != itEnd;
+ ++it)
+ sectionEnded(*it);
+ m_unfinishedSections.clear();
+ }
+
+ void RunContext::handleExpr(
+ AssertionInfo const& info,
+ ITransientExpression const& expr,
+ AssertionReaction& reaction
+ ) {
+ m_reporter->assertionStarting( info );
+
+ bool negated = isFalseTest( info.resultDisposition );
+ bool result = expr.getResult() != negated;
+
+ if( result ) {
+ if (!m_includeSuccessfulResults) {
+ assertionPassed();
+ }
+ else {
+ reportExpr(info, ResultWas::Ok, &expr, negated);
+ }
+ }
+ else {
+ reportExpr(info, ResultWas::ExpressionFailed, &expr, negated );
+ populateReaction( reaction );
+ }
+ }
+ void RunContext::reportExpr(
+ AssertionInfo const &info,
+ ResultWas::OfType resultType,
+ ITransientExpression const *expr,
+ bool negated ) {
+
+ m_lastAssertionInfo = info;
+ AssertionResultData data( resultType, LazyExpression( negated ) );
+
+ AssertionResult assertionResult{ info, data };
+ assertionResult.m_resultData.lazyExpression.m_transientExpression = expr;
+
+ assertionEnded( assertionResult );
+ }
+
+ void RunContext::handleMessage(
+ AssertionInfo const& info,
+ ResultWas::OfType resultType,
+ StringRef const& message,
+ AssertionReaction& reaction
+ ) {
+ m_reporter->assertionStarting( info );
+
+ m_lastAssertionInfo = info;
+
+ AssertionResultData data( resultType, LazyExpression( false ) );
+ data.message = message;
+ AssertionResult assertionResult{ m_lastAssertionInfo, data };
+ assertionEnded( assertionResult );
+ if( !assertionResult.isOk() )
+ populateReaction( reaction );
+ }
+ void RunContext::handleUnexpectedExceptionNotThrown(
+ AssertionInfo const& info,
+ AssertionReaction& reaction
+ ) {
+ handleNonExpr(info, Catch::ResultWas::DidntThrowException, reaction);
+ }
+
+ void RunContext::handleUnexpectedInflightException(
+ AssertionInfo const& info,
+ std::string const& message,
+ AssertionReaction& reaction
+ ) {
+ m_lastAssertionInfo = info;
+
+ AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) );
+ data.message = message;
+ AssertionResult assertionResult{ info, data };
+ assertionEnded( assertionResult );
+ populateReaction( reaction );
+ }
+
+ void RunContext::populateReaction( AssertionReaction& reaction ) {
+ reaction.shouldDebugBreak = m_config->shouldDebugBreak();
+ reaction.shouldThrow = aborting() || (m_lastAssertionInfo.resultDisposition & ResultDisposition::Normal);
+ }
+
+ void RunContext::handleIncomplete(
+ AssertionInfo const& info
+ ) {
+ m_lastAssertionInfo = info;
+
+ AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) );
+ data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE";
+ AssertionResult assertionResult{ info, data };
+ assertionEnded( assertionResult );
+ }
+ void RunContext::handleNonExpr(
+ AssertionInfo const &info,
+ ResultWas::OfType resultType,
+ AssertionReaction &reaction
+ ) {
+ m_lastAssertionInfo = info;
+
+ AssertionResultData data( resultType, LazyExpression( false ) );
+ AssertionResult assertionResult{ info, data };
+ assertionEnded( assertionResult );
+
+ if( !assertionResult.isOk() )
+ populateReaction( reaction );
+ }
+
+ IResultCapture& getResultCapture() {
+ if (auto* capture = getCurrentContext().getResultCapture())
+ return *capture;
+ else
+ CATCH_INTERNAL_ERROR("No result capture instance");
+ }
+}
+// end catch_run_context.cpp
+// start catch_section.cpp
+
+namespace Catch {
+
+ Section::Section( SectionInfo const& info )
+ : m_info( info ),
+ m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) )
+ {
+ m_timer.start();
+ }
+
+ Section::~Section() {
+ if( m_sectionIncluded ) {
+ SectionEndInfo endInfo{ m_info, m_assertions, m_timer.getElapsedSeconds() };
+ if( uncaught_exceptions() )
+ getResultCapture().sectionEndedEarly( endInfo );
+ else
+ getResultCapture().sectionEnded( endInfo );
+ }
+ }
+
+ // This indicates whether the section should be executed or not
+ Section::operator bool() const {
+ return m_sectionIncluded;
+ }
+
+} // end namespace Catch
+// end catch_section.cpp
+// start catch_section_info.cpp
+
+namespace Catch {
+
+ SectionInfo::SectionInfo
+ ( SourceLineInfo const& _lineInfo,
+ std::string const& _name )
+ : name( _name ),
+ lineInfo( _lineInfo )
+ {}
+
+} // end namespace Catch
+// end catch_section_info.cpp
+// start catch_session.cpp
+
+// start catch_session.h
+
+#include <memory>
+
+namespace Catch {
+
+ class Session : NonCopyable {
+ public:
+
+ Session();
+ ~Session() override;
+
+ void showHelp() const;
+ void libIdentify();
+
+ int applyCommandLine( int argc, char const * const * argv );
+
+ void useConfigData( ConfigData const& configData );
+
+ int run( int argc, char* argv[] );
+ #if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE)
+ int run( int argc, wchar_t* const argv[] );
+ #endif
+ int run();
+
+ clara::Parser const& cli() const;
+ void cli( clara::Parser const& newParser );
+ ConfigData& configData();
+ Config& config();
+ private:
+ int runInternal();
+
+ clara::Parser m_cli;
+ ConfigData m_configData;
+ std::shared_ptr<Config> m_config;
+ bool m_startupExceptions = false;
+ };
+
+} // end namespace Catch
+
+// end catch_session.h
+// start catch_version.h
+
+#include <iosfwd>
+
+namespace Catch {
+
+ // Versioning information
+ struct Version {
+ Version( Version const& ) = delete;
+ Version& operator=( Version const& ) = delete;
+ Version( unsigned int _majorVersion,
+ unsigned int _minorVersion,
+ unsigned int _patchNumber,
+ char const * const _branchName,
+ unsigned int _buildNumber );
+
+ unsigned int const majorVersion;
+ unsigned int const minorVersion;
+ unsigned int const patchNumber;
+
+ // buildNumber is only used if branchName is not null
+ char const * const branchName;
+ unsigned int const buildNumber;
+
+ friend std::ostream& operator << ( std::ostream& os, Version const& version );
+ };
+
+ Version const& libraryVersion();
+}
+
+// end catch_version.h
+#include <cstdlib>
+#include <iomanip>
+
+namespace Catch {
+
+ namespace {
+ const int MaxExitCode = 255;
+
+ IStreamingReporterPtr createReporter(std::string const& reporterName, IConfigPtr const& config) {
+ auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, config);
+ CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << "'");
+
+ return reporter;
+ }
+
+ IStreamingReporterPtr makeReporter(std::shared_ptr<Config> const& config) {
+ if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()) {
+ return createReporter(config->getReporterName(), config);
+ }
+
+ auto multi = std::unique_ptr<ListeningReporter>(new ListeningReporter);
+
+ auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners();
+ for (auto const& listener : listeners) {
+ multi->addListener(listener->create(Catch::ReporterConfig(config)));
+ }
+ multi->addReporter(createReporter(config->getReporterName(), config));
+ return std::move(multi);
+ }
+
+ Catch::Totals runTests(std::shared_ptr<Config> const& config) {
+ // FixMe: Add listeners in order first, then add reporters.
+
+ auto reporter = makeReporter(config);
+
+ RunContext context(config, std::move(reporter));
+
+ Totals totals;
+
+ context.testGroupStarting(config->name(), 1, 1);
+
+ TestSpec testSpec = config->testSpec();
+
+ auto const& allTestCases = getAllTestCasesSorted(*config);
+ for (auto const& testCase : allTestCases) {
+ if (!context.aborting() && matchTest(testCase, testSpec, *config))
+ totals += context.runTest(testCase);
+ else
+ context.reporter().skipTest(testCase);
+ }
+
+ if (config->warnAboutNoTests() && totals.testCases.total() == 0) {
+ ReusableStringStream testConfig;
+
+ bool first = true;
+ for (const auto& input : config->getTestsOrTags()) {
+ if (!first) { testConfig << ' '; }
+ first = false;
+ testConfig << input;
+ }
+
+ context.reporter().noMatchingTestCases(testConfig.str());
+ totals.error = -1;
+ }
+
+ context.testGroupEnded(config->name(), totals, 1, 1);
+ return totals;
+ }
+
+ void applyFilenamesAsTags(Catch::IConfig const& config) {
+ auto& tests = const_cast<std::vector<TestCase>&>(getAllTestCasesSorted(config));
+ for (auto& testCase : tests) {
+ auto tags = testCase.tags;
+
+ std::string filename = testCase.lineInfo.file;
+ auto lastSlash = filename.find_last_of("\\/");
+ if (lastSlash != std::string::npos) {
+ filename.erase(0, lastSlash);
+ filename[0] = '#';
+ }
+
+ auto lastDot = filename.find_last_of('.');
+ if (lastDot != std::string::npos) {
+ filename.erase(lastDot);
+ }
+
+ tags.push_back(std::move(filename));
+ setTags(testCase, tags);
+ }
+ }
+
+ } // anon namespace
+
+ Session::Session() {
+ static bool alreadyInstantiated = false;
+ if( alreadyInstantiated ) {
+ CATCH_TRY { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); }
+ CATCH_CATCH_ALL { getMutableRegistryHub().registerStartupException(); }
+ }
+
+ // There cannot be exceptions at startup in no-exception mode.
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+ const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions();
+ if ( !exceptions.empty() ) {
+ m_startupExceptions = true;
+ Colour colourGuard( Colour::Red );
+ Catch::cerr() << "Errors occurred during startup!" << '\n';
+ // iterate over all exceptions and notify user
+ for ( const auto& ex_ptr : exceptions ) {
+ try {
+ std::rethrow_exception(ex_ptr);
+ } catch ( std::exception const& ex ) {
+ Catch::cerr() << Column( ex.what() ).indent(2) << '\n';
+ }
+ }
+ }
+#endif
+
+ alreadyInstantiated = true;
+ m_cli = makeCommandLineParser( m_configData );
+ }
+ Session::~Session() {
+ Catch::cleanUp();
+ }
+
+ void Session::showHelp() const {
+ Catch::cout()
+ << "\nCatch v" << libraryVersion() << "\n"
+ << m_cli << std::endl
+ << "For more detailed usage please see the project docs\n" << std::endl;
+ }
+ void Session::libIdentify() {
+ Catch::cout()
+ << std::left << std::setw(16) << "description: " << "A Catch test executable\n"
+ << std::left << std::setw(16) << "category: " << "testframework\n"
+ << std::left << std::setw(16) << "framework: " << "Catch Test\n"
+ << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl;
+ }
+
+ int Session::applyCommandLine( int argc, char const * const * argv ) {
+ if( m_startupExceptions )
+ return 1;
+
+ auto result = m_cli.parse( clara::Args( argc, argv ) );
+ if( !result ) {
+ Catch::cerr()
+ << Colour( Colour::Red )
+ << "\nError(s) in input:\n"
+ << Column( result.errorMessage() ).indent( 2 )
+ << "\n\n";
+ Catch::cerr() << "Run with -? for usage\n" << std::endl;
+ return MaxExitCode;
+ }
+
+ if( m_configData.showHelp )
+ showHelp();
+ if( m_configData.libIdentify )
+ libIdentify();
+ m_config.reset();
+ return 0;
+ }
+
+ void Session::useConfigData( ConfigData const& configData ) {
+ m_configData = configData;
+ m_config.reset();
+ }
+
+ int Session::run( int argc, char* argv[] ) {
+ if( m_startupExceptions )
+ return 1;
+ int returnCode = applyCommandLine( argc, argv );
+ if( returnCode == 0 )
+ returnCode = run();
+ return returnCode;
+ }
+
+#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE)
+ int Session::run( int argc, wchar_t* const argv[] ) {
+
+ char **utf8Argv = new char *[ argc ];
+
+ for ( int i = 0; i < argc; ++i ) {
+ int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL );
+
+ utf8Argv[ i ] = new char[ bufSize ];
+
+ WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL );
+ }
+
+ int returnCode = run( argc, utf8Argv );
+
+ for ( int i = 0; i < argc; ++i )
+ delete [] utf8Argv[ i ];
+
+ delete [] utf8Argv;
+
+ return returnCode;
+ }
+#endif
+ int Session::run() {
+ if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) {
+ Catch::cout() << "...waiting for enter/ return before starting" << std::endl;
+ static_cast<void>(std::getchar());
+ }
+ int exitCode = runInternal();
+ if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) {
+ Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl;
+ static_cast<void>(std::getchar());
+ }
+ return exitCode;
+ }
+
+ clara::Parser const& Session::cli() const {
+ return m_cli;
+ }
+ void Session::cli( clara::Parser const& newParser ) {
+ m_cli = newParser;
+ }
+ ConfigData& Session::configData() {
+ return m_configData;
+ }
+ Config& Session::config() {
+ if( !m_config )
+ m_config = std::make_shared<Config>( m_configData );
+ return *m_config;
+ }
+
+ int Session::runInternal() {
+ if( m_startupExceptions )
+ return 1;
+
+ if (m_configData.showHelp || m_configData.libIdentify) {
+ return 0;
+ }
+
+ CATCH_TRY {
+ config(); // Force config to be constructed
+
+ seedRng( *m_config );
+
+ if( m_configData.filenamesAsTags )
+ applyFilenamesAsTags( *m_config );
+
+ // Handle list request
+ if( Option<std::size_t> listed = list( config() ) )
+ return static_cast<int>( *listed );
+
+ auto totals = runTests( m_config );
+ // Note that on unices only the lower 8 bits are usually used, clamping
+ // the return value to 255 prevents false negative when some multiple
+ // of 256 tests has failed
+ return (std::min) (MaxExitCode, (std::max) (totals.error, static_cast<int>(totals.assertions.failed)));
+ }
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+ catch( std::exception& ex ) {
+ Catch::cerr() << ex.what() << std::endl;
+ return MaxExitCode;
+ }
+#endif
+ }
+
+} // end namespace Catch
+// end catch_session.cpp
+// start catch_singletons.cpp
+
+#include <vector>
+
+namespace Catch {
+
+ namespace {
+ static auto getSingletons() -> std::vector<ISingleton*>*& {
+ static std::vector<ISingleton*>* g_singletons = nullptr;
+ if( !g_singletons )
+ g_singletons = new std::vector<ISingleton*>();
+ return g_singletons;
+ }
+ }
+
+ ISingleton::~ISingleton() {}
+
+ void addSingleton(ISingleton* singleton ) {
+ getSingletons()->push_back( singleton );
+ }
+ void cleanupSingletons() {
+ auto& singletons = getSingletons();
+ for( auto singleton : *singletons )
+ delete singleton;
+ delete singletons;
+ singletons = nullptr;
+ }
+
+} // namespace Catch
+// end catch_singletons.cpp
+// start catch_startup_exception_registry.cpp
+
+namespace Catch {
+void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept {
+ CATCH_TRY {
+ m_exceptions.push_back(exception);
+ } CATCH_CATCH_ALL {
+ // If we run out of memory during start-up there's really not a lot more we can do about it
+ std::terminate();
+ }
+ }
+
+ std::vector<std::exception_ptr> const& StartupExceptionRegistry::getExceptions() const noexcept {
+ return m_exceptions;
+ }
+
+} // end namespace Catch
+// end catch_startup_exception_registry.cpp
+// start catch_stream.cpp
+
+#include <cstdio>
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <vector>
+#include <memory>
+
+namespace Catch {
+
+ Catch::IStream::~IStream() = default;
+
+ namespace detail { namespace {
+ template<typename WriterF, std::size_t bufferSize=256>
+ class StreamBufImpl : public std::streambuf {
+ char data[bufferSize];
+ WriterF m_writer;
+
+ public:
+ StreamBufImpl() {
+ setp( data, data + sizeof(data) );
+ }
+
+ ~StreamBufImpl() noexcept {
+ StreamBufImpl::sync();
+ }
+
+ private:
+ int overflow( int c ) override {
+ sync();
+
+ if( c != EOF ) {
+ if( pbase() == epptr() )
+ m_writer( std::string( 1, static_cast<char>( c ) ) );
+ else
+ sputc( static_cast<char>( c ) );
+ }
+ return 0;
+ }
+
+ int sync() override {
+ if( pbase() != pptr() ) {
+ m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) );
+ setp( pbase(), epptr() );
+ }
+ return 0;
+ }
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ struct OutputDebugWriter {
+
+ void operator()( std::string const&str ) {
+ writeToDebugConsole( str );
+ }
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ class FileStream : public IStream {
+ mutable std::ofstream m_ofs;
+ public:
+ FileStream( StringRef filename ) {
+ m_ofs.open( filename.c_str() );
+ CATCH_ENFORCE( !m_ofs.fail(), "Unable to open file: '" << filename << "'" );
+ }
+ ~FileStream() override = default;
+ public: // IStream
+ std::ostream& stream() const override {
+ return m_ofs;
+ }
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ class CoutStream : public IStream {
+ mutable std::ostream m_os;
+ public:
+ // Store the streambuf from cout up-front because
+ // cout may get redirected when running tests
+ CoutStream() : m_os( Catch::cout().rdbuf() ) {}
+ ~CoutStream() override = default;
+
+ public: // IStream
+ std::ostream& stream() const override { return m_os; }
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ class DebugOutStream : public IStream {
+ std::unique_ptr<StreamBufImpl<OutputDebugWriter>> m_streamBuf;
+ mutable std::ostream m_os;
+ public:
+ DebugOutStream()
+ : m_streamBuf( new StreamBufImpl<OutputDebugWriter>() ),
+ m_os( m_streamBuf.get() )
+ {}
+
+ ~DebugOutStream() override = default;
+
+ public: // IStream
+ std::ostream& stream() const override { return m_os; }
+ };
+
+ }} // namespace anon::detail
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ auto makeStream( StringRef const &filename ) -> IStream const* {
+ if( filename.empty() )
+ return new detail::CoutStream();
+ else if( filename[0] == '%' ) {
+ if( filename == "%debug" )
+ return new detail::DebugOutStream();
+ else
+ CATCH_ERROR( "Unrecognised stream: '" << filename << "'" );
+ }
+ else
+ return new detail::FileStream( filename );
+ }
+
+ // This class encapsulates the idea of a pool of ostringstreams that can be reused.
+ struct StringStreams {
+ std::vector<std::unique_ptr<std::ostringstream>> m_streams;
+ std::vector<std::size_t> m_unused;
+ std::ostringstream m_referenceStream; // Used for copy state/ flags from
+
+ auto add() -> std::size_t {
+ if( m_unused.empty() ) {
+ m_streams.push_back( std::unique_ptr<std::ostringstream>( new std::ostringstream ) );
+ return m_streams.size()-1;
+ }
+ else {
+ auto index = m_unused.back();
+ m_unused.pop_back();
+ return index;
+ }
+ }
+
+ void release( std::size_t index ) {
+ m_streams[index]->copyfmt( m_referenceStream ); // Restore initial flags and other state
+ m_unused.push_back(index);
+ }
+ };
+
+ ReusableStringStream::ReusableStringStream()
+ : m_index( Singleton<StringStreams>::getMutable().add() ),
+ m_oss( Singleton<StringStreams>::getMutable().m_streams[m_index].get() )
+ {}
+
+ ReusableStringStream::~ReusableStringStream() {
+ static_cast<std::ostringstream*>( m_oss )->str("");
+ m_oss->clear();
+ Singleton<StringStreams>::getMutable().release( m_index );
+ }
+
+ auto ReusableStringStream::str() const -> std::string {
+ return static_cast<std::ostringstream*>( m_oss )->str();
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions
+ std::ostream& cout() { return std::cout; }
+ std::ostream& cerr() { return std::cerr; }
+ std::ostream& clog() { return std::clog; }
+#endif
+}
+// end catch_stream.cpp
+// start catch_string_manip.cpp
+
+#include <algorithm>
+#include <ostream>
+#include <cstring>
+#include <cctype>
+
+namespace Catch {
+
+ namespace {
+ char toLowerCh(char c) {
+ return static_cast<char>( std::tolower( c ) );
+ }
+ }
+
+ bool startsWith( std::string const& s, std::string const& prefix ) {
+ return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin());
+ }
+ bool startsWith( std::string const& s, char prefix ) {
+ return !s.empty() && s[0] == prefix;
+ }
+ bool endsWith( std::string const& s, std::string const& suffix ) {
+ return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin());
+ }
+ bool endsWith( std::string const& s, char suffix ) {
+ return !s.empty() && s[s.size()-1] == suffix;
+ }
+ bool contains( std::string const& s, std::string const& infix ) {
+ return s.find( infix ) != std::string::npos;
+ }
+ void toLowerInPlace( std::string& s ) {
+ std::transform( s.begin(), s.end(), s.begin(), toLowerCh );
+ }
+ std::string toLower( std::string const& s ) {
+ std::string lc = s;
+ toLowerInPlace( lc );
+ return lc;
+ }
+ std::string trim( std::string const& str ) {
+ static char const* whitespaceChars = "\n\r\t ";
+ std::string::size_type start = str.find_first_not_of( whitespaceChars );
+ std::string::size_type end = str.find_last_not_of( whitespaceChars );
+
+ return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string();
+ }
+
+ bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) {
+ bool replaced = false;
+ std::size_t i = str.find( replaceThis );
+ while( i != std::string::npos ) {
+ replaced = true;
+ str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() );
+ if( i < str.size()-withThis.size() )
+ i = str.find( replaceThis, i+withThis.size() );
+ else
+ i = std::string::npos;
+ }
+ return replaced;
+ }
+
+ pluralise::pluralise( std::size_t count, std::string const& label )
+ : m_count( count ),
+ m_label( label )
+ {}
+
+ std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) {
+ os << pluraliser.m_count << ' ' << pluraliser.m_label;
+ if( pluraliser.m_count != 1 )
+ os << 's';
+ return os;
+ }
+
+}
+// end catch_string_manip.cpp
+// start catch_stringref.cpp
+
+#if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wexit-time-destructors"
+#endif
+
+#include <ostream>
+#include <cstring>
+#include <cstdint>
+
+namespace {
+ const uint32_t byte_2_lead = 0xC0;
+ const uint32_t byte_3_lead = 0xE0;
+ const uint32_t byte_4_lead = 0xF0;
+}
+
+namespace Catch {
+ StringRef::StringRef( char const* rawChars ) noexcept
+ : StringRef( rawChars, static_cast<StringRef::size_type>(std::strlen(rawChars) ) )
+ {}
+
+ StringRef::operator std::string() const {
+ return std::string( m_start, m_size );
+ }
+
+ void StringRef::swap( StringRef& other ) noexcept {
+ std::swap( m_start, other.m_start );
+ std::swap( m_size, other.m_size );
+ std::swap( m_data, other.m_data );
+ }
+
+ auto StringRef::c_str() const -> char const* {
+ if( isSubstring() )
+ const_cast<StringRef*>( this )->takeOwnership();
+ return m_start;
+ }
+ auto StringRef::currentData() const noexcept -> char const* {
+ return m_start;
+ }
+
+ auto StringRef::isOwned() const noexcept -> bool {
+ return m_data != nullptr;
+ }
+ auto StringRef::isSubstring() const noexcept -> bool {
+ return m_start[m_size] != '\0';
+ }
+
+ void StringRef::takeOwnership() {
+ if( !isOwned() ) {
+ m_data = new char[m_size+1];
+ memcpy( m_data, m_start, m_size );
+ m_data[m_size] = '\0';
+ m_start = m_data;
+ }
+ }
+ auto StringRef::substr( size_type start, size_type size ) const noexcept -> StringRef {
+ if( start < m_size )
+ return StringRef( m_start+start, size );
+ else
+ return StringRef();
+ }
+ auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool {
+ return
+ size() == other.size() &&
+ (std::strncmp( m_start, other.m_start, size() ) == 0);
+ }
+ auto StringRef::operator != ( StringRef const& other ) const noexcept -> bool {
+ return !operator==( other );
+ }
+
+ auto StringRef::operator[](size_type index) const noexcept -> char {
+ return m_start[index];
+ }
+
+ auto StringRef::numberOfCharacters() const noexcept -> size_type {
+ size_type noChars = m_size;
+ // Make adjustments for uft encodings
+ for( size_type i=0; i < m_size; ++i ) {
+ char c = m_start[i];
+ if( ( c & byte_2_lead ) == byte_2_lead ) {
+ noChars--;
+ if (( c & byte_3_lead ) == byte_3_lead )
+ noChars--;
+ if( ( c & byte_4_lead ) == byte_4_lead )
+ noChars--;
+ }
+ }
+ return noChars;
+ }
+
+ auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string {
+ std::string str;
+ str.reserve( lhs.size() + rhs.size() );
+ str += lhs;
+ str += rhs;
+ return str;
+ }
+ auto operator + ( StringRef const& lhs, const char* rhs ) -> std::string {
+ return std::string( lhs ) + std::string( rhs );
+ }
+ auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string {
+ return std::string( lhs ) + std::string( rhs );
+ }
+
+ auto operator << ( std::ostream& os, StringRef const& str ) -> std::ostream& {
+ return os.write(str.currentData(), str.size());
+ }
+
+ auto operator+=( std::string& lhs, StringRef const& rhs ) -> std::string& {
+ lhs.append(rhs.currentData(), rhs.size());
+ return lhs;
+ }
+
+} // namespace Catch
+
+#if defined(__clang__)
+# pragma clang diagnostic pop
+#endif
+// end catch_stringref.cpp
+// start catch_tag_alias.cpp
+
+namespace Catch {
+ TagAlias::TagAlias(std::string const & _tag, SourceLineInfo _lineInfo): tag(_tag), lineInfo(_lineInfo) {}
+}
+// end catch_tag_alias.cpp
+// start catch_tag_alias_autoregistrar.cpp
+
+namespace Catch {
+
+ RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) {
+ CATCH_TRY {
+ getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo);
+ } CATCH_CATCH_ALL {
+ // Do not throw when constructing global objects, instead register the exception to be processed later
+ getMutableRegistryHub().registerStartupException();
+ }
+ }
+
+}
+// end catch_tag_alias_autoregistrar.cpp
+// start catch_tag_alias_registry.cpp
+
+#include <sstream>
+
+namespace Catch {
+
+ TagAliasRegistry::~TagAliasRegistry() {}
+
+ TagAlias const* TagAliasRegistry::find( std::string const& alias ) const {
+ auto it = m_registry.find( alias );
+ if( it != m_registry.end() )
+ return &(it->second);
+ else
+ return nullptr;
+ }
+
+ std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const {
+ std::string expandedTestSpec = unexpandedTestSpec;
+ for( auto const& registryKvp : m_registry ) {
+ std::size_t pos = expandedTestSpec.find( registryKvp.first );
+ if( pos != std::string::npos ) {
+ expandedTestSpec = expandedTestSpec.substr( 0, pos ) +
+ registryKvp.second.tag +
+ expandedTestSpec.substr( pos + registryKvp.first.size() );
+ }
+ }
+ return expandedTestSpec;
+ }
+
+ void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) {
+ CATCH_ENFORCE( startsWith(alias, "[@") && endsWith(alias, ']'),
+ "error: tag alias, '" << alias << "' is not of the form [@alias name].\n" << lineInfo );
+
+ CATCH_ENFORCE( m_registry.insert(std::make_pair(alias, TagAlias(tag, lineInfo))).second,
+ "error: tag alias, '" << alias << "' already registered.\n"
+ << "\tFirst seen at: " << find(alias)->lineInfo << "\n"
+ << "\tRedefined at: " << lineInfo );
+ }
+
+ ITagAliasRegistry::~ITagAliasRegistry() {}
+
+ ITagAliasRegistry const& ITagAliasRegistry::get() {
+ return getRegistryHub().getTagAliasRegistry();
+ }
+
+} // end namespace Catch
+// end catch_tag_alias_registry.cpp
+// start catch_test_case_info.cpp
+
+#include <cctype>
+#include <exception>
+#include <algorithm>
+#include <sstream>
+
+namespace Catch {
+
+ namespace {
+ TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) {
+ if( startsWith( tag, '.' ) ||
+ tag == "!hide" )
+ return TestCaseInfo::IsHidden;
+ else if( tag == "!throws" )
+ return TestCaseInfo::Throws;
+ else if( tag == "!shouldfail" )
+ return TestCaseInfo::ShouldFail;
+ else if( tag == "!mayfail" )
+ return TestCaseInfo::MayFail;
+ else if( tag == "!nonportable" )
+ return TestCaseInfo::NonPortable;
+ else if( tag == "!benchmark" )
+ return static_cast<TestCaseInfo::SpecialProperties>( TestCaseInfo::Benchmark | TestCaseInfo::IsHidden );
+ else
+ return TestCaseInfo::None;
+ }
+ bool isReservedTag( std::string const& tag ) {
+ return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( static_cast<unsigned char>(tag[0]) );
+ }
+ void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) {
+ CATCH_ENFORCE( !isReservedTag(tag),
+ "Tag name: [" << tag << "] is not allowed.\n"
+ << "Tag names starting with non alpha-numeric characters are reserved\n"
+ << _lineInfo );
+ }
+ }
+
+ TestCase makeTestCase( ITestInvoker* _testCase,
+ std::string const& _className,
+ NameAndTags const& nameAndTags,
+ SourceLineInfo const& _lineInfo )
+ {
+ bool isHidden = false;
+
+ // Parse out tags
+ std::vector<std::string> tags;
+ std::string desc, tag;
+ bool inTag = false;
+ std::string _descOrTags = nameAndTags.tags;
+ for (char c : _descOrTags) {
+ if( !inTag ) {
+ if( c == '[' )
+ inTag = true;
+ else
+ desc += c;
+ }
+ else {
+ if( c == ']' ) {
+ TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag );
+ if( ( prop & TestCaseInfo::IsHidden ) != 0 )
+ isHidden = true;
+ else if( prop == TestCaseInfo::None )
+ enforceNotReservedTag( tag, _lineInfo );
+
+ tags.push_back( tag );
+ tag.clear();
+ inTag = false;
+ }
+ else
+ tag += c;
+ }
+ }
+ if( isHidden ) {
+ tags.push_back( "." );
+ }
+
+ TestCaseInfo info( nameAndTags.name, _className, desc, tags, _lineInfo );
+ return TestCase( _testCase, std::move(info) );
+ }
+
+ void setTags( TestCaseInfo& testCaseInfo, std::vector<std::string> tags ) {
+ std::sort(begin(tags), end(tags));
+ tags.erase(std::unique(begin(tags), end(tags)), end(tags));
+ testCaseInfo.lcaseTags.clear();
+
+ for( auto const& tag : tags ) {
+ std::string lcaseTag = toLower( tag );
+ testCaseInfo.properties = static_cast<TestCaseInfo::SpecialProperties>( testCaseInfo.properties | parseSpecialTag( lcaseTag ) );
+ testCaseInfo.lcaseTags.push_back( lcaseTag );
+ }
+ testCaseInfo.tags = std::move(tags);
+ }
+
+ TestCaseInfo::TestCaseInfo( std::string const& _name,
+ std::string const& _className,
+ std::string const& _description,
+ std::vector<std::string> const& _tags,
+ SourceLineInfo const& _lineInfo )
+ : name( _name ),
+ className( _className ),
+ description( _description ),
+ lineInfo( _lineInfo ),
+ properties( None )
+ {
+ setTags( *this, _tags );
+ }
+
+ bool TestCaseInfo::isHidden() const {
+ return ( properties & IsHidden ) != 0;
+ }
+ bool TestCaseInfo::throws() const {
+ return ( properties & Throws ) != 0;
+ }
+ bool TestCaseInfo::okToFail() const {
+ return ( properties & (ShouldFail | MayFail ) ) != 0;
+ }
+ bool TestCaseInfo::expectedToFail() const {
+ return ( properties & (ShouldFail ) ) != 0;
+ }
+
+ std::string TestCaseInfo::tagsAsString() const {
+ std::string ret;
+ // '[' and ']' per tag
+ std::size_t full_size = 2 * tags.size();
+ for (const auto& tag : tags) {
+ full_size += tag.size();
+ }
+ ret.reserve(full_size);
+ for (const auto& tag : tags) {
+ ret.push_back('[');
+ ret.append(tag);
+ ret.push_back(']');
+ }
+
+ return ret;
+ }
+
+ TestCase::TestCase( ITestInvoker* testCase, TestCaseInfo&& info ) : TestCaseInfo( std::move(info) ), test( testCase ) {}
+
+ TestCase TestCase::withName( std::string const& _newName ) const {
+ TestCase other( *this );
+ other.name = _newName;
+ return other;
+ }
+
+ void TestCase::invoke() const {
+ test->invoke();
+ }
+
+ bool TestCase::operator == ( TestCase const& other ) const {
+ return test.get() == other.test.get() &&
+ name == other.name &&
+ className == other.className;
+ }
+
+ bool TestCase::operator < ( TestCase const& other ) const {
+ return name < other.name;
+ }
+
+ TestCaseInfo const& TestCase::getTestCaseInfo() const
+ {
+ return *this;
+ }
+
+} // end namespace Catch
+// end catch_test_case_info.cpp
+// start catch_test_case_registry_impl.cpp
+
+#include <sstream>
+
+namespace Catch {
+
+ std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) {
+
+ std::vector<TestCase> sorted = unsortedTestCases;
+
+ switch( config.runOrder() ) {
+ case RunTests::InLexicographicalOrder:
+ std::sort( sorted.begin(), sorted.end() );
+ break;
+ case RunTests::InRandomOrder:
+ seedRng( config );
+ std::shuffle( sorted.begin(), sorted.end(), rng() );
+ break;
+ case RunTests::InDeclarationOrder:
+ // already in declaration order
+ break;
+ }
+ return sorted;
+ }
+ bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) {
+ return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() );
+ }
+
+ void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) {
+ std::set<TestCase> seenFunctions;
+ for( auto const& function : functions ) {
+ auto prev = seenFunctions.insert( function );
+ CATCH_ENFORCE( prev.second,
+ "error: TEST_CASE( \"" << function.name << "\" ) already defined.\n"
+ << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n"
+ << "\tRedefined at " << function.getTestCaseInfo().lineInfo );
+ }
+ }
+
+ std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ) {
+ std::vector<TestCase> filtered;
+ filtered.reserve( testCases.size() );
+ for( auto const& testCase : testCases )
+ if( matchTest( testCase, testSpec, config ) )
+ filtered.push_back( testCase );
+ return filtered;
+ }
+ std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ) {
+ return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config );
+ }
+
+ void TestRegistry::registerTest( TestCase const& testCase ) {
+ std::string name = testCase.getTestCaseInfo().name;
+ if( name.empty() ) {
+ ReusableStringStream rss;
+ rss << "Anonymous test case " << ++m_unnamedCount;
+ return registerTest( testCase.withName( rss.str() ) );
+ }
+ m_functions.push_back( testCase );
+ }
+
+ std::vector<TestCase> const& TestRegistry::getAllTests() const {
+ return m_functions;
+ }
+ std::vector<TestCase> const& TestRegistry::getAllTestsSorted( IConfig const& config ) const {
+ if( m_sortedFunctions.empty() )
+ enforceNoDuplicateTestCases( m_functions );
+
+ if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) {
+ m_sortedFunctions = sortTests( config, m_functions );
+ m_currentSortOrder = config.runOrder();
+ }
+ return m_sortedFunctions;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ TestInvokerAsFunction::TestInvokerAsFunction( void(*testAsFunction)() ) noexcept : m_testAsFunction( testAsFunction ) {}
+
+ void TestInvokerAsFunction::invoke() const {
+ m_testAsFunction();
+ }
+
+ std::string extractClassName( StringRef const& classOrQualifiedMethodName ) {
+ std::string className = classOrQualifiedMethodName;
+ if( startsWith( className, '&' ) )
+ {
+ std::size_t lastColons = className.rfind( "::" );
+ std::size_t penultimateColons = className.rfind( "::", lastColons-1 );
+ if( penultimateColons == std::string::npos )
+ penultimateColons = 1;
+ className = className.substr( penultimateColons, lastColons-penultimateColons );
+ }
+ return className;
+ }
+
+} // end namespace Catch
+// end catch_test_case_registry_impl.cpp
+// start catch_test_case_tracker.cpp
+
+#include <algorithm>
+#include <cassert>
+#include <stdexcept>
+#include <memory>
+#include <sstream>
+
+#if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wexit-time-destructors"
+#endif
+
+namespace Catch {
+namespace TestCaseTracking {
+
+ NameAndLocation::NameAndLocation( std::string const& _name, SourceLineInfo const& _location )
+ : name( _name ),
+ location( _location )
+ {}
+
+ ITracker::~ITracker() = default;
+
+ TrackerContext& TrackerContext::instance() {
+ static TrackerContext s_instance;
+ return s_instance;
+ }
+
+ ITracker& TrackerContext::startRun() {
+ m_rootTracker = std::make_shared<SectionTracker>( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, nullptr );
+ m_currentTracker = nullptr;
+ m_runState = Executing;
+ return *m_rootTracker;
+ }
+
+ void TrackerContext::endRun() {
+ m_rootTracker.reset();
+ m_currentTracker = nullptr;
+ m_runState = NotStarted;
+ }
+
+ void TrackerContext::startCycle() {
+ m_currentTracker = m_rootTracker.get();
+ m_runState = Executing;
+ }
+ void TrackerContext::completeCycle() {
+ m_runState = CompletedCycle;
+ }
+
+ bool TrackerContext::completedCycle() const {
+ return m_runState == CompletedCycle;
+ }
+ ITracker& TrackerContext::currentTracker() {
+ return *m_currentTracker;
+ }
+ void TrackerContext::setCurrentTracker( ITracker* tracker ) {
+ m_currentTracker = tracker;
+ }
+
+ TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
+ : m_nameAndLocation( nameAndLocation ),
+ m_ctx( ctx ),
+ m_parent( parent )
+ {}
+
+ NameAndLocation const& TrackerBase::nameAndLocation() const {
+ return m_nameAndLocation;
+ }
+ bool TrackerBase::isComplete() const {
+ return m_runState == CompletedSuccessfully || m_runState == Failed;
+ }
+ bool TrackerBase::isSuccessfullyCompleted() const {
+ return m_runState == CompletedSuccessfully;
+ }
+ bool TrackerBase::isOpen() const {
+ return m_runState != NotStarted && !isComplete();
+ }
+ bool TrackerBase::hasChildren() const {
+ return !m_children.empty();
+ }
+
+ void TrackerBase::addChild( ITrackerPtr const& child ) {
+ m_children.push_back( child );
+ }
+
+ ITrackerPtr TrackerBase::findChild( NameAndLocation const& nameAndLocation ) {
+ auto it = std::find_if( m_children.begin(), m_children.end(),
+ [&nameAndLocation]( ITrackerPtr const& tracker ){
+ return
+ tracker->nameAndLocation().location == nameAndLocation.location &&
+ tracker->nameAndLocation().name == nameAndLocation.name;
+ } );
+ return( it != m_children.end() )
+ ? *it
+ : nullptr;
+ }
+ ITracker& TrackerBase::parent() {
+ assert( m_parent ); // Should always be non-null except for root
+ return *m_parent;
+ }
+
+ void TrackerBase::openChild() {
+ if( m_runState != ExecutingChildren ) {
+ m_runState = ExecutingChildren;
+ if( m_parent )
+ m_parent->openChild();
+ }
+ }
+
+ bool TrackerBase::isSectionTracker() const { return false; }
+ bool TrackerBase::isIndexTracker() const { return false; }
+
+ void TrackerBase::open() {
+ m_runState = Executing;
+ moveToThis();
+ if( m_parent )
+ m_parent->openChild();
+ }
+
+ void TrackerBase::close() {
+
+ // Close any still open children (e.g. generators)
+ while( &m_ctx.currentTracker() != this )
+ m_ctx.currentTracker().close();
+
+ switch( m_runState ) {
+ case NeedsAnotherRun:
+ break;
+
+ case Executing:
+ m_runState = CompletedSuccessfully;
+ break;
+ case ExecutingChildren:
+ if( m_children.empty() || m_children.back()->isComplete() )
+ m_runState = CompletedSuccessfully;
+ break;
+
+ case NotStarted:
+ case CompletedSuccessfully:
+ case Failed:
+ CATCH_INTERNAL_ERROR( "Illogical state: " << m_runState );
+
+ default:
+ CATCH_INTERNAL_ERROR( "Unknown state: " << m_runState );
+ }
+ moveToParent();
+ m_ctx.completeCycle();
+ }
+ void TrackerBase::fail() {
+ m_runState = Failed;
+ if( m_parent )
+ m_parent->markAsNeedingAnotherRun();
+ moveToParent();
+ m_ctx.completeCycle();
+ }
+ void TrackerBase::markAsNeedingAnotherRun() {
+ m_runState = NeedsAnotherRun;
+ }
+
+ void TrackerBase::moveToParent() {
+ assert( m_parent );
+ m_ctx.setCurrentTracker( m_parent );
+ }
+ void TrackerBase::moveToThis() {
+ m_ctx.setCurrentTracker( this );
+ }
+
+ SectionTracker::SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
+ : TrackerBase( nameAndLocation, ctx, parent )
+ {
+ if( parent ) {
+ while( !parent->isSectionTracker() )
+ parent = &parent->parent();
+
+ SectionTracker& parentSection = static_cast<SectionTracker&>( *parent );
+ addNextFilters( parentSection.m_filters );
+ }
+ }
+
+ bool SectionTracker::isSectionTracker() const { return true; }
+
+ SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) {
+ std::shared_ptr<SectionTracker> section;
+
+ ITracker& currentTracker = ctx.currentTracker();
+ if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {
+ assert( childTracker );
+ assert( childTracker->isSectionTracker() );
+ section = std::static_pointer_cast<SectionTracker>( childTracker );
+ }
+ else {
+ section = std::make_shared<SectionTracker>( nameAndLocation, ctx, &currentTracker );
+ currentTracker.addChild( section );
+ }
+ if( !ctx.completedCycle() )
+ section->tryOpen();
+ return *section;
+ }
+
+ void SectionTracker::tryOpen() {
+ if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) )
+ open();
+ }
+
+ void SectionTracker::addInitialFilters( std::vector<std::string> const& filters ) {
+ if( !filters.empty() ) {
+ m_filters.push_back(""); // Root - should never be consulted
+ m_filters.push_back(""); // Test Case - not a section filter
+ m_filters.insert( m_filters.end(), filters.begin(), filters.end() );
+ }
+ }
+ void SectionTracker::addNextFilters( std::vector<std::string> const& filters ) {
+ if( filters.size() > 1 )
+ m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() );
+ }
+
+ IndexTracker::IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size )
+ : TrackerBase( nameAndLocation, ctx, parent ),
+ m_size( size )
+ {}
+
+ bool IndexTracker::isIndexTracker() const { return true; }
+
+ IndexTracker& IndexTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) {
+ std::shared_ptr<IndexTracker> tracker;
+
+ ITracker& currentTracker = ctx.currentTracker();
+ if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {
+ assert( childTracker );
+ assert( childTracker->isIndexTracker() );
+ tracker = std::static_pointer_cast<IndexTracker>( childTracker );
+ }
+ else {
+ tracker = std::make_shared<IndexTracker>( nameAndLocation, ctx, &currentTracker, size );
+ currentTracker.addChild( tracker );
+ }
+
+ if( !ctx.completedCycle() && !tracker->isComplete() ) {
+ if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun )
+ tracker->moveNext();
+ tracker->open();
+ }
+
+ return *tracker;
+ }
+
+ int IndexTracker::index() const { return m_index; }
+
+ void IndexTracker::moveNext() {
+ m_index++;
+ m_children.clear();
+ }
+
+ void IndexTracker::close() {
+ TrackerBase::close();
+ if( m_runState == CompletedSuccessfully && m_index < m_size-1 )
+ m_runState = Executing;
+ }
+
+} // namespace TestCaseTracking
+
+using TestCaseTracking::ITracker;
+using TestCaseTracking::TrackerContext;
+using TestCaseTracking::SectionTracker;
+using TestCaseTracking::IndexTracker;
+
+} // namespace Catch
+
+#if defined(__clang__)
+# pragma clang diagnostic pop
+#endif
+// end catch_test_case_tracker.cpp
+// start catch_test_registry.cpp
+
+namespace Catch {
+
+ auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker* {
+ return new(std::nothrow) TestInvokerAsFunction( testAsFunction );
+ }
+
+ NameAndTags::NameAndTags( StringRef const& name_ , StringRef const& tags_ ) noexcept : name( name_ ), tags( tags_ ) {}
+
+ AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept {
+ CATCH_TRY {
+ getMutableRegistryHub()
+ .registerTest(
+ makeTestCase(
+ invoker,
+ extractClassName( classOrMethod ),
+ nameAndTags,
+ lineInfo));
+ } CATCH_CATCH_ALL {
+ // Do not throw when constructing global objects, instead register the exception to be processed later
+ getMutableRegistryHub().registerStartupException();
+ }
+ }
+
+ AutoReg::~AutoReg() = default;
+}
+// end catch_test_registry.cpp
+// start catch_test_spec.cpp
+
+#include <algorithm>
+#include <string>
+#include <vector>
+#include <memory>
+
+namespace Catch {
+
+ TestSpec::Pattern::~Pattern() = default;
+ TestSpec::NamePattern::~NamePattern() = default;
+ TestSpec::TagPattern::~TagPattern() = default;
+ TestSpec::ExcludedPattern::~ExcludedPattern() = default;
+
+ TestSpec::NamePattern::NamePattern( std::string const& name )
+ : m_wildcardPattern( toLower( name ), CaseSensitive::No )
+ {}
+ bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const {
+ return m_wildcardPattern.matches( toLower( testCase.name ) );
+ }
+
+ TestSpec::TagPattern::TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {}
+ bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const {
+ return std::find(begin(testCase.lcaseTags),
+ end(testCase.lcaseTags),
+ m_tag) != end(testCase.lcaseTags);
+ }
+
+ TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {}
+ bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); }
+
+ bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const {
+ // All patterns in a filter must match for the filter to be a match
+ for( auto const& pattern : m_patterns ) {
+ if( !pattern->matches( testCase ) )
+ return false;
+ }
+ return true;
+ }
+
+ bool TestSpec::hasFilters() const {
+ return !m_filters.empty();
+ }
+ bool TestSpec::matches( TestCaseInfo const& testCase ) const {
+ // A TestSpec matches if any filter matches
+ for( auto const& filter : m_filters )
+ if( filter.matches( testCase ) )
+ return true;
+ return false;
+ }
+}
+// end catch_test_spec.cpp
+// start catch_test_spec_parser.cpp
+
+namespace Catch {
+
+ TestSpecParser::TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {}
+
+ TestSpecParser& TestSpecParser::parse( std::string const& arg ) {
+ m_mode = None;
+ m_exclusion = false;
+ m_start = std::string::npos;
+ m_arg = m_tagAliases->expandAliases( arg );
+ m_escapeChars.clear();
+ for( m_pos = 0; m_pos < m_arg.size(); ++m_pos )
+ visitChar( m_arg[m_pos] );
+ if( m_mode == Name )
+ addPattern<TestSpec::NamePattern>();
+ return *this;
+ }
+ TestSpec TestSpecParser::testSpec() {
+ addFilter();
+ return m_testSpec;
+ }
+
+ void TestSpecParser::visitChar( char c ) {
+ if( m_mode == None ) {
+ switch( c ) {
+ case ' ': return;
+ case '~': m_exclusion = true; return;
+ case '[': return startNewMode( Tag, ++m_pos );
+ case '"': return startNewMode( QuotedName, ++m_pos );
+ case '\\': return escape();
+ default: startNewMode( Name, m_pos ); break;
+ }
+ }
+ if( m_mode == Name ) {
+ if( c == ',' ) {
+ addPattern<TestSpec::NamePattern>();
+ addFilter();
+ }
+ else if( c == '[' ) {
+ if( subString() == "exclude:" )
+ m_exclusion = true;
+ else
+ addPattern<TestSpec::NamePattern>();
+ startNewMode( Tag, ++m_pos );
+ }
+ else if( c == '\\' )
+ escape();
+ }
+ else if( m_mode == EscapedName )
+ m_mode = Name;
+ else if( m_mode == QuotedName && c == '"' )
+ addPattern<TestSpec::NamePattern>();
+ else if( m_mode == Tag && c == ']' )
+ addPattern<TestSpec::TagPattern>();
+ }
+ void TestSpecParser::startNewMode( Mode mode, std::size_t start ) {
+ m_mode = mode;
+ m_start = start;
+ }
+ void TestSpecParser::escape() {
+ if( m_mode == None )
+ m_start = m_pos;
+ m_mode = EscapedName;
+ m_escapeChars.push_back( m_pos );
+ }
+ std::string TestSpecParser::subString() const { return m_arg.substr( m_start, m_pos - m_start ); }
+
+ void TestSpecParser::addFilter() {
+ if( !m_currentFilter.m_patterns.empty() ) {
+ m_testSpec.m_filters.push_back( m_currentFilter );
+ m_currentFilter = TestSpec::Filter();
+ }
+ }
+
+ TestSpec parseTestSpec( std::string const& arg ) {
+ return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec();
+ }
+
+} // namespace Catch
+// end catch_test_spec_parser.cpp
+// start catch_timer.cpp
+
+#include <chrono>
+
+static const uint64_t nanosecondsInSecond = 1000000000;
+
+namespace Catch {
+
+ auto getCurrentNanosecondsSinceEpoch() -> uint64_t {
+ return std::chrono::duration_cast<std::chrono::nanoseconds>( std::chrono::high_resolution_clock::now().time_since_epoch() ).count();
+ }
+
+ namespace {
+ auto estimateClockResolution() -> uint64_t {
+ uint64_t sum = 0;
+ static const uint64_t iterations = 1000000;
+
+ auto startTime = getCurrentNanosecondsSinceEpoch();
+
+ for( std::size_t i = 0; i < iterations; ++i ) {
+
+ uint64_t ticks;
+ uint64_t baseTicks = getCurrentNanosecondsSinceEpoch();
+ do {
+ ticks = getCurrentNanosecondsSinceEpoch();
+ } while( ticks == baseTicks );
+
+ auto delta = ticks - baseTicks;
+ sum += delta;
+
+ // If we have been calibrating for over 3 seconds -- the clock
+ // is terrible and we should move on.
+ // TBD: How to signal that the measured resolution is probably wrong?
+ if (ticks > startTime + 3 * nanosecondsInSecond) {
+ return sum / i;
+ }
+ }
+
+ // We're just taking the mean, here. To do better we could take the std. dev and exclude outliers
+ // - and potentially do more iterations if there's a high variance.
+ return sum/iterations;
+ }
+ }
+ auto getEstimatedClockResolution() -> uint64_t {
+ static auto s_resolution = estimateClockResolution();
+ return s_resolution;
+ }
+
+ void Timer::start() {
+ m_nanoseconds = getCurrentNanosecondsSinceEpoch();
+ }
+ auto Timer::getElapsedNanoseconds() const -> uint64_t {
+ return getCurrentNanosecondsSinceEpoch() - m_nanoseconds;
+ }
+ auto Timer::getElapsedMicroseconds() const -> uint64_t {
+ return getElapsedNanoseconds()/1000;
+ }
+ auto Timer::getElapsedMilliseconds() const -> unsigned int {
+ return static_cast<unsigned int>(getElapsedMicroseconds()/1000);
+ }
+ auto Timer::getElapsedSeconds() const -> double {
+ return getElapsedMicroseconds()/1000000.0;
+ }
+
+} // namespace Catch
+// end catch_timer.cpp
+// start catch_tostring.cpp
+
+#if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wexit-time-destructors"
+# pragma clang diagnostic ignored "-Wglobal-constructors"
+#endif
+
+// Enable specific decls locally
+#if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER)
+#define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
+#endif
+
+#include <cmath>
+#include <iomanip>
+
+namespace Catch {
+
+namespace Detail {
+
+ const std::string unprintableString = "{?}";
+
+ namespace {
+ const int hexThreshold = 255;
+
+ struct Endianness {
+ enum Arch { Big, Little };
+
+ static Arch which() {
+ union _{
+ int asInt;
+ char asChar[sizeof (int)];
+ } u;
+
+ u.asInt = 1;
+ return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little;
+ }
+ };
+ }
+
+ std::string rawMemoryToString( const void *object, std::size_t size ) {
+ // Reverse order for little endian architectures
+ int i = 0, end = static_cast<int>( size ), inc = 1;
+ if( Endianness::which() == Endianness::Little ) {
+ i = end-1;
+ end = inc = -1;
+ }
+
+ unsigned char const *bytes = static_cast<unsigned char const *>(object);
+ ReusableStringStream rss;
+ rss << "0x" << std::setfill('0') << std::hex;
+ for( ; i != end; i += inc )
+ rss << std::setw(2) << static_cast<unsigned>(bytes[i]);
+ return rss.str();
+ }
+}
+
+template<typename T>
+std::string fpToString( T value, int precision ) {
+ if (std::isnan(value)) {
+ return "nan";
+ }
+
+ ReusableStringStream rss;
+ rss << std::setprecision( precision )
+ << std::fixed
+ << value;
+ std::string d = rss.str();
+ std::size_t i = d.find_last_not_of( '0' );
+ if( i != std::string::npos && i != d.size()-1 ) {
+ if( d[i] == '.' )
+ i++;
+ d = d.substr( 0, i+1 );
+ }
+ return d;
+}
+
+//// ======================================================= ////
+//
+// Out-of-line defs for full specialization of StringMaker
+//
+//// ======================================================= ////
+
+std::string StringMaker<std::string>::convert(const std::string& str) {
+ if (!getCurrentContext().getConfig()->showInvisibles()) {
+ return '"' + str + '"';
+ }
+
+ std::string s("\"");
+ for (char c : str) {
+ switch (c) {
+ case '\n':
+ s.append("\\n");
+ break;
+ case '\t':
+ s.append("\\t");
+ break;
+ default:
+ s.push_back(c);
+ break;
+ }
+ }
+ s.append("\"");
+ return s;
+}
+
+#ifdef CATCH_CONFIG_WCHAR
+std::string StringMaker<std::wstring>::convert(const std::wstring& wstr) {
+ std::string s;
+ s.reserve(wstr.size());
+ for (auto c : wstr) {
+ s += (c <= 0xff) ? static_cast<char>(c) : '?';
+ }
+ return ::Catch::Detail::stringify(s);
+}
+#endif
+
+std::string StringMaker<char const*>::convert(char const* str) {
+ if (str) {
+ return ::Catch::Detail::stringify(std::string{ str });
+ } else {
+ return{ "{null string}" };
+ }
+}
+std::string StringMaker<char*>::convert(char* str) {
+ if (str) {
+ return ::Catch::Detail::stringify(std::string{ str });
+ } else {
+ return{ "{null string}" };
+ }
+}
+#ifdef CATCH_CONFIG_WCHAR
+std::string StringMaker<wchar_t const*>::convert(wchar_t const * str) {
+ if (str) {
+ return ::Catch::Detail::stringify(std::wstring{ str });
+ } else {
+ return{ "{null string}" };
+ }
+}
+std::string StringMaker<wchar_t *>::convert(wchar_t * str) {
+ if (str) {
+ return ::Catch::Detail::stringify(std::wstring{ str });
+ } else {
+ return{ "{null string}" };
+ }
+}
+#endif
+
+std::string StringMaker<int>::convert(int value) {
+ return ::Catch::Detail::stringify(static_cast<long long>(value));
+}
+std::string StringMaker<long>::convert(long value) {
+ return ::Catch::Detail::stringify(static_cast<long long>(value));
+}
+std::string StringMaker<long long>::convert(long long value) {
+ ReusableStringStream rss;
+ rss << value;
+ if (value > Detail::hexThreshold) {
+ rss << " (0x" << std::hex << value << ')';
+ }
+ return rss.str();
+}
+
+std::string StringMaker<unsigned int>::convert(unsigned int value) {
+ return ::Catch::Detail::stringify(static_cast<unsigned long long>(value));
+}
+std::string StringMaker<unsigned long>::convert(unsigned long value) {
+ return ::Catch::Detail::stringify(static_cast<unsigned long long>(value));
+}
+std::string StringMaker<unsigned long long>::convert(unsigned long long value) {
+ ReusableStringStream rss;
+ rss << value;
+ if (value > Detail::hexThreshold) {
+ rss << " (0x" << std::hex << value << ')';
+ }
+ return rss.str();
+}
+
+std::string StringMaker<bool>::convert(bool b) {
+ return b ? "true" : "false";
+}
+
+std::string StringMaker<char>::convert(char value) {
+ if (value == '\r') {
+ return "'\\r'";
+ } else if (value == '\f') {
+ return "'\\f'";
+ } else if (value == '\n') {
+ return "'\\n'";
+ } else if (value == '\t') {
+ return "'\\t'";
+ } else if ('\0' <= value && value < ' ') {
+ return ::Catch::Detail::stringify(static_cast<unsigned int>(value));
+ } else {
+ char chstr[] = "' '";
+ chstr[1] = value;
+ return chstr;
+ }
+}
+std::string StringMaker<signed char>::convert(signed char c) {
+ return ::Catch::Detail::stringify(static_cast<char>(c));
+}
+std::string StringMaker<unsigned char>::convert(unsigned char c) {
+ return ::Catch::Detail::stringify(static_cast<char>(c));
+}
+
+std::string StringMaker<std::nullptr_t>::convert(std::nullptr_t) {
+ return "nullptr";
+}
+
+std::string StringMaker<float>::convert(float value) {
+ return fpToString(value, 5) + 'f';
+}
+std::string StringMaker<double>::convert(double value) {
+ return fpToString(value, 10);
+}
+
+std::string ratio_string<std::atto>::symbol() { return "a"; }
+std::string ratio_string<std::femto>::symbol() { return "f"; }
+std::string ratio_string<std::pico>::symbol() { return "p"; }
+std::string ratio_string<std::nano>::symbol() { return "n"; }
+std::string ratio_string<std::micro>::symbol() { return "u"; }
+std::string ratio_string<std::milli>::symbol() { return "m"; }
+
+} // end namespace Catch
+
+#if defined(__clang__)
+# pragma clang diagnostic pop
+#endif
+
+// end catch_tostring.cpp
+// start catch_totals.cpp
+
+namespace Catch {
+
+ Counts Counts::operator - ( Counts const& other ) const {
+ Counts diff;
+ diff.passed = passed - other.passed;
+ diff.failed = failed - other.failed;
+ diff.failedButOk = failedButOk - other.failedButOk;
+ return diff;
+ }
+
+ Counts& Counts::operator += ( Counts const& other ) {
+ passed += other.passed;
+ failed += other.failed;
+ failedButOk += other.failedButOk;
+ return *this;
+ }
+
+ std::size_t Counts::total() const {
+ return passed + failed + failedButOk;
+ }
+ bool Counts::allPassed() const {
+ return failed == 0 && failedButOk == 0;
+ }
+ bool Counts::allOk() const {
+ return failed == 0;
+ }
+
+ Totals Totals::operator - ( Totals const& other ) const {
+ Totals diff;
+ diff.assertions = assertions - other.assertions;
+ diff.testCases = testCases - other.testCases;
+ return diff;
+ }
+
+ Totals& Totals::operator += ( Totals const& other ) {
+ assertions += other.assertions;
+ testCases += other.testCases;
+ return *this;
+ }
+
+ Totals Totals::delta( Totals const& prevTotals ) const {
+ Totals diff = *this - prevTotals;
+ if( diff.assertions.failed > 0 )
+ ++diff.testCases.failed;
+ else if( diff.assertions.failedButOk > 0 )
+ ++diff.testCases.failedButOk;
+ else
+ ++diff.testCases.passed;
+ return diff;
+ }
+
+}
+// end catch_totals.cpp
+// start catch_uncaught_exceptions.cpp
+
+#include <exception>
+
+namespace Catch {
+ bool uncaught_exceptions() {
+#if defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
+ return std::uncaught_exceptions() > 0;
+#else
+ return std::uncaught_exception();
+#endif
+ }
+} // end namespace Catch
+// end catch_uncaught_exceptions.cpp
+// start catch_version.cpp
+
+#include <ostream>
+
+namespace Catch {
+
+ Version::Version
+ ( unsigned int _majorVersion,
+ unsigned int _minorVersion,
+ unsigned int _patchNumber,
+ char const * const _branchName,
+ unsigned int _buildNumber )
+ : majorVersion( _majorVersion ),
+ minorVersion( _minorVersion ),
+ patchNumber( _patchNumber ),
+ branchName( _branchName ),
+ buildNumber( _buildNumber )
+ {}
+
+ std::ostream& operator << ( std::ostream& os, Version const& version ) {
+ os << version.majorVersion << '.'
+ << version.minorVersion << '.'
+ << version.patchNumber;
+ // branchName is never null -> 0th char is \0 if it is empty
+ if (version.branchName[0]) {
+ os << '-' << version.branchName
+ << '.' << version.buildNumber;
+ }
+ return os;
+ }
+
+ Version const& libraryVersion() {
+ static Version version( 2, 4, 0, "", 0 );
+ return version;
+ }
+
+}
+// end catch_version.cpp
+// start catch_wildcard_pattern.cpp
+
+#include <sstream>
+
+namespace Catch {
+
+ WildcardPattern::WildcardPattern( std::string const& pattern,
+ CaseSensitive::Choice caseSensitivity )
+ : m_caseSensitivity( caseSensitivity ),
+ m_pattern( adjustCase( pattern ) )
+ {
+ if( startsWith( m_pattern, '*' ) ) {
+ m_pattern = m_pattern.substr( 1 );
+ m_wildcard = WildcardAtStart;
+ }
+ if( endsWith( m_pattern, '*' ) ) {
+ m_pattern = m_pattern.substr( 0, m_pattern.size()-1 );
+ m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd );
+ }
+ }
+
+ bool WildcardPattern::matches( std::string const& str ) const {
+ switch( m_wildcard ) {
+ case NoWildcard:
+ return m_pattern == adjustCase( str );
+ case WildcardAtStart:
+ return endsWith( adjustCase( str ), m_pattern );
+ case WildcardAtEnd:
+ return startsWith( adjustCase( str ), m_pattern );
+ case WildcardAtBothEnds:
+ return contains( adjustCase( str ), m_pattern );
+ default:
+ CATCH_INTERNAL_ERROR( "Unknown enum" );
+ }
+ }
+
+ std::string WildcardPattern::adjustCase( std::string const& str ) const {
+ return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str;
+ }
+}
+// end catch_wildcard_pattern.cpp
+// start catch_xmlwriter.cpp
+
+#include <iomanip>
+
+using uchar = unsigned char;
+
+namespace Catch {
+
+namespace {
+
+ size_t trailingBytes(unsigned char c) {
+ if ((c & 0xE0) == 0xC0) {
+ return 2;
+ }
+ if ((c & 0xF0) == 0xE0) {
+ return 3;
+ }
+ if ((c & 0xF8) == 0xF0) {
+ return 4;
+ }
+ CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered");
+ }
+
+ uint32_t headerValue(unsigned char c) {
+ if ((c & 0xE0) == 0xC0) {
+ return c & 0x1F;
+ }
+ if ((c & 0xF0) == 0xE0) {
+ return c & 0x0F;
+ }
+ if ((c & 0xF8) == 0xF0) {
+ return c & 0x07;
+ }
+ CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered");
+ }
+
+ void hexEscapeChar(std::ostream& os, unsigned char c) {
+ os << "\\x"
+ << std::uppercase << std::hex << std::setfill('0') << std::setw(2)
+ << static_cast<int>(c);
+ }
+
+} // anonymous namespace
+
+ XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat )
+ : m_str( str ),
+ m_forWhat( forWhat )
+ {}
+
+ void XmlEncode::encodeTo( std::ostream& os ) const {
+ // Apostrophe escaping not necessary if we always use " to write attributes
+ // (see: http://www.w3.org/TR/xml/#syntax)
+
+ for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) {
+ uchar c = m_str[idx];
+ switch (c) {
+ case '<': os << "&lt;"; break;
+ case '&': os << "&amp;"; break;
+
+ case '>':
+ // See: http://www.w3.org/TR/xml/#syntax
+ if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']')
+ os << "&gt;";
+ else
+ os << c;
+ break;
+
+ case '\"':
+ if (m_forWhat == ForAttributes)
+ os << "&quot;";
+ else
+ os << c;
+ break;
+
+ default:
+ // Check for control characters and invalid utf-8
+
+ // Escape control characters in standard ascii
+ // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0
+ if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) {
+ hexEscapeChar(os, c);
+ break;
+ }
+
+ // Plain ASCII: Write it to stream
+ if (c < 0x7F) {
+ os << c;
+ break;
+ }
+
+ // UTF-8 territory
+ // Check if the encoding is valid and if it is not, hex escape bytes.
+ // Important: We do not check the exact decoded values for validity, only the encoding format
+ // First check that this bytes is a valid lead byte:
+ // This means that it is not encoded as 1111 1XXX
+ // Or as 10XX XXXX
+ if (c < 0xC0 ||
+ c >= 0xF8) {
+ hexEscapeChar(os, c);
+ break;
+ }
+
+ auto encBytes = trailingBytes(c);
+ // Are there enough bytes left to avoid accessing out-of-bounds memory?
+ if (idx + encBytes - 1 >= m_str.size()) {
+ hexEscapeChar(os, c);
+ break;
+ }
+ // The header is valid, check data
+ // The next encBytes bytes must together be a valid utf-8
+ // This means: bitpattern 10XX XXXX and the extracted value is sane (ish)
+ bool valid = true;
+ uint32_t value = headerValue(c);
+ for (std::size_t n = 1; n < encBytes; ++n) {
+ uchar nc = m_str[idx + n];
+ valid &= ((nc & 0xC0) == 0x80);
+ value = (value << 6) | (nc & 0x3F);
+ }
+
+ if (
+ // Wrong bit pattern of following bytes
+ (!valid) ||
+ // Overlong encodings
+ (value < 0x80) ||
+ (0x80 <= value && value < 0x800 && encBytes > 2) ||
+ (0x800 < value && value < 0x10000 && encBytes > 3) ||
+ // Encoded value out of range
+ (value >= 0x110000)
+ ) {
+ hexEscapeChar(os, c);
+ break;
+ }
+
+ // If we got here, this is in fact a valid(ish) utf-8 sequence
+ for (std::size_t n = 0; n < encBytes; ++n) {
+ os << m_str[idx + n];
+ }
+ idx += encBytes - 1;
+ break;
+ }
+ }
+ }
+
+ std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) {
+ xmlEncode.encodeTo( os );
+ return os;
+ }
+
+ XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer )
+ : m_writer( writer )
+ {}
+
+ XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept
+ : m_writer( other.m_writer ){
+ other.m_writer = nullptr;
+ }
+ XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept {
+ if ( m_writer ) {
+ m_writer->endElement();
+ }
+ m_writer = other.m_writer;
+ other.m_writer = nullptr;
+ return *this;
+ }
+
+ XmlWriter::ScopedElement::~ScopedElement() {
+ if( m_writer )
+ m_writer->endElement();
+ }
+
+ XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, bool indent ) {
+ m_writer->writeText( text, indent );
+ return *this;
+ }
+
+ XmlWriter::XmlWriter( std::ostream& os ) : m_os( os )
+ {
+ writeDeclaration();
+ }
+
+ XmlWriter::~XmlWriter() {
+ while( !m_tags.empty() )
+ endElement();
+ }
+
+ XmlWriter& XmlWriter::startElement( std::string const& name ) {
+ ensureTagClosed();
+ newlineIfNecessary();
+ m_os << m_indent << '<' << name;
+ m_tags.push_back( name );
+ m_indent += " ";
+ m_tagIsOpen = true;
+ return *this;
+ }
+
+ XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name ) {
+ ScopedElement scoped( this );
+ startElement( name );
+ return scoped;
+ }
+
+ XmlWriter& XmlWriter::endElement() {
+ newlineIfNecessary();
+ m_indent = m_indent.substr( 0, m_indent.size()-2 );
+ if( m_tagIsOpen ) {
+ m_os << "/>";
+ m_tagIsOpen = false;
+ }
+ else {
+ m_os << m_indent << "</" << m_tags.back() << ">";
+ }
+ m_os << std::endl;
+ m_tags.pop_back();
+ return *this;
+ }
+
+ XmlWriter& XmlWriter::writeAttribute( std::string const& name, std::string const& attribute ) {
+ if( !name.empty() && !attribute.empty() )
+ m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"';
+ return *this;
+ }
+
+ XmlWriter& XmlWriter::writeAttribute( std::string const& name, bool attribute ) {
+ m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"';
+ return *this;
+ }
+
+ XmlWriter& XmlWriter::writeText( std::string const& text, bool indent ) {
+ if( !text.empty() ){
+ bool tagWasOpen = m_tagIsOpen;
+ ensureTagClosed();
+ if( tagWasOpen && indent )
+ m_os << m_indent;
+ m_os << XmlEncode( text );
+ m_needsNewline = true;
+ }
+ return *this;
+ }
+
+ XmlWriter& XmlWriter::writeComment( std::string const& text ) {
+ ensureTagClosed();
+ m_os << m_indent << "<!--" << text << "-->";
+ m_needsNewline = true;
+ return *this;
+ }
+
+ void XmlWriter::writeStylesheetRef( std::string const& url ) {
+ m_os << "<?xml-stylesheet type=\"text/xsl\" href=\"" << url << "\"?>\n";
+ }
+
+ XmlWriter& XmlWriter::writeBlankLine() {
+ ensureTagClosed();
+ m_os << '\n';
+ return *this;
+ }
+
+ void XmlWriter::ensureTagClosed() {
+ if( m_tagIsOpen ) {
+ m_os << ">" << std::endl;
+ m_tagIsOpen = false;
+ }
+ }
+
+ void XmlWriter::writeDeclaration() {
+ m_os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+ }
+
+ void XmlWriter::newlineIfNecessary() {
+ if( m_needsNewline ) {
+ m_os << std::endl;
+ m_needsNewline = false;
+ }
+ }
+}
+// end catch_xmlwriter.cpp
+// start catch_reporter_bases.cpp
+
+#include <cstring>
+#include <cfloat>
+#include <cstdio>
+#include <cassert>
+#include <memory>
+
+namespace Catch {
+ void prepareExpandedExpression(AssertionResult& result) {
+ result.getExpandedExpression();
+ }
+
+ // Because formatting using c++ streams is stateful, drop down to C is required
+ // Alternatively we could use stringstream, but its performance is... not good.
+ std::string getFormattedDuration( double duration ) {
+ // Max exponent + 1 is required to represent the whole part
+ // + 1 for decimal point
+ // + 3 for the 3 decimal places
+ // + 1 for null terminator
+ const std::size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1;
+ char buffer[maxDoubleSize];
+
+ // Save previous errno, to prevent sprintf from overwriting it
+ ErrnoGuard guard;
+#ifdef _MSC_VER
+ sprintf_s(buffer, "%.3f", duration);
+#else
+ sprintf(buffer, "%.3f", duration);
+#endif
+ return std::string(buffer);
+ }
+
+ TestEventListenerBase::TestEventListenerBase(ReporterConfig const & _config)
+ :StreamingReporterBase(_config) {}
+
+ void TestEventListenerBase::assertionStarting(AssertionInfo const &) {}
+
+ bool TestEventListenerBase::assertionEnded(AssertionStats const &) {
+ return false;
+ }
+
+} // end namespace Catch
+// end catch_reporter_bases.cpp
+// start catch_reporter_compact.cpp
+
+namespace {
+
+#ifdef CATCH_PLATFORM_MAC
+ const char* failedString() { return "FAILED"; }
+ const char* passedString() { return "PASSED"; }
+#else
+ const char* failedString() { return "failed"; }
+ const char* passedString() { return "passed"; }
+#endif
+
+ // Colour::LightGrey
+ Catch::Colour::Code dimColour() { return Catch::Colour::FileName; }
+
+ std::string bothOrAll( std::size_t count ) {
+ return count == 1 ? std::string() :
+ count == 2 ? "both " : "all " ;
+ }
+
+} // anon namespace
+
+namespace Catch {
+namespace {
+// Colour, message variants:
+// - white: No tests ran.
+// - red: Failed [both/all] N test cases, failed [both/all] M assertions.
+// - white: Passed [both/all] N test cases (no assertions).
+// - red: Failed N tests cases, failed M assertions.
+// - green: Passed [both/all] N tests cases with M assertions.
+void printTotals(std::ostream& out, const Totals& totals) {
+ if (totals.testCases.total() == 0) {
+ out << "No tests ran.";
+ } else if (totals.testCases.failed == totals.testCases.total()) {
+ Colour colour(Colour::ResultError);
+ const std::string qualify_assertions_failed =
+ totals.assertions.failed == totals.assertions.total() ?
+ bothOrAll(totals.assertions.failed) : std::string();
+ out <<
+ "Failed " << bothOrAll(totals.testCases.failed)
+ << pluralise(totals.testCases.failed, "test case") << ", "
+ "failed " << qualify_assertions_failed <<
+ pluralise(totals.assertions.failed, "assertion") << '.';
+ } else if (totals.assertions.total() == 0) {
+ out <<
+ "Passed " << bothOrAll(totals.testCases.total())
+ << pluralise(totals.testCases.total(), "test case")
+ << " (no assertions).";
+ } else if (totals.assertions.failed) {
+ Colour colour(Colour::ResultError);
+ out <<
+ "Failed " << pluralise(totals.testCases.failed, "test case") << ", "
+ "failed " << pluralise(totals.assertions.failed, "assertion") << '.';
+ } else {
+ Colour colour(Colour::ResultSuccess);
+ out <<
+ "Passed " << bothOrAll(totals.testCases.passed)
+ << pluralise(totals.testCases.passed, "test case") <<
+ " with " << pluralise(totals.assertions.passed, "assertion") << '.';
+ }
+}
+
+// Implementation of CompactReporter formatting
+class AssertionPrinter {
+public:
+ AssertionPrinter& operator= (AssertionPrinter const&) = delete;
+ AssertionPrinter(AssertionPrinter const&) = delete;
+ AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages)
+ : stream(_stream)
+ , result(_stats.assertionResult)
+ , messages(_stats.infoMessages)
+ , itMessage(_stats.infoMessages.begin())
+ , printInfoMessages(_printInfoMessages) {}
+
+ void print() {
+ printSourceInfo();
+
+ itMessage = messages.begin();
+
+ switch (result.getResultType()) {
+ case ResultWas::Ok:
+ printResultType(Colour::ResultSuccess, passedString());
+ printOriginalExpression();
+ printReconstructedExpression();
+ if (!result.hasExpression())
+ printRemainingMessages(Colour::None);
+ else
+ printRemainingMessages();
+ break;
+ case ResultWas::ExpressionFailed:
+ if (result.isOk())
+ printResultType(Colour::ResultSuccess, failedString() + std::string(" - but was ok"));
+ else
+ printResultType(Colour::Error, failedString());
+ printOriginalExpression();
+ printReconstructedExpression();
+ printRemainingMessages();
+ break;
+ case ResultWas::ThrewException:
+ printResultType(Colour::Error, failedString());
+ printIssue("unexpected exception with message:");
+ printMessage();
+ printExpressionWas();
+ printRemainingMessages();
+ break;
+ case ResultWas::FatalErrorCondition:
+ printResultType(Colour::Error, failedString());
+ printIssue("fatal error condition with message:");
+ printMessage();
+ printExpressionWas();
+ printRemainingMessages();
+ break;
+ case ResultWas::DidntThrowException:
+ printResultType(Colour::Error, failedString());
+ printIssue("expected exception, got none");
+ printExpressionWas();
+ printRemainingMessages();
+ break;
+ case ResultWas::Info:
+ printResultType(Colour::None, "info");
+ printMessage();
+ printRemainingMessages();
+ break;
+ case ResultWas::Warning:
+ printResultType(Colour::None, "warning");
+ printMessage();
+ printRemainingMessages();
+ break;
+ case ResultWas::ExplicitFailure:
+ printResultType(Colour::Error, failedString());
+ printIssue("explicitly");
+ printRemainingMessages(Colour::None);
+ break;
+ // These cases are here to prevent compiler warnings
+ case ResultWas::Unknown:
+ case ResultWas::FailureBit:
+ case ResultWas::Exception:
+ printResultType(Colour::Error, "** internal error **");
+ break;
+ }
+ }
+
+private:
+ void printSourceInfo() const {
+ Colour colourGuard(Colour::FileName);
+ stream << result.getSourceInfo() << ':';
+ }
+
+ void printResultType(Colour::Code colour, std::string const& passOrFail) const {
+ if (!passOrFail.empty()) {
+ {
+ Colour colourGuard(colour);
+ stream << ' ' << passOrFail;
+ }
+ stream << ':';
+ }
+ }
+
+ void printIssue(std::string const& issue) const {
+ stream << ' ' << issue;
+ }
+
+ void printExpressionWas() {
+ if (result.hasExpression()) {
+ stream << ';';
+ {
+ Colour colour(dimColour());
+ stream << " expression was:";
+ }
+ printOriginalExpression();
+ }
+ }
+
+ void printOriginalExpression() const {
+ if (result.hasExpression()) {
+ stream << ' ' << result.getExpression();
+ }
+ }
+
+ void printReconstructedExpression() const {
+ if (result.hasExpandedExpression()) {
+ {
+ Colour colour(dimColour());
+ stream << " for: ";
+ }
+ stream << result.getExpandedExpression();
+ }
+ }
+
+ void printMessage() {
+ if (itMessage != messages.end()) {
+ stream << " '" << itMessage->message << '\'';
+ ++itMessage;
+ }
+ }
+
+ void printRemainingMessages(Colour::Code colour = dimColour()) {
+ if (itMessage == messages.end())
+ return;
+
+ // using messages.end() directly yields (or auto) compilation error:
+ std::vector<MessageInfo>::const_iterator itEnd = messages.end();
+ const std::size_t N = static_cast<std::size_t>(std::distance(itMessage, itEnd));
+
+ {
+ Colour colourGuard(colour);
+ stream << " with " << pluralise(N, "message") << ':';
+ }
+
+ for (; itMessage != itEnd; ) {
+ // If this assertion is a warning ignore any INFO messages
+ if (printInfoMessages || itMessage->type != ResultWas::Info) {
+ stream << " '" << itMessage->message << '\'';
+ if (++itMessage != itEnd) {
+ Colour colourGuard(dimColour());
+ stream << " and";
+ }
+ }
+ }
+ }
+
+private:
+ std::ostream& stream;
+ AssertionResult const& result;
+ std::vector<MessageInfo> messages;
+ std::vector<MessageInfo>::const_iterator itMessage;
+ bool printInfoMessages;
+};
+
+} // anon namespace
+
+ std::string CompactReporter::getDescription() {
+ return "Reports test results on a single line, suitable for IDEs";
+ }
+
+ ReporterPreferences CompactReporter::getPreferences() const {
+ return m_reporterPrefs;
+ }
+
+ void CompactReporter::noMatchingTestCases( std::string const& spec ) {
+ stream << "No test cases matched '" << spec << '\'' << std::endl;
+ }
+
+ void CompactReporter::assertionStarting( AssertionInfo const& ) {}
+
+ bool CompactReporter::assertionEnded( AssertionStats const& _assertionStats ) {
+ AssertionResult const& result = _assertionStats.assertionResult;
+
+ bool printInfoMessages = true;
+
+ // Drop out if result was successful and we're not printing those
+ if( !m_config->includeSuccessfulResults() && result.isOk() ) {
+ if( result.getResultType() != ResultWas::Warning )
+ return false;
+ printInfoMessages = false;
+ }
+
+ AssertionPrinter printer( stream, _assertionStats, printInfoMessages );
+ printer.print();
+
+ stream << std::endl;
+ return true;
+ }
+
+ void CompactReporter::sectionEnded(SectionStats const& _sectionStats) {
+ if (m_config->showDurations() == ShowDurations::Always) {
+ stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl;
+ }
+ }
+
+ void CompactReporter::testRunEnded( TestRunStats const& _testRunStats ) {
+ printTotals( stream, _testRunStats.totals );
+ stream << '\n' << std::endl;
+ StreamingReporterBase::testRunEnded( _testRunStats );
+ }
+
+ CompactReporter::~CompactReporter() {}
+
+ CATCH_REGISTER_REPORTER( "compact", CompactReporter )
+
+} // end namespace Catch
+// end catch_reporter_compact.cpp
+// start catch_reporter_console.cpp
+
+#include <cfloat>
+#include <cstdio>
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch
+ // Note that 4062 (not all labels are handled
+ // and default is missing) is enabled
+#endif
+
+namespace Catch {
+
+namespace {
+
+// Formatter impl for ConsoleReporter
+class ConsoleAssertionPrinter {
+public:
+ ConsoleAssertionPrinter& operator= (ConsoleAssertionPrinter const&) = delete;
+ ConsoleAssertionPrinter(ConsoleAssertionPrinter const&) = delete;
+ ConsoleAssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages)
+ : stream(_stream),
+ stats(_stats),
+ result(_stats.assertionResult),
+ colour(Colour::None),
+ message(result.getMessage()),
+ messages(_stats.infoMessages),
+ printInfoMessages(_printInfoMessages) {
+ switch (result.getResultType()) {
+ case ResultWas::Ok:
+ colour = Colour::Success;
+ passOrFail = "PASSED";
+ //if( result.hasMessage() )
+ if (_stats.infoMessages.size() == 1)
+ messageLabel = "with message";
+ if (_stats.infoMessages.size() > 1)
+ messageLabel = "with messages";
+ break;
+ case ResultWas::ExpressionFailed:
+ if (result.isOk()) {
+ colour = Colour::Success;
+ passOrFail = "FAILED - but was ok";
+ } else {
+ colour = Colour::Error;
+ passOrFail = "FAILED";
+ }
+ if (_stats.infoMessages.size() == 1)
+ messageLabel = "with message";
+ if (_stats.infoMessages.size() > 1)
+ messageLabel = "with messages";
+ break;
+ case ResultWas::ThrewException:
+ colour = Colour::Error;
+ passOrFail = "FAILED";
+ messageLabel = "due to unexpected exception with ";
+ if (_stats.infoMessages.size() == 1)
+ messageLabel += "message";
+ if (_stats.infoMessages.size() > 1)
+ messageLabel += "messages";
+ break;
+ case ResultWas::FatalErrorCondition:
+ colour = Colour::Error;
+ passOrFail = "FAILED";
+ messageLabel = "due to a fatal error condition";
+ break;
+ case ResultWas::DidntThrowException:
+ colour = Colour::Error;
+ passOrFail = "FAILED";
+ messageLabel = "because no exception was thrown where one was expected";
+ break;
+ case ResultWas::Info:
+ messageLabel = "info";
+ break;
+ case ResultWas::Warning:
+ messageLabel = "warning";
+ break;
+ case ResultWas::ExplicitFailure:
+ passOrFail = "FAILED";
+ colour = Colour::Error;
+ if (_stats.infoMessages.size() == 1)
+ messageLabel = "explicitly with message";
+ if (_stats.infoMessages.size() > 1)
+ messageLabel = "explicitly with messages";
+ break;
+ // These cases are here to prevent compiler warnings
+ case ResultWas::Unknown:
+ case ResultWas::FailureBit:
+ case ResultWas::Exception:
+ passOrFail = "** internal error **";
+ colour = Colour::Error;
+ break;
+ }
+ }
+
+ void print() const {
+ printSourceInfo();
+ if (stats.totals.assertions.total() > 0) {
+ if (result.isOk())
+ stream << '\n';
+ printResultType();
+ printOriginalExpression();
+ printReconstructedExpression();
+ } else {
+ stream << '\n';
+ }
+ printMessage();
+ }
+
+private:
+ void printResultType() const {
+ if (!passOrFail.empty()) {
+ Colour colourGuard(colour);
+ stream << passOrFail << ":\n";
+ }
+ }
+ void printOriginalExpression() const {
+ if (result.hasExpression()) {
+ Colour colourGuard(Colour::OriginalExpression);
+ stream << " ";
+ stream << result.getExpressionInMacro();
+ stream << '\n';
+ }
+ }
+ void printReconstructedExpression() const {
+ if (result.hasExpandedExpression()) {
+ stream << "with expansion:\n";
+ Colour colourGuard(Colour::ReconstructedExpression);
+ stream << Column(result.getExpandedExpression()).indent(2) << '\n';
+ }
+ }
+ void printMessage() const {
+ if (!messageLabel.empty())
+ stream << messageLabel << ':' << '\n';
+ for (auto const& msg : messages) {
+ // If this assertion is a warning ignore any INFO messages
+ if (printInfoMessages || msg.type != ResultWas::Info)
+ stream << Column(msg.message).indent(2) << '\n';
+ }
+ }
+ void printSourceInfo() const {
+ Colour colourGuard(Colour::FileName);
+ stream << result.getSourceInfo() << ": ";
+ }
+
+ std::ostream& stream;
+ AssertionStats const& stats;
+ AssertionResult const& result;
+ Colour::Code colour;
+ std::string passOrFail;
+ std::string messageLabel;
+ std::string message;
+ std::vector<MessageInfo> messages;
+ bool printInfoMessages;
+};
+
+std::size_t makeRatio(std::size_t number, std::size_t total) {
+ std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number / total : 0;
+ return (ratio == 0 && number > 0) ? 1 : ratio;
+}
+
+std::size_t& findMax(std::size_t& i, std::size_t& j, std::size_t& k) {
+ if (i > j && i > k)
+ return i;
+ else if (j > k)
+ return j;
+ else
+ return k;
+}
+
+struct ColumnInfo {
+ enum Justification { Left, Right };
+ std::string name;
+ int width;
+ Justification justification;
+};
+struct ColumnBreak {};
+struct RowBreak {};
+
+class Duration {
+ enum class Unit {
+ Auto,
+ Nanoseconds,
+ Microseconds,
+ Milliseconds,
+ Seconds,
+ Minutes
+ };
+ static const uint64_t s_nanosecondsInAMicrosecond = 1000;
+ static const uint64_t s_nanosecondsInAMillisecond = 1000 * s_nanosecondsInAMicrosecond;
+ static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond;
+ static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond;
+
+ uint64_t m_inNanoseconds;
+ Unit m_units;
+
+public:
+ explicit Duration(uint64_t inNanoseconds, Unit units = Unit::Auto)
+ : m_inNanoseconds(inNanoseconds),
+ m_units(units) {
+ if (m_units == Unit::Auto) {
+ if (m_inNanoseconds < s_nanosecondsInAMicrosecond)
+ m_units = Unit::Nanoseconds;
+ else if (m_inNanoseconds < s_nanosecondsInAMillisecond)
+ m_units = Unit::Microseconds;
+ else if (m_inNanoseconds < s_nanosecondsInASecond)
+ m_units = Unit::Milliseconds;
+ else if (m_inNanoseconds < s_nanosecondsInAMinute)
+ m_units = Unit::Seconds;
+ else
+ m_units = Unit::Minutes;
+ }
+
+ }
+
+ auto value() const -> double {
+ switch (m_units) {
+ case Unit::Microseconds:
+ return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMicrosecond);
+ case Unit::Milliseconds:
+ return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMillisecond);
+ case Unit::Seconds:
+ return m_inNanoseconds / static_cast<double>(s_nanosecondsInASecond);
+ case Unit::Minutes:
+ return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMinute);
+ default:
+ return static_cast<double>(m_inNanoseconds);
+ }
+ }
+ auto unitsAsString() const -> std::string {
+ switch (m_units) {
+ case Unit::Nanoseconds:
+ return "ns";
+ case Unit::Microseconds:
+ return "µs";
+ case Unit::Milliseconds:
+ return "ms";
+ case Unit::Seconds:
+ return "s";
+ case Unit::Minutes:
+ return "m";
+ default:
+ return "** internal error **";
+ }
+
+ }
+ friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& {
+ return os << duration.value() << " " << duration.unitsAsString();
+ }
+};
+} // end anon namespace
+
+class TablePrinter {
+ std::ostream& m_os;
+ std::vector<ColumnInfo> m_columnInfos;
+ std::ostringstream m_oss;
+ int m_currentColumn = -1;
+ bool m_isOpen = false;
+
+public:
+ TablePrinter( std::ostream& os, std::vector<ColumnInfo> columnInfos )
+ : m_os( os ),
+ m_columnInfos( std::move( columnInfos ) ) {}
+
+ auto columnInfos() const -> std::vector<ColumnInfo> const& {
+ return m_columnInfos;
+ }
+
+ void open() {
+ if (!m_isOpen) {
+ m_isOpen = true;
+ *this << RowBreak();
+ for (auto const& info : m_columnInfos)
+ *this << info.name << ColumnBreak();
+ *this << RowBreak();
+ m_os << Catch::getLineOfChars<'-'>() << "\n";
+ }
+ }
+ void close() {
+ if (m_isOpen) {
+ *this << RowBreak();
+ m_os << std::endl;
+ m_isOpen = false;
+ }
+ }
+
+ template<typename T>
+ friend TablePrinter& operator << (TablePrinter& tp, T const& value) {
+ tp.m_oss << value;
+ return tp;
+ }
+
+ friend TablePrinter& operator << (TablePrinter& tp, ColumnBreak) {
+ auto colStr = tp.m_oss.str();
+ // This takes account of utf8 encodings
+ auto strSize = Catch::StringRef(colStr).numberOfCharacters();
+ tp.m_oss.str("");
+ tp.open();
+ if (tp.m_currentColumn == static_cast<int>(tp.m_columnInfos.size() - 1)) {
+ tp.m_currentColumn = -1;
+ tp.m_os << "\n";
+ }
+ tp.m_currentColumn++;
+
+ auto colInfo = tp.m_columnInfos[tp.m_currentColumn];
+ auto padding = (strSize + 2 < static_cast<std::size_t>(colInfo.width))
+ ? std::string(colInfo.width - (strSize + 2), ' ')
+ : std::string();
+ if (colInfo.justification == ColumnInfo::Left)
+ tp.m_os << colStr << padding << " ";
+ else
+ tp.m_os << padding << colStr << " ";
+ return tp;
+ }
+
+ friend TablePrinter& operator << (TablePrinter& tp, RowBreak) {
+ if (tp.m_currentColumn > 0) {
+ tp.m_os << "\n";
+ tp.m_currentColumn = -1;
+ }
+ return tp;
+ }
+};
+
+ConsoleReporter::ConsoleReporter(ReporterConfig const& config)
+ : StreamingReporterBase(config),
+ m_tablePrinter(new TablePrinter(config.stream(),
+ {
+ { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 32, ColumnInfo::Left },
+ { "iters", 8, ColumnInfo::Right },
+ { "elapsed ns", 14, ColumnInfo::Right },
+ { "average", 14, ColumnInfo::Right }
+ })) {}
+ConsoleReporter::~ConsoleReporter() = default;
+
+std::string ConsoleReporter::getDescription() {
+ return "Reports test results as plain lines of text";
+}
+
+void ConsoleReporter::noMatchingTestCases(std::string const& spec) {
+ stream << "No test cases matched '" << spec << '\'' << std::endl;
+}
+
+void ConsoleReporter::assertionStarting(AssertionInfo const&) {}
+
+bool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) {
+ AssertionResult const& result = _assertionStats.assertionResult;
+
+ bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();
+
+ // Drop out if result was successful but we're not printing them.
+ if (!includeResults && result.getResultType() != ResultWas::Warning)
+ return false;
+
+ lazyPrint();
+
+ ConsoleAssertionPrinter printer(stream, _assertionStats, includeResults);
+ printer.print();
+ stream << std::endl;
+ return true;
+}
+
+void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) {
+ m_headerPrinted = false;
+ StreamingReporterBase::sectionStarting(_sectionInfo);
+}
+void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) {
+ m_tablePrinter->close();
+ if (_sectionStats.missingAssertions) {
+ lazyPrint();
+ Colour colour(Colour::ResultError);
+ if (m_sectionStack.size() > 1)
+ stream << "\nNo assertions in section";
+ else
+ stream << "\nNo assertions in test case";
+ stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl;
+ }
+ if (m_config->showDurations() == ShowDurations::Always) {
+ stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl;
+ }
+ if (m_headerPrinted) {
+ m_headerPrinted = false;
+ }
+ StreamingReporterBase::sectionEnded(_sectionStats);
+}
+
+void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) {
+ lazyPrintWithoutClosingBenchmarkTable();
+
+ auto nameCol = Column( info.name ).width( static_cast<std::size_t>( m_tablePrinter->columnInfos()[0].width - 2 ) );
+
+ bool firstLine = true;
+ for (auto line : nameCol) {
+ if (!firstLine)
+ (*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak();
+ else
+ firstLine = false;
+
+ (*m_tablePrinter) << line << ColumnBreak();
+ }
+}
+void ConsoleReporter::benchmarkEnded(BenchmarkStats const& stats) {
+ Duration average(stats.elapsedTimeInNanoseconds / stats.iterations);
+ (*m_tablePrinter)
+ << stats.iterations << ColumnBreak()
+ << stats.elapsedTimeInNanoseconds << ColumnBreak()
+ << average << ColumnBreak();
+}
+
+void ConsoleReporter::testCaseEnded(TestCaseStats const& _testCaseStats) {
+ m_tablePrinter->close();
+ StreamingReporterBase::testCaseEnded(_testCaseStats);
+ m_headerPrinted = false;
+}
+void ConsoleReporter::testGroupEnded(TestGroupStats const& _testGroupStats) {
+ if (currentGroupInfo.used) {
+ printSummaryDivider();
+ stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n";
+ printTotals(_testGroupStats.totals);
+ stream << '\n' << std::endl;
+ }
+ StreamingReporterBase::testGroupEnded(_testGroupStats);
+}
+void ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) {
+ printTotalsDivider(_testRunStats.totals);
+ printTotals(_testRunStats.totals);
+ stream << std::endl;
+ StreamingReporterBase::testRunEnded(_testRunStats);
+}
+
+void ConsoleReporter::lazyPrint() {
+
+ m_tablePrinter->close();
+ lazyPrintWithoutClosingBenchmarkTable();
+}
+
+void ConsoleReporter::lazyPrintWithoutClosingBenchmarkTable() {
+
+ if (!currentTestRunInfo.used)
+ lazyPrintRunInfo();
+ if (!currentGroupInfo.used)
+ lazyPrintGroupInfo();
+
+ if (!m_headerPrinted) {
+ printTestCaseAndSectionHeader();
+ m_headerPrinted = true;
+ }
+}
+void ConsoleReporter::lazyPrintRunInfo() {
+ stream << '\n' << getLineOfChars<'~'>() << '\n';
+ Colour colour(Colour::SecondaryText);
+ stream << currentTestRunInfo->name
+ << " is a Catch v" << libraryVersion() << " host application.\n"
+ << "Run with -? for options\n\n";
+
+ if (m_config->rngSeed() != 0)
+ stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n";
+
+ currentTestRunInfo.used = true;
+}
+void ConsoleReporter::lazyPrintGroupInfo() {
+ if (!currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1) {
+ printClosedHeader("Group: " + currentGroupInfo->name);
+ currentGroupInfo.used = true;
+ }
+}
+void ConsoleReporter::printTestCaseAndSectionHeader() {
+ assert(!m_sectionStack.empty());
+ printOpenHeader(currentTestCaseInfo->name);
+
+ if (m_sectionStack.size() > 1) {
+ Colour colourGuard(Colour::Headers);
+
+ auto
+ it = m_sectionStack.begin() + 1, // Skip first section (test case)
+ itEnd = m_sectionStack.end();
+ for (; it != itEnd; ++it)
+ printHeaderString(it->name, 2);
+ }
+
+ SourceLineInfo lineInfo = m_sectionStack.back().lineInfo;
+
+ if (!lineInfo.empty()) {
+ stream << getLineOfChars<'-'>() << '\n';
+ Colour colourGuard(Colour::FileName);
+ stream << lineInfo << '\n';
+ }
+ stream << getLineOfChars<'.'>() << '\n' << std::endl;
+}
+
+void ConsoleReporter::printClosedHeader(std::string const& _name) {
+ printOpenHeader(_name);
+ stream << getLineOfChars<'.'>() << '\n';
+}
+void ConsoleReporter::printOpenHeader(std::string const& _name) {
+ stream << getLineOfChars<'-'>() << '\n';
+ {
+ Colour colourGuard(Colour::Headers);
+ printHeaderString(_name);
+ }
+}
+
+// if string has a : in first line will set indent to follow it on
+// subsequent lines
+void ConsoleReporter::printHeaderString(std::string const& _string, std::size_t indent) {
+ std::size_t i = _string.find(": ");
+ if (i != std::string::npos)
+ i += 2;
+ else
+ i = 0;
+ stream << Column(_string).indent(indent + i).initialIndent(indent) << '\n';
+}
+
+struct SummaryColumn {
+
+ SummaryColumn( std::string _label, Colour::Code _colour )
+ : label( std::move( _label ) ),
+ colour( _colour ) {}
+ SummaryColumn addRow( std::size_t count ) {
+ ReusableStringStream rss;
+ rss << count;
+ std::string row = rss.str();
+ for (auto& oldRow : rows) {
+ while (oldRow.size() < row.size())
+ oldRow = ' ' + oldRow;
+ while (oldRow.size() > row.size())
+ row = ' ' + row;
+ }
+ rows.push_back(row);
+ return *this;
+ }
+
+ std::string label;
+ Colour::Code colour;
+ std::vector<std::string> rows;
+
+};
+
+void ConsoleReporter::printTotals( Totals const& totals ) {
+ if (totals.testCases.total() == 0) {
+ stream << Colour(Colour::Warning) << "No tests ran\n";
+ } else if (totals.assertions.total() > 0 && totals.testCases.allPassed()) {
+ stream << Colour(Colour::ResultSuccess) << "All tests passed";
+ stream << " ("
+ << pluralise(totals.assertions.passed, "assertion") << " in "
+ << pluralise(totals.testCases.passed, "test case") << ')'
+ << '\n';
+ } else {
+
+ std::vector<SummaryColumn> columns;
+ columns.push_back(SummaryColumn("", Colour::None)
+ .addRow(totals.testCases.total())
+ .addRow(totals.assertions.total()));
+ columns.push_back(SummaryColumn("passed", Colour::Success)
+ .addRow(totals.testCases.passed)
+ .addRow(totals.assertions.passed));
+ columns.push_back(SummaryColumn("failed", Colour::ResultError)
+ .addRow(totals.testCases.failed)
+ .addRow(totals.assertions.failed));
+ columns.push_back(SummaryColumn("failed as expected", Colour::ResultExpectedFailure)
+ .addRow(totals.testCases.failedButOk)
+ .addRow(totals.assertions.failedButOk));
+
+ printSummaryRow("test cases", columns, 0);
+ printSummaryRow("assertions", columns, 1);
+ }
+}
+void ConsoleReporter::printSummaryRow(std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row) {
+ for (auto col : cols) {
+ std::string value = col.rows[row];
+ if (col.label.empty()) {
+ stream << label << ": ";
+ if (value != "0")
+ stream << value;
+ else
+ stream << Colour(Colour::Warning) << "- none -";
+ } else if (value != "0") {
+ stream << Colour(Colour::LightGrey) << " | ";
+ stream << Colour(col.colour)
+ << value << ' ' << col.label;
+ }
+ }
+ stream << '\n';
+}
+
+void ConsoleReporter::printTotalsDivider(Totals const& totals) {
+ if (totals.testCases.total() > 0) {
+ std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total());
+ std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total());
+ std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total());
+ while (failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1)
+ findMax(failedRatio, failedButOkRatio, passedRatio)++;
+ while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1)
+ findMax(failedRatio, failedButOkRatio, passedRatio)--;
+
+ stream << Colour(Colour::Error) << std::string(failedRatio, '=');
+ stream << Colour(Colour::ResultExpectedFailure) << std::string(failedButOkRatio, '=');
+ if (totals.testCases.allPassed())
+ stream << Colour(Colour::ResultSuccess) << std::string(passedRatio, '=');
+ else
+ stream << Colour(Colour::Success) << std::string(passedRatio, '=');
+ } else {
+ stream << Colour(Colour::Warning) << std::string(CATCH_CONFIG_CONSOLE_WIDTH - 1, '=');
+ }
+ stream << '\n';
+}
+void ConsoleReporter::printSummaryDivider() {
+ stream << getLineOfChars<'-'>() << '\n';
+}
+
+CATCH_REGISTER_REPORTER("console", ConsoleReporter)
+
+} // end namespace Catch
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+// end catch_reporter_console.cpp
+// start catch_reporter_junit.cpp
+
+#include <cassert>
+#include <sstream>
+#include <ctime>
+#include <algorithm>
+
+namespace Catch {
+
+ namespace {
+ std::string getCurrentTimestamp() {
+ // Beware, this is not reentrant because of backward compatibility issues
+ // Also, UTC only, again because of backward compatibility (%z is C++11)
+ time_t rawtime;
+ std::time(&rawtime);
+ auto const timeStampSize = sizeof("2017-01-16T17:06:45Z");
+
+#ifdef _MSC_VER
+ std::tm timeInfo = {};
+ gmtime_s(&timeInfo, &rawtime);
+#else
+ std::tm* timeInfo;
+ timeInfo = std::gmtime(&rawtime);
+#endif
+
+ char timeStamp[timeStampSize];
+ const char * const fmt = "%Y-%m-%dT%H:%M:%SZ";
+
+#ifdef _MSC_VER
+ std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);
+#else
+ std::strftime(timeStamp, timeStampSize, fmt, timeInfo);
+#endif
+ return std::string(timeStamp);
+ }
+
+ std::string fileNameTag(const std::vector<std::string> &tags) {
+ auto it = std::find_if(begin(tags),
+ end(tags),
+ [] (std::string const& tag) {return tag.front() == '#'; });
+ if (it != tags.end())
+ return it->substr(1);
+ return std::string();
+ }
+ } // anonymous namespace
+
+ JunitReporter::JunitReporter( ReporterConfig const& _config )
+ : CumulativeReporterBase( _config ),
+ xml( _config.stream() )
+ {
+ m_reporterPrefs.shouldRedirectStdOut = true;
+ m_reporterPrefs.shouldReportAllAssertions = true;
+ }
+
+ JunitReporter::~JunitReporter() {}
+
+ std::string JunitReporter::getDescription() {
+ return "Reports test results in an XML format that looks like Ant's junitreport target";
+ }
+
+ void JunitReporter::noMatchingTestCases( std::string const& /*spec*/ ) {}
+
+ void JunitReporter::testRunStarting( TestRunInfo const& runInfo ) {
+ CumulativeReporterBase::testRunStarting( runInfo );
+ xml.startElement( "testsuites" );
+ }
+
+ void JunitReporter::testGroupStarting( GroupInfo const& groupInfo ) {
+ suiteTimer.start();
+ stdOutForSuite.clear();
+ stdErrForSuite.clear();
+ unexpectedExceptions = 0;
+ CumulativeReporterBase::testGroupStarting( groupInfo );
+ }
+
+ void JunitReporter::testCaseStarting( TestCaseInfo const& testCaseInfo ) {
+ m_okToFail = testCaseInfo.okToFail();
+ }
+
+ bool JunitReporter::assertionEnded( AssertionStats const& assertionStats ) {
+ if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail )
+ unexpectedExceptions++;
+ return CumulativeReporterBase::assertionEnded( assertionStats );
+ }
+
+ void JunitReporter::testCaseEnded( TestCaseStats const& testCaseStats ) {
+ stdOutForSuite += testCaseStats.stdOut;
+ stdErrForSuite += testCaseStats.stdErr;
+ CumulativeReporterBase::testCaseEnded( testCaseStats );
+ }
+
+ void JunitReporter::testGroupEnded( TestGroupStats const& testGroupStats ) {
+ double suiteTime = suiteTimer.getElapsedSeconds();
+ CumulativeReporterBase::testGroupEnded( testGroupStats );
+ writeGroup( *m_testGroups.back(), suiteTime );
+ }
+
+ void JunitReporter::testRunEndedCumulative() {
+ xml.endElement();
+ }
+
+ void JunitReporter::writeGroup( TestGroupNode const& groupNode, double suiteTime ) {
+ XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" );
+ TestGroupStats const& stats = groupNode.value;
+ xml.writeAttribute( "name", stats.groupInfo.name );
+ xml.writeAttribute( "errors", unexpectedExceptions );
+ xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions );
+ xml.writeAttribute( "tests", stats.totals.assertions.total() );
+ xml.writeAttribute( "hostname", "tbd" ); // !TBD
+ if( m_config->showDurations() == ShowDurations::Never )
+ xml.writeAttribute( "time", "" );
+ else
+ xml.writeAttribute( "time", suiteTime );
+ xml.writeAttribute( "timestamp", getCurrentTimestamp() );
+
+ // Write test cases
+ for( auto const& child : groupNode.children )
+ writeTestCase( *child );
+
+ xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), false );
+ xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), false );
+ }
+
+ void JunitReporter::writeTestCase( TestCaseNode const& testCaseNode ) {
+ TestCaseStats const& stats = testCaseNode.value;
+
+ // All test cases have exactly one section - which represents the
+ // test case itself. That section may have 0-n nested sections
+ assert( testCaseNode.children.size() == 1 );
+ SectionNode const& rootSection = *testCaseNode.children.front();
+
+ std::string className = stats.testInfo.className;
+
+ if( className.empty() ) {
+ className = fileNameTag(stats.testInfo.tags);
+ if ( className.empty() )
+ className = "global";
+ }
+
+ if ( !m_config->name().empty() )
+ className = m_config->name() + "." + className;
+
+ writeSection( className, "", rootSection );
+ }
+
+ void JunitReporter::writeSection( std::string const& className,
+ std::string const& rootName,
+ SectionNode const& sectionNode ) {
+ std::string name = trim( sectionNode.stats.sectionInfo.name );
+ if( !rootName.empty() )
+ name = rootName + '/' + name;
+
+ if( !sectionNode.assertions.empty() ||
+ !sectionNode.stdOut.empty() ||
+ !sectionNode.stdErr.empty() ) {
+ XmlWriter::ScopedElement e = xml.scopedElement( "testcase" );
+ if( className.empty() ) {
+ xml.writeAttribute( "classname", name );
+ xml.writeAttribute( "name", "root" );
+ }
+ else {
+ xml.writeAttribute( "classname", className );
+ xml.writeAttribute( "name", name );
+ }
+ xml.writeAttribute( "time", ::Catch::Detail::stringify( sectionNode.stats.durationInSeconds ) );
+
+ writeAssertions( sectionNode );
+
+ if( !sectionNode.stdOut.empty() )
+ xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false );
+ if( !sectionNode.stdErr.empty() )
+ xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false );
+ }
+ for( auto const& childNode : sectionNode.childSections )
+ if( className.empty() )
+ writeSection( name, "", *childNode );
+ else
+ writeSection( className, name, *childNode );
+ }
+
+ void JunitReporter::writeAssertions( SectionNode const& sectionNode ) {
+ for( auto const& assertion : sectionNode.assertions )
+ writeAssertion( assertion );
+ }
+
+ void JunitReporter::writeAssertion( AssertionStats const& stats ) {
+ AssertionResult const& result = stats.assertionResult;
+ if( !result.isOk() ) {
+ std::string elementName;
+ switch( result.getResultType() ) {
+ case ResultWas::ThrewException:
+ case ResultWas::FatalErrorCondition:
+ elementName = "error";
+ break;
+ case ResultWas::ExplicitFailure:
+ elementName = "failure";
+ break;
+ case ResultWas::ExpressionFailed:
+ elementName = "failure";
+ break;
+ case ResultWas::DidntThrowException:
+ elementName = "failure";
+ break;
+
+ // We should never see these here:
+ case ResultWas::Info:
+ case ResultWas::Warning:
+ case ResultWas::Ok:
+ case ResultWas::Unknown:
+ case ResultWas::FailureBit:
+ case ResultWas::Exception:
+ elementName = "internalError";
+ break;
+ }
+
+ XmlWriter::ScopedElement e = xml.scopedElement( elementName );
+
+ xml.writeAttribute( "message", result.getExpandedExpression() );
+ xml.writeAttribute( "type", result.getTestMacroName() );
+
+ ReusableStringStream rss;
+ if( !result.getMessage().empty() )
+ rss << result.getMessage() << '\n';
+ for( auto const& msg : stats.infoMessages )
+ if( msg.type == ResultWas::Info )
+ rss << msg.message << '\n';
+
+ rss << "at " << result.getSourceInfo();
+ xml.writeText( rss.str(), false );
+ }
+ }
+
+ CATCH_REGISTER_REPORTER( "junit", JunitReporter )
+
+} // end namespace Catch
+// end catch_reporter_junit.cpp
+// start catch_reporter_listening.cpp
+
+#include <cassert>
+
+namespace Catch {
+
+ ListeningReporter::ListeningReporter() {
+ // We will assume that listeners will always want all assertions
+ m_preferences.shouldReportAllAssertions = true;
+ }
+
+ void ListeningReporter::addListener( IStreamingReporterPtr&& listener ) {
+ m_listeners.push_back( std::move( listener ) );
+ }
+
+ void ListeningReporter::addReporter(IStreamingReporterPtr&& reporter) {
+ assert(!m_reporter && "Listening reporter can wrap only 1 real reporter");
+ m_reporter = std::move( reporter );
+ m_preferences.shouldRedirectStdOut = m_reporter->getPreferences().shouldRedirectStdOut;
+ }
+
+ ReporterPreferences ListeningReporter::getPreferences() const {
+ return m_preferences;
+ }
+
+ std::set<Verbosity> ListeningReporter::getSupportedVerbosities() {
+ return std::set<Verbosity>{ };
+ }
+
+ void ListeningReporter::noMatchingTestCases( std::string const& spec ) {
+ for ( auto const& listener : m_listeners ) {
+ listener->noMatchingTestCases( spec );
+ }
+ m_reporter->noMatchingTestCases( spec );
+ }
+
+ void ListeningReporter::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) {
+ for ( auto const& listener : m_listeners ) {
+ listener->benchmarkStarting( benchmarkInfo );
+ }
+ m_reporter->benchmarkStarting( benchmarkInfo );
+ }
+ void ListeningReporter::benchmarkEnded( BenchmarkStats const& benchmarkStats ) {
+ for ( auto const& listener : m_listeners ) {
+ listener->benchmarkEnded( benchmarkStats );
+ }
+ m_reporter->benchmarkEnded( benchmarkStats );
+ }
+
+ void ListeningReporter::testRunStarting( TestRunInfo const& testRunInfo ) {
+ for ( auto const& listener : m_listeners ) {
+ listener->testRunStarting( testRunInfo );
+ }
+ m_reporter->testRunStarting( testRunInfo );
+ }
+
+ void ListeningReporter::testGroupStarting( GroupInfo const& groupInfo ) {
+ for ( auto const& listener : m_listeners ) {
+ listener->testGroupStarting( groupInfo );
+ }
+ m_reporter->testGroupStarting( groupInfo );
+ }
+
+ void ListeningReporter::testCaseStarting( TestCaseInfo const& testInfo ) {
+ for ( auto const& listener : m_listeners ) {
+ listener->testCaseStarting( testInfo );
+ }
+ m_reporter->testCaseStarting( testInfo );
+ }
+
+ void ListeningReporter::sectionStarting( SectionInfo const& sectionInfo ) {
+ for ( auto const& listener : m_listeners ) {
+ listener->sectionStarting( sectionInfo );
+ }
+ m_reporter->sectionStarting( sectionInfo );
+ }
+
+ void ListeningReporter::assertionStarting( AssertionInfo const& assertionInfo ) {
+ for ( auto const& listener : m_listeners ) {
+ listener->assertionStarting( assertionInfo );
+ }
+ m_reporter->assertionStarting( assertionInfo );
+ }
+
+ // The return value indicates if the messages buffer should be cleared:
+ bool ListeningReporter::assertionEnded( AssertionStats const& assertionStats ) {
+ for( auto const& listener : m_listeners ) {
+ static_cast<void>( listener->assertionEnded( assertionStats ) );
+ }
+ return m_reporter->assertionEnded( assertionStats );
+ }
+
+ void ListeningReporter::sectionEnded( SectionStats const& sectionStats ) {
+ for ( auto const& listener : m_listeners ) {
+ listener->sectionEnded( sectionStats );
+ }
+ m_reporter->sectionEnded( sectionStats );
+ }
+
+ void ListeningReporter::testCaseEnded( TestCaseStats const& testCaseStats ) {
+ for ( auto const& listener : m_listeners ) {
+ listener->testCaseEnded( testCaseStats );
+ }
+ m_reporter->testCaseEnded( testCaseStats );
+ }
+
+ void ListeningReporter::testGroupEnded( TestGroupStats const& testGroupStats ) {
+ for ( auto const& listener : m_listeners ) {
+ listener->testGroupEnded( testGroupStats );
+ }
+ m_reporter->testGroupEnded( testGroupStats );
+ }
+
+ void ListeningReporter::testRunEnded( TestRunStats const& testRunStats ) {
+ for ( auto const& listener : m_listeners ) {
+ listener->testRunEnded( testRunStats );
+ }
+ m_reporter->testRunEnded( testRunStats );
+ }
+
+ void ListeningReporter::skipTest( TestCaseInfo const& testInfo ) {
+ for ( auto const& listener : m_listeners ) {
+ listener->skipTest( testInfo );
+ }
+ m_reporter->skipTest( testInfo );
+ }
+
+ bool ListeningReporter::isMulti() const {
+ return true;
+ }
+
+} // end namespace Catch
+// end catch_reporter_listening.cpp
+// start catch_reporter_xml.cpp
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch
+ // Note that 4062 (not all labels are handled
+ // and default is missing) is enabled
+#endif
+
+namespace Catch {
+ XmlReporter::XmlReporter( ReporterConfig const& _config )
+ : StreamingReporterBase( _config ),
+ m_xml(_config.stream())
+ {
+ m_reporterPrefs.shouldRedirectStdOut = true;
+ m_reporterPrefs.shouldReportAllAssertions = true;
+ }
+
+ XmlReporter::~XmlReporter() = default;
+
+ std::string XmlReporter::getDescription() {
+ return "Reports test results as an XML document";
+ }
+
+ std::string XmlReporter::getStylesheetRef() const {
+ return std::string();
+ }
+
+ void XmlReporter::writeSourceInfo( SourceLineInfo const& sourceInfo ) {
+ m_xml
+ .writeAttribute( "filename", sourceInfo.file )
+ .writeAttribute( "line", sourceInfo.line );
+ }
+
+ void XmlReporter::noMatchingTestCases( std::string const& s ) {
+ StreamingReporterBase::noMatchingTestCases( s );
+ }
+
+ void XmlReporter::testRunStarting( TestRunInfo const& testInfo ) {
+ StreamingReporterBase::testRunStarting( testInfo );
+ std::string stylesheetRef = getStylesheetRef();
+ if( !stylesheetRef.empty() )
+ m_xml.writeStylesheetRef( stylesheetRef );
+ m_xml.startElement( "Catch" );
+ if( !m_config->name().empty() )
+ m_xml.writeAttribute( "name", m_config->name() );
+ }
+
+ void XmlReporter::testGroupStarting( GroupInfo const& groupInfo ) {
+ StreamingReporterBase::testGroupStarting( groupInfo );
+ m_xml.startElement( "Group" )
+ .writeAttribute( "name", groupInfo.name );
+ }
+
+ void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) {
+ StreamingReporterBase::testCaseStarting(testInfo);
+ m_xml.startElement( "TestCase" )
+ .writeAttribute( "name", trim( testInfo.name ) )
+ .writeAttribute( "description", testInfo.description )
+ .writeAttribute( "tags", testInfo.tagsAsString() );
+
+ writeSourceInfo( testInfo.lineInfo );
+
+ if ( m_config->showDurations() == ShowDurations::Always )
+ m_testCaseTimer.start();
+ m_xml.ensureTagClosed();
+ }
+
+ void XmlReporter::sectionStarting( SectionInfo const& sectionInfo ) {
+ StreamingReporterBase::sectionStarting( sectionInfo );
+ if( m_sectionDepth++ > 0 ) {
+ m_xml.startElement( "Section" )
+ .writeAttribute( "name", trim( sectionInfo.name ) );
+ writeSourceInfo( sectionInfo.lineInfo );
+ m_xml.ensureTagClosed();
+ }
+ }
+
+ void XmlReporter::assertionStarting( AssertionInfo const& ) { }
+
+ bool XmlReporter::assertionEnded( AssertionStats const& assertionStats ) {
+
+ AssertionResult const& result = assertionStats.assertionResult;
+
+ bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();
+
+ if( includeResults || result.getResultType() == ResultWas::Warning ) {
+ // Print any info messages in <Info> tags.
+ for( auto const& msg : assertionStats.infoMessages ) {
+ if( msg.type == ResultWas::Info && includeResults ) {
+ m_xml.scopedElement( "Info" )
+ .writeText( msg.message );
+ } else if ( msg.type == ResultWas::Warning ) {
+ m_xml.scopedElement( "Warning" )
+ .writeText( msg.message );
+ }
+ }
+ }
+
+ // Drop out if result was successful but we're not printing them.
+ if( !includeResults && result.getResultType() != ResultWas::Warning )
+ return true;
+
+ // Print the expression if there is one.
+ if( result.hasExpression() ) {
+ m_xml.startElement( "Expression" )
+ .writeAttribute( "success", result.succeeded() )
+ .writeAttribute( "type", result.getTestMacroName() );
+
+ writeSourceInfo( result.getSourceInfo() );
+
+ m_xml.scopedElement( "Original" )
+ .writeText( result.getExpression() );
+ m_xml.scopedElement( "Expanded" )
+ .writeText( result.getExpandedExpression() );
+ }
+
+ // And... Print a result applicable to each result type.
+ switch( result.getResultType() ) {
+ case ResultWas::ThrewException:
+ m_xml.startElement( "Exception" );
+ writeSourceInfo( result.getSourceInfo() );
+ m_xml.writeText( result.getMessage() );
+ m_xml.endElement();
+ break;
+ case ResultWas::FatalErrorCondition:
+ m_xml.startElement( "FatalErrorCondition" );
+ writeSourceInfo( result.getSourceInfo() );
+ m_xml.writeText( result.getMessage() );
+ m_xml.endElement();
+ break;
+ case ResultWas::Info:
+ m_xml.scopedElement( "Info" )
+ .writeText( result.getMessage() );
+ break;
+ case ResultWas::Warning:
+ // Warning will already have been written
+ break;
+ case ResultWas::ExplicitFailure:
+ m_xml.startElement( "Failure" );
+ writeSourceInfo( result.getSourceInfo() );
+ m_xml.writeText( result.getMessage() );
+ m_xml.endElement();
+ break;
+ default:
+ break;
+ }
+
+ if( result.hasExpression() )
+ m_xml.endElement();
+
+ return true;
+ }
+
+ void XmlReporter::sectionEnded( SectionStats const& sectionStats ) {
+ StreamingReporterBase::sectionEnded( sectionStats );
+ if( --m_sectionDepth > 0 ) {
+ XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" );
+ e.writeAttribute( "successes", sectionStats.assertions.passed );
+ e.writeAttribute( "failures", sectionStats.assertions.failed );
+ e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk );
+
+ if ( m_config->showDurations() == ShowDurations::Always )
+ e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds );
+
+ m_xml.endElement();
+ }
+ }
+
+ void XmlReporter::testCaseEnded( TestCaseStats const& testCaseStats ) {
+ StreamingReporterBase::testCaseEnded( testCaseStats );
+ XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" );
+ e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() );
+
+ if ( m_config->showDurations() == ShowDurations::Always )
+ e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() );
+
+ if( !testCaseStats.stdOut.empty() )
+ m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false );
+ if( !testCaseStats.stdErr.empty() )
+ m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false );
+
+ m_xml.endElement();
+ }
+
+ void XmlReporter::testGroupEnded( TestGroupStats const& testGroupStats ) {
+ StreamingReporterBase::testGroupEnded( testGroupStats );
+ // TODO: Check testGroupStats.aborting and act accordingly.
+ m_xml.scopedElement( "OverallResults" )
+ .writeAttribute( "successes", testGroupStats.totals.assertions.passed )
+ .writeAttribute( "failures", testGroupStats.totals.assertions.failed )
+ .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk );
+ m_xml.endElement();
+ }
+
+ void XmlReporter::testRunEnded( TestRunStats const& testRunStats ) {
+ StreamingReporterBase::testRunEnded( testRunStats );
+ m_xml.scopedElement( "OverallResults" )
+ .writeAttribute( "successes", testRunStats.totals.assertions.passed )
+ .writeAttribute( "failures", testRunStats.totals.assertions.failed )
+ .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk );
+ m_xml.endElement();
+ }
+
+ CATCH_REGISTER_REPORTER( "xml", XmlReporter )
+
+} // end namespace Catch
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+// end catch_reporter_xml.cpp
+
+namespace Catch {
+ LeakDetector leakDetector;
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+// end catch_impl.hpp
+#endif
+
+#ifdef CATCH_CONFIG_MAIN
+// start catch_default_main.hpp
+
+#ifndef __OBJC__
+
+#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)
+// Standard C/C++ Win32 Unicode wmain entry point
+extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) {
+#else
+// Standard C/C++ main entry point
+int main (int argc, char * argv[]) {
+#endif
+
+ return Catch::Session().run( argc, argv );
+}
+
+#else // __OBJC__
+
+// Objective-C entry point
+int main (int argc, char * const argv[]) {
+#if !CATCH_ARC_ENABLED
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+#endif
+
+ Catch::registerTestMethods();
+ int result = Catch::Session().run( argc, (char**)argv );
+
+#if !CATCH_ARC_ENABLED
+ [pool drain];
+#endif
+
+ return result;
+}
+
+#endif // __OBJC__
+
+// end catch_default_main.hpp
+#endif
+
+#if !defined(CATCH_CONFIG_IMPL_ONLY)
+
+#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED
+# undef CLARA_CONFIG_MAIN
+#endif
+
+#if !defined(CATCH_CONFIG_DISABLE)
+//////
+// If this config identifier is defined then all CATCH macros are prefixed with CATCH_
+#ifdef CATCH_CONFIG_PREFIX_ALL
+
+#define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ )
+#define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
+
+#define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", __VA_ARGS__ )
+#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
+#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
+#define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr )
+#endif// CATCH_CONFIG_DISABLE_MATCHERS
+#define CATCH_REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ )
+
+#define CATCH_CHECK( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+#define CATCH_CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
+#define CATCH_CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+#define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+#define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
+
+#define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", __VA_ARGS__ )
+#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
+#define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
+#endif // CATCH_CONFIG_DISABLE_MATCHERS
+#define CATCH_CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+
+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
+#define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )
+
+#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
+#endif // CATCH_CONFIG_DISABLE_MATCHERS
+
+#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
+#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
+#define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE",__VA_ARGS__ )
+
+#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
+#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
+#define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
+#define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
+#define CATCH_DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )
+#define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
+#define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+#define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+
+#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE()
+
+// "BDD-style" convenience wrappers
+#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ )
+#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
+#define CATCH_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc )
+#define CATCH_AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc )
+#define CATCH_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc )
+#define CATCH_AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc )
+#define CATCH_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
+#define CATCH_AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
+
+// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
+#else
+
+#define REQUIRE( ... ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ )
+#define REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
+
+#define REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ )
+#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
+#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
+#define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr )
+#endif // CATCH_CONFIG_DISABLE_MATCHERS
+#define REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ )
+
+#define CHECK( ... ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+#define CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
+#define CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+#define CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+#define CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
+
+#define CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
+#define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
+#endif // CATCH_CONFIG_DISABLE_MATCHERS
+#define CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+
+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
+#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )
+
+#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
+#endif // CATCH_CONFIG_DISABLE_MATCHERS
+
+#define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
+#define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
+#define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE",__VA_ARGS__ )
+
+#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
+#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
+#define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
+#define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
+#define DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )
+#define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
+#define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+#define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE()
+
+#endif
+
+#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature )
+
+// "BDD-style" convenience wrappers
+#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ )
+#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
+
+#define GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc )
+#define AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc )
+#define WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc )
+#define AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc )
+#define THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
+#define AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
+
+using Catch::Detail::Approx;
+
+#else // CATCH_CONFIG_DISABLE
+
+//////
+// If this config identifier is defined then all CATCH macros are prefixed with CATCH_
+#ifdef CATCH_CONFIG_PREFIX_ALL
+
+#define CATCH_REQUIRE( ... ) (void)(0)
+#define CATCH_REQUIRE_FALSE( ... ) (void)(0)
+
+#define CATCH_REQUIRE_THROWS( ... ) (void)(0)
+#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0)
+#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) (void)(0)
+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
+#define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)
+#endif// CATCH_CONFIG_DISABLE_MATCHERS
+#define CATCH_REQUIRE_NOTHROW( ... ) (void)(0)
+
+#define CATCH_CHECK( ... ) (void)(0)
+#define CATCH_CHECK_FALSE( ... ) (void)(0)
+#define CATCH_CHECKED_IF( ... ) if (__VA_ARGS__)
+#define CATCH_CHECKED_ELSE( ... ) if (!(__VA_ARGS__))
+#define CATCH_CHECK_NOFAIL( ... ) (void)(0)
+
+#define CATCH_CHECK_THROWS( ... ) (void)(0)
+#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) (void)(0)
+#define CATCH_CHECK_THROWS_WITH( expr, matcher ) (void)(0)
+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
+#define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)
+#endif // CATCH_CONFIG_DISABLE_MATCHERS
+#define CATCH_CHECK_NOTHROW( ... ) (void)(0)
+
+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
+#define CATCH_CHECK_THAT( arg, matcher ) (void)(0)
+
+#define CATCH_REQUIRE_THAT( arg, matcher ) (void)(0)
+#endif // CATCH_CONFIG_DISABLE_MATCHERS
+
+#define CATCH_INFO( msg ) (void)(0)
+#define CATCH_WARN( msg ) (void)(0)
+#define CATCH_CAPTURE( msg ) (void)(0)
+
+#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
+#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
+#define CATCH_METHOD_AS_TEST_CASE( method, ... )
+#define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0)
+#define CATCH_SECTION( ... )
+#define CATCH_DYNAMIC_SECTION( ... )
+#define CATCH_FAIL( ... ) (void)(0)
+#define CATCH_FAIL_CHECK( ... ) (void)(0)
+#define CATCH_SUCCEED( ... ) (void)(0)
+
+#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
+
+// "BDD-style" convenience wrappers
+#define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
+#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className )
+#define CATCH_GIVEN( desc )
+#define CATCH_AND_GIVEN( desc )
+#define CATCH_WHEN( desc )
+#define CATCH_AND_WHEN( desc )
+#define CATCH_THEN( desc )
+#define CATCH_AND_THEN( desc )
+
+// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
+#else
+
+#define REQUIRE( ... ) (void)(0)
+#define REQUIRE_FALSE( ... ) (void)(0)
+
+#define REQUIRE_THROWS( ... ) (void)(0)
+#define REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0)
+#define REQUIRE_THROWS_WITH( expr, matcher ) (void)(0)
+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
+#define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)
+#endif // CATCH_CONFIG_DISABLE_MATCHERS
+#define REQUIRE_NOTHROW( ... ) (void)(0)
+
+#define CHECK( ... ) (void)(0)
+#define CHECK_FALSE( ... ) (void)(0)
+#define CHECKED_IF( ... ) if (__VA_ARGS__)
+#define CHECKED_ELSE( ... ) if (!(__VA_ARGS__))
+#define CHECK_NOFAIL( ... ) (void)(0)
+
+#define CHECK_THROWS( ... ) (void)(0)
+#define CHECK_THROWS_AS( expr, exceptionType ) (void)(0)
+#define CHECK_THROWS_WITH( expr, matcher ) (void)(0)
+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
+#define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)
+#endif // CATCH_CONFIG_DISABLE_MATCHERS
+#define CHECK_NOTHROW( ... ) (void)(0)
+
+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
+#define CHECK_THAT( arg, matcher ) (void)(0)
+
+#define REQUIRE_THAT( arg, matcher ) (void)(0)
+#endif // CATCH_CONFIG_DISABLE_MATCHERS
+
+#define INFO( msg ) (void)(0)
+#define WARN( msg ) (void)(0)
+#define CAPTURE( msg ) (void)(0)
+
+#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
+#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
+#define METHOD_AS_TEST_CASE( method, ... )
+#define REGISTER_TEST_CASE( Function, ... ) (void)(0)
+#define SECTION( ... )
+#define DYNAMIC_SECTION( ... )
+#define FAIL( ... ) (void)(0)
+#define FAIL_CHECK( ... ) (void)(0)
+#define SUCCEED( ... ) (void)(0)
+#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
+
+#endif
+
+#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
+
+// "BDD-style" convenience wrappers
+#define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) )
+#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className )
+
+#define GIVEN( desc )
+#define AND_GIVEN( desc )
+#define WHEN( desc )
+#define AND_WHEN( desc )
+#define THEN( desc )
+#define AND_THEN( desc )
+
+using Catch::Detail::Approx;
+
+#endif
+
+#endif // ! CATCH_CONFIG_IMPL_ONLY
+
+// start catch_reenable_warnings.h
+
+
+#ifdef __clang__
+# ifdef __ICC // icpc defines the __clang__ macro
+# pragma warning(pop)
+# else
+# pragma clang diagnostic pop
+# endif
+#elif defined __GNUC__
+# pragma GCC diagnostic pop
+#endif
+
+// end catch_reenable_warnings.h
+// end catch.hpp
+#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
+
diff --git a/gulrak-filesystem/test/cmake/ParseAndAddCatchTests.cmake b/gulrak-filesystem/test/cmake/ParseAndAddCatchTests.cmake
new file mode 100644
index 0000000..5e89cb7
--- /dev/null
+++ b/gulrak-filesystem/test/cmake/ParseAndAddCatchTests.cmake
@@ -0,0 +1,230 @@
+#==================================================================================================#
+# supported macros #
+# - TEST_CASE, #
+# - SCENARIO, #
+# - TEST_CASE_METHOD, #
+# - CATCH_TEST_CASE, #
+# - CATCH_SCENARIO, #
+# - CATCH_TEST_CASE_METHOD. #
+# #
+# Usage #
+# 1. make sure this module is in the path or add this otherwise: #
+# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake.modules/") #
+# 2. make sure that you've enabled testing option for the project by the call: #
+# enable_testing() #
+# 3. add the lines to the script for testing target (sample CMakeLists.txt): #
+# project(testing_target) #
+# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake.modules/") #
+# enable_testing() #
+# #
+# find_path(CATCH_INCLUDE_DIR "catch.hpp") #
+# include_directories(${INCLUDE_DIRECTORIES} ${CATCH_INCLUDE_DIR}) #
+# #
+# file(GLOB SOURCE_FILES "*.cpp") #
+# add_executable(${PROJECT_NAME} ${SOURCE_FILES}) #
+# #
+# include(ParseAndAddCatchTests) #
+# ParseAndAddCatchTests(${PROJECT_NAME}) #
+# #
+# The following variables affect the behavior of the script: #
+# #
+# PARSE_CATCH_TESTS_VERBOSE (Default OFF) #
+# -- enables debug messages #
+# PARSE_CATCH_TESTS_NO_HIDDEN_TESTS (Default OFF) #
+# -- excludes tests marked with [!hide], [.] or [.foo] tags #
+# PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME (Default ON) #
+# -- adds fixture class name to the test name #
+# PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME (Default ON) #
+# -- adds cmake target name to the test name #
+# PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS (Default OFF) #
+# -- causes CMake to rerun when file with tests changes so that new tests will be discovered #
+# #
+# One can also set (locally) the optional variable OptionalCatchTestLauncher to precise the way #
+# a test should be run. For instance to use test MPI, one can write #
+# set(OptionalCatchTestLauncher ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${NUMPROC}) #
+# just before calling this ParseAndAddCatchTests function #
+# #
+# The AdditionalCatchParameters optional variable can be used to pass extra argument to the test #
+# command. For example, to include successful tests in the output, one can write #
+# set(AdditionalCatchParameters --success) #
+# #
+# After the script, the ParseAndAddCatchTests_TESTS property for the target, and for each source #
+# file in the target is set, and contains the list of the tests extracted from that target, or #
+# from that file. This is useful, for example to add further labels or properties to the tests. #
+# #
+#==================================================================================================#
+
+if (CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.8)
+ message(FATAL_ERROR "ParseAndAddCatchTests requires CMake 2.8.8 or newer")
+endif()
+
+option(PARSE_CATCH_TESTS_VERBOSE "Print Catch to CTest parser debug messages" OFF)
+option(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS "Exclude tests with [!hide], [.] or [.foo] tags" OFF)
+option(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME "Add fixture class name to the test name" ON)
+option(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME "Add target name to the test name" ON)
+option(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS "Add test file to CMAKE_CONFIGURE_DEPENDS property" OFF)
+
+function(ParseAndAddCatchTests_PrintDebugMessage)
+ if(PARSE_CATCH_TESTS_VERBOSE)
+ message(STATUS "ParseAndAddCatchTests: ${ARGV}")
+ endif()
+endfunction()
+
+# This removes the contents between
+# - block comments (i.e. /* ... */)
+# - full line comments (i.e. // ... )
+# contents have been read into '${CppCode}'.
+# !keep partial line comments
+function(ParseAndAddCatchTests_RemoveComments CppCode)
+ string(ASCII 2 CMakeBeginBlockComment)
+ string(ASCII 3 CMakeEndBlockComment)
+ string(REGEX REPLACE "/\\*" "${CMakeBeginBlockComment}" ${CppCode} "${${CppCode}}")
+ string(REGEX REPLACE "\\*/" "${CMakeEndBlockComment}" ${CppCode} "${${CppCode}}")
+ string(REGEX REPLACE "${CMakeBeginBlockComment}[^${CMakeEndBlockComment}]*${CMakeEndBlockComment}" "" ${CppCode} "${${CppCode}}")
+ string(REGEX REPLACE "\n[ \t]*//+[^\n]+" "\n" ${CppCode} "${${CppCode}}")
+
+ set(${CppCode} "${${CppCode}}" PARENT_SCOPE)
+endfunction()
+
+# Worker function
+function(ParseAndAddCatchTests_ParseFile SourceFile TestTarget)
+ # If SourceFile is an object library, do not scan it (as it is not a file). Exit without giving a warning about a missing file.
+ if(SourceFile MATCHES "\\\$<TARGET_OBJECTS:.+>")
+ ParseAndAddCatchTests_PrintDebugMessage("Detected OBJECT library: ${SourceFile} this will not be scanned for tests.")
+ return()
+ endif()
+ # According to CMake docs EXISTS behavior is well-defined only for full paths.
+ get_filename_component(SourceFile ${SourceFile} ABSOLUTE)
+ if(NOT EXISTS ${SourceFile})
+ message(WARNING "Cannot find source file: ${SourceFile}")
+ return()
+ endif()
+ ParseAndAddCatchTests_PrintDebugMessage("parsing ${SourceFile}")
+ file(STRINGS ${SourceFile} Contents NEWLINE_CONSUME)
+
+ # Remove block and fullline comments
+ ParseAndAddCatchTests_RemoveComments(Contents)
+
+ # Find definition of test names
+ string(REGEX MATCHALL "[ \t]*(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^\)]+\\)+[ \t\n]*{+[ \t]*(//[^\n]*[Tt][Ii][Mm][Ee][Oo][Uu][Tt][ \t]*[0-9]+)*" Tests "${Contents}")
+
+ if(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS AND Tests)
+ ParseAndAddCatchTests_PrintDebugMessage("Adding ${SourceFile} to CMAKE_CONFIGURE_DEPENDS property")
+ set_property(
+ DIRECTORY
+ APPEND
+ PROPERTY CMAKE_CONFIGURE_DEPENDS ${SourceFile}
+ )
+ endif()
+
+ foreach(TestName ${Tests})
+ # Strip newlines
+ string(REGEX REPLACE "\\\\\n|\n" "" TestName "${TestName}")
+
+ # Get test type and fixture if applicable
+ string(REGEX MATCH "(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^,^\"]*" TestTypeAndFixture "${TestName}")
+ string(REGEX MATCH "(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)" TestType "${TestTypeAndFixture}")
+ string(REGEX REPLACE "${TestType}\\([ \t]*" "" TestFixture "${TestTypeAndFixture}")
+
+ # Get string parts of test definition
+ string(REGEX MATCHALL "\"+([^\\^\"]|\\\\\")+\"+" TestStrings "${TestName}")
+
+ # Strip wrapping quotation marks
+ string(REGEX REPLACE "^\"(.*)\"$" "\\1" TestStrings "${TestStrings}")
+ string(REPLACE "\";\"" ";" TestStrings "${TestStrings}")
+
+ # Validate that a test name and tags have been provided
+ list(LENGTH TestStrings TestStringsLength)
+ if(TestStringsLength GREATER 2 OR TestStringsLength LESS 1)
+ message(FATAL_ERROR "You must provide a valid test name and tags for all tests in ${SourceFile}")
+ endif()
+
+ # Assign name and tags
+ list(GET TestStrings 0 Name)
+ if("${TestType}" STREQUAL "SCENARIO")
+ set(Name "Scenario: ${Name}")
+ endif()
+ if(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME AND "${TestType}" MATCHES "(CATCH_)?TEST_CASE_METHOD" AND TestFixture )
+ set(CTestName "${TestFixture}:${Name}")
+ else()
+ set(CTestName "${Name}")
+ endif()
+ if(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME)
+ set(CTestName "${TestTarget}:${CTestName}")
+ endif()
+ # add target to labels to enable running all tests added from this target
+ set(Labels ${TestTarget})
+ if(TestStringsLength EQUAL 2)
+ list(GET TestStrings 1 Tags)
+ string(TOLOWER "${Tags}" Tags)
+ # remove target from labels if the test is hidden
+ if("${Tags}" MATCHES ".*\\[!?(hide|\\.)\\].*")
+ list(REMOVE_ITEM Labels ${TestTarget})
+ endif()
+ string(REPLACE "]" ";" Tags "${Tags}")
+ string(REPLACE "[" "" Tags "${Tags}")
+ else()
+ # unset tags variable from previous loop
+ unset(Tags)
+ endif()
+
+ list(APPEND Labels ${Tags})
+
+ set(HiddenTagFound OFF)
+ foreach(label ${Labels})
+ string(REGEX MATCH "^!hide|^\\." result ${label})
+ if(result)
+ set(HiddenTagFound ON)
+ break()
+ endif(result)
+ endforeach(label)
+ if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound} AND ${CMAKE_VERSION} VERSION_LESS "3.9")
+ ParseAndAddCatchTests_PrintDebugMessage("Skipping test \"${CTestName}\" as it has [!hide], [.] or [.foo] label")
+ else()
+ ParseAndAddCatchTests_PrintDebugMessage("Adding test \"${CTestName}\"")
+ if(Labels)
+ ParseAndAddCatchTests_PrintDebugMessage("Setting labels to ${Labels}")
+ endif()
+
+ # Escape commas in the test spec
+ string(REPLACE "," "\\," Name ${Name})
+
+ # Work around CMake 3.18.0 change in `add_test()`, before the escaped quotes were neccessary,
+ # only with CMake 3.18.0 the escaped double quotes confuse the call. This change is reverted in 3.18.1
+ if(NOT ${CMAKE_VERSION} VERSION_EQUAL "3.18")
+ set(CTestName "\"${CTestName}\"")
+ endif()
+ # Add the test and set its properties
+ add_test(NAME "${CTestName}" COMMAND ${OptionalCatchTestLauncher} $<TARGET_FILE:${TestTarget}> ${Name} ${AdditionalCatchParameters})
+ # Old CMake versions do not document VERSION_GREATER_EQUAL, so we use VERSION_GREATER with 3.8 instead
+ if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound} AND ${CMAKE_VERSION} VERSION_GREATER "3.8")
+ ParseAndAddCatchTests_PrintDebugMessage("Setting DISABLED test property")
+ set_tests_properties("${CTestName}" PROPERTIES DISABLED ON)
+ else()
+ set_tests_properties("${CTestName}" PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran"
+ LABELS "${Labels}")
+ endif()
+ set_property(
+ TARGET ${TestTarget}
+ APPEND
+ PROPERTY ParseAndAddCatchTests_TESTS "${CTestName}")
+ set_property(
+ SOURCE ${SourceFile}
+ APPEND
+ PROPERTY ParseAndAddCatchTests_TESTS "${CTestName}")
+ endif()
+
+
+ endforeach()
+endfunction()
+
+# entry point
+function(ParseAndAddCatchTests TestTarget)
+ ParseAndAddCatchTests_PrintDebugMessage("Started parsing ${TestTarget}")
+ get_target_property(SourceFiles ${TestTarget} SOURCES)
+ ParseAndAddCatchTests_PrintDebugMessage("Found the following sources: ${SourceFiles}")
+ foreach(SourceFile ${SourceFiles})
+ ParseAndAddCatchTests_ParseFile(${SourceFile} ${TestTarget})
+ endforeach()
+ ParseAndAddCatchTests_PrintDebugMessage("Finished parsing ${TestTarget}")
+endfunction()
diff --git a/gulrak-filesystem/test/exception.cpp b/gulrak-filesystem/test/exception.cpp
new file mode 100644
index 0000000..8d8b745
--- /dev/null
+++ b/gulrak-filesystem/test/exception.cpp
@@ -0,0 +1,5 @@
+#include <ghc/filesystem.hpp>
+
+int main() {
+ return 0;
+}
diff --git a/gulrak-filesystem/test/filesystem_test.cpp b/gulrak-filesystem/test/filesystem_test.cpp
new file mode 100644
index 0000000..7fdd0a5
--- /dev/null
+++ b/gulrak-filesystem/test/filesystem_test.cpp
@@ -0,0 +1,2956 @@
+//---------------------------------------------------------------------------------------
+//
+// Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+//---------------------------------------------------------------------------------------
+#include <algorithm>
+#include <cstdio>
+#include <cstring>
+#include <fstream>
+#include <functional>
+#include <iomanip>
+#include <iostream>
+#include <map>
+#include <random>
+#include <set>
+#include <sstream>
+#include <thread>
+
+#if (defined(WIN32) || defined(_WIN32)) && !defined(__GNUC__)
+#define NOMINMAX 1
+#endif
+
+#ifdef USE_STD_FS
+#include <filesystem>
+namespace fs {
+using namespace std::filesystem;
+using ifstream = std::ifstream;
+using ofstream = std::ofstream;
+using fstream = std::fstream;
+} // namespace fs
+#ifdef __GNUC__
+#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
+#endif
+#ifdef _MSC_VER
+#define IS_WCHAR_PATH
+#endif
+#ifdef WIN32
+#define GHC_OS_WINDOWS
+#endif
+#else
+#ifdef GHC_FILESYSTEM_FWD_TEST
+#include <ghc/fs_fwd.hpp>
+#else
+#include <ghc/filesystem.hpp>
+#endif
+namespace fs {
+using namespace ghc::filesystem;
+using ifstream = ghc::filesystem::ifstream;
+using ofstream = ghc::filesystem::ofstream;
+using fstream = ghc::filesystem::fstream;
+} // namespace fs
+#endif
+
+#if defined(WIN32) || defined(_WIN32)
+#include <windows.h>
+#else
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+#endif
+
+#ifndef GHC_FILESYSTEM_FWD_TEST
+#define CATCH_CONFIG_MAIN
+#endif
+#include "catch.hpp"
+
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// Behaviour Switches (should match the config in ghc/filesystem.hpp):
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// LWG #2682 disables the since then invalid use of the copy option create_symlinks on directories
+#define TEST_LWG_2682_BEHAVIOUR
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// LWG #2395 makes crate_directory/create_directories not emit an error if there is a regular
+// file with that name, it is superceded by P1164R1, so only activate if really needed
+// #define TEST_LWG_2935_BEHAVIOUR
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// LWG #2937 enforces that fs::equivalent emits an error, if !fs::exists(p1)||!exists(p2)
+#define TEST_LWG_2937_BEHAVIOUR
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+template <typename TP>
+std::time_t to_time_t(TP tp)
+{
+ using namespace std::chrono;
+ auto sctp = time_point_cast<system_clock::duration>(tp - TP::clock::now() + system_clock::now());
+ return system_clock::to_time_t(sctp);
+}
+
+template <typename TP>
+TP from_time_t(std::time_t t)
+{
+ using namespace std::chrono;
+ auto sctp = system_clock::from_time_t(t);
+ auto tp = time_point_cast<typename TP::duration>(sctp - system_clock::now() + TP::clock::now());
+ return tp;
+}
+
+namespace Catch {
+template <>
+struct StringMaker<fs::path>
+{
+ static std::string convert(fs::path const& value) { return '"' + value.string() + '"'; }
+};
+
+template <>
+struct StringMaker<fs::perms>
+{
+ static std::string convert(fs::perms const& value) { return std::to_string(static_cast<unsigned int>(value)); }
+};
+
+template <>
+struct StringMaker<fs::file_status>
+{
+ static std::string convert(fs::file_status const& value) {
+ return std::string("[") + std::to_string(static_cast<unsigned int>(value.type())) + "," + std::to_string(static_cast<unsigned int>(value.permissions())) + "]";
+ }
+};
+
+#ifdef __cpp_lib_char8_t
+template <>
+struct StringMaker<char8_t>
+{
+ static std::string convert(char8_t const& value) { return std::to_string(static_cast<unsigned int>(value)); }
+};
+#endif
+
+template <>
+struct StringMaker<fs::file_time_type>
+{
+ static std::string convert(fs::file_time_type const& value)
+ {
+ std::time_t t = to_time_t(value);
+ std::tm* ptm = std::localtime(&t);
+ std::ostringstream os;
+ if (ptm) {
+ std::tm ttm = *ptm;
+ os << std::put_time(&ttm, "%Y-%m-%d %H:%M:%S");
+ }
+ else {
+ os << "(invalid-time)";
+ }
+ return os.str();
+ }
+};
+} // namespace Catch
+
+enum class TempOpt { none, change_path };
+class TemporaryDirectory
+{
+public:
+ TemporaryDirectory(TempOpt opt = TempOpt::none)
+ {
+ static auto seed = std::chrono::high_resolution_clock::now().time_since_epoch().count();
+ static auto rng = std::bind(std::uniform_int_distribution<int>(0, 35), std::mt19937(static_cast<unsigned int>(seed) ^ static_cast<unsigned int>(reinterpret_cast<ptrdiff_t>(&opt))));
+ std::string filename;
+ do {
+ filename = "test_";
+ for (int i = 0; i < 8; ++i) {
+ filename += "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[rng()];
+ }
+ _path = fs::canonical(fs::temp_directory_path()) / filename;
+ } while (fs::exists(_path));
+ fs::create_directories(_path);
+ if (opt == TempOpt::change_path) {
+ _orig_dir = fs::current_path();
+ fs::current_path(_path);
+ }
+ }
+
+ ~TemporaryDirectory()
+ {
+ if (!_orig_dir.empty()) {
+ fs::current_path(_orig_dir);
+ }
+ fs::remove_all(_path);
+ }
+
+ const fs::path& path() const { return _path; }
+
+private:
+ fs::path _path;
+ fs::path _orig_dir;
+};
+
+static void generateFile(const fs::path& pathname, int withSize = -1)
+{
+ fs::ofstream outfile(pathname);
+ if (withSize < 0) {
+ outfile << "Hello world!" << std::endl;
+ }
+ else {
+ outfile << std::string(size_t(withSize), '*');
+ }
+}
+
+#ifdef GHC_OS_WINDOWS
+inline bool isWow64Proc()
+{
+ typedef BOOL(WINAPI * IsWow64Process_t)(HANDLE, PBOOL);
+ BOOL bIsWow64 = FALSE;
+ auto fnIsWow64Process = (IsWow64Process_t)GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process");
+ if (NULL != fnIsWow64Process) {
+ if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64)) {
+ bIsWow64 = FALSE;
+ }
+ }
+ return bIsWow64 == TRUE;
+}
+
+static bool is_symlink_creation_supported()
+{
+ bool result = true;
+ HKEY key;
+ REGSAM flags = KEY_READ;
+#ifdef _WIN64
+ flags |= KEY_WOW64_64KEY;
+#elif defined(KEY_WOW64_64KEY)
+ if (isWow64Proc()) {
+ flags |= KEY_WOW64_64KEY;
+ }
+ else {
+ flags |= KEY_WOW64_32KEY;
+ }
+#else
+ result = false;
+#endif
+ if (result) {
+ auto err = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\AppModelUnlock", 0, flags, &key);
+ if (err == ERROR_SUCCESS) {
+ DWORD val = 0, size = sizeof(DWORD);
+ err = RegQueryValueExW(key, L"AllowDevelopmentWithoutDevLicense", 0, NULL, reinterpret_cast<LPBYTE>(&val), &size);
+ RegCloseKey(key);
+ if (err != ERROR_SUCCESS) {
+ result = false;
+ }
+ else {
+ result = (val != 0);
+ }
+ }
+ else {
+ result = false;
+ }
+ }
+ if (!result) {
+ std::clog << "Warning: Symlink creation not supported." << std::endl;
+ }
+ return result;
+}
+#else
+static bool is_symlink_creation_supported()
+{
+ return true;
+}
+#endif
+
+static bool has_host_root_name_support()
+{
+ return fs::path("//host").has_root_name();
+}
+
+template <class T>
+class TestAllocator
+{
+public:
+ using value_type = T;
+ using pointer = T*;
+ using const_pointer = const T*;
+ using reference = T&;
+ using const_reference = const T&;
+ using difference_type = ptrdiff_t;
+ using size_type = size_t;
+ TestAllocator() noexcept {}
+ template <class U>
+ TestAllocator(TestAllocator<U> const&) noexcept
+ {
+ }
+ value_type* allocate(std::size_t n) { return static_cast<value_type*>(::operator new(n * sizeof(value_type))); }
+ void deallocate(value_type* p, std::size_t) noexcept { ::operator delete(p); }
+ template<class U>
+ struct rebind {
+ typedef TestAllocator<U> other;
+ };
+};
+
+template <class T, class U>
+bool operator==(TestAllocator<T> const&, TestAllocator<U> const&) noexcept
+{
+ return true;
+}
+
+template <class T, class U>
+bool operator!=(TestAllocator<T> const& x, TestAllocator<U> const& y) noexcept
+{
+ return !(x == y);
+}
+
+TEST_CASE("Temporary Directory", "[fs.test.tempdir]")
+{
+ fs::path tempPath;
+ {
+ TemporaryDirectory t;
+ tempPath = t.path();
+ REQUIRE(fs::exists(fs::path(t.path())));
+ REQUIRE(fs::is_directory(t.path()));
+ }
+ REQUIRE(!fs::exists(tempPath));
+}
+
+#ifdef GHC_FILESYSTEM_VERSION
+TEST_CASE("fs::detail::fromUtf8", "[filesystem][fs.detail.utf8]")
+{
+ CHECK(fs::detail::fromUtf8<std::wstring>("foobar").length() == 6);
+ CHECK(fs::detail::fromUtf8<std::wstring>("foobar") == L"foobar");
+ CHECK(fs::detail::fromUtf8<std::wstring>(u8"föobar").length() == 6);
+ CHECK(fs::detail::fromUtf8<std::wstring>(u8"föobar") == L"föobar");
+
+ CHECK(fs::detail::toUtf8(std::wstring(L"foobar")).length() == 6);
+ CHECK(fs::detail::toUtf8(std::wstring(L"foobar")) == "foobar");
+ CHECK(fs::detail::toUtf8(std::wstring(L"föobar")).length() == 7);
+ //CHECK(fs::detail::toUtf8(std::wstring(L"föobar")) == u8"föobar");
+
+#ifdef GHC_RAISE_UNICODE_ERRORS
+ CHECK_THROWS_AS(fs::detail::fromUtf8<std::u16string>(std::string("\xed\xa0\x80")), fs::filesystem_error);
+ CHECK_THROWS_AS(fs::detail::fromUtf8<std::u16string>(std::string("\xc3")), fs::filesystem_error);
+#else
+ CHECK(std::u16string(2,0xfffd) == fs::detail::fromUtf8<std::u16string>(std::string("\xed\xa0\x80")));
+ CHECK(std::u16string(1,0xfffd) == fs::detail::fromUtf8<std::u16string>(std::string("\xc3")));
+#endif
+}
+
+TEST_CASE("fs::detail::toUtf8", "[filesystem][fs.detail.utf8]")
+{
+ std::string t;
+ CHECK(std::string("\xc3\xa4/\xe2\x82\xac\xf0\x9d\x84\x9e") == fs::detail::toUtf8(std::u16string(u"\u00E4/\u20AC\U0001D11E")));
+#ifdef GHC_RAISE_UNICODE_ERRORS
+ CHECK_THROWS_AS(fs::detail::toUtf8(std::u16string(1, 0xd800)), fs::filesystem_error);
+ CHECK_THROWS_AS(fs::detail::appendUTF8(t, 0x200000), fs::filesystem_error);
+#else
+ CHECK(std::string("\xEF\xBF\xBD") == fs::detail::toUtf8(std::u16string(1, 0xd800)));
+ fs::detail::appendUTF8(t, 0x200000);
+ CHECK(std::string("\xEF\xBF\xBD") == t);
+#endif
+}
+#endif
+
+TEST_CASE("fs.path.generic - path::preferred_separator", "[filesystem][path][fs.path.generic]")
+{
+#ifdef GHC_OS_WINDOWS
+ CHECK(fs::path::preferred_separator == '\\');
+#else
+ CHECK(fs::path::preferred_separator == '/');
+#endif
+}
+
+#ifndef GHC_OS_WINDOWS
+TEST_CASE("fs.path.generic - path(\"//host\").has_root_name()", "[filesystem][path][fs.path.generic]")
+{
+ if (!has_host_root_name_support()) {
+ WARN("This implementation doesn't support path(\"//host\").has_root_name() == true [C++17 30.12.8.1 par. 4] on this platform, tests based on this are skipped. (Should be okay.)");
+ }
+}
+#endif
+
+TEST_CASE("fs.path.construct - path constructors and destructor", "[filesystem][path][fs.path.construct]")
+{
+ CHECK("/usr/local/bin" == fs::path("/usr/local/bin").generic_string());
+ std::string str = "/usr/local/bin";
+#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)
+ std::u8string u8str = u8"/usr/local/bin";
+#endif
+ std::u16string u16str = u"/usr/local/bin";
+ std::u32string u32str = U"/usr/local/bin";
+#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)
+ CHECK(u8str == fs::path(u8str).generic_u8string());
+#endif
+ CHECK(u16str == fs::path(u16str).generic_u16string());
+ CHECK(u32str == fs::path(u32str).generic_u32string());
+ CHECK(str == fs::path(str, fs::path::format::generic_format));
+ CHECK(str == fs::path(str.begin(), str.end()));
+ CHECK(fs::path(std::wstring(3, 67)) == "CCC");
+#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)
+ CHECK(str == fs::path(u8str.begin(), u8str.end()));
+#endif
+ CHECK(str == fs::path(u16str.begin(), u16str.end()));
+ CHECK(str == fs::path(u32str.begin(), u32str.end()));
+#ifdef GHC_FILESYSTEM_VERSION
+ CHECK(fs::path("///foo/bar") == "/foo/bar");
+ CHECK(fs::path("//foo//bar") == "//foo/bar");
+#endif
+#ifdef GHC_OS_WINDOWS
+ CHECK("\\usr\\local\\bin" == fs::path("/usr/local/bin"));
+ CHECK("C:\\usr\\local\\bin" == fs::path("C:\\usr\\local\\bin"));
+#else
+ CHECK("/usr/local/bin" == fs::path("/usr/local/bin"));
+#endif
+ if (has_host_root_name_support()) {
+ CHECK("//host/foo/bar" == fs::path("//host/foo/bar"));
+ }
+
+#if !defined(GHC_OS_WINDOWS) && !(defined(__GLIBCXX__) && !(defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE >= 8))) && !defined(USE_STD_FS)
+ std::locale loc;
+ bool testUTF8Locale = false;
+ try {
+ if (const char* lang = std::getenv("LANG")) {
+ loc = std::locale(lang);
+ }
+ else {
+ loc = std::locale("en_US.UTF-8");
+ }
+ std::string name = loc.name();
+ if (name.length() > 5 && (name.substr(name.length() - 5) == "UTF-8" || name.substr(name.length() - 5) == "utf-8")) {
+ testUTF8Locale = true;
+ }
+ }
+ catch (std::runtime_error&) {
+ WARN("Couldn't create an UTF-8 locale!");
+ }
+ if (testUTF8Locale) {
+ CHECK("/usr/local/bin" == fs::path("/usr/local/bin", loc));
+ CHECK(str == fs::path(str.begin(), str.end(), loc));
+ CHECK(str == fs::path(u16str.begin(), u16str.end(), loc));
+ CHECK(str == fs::path(u32str.begin(), u32str.end(), loc));
+ }
+#endif
+}
+
+TEST_CASE("fs.path.assign - path assignments", "[filesystem][path][fs.path.assign]")
+{
+ fs::path p1{"/foo/bar"};
+ fs::path p2{"/usr/local"};
+ fs::path p3;
+ p3 = p1;
+ REQUIRE(p1 == p3);
+ p3 = fs::path{"/usr/local"};
+ REQUIRE(p2 == p3);
+ p3 = fs::path{L"/usr/local"};
+ REQUIRE(p2 == p3);
+ p3.assign(L"/usr/local");
+ REQUIRE(p2 == p3);
+#if defined(IS_WCHAR_PATH) || defined(GHC_USE_WCHAR_T)
+ p3 = fs::path::string_type{L"/foo/bar"};
+ REQUIRE(p1 == p3);
+ p3.assign(fs::path::string_type{L"/usr/local"});
+ REQUIRE(p2 == p3);
+#else
+ p3 = fs::path::string_type{"/foo/bar"};
+ REQUIRE(p1 == p3);
+ p3.assign(fs::path::string_type{"/usr/local"});
+ REQUIRE(p2 == p3);
+#endif
+ p3 = std::u16string(u"/foo/bar");
+ REQUIRE(p1 == p3);
+ p3 = U"/usr/local";
+ REQUIRE(p2 == p3);
+ p3.assign(std::u16string(u"/foo/bar"));
+ REQUIRE(p1 == p3);
+ std::string s{"/usr/local"};
+ p3.assign(s.begin(), s.end());
+ REQUIRE(p2 == p3);
+}
+
+TEST_CASE("fs.path.append - path appends", "[filesystem][path][fs.path.append]")
+{
+#ifdef GHC_OS_WINDOWS
+ CHECK(fs::path("foo") / "c:/bar" == "c:/bar");
+ CHECK(fs::path("foo") / "c:" == "c:");
+ CHECK(fs::path("c:") / "" == "c:");
+ CHECK(fs::path("c:foo") / "/bar" == "c:/bar");
+ CHECK(fs::path("c:foo") / "c:bar" == "c:foo/bar");
+#else
+ CHECK(fs::path("foo") / "" == "foo/");
+ CHECK(fs::path("foo") / "/bar" == "/bar");
+ CHECK(fs::path("/foo") / "/" == "/");
+ if (has_host_root_name_support()) {
+ CHECK(fs::path("//host/foo") / "/bar" == "/bar");
+ CHECK(fs::path("//host") / "/" == "//host/");
+ CHECK(fs::path("//host/foo") / "/" == "/");
+ }
+#endif
+ CHECK(fs::path("/foo/bar") / "some///other" == "/foo/bar/some/other");
+ fs::path p1{"/tmp/test"};
+ fs::path p2{"foobar.txt"};
+ fs::path p3 = p1 / p2;
+ CHECK("/tmp/test/foobar.txt" == p3);
+ // TODO: append(first, last)
+}
+
+TEST_CASE("fs.path.concat - path concatenation", "[filesystem][path][fs.path.concat]")
+{
+ CHECK((fs::path("foo") += fs::path("bar")) == "foobar");
+ CHECK((fs::path("foo") += fs::path("/bar")) == "foo/bar");
+
+ CHECK((fs::path("foo") += std::string("bar")) == "foobar");
+ CHECK((fs::path("foo") += std::string("/bar")) == "foo/bar");
+
+ CHECK((fs::path("foo") += "bar") == "foobar");
+ CHECK((fs::path("foo") += "/bar") == "foo/bar");
+ CHECK((fs::path("foo") += L"bar") == "foobar");
+ CHECK((fs::path("foo") += L"/bar") == "foo/bar");
+
+ CHECK((fs::path("foo") += 'b') == "foob");
+ CHECK((fs::path("foo") += '/') == "foo/");
+ CHECK((fs::path("foo") += L'b') == "foob");
+ CHECK((fs::path("foo") += L'/') == "foo/");
+
+ CHECK((fs::path("foo") += std::string("bar")) == "foobar");
+ CHECK((fs::path("foo") += std::string("/bar")) == "foo/bar");
+
+ CHECK((fs::path("foo") += std::u16string(u"bar")) == "foobar");
+ CHECK((fs::path("foo") += std::u16string(u"/bar")) == "foo/bar");
+
+ CHECK((fs::path("foo") += std::u32string(U"bar")) == "foobar");
+ CHECK((fs::path("foo") += std::u32string(U"/bar")) == "foo/bar");
+
+ CHECK(fs::path("foo").concat("bar") == "foobar");
+ CHECK(fs::path("foo").concat("/bar") == "foo/bar");
+ CHECK(fs::path("foo").concat(L"bar") == "foobar");
+ CHECK(fs::path("foo").concat(L"/bar") == "foo/bar");
+ std::string bar = "bar";
+ CHECK(fs::path("foo").concat(bar.begin(), bar.end()) == "foobar");
+#ifndef USE_STD_FS
+ CHECK((fs::path("/foo/bar") += "/some///other") == "/foo/bar/some/other");
+#endif
+ // TODO: contat(first, last)
+}
+
+TEST_CASE("fs.path.modifiers - path modifiers", "[filesystem][path][fs.path.modifiers]")
+{
+ fs::path p = fs::path("/foo/bar");
+ p.clear();
+ CHECK(p == "");
+
+ // make_preferred() is a no-op
+#ifdef GHC_OS_WINDOWS
+ CHECK(fs::path("foo\\bar") == "foo/bar");
+ CHECK(fs::path("foo\\bar").make_preferred() == "foo/bar");
+#else
+ CHECK(fs::path("foo\\bar") == "foo\\bar");
+ CHECK(fs::path("foo\\bar").make_preferred() == "foo\\bar");
+#endif
+ CHECK(fs::path("foo/bar").make_preferred() == "foo/bar");
+
+ CHECK(fs::path("foo/bar").remove_filename() == "foo/");
+ CHECK(fs::path("foo/").remove_filename() == "foo/");
+ CHECK(fs::path("/foo").remove_filename() == "/");
+ CHECK(fs::path("/").remove_filename() == "/");
+
+ CHECK(fs::path("/foo").replace_filename("bar") == "/bar");
+ CHECK(fs::path("/").replace_filename("bar") == "/bar");
+ CHECK(fs::path("/foo").replace_filename("b//ar") == "/b/ar");
+
+ CHECK(fs::path("/foo/bar.txt").replace_extension("odf") == "/foo/bar.odf");
+ CHECK(fs::path("/foo/bar.txt").replace_extension() == "/foo/bar");
+ CHECK(fs::path("/foo/bar").replace_extension("odf") == "/foo/bar.odf");
+ CHECK(fs::path("/foo/bar").replace_extension(".odf") == "/foo/bar.odf");
+ CHECK(fs::path("/foo/bar.").replace_extension(".odf") == "/foo/bar.odf");
+ CHECK(fs::path("/foo/bar/").replace_extension("odf") == "/foo/bar/.odf");
+
+ fs::path p1 = "foo";
+ fs::path p2 = "bar";
+ p1.swap(p2);
+ CHECK(p1 == "bar");
+ CHECK(p2 == "foo");
+}
+
+TEST_CASE("fs.path.native.obs - path native format observers", "[filesystem][path][fs.path.native.obs]")
+{
+#ifdef GHC_OS_WINDOWS
+#if defined(IS_WCHAR_PATH) || defined(GHC_USE_WCHAR_T)
+ CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").native() == fs::path::string_type(L"\u00E4\\\u20AC"));
+ // CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").string() == std::string("ä\\€")); // MSVCs returns local DBCS encoding
+#else
+ CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").native() == fs::path::string_type("\xc3\xa4\\\xe2\x82\xac"));
+ CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").string() == std::string("\xc3\xa4\\\xe2\x82\xac"));
+ CHECK(!::strcmp(fs::u8path("\xc3\xa4\\\xe2\x82\xac").c_str(), "\xc3\xa4\\\xe2\x82\xac"));
+ CHECK((std::string)fs::u8path("\xc3\xa4\\\xe2\x82\xac") == std::string("\xc3\xa4\\\xe2\x82\xac"));
+#endif
+ CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").wstring() == std::wstring(L"\u00E4\\\u20AC"));
+#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)
+ CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").u8string() == std::u8string(u8"\u00E4\\\u20AC"));
+#else
+ CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").u8string() == std::string("\xc3\xa4\\\xe2\x82\xac"));
+#endif
+ CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").u16string() == std::u16string(u"\u00E4\\\u20AC"));
+ CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").u32string() == std::u32string(U"\U000000E4\\\U000020AC"));
+#else
+ CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").native() == fs::path::string_type("\xc3\xa4/\xe2\x82\xac"));
+ CHECK(!::strcmp(fs::u8path("\xc3\xa4/\xe2\x82\xac").c_str(), "\xc3\xa4/\xe2\x82\xac"));
+ CHECK((std::string)fs::u8path("\xc3\xa4/\xe2\x82\xac") == std::string("\xc3\xa4/\xe2\x82\xac"));
+ CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").string() == std::string("\xc3\xa4/\xe2\x82\xac"));
+ CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").wstring() == std::wstring(L"ä/€"));
+#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)
+ CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").u8string() == std::u8string(u8"\xc3\xa4/\xe2\x82\xac"));
+#else
+ CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").u8string() == std::string("\xc3\xa4/\xe2\x82\xac"));
+#endif
+ CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").u16string() == std::u16string(u"\u00E4/\u20AC"));
+ INFO("This check might fail on GCC8 (with \"Illegal byte sequence\") due to not detecting the valid unicode codepoint U+1D11E.");
+ CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac\xf0\x9d\x84\x9e").u16string() == std::u16string(u"\u00E4/\u20AC\U0001D11E"));
+ CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").u32string() == std::u32string(U"\U000000E4/\U000020AC"));
+#endif
+}
+
+TEST_CASE("fs.path.generic.obs - path generic format observers", "[filesystem][path][fs.path.generic.obs]")
+{
+#ifdef GHC_OS_WINDOWS
+#ifndef IS_WCHAR_PATH
+ CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").generic_string() == std::string("\xc3\xa4/\xe2\x82\xac"));
+#endif
+#ifndef USE_STD_FS
+ auto t = fs::u8path("\xc3\xa4\\\xe2\x82\xac").generic_string<char, std::char_traits<char>, TestAllocator<char>>();
+ CHECK(t.c_str() == std::string("\xc3\xa4/\xe2\x82\xac"));
+#endif
+ CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").generic_wstring() == std::wstring(L"\U000000E4/\U000020AC"));
+#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)
+ CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").generic_u8string() == std::u8string(u8"\u00E4/\u20AC"));
+#else
+ CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").generic_u8string() == std::string("\xc3\xa4/\xe2\x82\xac"));
+#endif
+ CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").generic_u16string() == std::u16string(u"\u00E4/\u20AC"));
+ CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").generic_u32string() == std::u32string(U"\U000000E4/\U000020AC"));
+#else
+ CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_string() == std::string("\xc3\xa4/\xe2\x82\xac"));
+#ifndef USE_STD_FS
+ auto t = fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_string<char, std::char_traits<char>, TestAllocator<char>>();
+ CHECK(t.c_str() == std::string("\xc3\xa4/\xe2\x82\xac"));
+#endif
+ CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_wstring() == std::wstring(L"ä/€"));
+#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)
+ CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_u8string() == std::u8string(u8"\xc3\xa4/\xe2\x82\xac"));
+#else
+ CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_u8string() == std::string("\xc3\xa4/\xe2\x82\xac"));
+#endif
+ CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_u16string() == std::u16string(u"\u00E4/\u20AC"));
+ CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_u32string() == std::u32string(U"\U000000E4/\U000020AC"));
+#endif
+}
+
+TEST_CASE("fs.path.compare - path compare", "[filesystem][path][fs.path.compare]")
+{
+ CHECK(fs::path("/foo/b").compare("/foo/a") > 0);
+ CHECK(fs::path("/foo/b").compare("/foo/b") == 0);
+ CHECK(fs::path("/foo/b").compare("/foo/c") < 0);
+
+ CHECK(fs::path("/foo/b").compare(std::string("/foo/a")) > 0);
+ CHECK(fs::path("/foo/b").compare(std::string("/foo/b")) == 0);
+ CHECK(fs::path("/foo/b").compare(std::string("/foo/c")) < 0);
+
+ CHECK(fs::path("/foo/b").compare(fs::path("/foo/a")) > 0);
+ CHECK(fs::path("/foo/b").compare(fs::path("/foo/b")) == 0);
+ CHECK(fs::path("/foo/b").compare(fs::path("/foo/c")) < 0);
+
+#ifdef GHC_OS_WINDOWS
+ CHECK(fs::path("c:\\a\\b").compare("C:\\a\\b") == 0);
+ CHECK(fs::path("c:\\a\\b").compare("d:\\a\\b") != 0);
+ CHECK(fs::path("c:\\a\\b").compare("C:\\A\\b") != 0);
+#endif
+
+#ifdef LWG_2936_BEHAVIOUR
+ CHECK(fs::path("/a/b/").compare("/a/b/c") < 0);
+ CHECK(fs::path("/a/b/").compare("a/c") > 0);
+#endif // LWG_2936_BEHAVIOUR
+}
+
+TEST_CASE("fs.path.decompose - path decomposition", "[filesystem][path][fs.path.decompose]")
+{
+ // root_name()
+ CHECK(fs::path("").root_name() == "");
+ CHECK(fs::path(".").root_name() == "");
+ CHECK(fs::path("..").root_name() == "");
+ CHECK(fs::path("foo").root_name() == "");
+ CHECK(fs::path("/").root_name() == "");
+ CHECK(fs::path("/foo").root_name() == "");
+ CHECK(fs::path("foo/").root_name() == "");
+ CHECK(fs::path("/foo/").root_name() == "");
+ CHECK(fs::path("foo/bar").root_name() == "");
+ CHECK(fs::path("/foo/bar").root_name() == "");
+ CHECK(fs::path("///foo/bar").root_name() == "");
+#ifdef GHC_OS_WINDOWS
+ CHECK(fs::path("C:/foo").root_name() == "C:");
+ CHECK(fs::path("C:\\foo").root_name() == "C:");
+ CHECK(fs::path("C:foo").root_name() == "C:");
+#endif
+
+ // root_directory()
+ CHECK(fs::path("").root_directory() == "");
+ CHECK(fs::path(".").root_directory() == "");
+ CHECK(fs::path("..").root_directory() == "");
+ CHECK(fs::path("foo").root_directory() == "");
+ CHECK(fs::path("/").root_directory() == "/");
+ CHECK(fs::path("/foo").root_directory() == "/");
+ CHECK(fs::path("foo/").root_directory() == "");
+ CHECK(fs::path("/foo/").root_directory() == "/");
+ CHECK(fs::path("foo/bar").root_directory() == "");
+ CHECK(fs::path("/foo/bar").root_directory() == "/");
+ CHECK(fs::path("///foo/bar").root_directory() == "/");
+#ifdef GHC_OS_WINDOWS
+ CHECK(fs::path("C:/foo").root_directory() == "/");
+ CHECK(fs::path("C:\\foo").root_directory() == "/");
+ CHECK(fs::path("C:foo").root_directory() == "");
+#endif
+
+ // root_path()
+ CHECK(fs::path("").root_path() == "");
+ CHECK(fs::path(".").root_path() == "");
+ CHECK(fs::path("..").root_path() == "");
+ CHECK(fs::path("foo").root_path() == "");
+ CHECK(fs::path("/").root_path() == "/");
+ CHECK(fs::path("/foo").root_path() == "/");
+ CHECK(fs::path("foo/").root_path() == "");
+ CHECK(fs::path("/foo/").root_path() == "/");
+ CHECK(fs::path("foo/bar").root_path() == "");
+ CHECK(fs::path("/foo/bar").root_path() == "/");
+ CHECK(fs::path("///foo/bar").root_path() == "/");
+#ifdef GHC_OS_WINDOWS
+ CHECK(fs::path("C:/foo").root_path() == "C:/");
+ CHECK(fs::path("C:\\foo").root_path() == "C:/");
+ CHECK(fs::path("C:foo").root_path() == "C:");
+#endif
+
+ // relative_path()
+ CHECK(fs::path("").relative_path() == "");
+ CHECK(fs::path(".").relative_path() == ".");
+ CHECK(fs::path("..").relative_path() == "..");
+ CHECK(fs::path("foo").relative_path() == "foo");
+ CHECK(fs::path("/").relative_path() == "");
+ CHECK(fs::path("/foo").relative_path() == "foo");
+ CHECK(fs::path("foo/").relative_path() == "foo/");
+ CHECK(fs::path("/foo/").relative_path() == "foo/");
+ CHECK(fs::path("foo/bar").relative_path() == "foo/bar");
+ CHECK(fs::path("/foo/bar").relative_path() == "foo/bar");
+ CHECK(fs::path("///foo/bar").relative_path() == "foo/bar");
+#ifdef GHC_OS_WINDOWS
+ CHECK(fs::path("C:/foo").relative_path() == "foo");
+ CHECK(fs::path("C:\\foo").relative_path() == "foo");
+ CHECK(fs::path("C:foo").relative_path() == "foo");
+#endif
+
+ // parent_path()
+ CHECK(fs::path("").parent_path() == "");
+ CHECK(fs::path(".").parent_path() == "");
+ CHECK(fs::path("..").parent_path() == ""); // unintuitive but as defined in the standard
+ CHECK(fs::path("foo").parent_path() == "");
+ CHECK(fs::path("/").parent_path() == "/");
+ CHECK(fs::path("/foo").parent_path() == "/");
+ CHECK(fs::path("foo/").parent_path() == "foo");
+ CHECK(fs::path("/foo/").parent_path() == "/foo");
+ CHECK(fs::path("foo/bar").parent_path() == "foo");
+ CHECK(fs::path("/foo/bar").parent_path() == "/foo");
+ CHECK(fs::path("///foo/bar").parent_path() == "/foo");
+#ifdef GHC_OS_WINDOWS
+ CHECK(fs::path("C:/foo").parent_path() == "C:/");
+ CHECK(fs::path("C:\\foo").parent_path() == "C:/");
+ CHECK(fs::path("C:foo").parent_path() == "C:");
+#endif
+
+ // filename()
+ CHECK(fs::path("").filename() == "");
+ CHECK(fs::path(".").filename() == ".");
+ CHECK(fs::path("..").filename() == "..");
+ CHECK(fs::path("foo").filename() == "foo");
+ CHECK(fs::path("/").filename() == "");
+ CHECK(fs::path("/foo").filename() == "foo");
+ CHECK(fs::path("foo/").filename() == "");
+ CHECK(fs::path("/foo/").filename() == "");
+ CHECK(fs::path("foo/bar").filename() == "bar");
+ CHECK(fs::path("/foo/bar").filename() == "bar");
+ CHECK(fs::path("///foo/bar").filename() == "bar");
+#ifdef GHC_OS_WINDOWS
+ CHECK(fs::path("C:/foo").filename() == "foo");
+ CHECK(fs::path("C:\\foo").filename() == "foo");
+ CHECK(fs::path("C:foo").filename() == "foo");
+#endif
+
+ // stem()
+ CHECK(fs::path("/foo/bar.txt").stem() == "bar");
+ {
+ fs::path p = "foo.bar.baz.tar";
+ CHECK(p.extension() == ".tar");
+ p = p.stem();
+ CHECK(p.extension() == ".baz");
+ p = p.stem();
+ CHECK(p.extension() == ".bar");
+ p = p.stem();
+ CHECK(p == "foo");
+ }
+ CHECK(fs::path("/foo/.profile").stem() == ".profile");
+ CHECK(fs::path(".bar").stem() == ".bar");
+ CHECK(fs::path("..bar").stem() == ".");
+
+ // extension()
+ CHECK(fs::path("/foo/bar.txt").extension() == ".txt");
+ CHECK(fs::path("/foo/bar").extension() == "");
+ CHECK(fs::path("/foo/.profile").extension() == "");
+ CHECK(fs::path(".bar").extension() == "");
+ CHECK(fs::path("..bar").extension() == ".bar");
+
+ if (has_host_root_name_support()) {
+ // //host-based root-names
+ CHECK(fs::path("//host").root_name() == "//host");
+ CHECK(fs::path("//host/foo").root_name() == "//host");
+ CHECK(fs::path("//host").root_directory() == "");
+ CHECK(fs::path("//host/foo").root_directory() == "/");
+ CHECK(fs::path("//host").root_path() == "//host");
+ CHECK(fs::path("//host/foo").root_path() == "//host/");
+ CHECK(fs::path("//host").relative_path() == "");
+ CHECK(fs::path("//host/foo").relative_path() == "foo");
+ CHECK(fs::path("//host").parent_path() == "//host");
+ CHECK(fs::path("//host/foo").parent_path() == "//host/");
+ CHECK(fs::path("//host").filename() == "");
+ CHECK(fs::path("//host/foo").filename() == "foo");
+ }
+}
+
+TEST_CASE("fs.path.query - path query", "[fielsystem][path][fs.path.query]")
+{
+ // empty
+ CHECK(fs::path("").empty());
+ CHECK(!fs::path("foo").empty());
+
+ // has_root_path()
+ CHECK(!fs::path("foo").has_root_path());
+ CHECK(!fs::path("foo/bar").has_root_path());
+ CHECK(fs::path("/foo").has_root_path());
+#ifdef GHC_OS_WINDOWS
+ CHECK(fs::path("C:foo").has_root_path());
+ CHECK(fs::path("C:/foo").has_root_path());
+#endif
+
+ // has_root_name()
+ CHECK(!fs::path("foo").has_root_name());
+ CHECK(!fs::path("foo/bar").has_root_name());
+ CHECK(!fs::path("/foo").has_root_name());
+#ifdef GHC_OS_WINDOWS
+ CHECK(fs::path("C:foo").has_root_name());
+ CHECK(fs::path("C:/foo").has_root_name());
+#endif
+
+ // has_root_directory()
+ CHECK(!fs::path("foo").has_root_directory());
+ CHECK(!fs::path("foo/bar").has_root_directory());
+ CHECK(fs::path("/foo").has_root_directory());
+#ifdef GHC_OS_WINDOWS
+ CHECK(!fs::path("C:foo").has_root_directory());
+ CHECK(fs::path("C:/foo").has_root_directory());
+#endif
+
+ // has_relative_path()
+ CHECK(!fs::path("").has_relative_path());
+ CHECK(!fs::path("/").has_relative_path());
+ CHECK(fs::path("/foo").has_relative_path());
+
+ // has_parent_path()
+ CHECK(!fs::path("").has_parent_path());
+ CHECK(!fs::path(".").has_parent_path());
+ CHECK(!fs::path("..").has_parent_path()); // unintuitive but as defined in the standard
+ CHECK(!fs::path("foo").has_parent_path());
+ CHECK(fs::path("/").has_parent_path());
+ CHECK(fs::path("/foo").has_parent_path());
+ CHECK(fs::path("foo/").has_parent_path());
+ CHECK(fs::path("/foo/").has_parent_path());
+
+ // has_filename()
+ CHECK(fs::path("foo").has_filename());
+ CHECK(fs::path("foo/bar").has_filename());
+ CHECK(!fs::path("/foo/bar/").has_filename());
+
+ // has_stem()
+ CHECK(fs::path("foo").has_stem());
+ CHECK(fs::path("foo.bar").has_stem());
+ CHECK(fs::path(".profile").has_stem());
+ CHECK(!fs::path("/foo/").has_stem());
+
+ // has_extension()
+ CHECK(!fs::path("foo").has_extension());
+ CHECK(fs::path("foo.bar").has_extension());
+ CHECK(!fs::path(".profile").has_extension());
+
+ // is_absolute()
+ CHECK(!fs::path("foo/bar").is_absolute());
+#ifdef GHC_OS_WINDOWS
+ CHECK(!fs::path("/foo").is_absolute());
+ CHECK(!fs::path("c:foo").is_absolute());
+ CHECK(fs::path("c:/foo").is_absolute());
+#else
+ CHECK(fs::path("/foo").is_absolute());
+#endif
+
+ // is_relative()
+ CHECK(fs::path("foo/bar").is_relative());
+#ifdef GHC_OS_WINDOWS
+ CHECK(fs::path("/foo").is_relative());
+ CHECK(fs::path("c:foo").is_relative());
+ CHECK(!fs::path("c:/foo").is_relative());
+#else
+ CHECK(!fs::path("/foo").is_relative());
+#endif
+
+ if (has_host_root_name_support()) {
+ CHECK(fs::path("//host").has_root_name());
+ CHECK(fs::path("//host/foo").has_root_name());
+ CHECK(fs::path("//host").has_root_path());
+ CHECK(fs::path("//host/foo").has_root_path());
+ CHECK(!fs::path("//host").has_root_directory());
+ CHECK(fs::path("//host/foo").has_root_directory());
+ CHECK(!fs::path("//host").has_relative_path());
+ CHECK(fs::path("//host/foo").has_relative_path());
+ CHECK(fs::path("//host/foo").is_absolute());
+ CHECK(!fs::path("//host/foo").is_relative());
+ }
+}
+
+TEST_CASE("fs.path.gen - path generation", "[filesystem][path][fs.path.gen]")
+{
+ // lexically_normal()
+ CHECK(fs::path("foo/./bar/..").lexically_normal() == "foo/");
+ CHECK(fs::path("foo/.///bar/../").lexically_normal() == "foo/");
+ CHECK(fs::path("/foo/../..").lexically_normal() == "/");
+ CHECK(fs::path("foo/..").lexically_normal() == ".");
+ CHECK(fs::path("ab/cd/ef/../../qw").lexically_normal() == "ab/qw");
+ CHECK(fs::path("a/b/../../../c").lexically_normal() == "../c");
+ CHECK(fs::path("../").lexically_normal() == "..");
+#ifdef GHC_OS_WINDOWS
+ CHECK(fs::path("\\/\\///\\/").lexically_normal() == "/");
+ CHECK(fs::path("a/b/..\\//..///\\/../c\\\\/").lexically_normal() == "../c/");
+ CHECK(fs::path("..a/b/..\\//..///\\/../c\\\\/").lexically_normal() == "../c/");
+ CHECK(fs::path("..\\").lexically_normal() == "..");
+#endif
+
+ // lexically_relative()
+ CHECK(fs::path("/a/d").lexically_relative("/a/b/c") == "../../d");
+ CHECK(fs::path("/a/b/c").lexically_relative("/a/d") == "../b/c");
+ CHECK(fs::path("a/b/c").lexically_relative("a") == "b/c");
+ CHECK(fs::path("a/b/c").lexically_relative("a/b/c/x/y") == "../..");
+ CHECK(fs::path("a/b/c").lexically_relative("a/b/c") == ".");
+ CHECK(fs::path("a/b").lexically_relative("c/d") == "../../a/b");
+ CHECK(fs::path("a/b").lexically_relative("a/") == "b");
+ if (has_host_root_name_support()) {
+ CHECK(fs::path("//host1/foo").lexically_relative("//host2.bar") == "");
+ }
+#ifdef GHC_OS_WINDOWS
+ CHECK(fs::path("c:/foo").lexically_relative("/bar") == "");
+ CHECK(fs::path("c:foo").lexically_relative("c:/bar") == "");
+ CHECK(fs::path("foo").lexically_relative("/bar") == "");
+ CHECK(fs::path("c:/foo/bar.txt").lexically_relative("c:/foo/") == "bar.txt");
+ CHECK(fs::path("c:/foo/bar.txt").lexically_relative("C:/foo/") == "bar.txt");
+#else
+ CHECK(fs::path("/foo").lexically_relative("bar") == "");
+ CHECK(fs::path("foo").lexically_relative("/bar") == "");
+#endif
+
+ // lexically_proximate()
+ CHECK(fs::path("/a/d").lexically_proximate("/a/b/c") == "../../d");
+ if (has_host_root_name_support()) {
+ CHECK(fs::path("//host1/a/d").lexically_proximate("//host2/a/b/c") == "//host1/a/d");
+ }
+ CHECK(fs::path("a/d").lexically_proximate("/a/b/c") == "a/d");
+#ifdef GHC_OS_WINDOWS
+ CHECK(fs::path("c:/a/d").lexically_proximate("c:/a/b/c") == "../../d");
+ CHECK(fs::path("c:/a/d").lexically_proximate("d:/a/b/c") == "c:/a/d");
+ CHECK(fs::path("c:/foo").lexically_proximate("/bar") == "c:/foo");
+ CHECK(fs::path("c:foo").lexically_proximate("c:/bar") == "c:foo");
+ CHECK(fs::path("foo").lexically_proximate("/bar") == "foo");
+#else
+ CHECK(fs::path("/foo").lexically_proximate("bar") == "/foo");
+ CHECK(fs::path("foo").lexically_proximate("/bar") == "foo");
+#endif
+}
+
+static std::string iterateResult(const fs::path& path)
+{
+ std::ostringstream result;
+ for (fs::path::const_iterator i = path.begin(); i != path.end(); ++i) {
+ if (i != path.begin()) {
+ result << ",";
+ }
+ result << i->generic_string();
+ }
+ return result.str();
+}
+
+static std::string reverseIterateResult(const fs::path& path)
+{
+ std::ostringstream result;
+ fs::path::const_iterator iter = path.end();
+ bool first = true;
+ if (iter != path.begin()) {
+ do {
+ --iter;
+ if (!first) {
+ result << ",";
+ }
+ first = false;
+ result << iter->generic_string();
+ } while (iter != path.begin());
+ }
+ return result.str();
+}
+
+TEST_CASE("fs.path.itr - path iterators", "[filesystem][path][fs.path.itr]")
+{
+ CHECK(iterateResult(fs::path()).empty());
+ CHECK("." == iterateResult(fs::path(".")));
+ CHECK(".." == iterateResult(fs::path("..")));
+ CHECK("foo" == iterateResult(fs::path("foo")));
+ CHECK("/" == iterateResult(fs::path("/")));
+ CHECK("/,foo" == iterateResult(fs::path("/foo")));
+ CHECK("foo," == iterateResult(fs::path("foo/")));
+ CHECK("/,foo," == iterateResult(fs::path("/foo/")));
+ CHECK("foo,bar" == iterateResult(fs::path("foo/bar")));
+ CHECK("/,foo,bar" == iterateResult(fs::path("/foo/bar")));
+#ifndef USE_STD_FS
+ // ghc::filesystem enforces redundant slashes to be reduced to one
+ CHECK("/,foo,bar" == iterateResult(fs::path("///foo/bar")));
+#else
+ // typically std::filesystem keeps them
+ CHECK("///,foo,bar" == iterateResult(fs::path("///foo/bar")));
+#endif
+ CHECK("/,foo,bar," == iterateResult(fs::path("/foo/bar///")));
+ CHECK("foo,.,bar,..," == iterateResult(fs::path("foo/.///bar/../")));
+#ifdef GHC_OS_WINDOWS
+ CHECK("C:,/,foo" == iterateResult(fs::path("C:/foo")));
+#endif
+
+ CHECK(reverseIterateResult(fs::path()).empty());
+ CHECK("." == reverseIterateResult(fs::path(".")));
+ CHECK(".." == reverseIterateResult(fs::path("..")));
+ CHECK("foo" == reverseIterateResult(fs::path("foo")));
+ CHECK("/" == reverseIterateResult(fs::path("/")));
+ CHECK("foo,/" == reverseIterateResult(fs::path("/foo")));
+ CHECK(",foo" == reverseIterateResult(fs::path("foo/")));
+ CHECK(",foo,/" == reverseIterateResult(fs::path("/foo/")));
+ CHECK("bar,foo" == reverseIterateResult(fs::path("foo/bar")));
+ CHECK("bar,foo,/" == reverseIterateResult(fs::path("/foo/bar")));
+#ifndef USE_STD_FS
+ // ghc::filesystem enforces redundant slashes to be reduced to one
+ CHECK("bar,foo,/" == reverseIterateResult(fs::path("///foo/bar")));
+#else
+ // typically std::filesystem keeps them
+ CHECK("bar,foo,///" == reverseIterateResult(fs::path("///foo/bar")));
+#endif
+ CHECK(",bar,foo,/" == reverseIterateResult(fs::path("/foo/bar///")));
+ CHECK(",..,bar,.,foo" == reverseIterateResult(fs::path("foo/.///bar/../")));
+#ifdef GHC_OS_WINDOWS
+ CHECK("foo,/,C:" == reverseIterateResult(fs::path("C:/foo")));
+ CHECK("foo,C:" == reverseIterateResult(fs::path("C:foo")));
+#endif
+ {
+ fs::path p1 = "/foo/bar/test.txt";
+ fs::path p2;
+ for (auto pe : p1) {
+ p2 /= pe;
+ }
+ CHECK(p1 == p2);
+ CHECK("bar" == *(--fs::path("/foo/bar").end()));
+ auto p = fs::path("/foo/bar");
+ auto pi = p.end();
+ pi--;
+ CHECK("bar" == *pi);
+ }
+
+ if (has_host_root_name_support()) {
+ CHECK("foo" == *(--fs::path("//host/foo").end()));
+ auto p = fs::path("//host/foo");
+ auto pi = p.end();
+ pi--;
+ CHECK("foo" == *pi);
+ CHECK("//host" == iterateResult(fs::path("//host")));
+ CHECK("//host,/,foo" == iterateResult(fs::path("//host/foo")));
+ CHECK("//host" == reverseIterateResult(fs::path("//host")));
+ CHECK("foo,/,//host" == reverseIterateResult(fs::path("//host/foo")));
+ {
+ fs::path p1 = "//host/foo/bar/test.txt";
+ fs::path p2;
+ for (auto pe : p1) {
+ p2 /= pe;
+ }
+ CHECK(p1 == p2);
+ }
+ }
+}
+
+TEST_CASE("fs.path.nonmember - path non-member functions", "[filesystem][path][fs.path.nonmember]")
+{
+ fs::path p1("foo/bar");
+ fs::path p2("some/other");
+ fs::swap(p1, p2);
+ CHECK(p1 == "some/other");
+ CHECK(p2 == "foo/bar");
+ CHECK(hash_value(p1));
+ CHECK(p2 < p1);
+ CHECK(p2 <= p1);
+ CHECK(p1 <= p1);
+ CHECK(!(p1 < p2));
+ CHECK(!(p1 <= p2));
+ CHECK(p1 > p2);
+ CHECK(p1 >= p2);
+ CHECK(p1 >= p1);
+ CHECK(!(p2 > p1));
+ CHECK(!(p2 >= p1));
+ CHECK(p1 != p2);
+ CHECK(p1 / p2 == "some/other/foo/bar");
+}
+
+TEST_CASE("fs.path.io - path inserter and extractor", "[filesystem][path][fs.path.io]")
+{
+ {
+ std::ostringstream os;
+ os << fs::path("/root/foo bar");
+#ifdef GHC_OS_WINDOWS
+ CHECK(os.str() == "\"\\\\root\\\\foo bar\"");
+#else
+ CHECK(os.str() == "\"/root/foo bar\"");
+#endif
+ }
+ {
+ std::ostringstream os;
+ os << fs::path("/root/foo\"bar");
+#ifdef GHC_OS_WINDOWS
+ CHECK(os.str() == "\"\\\\root\\\\foo\\\"bar\"");
+#else
+ CHECK(os.str() == "\"/root/foo\\\"bar\"");
+#endif
+ }
+
+ {
+ std::istringstream is("\"/root/foo bar\"");
+ fs::path p;
+ is >> p;
+ CHECK(p == fs::path("/root/foo bar"));
+ CHECK((is.flags() & std::ios_base::skipws) == std::ios_base::skipws);
+ }
+ {
+ std::istringstream is("\"/root/foo bar\"");
+ is >> std::noskipws;
+ fs::path p;
+ is >> p;
+ CHECK(p == fs::path("/root/foo bar"));
+ CHECK((is.flags() & std::ios_base::skipws) != std::ios_base::skipws);
+ }
+ {
+ std::istringstream is("\"/root/foo\\\"bar\"");
+ fs::path p;
+ is >> p;
+ CHECK(p == fs::path("/root/foo\"bar"));
+ }
+ {
+ std::istringstream is("/root/foo");
+ fs::path p;
+ is >> p;
+ CHECK(p == fs::path("/root/foo"));
+ }
+}
+
+TEST_CASE("fs.path.factory - path factory functions", "[filesystem][path][fs.path.factory]")
+{
+ CHECK(fs::u8path("foo/bar") == fs::path("foo/bar"));
+ CHECK(fs::u8path("foo/bar") == fs::path("foo/bar"));
+ std::string str("/foo/bar/test.txt");
+ CHECK(fs::u8path(str.begin(), str.end()) == str);
+}
+
+TEST_CASE("fs.class.filesystem_error - class filesystem_error", "[filesystem][filesystem_error][fs.class.filesystem_error]")
+{
+ std::error_code ec(1, std::system_category());
+ fs::filesystem_error fse("None", std::error_code());
+ fse = fs::filesystem_error("Some error", ec);
+ CHECK(fse.code().value() == 1);
+ CHECK(!std::string(fse.what()).empty());
+ CHECK(fse.path1().empty());
+ CHECK(fse.path2().empty());
+ fse = fs::filesystem_error("Some error", fs::path("foo/bar"), ec);
+ CHECK(!std::string(fse.what()).empty());
+ CHECK(fse.path1() == "foo/bar");
+ CHECK(fse.path2().empty());
+ fse = fs::filesystem_error("Some error", fs::path("foo/bar"), fs::path("some/other"), ec);
+ CHECK(!std::string(fse.what()).empty());
+ CHECK(fse.path1() == "foo/bar");
+ CHECK(fse.path2() == "some/other");
+}
+
+constexpr fs::perms constExprOwnerAll()
+{
+ return fs::perms::owner_read | fs::perms::owner_write | fs::perms::owner_exec;
+}
+
+TEST_CASE("fs.enum - enum class perms", "[filesystem][enum][fs.enum]")
+{
+ static_assert(constExprOwnerAll() == fs::perms::owner_all, "constexpr didn't result in owner_all");
+ CHECK((fs::perms::owner_read | fs::perms::owner_write | fs::perms::owner_exec) == fs::perms::owner_all);
+ CHECK((fs::perms::group_read | fs::perms::group_write | fs::perms::group_exec) == fs::perms::group_all);
+ CHECK((fs::perms::others_read | fs::perms::others_write | fs::perms::others_exec) == fs::perms::others_all);
+ CHECK((fs::perms::owner_all | fs::perms::group_all | fs::perms::others_all) == fs::perms::all);
+ CHECK((fs::perms::all | fs::perms::set_uid | fs::perms::set_gid | fs::perms::sticky_bit) == fs::perms::mask);
+}
+
+TEST_CASE("fs.class.file_status - class file_status", "[filesystem][file_status][fs.class.file_status]")
+{
+ {
+ fs::file_status fs;
+ CHECK(fs.type() == fs::file_type::none);
+ CHECK(fs.permissions() == fs::perms::unknown);
+ }
+ {
+ fs::file_status fs{fs::file_type::regular};
+ CHECK(fs.type() == fs::file_type::regular);
+ CHECK(fs.permissions() == fs::perms::unknown);
+ }
+ {
+ fs::file_status fs{fs::file_type::directory, fs::perms::owner_read | fs::perms::owner_write | fs::perms::owner_exec};
+ CHECK(fs.type() == fs::file_type::directory);
+ CHECK(fs.permissions() == fs::perms::owner_all);
+ fs.type(fs::file_type::block);
+ CHECK(fs.type() == fs::file_type::block);
+ fs.type(fs::file_type::character);
+ CHECK(fs.type() == fs::file_type::character);
+ fs.type(fs::file_type::fifo);
+ CHECK(fs.type() == fs::file_type::fifo);
+ fs.type(fs::file_type::symlink);
+ CHECK(fs.type() == fs::file_type::symlink);
+ fs.type(fs::file_type::socket);
+ CHECK(fs.type() == fs::file_type::socket);
+ fs.permissions(fs.permissions() | fs::perms::group_all | fs::perms::others_all);
+ CHECK(fs.permissions() == fs::perms::all);
+ }
+ {
+ fs::file_status fst(fs::file_type::regular);
+ fs::file_status fs(std::move(fst));
+ CHECK(fs.type() == fs::file_type::regular);
+ CHECK(fs.permissions() == fs::perms::unknown);
+ }
+#if !defined(USE_STD_FS) || defined(GHC_FILESYSTEM_RUNNING_CPP20)
+ {
+ fs::file_status fs1{fs::file_type::regular, fs::perms::owner_read | fs::perms::owner_write | fs::perms::owner_exec};
+ fs::file_status fs2{fs::file_type::regular, fs::perms::owner_read | fs::perms::owner_write | fs::perms::owner_exec};
+ fs::file_status fs3{fs::file_type::directory, fs::perms::owner_read | fs::perms::owner_write | fs::perms::owner_exec};
+ fs::file_status fs4{fs::file_type::regular, fs::perms::owner_read | fs::perms::owner_write};
+ CHECK(fs1 == fs2);
+ CHECK_FALSE(fs1 == fs3);
+ CHECK_FALSE(fs1 == fs4);
+ }
+#endif
+}
+
+TEST_CASE("fs.dir.entry - class directory_entry", "[filesystem][directory_entry][fs.dir.entry]")
+{
+ TemporaryDirectory t;
+ std::error_code ec;
+ auto de = fs::directory_entry(t.path());
+ CHECK(de.path() == t.path());
+ CHECK((fs::path)de == t.path());
+ CHECK(de.exists());
+ CHECK(!de.is_block_file());
+ CHECK(!de.is_character_file());
+ CHECK(de.is_directory());
+ CHECK(!de.is_fifo());
+ CHECK(!de.is_other());
+ CHECK(!de.is_regular_file());
+ CHECK(!de.is_socket());
+ CHECK(!de.is_symlink());
+ CHECK(de.status().type() == fs::file_type::directory);
+ ec.clear();
+ CHECK(de.status(ec).type() == fs::file_type::directory);
+ CHECK(!ec);
+ CHECK_NOTHROW(de.refresh());
+ fs::directory_entry none;
+ CHECK_THROWS_AS(none.refresh(), fs::filesystem_error);
+ ec.clear();
+ CHECK_NOTHROW(none.refresh(ec));
+ CHECK(ec);
+ CHECK_THROWS_AS(de.assign(""), fs::filesystem_error);
+ ec.clear();
+ CHECK_NOTHROW(de.assign("", ec));
+ CHECK(ec);
+ generateFile(t.path() / "foo", 1234);
+ auto now = fs::file_time_type::clock::now();
+ CHECK_NOTHROW(de.assign(t.path() / "foo"));
+ CHECK_NOTHROW(de.assign(t.path() / "foo", ec));
+ CHECK(!ec);
+ de = fs::directory_entry(t.path() / "foo");
+ CHECK(de.path() == t.path() / "foo");
+ CHECK(de.exists());
+ CHECK(de.exists(ec));
+ CHECK(!ec);
+ CHECK(!de.is_block_file());
+ CHECK(!de.is_block_file(ec));
+ CHECK(!ec);
+ CHECK(!de.is_character_file());
+ CHECK(!de.is_character_file(ec));
+ CHECK(!ec);
+ CHECK(!de.is_directory());
+ CHECK(!de.is_directory(ec));
+ CHECK(!ec);
+ CHECK(!de.is_fifo());
+ CHECK(!de.is_fifo(ec));
+ CHECK(!ec);
+ CHECK(!de.is_other());
+ CHECK(!de.is_other(ec));
+ CHECK(!ec);
+ CHECK(de.is_regular_file());
+ CHECK(de.is_regular_file(ec));
+ CHECK(!ec);
+ CHECK(!de.is_socket());
+ CHECK(!de.is_socket(ec));
+ CHECK(!ec);
+ CHECK(!de.is_symlink());
+ CHECK(!de.is_symlink(ec));
+ CHECK(!ec);
+ CHECK(de.file_size() == 1234);
+ CHECK(de.file_size(ec) == 1234);
+ CHECK(std::abs(std::chrono::duration_cast<std::chrono::seconds>(de.last_write_time() - now).count()) < 3);
+ ec.clear();
+ CHECK(std::abs(std::chrono::duration_cast<std::chrono::seconds>(de.last_write_time(ec) - now).count()) < 3);
+ CHECK(!ec);
+#ifndef GHC_OS_WEB
+ CHECK(de.hard_link_count() == 1);
+ CHECK(de.hard_link_count(ec) == 1);
+ CHECK(!ec);
+#endif
+ CHECK_THROWS_AS(de.replace_filename("bar"), fs::filesystem_error);
+ CHECK_NOTHROW(de.replace_filename("foo"));
+ ec.clear();
+ CHECK_NOTHROW(de.replace_filename("bar", ec));
+ CHECK(ec);
+ auto de2none = fs::directory_entry();
+ ec.clear();
+#ifndef GHC_OS_WEB
+ CHECK(de2none.hard_link_count(ec) == static_cast<uintmax_t>(-1));
+ CHECK_THROWS_AS(de2none.hard_link_count(), fs::filesystem_error);
+ CHECK(ec);
+#endif
+ ec.clear();
+ CHECK_NOTHROW(de2none.last_write_time(ec));
+ CHECK_THROWS_AS(de2none.last_write_time(), fs::filesystem_error);
+ CHECK(ec);
+ ec.clear();
+ CHECK_THROWS_AS(de2none.file_size(), fs::filesystem_error);
+ CHECK(de2none.file_size(ec) == static_cast<uintmax_t>(-1));
+ CHECK(ec);
+ ec.clear();
+ CHECK(de2none.status().type() == fs::file_type::not_found);
+ CHECK(de2none.status(ec).type() == fs::file_type::not_found);
+ CHECK(ec);
+ generateFile(t.path() / "a");
+ generateFile(t.path() / "b");
+ auto d1 = fs::directory_entry(t.path() / "a");
+ auto d2 = fs::directory_entry(t.path() / "b");
+ CHECK(d1 < d2);
+ CHECK(!(d2 < d1));
+ CHECK(d1 <= d2);
+ CHECK(!(d2 <= d1));
+ CHECK(d2 > d1);
+ CHECK(!(d1 > d2));
+ CHECK(d2 >= d1);
+ CHECK(!(d1 >= d2));
+ CHECK(d1 != d2);
+ CHECK(!(d2 != d2));
+ CHECK(d1 == d1);
+ CHECK(!(d1 == d2));
+}
+
+TEST_CASE("fs.class.directory_iterator - class directory_iterator", "[filesystem][directory_iterator][fs.class.directory_iterator]")
+{
+ {
+ TemporaryDirectory t;
+ CHECK(fs::directory_iterator(t.path()) == fs::directory_iterator());
+ generateFile(t.path() / "test", 1234);
+ REQUIRE(fs::directory_iterator(t.path()) != fs::directory_iterator());
+ auto iter = fs::directory_iterator(t.path());
+ fs::directory_iterator iter2(iter);
+ fs::directory_iterator iter3, iter4;
+ iter3 = iter;
+ CHECK(iter->path().filename() == "test");
+ CHECK(iter2->path().filename() == "test");
+ CHECK(iter3->path().filename() == "test");
+ iter4 = std::move(iter3);
+ CHECK(iter4->path().filename() == "test");
+ CHECK(iter->path() == t.path() / "test");
+ CHECK(!iter->is_symlink());
+ CHECK(iter->is_regular_file());
+ CHECK(!iter->is_directory());
+ CHECK(iter->file_size() == 1234);
+ CHECK(++iter == fs::directory_iterator());
+ CHECK_THROWS_AS(fs::directory_iterator(t.path() / "non-existing"), fs::filesystem_error);
+ int cnt = 0;
+ for(auto de : fs::directory_iterator(t.path())) {
+ ++cnt;
+ }
+ CHECK(cnt == 1);
+ }
+ if (is_symlink_creation_supported()) {
+ TemporaryDirectory t;
+ fs::path td = t.path() / "testdir";
+ CHECK(fs::directory_iterator(t.path()) == fs::directory_iterator());
+ generateFile(t.path() / "test", 1234);
+ fs::create_directory(td);
+ REQUIRE_NOTHROW(fs::create_symlink(t.path() / "test", td / "testlink"));
+ std::error_code ec;
+ REQUIRE(fs::directory_iterator(td) != fs::directory_iterator());
+ auto iter = fs::directory_iterator(td);
+ CHECK(iter->path().filename() == "testlink");
+ CHECK(iter->path() == td / "testlink");
+ CHECK(iter->is_symlink());
+ CHECK(iter->is_regular_file());
+ CHECK(!iter->is_directory());
+ CHECK(iter->file_size() == 1234);
+ CHECK(++iter == fs::directory_iterator());
+ }
+ {
+ // Issue #8: check if resources are freed when iterator reaches end()
+ TemporaryDirectory t(TempOpt::change_path);
+ auto p = fs::path("test/");
+ fs::create_directory(p);
+ auto iter = fs::directory_iterator(p);
+ while (iter != fs::directory_iterator()) {
+ ++iter;
+ }
+ CHECK(fs::remove_all(p) == 1);
+ CHECK_NOTHROW(fs::create_directory(p));
+ }
+}
+
+TEST_CASE("fs.class.rec.dir.itr - class recursive_directory_iterator", "[filesystem][recursive_directory_iterator][fs.class.rec.dir.itr]")
+{
+ {
+ auto iter = fs::recursive_directory_iterator(".");
+ iter.pop();
+ CHECK(iter == fs::recursive_directory_iterator());
+ }
+ {
+ TemporaryDirectory t;
+ CHECK(fs::recursive_directory_iterator(t.path()) == fs::recursive_directory_iterator());
+ generateFile(t.path() / "test", 1234);
+ REQUIRE(fs::recursive_directory_iterator(t.path()) != fs::recursive_directory_iterator());
+ auto iter = fs::recursive_directory_iterator(t.path());
+ CHECK(iter->path().filename() == "test");
+ CHECK(iter->path() == t.path() / "test");
+ CHECK(!iter->is_symlink());
+ CHECK(iter->is_regular_file());
+ CHECK(!iter->is_directory());
+ CHECK(iter->file_size() == 1234);
+ CHECK(++iter == fs::recursive_directory_iterator());
+ }
+
+ {
+ TemporaryDirectory t;
+ fs::path td = t.path() / "testdir";
+ fs::create_directories(td);
+ generateFile(td / "test", 1234);
+ REQUIRE(fs::recursive_directory_iterator(t.path()) != fs::recursive_directory_iterator());
+ auto iter = fs::recursive_directory_iterator(t.path());
+
+ CHECK(iter->path().filename() == "testdir");
+ CHECK(iter->path() == td);
+ CHECK(!iter->is_symlink());
+ CHECK(!iter->is_regular_file());
+ CHECK(iter->is_directory());
+
+ CHECK(++iter != fs::recursive_directory_iterator());
+
+ CHECK(iter->path().filename() == "test");
+ CHECK(iter->path() == td / "test");
+ CHECK(!iter->is_symlink());
+ CHECK(iter->is_regular_file());
+ CHECK(!iter->is_directory());
+ CHECK(iter->file_size() == 1234);
+
+ CHECK(++iter == fs::recursive_directory_iterator());
+ }
+ {
+ TemporaryDirectory t;
+ std::error_code ec;
+ CHECK(fs::recursive_directory_iterator(t.path(), fs::directory_options::none) == fs::recursive_directory_iterator());
+ CHECK(fs::recursive_directory_iterator(t.path(), fs::directory_options::none, ec) == fs::recursive_directory_iterator());
+ CHECK(!ec);
+ CHECK(fs::recursive_directory_iterator(t.path(), ec) == fs::recursive_directory_iterator());
+ CHECK(!ec);
+ generateFile(t.path() / "test");
+ fs::recursive_directory_iterator rd1(t.path());
+ CHECK(fs::recursive_directory_iterator(rd1) != fs::recursive_directory_iterator());
+ fs::recursive_directory_iterator rd2(t.path());
+ CHECK(fs::recursive_directory_iterator(std::move(rd2)) != fs::recursive_directory_iterator());
+ fs::recursive_directory_iterator rd3(t.path(), fs::directory_options::skip_permission_denied);
+ CHECK(rd3.options() == fs::directory_options::skip_permission_denied);
+ fs::recursive_directory_iterator rd4;
+ rd4 = std::move(rd3);
+ CHECK(rd4 != fs::recursive_directory_iterator());
+ CHECK_NOTHROW(++rd4);
+ CHECK(rd4 == fs::recursive_directory_iterator());
+ fs::recursive_directory_iterator rd5;
+ rd5 = rd4;
+ }
+ {
+ TemporaryDirectory t(TempOpt::change_path);
+ generateFile("a");
+ fs::create_directory("d1");
+ fs::create_directory("d1/d2");
+ generateFile("d1/b");
+ generateFile("d1/c");
+ generateFile("d1/d2/d");
+ generateFile("e");
+ auto iter = fs::recursive_directory_iterator(".");
+ std::multimap<std::string, int> result;
+ while(iter != fs::recursive_directory_iterator()) {
+ result.insert(std::make_pair(iter->path().generic_string(), iter.depth()));
+ ++iter;
+ }
+ std::stringstream os;
+ for(auto p : result) {
+ os << "[" << p.first << "," << p.second << "],";
+ }
+ CHECK(os.str() == "[./a,0],[./d1,0],[./d1/b,1],[./d1/c,1],[./d1/d2,1],[./d1/d2/d,2],[./e,0],");
+ }
+ {
+ TemporaryDirectory t(TempOpt::change_path);
+ generateFile("a");
+ fs::create_directory("d1");
+ fs::create_directory("d1/d2");
+ generateFile("d1/b");
+ generateFile("d1/c");
+ generateFile("d1/d2/d");
+ generateFile("e");
+ std::multiset<std::string> result;
+ for(auto de : fs::recursive_directory_iterator(".")) {
+ result.insert(de.path().generic_string());
+ }
+ std::stringstream os;
+ for(auto p : result) {
+ os << p << ",";
+ }
+ CHECK(os.str() == "./a,./d1,./d1/b,./d1/c,./d1/d2,./d1/d2/d,./e,");
+ }
+ {
+ TemporaryDirectory t(TempOpt::change_path);
+ generateFile("a");
+ fs::create_directory("d1");
+ fs::create_directory("d1/d2");
+ generateFile("d1/d2/b");
+ generateFile("e");
+ auto iter = fs::recursive_directory_iterator(".");
+ std::multimap<std::string, int> result;
+ while(iter != fs::recursive_directory_iterator()) {
+ result.insert(std::make_pair(iter->path().generic_string(), iter.depth()));
+ if(iter->path() == "./d1/d2") {
+ iter.disable_recursion_pending();
+ }
+ ++iter;
+ }
+ std::stringstream os;
+ for(auto p : result) {
+ os << "[" << p.first << "," << p.second << "],";
+ }
+ CHECK(os.str() == "[./a,0],[./d1,0],[./d1/d2,1],[./e,0],");
+ }
+ {
+ TemporaryDirectory t(TempOpt::change_path);
+ generateFile("a");
+ fs::create_directory("d1");
+ fs::create_directory("d1/d2");
+ generateFile("d1/d2/b");
+ generateFile("e");
+ auto iter = fs::recursive_directory_iterator(".");
+ std::multimap<std::string, int> result;
+ while(iter != fs::recursive_directory_iterator()) {
+ result.insert(std::make_pair(iter->path().generic_string(), iter.depth()));
+ if(iter->path() == "./d1/d2") {
+ iter.pop();
+ }
+ else {
+ ++iter;
+ }
+ }
+ std::stringstream os;
+ for(auto p : result) {
+ os << "[" << p.first << "," << p.second << "],";
+ }
+ CHECK(os.str() == "[./a,0],[./d1,0],[./d1/d2,1],[./e,0],");
+ }
+ if (is_symlink_creation_supported()) {
+ TemporaryDirectory t(TempOpt::change_path);
+ fs::create_directory("d1");
+ generateFile("d1/a");
+ fs::create_directory("d2");
+ generateFile("d2/b");
+ fs::create_directory_symlink("../d1", "d2/ds1");
+ fs::create_directory_symlink("d3", "d2/ds2");
+ std::multiset<std::string> result;
+ REQUIRE_NOTHROW([&](){
+ for (const auto& de : fs::recursive_directory_iterator("d2", fs::directory_options::follow_directory_symlink)) {
+ result.insert(de.path().generic_string());
+ }
+ }());
+ std::stringstream os;
+ for(const auto& p : result) {
+ os << p << ",";
+ }
+ CHECK(os.str() == "d2/b,d2/ds1,d2/ds1/a,d2/ds2,");
+ os.str("");
+ result.clear();
+ REQUIRE_NOTHROW([&](){
+ for (const auto& de : fs::recursive_directory_iterator("d2")) {
+ result.insert(de.path().generic_string());
+ }
+ }());
+ for(const auto& p : result) {
+ os << p << ",";
+ }
+ CHECK(os.str() == "d2/b,d2/ds1,d2/ds2,");
+ }
+}
+
+TEST_CASE("fs.op.absolute - absolute", "[filesystem][operations][fs.op.absolute]")
+{
+ CHECK(fs::absolute("") == fs::current_path() / "");
+ CHECK(fs::absolute(fs::current_path()) == fs::current_path());
+ CHECK(fs::absolute(".") == fs::current_path() / ".");
+ CHECK((fs::absolute("..") == fs::current_path().parent_path() || fs::absolute("..") == fs::current_path() / ".."));
+ CHECK(fs::absolute("foo") == fs::current_path() / "foo");
+ std::error_code ec;
+ CHECK(fs::absolute("", ec) == fs::current_path() / "");
+ CHECK(!ec);
+ CHECK(fs::absolute("foo", ec) == fs::current_path() / "foo");
+ CHECK(!ec);
+}
+
+TEST_CASE("fs.op.canonical - canonical", "[filesystem][operations][fs.op.canonical]")
+{
+ CHECK_THROWS_AS(fs::canonical(""), fs::filesystem_error);
+ {
+ std::error_code ec;
+ CHECK(fs::canonical("", ec) == "");
+ CHECK(ec);
+ }
+ CHECK(fs::canonical(fs::current_path()) == fs::current_path());
+
+ CHECK(fs::canonical(".") == fs::current_path());
+ CHECK(fs::canonical("..") == fs::current_path().parent_path());
+ CHECK(fs::canonical("/") == fs::current_path().root_path());
+ CHECK_THROWS_AS(fs::canonical("foo"), fs::filesystem_error);
+ {
+ std::error_code ec;
+ CHECK_NOTHROW(fs::canonical("foo", ec));
+ CHECK(ec);
+ }
+ {
+ TemporaryDirectory t(TempOpt::change_path);
+ auto dir = t.path() / "d0";
+ fs::create_directories(dir / "d1");
+ generateFile(dir / "f0");
+ fs::path rel(dir.filename());
+ CHECK(fs::canonical(dir) == dir);
+ CHECK(fs::canonical(rel) == dir);
+ CHECK(fs::canonical(dir / "f0") == dir / "f0");
+ CHECK(fs::canonical(rel / "f0") == dir / "f0");
+ CHECK(fs::canonical(rel / "./f0") == dir / "f0");
+ CHECK(fs::canonical(rel / "d1/../f0") == dir / "f0");
+ }
+
+ if (is_symlink_creation_supported()) {
+ TemporaryDirectory t(TempOpt::change_path);
+ fs::create_directory(t.path() / "dir1");
+ generateFile(t.path() / "dir1/test1");
+ fs::create_directory(t.path() / "dir2");
+ fs::create_directory_symlink(t.path() / "dir1", t.path() / "dir2/dirSym");
+ CHECK(fs::canonical(t.path() / "dir2/dirSym/test1") == t.path() / "dir1/test1");
+ }
+}
+
+TEST_CASE("fs.op.copy - copy", "[filesystem][operations][fs.op.copy]")
+{
+ {
+ TemporaryDirectory t(TempOpt::change_path);
+ std::error_code ec;
+ fs::create_directory("dir1");
+ generateFile("dir1/file1");
+ generateFile("dir1/file2");
+ fs::create_directory("dir1/dir2");
+ generateFile("dir1/dir2/file3");
+ CHECK_NOTHROW(fs::copy("dir1", "dir3"));
+ CHECK(fs::exists("dir3/file1"));
+ CHECK(fs::exists("dir3/file2"));
+ CHECK(!fs::exists("dir3/dir2"));
+ CHECK_NOTHROW(fs::copy("dir1", "dir4", fs::copy_options::recursive, ec));
+ CHECK(!ec);
+ CHECK(fs::exists("dir4/file1"));
+ CHECK(fs::exists("dir4/file2"));
+ CHECK(fs::exists("dir4/dir2/file3"));
+ fs::create_directory("dir5");
+ generateFile("dir5/file1");
+ CHECK_THROWS_AS(fs::copy("dir1/file1", "dir5/file1"), fs::filesystem_error);
+ CHECK_NOTHROW(fs::copy("dir1/file1", "dir5/file1", fs::copy_options::skip_existing));
+ }
+ if (is_symlink_creation_supported()) {
+ TemporaryDirectory t(TempOpt::change_path);
+ std::error_code ec;
+ fs::create_directory("dir1");
+ generateFile("dir1/file1");
+ generateFile("dir1/file2");
+ fs::create_directory("dir1/dir2");
+ generateFile("dir1/dir2/file3");
+#ifdef TEST_LWG_2682_BEHAVIOUR
+ REQUIRE_THROWS_AS(fs::copy("dir1", "dir3", fs::copy_options::create_symlinks | fs::copy_options::recursive), fs::filesystem_error);
+#else
+ REQUIRE_NOTHROW(fs::copy("dir1", "dir3", fs::copy_options::create_symlinks | fs::copy_options::recursive));
+ CHECK(!ec);
+ CHECK(fs::exists("dir3/file1"));
+ CHECK(fs::is_symlink("dir3/file1"));
+ CHECK(fs::exists("dir3/file2"));
+ CHECK(fs::is_symlink("dir3/file2"));
+ CHECK(fs::exists("dir3/dir2/file3"));
+ CHECK(fs::is_symlink("dir3/dir2/file3"));
+#endif
+ }
+#ifndef GHC_OS_WEB
+ {
+ TemporaryDirectory t(TempOpt::change_path);
+ std::error_code ec;
+ fs::create_directory("dir1");
+ generateFile("dir1/file1");
+ generateFile("dir1/file2");
+ fs::create_directory("dir1/dir2");
+ generateFile("dir1/dir2/file3");
+ auto f1hl = fs::hard_link_count("dir1/file1");
+ auto f2hl = fs::hard_link_count("dir1/file2");
+ auto f3hl = fs::hard_link_count("dir1/dir2/file3");
+ CHECK_NOTHROW(fs::copy("dir1", "dir3", fs::copy_options::create_hard_links | fs::copy_options::recursive, ec));
+ REQUIRE(!ec);
+ CHECK(fs::exists("dir3/file1"));
+ CHECK(fs::hard_link_count("dir1/file1") == f1hl + 1);
+ CHECK(fs::exists("dir3/file2"));
+ CHECK(fs::hard_link_count("dir1/file2") == f2hl + 1);
+ CHECK(fs::exists("dir3/dir2/file3"));
+ CHECK(fs::hard_link_count("dir1/dir2/file3") == f3hl + 1);
+ }
+#endif
+}
+
+TEST_CASE("fs.op.copy_file - copy_file", "[filesystem][operations][fs.op.copy_file]")
+{
+ TemporaryDirectory t(TempOpt::change_path);
+ std::error_code ec;
+ generateFile("foo", 100);
+ CHECK(!fs::exists("bar"));
+ CHECK(fs::copy_file("foo", "bar"));
+ CHECK(fs::exists("bar"));
+ CHECK(fs::file_size("foo") == fs::file_size("bar"));
+ CHECK(fs::copy_file("foo", "bar2", ec));
+ CHECK(!ec);
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+ generateFile("foo2", 200);
+ CHECK(fs::copy_file("foo2", "bar", fs::copy_options::update_existing));
+ CHECK(fs::file_size("bar") == 200);
+ CHECK(!fs::copy_file("foo", "bar", fs::copy_options::update_existing));
+ CHECK(fs::file_size("bar") == 200);
+ CHECK(fs::copy_file("foo", "bar", fs::copy_options::overwrite_existing));
+ CHECK(fs::file_size("bar") == 100);
+ CHECK_THROWS_AS(fs::copy_file("foobar", "foobar2"), fs::filesystem_error);
+ CHECK_NOTHROW(fs::copy_file("foobar", "foobar2", ec));
+ CHECK(ec);
+ CHECK(!fs::exists("foobar"));
+}
+
+TEST_CASE("fs.op.copy_symlink - copy_symlink", "[filesystem][operations][fs.op.copy_symlink]")
+{
+ TemporaryDirectory t(TempOpt::change_path);
+ std::error_code ec;
+ generateFile("foo");
+ fs::create_directory("dir");
+ if (is_symlink_creation_supported()) {
+ fs::create_symlink("foo", "sfoo");
+ fs::create_directory_symlink("dir", "sdir");
+ CHECK_NOTHROW(fs::copy_symlink("sfoo", "sfooc"));
+ CHECK(fs::exists("sfooc"));
+ CHECK_NOTHROW(fs::copy_symlink("sfoo", "sfooc2", ec));
+ CHECK(fs::exists("sfooc2"));
+ CHECK(!ec);
+ CHECK_NOTHROW(fs::copy_symlink("sdir", "sdirc"));
+ CHECK(fs::exists("sdirc"));
+ CHECK_NOTHROW(fs::copy_symlink("sdir", "sdirc2", ec));
+ CHECK(fs::exists("sdirc2"));
+ CHECK(!ec);
+ }
+ CHECK_THROWS_AS(fs::copy_symlink("bar", "barc"), fs::filesystem_error);
+ CHECK_NOTHROW(fs::copy_symlink("bar", "barc", ec));
+ CHECK(ec);
+}
+
+TEST_CASE("fs.op.create_directories - create_directories", "[filesystem][operations][fs.op.create_directories]")
+{
+ TemporaryDirectory t;
+ fs::path p = t.path() / "testdir";
+ fs::path p2 = p / "nested";
+ REQUIRE(!fs::exists(p));
+ REQUIRE(!fs::exists(p2));
+ CHECK(fs::create_directories(p2));
+ CHECK(fs::is_directory(p));
+ CHECK(fs::is_directory(p2));
+ CHECK(!fs::create_directories(p2));
+#ifdef TEST_LWG_2935_BEHAVIOUR
+ INFO("This test expects LWG #2935 result conformance.");
+ p = t.path() / "testfile";
+ generateFile(p);
+ CHECK(fs::is_regular_file(p));
+ CHECK(!fs::is_directory(p));
+ bool created = false;
+ CHECK_NOTHROW((created = fs::create_directories(p)));
+ CHECK(!created);
+ CHECK(fs::is_regular_file(p));
+ CHECK(!fs::is_directory(p));
+ std::error_code ec;
+ CHECK_NOTHROW((created = fs::create_directories(p, ec)));
+ CHECK(!created);
+ CHECK(!ec);
+ CHECK(fs::is_regular_file(p));
+ CHECK(!fs::is_directory(p));
+ CHECK(!fs::create_directories(p, ec));
+#else
+ INFO("This test expects conformance with P1164R1. (implemented by GCC with issue #86910.)");
+ p = t.path() / "testfile";
+ generateFile(p);
+ CHECK(fs::is_regular_file(p));
+ CHECK(!fs::is_directory(p));
+ CHECK_THROWS_AS(fs::create_directories(p), fs::filesystem_error);
+ CHECK(fs::is_regular_file(p));
+ CHECK(!fs::is_directory(p));
+ std::error_code ec;
+ CHECK_NOTHROW(fs::create_directories(p, ec));
+ CHECK(ec);
+ CHECK(fs::is_regular_file(p));
+ CHECK(!fs::is_directory(p));
+ CHECK(!fs::create_directories(p, ec));
+#endif
+}
+
+TEST_CASE("fs.op.create_directory - create_directory", "[filesystem][operations][fs.op.create_directory]")
+{
+ TemporaryDirectory t;
+ fs::path p = t.path() / "testdir";
+ REQUIRE(!fs::exists(p));
+ CHECK(fs::create_directory(p));
+ CHECK(fs::is_directory(p));
+ CHECK(!fs::is_regular_file(p));
+ CHECK(fs::create_directory(p / "nested", p));
+ CHECK(fs::is_directory(p / "nested"));
+ CHECK(!fs::is_regular_file(p / "nested"));
+#ifdef TEST_LWG_2935_BEHAVIOUR
+ INFO("This test expects LWG #2935 result conformance.");
+ p = t.path() / "testfile";
+ generateFile(p);
+ CHECK(fs::is_regular_file(p));
+ CHECK(!fs::is_directory(p));
+ bool created = false;
+ CHECK_NOTHROW((created = fs::create_directory(p)));
+ CHECK(!created);
+ CHECK(fs::is_regular_file(p));
+ CHECK(!fs::is_directory(p));
+ std::error_code ec;
+ CHECK_NOTHROW((created = fs::create_directory(p, ec)));
+ CHECK(!created);
+ CHECK(!ec);
+ CHECK(fs::is_regular_file(p));
+ CHECK(!fs::is_directory(p));
+ CHECK(!fs::create_directories(p, ec));
+#else
+ INFO("This test expects conformance with P1164R1. (implemented by GCC with issue #86910.)");
+ p = t.path() / "testfile";
+ generateFile(p);
+ CHECK(fs::is_regular_file(p));
+ CHECK(!fs::is_directory(p));
+ REQUIRE_THROWS_AS(fs::create_directory(p), fs::filesystem_error);
+ CHECK(fs::is_regular_file(p));
+ CHECK(!fs::is_directory(p));
+ std::error_code ec;
+ REQUIRE_NOTHROW(fs::create_directory(p, ec));
+ CHECK(ec);
+ CHECK(fs::is_regular_file(p));
+ CHECK(!fs::is_directory(p));
+ CHECK(!fs::create_directory(p, ec));
+#endif
+}
+
+TEST_CASE("fs.op.create_directory_symlink - create_directory_symlink", "[filesystem][operations][fs.op.create_directory_symlink]")
+{
+ if (is_symlink_creation_supported()) {
+ TemporaryDirectory t;
+ fs::create_directory(t.path() / "dir1");
+ generateFile(t.path() / "dir1/test1");
+ fs::create_directory(t.path() / "dir2");
+ fs::create_directory_symlink(t.path() / "dir1", t.path() / "dir2/dirSym");
+ CHECK(fs::exists(t.path() / "dir2/dirSym"));
+ CHECK(fs::is_symlink(t.path() / "dir2/dirSym"));
+ CHECK(fs::exists(t.path() / "dir2/dirSym/test1"));
+ CHECK(fs::is_regular_file(t.path() / "dir2/dirSym/test1"));
+ CHECK_THROWS_AS(fs::create_directory_symlink(t.path() / "dir1", t.path() / "dir2/dirSym"), fs::filesystem_error);
+ std::error_code ec;
+ CHECK_NOTHROW(fs::create_directory_symlink(t.path() / "dir1", t.path() / "dir2/dirSym", ec));
+ CHECK(ec);
+ }
+}
+
+TEST_CASE("fs.op.create_hard_link - create_hard_link", "[filesystem][operations][fs.op.create_hard_link]")
+{
+#ifndef GHC_OS_WEB
+ TemporaryDirectory t(TempOpt::change_path);
+ std::error_code ec;
+ generateFile("foo", 1234);
+ CHECK_NOTHROW(fs::create_hard_link("foo", "bar"));
+ CHECK(fs::exists("bar"));
+ CHECK(!fs::is_symlink("bar"));
+ CHECK_NOTHROW(fs::create_hard_link("foo", "bar2", ec));
+ CHECK(fs::exists("bar2"));
+ CHECK(!fs::is_symlink("bar2"));
+ CHECK(!ec);
+ CHECK_THROWS_AS(fs::create_hard_link("nofoo", "bar"), fs::filesystem_error);
+ CHECK_NOTHROW(fs::create_hard_link("nofoo", "bar", ec));
+ CHECK(ec);
+#endif
+}
+
+TEST_CASE("fs.op.create_symlink - create_symlink", "[filesystem][operations][fs.op.create_symlink]")
+{
+ if (is_symlink_creation_supported()) {
+ TemporaryDirectory t;
+ fs::create_directory(t.path() / "dir1");
+ generateFile(t.path() / "dir1/test1");
+ fs::create_directory(t.path() / "dir2");
+ fs::create_symlink(t.path() / "dir1/test1", t.path() / "dir2/fileSym");
+ CHECK(fs::exists(t.path() / "dir2/fileSym"));
+ CHECK(fs::is_symlink(t.path() / "dir2/fileSym"));
+ CHECK(fs::exists(t.path() / "dir2/fileSym"));
+ CHECK(fs::is_regular_file(t.path() / "dir2/fileSym"));
+ CHECK_THROWS_AS(fs::create_symlink(t.path() / "dir1", t.path() / "dir2/fileSym"), fs::filesystem_error);
+ std::error_code ec;
+ CHECK_NOTHROW(fs::create_symlink(t.path() / "dir1", t.path() / "dir2/fileSym", ec));
+ CHECK(ec);
+ }
+}
+
+TEST_CASE("fs.op.current_path - current_path", "[filesystem][operations][fs.op.current_path]")
+{
+ TemporaryDirectory t;
+ std::error_code ec;
+ fs::path p1 = fs::current_path();
+ CHECK_NOTHROW(fs::current_path(t.path()));
+ CHECK(p1 != fs::current_path());
+ CHECK_NOTHROW(fs::current_path(p1, ec));
+ CHECK(!ec);
+ CHECK_THROWS_AS(fs::current_path(t.path() / "foo"), fs::filesystem_error);
+ CHECK(p1 == fs::current_path());
+ CHECK_NOTHROW(fs::current_path(t.path() / "foo", ec));
+ CHECK(ec);
+}
+
+TEST_CASE("fs.op.equivalent - equivalent", "[filesystem][operations][fs.op.equivalent]")
+{
+ TemporaryDirectory t(TempOpt::change_path);
+ generateFile("foo", 1234);
+ CHECK(fs::equivalent(t.path() / "foo", "foo"));
+ if (is_symlink_creation_supported()) {
+ std::error_code ec(42, std::system_category());
+ fs::create_symlink("foo", "foo2");
+ CHECK(fs::equivalent("foo", "foo2"));
+ CHECK(fs::equivalent("foo", "foo2", ec));
+ CHECK(!ec);
+ }
+#ifdef TEST_LWG_2937_BEHAVIOUR
+ INFO("This test expects LWG #2937 result conformance.");
+ std::error_code ec;
+ bool result = false;
+ REQUIRE_THROWS_AS(fs::equivalent("foo", "foo3"), fs::filesystem_error);
+ CHECK_NOTHROW(result = fs::equivalent("foo", "foo3", ec));
+ CHECK(!result);
+ CHECK(ec);
+ ec.clear();
+ CHECK_THROWS_AS(fs::equivalent("foo3", "foo"), fs::filesystem_error);
+ CHECK_NOTHROW(result = fs::equivalent("foo3", "foo", ec));
+ CHECK(!result);
+ CHECK(ec);
+ ec.clear();
+ CHECK_THROWS_AS(fs::equivalent("foo3", "foo4"), fs::filesystem_error);
+ CHECK_NOTHROW(result = fs::equivalent("foo3", "foo4", ec));
+ CHECK(!result);
+ CHECK(ec);
+#else
+ INFO("This test expects conformance predating LWG #2937 result.");
+ std::error_code ec;
+ bool result = false;
+ REQUIRE_NOTHROW(result = fs::equivalent("foo", "foo3"));
+ CHECK(!result);
+ CHECK_NOTHROW(result = fs::equivalent("foo", "foo3", ec));
+ CHECK(!result);
+ CHECK(!ec);
+ ec.clear();
+ CHECK_NOTHROW(result = fs::equivalent("foo3", "foo"));
+ CHECK(!result);
+ CHECK_NOTHROW(result = fs::equivalent("foo3", "foo", ec));
+ CHECK(!result);
+ CHECK(!ec);
+ ec.clear();
+ CHECK_THROWS_AS(result = fs::equivalent("foo4", "foo3"), fs::filesystem_error);
+ CHECK(!result);
+ CHECK_NOTHROW(result = fs::equivalent("foo4", "foo3", ec));
+ CHECK(!result);
+ CHECK(ec);
+#endif
+}
+
+TEST_CASE("fs.op.exists - exists", "[filesystem][operations][fs.op.exists]")
+{
+ TemporaryDirectory t(TempOpt::change_path);
+ std::error_code ec;
+ CHECK(!fs::exists(""));
+ CHECK(!fs::exists("foo"));
+ CHECK(!fs::exists("foo", ec));
+ CHECK(!ec);
+ ec = std::error_code(42, std::system_category());
+ CHECK(!fs::exists("foo", ec));
+#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)
+ CHECK(!fs::exists(u8"foo"));
+#endif
+ CHECK(!ec);
+ ec.clear();
+ CHECK(fs::exists(t.path()));
+ CHECK(fs::exists(t.path(), ec));
+ CHECK(!ec);
+ ec = std::error_code(42, std::system_category());
+ CHECK(fs::exists(t.path(), ec));
+ CHECK(!ec);
+#if defined(GHC_OS_WINDOWS) && !defined(GHC_FILESYSTEM_FWD)
+ if (::GetFileAttributesW(L"C:\\fs-test") != INVALID_FILE_ATTRIBUTES) {
+ CHECK(fs::exists("C:\\fs-test"));
+ }
+#endif
+}
+
+TEST_CASE("fs.op.file_size - file_size", "[filesystem][operations][fs.op.file_size]")
+{
+ TemporaryDirectory t(TempOpt::change_path);
+ std::error_code ec;
+ generateFile("foo", 0);
+ generateFile("bar", 1234);
+ CHECK(fs::file_size("foo") == 0);
+ ec = std::error_code(42, std::system_category());
+ CHECK(fs::file_size("foo", ec) == 0);
+ CHECK(!ec);
+ ec.clear();
+ CHECK(fs::file_size("bar") == 1234);
+ ec = std::error_code(42, std::system_category());
+ CHECK(fs::file_size("bar", ec) == 1234);
+ CHECK(!ec);
+ ec.clear();
+ CHECK_THROWS_AS(fs::file_size("foobar"), fs::filesystem_error);
+ CHECK(fs::file_size("foobar", ec) == static_cast<uintmax_t>(-1));
+ CHECK(ec);
+ ec.clear();
+}
+
+#ifndef GHC_OS_WINDOWS
+static uintmax_t getHardlinkCount(const fs::path& p)
+{
+ struct stat st = {};
+ auto rc = ::lstat(p.c_str(), &st);
+ return rc == 0 ? st.st_nlink : ~0u;
+}
+#endif
+
+TEST_CASE("fs.op.hard_link_count - hard_link_count", "[filesystem][operations][fs.op.hard_link_count]")
+{
+#ifndef GHC_OS_WEB
+ TemporaryDirectory t(TempOpt::change_path);
+ std::error_code ec;
+#ifdef GHC_OS_WINDOWS
+ // windows doesn't implement "."/".." as hardlinks, so it
+ // starts with 1 and subdirectories don't change the count
+ CHECK(fs::hard_link_count(t.path()) == 1);
+ fs::create_directory("dir");
+ CHECK(fs::hard_link_count(t.path()) == 1);
+#else
+ // unix/bsd/linux typically implements "."/".." as hardlinks
+ // so an empty dir has 2 (from parent and the ".") and
+ // adding a subdirectory adds one due to its ".."
+ CHECK(fs::hard_link_count(t.path()) == getHardlinkCount(t.path()));
+ fs::create_directory("dir");
+ CHECK(fs::hard_link_count(t.path()) == getHardlinkCount(t.path()));
+#endif
+ generateFile("foo");
+ CHECK(fs::hard_link_count(t.path() / "foo") == 1);
+ ec = std::error_code(42, std::system_category());
+ CHECK(fs::hard_link_count(t.path() / "foo", ec) == 1);
+ CHECK(!ec);
+ CHECK_THROWS_AS(fs::hard_link_count(t.path() / "bar"), fs::filesystem_error);
+ CHECK_NOTHROW(fs::hard_link_count(t.path() / "bar", ec));
+ CHECK(ec);
+ ec.clear();
+#else
+ WARN("Test for unsupportet features are disabled on JS/Wasm target.");
+#endif
+}
+
+class FileTypeMixFixture
+{
+public:
+ FileTypeMixFixture()
+ : _t(TempOpt::change_path)
+ , _hasFifo(false)
+ , _hasSocket(false)
+ {
+ generateFile("regular");
+ fs::create_directory("directory");
+ if (is_symlink_creation_supported()) {
+ fs::create_symlink("regular", "file_symlink");
+ fs::create_directory_symlink("directory", "dir_symlink");
+ }
+#if !defined(GHC_OS_WINDOWS) && !defined(GHC_OS_WEB)
+ REQUIRE(::mkfifo("fifo", 0644) == 0);
+ _hasFifo = true;
+ struct ::sockaddr_un addr;
+ addr.sun_family = AF_UNIX;
+ std::strncpy(addr.sun_path, "socket", sizeof(addr.sun_path));
+ int fd = socket(PF_UNIX, SOCK_STREAM, 0);
+ bind(fd, (struct sockaddr*)&addr, sizeof addr);
+ _hasSocket = true;
+#endif
+ }
+
+ ~FileTypeMixFixture() {}
+
+ bool has_fifo() const { return _hasFifo; }
+
+ bool has_socket() const { return _hasSocket; }
+
+ fs::path block_path() const
+ {
+ std::error_code ec;
+ if (fs::exists("/dev/sda", ec)) {
+ return "/dev/sda";
+ }
+ else if (fs::exists("/dev/disk0", ec)) {
+ return "/dev/disk0";
+ }
+ return fs::path();
+ }
+
+ fs::path character_path() const
+ {
+ std::error_code ec;
+ if (fs::exists("/dev/null", ec)) {
+ return "/dev/null";
+ }
+ else if (fs::exists("NUL", ec)) {
+ return "NUL";
+ }
+ return fs::path();
+ }
+ fs::path temp_path() const { return _t.path(); }
+
+private:
+ TemporaryDirectory _t;
+ bool _hasFifo;
+ bool _hasSocket;
+};
+
+TEST_CASE_METHOD(FileTypeMixFixture, "fs.op.is_block_file - is_block_file", "[filesystem][operations][fs.op.is_block_file]")
+{
+ std::error_code ec;
+ CHECK(!fs::is_block_file("directory"));
+ CHECK(!fs::is_block_file("regular"));
+ if (is_symlink_creation_supported()) {
+ CHECK(!fs::is_block_file("dir_symlink"));
+ CHECK(!fs::is_block_file("file_symlink"));
+ }
+ CHECK((has_fifo() ? !fs::is_block_file("fifo") : true));
+ CHECK((has_socket() ? !fs::is_block_file("socket") : true));
+ CHECK((block_path().empty() ? true : fs::is_block_file(block_path())));
+ CHECK((character_path().empty() ? true : !fs::is_block_file(character_path())));
+ CHECK_NOTHROW(fs::is_block_file("notfound"));
+ CHECK_NOTHROW(fs::is_block_file("notfound", ec));
+ CHECK(ec);
+ ec.clear();
+ CHECK(!fs::is_block_file(fs::file_status(fs::file_type::none)));
+ CHECK(!fs::is_block_file(fs::file_status(fs::file_type::not_found)));
+ CHECK(!fs::is_block_file(fs::file_status(fs::file_type::regular)));
+ CHECK(!fs::is_block_file(fs::file_status(fs::file_type::directory)));
+ CHECK(!fs::is_block_file(fs::file_status(fs::file_type::symlink)));
+ CHECK(fs::is_block_file(fs::file_status(fs::file_type::block)));
+ CHECK(!fs::is_block_file(fs::file_status(fs::file_type::character)));
+ CHECK(!fs::is_block_file(fs::file_status(fs::file_type::fifo)));
+ CHECK(!fs::is_block_file(fs::file_status(fs::file_type::socket)));
+ CHECK(!fs::is_block_file(fs::file_status(fs::file_type::unknown)));
+}
+
+TEST_CASE_METHOD(FileTypeMixFixture, "fs.op.is_character_file - is_character_file", "[filesystem][operations][fs.op.is_character_file]")
+{
+ std::error_code ec;
+ CHECK(!fs::is_character_file("directory"));
+ CHECK(!fs::is_character_file("regular"));
+ if (is_symlink_creation_supported()) {
+ CHECK(!fs::is_character_file("dir_symlink"));
+ CHECK(!fs::is_character_file("file_symlink"));
+ }
+ CHECK((has_fifo() ? !fs::is_character_file("fifo") : true));
+ CHECK((has_socket() ? !fs::is_character_file("socket") : true));
+ CHECK((block_path().empty() ? true : !fs::is_character_file(block_path())));
+ CHECK((character_path().empty() ? true : fs::is_character_file(character_path())));
+ CHECK_NOTHROW(fs::is_character_file("notfound"));
+ CHECK_NOTHROW(fs::is_character_file("notfound", ec));
+ CHECK(ec);
+ ec.clear();
+ CHECK(!fs::is_character_file(fs::file_status(fs::file_type::none)));
+ CHECK(!fs::is_character_file(fs::file_status(fs::file_type::not_found)));
+ CHECK(!fs::is_character_file(fs::file_status(fs::file_type::regular)));
+ CHECK(!fs::is_character_file(fs::file_status(fs::file_type::directory)));
+ CHECK(!fs::is_character_file(fs::file_status(fs::file_type::symlink)));
+ CHECK(!fs::is_character_file(fs::file_status(fs::file_type::block)));
+ CHECK(fs::is_character_file(fs::file_status(fs::file_type::character)));
+ CHECK(!fs::is_character_file(fs::file_status(fs::file_type::fifo)));
+ CHECK(!fs::is_character_file(fs::file_status(fs::file_type::socket)));
+ CHECK(!fs::is_character_file(fs::file_status(fs::file_type::unknown)));
+}
+
+TEST_CASE_METHOD(FileTypeMixFixture, "fs.op.is_directory - is_directory", "[filesystem][operations][fs.op.is_directory]")
+{
+ std::error_code ec;
+ CHECK(fs::is_directory("directory"));
+ CHECK(!fs::is_directory("regular"));
+ if (is_symlink_creation_supported()) {
+ CHECK(fs::is_directory("dir_symlink"));
+ CHECK(!fs::is_directory("file_symlink"));
+ }
+ CHECK((has_fifo() ? !fs::is_directory("fifo") : true));
+ CHECK((has_socket() ? !fs::is_directory("socket") : true));
+ CHECK((block_path().empty() ? true : !fs::is_directory(block_path())));
+ CHECK((character_path().empty() ? true : !fs::is_directory(character_path())));
+ CHECK_NOTHROW(fs::is_directory("notfound"));
+ CHECK_NOTHROW(fs::is_directory("notfound", ec));
+ CHECK(ec);
+ ec.clear();
+ CHECK(!fs::is_directory(fs::file_status(fs::file_type::none)));
+ CHECK(!fs::is_directory(fs::file_status(fs::file_type::not_found)));
+ CHECK(!fs::is_directory(fs::file_status(fs::file_type::regular)));
+ CHECK(fs::is_directory(fs::file_status(fs::file_type::directory)));
+ CHECK(!fs::is_directory(fs::file_status(fs::file_type::symlink)));
+ CHECK(!fs::is_directory(fs::file_status(fs::file_type::block)));
+ CHECK(!fs::is_directory(fs::file_status(fs::file_type::character)));
+ CHECK(!fs::is_directory(fs::file_status(fs::file_type::fifo)));
+ CHECK(!fs::is_directory(fs::file_status(fs::file_type::socket)));
+ CHECK(!fs::is_directory(fs::file_status(fs::file_type::unknown)));
+}
+
+TEST_CASE("fs.op.is_empty - is_empty", "[filesystem][operations][fs.op.is_empty]")
+{
+ TemporaryDirectory t(TempOpt::change_path);
+ std::error_code ec;
+ CHECK(fs::is_empty(t.path()));
+ CHECK(fs::is_empty(t.path(), ec));
+ CHECK(!ec);
+ generateFile("foo", 0);
+ generateFile("bar", 1234);
+ CHECK(fs::is_empty("foo"));
+ CHECK(fs::is_empty("foo", ec));
+ CHECK(!ec);
+ CHECK(!fs::is_empty("bar"));
+ CHECK(!fs::is_empty("bar", ec));
+ CHECK(!ec);
+ CHECK_THROWS_AS(fs::is_empty("foobar"), fs::filesystem_error);
+ bool result = false;
+ CHECK_NOTHROW(result = fs::is_empty("foobar", ec));
+ CHECK(!result);
+ CHECK(ec);
+}
+
+TEST_CASE_METHOD(FileTypeMixFixture, "fs.op.is_fifo - is_fifo", "[filesystem][operations][fs.op.is_fifo]")
+{
+ std::error_code ec;
+ CHECK(!fs::is_fifo("directory"));
+ CHECK(!fs::is_fifo("regular"));
+ if (is_symlink_creation_supported()) {
+ CHECK(!fs::is_fifo("dir_symlink"));
+ CHECK(!fs::is_fifo("file_symlink"));
+ }
+ CHECK((has_fifo() ? fs::is_fifo("fifo") : true));
+ CHECK((has_socket() ? !fs::is_fifo("socket") : true));
+ CHECK((block_path().empty() ? true : !fs::is_fifo(block_path())));
+ CHECK((character_path().empty() ? true : !fs::is_fifo(character_path())));
+ CHECK_NOTHROW(fs::is_fifo("notfound"));
+ CHECK_NOTHROW(fs::is_fifo("notfound", ec));
+ CHECK(ec);
+ ec.clear();
+ CHECK(!fs::is_fifo(fs::file_status(fs::file_type::none)));
+ CHECK(!fs::is_fifo(fs::file_status(fs::file_type::not_found)));
+ CHECK(!fs::is_fifo(fs::file_status(fs::file_type::regular)));
+ CHECK(!fs::is_fifo(fs::file_status(fs::file_type::directory)));
+ CHECK(!fs::is_fifo(fs::file_status(fs::file_type::symlink)));
+ CHECK(!fs::is_fifo(fs::file_status(fs::file_type::block)));
+ CHECK(!fs::is_fifo(fs::file_status(fs::file_type::character)));
+ CHECK(fs::is_fifo(fs::file_status(fs::file_type::fifo)));
+ CHECK(!fs::is_fifo(fs::file_status(fs::file_type::socket)));
+ CHECK(!fs::is_fifo(fs::file_status(fs::file_type::unknown)));
+}
+
+TEST_CASE_METHOD(FileTypeMixFixture, "fs.op.is_other - is_other", "[filesystem][operations][fs.op.is_other]")
+{
+ std::error_code ec;
+ CHECK(!fs::is_other("directory"));
+ CHECK(!fs::is_other("regular"));
+ if (is_symlink_creation_supported()) {
+ CHECK(!fs::is_other("dir_symlink"));
+ CHECK(!fs::is_other("file_symlink"));
+ }
+ CHECK((has_fifo() ? fs::is_other("fifo") : true));
+ CHECK((has_socket() ? fs::is_other("socket") : true));
+ CHECK((block_path().empty() ? true : fs::is_other(block_path())));
+ CHECK((character_path().empty() ? true : fs::is_other(character_path())));
+ CHECK_NOTHROW(fs::is_other("notfound"));
+ CHECK_NOTHROW(fs::is_other("notfound", ec));
+ CHECK(ec);
+ ec.clear();
+ CHECK(!fs::is_other(fs::file_status(fs::file_type::none)));
+ CHECK(!fs::is_other(fs::file_status(fs::file_type::not_found)));
+ CHECK(!fs::is_other(fs::file_status(fs::file_type::regular)));
+ CHECK(!fs::is_other(fs::file_status(fs::file_type::directory)));
+ CHECK(!fs::is_other(fs::file_status(fs::file_type::symlink)));
+ CHECK(fs::is_other(fs::file_status(fs::file_type::block)));
+ CHECK(fs::is_other(fs::file_status(fs::file_type::character)));
+ CHECK(fs::is_other(fs::file_status(fs::file_type::fifo)));
+ CHECK(fs::is_other(fs::file_status(fs::file_type::socket)));
+ CHECK(fs::is_other(fs::file_status(fs::file_type::unknown)));
+}
+
+TEST_CASE_METHOD(FileTypeMixFixture, "fs.op.is_regular_file - is_regular_file", "[filesystem][operations][fs.op.is_regular_file]")
+{
+ std::error_code ec;
+ CHECK(!fs::is_regular_file("directory"));
+ CHECK(fs::is_regular_file("regular"));
+ if (is_symlink_creation_supported()) {
+ CHECK(!fs::is_regular_file("dir_symlink"));
+ CHECK(fs::is_regular_file("file_symlink"));
+ }
+ CHECK((has_fifo() ? !fs::is_regular_file("fifo") : true));
+ CHECK((has_socket() ? !fs::is_regular_file("socket") : true));
+ CHECK((block_path().empty() ? true : !fs::is_regular_file(block_path())));
+ CHECK((character_path().empty() ? true : !fs::is_regular_file(character_path())));
+ CHECK_NOTHROW(fs::is_regular_file("notfound"));
+ CHECK_NOTHROW(fs::is_regular_file("notfound", ec));
+ CHECK(ec);
+ ec.clear();
+ CHECK(!fs::is_regular_file(fs::file_status(fs::file_type::none)));
+ CHECK(!fs::is_regular_file(fs::file_status(fs::file_type::not_found)));
+ CHECK(fs::is_regular_file(fs::file_status(fs::file_type::regular)));
+ CHECK(!fs::is_regular_file(fs::file_status(fs::file_type::directory)));
+ CHECK(!fs::is_regular_file(fs::file_status(fs::file_type::symlink)));
+ CHECK(!fs::is_regular_file(fs::file_status(fs::file_type::block)));
+ CHECK(!fs::is_regular_file(fs::file_status(fs::file_type::character)));
+ CHECK(!fs::is_regular_file(fs::file_status(fs::file_type::fifo)));
+ CHECK(!fs::is_regular_file(fs::file_status(fs::file_type::socket)));
+ CHECK(!fs::is_regular_file(fs::file_status(fs::file_type::unknown)));
+}
+
+TEST_CASE_METHOD(FileTypeMixFixture, "fs.op.is_socket - is_socket", "[filesystem][operations][fs.op.is_socket]")
+{
+ std::error_code ec;
+ CHECK(!fs::is_socket("directory"));
+ CHECK(!fs::is_socket("regular"));
+ if (is_symlink_creation_supported()) {
+ CHECK(!fs::is_socket("dir_symlink"));
+ CHECK(!fs::is_socket("file_symlink"));
+ }
+ CHECK((has_fifo() ? !fs::is_socket("fifo") : true));
+ CHECK((has_socket() ? fs::is_socket("socket") : true));
+ CHECK((block_path().empty() ? true : !fs::is_socket(block_path())));
+ CHECK((character_path().empty() ? true : !fs::is_socket(character_path())));
+ CHECK_NOTHROW(fs::is_socket("notfound"));
+ CHECK_NOTHROW(fs::is_socket("notfound", ec));
+ CHECK(ec);
+ ec.clear();
+ CHECK(!fs::is_socket(fs::file_status(fs::file_type::none)));
+ CHECK(!fs::is_socket(fs::file_status(fs::file_type::not_found)));
+ CHECK(!fs::is_socket(fs::file_status(fs::file_type::regular)));
+ CHECK(!fs::is_socket(fs::file_status(fs::file_type::directory)));
+ CHECK(!fs::is_socket(fs::file_status(fs::file_type::symlink)));
+ CHECK(!fs::is_socket(fs::file_status(fs::file_type::block)));
+ CHECK(!fs::is_socket(fs::file_status(fs::file_type::character)));
+ CHECK(!fs::is_socket(fs::file_status(fs::file_type::fifo)));
+ CHECK(fs::is_socket(fs::file_status(fs::file_type::socket)));
+ CHECK(!fs::is_socket(fs::file_status(fs::file_type::unknown)));
+}
+
+TEST_CASE_METHOD(FileTypeMixFixture, "fs.op.is_symlink - is_symlink", "[filesystem][operations][fs.op.is_symlink]")
+{
+ std::error_code ec;
+ CHECK(!fs::is_symlink("directory"));
+ CHECK(!fs::is_symlink("regular"));
+ if (is_symlink_creation_supported()) {
+ CHECK(fs::is_symlink("dir_symlink"));
+ CHECK(fs::is_symlink("file_symlink"));
+ }
+ CHECK((has_fifo() ? !fs::is_symlink("fifo") : true));
+ CHECK((has_socket() ? !fs::is_symlink("socket") : true));
+ CHECK((block_path().empty() ? true : !fs::is_symlink(block_path())));
+ CHECK((character_path().empty() ? true : !fs::is_symlink(character_path())));
+ CHECK_NOTHROW(fs::is_symlink("notfound"));
+ CHECK_NOTHROW(fs::is_symlink("notfound", ec));
+ CHECK(ec);
+ ec.clear();
+ CHECK(!fs::is_symlink(fs::file_status(fs::file_type::none)));
+ CHECK(!fs::is_symlink(fs::file_status(fs::file_type::not_found)));
+ CHECK(!fs::is_symlink(fs::file_status(fs::file_type::regular)));
+ CHECK(!fs::is_symlink(fs::file_status(fs::file_type::directory)));
+ CHECK(fs::is_symlink(fs::file_status(fs::file_type::symlink)));
+ CHECK(!fs::is_symlink(fs::file_status(fs::file_type::block)));
+ CHECK(!fs::is_symlink(fs::file_status(fs::file_type::character)));
+ CHECK(!fs::is_symlink(fs::file_status(fs::file_type::fifo)));
+ CHECK(!fs::is_symlink(fs::file_status(fs::file_type::socket)));
+ CHECK(!fs::is_symlink(fs::file_status(fs::file_type::unknown)));
+}
+
+#ifndef GHC_OS_WEB
+static fs::file_time_type timeFromString(const std::string& str)
+{
+ struct ::tm tm;
+ ::memset(&tm, 0, sizeof(::tm));
+ std::istringstream is(str);
+ is >> std::get_time(&tm, "%Y-%m-%dT%H:%M:%S");
+ if (is.fail()) {
+ throw std::exception();
+ }
+ return from_time_t<fs::file_time_type>(std::mktime(&tm));
+}
+#endif
+
+TEST_CASE("fs.op.last_write_time - last_write_time", "[filesystem][operations][fs.op.last_write_time]")
+{
+ TemporaryDirectory t(TempOpt::change_path);
+ std::error_code ec;
+ fs::file_time_type ft;
+ generateFile("foo");
+ auto now = fs::file_time_type::clock::now();
+ CHECK(std::abs(std::chrono::duration_cast<std::chrono::seconds>(fs::last_write_time(t.path()) - now).count()) < 3);
+ CHECK(std::abs(std::chrono::duration_cast<std::chrono::seconds>(fs::last_write_time("foo") - now).count()) < 3);
+ CHECK_THROWS_AS(fs::last_write_time("bar"), fs::filesystem_error);
+ CHECK_NOTHROW(ft = fs::last_write_time("bar", ec));
+ CHECK(ft == fs::file_time_type::min());
+ CHECK(ec);
+ ec.clear();
+ if (is_symlink_creation_supported()) {
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+ fs::create_symlink("foo", "foo2");
+ ft = fs::last_write_time("foo");
+ // checks that the time of the symlink is fetched
+ CHECK(ft == fs::last_write_time("foo2"));
+ }
+#ifndef GHC_OS_WEB
+ auto nt = timeFromString("2015-10-21T04:30:00");
+ CHECK_NOTHROW(fs::last_write_time(t.path() / "foo", nt));
+ CHECK(std::abs(std::chrono::duration_cast<std::chrono::seconds>(fs::last_write_time("foo") - nt).count()) < 1);
+ nt = timeFromString("2015-10-21T04:29:00");
+ CHECK_NOTHROW(fs::last_write_time("foo", nt, ec));
+ CHECK(std::abs(std::chrono::duration_cast<std::chrono::seconds>(fs::last_write_time("foo") - nt).count()) < 1);
+ CHECK(!ec);
+ CHECK_THROWS_AS(fs::last_write_time("bar", nt), fs::filesystem_error);
+ CHECK_NOTHROW(fs::last_write_time("bar", nt, ec));
+ CHECK(ec);
+#endif
+}
+
+TEST_CASE("fs.op.permissions - permissions", "[filesystem][operations][fs.op.permissions]")
+{
+ TemporaryDirectory t(TempOpt::change_path);
+ std::error_code ec;
+ generateFile("foo", 512);
+ auto allWrite = fs::perms::owner_write | fs::perms::group_write | fs::perms::others_write;
+ CHECK_NOTHROW(fs::permissions("foo", allWrite, fs::perm_options::remove));
+ CHECK((fs::status("foo").permissions() & fs::perms::owner_write) != fs::perms::owner_write);
+#if !defined(GHC_OS_WINDOWS)
+ if (geteuid() != 0)
+#endif
+ {
+ CHECK_THROWS_AS(fs::resize_file("foo", 1024), fs::filesystem_error);
+ CHECK(fs::file_size("foo") == 512);
+ }
+ CHECK_NOTHROW(fs::permissions("foo", fs::perms::owner_write, fs::perm_options::add));
+ CHECK((fs::status("foo").permissions() & fs::perms::owner_write) == fs::perms::owner_write);
+ CHECK_NOTHROW(fs::resize_file("foo", 2048));
+ CHECK(fs::file_size("foo") == 2048);
+ CHECK_THROWS_AS(fs::permissions("bar", fs::perms::owner_write, fs::perm_options::add), fs::filesystem_error);
+ CHECK_NOTHROW(fs::permissions("bar", fs::perms::owner_write, fs::perm_options::add, ec));
+ CHECK(ec);
+ CHECK_THROWS_AS(fs::permissions("bar", fs::perms::owner_write, static_cast<fs::perm_options>(0)), fs::filesystem_error);
+}
+
+TEST_CASE("fs.op.proximate - proximate", "[filesystem][operations][fs.op.proximate]")
+{
+ std::error_code ec;
+ CHECK(fs::proximate("/a/d", "/a/b/c") == "../../d");
+ CHECK(fs::proximate("/a/d", "/a/b/c", ec) == "../../d");
+ CHECK(!ec);
+ CHECK(fs::proximate("/a/b/c", "/a/d") == "../b/c");
+ CHECK(fs::proximate("/a/b/c", "/a/d", ec) == "../b/c");
+ CHECK(!ec);
+ CHECK(fs::proximate("a/b/c", "a") == "b/c");
+ CHECK(fs::proximate("a/b/c", "a", ec) == "b/c");
+ CHECK(!ec);
+ CHECK(fs::proximate("a/b/c", "a/b/c/x/y") == "../..");
+ CHECK(fs::proximate("a/b/c", "a/b/c/x/y", ec) == "../..");
+ CHECK(!ec);
+ CHECK(fs::proximate("a/b/c", "a/b/c") == ".");
+ CHECK(fs::proximate("a/b/c", "a/b/c", ec) == ".");
+ CHECK(!ec);
+ CHECK(fs::proximate("a/b", "c/d") == "../../a/b");
+ CHECK(fs::proximate("a/b", "c/d", ec) == "../../a/b");
+ CHECK(!ec);
+#ifndef GHC_OS_WINDOWS
+ if (has_host_root_name_support()) {
+ CHECK(fs::proximate("//host1/a/d", "//host2/a/b/c") == "//host1/a/d");
+ CHECK(fs::proximate("//host1/a/d", "//host2/a/b/c", ec) == "//host1/a/d");
+ CHECK(!ec);
+ }
+#endif
+}
+
+TEST_CASE("fs.op.read_symlink - read_symlink", "[filesystem][operations][fs.op.read_symlink]")
+{
+ if (is_symlink_creation_supported()) {
+ TemporaryDirectory t(TempOpt::change_path);
+ std::error_code ec;
+ generateFile("foo");
+ fs::create_symlink(t.path() / "foo", "bar");
+ CHECK(fs::read_symlink("bar") == t.path() / "foo");
+ CHECK(fs::read_symlink("bar", ec) == t.path() / "foo");
+ CHECK(!ec);
+ CHECK_THROWS_AS(fs::read_symlink("foobar"), fs::filesystem_error);
+ CHECK(fs::read_symlink("foobar", ec) == fs::path());
+ CHECK(ec);
+ }
+}
+
+TEST_CASE("fs.op.relative - relative", "[filesystem][operations][fs.op.relative]")
+{
+ CHECK(fs::relative("/a/d", "/a/b/c") == "../../d");
+ CHECK(fs::relative("/a/b/c", "/a/d") == "../b/c");
+ CHECK(fs::relative("a/b/c", "a") == "b/c");
+ CHECK(fs::relative("a/b/c", "a/b/c/x/y") == "../..");
+ CHECK(fs::relative("a/b/c", "a/b/c") == ".");
+ CHECK(fs::relative("a/b", "c/d") == "../../a/b");
+ std::error_code ec;
+ CHECK(fs::relative(fs::current_path() / "foo", ec) == "foo");
+ CHECK(!ec);
+}
+
+TEST_CASE("fs.op.remove - remove", "[filesystem][operations][fs.op.remove]")
+{
+ TemporaryDirectory t(TempOpt::change_path);
+ std::error_code ec;
+ generateFile("foo");
+ CHECK(fs::remove("foo"));
+ CHECK(!fs::exists("foo"));
+ CHECK(!fs::remove("foo"));
+ generateFile("foo");
+ CHECK(fs::remove("foo", ec));
+ CHECK(!fs::exists("foo"));
+ if (is_symlink_creation_supported()) {
+ generateFile("foo");
+ fs::create_symlink("foo", "bar");
+ CHECK(fs::exists(fs::symlink_status("bar")));
+ CHECK(fs::remove("bar", ec));
+ CHECK(fs::exists("foo"));
+ CHECK(!fs::exists(fs::symlink_status("bar")));
+ }
+ CHECK(!fs::remove("bar"));
+ CHECK(!fs::remove("bar", ec));
+ CHECK(!ec);
+}
+
+TEST_CASE("fs.op.remove_all - remove_all", "[filesystem][operations][fs.op.remove_all]")
+{
+ TemporaryDirectory t(TempOpt::change_path);
+ std::error_code ec;
+ generateFile("foo");
+ CHECK(fs::remove_all("foo", ec) == 1);
+ CHECK(!ec);
+ ec.clear();
+ CHECK(fs::directory_iterator(t.path()) == fs::directory_iterator());
+ fs::create_directories("dir1/dir1a");
+ fs::create_directories("dir1/dir1b");
+ generateFile("dir1/dir1a/f1");
+ generateFile("dir1/dir1b/f2");
+ CHECK_NOTHROW(fs::remove_all("dir1/non-existing", ec));
+ CHECK(!ec);
+ CHECK(fs::remove_all("dir1/non-existing", ec) == 0);
+ if (is_symlink_creation_supported()) {
+ fs::create_directory_symlink("dir1", "dir1link");
+ CHECK(fs::remove_all("dir1link") == 1);
+ }
+ CHECK(fs::remove_all("dir1") == 5);
+ CHECK(fs::directory_iterator(t.path()) == fs::directory_iterator());
+}
+
+TEST_CASE("fs.op.rename - rename", "[filesystem][operations][fs.op.rename]")
+{
+ TemporaryDirectory t(TempOpt::change_path);
+ std::error_code ec;
+ generateFile("foo", 123);
+ fs::create_directory("dir1");
+ CHECK_NOTHROW(fs::rename("foo", "bar"));
+ CHECK(!fs::exists("foo"));
+ CHECK(fs::exists("bar"));
+ CHECK_NOTHROW(fs::rename("dir1", "dir2"));
+ CHECK(fs::exists("dir2"));
+ generateFile("foo2", 42);
+ CHECK_NOTHROW(fs::rename("bar", "foo2"));
+ CHECK(fs::exists("foo2"));
+ CHECK(fs::file_size("foo2") == 123u);
+ CHECK(!fs::exists("bar"));
+ CHECK_NOTHROW(fs::rename("foo2", "foo", ec));
+ CHECK(!ec);
+ CHECK_THROWS_AS(fs::rename("foobar", "barfoo"), fs::filesystem_error);
+ CHECK_NOTHROW(fs::rename("foobar", "barfoo", ec));
+ CHECK(ec);
+ CHECK(!fs::exists("barfoo"));
+}
+
+TEST_CASE("fs.op.resize_file - resize_file", "[filesystem][operations][fs.op.resize_file]")
+{
+ TemporaryDirectory t(TempOpt::change_path);
+ std::error_code ec;
+ generateFile("foo", 1024);
+ CHECK(fs::file_size("foo") == 1024);
+ CHECK_NOTHROW(fs::resize_file("foo", 2048));
+ CHECK(fs::file_size("foo") == 2048);
+ CHECK_NOTHROW(fs::resize_file("foo", 1000, ec));
+ CHECK(!ec);
+ CHECK(fs::file_size("foo") == 1000);
+ CHECK_THROWS_AS(fs::resize_file("bar", 2048), fs::filesystem_error);
+ CHECK(!fs::exists("bar"));
+ CHECK_NOTHROW(fs::resize_file("bar", 4096, ec));
+ CHECK(ec);
+ CHECK(!fs::exists("bar"));
+}
+
+TEST_CASE("fs.op.space - space", "[filesystem][operations][fs.op.space]")
+{
+ {
+ fs::space_info si;
+ CHECK_NOTHROW(si = fs::space(fs::current_path()));
+ CHECK(si.capacity > 1024 * 1024);
+ CHECK(si.capacity > si.free);
+ CHECK(si.free >= si.available);
+ }
+ {
+ std::error_code ec;
+ fs::space_info si;
+ CHECK_NOTHROW(si = fs::space(fs::current_path(), ec));
+ CHECK(si.capacity > 1024 * 1024);
+ CHECK(si.capacity > si.free);
+ CHECK(si.free >= si.available);
+ CHECK(!ec);
+ }
+#ifndef GHC_OS_WEB // statvfs under emscripten always returns a result, so this tests would fail
+ {
+ std::error_code ec;
+ fs::space_info si;
+ CHECK_NOTHROW(si = fs::space("foobar42", ec));
+ CHECK(si.capacity == static_cast<uintmax_t>(-1));
+ CHECK(si.free == static_cast<uintmax_t>(-1));
+ CHECK(si.available == static_cast<uintmax_t>(-1));
+ CHECK(ec);
+ }
+ CHECK_THROWS_AS(fs::space("foobar42"), fs::filesystem_error);
+#endif
+}
+
+TEST_CASE("fs.op.status - status", "[filesystem][operations][fs.op.status]")
+{
+ TemporaryDirectory t(TempOpt::change_path);
+ std::error_code ec;
+ fs::file_status fs;
+ CHECK_NOTHROW(fs = fs::status("foo"));
+ CHECK(fs.type() == fs::file_type::not_found);
+ CHECK(fs.permissions() == fs::perms::unknown);
+ CHECK_NOTHROW(fs = fs::status("bar", ec));
+ CHECK(fs.type() == fs::file_type::not_found);
+ CHECK(fs.permissions() == fs::perms::unknown);
+ CHECK(ec);
+ ec.clear();
+ fs = fs::status(t.path());
+ CHECK(fs.type() == fs::file_type::directory);
+ CHECK((fs.permissions() & (fs::perms::owner_read | fs::perms::owner_write)) == (fs::perms::owner_read | fs::perms::owner_write));
+ generateFile("foobar");
+ fs = fs::status(t.path() / "foobar");
+ CHECK(fs.type() == fs::file_type::regular);
+ CHECK((fs.permissions() & (fs::perms::owner_read | fs::perms::owner_write)) == (fs::perms::owner_read | fs::perms::owner_write));
+ if (is_symlink_creation_supported()) {
+ fs::create_symlink(t.path() / "foobar", t.path() / "barfoo");
+ fs = fs::status(t.path() / "barfoo");
+ CHECK(fs.type() == fs::file_type::regular);
+ CHECK((fs.permissions() & (fs::perms::owner_read | fs::perms::owner_write)) == (fs::perms::owner_read | fs::perms::owner_write));
+ }
+}
+
+TEST_CASE("fs.op.status_known - status_known", "[filesystem][operations][fs.op.status_known]")
+{
+ CHECK(!fs::status_known(fs::file_status()));
+ CHECK(fs::status_known(fs::file_status(fs::file_type::not_found)));
+ CHECK(fs::status_known(fs::file_status(fs::file_type::regular)));
+ CHECK(fs::status_known(fs::file_status(fs::file_type::directory)));
+ CHECK(fs::status_known(fs::file_status(fs::file_type::symlink)));
+ CHECK(fs::status_known(fs::file_status(fs::file_type::character)));
+ CHECK(fs::status_known(fs::file_status(fs::file_type::fifo)));
+ CHECK(fs::status_known(fs::file_status(fs::file_type::socket)));
+ CHECK(fs::status_known(fs::file_status(fs::file_type::unknown)));
+}
+
+TEST_CASE("fs.op.symlink_status - symlink_status", "[filesystem][operations][fs.op.symlink_status]")
+{
+ TemporaryDirectory t(TempOpt::change_path);
+ std::error_code ec;
+ fs::file_status fs;
+ CHECK_NOTHROW(fs = fs::symlink_status("foo"));
+ CHECK(fs.type() == fs::file_type::not_found);
+ CHECK(fs.permissions() == fs::perms::unknown);
+ CHECK_NOTHROW(fs = fs::symlink_status("bar", ec));
+ CHECK(fs.type() == fs::file_type::not_found);
+ CHECK(fs.permissions() == fs::perms::unknown);
+ CHECK(ec);
+ ec.clear();
+ fs = fs::symlink_status(t.path());
+ CHECK(fs.type() == fs::file_type::directory);
+ CHECK((fs.permissions() & (fs::perms::owner_read | fs::perms::owner_write)) == (fs::perms::owner_read | fs::perms::owner_write));
+ generateFile("foobar");
+ fs = fs::symlink_status(t.path() / "foobar");
+ CHECK(fs.type() == fs::file_type::regular);
+ CHECK((fs.permissions() & (fs::perms::owner_read | fs::perms::owner_write)) == (fs::perms::owner_read | fs::perms::owner_write));
+ if (is_symlink_creation_supported()) {
+ fs::create_symlink(t.path() / "foobar", t.path() / "barfoo");
+ fs = fs::symlink_status(t.path() / "barfoo");
+ CHECK(fs.type() == fs::file_type::symlink);
+ }
+}
+
+TEST_CASE("fs.op.temp_dir_path - temporary_directory_path", "[filesystem][operations][fs.op.temp_dir_path]")
+{
+ std::error_code ec;
+ CHECK_NOTHROW(fs::exists(fs::temp_directory_path()));
+ CHECK_NOTHROW(fs::exists(fs::temp_directory_path(ec)));
+ CHECK(!fs::temp_directory_path().empty());
+ CHECK(!ec);
+}
+
+TEST_CASE("fs.op.weakly_canonical - weakly_canonical", "[filesystem][operations][fs.op.weakly_canonical]")
+{
+ INFO("This might fail on std::implementations that return fs::current_path() for fs::canonical(\"\")");
+ CHECK(fs::weakly_canonical("") == ".");
+ if(fs::weakly_canonical("") == ".") {
+ CHECK(fs::weakly_canonical("foo/bar") == "foo/bar");
+ CHECK(fs::weakly_canonical("foo/./bar") == "foo/bar");
+ CHECK(fs::weakly_canonical("foo/../bar") == "bar");
+ }
+ else {
+ CHECK(fs::weakly_canonical("foo/bar") == fs::current_path() / "foo/bar");
+ CHECK(fs::weakly_canonical("foo/./bar") == fs::current_path() / "foo/bar");
+ CHECK(fs::weakly_canonical("foo/../bar") == fs::current_path() / "bar");
+ }
+
+ {
+ TemporaryDirectory t(TempOpt::change_path);
+ auto dir = t.path() / "d0";
+ fs::create_directories(dir / "d1");
+ generateFile(dir / "f0");
+ fs::path rel(dir.filename());
+ CHECK(fs::weakly_canonical(dir) == dir);
+ CHECK(fs::weakly_canonical(rel) == dir);
+ CHECK(fs::weakly_canonical(dir / "f0") == dir / "f0");
+ CHECK(fs::weakly_canonical(dir / "f0/") == dir / "f0/");
+ CHECK(fs::weakly_canonical(dir / "f1") == dir / "f1");
+ CHECK(fs::weakly_canonical(rel / "f0") == dir / "f0");
+ CHECK(fs::weakly_canonical(rel / "f0/") == dir / "f0/");
+ CHECK(fs::weakly_canonical(rel / "f1") == dir / "f1");
+ CHECK(fs::weakly_canonical(rel / "./f0") == dir / "f0");
+ CHECK(fs::weakly_canonical(rel / "./f1") == dir / "f1");
+ CHECK(fs::weakly_canonical(rel / "d1/../f0") == dir / "f0");
+ CHECK(fs::weakly_canonical(rel / "d1/../f1") == dir / "f1");
+ CHECK(fs::weakly_canonical(rel / "d1/../f1/../f2") == dir / "f2");
+ }
+}
+
+TEST_CASE("std::string_view support", "[filesystem][fs.string_view]")
+{
+#if defined(GHC_HAS_STD_STRING_VIEW) || defined(GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW)
+
+#if defined(GHC_HAS_STD_STRING_VIEW)
+ using namespace std::literals;
+ using string_view = std::string_view;
+ using wstring_view = std::wstring_view;
+#elif defined(GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW)
+ using string_view = std::experimental::string_view;
+ using wstring_view = std::experimental::wstring_view;
+#endif
+
+ {
+ std::string p("foo/bar");
+ string_view sv(p);
+ CHECK(fs::path(sv, fs::path::format::generic_format).generic_string() == "foo/bar");
+ fs::path p2("fo");
+ p2 += string_view("o");
+ CHECK(p2 == "foo");
+ CHECK(p2.compare(string_view("foo")) == 0);
+ }
+ {
+ auto p = fs::path{"XYZ"};
+ p /= string_view("Appendix");
+ CHECK(p == "XYZ/Appendix");
+ }
+ {
+ std::wstring p(L"foo/bar");
+ wstring_view sv(p);
+ CHECK(fs::path(sv, fs::path::format::generic_format).generic_string() == "foo/bar");
+ fs::path p2(L"fo");
+ p2 += wstring_view(L"o");
+ CHECK(p2 == "foo");
+ CHECK(p2.compare(wstring_view(L"foo")) == 0);
+ }
+
+#else
+ WARN("std::string_view specific tests are empty without std::string_view.");
+#endif
+}
+
+TEST_CASE("Windows: Long filename support", "[filesystem][path][fs.path.win.long]")
+{
+#ifdef GHC_OS_WINDOWS
+ TemporaryDirectory t(TempOpt::change_path);
+ char c = 'A';
+ fs::path dir{"\\\\?\\"};
+ dir += fs::current_path().u8string();
+ for (; c <= 'Z'; ++c) {
+ std::string part = std::string(16, c);
+ dir /= part;
+ CHECK_NOTHROW(fs::create_directory(dir));
+ CHECK(fs::exists(dir));
+ generateFile(dir / "f0");
+ REQUIRE(fs::exists(dir / "f0"));
+ }
+ CHECK(c > 'Z');
+ fs::remove_all(fs::current_path() / std::string(16, 'A'));
+ CHECK(!fs::exists(fs::current_path() / std::string(16, 'A')));
+ CHECK_NOTHROW(fs::create_directories(dir));
+ CHECK(fs::exists(dir));
+ generateFile(dir / "f0");
+ CHECK(fs::exists(dir / "f0"));
+#else
+ WARN("Windows specific tests are empty on non-Windows systems.");
+#endif
+}
+
+TEST_CASE("Windows: path namespace handling", "[filesystem][path][fs.path.win.namespaces]")
+{
+#ifdef GHC_OS_WINDOWS
+ {
+ std::error_code ec;
+ fs::path p(R"(\\localhost\c$\Windows)");
+ auto symstat = fs::symlink_status(p, ec);
+ CHECK(!ec);
+ auto p2 = fs::canonical(p, ec);
+ CHECK(!ec);
+ CHECK(p2 == p);
+ }
+
+ struct TestInfo
+ {
+ std::string _path;
+ std::string _string;
+ std::string _rootName;
+ std::string _rootPath;
+ std::string _iterateResult;
+ };
+ std::vector<TestInfo> variants = {
+ {R"(C:\Windows\notepad.exe)", R"(C:\Windows\notepad.exe)", "C:", "C:\\", "C:,/,Windows,notepad.exe"},
+#ifdef USE_STD_FS
+ {R"(\\?\C:\Windows\notepad.exe)", R"(\\?\C:\Windows\notepad.exe)", "\\\\?", "\\\\?\\", "//?,/,C:,Windows,notepad.exe"},
+ {R"(\??\C:\Windows\notepad.exe)", R"(\??\C:\Windows\notepad.exe)", "\\??", "\\??\\", "/??,/,C:,Windows,notepad.exe"},
+#else
+ {R"(\\?\C:\Windows\notepad.exe)", R"(\\?\C:\Windows\notepad.exe)", "C:", "C:\\", "//?/,C:,/,Windows,notepad.exe"},
+ {R"(\??\C:\Windows\notepad.exe)", R"(\??\C:\Windows\notepad.exe)", "C:", "C:\\", "/?\?/,C:,/,Windows,notepad.exe"},
+#endif
+ {R"(\\.\C:\Windows\notepad.exe)", R"(\\.\C:\Windows\notepad.exe)", "\\\\.", "\\\\.\\", "//.,/,C:,Windows,notepad.exe"},
+ {R"(\\?\HarddiskVolume1\Windows\notepad.exe)", R"(\\?\HarddiskVolume1\Windows\notepad.exe)", "\\\\?", "\\\\?\\", "//?,/,HarddiskVolume1,Windows,notepad.exe"},
+ {R"(\\?\Harddisk0Partition1\Windows\notepad.exe)", R"(\\?\Harddisk0Partition1\Windows\notepad.exe)", "\\\\?", "\\\\?\\", "//?,/,Harddisk0Partition1,Windows,notepad.exe"},
+ {R"(\\.\GLOBALROOT\Device\HarddiskVolume1\Windows\notepad.exe)", R"(\\.\GLOBALROOT\Device\HarddiskVolume1\Windows\notepad.exe)", "\\\\.", "\\\\.\\", "//.,/,GLOBALROOT,Device,HarddiskVolume1,Windows,notepad.exe"},
+ {R"(\\?\GLOBALROOT\Device\Harddisk0\Partition1\Windows\notepad.exe)", R"(\\?\GLOBALROOT\Device\Harddisk0\Partition1\Windows\notepad.exe)", "\\\\?", "\\\\?\\", "//?,/,GLOBALROOT,Device,Harddisk0,Partition1,Windows,notepad.exe"},
+ {R"(\\?\Volume{e8a4a89d-0000-0000-0000-100000000000}\Windows\notepad.exe)", R"(\\?\Volume{e8a4a89d-0000-0000-0000-100000000000}\Windows\notepad.exe)", "\\\\?", "\\\\?\\", "//?,/,Volume{e8a4a89d-0000-0000-0000-100000000000},Windows,notepad.exe"},
+ {R"(\\LOCALHOST\C$\Windows\notepad.exe)", R"(\\LOCALHOST\C$\Windows\notepad.exe)", "\\\\LOCALHOST", "\\\\LOCALHOST\\", "//LOCALHOST,/,C$,Windows,notepad.exe"},
+ {R"(\\?\UNC\C$\Windows\notepad.exe)", R"(\\?\UNC\C$\Windows\notepad.exe)", "\\\\?", "\\\\?\\", "//?,/,UNC,C$,Windows,notepad.exe"},
+ {R"(\\?\GLOBALROOT\Device\Mup\C$\Windows\notepad.exe)", R"(\\?\GLOBALROOT\Device\Mup\C$\Windows\notepad.exe)", "\\\\?", "\\\\?\\", "//?,/,GLOBALROOT,Device,Mup,C$,Windows,notepad.exe"},
+ };
+
+ for (auto ti : variants) {
+ INFO("Used path: " + ti._path);
+ auto p = fs::path(ti._path);
+ CHECK(p.string() == ti._string);
+ CHECK(p.is_absolute());
+ CHECK(p.root_name().string() == ti._rootName);
+ CHECK(p.root_path().string() == ti._rootPath);
+ CHECK(iterateResult(p) == ti._iterateResult);
+ }
+#else
+ WARN("Windows specific tests are empty on non-Windows systems.");
+#endif
+}
+
+TEST_CASE("Windows: Mapped folders handling ", "[filesystem][fs.win][fs.win.mapped]")
+{
+#ifdef GHC_OS_WINDOWS
+ // this test expects a mapped volume on C:\\fs-test as is the case on the development test system
+ // does nothing on other systems
+ if (fs::exists("C:\\fs-test")) {
+ CHECK(fs::canonical("C:\\fs-test\\Test.txt").string() == "C:\\fs-test\\Test.txt");
+ }
+#else
+ WARN("Windows specific tests are empty on non-Windows systems.");
+#endif
+}
+
+TEST_CASE("Windows: Deletion of Read-only Files", "[filesystem][fs.win][fs.win.remove]")
+{
+#ifdef GHC_OS_WINDOWS
+ TemporaryDirectory t(TempOpt::change_path);
+ std::error_code ec;
+ generateFile("foo", 512);
+ auto allWrite = fs::perms::owner_write | fs::perms::group_write | fs::perms::others_write;
+ CHECK_NOTHROW(fs::permissions("foo", allWrite, fs::perm_options::remove));
+ CHECK_NOTHROW(fs::remove("foo"));
+ CHECK(!fs::exists("foo"));
+#else
+ WARN("Windows specific tests are empty on non-Windows systems.");
+#endif
+}
diff --git a/gulrak-filesystem/test/fwd_test.cpp b/gulrak-filesystem/test/fwd_test.cpp
new file mode 100644
index 0000000..7905707
--- /dev/null
+++ b/gulrak-filesystem/test/fwd_test.cpp
@@ -0,0 +1,7 @@
+// This test file is part of the fwd_test.cpp/impl_test.cpp pair
+// and used to test the new optional two-part usage of ghc::filesystem
+// where exactly one cpp includes fs_impl.hpp and all others use
+// fs_fwd.hpp (to test this with maximum functionality, the unit tests
+// are included here, signaling they should only include the fs_fwd.hpp)
+#define GHC_FILESYSTEM_FWD_TEST
+#include "filesystem_test.cpp"
diff --git a/gulrak-filesystem/test/impl_test.cpp b/gulrak-filesystem/test/impl_test.cpp
new file mode 100644
index 0000000..092be63
--- /dev/null
+++ b/gulrak-filesystem/test/impl_test.cpp
@@ -0,0 +1,8 @@
+// This test file is part of the fwd_test.cpp/impl_test.cpp pair
+// and used to test the new optional two-part usage of ghc::filesystem
+// where exactly one cpp includes fs_impl.hpp and all others use
+// fs_fwd.hpp (to test this with maximum functionality, the unit tests
+// are included here, signaling they should only include the fs_fwd.hpp)
+#include <ghc/fs_impl.hpp>
+#define CATCH_CONFIG_MAIN
+#include "catch.hpp"
diff --git a/gulrak-filesystem/test/multi1.cpp b/gulrak-filesystem/test/multi1.cpp
new file mode 100644
index 0000000..6a9fac4
--- /dev/null
+++ b/gulrak-filesystem/test/multi1.cpp
@@ -0,0 +1,42 @@
+//---------------------------------------------------------------------------------------
+//
+// Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+//---------------------------------------------------------------------------------------
+#define CATCH_CONFIG_MAIN
+#include "catch.hpp"
+
+#include <ghc/filesystem.hpp>
+namespace fs = ghc::filesystem;
+
+// This test and the one in multi2.cpp doesn't actualy test relevant functionality,
+// it is just used to check that it is possible to include filesystem.h in multiple
+// source files.
+TEST_CASE("Multifile-test 1", "[multi]")
+{
+ CHECK("/usr/local/bin" == fs::path("/usr/local/bin").generic_string());
+ std::string str = "/usr/local/bin";
+ std::u16string u16str = u"/usr/local/bin";
+ std::u32string u32str = U"/usr/local/bin";
+ CHECK(str == fs::path(str.begin(), str.end()));
+ CHECK(str == fs::path(u16str.begin(), u16str.end()));
+ CHECK(str == fs::path(u32str.begin(), u32str.end()));
+}
diff --git a/gulrak-filesystem/test/multi2.cpp b/gulrak-filesystem/test/multi2.cpp
new file mode 100644
index 0000000..6bf3250
--- /dev/null
+++ b/gulrak-filesystem/test/multi2.cpp
@@ -0,0 +1,40 @@
+//---------------------------------------------------------------------------------------
+//
+// Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+//---------------------------------------------------------------------------------------
+#include "catch.hpp"
+#include <ghc/filesystem.hpp>
+namespace fs = ghc::filesystem;
+
+// This test and the one in multi1.cpp doesn't actualy test relevant functionality,
+// it is just used to check that it is possible to include filesystem.h in multiple
+// source files.
+TEST_CASE("Multifile-test 2", "[multi]")
+{
+ CHECK("/usr/local/bin" == fs::path("/usr/local/bin").generic_string());
+ std::string str = "/usr/local/bin";
+ std::u16string u16str = u"/usr/local/bin";
+ std::u32string u32str = U"/usr/local/bin";
+ CHECK(str == fs::path(str.begin(), str.end()));
+ CHECK(str == fs::path(u16str.begin(), u16str.end()));
+ CHECK(str == fs::path(u32str.begin(), u32str.end()));
+}
diff --git a/osx_environment.sh b/osx_environment.sh
index 09fa347..2ee886d 100644
--- a/osx_environment.sh
+++ b/osx_environment.sh
@@ -1,7 +1,7 @@
#!/bin/bash
# Checks if directory exists, otherwise asks to install package.
-function check_dir_exists() {
+check_dir_exists() {
local path=$1
local package=$2
@@ -11,7 +11,7 @@ function check_dir_exists() {
fi
}
-if [ ! $BARRIER_BUILD_ENV ]; then
+if [ -z "$BARRIER_BUILD_ENV" ]; then
check_dir_exists '/Applications/Xcode.app' 'Xcode'
printf "Modifying environment for Barrier build...\n"
@@ -29,18 +29,15 @@ if [ ! $BARRIER_BUILD_ENV ]; then
elif command -v brew; then
printf "Detected Homebrew\n"
- QT_PATH=$(brew --prefix qt)
- OPENSSL_PATH=$(brew --prefix openssl)
+ QT_PATH=$(brew --prefix qt@5)
- check_dir_exists "$QT_PATH" 'qt'
- check_dir_exists "$OPENSSL_PATH" 'openssl'
+ check_dir_exists "$QT_PATH" 'qt5'
export BARRIER_BUILD_BREW=1
- export CMAKE_PREFIX_PATH="$QT_PATH:$CMAKE_PREFIX_PATH"
- export LD_LIBRARY_PATH="$OPENSSL_PATH/lib:$LD_LIBRARY_PATH"
- export CPATH="$OPENSSL_PATH/include:$CPATH"
- export PKG_CONFIG_PATH="$OPENSSL_PATH/lib/pkgconfig:$PKG_CONFIG_PATH"
-
+ export CMAKE_PREFIX_PATH="/opt/procursus:$QT_PATH:$CMAKE_PREFIX_PATH"
+ export LD_LIBRARY_PATH="/opt/procursus/lib:$LD_LIBRARY_PATH"
+ export CPATH="/opt/procursus/include:$CPATH"
+ export PKG_CONFIG_PATH="/opt/procursus/lib/pkgconfig:$PKG_CONFIG_PATH"
else
printf "Neither Homebrew nor Macports is installed. Can't get dependency paths\n"
exit 1
diff --git a/res/Readme.txt b/res/Readme.txt
index 0b2802b..9cfcf3c 100644
--- a/res/Readme.txt
+++ b/res/Readme.txt
@@ -1,4 +1,4 @@
-Thank you for chosing Barrier!
+Thank you for choosing Barrier!
https://github.com/debauchee/barrier/
Barrier allows you to share your keyboard and mouse between computers over a network.
diff --git a/res/barrier.desktop b/res/barrier.desktop
index 6bb60e1..a47fd8e 100644
--- a/res/barrier.desktop
+++ b/res/barrier.desktop
@@ -5,6 +5,5 @@ Comment=Keyboard and mouse sharing solution
Exec=barrier
Icon=barrier
Terminal=false
-Categories=Utility;DesktopUtility;
+Categories=Utility;RemoteAccess;
Keywords=keyboard;mouse;sharing;network;share;
-
diff --git a/res/config.h.in b/res/config.h.in
index 2bd3b3b..53d3a3e 100644
--- a/res/config.h.in
+++ b/res/config.h.in
@@ -19,9 +19,6 @@
/* Define if your compiler has standard C++ library support. */
#cmakedefine HAVE_CXX_STDLIB ${HAVE_CXX_STDLIB}
-/* Define if the <X11/extensions/dpms.h> header file declares function prototypes. */
-#cmakedefine HAVE_DPMS_PROTOTYPES ${HAVE_DPMS_PROTOTYPES}
-
/* Define if you have a working `getpwuid_r` function. */
#cmakedefine HAVE_GETPWUID_R ${HAVE_GETPWUID_R}
@@ -97,9 +94,6 @@
/* Define to 1 if you have the <unistd.h> header file. */
#cmakedefine HAVE_UNISTD_H ${HAVE_UNISTD_H}
-/* Define to 1 if you have the `vsnprintf` function. */
-#cmakedefine HAVE_VSNPRINTF ${HAVE_VSNPRINTF}
-
/* Define to 1 if you have the <wchar.h> header file. */
#cmakedefine HAVE_WCHAR_H ${HAVE_WCHAR_H}
@@ -115,9 +109,6 @@
/* Define to 1 if you have the <X11/extensions/XKBstr.h> header file. */
#cmakedefine HAVE_X11_EXTENSIONS_XKBSTR_H ${HAVE_X11_EXTENSIONS_XKBSTR_H}
-/* Define to 1 if you have the <X11/extensions/XTest.h> header file. */
-#cmakedefine HAVE_X11_EXTENSIONS_XTEST_H ${HAVE_X11_EXTENSIONS_XTEST_H}
-
/* Define to 1 if you have the <X11/XKBlib.h> header file. */
#cmakedefine HAVE_X11_XKBLIB_H ${HAVE_X11_XKBLIB_H}
@@ -160,8 +151,5 @@
/* Define to 1 if your <sys/time.h> declares `struct tm`. */
#cmakedefine TM_IN_SYS_TIME ${TM_IN_SYS_TIME}
-/* Define to 1 if the X Window System is missing or not being used. */
-#cmakedefine X_DISPLAY_MISSING ${X_DISPLAY_MISSING}
-
/* Define to `unsigned int` if <sys/types.h> does not define. */
#cmakedefine size_t ${size_t}
diff --git a/res/makeicon.sh b/res/makeicon.sh
index 2883755..cfebe30 100755
--- a/res/makeicon.sh
+++ b/res/makeicon.sh
@@ -1,10 +1,10 @@
#!/bin/sh
ICNS_BASE=../dist/macos/bundle/Barrier.app/Contents/Resources
if ! which magick >/dev/null 2>&1; then
- echo "Need ImageMagic for this"
+ echo "Need ImageMagick for this"
exit 10
fi
-cd $(dirname $0) || exit $?
+cd "$(dirname "$0")" || exit $?
if [ ! -r barrier.png ]; then
echo "Use inkscape (or another vector graphics editor) to create barrier.png from barrier.svg first"
exit 10
@@ -12,11 +12,11 @@ fi
rm -rf work || exit $?
mkdir -p work || exit $?
for s in 16 24 32 48 64 128 256 512 1024; do
- magick convert barrier.png -resize ${s}x${s} -depth 8 work/${s}.png || exit $?
+ magick convert barrier.png -resize "${s}x${s}" -depth 8 "work/${s}.png" || exit $?
done
# windows icon
magick convert work/{16,24,32,48,64,128}.png barrier.png barrier.ico || exit $?
# macos icon
-png2icns $ICNS_BASE/Barrier.icns work/{16,32,256,512,1024}.png || exit $?
+png2icns "$ICNS_BASE/Barrier.icns" work/{16,32,256,512,1024}.png || exit $?
rm -rf work
echo Done
diff --git a/res/openssl/barrier.conf b/res/openssl/barrier.conf
deleted file mode 100644
index a29abfd..0000000
--- a/res/openssl/barrier.conf
+++ /dev/null
@@ -1,65 +0,0 @@
-#
-# Barrier OpenSSL configuration file.
-# Used for generation of certificate requests.
-#
-
-dir = .
-
-[ca]
-default_ca = CA_default
-
-[CA_default]
-serial = $dir/serial
-database = $dir/certindex.txt
-new_certs_dir = $dir/certs
-certificate = $dir/cacert.pem
-private_key = $dir/private/cakey.pem
-default_days = 365
-default_md = md5
-preserve = no
-email_in_dn = no
-nameopt = default_ca
-certopt = default_ca
-policy = policy_match
-
-[policy_match]
-countryName = match
-stateOrProvinceName = match
-organizationName = match
-organizationalUnitName = optional
-commonName = supplied
-emailAddress = optional
-
-[req]
-default_bits = 2048 # Size of keys
-default_keyfile = key.pem # name of generated keys
-default_md = md5 # message digest algorithm
-string_mask = nombstr # permitted characters
-distinguished_name = req_distinguished_name
-req_extensions = v3_req
-
-[req_distinguished_name]
-0.organizationName = Organization Name (company)
-organizationalUnitName = Organizational Unit Name (department, division)
-emailAddress = Email Address
-emailAddress_max = 40
-localityName = Locality Name (city, district)
-stateOrProvinceName = State or Province Name (full name)
-countryName = Country Name (2 letter code)
-countryName_min = 2
-countryName_max = 2
-commonName = Common Name (hostname, IP, or your name)
-commonName_max = 64
-0.organizationName_default = My Company
-localityName_default = My Town
-stateOrProvinceName_default = State or Providence
-countryName_default = US
-
-[v3_ca]
-basicConstraints = CA:TRUE
-subjectKeyIdentifier = hash
-authorityKeyIdentifier = keyid:always,issuer:always
-
-[v3_req]
-basicConstraints = CA:FALSE
-subjectKeyIdentifier = hash
diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml
index 25b1f47..9e20c67 100644
--- a/snap/snapcraft.yaml
+++ b/snap/snapcraft.yaml
@@ -1,7 +1,7 @@
name: barrier
base: core18
version: master
-version-script: git describe --tags --long | sed "s/^v//"
+version-script: git describe --tags | sed "s/^v//"
adopt-info: appstream-flathub
grade: stable # must be 'stable' to release into candidate/stable channels
confinement: strict # use 'strict' once you have the right plugs and slots
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 55aad09..cc44fb2 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,11 +1,11 @@
# barrier -- mouse and keyboard sharing utility
# Copyright (C) 2012-2016 Symless Ltd.
# Copyright (C) 2011 Nick Bolton
-#
+#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
-#
+#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -19,7 +19,13 @@ include_directories (${CMAKE_CURRENT_BINARY_DIR}/lib)
add_subdirectory(lib)
add_subdirectory(cmd)
-add_subdirectory(test)
+
+include(../cmake/gtest.cmake)
+
+if (BARRIER_BUILD_TESTS)
+ add_subdirectory(test/integtests)
+ add_subdirectory(test/unittests)
+endif()
if (BARRIER_BUILD_GUI)
add_subdirectory(gui)
diff --git a/src/cmd/CMakeLists.txt b/src/cmd/CMakeLists.txt
index ebf2a0d..946b19a 100644
--- a/src/cmd/CMakeLists.txt
+++ b/src/cmd/CMakeLists.txt
@@ -1,11 +1,11 @@
# barrier -- mouse and keyboard sharing utility
# Copyright (C) 2012-2016 Symless Ltd.
# Copyright (C) 2011 Nick Bolton
-#
+#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
-#
+#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -18,6 +18,5 @@ add_subdirectory(barrierc)
add_subdirectory(barriers)
if (WIN32)
- add_subdirectory(barrierd)
+ add_subdirectory(barrierd)
endif()
-
diff --git a/src/cmd/barrierc/CMakeLists.txt b/src/cmd/barrierc/CMakeLists.txt
index 0c08550..45e9ab0 100644
--- a/src/cmd/barrierc/CMakeLists.txt
+++ b/src/cmd/barrierc/CMakeLists.txt
@@ -1,11 +1,11 @@
# barrier -- mouse and keyboard sharing utility
# Copyright (C) 2012-2016 Symless Ltd.
# Copyright (C) 2009 Nick Bolton
-#
+#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
-#
+#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -21,16 +21,7 @@ set(sources
if (WIN32)
file(GLOB arch_headers "MSWindows*.h")
file(GLOB arch_sources "MSWindows*.cpp")
- list(APPEND sources
- resource.h
- barrierc.ico
- barrierc.rc
- tb_error.ico
- tb_idle.ico
- tb_run.ico
- tb_wait.ico
- barrierc.exe.manifest
- )
+ list(APPEND sources barrierc.rc)
elseif (APPLE)
file(GLOB arch_headers "OSX*.h")
file(GLOB arch_sources "OSX*.cpp")
@@ -55,4 +46,3 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
install (TARGETS barrierc DESTINATION bin)
endif()
-
diff --git a/src/cmd/barrierc/MSWindowsClientTaskBarReceiver.cpp b/src/cmd/barrierc/MSWindowsClientTaskBarReceiver.cpp
index 8d17900..dd2f59c 100644
--- a/src/cmd/barrierc/MSWindowsClientTaskBarReceiver.cpp
+++ b/src/cmd/barrierc/MSWindowsClientTaskBarReceiver.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2003 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/cmd/barrierc/MSWindowsClientTaskBarReceiver.h b/src/cmd/barrierc/MSWindowsClientTaskBarReceiver.h
index 91688e8..868b35b 100644
--- a/src/cmd/barrierc/MSWindowsClientTaskBarReceiver.h
+++ b/src/cmd/barrierc/MSWindowsClientTaskBarReceiver.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2003 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/cmd/barrierc/OSXClientTaskBarReceiver.cpp b/src/cmd/barrierc/OSXClientTaskBarReceiver.cpp
index 7e79991..e273f99 100644
--- a/src/cmd/barrierc/OSXClientTaskBarReceiver.cpp
+++ b/src/cmd/barrierc/OSXClientTaskBarReceiver.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -66,4 +66,3 @@ createTaskBarReceiver(const BufferedLogOutputter* logBuffer, IEventQueue* events
{
return new OSXClientTaskBarReceiver(logBuffer, events);
}
-
diff --git a/src/cmd/barrierc/OSXClientTaskBarReceiver.h b/src/cmd/barrierc/OSXClientTaskBarReceiver.h
index fcc763a..59d5344 100644
--- a/src/cmd/barrierc/OSXClientTaskBarReceiver.h
+++ b/src/cmd/barrierc/OSXClientTaskBarReceiver.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/cmd/barrierc/XWindowsClientTaskBarReceiver.cpp b/src/cmd/barrierc/XWindowsClientTaskBarReceiver.cpp
index f56481c..f829ae0 100644
--- a/src/cmd/barrierc/XWindowsClientTaskBarReceiver.cpp
+++ b/src/cmd/barrierc/XWindowsClientTaskBarReceiver.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2003 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/cmd/barrierc/XWindowsClientTaskBarReceiver.h b/src/cmd/barrierc/XWindowsClientTaskBarReceiver.h
index 73250d0..c3db22e 100644
--- a/src/cmd/barrierc/XWindowsClientTaskBarReceiver.h
+++ b/src/cmd/barrierc/XWindowsClientTaskBarReceiver.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2003 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/cmd/barrierc/barrierc.cpp b/src/cmd/barrierc/barrierc.cpp
index 28d8efc..466a032 100644
--- a/src/cmd/barrierc/barrierc.cpp
+++ b/src/cmd/barrierc/barrierc.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -32,13 +32,13 @@
#endif
int
-main(int argc, char** argv)
+main(int argc, char** argv)
{
#if SYSAPI_WIN32
// record window instance for tray icon, etc
ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL));
#endif
-
+
Arch arch;
arch.init();
diff --git a/src/cmd/barrierc/barrierc.exe.manifest b/src/cmd/barrierc/barrierc.exe.manifest
deleted file mode 100644
index 2c6f365..0000000
--- a/src/cmd/barrierc/barrierc.exe.manifest
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"><trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"><security><requestedPrivileges><requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel></requestedPrivileges></security></trustInfo><application xmlns="urn:schemas-microsoft-com:asm.v3"><windowsSettings><dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitor</dpiAwareness><dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware></windowsSettings></application></assembly> \ No newline at end of file
diff --git a/src/cmd/barrierc/barrierc.rc b/src/cmd/barrierc/barrierc.rc
index b34127c..3000dcc 100644
--- a/src/cmd/barrierc/barrierc.rc
+++ b/src/cmd/barrierc/barrierc.rc
@@ -1,4 +1,4 @@
-//Microsoft Developer Studio generated resource script.
+// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
@@ -8,9 +8,6 @@
// Generated from the TEXTINCLUDE 2 resource.
//
#include <winresrc.h>
-#if !defined(IDC_STATIC)
-#define IDC_STATIC (-1)
-#endif
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
@@ -19,10 +16,8 @@
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
-#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
-#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
@@ -30,18 +25,18 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
// TEXTINCLUDE
//
-1 TEXTINCLUDE DISCARDABLE
+1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
-2 TEXTINCLUDE DISCARDABLE
+2 TEXTINCLUDE
BEGIN
"#include <winresrc.h>\r\n"
"\0"
END
-3 TEXTINCLUDE DISCARDABLE
+3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
@@ -52,29 +47,56 @@ END
/////////////////////////////////////////////////////////////////////////////
//
-// Icon
+// Version
//
-// Icon with lowest ID value placed first to ensure application icon
-// remains consistent on all systems.
-IDI_BARRIER ICON DISCARDABLE "barrierc.ico"
-IDI_TASKBAR_NOT_RUNNING ICON DISCARDABLE "tb_idle.ico"
-IDI_TASKBAR_NOT_WORKING ICON DISCARDABLE "tb_error.ico"
-IDI_TASKBAR_NOT_CONNECTED ICON DISCARDABLE "tb_wait.ico"
-IDI_TASKBAR_CONNECTED ICON DISCARDABLE "tb_run.ico"
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION BARRIER_VERSION_MAJOR, BARRIER_VERSION_MINOR, BARRIER_VERSION_PATCH, BARRIER_BUILD_NUMBER
+ PRODUCTVERSION BARRIER_VERSION_MAJOR, BARRIER_VERSION_MINOR, BARRIER_VERSION_PATCH, BARRIER_BUILD_NUMBER
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS VOS_NT_WINDOWS32
+ FILETYPE VFT_APP
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "Debauchee Open Source Group"
+ VALUE "CompanyWeb", "https://github.com/debauchee/barrier/"
+ VALUE "FileVersion", BARRIER_VERSION
+ VALUE "LegalCopyright", "Copyright (C) 2018 Debauchee Open Source Group\nCopyright (C) 2012-2016 Symless Ltd.\nCopyright (C) 2008-2014 Nick Bolton\nCopyright (C) 2002-2014 Chris Schoeneman"
+ VALUE "ProductName", "Barrier"
+ VALUE "ProductVersion", BARRIER_VERSION
+ VALUE "OriginalFilename", "barrierc.exe"
+ VALUE "FileDescription", "Open source KVM software client"
+ VALUE "InternalName", "barrierc"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
/////////////////////////////////////////////////////////////////////////////
//
-// Dialog
+// Icon
//
-IDD_TASKBAR_STATUS DIALOG DISCARDABLE 0, 0, 145, 18
-STYLE DS_MODALFRAME | WS_POPUP
-FONT 8, "MS Sans Serif"
-BEGIN
- EDITTEXT IDC_TASKBAR_STATUS_STATUS,3,3,139,12,ES_AUTOHSCROLL |
- ES_READONLY | NOT WS_BORDER
-END
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_BARRIER ICON "barrierc.ico"
+IDI_TASKBAR_NOT_RUNNING ICON "tb_idle.ico"
+IDI_TASKBAR_NOT_WORKING ICON "tb_error.ico"
+IDI_TASKBAR_NOT_CONNECTED ICON "tb_wait.ico"
+IDI_TASKBAR_CONNECTED ICON "tb_run.ico"
/////////////////////////////////////////////////////////////////////////////
@@ -82,7 +104,7 @@ END
// Menu
//
-IDR_TASKBAR MENU DISCARDABLE
+IDR_TASKBAR MENU
BEGIN
POPUP "Barrier"
BEGIN
@@ -92,19 +114,12 @@ BEGIN
POPUP "Set Log Level"
BEGIN
MENUITEM "Error", IDC_TASKBAR_LOG_LEVEL_ERROR
-
MENUITEM "Warning", IDC_TASKBAR_LOG_LEVEL_WARNING
-
MENUITEM "Note", IDC_TASKBAR_LOG_LEVEL_NOTE
-
MENUITEM "Info", IDC_TASKBAR_LOG_LEVEL_INFO
-
MENUITEM "Debug", IDC_TASKBAR_LOG_LEVEL_DEBUG
-
MENUITEM "Debug1", IDC_TASKBAR_LOG_LEVEL_DEBUG1
-
MENUITEM "Debug2", IDC_TASKBAR_LOG_LEVEL_DEBUG2
-
END
MENUITEM SEPARATOR
MENUITEM "Quit", IDC_TASKBAR_QUIT
@@ -114,10 +129,24 @@ END
/////////////////////////////////////////////////////////////////////////////
//
+// Dialog
+//
+
+IDD_TASKBAR_STATUS DIALOG 0, 0, 145, 18
+STYLE DS_MODALFRAME | WS_POPUP
+FONT 8, "MS Sans Serif"
+BEGIN
+ EDITTEXT IDC_TASKBAR_STATUS_STATUS,3,3,139,12,ES_AUTOHSCROLL |
+ ES_READONLY | NOT WS_BORDER
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
// String Table
//
-STRINGTABLE DISCARDABLE
+STRINGTABLE
BEGIN
IDS_FAILED "Barrier is about to quit with errors or warnings. Please check the log then click OK."
IDS_INIT_FAILED "Barrier failed to initialize: %{1}"
diff --git a/src/cmd/barrierc/resource.h b/src/cmd/barrierc/resource.h
index 57b271e..5603ba5 100644
--- a/src/cmd/barrierc/resource.h
+++ b/src/cmd/barrierc/resource.h
@@ -26,7 +26,7 @@
#define IDC_TASKBAR_LOG_LEVEL_DEBUG2 40015
// Next default values for new objects
-//
+//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 109
diff --git a/src/cmd/barrierd/CMakeLists.txt b/src/cmd/barrierd/CMakeLists.txt
index aeae94c..5c57882 100644
--- a/src/cmd/barrierd/CMakeLists.txt
+++ b/src/cmd/barrierd/CMakeLists.txt
@@ -16,6 +16,9 @@
file(GLOB headers "*.h")
file(GLOB sources "*.cpp")
+if (WIN32)
+ list(APPEND sources barrierd.rc)
+endif()
if (WIN32)
add_executable (barrierd WIN32 ${sources})
diff --git a/src/cmd/barrierd/barrierd.cpp b/src/cmd/barrierd/barrierd.cpp
index dd351f9..710e89d 100644
--- a/src/cmd/barrierd/barrierd.cpp
+++ b/src/cmd/barrierd/barrierd.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/cmd/barrierd/barrierd.ico b/src/cmd/barrierd/barrierd.ico
new file mode 100644
index 0000000..6e90545
--- /dev/null
+++ b/src/cmd/barrierd/barrierd.ico
Binary files differ
diff --git a/src/cmd/barrierd/barrierd.rc b/src/cmd/barrierd/barrierd.rc
new file mode 100644
index 0000000..c5ad502
--- /dev/null
+++ b/src/cmd/barrierd/barrierd.rc
@@ -0,0 +1,111 @@
+// Microsoft Visual C++ generated resource script.
+//
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include <winresrc.h>
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include <winresrc.h>\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION BARRIER_VERSION_MAJOR, BARRIER_VERSION_MINOR, BARRIER_VERSION_PATCH, BARRIER_BUILD_NUMBER
+ PRODUCTVERSION BARRIER_VERSION_MAJOR, BARRIER_VERSION_MINOR, BARRIER_VERSION_PATCH, BARRIER_BUILD_NUMBER
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS VOS_NT_WINDOWS32
+ FILETYPE VFT_APP
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "Debauchee Open Source Group"
+ VALUE "CompanyWeb", "https://github.com/debauchee/barrier/"
+ VALUE "FileVersion", BARRIER_VERSION
+ VALUE "LegalCopyright", "Copyright (C) 2018 Debauchee Open Source Group\nCopyright (C) 2012-2016 Symless Ltd.\nCopyright (C) 2008-2014 Nick Bolton\nCopyright (C) 2002-2014 Chris Schoeneman"
+ VALUE "ProductName", "Barrier"
+ VALUE "ProductVersion", BARRIER_VERSION
+ VALUE "OriginalFilename", "barrierd.exe"
+ VALUE "FileDescription", "Open source KVM software daemon"
+ VALUE "InternalName", "barrierd"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_BARRIER ICON "barrierd.ico"
+
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/src/cmd/barriers/CMakeLists.txt b/src/cmd/barriers/CMakeLists.txt
index 912421f..c9fa750 100644
--- a/src/cmd/barriers/CMakeLists.txt
+++ b/src/cmd/barriers/CMakeLists.txt
@@ -1,11 +1,11 @@
# barrier -- mouse and keyboard sharing utility
# Copyright (C) 2012-2016 Symless Ltd.
# Copyright (C) 2009 Nick Bolton
-#
+#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
-#
+#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -21,16 +21,7 @@ set(sources
if (WIN32)
file(GLOB arch_headers "MSWindows*.h")
file(GLOB arch_sources "MSWindows*.cpp")
- list(APPEND sources
- resource.h
- barriers.ico
- barriers.rc
- tb_error.ico
- tb_idle.ico
- tb_run.ico
- tb_wait.ico
- barriers.exe.manifest
- )
+ list(APPEND sources barriers.rc)
elseif (APPLE)
file(GLOB arch_headers "OSX*.h")
file(GLOB arch_sources "OSX*.cpp")
@@ -55,5 +46,3 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
install (TARGETS barriers DESTINATION bin)
endif()
-
-
diff --git a/src/cmd/barriers/MSWindowsServerTaskBarReceiver.cpp b/src/cmd/barriers/MSWindowsServerTaskBarReceiver.cpp
index a221dac..c86048a 100644
--- a/src/cmd/barriers/MSWindowsServerTaskBarReceiver.cpp
+++ b/src/cmd/barriers/MSWindowsServerTaskBarReceiver.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2003 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/cmd/barriers/MSWindowsServerTaskBarReceiver.h b/src/cmd/barriers/MSWindowsServerTaskBarReceiver.h
index a308ab4..c79a2b2 100644
--- a/src/cmd/barriers/MSWindowsServerTaskBarReceiver.h
+++ b/src/cmd/barriers/MSWindowsServerTaskBarReceiver.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2003 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/cmd/barriers/OSXServerTaskBarReceiver.cpp b/src/cmd/barriers/OSXServerTaskBarReceiver.cpp
index bbe8fd1..5fb525a 100644
--- a/src/cmd/barriers/OSXServerTaskBarReceiver.cpp
+++ b/src/cmd/barriers/OSXServerTaskBarReceiver.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/cmd/barriers/OSXServerTaskBarReceiver.h b/src/cmd/barriers/OSXServerTaskBarReceiver.h
index ab6928f..1ad4501 100644
--- a/src/cmd/barriers/OSXServerTaskBarReceiver.h
+++ b/src/cmd/barriers/OSXServerTaskBarReceiver.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/cmd/barriers/XWindowsServerTaskBarReceiver.cpp b/src/cmd/barriers/XWindowsServerTaskBarReceiver.cpp
index 7f525c5..6dfcdaa 100644
--- a/src/cmd/barriers/XWindowsServerTaskBarReceiver.cpp
+++ b/src/cmd/barriers/XWindowsServerTaskBarReceiver.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2003 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/cmd/barriers/XWindowsServerTaskBarReceiver.h b/src/cmd/barriers/XWindowsServerTaskBarReceiver.h
index 549a62f..ce56a3b 100644
--- a/src/cmd/barriers/XWindowsServerTaskBarReceiver.h
+++ b/src/cmd/barriers/XWindowsServerTaskBarReceiver.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2003 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/cmd/barriers/barriers.cpp b/src/cmd/barriers/barriers.cpp
index 21c4d80..169c5d3 100644
--- a/src/cmd/barriers/barriers.cpp
+++ b/src/cmd/barriers/barriers.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -32,7 +32,7 @@
#endif
int
-main(int argc, char** argv)
+main(int argc, char** argv)
{
#if SYSAPI_WIN32
// record window instance for tray icon, etc
@@ -45,7 +45,7 @@ main(int argc, char** argv)
*/
setenv("OS_ACTIVITY_DT_MODE", "NO", true);
#endif
-
+
Arch arch;
arch.init();
diff --git a/src/cmd/barriers/barriers.exe.manifest b/src/cmd/barriers/barriers.exe.manifest
deleted file mode 100644
index 7309fde..0000000
--- a/src/cmd/barriers/barriers.exe.manifest
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"><trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"><security><requestedPrivileges><requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel></requestedPrivileges></security></trustInfo><application xmlns="urn:schemas-microsoft-com:asm.v3"><windowsSettings><dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware></windowsSettings></application></assembly> \ No newline at end of file
diff --git a/src/cmd/barriers/barriers.rc b/src/cmd/barriers/barriers.rc
index c4d263c..f9d8af1 100644
--- a/src/cmd/barriers/barriers.rc
+++ b/src/cmd/barriers/barriers.rc
@@ -16,10 +16,8 @@
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
-#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
-#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
@@ -27,18 +25,18 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
// TEXTINCLUDE
//
-1 TEXTINCLUDE
+1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
-2 TEXTINCLUDE
+2 TEXTINCLUDE
BEGIN
"#include <winresrc.h>\r\n"
"\0"
END
-3 TEXTINCLUDE
+3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
@@ -49,23 +47,64 @@ END
/////////////////////////////////////////////////////////////////////////////
//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION BARRIER_VERSION_MAJOR, BARRIER_VERSION_MINOR, BARRIER_VERSION_PATCH, BARRIER_BUILD_NUMBER
+ PRODUCTVERSION BARRIER_VERSION_MAJOR, BARRIER_VERSION_MINOR, BARRIER_VERSION_PATCH, BARRIER_BUILD_NUMBER
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS VOS_NT_WINDOWS32
+ FILETYPE VFT_APP
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "Debauchee Open Source Group"
+ VALUE "CompanyWeb", "https://github.com/debauchee/barrier/"
+ VALUE "FileVersion", BARRIER_VERSION
+ VALUE "LegalCopyright", "Copyright (C) 2018 Debauchee Open Source Group\nCopyright (C) 2012-2016 Symless Ltd.\nCopyright (C) 2008-2014 Nick Bolton\nCopyright (C) 2002-2014 Chris Schoeneman"
+ VALUE "ProductName", "Barrier"
+ VALUE "ProductVersion", BARRIER_VERSION
+ VALUE "OriginalFilename", "barriers.exe"
+ VALUE "FileDescription", "Open source KVM software server"
+ VALUE "InternalName", "barriers"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
-IDI_BARRIER ICON "barriers.ico"
-IDI_TASKBAR_NOT_RUNNING ICON "tb_idle.ico"
-IDI_TASKBAR_NOT_WORKING ICON "tb_error.ico"
+IDI_BARRIER ICON "barriers.ico"
+IDI_TASKBAR_NOT_RUNNING ICON "tb_idle.ico"
+IDI_TASKBAR_NOT_WORKING ICON "tb_error.ico"
IDI_TASKBAR_NOT_CONNECTED ICON "tb_wait.ico"
-IDI_TASKBAR_CONNECTED ICON "tb_run.ico"
+IDI_TASKBAR_CONNECTED ICON "tb_run.ico"
+
/////////////////////////////////////////////////////////////////////////////
//
// Menu
//
-IDR_TASKBAR MENU
+IDR_TASKBAR MENU
BEGIN
POPUP "Barrier"
BEGIN
@@ -110,7 +149,7 @@ END
// String Table
//
-STRINGTABLE
+STRINGTABLE
BEGIN
IDS_FAILED "Barrier is about to quit with errors or warnings. Please check the log then click OK."
IDS_INIT_FAILED "Barrier failed to initialize: %{1}"
diff --git a/src/cmd/barriers/resource.h b/src/cmd/barriers/resource.h
index 9594db1..3ee57e7 100644
--- a/src/cmd/barriers/resource.h
+++ b/src/cmd/barriers/resource.h
@@ -31,7 +31,7 @@
#define ID_BARRIER_RESETSERVER 40017
// Next default values for new objects
-//
+//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 109
diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt
index f29fd91..570e842 100644
--- a/src/gui/CMakeLists.txt
+++ b/src/gui/CMakeLists.txt
@@ -6,15 +6,124 @@ set (CMAKE_AUTORCC ON)
set (CMAKE_AUTOUIC ON)
set (CMAKE_INCLUDE_CURRENT_DIR ON)
-file (GLOB GUI_SOURCE_FILES src/*.cpp src/*.h)
-file (GLOB GUI_UI_FILES src/*.ui)
+# files that are used both in tests and the app
+set(GUI_COMMON_SOURCE_FILES
+ src/Action.cpp
+ src/Hotkey.cpp
+ src/KeySequence.cpp
+)
+
+set(GUI_COMMON_HEADER_FILES
+ src/Action.h
+ src/Hotkey.h
+ src/KeySequence.h
+)
+
+set(GUI_SOURCE_FILES
+ src/AboutDialog.cpp
+ src/ActionDialog.cpp
+ src/AddClientDialog.cpp
+ src/AppConfig.cpp
+ src/BarrierLocale.cpp
+ src/BaseConfig.cpp
+ src/CommandProcess.cpp
+ src/DataDownloader.cpp
+ src/DisplayIsValid.cpp
+ src/FingerprintAcceptDialog.cpp
+ src/HotkeyDialog.cpp
+ src/IpcClient.cpp
+ src/Ipc.cpp
+ src/IpcReader.cpp
+ src/KeySequenceWidget.cpp
+ src/LogWindow.cpp
+ src/main.cpp
+ src/MainWindow.cpp
+ src/NewScreenWidget.cpp
+ src/QBarrierApplication.cpp
+ src/QUtility.cpp
+ src/Screen.cpp
+ src/ScreenSettingsDialog.cpp
+ src/ScreenSetupModel.cpp
+ src/ScreenSetupView.cpp
+ src/ServerConfig.cpp
+ src/ServerConfigDialog.cpp
+ src/SettingsDialog.cpp
+ src/SetupWizard.cpp
+ src/SslCertificate.cpp
+ src/TrashScreenWidget.cpp
+ src/VersionChecker.cpp
+ src/ZeroconfBrowser.cpp
+ src/ZeroconfRegister.cpp
+ src/ZeroconfServer.cpp
+ src/ZeroconfService.cpp
+ src/ZeroconfThread.cpp
+)
+
+set(GUI_HEADER_FILES
+ src/AboutDialog.h
+ src/ActionDialog.h
+ src/AddClientDialog.h
+ src/AppConfig.h
+ src/BarrierLocale.h
+ src/BaseConfig.h
+ src/CommandProcess.h
+ src/DataDownloader.h
+ src/DisplayIsValid.h
+ src/ElevateMode.h
+ src/HotkeyDialog.h
+ src/IpcClient.h
+ src/Ipc.h
+ src/IpcReader.h
+ src/KeySequenceWidget.h
+ src/LogWindow.h
+ src/MainWindow.h
+ src/NewScreenWidget.h
+ src/ProcessorArch.h
+ src/QBarrierApplication.h
+ src/QUtility.h
+ src/Screen.h
+ src/ScreenSettingsDialog.h
+ src/ScreenSetupModel.h
+ src/ScreenSetupView.h
+ src/ServerConfigDialog.h
+ src/ServerConfig.h
+ src/SettingsDialog.h
+ src/SetupWizard.h
+ src/ShutdownCh.h
+ src/SslCertificate.h
+ src/TrashScreenWidget.h
+ src/VersionChecker.h
+ src/ZeroconfBrowser.h
+ src/ZeroconfRecord.h
+ src/ZeroconfRegister.h
+ src/ZeroconfServer.h
+ src/ZeroconfService.h
+ src/ZeroconfThread.h
+)
+
+set(GUI_UI_FILES
+ src/AboutDialogBase.ui
+ src/ActionDialogBase.ui
+ src/AddClientDialogBase.ui
+ src/FingerprintAcceptDialog.ui
+ src/HotkeyDialogBase.ui
+ src/LogWindowBase.ui
+ src/MainWindowBase.ui
+ src/ScreenSettingsDialogBase.ui
+ src/ServerConfigDialogBase.ui
+ src/SettingsDialogBase.ui
+ src/SetupWizardBase.ui
+)
if (WIN32)
set (GUI_RC_FILES res/win/Barrier.rc)
endif()
add_executable (barrier WIN32
+ ${GUI_COMMON_SOURCE_FILES}
+ ${GUI_COMMON_HEADER_FILES}
${GUI_SOURCE_FILES}
+ ${GUI_HEADER_FILES}
${GUI_UI_FILES}
${GUI_RC_FILES}
res/Barrier.qrc
@@ -22,13 +131,13 @@ add_executable (barrier WIN32
include_directories (./src)
-target_link_libraries (barrier Qt5::Core Qt5::Widgets Qt5::Network)
+target_link_libraries(barrier net base io Qt5::Core Qt5::Widgets Qt5::Network ${OPENSSL_LIBS})
target_compile_definitions (barrier PRIVATE -DBARRIER_VERSION_STAGE="${BARRIER_VERSION_STAGE}")
target_compile_definitions (barrier PRIVATE -DBARRIER_REVISION="${BARRIER_REVISION}")
if (WIN32)
include_directories ($ENV{BONJOUR_SDK_HOME}/Include)
- find_library (DNSSD_LIB dnssd.lib
+ find_library (DNSSD_LIB dnssd.lib
HINTS ENV BONJOUR_SDK_HOME
PATH_SUFFIXES "Lib/x64")
set_target_properties (barrier PROPERTIES LINK_FLAGS "/NODEFAULTLIB:LIBCMT")
@@ -51,3 +160,22 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR ${CMAKE_SYSTEM_NAME} MATCHES "BSD")
install (TARGETS barrier DESTINATION bin)
endif()
+
+if (BARRIER_BUILD_TESTS)
+ set(GUI_TEST_SOURCE_FILES
+ test/KeySequenceTests.cpp
+ test/HotkeyTests.cpp
+ test/main.cpp
+ )
+
+ add_executable(guiunittests
+ ${GUI_TEST_SOURCE_FILES}
+ ${GUI_COMMON_SOURCE_FILES}
+ ${GUI_COMMON_HEADER_FILES}
+ )
+
+ add_test(guiunittests guiunittests)
+
+ target_include_directories(guiunittests PUBLIC ../../ext)
+ target_link_libraries(guiunittests gtest gmock Qt5::Core Qt5::Widgets Qt5::Network ${libs})
+endif()
diff --git a/src/gui/gui.pro b/src/gui/gui.pro
deleted file mode 100644
index 14a2407..0000000
--- a/src/gui/gui.pro
+++ /dev/null
@@ -1,162 +0,0 @@
-QT += widgets \
- network
-TEMPLATE = app
-TARGET = barrier
-DEFINES += VERSION_STAGE=\\\"$$QMAKE_VERSION_STAGE\\\"
-DEFINES += VERSION_REVISION=\\\"$$QMAKE_VERSION_REVISION\\\"
-DEFINES -= UNICODE
-DEFINES += _MBCS
-DEPENDPATH += . \
- res
-INCLUDEPATH += . \
- src \
- ../lib/shared/
-FORMS += src/MainWindowBase.ui \
- src/AboutDialogBase.ui \
- src/ServerConfigDialogBase.ui \
- src/ScreenSettingsDialogBase.ui \
- src/ActionDialogBase.ui \
- src/HotkeyDialogBase.ui \
- src/SettingsDialogBase.ui \
- src/SetupWizardBase.ui \
- src/AddClientDialogBase.ui \
- src/ActivationDialog.ui \
- src/CancelActivationDialog.ui \
- src/FailedLoginDialog.ui
-SOURCES += src/main.cpp \
- src/MainWindow.cpp \
- src/AboutDialog.cpp \
- src/ServerConfig.cpp \
- src/ServerConfigDialog.cpp \
- src/ScreenSetupView.cpp \
- src/Screen.cpp \
- src/ScreenSetupModel.cpp \
- src/NewScreenWidget.cpp \
- src/TrashScreenWidget.cpp \
- src/ScreenSettingsDialog.cpp \
- src/BaseConfig.cpp \
- src/HotkeyDialog.cpp \
- src/ActionDialog.cpp \
- src/Hotkey.cpp \
- src/Action.cpp \
- src/KeySequence.cpp \
- src/KeySequenceWidget.cpp \
- src/SettingsDialog.cpp \
- src/AppConfig.cpp \
- src/QBarrierApplication.cpp \
- src/VersionChecker.cpp \
- src/SetupWizard.cpp \
- src/IpcClient.cpp \
- src/IpcReader.cpp \
- src/Ipc.cpp \
- src/BarrierLocale.cpp \
- src/QUtility.cpp \
- src/ZeroconfServer.cpp \
- src/ZeroconfThread.cpp \
- src/ZeroconfRegister.cpp \
- src/ZeroconfBrowser.cpp \
- src/ZeroconfService.cpp \
- src/DataDownloader.cpp \
- src/AddClientDialog.cpp \
- src/CommandProcess.cpp \
- src/CoreInterface.cpp \
- src/Fingerprint.cpp \
- src/SslCertificate.cpp \
- src/WebClient.cpp \
- src/ActivationNotifier.cpp \
- src/ActivationDialog.cpp \
- src/CancelActivationDialog.cpp \
- src/FailedLoginDialog.cpp \
- ../lib/shared/SerialKey.cpp \
- src/LicenseManager.cpp
-HEADERS += src/MainWindow.h \
- src/AboutDialog.h \
- src/ServerConfig.h \
- src/ServerConfigDialog.h \
- src/ScreenSetupView.h \
- src/Screen.h \
- src/ScreenSetupModel.h \
- src/NewScreenWidget.h \
- src/TrashScreenWidget.h \
- src/ScreenSettingsDialog.h \
- src/BaseConfig.h \
- src/HotkeyDialog.h \
- src/ActionDialog.h \
- src/Hotkey.h \
- src/Action.h \
- src/KeySequence.h \
- src/KeySequenceWidget.h \
- src/SettingsDialog.h \
- src/AppConfig.h \
- src/QBarrierApplication.h \
- src/VersionChecker.h \
- src/SetupWizard.h \
- src/IpcClient.h \
- src/IpcReader.h \
- src/Ipc.h \
- src/BarrierLocale.h \
- src/QUtility.h \
- src/ZeroconfServer.h \
- src/ZeroconfThread.h \
- src/ZeroconfRegister.h \
- src/ZeroconfRecord.h \
- src/ZeroconfBrowser.h \
- src/ZeroconfService.h \
- src/DataDownloader.h \
- src/AddClientDialog.h \
- src/CommandProcess.h \
- src/ProcessorArch.h \
- src/CoreInterface.h \
- src/Fingerprint.h \
- src/SslCertificate.h \
- src/WebClient.h \
- src/ActivationNotifier.h \
- src/ElevateMode.h \
- src/ActivationDialog.h \
- src/CancelActivationDialog.h \
- src/FailedLoginDialog.h \
- ../lib/shared/EditionType.h \
- ../lib/shared/SerialKey.h \
- src/LicenseManager.h
-RESOURCES += res/Barrier.qrc
-RC_FILE = res/win/Barrier.rc
-macx {
- QMAKE_INFO_PLIST = res/mac/Info.plist
- TARGET = Barrier
- QBARRIER_ICON.files = res/mac/Barrier.icns
- QBARRIER_ICON.path = Contents/Resources
- QMAKE_BUNDLE_DATA += QBARRIER_ICON
- LIBS += $$MACX_LIBS
-}
-unix:!macx:LIBS += -ldns_sd
-debug {
- OBJECTS_DIR = tmp/debug
- MOC_DIR = tmp/debug
- RCC_DIR = tmp/debug
-}
-release {
- OBJECTS_DIR = tmp/release
- MOC_DIR = tmp/release
- RCC_DIR = tmp/release
-}
-win32-msvc2015 {
- LIBS += -lAdvapi32
- QMAKE_LFLAGS += /NODEFAULTLIB:LIBCMT
-}
-win32-msvc* {
- contains(QMAKE_HOST.arch, x86):{
- QMAKE_LFLAGS *= /MACHINE:X86
- LIBS += -L"$$(BONJOUR_SDK_HOME)/Lib/Win32" -ldnssd
- }
-
- contains(QMAKE_HOST.arch, x86_64):{
- QMAKE_LFLAGS *= /MACHINE:X64
- LIBS += -L"$$(BONJOUR_SDK_HOME)/Lib/x64" -ldnssd
- }
-}
-win32 {
- Debug:DESTDIR = ../../bin/Debug
- Release:DESTDIR = ../../bin/Release
- INCLUDEPATH += "$$(BONJOUR_SDK_HOME)/Include"
-}
-else:DESTDIR = ../../bin
diff --git a/src/gui/gui.ts b/src/gui/gui.ts
index 99bc7aa..308d41e 100644
--- a/src/gui/gui.ts
+++ b/src/gui/gui.ts
@@ -650,12 +650,17 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
+ <source>All files (*.*)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
+ <source>Barrier Configurations (*.conf)</source>
<translation type="unfinished"></translation>
</message>
<message>
diff --git a/src/gui/lang.cmd b/src/gui/lang.cmd
index 4418593..fbab95c 100644
--- a/src/gui/lang.cmd
+++ b/src/gui/lang.cmd
@@ -1 +1 @@
-lupdate -noobsolete gui.pro -ts gui.ts \ No newline at end of file
+lupdate -noobsolete src/* -ts gui.ts
diff --git a/src/gui/langbuild.cmd b/src/gui/langbuild.cmd
index b86d202..aaeefbb 100644..100755
--- a/src/gui/langbuild.cmd
+++ b/src/gui/langbuild.cmd
@@ -1,2 +1,2 @@
-cd res/lang
-lrelease *.ts \ No newline at end of file
+cd res/lang
+lrelease *.ts
diff --git a/src/gui/res/lang/Languages.xml b/src/gui/res/lang/Languages.xml
index 5948f9c..723d667 100644
--- a/src/gui/res/lang/Languages.xml
+++ b/src/gui/res/lang/Languages.xml
@@ -1,46 +1,46 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<languages>
- <language ietfCode="en" name="English" />
- <language ietfCode="ca-AD" name="Català (Andorra)" />
- <language ietfCode="cs-CZ" name="Čeština" />
- <language ietfCode="cy" name="Cymraeg" />
- <language ietfCode="da" name="Dansk" />
- <language ietfCode="de" name="Deutsch" />
- <language ietfCode="es" name="Español" />
- <language ietfCode="fr" name="Français" />
- <language ietfCode="hr-HR" name="Hrvatski" />
- <language ietfCode="id" name="Indonesia" />
- <language ietfCode="it" name="Italiano" />
- <language ietfCode="lv" name="Latvijas" />
- <language ietfCode="lt" name="Lietuvos" />
- <language ietfCode="hu-HU" name="Magyar" />
- <language ietfCode="nl-NL" name="Nederlands" />
- <language ietfCode="no" name="Norsk" />
- <language ietfCode="pl-PL" name="Polski" />
- <language ietfCode="pt-PT" name="Português" />
- <language ietfCode="pt-BR" name="Português (Brasil)" />
- <language ietfCode="ro" name="Română" />
- <language ietfCode="sq-AL" name="Shqiptar" />
- <language ietfCode="sl-SI" name="Slovenščina" />
- <language ietfCode="sk-SK" name="Slovenčina" />
- <language ietfCode="fi" name="Suomi" />
- <language ietfCode="sv" name="Svenska" />
- <language ietfCode="vi" name="Tiếng Việt" />
- <language ietfCode="tr-TR" name="Türkçe" />
- <language ietfCode="bg-BG" name="български" />
- <language ietfCode="ru" name="Русский" />
- <language ietfCode="sr" name="српски" />
- <language ietfCode="uk" name="Український" />
- <language ietfCode="grk" name="Ελληνικά" />
- <language ietfCode="he" name="עברית" />
- <language ietfCode="ar" name="العربية" />
- <language ietfCode="pes-IR" name="فارسی" />
- <language ietfCode="ur" name="اردو" />
- <language ietfCode="mr" name="मराठी" />
- <language ietfCode="si" name="Sඉන්හල" />
- <language ietfCode="th-TH" name="ภาษาไทย" />
- <language ietfCode="zh-CN" name="中文 (简体)" />
- <language ietfCode="zh-TW" name="中文 (繁體)" />
- <language ietfCode="ja-JP" name="日本語" />
- <language ietfCode="ko" name="한국어" />
-</languages>
+<?xml version="1.0" encoding="UTF-8" ?>
+<languages>
+ <language ietfCode="en" name="English" />
+ <language ietfCode="ca-AD" name="Català (Andorra)" />
+ <language ietfCode="cs-CZ" name="Čeština" />
+ <language ietfCode="cy" name="Cymraeg" />
+ <language ietfCode="da" name="Dansk" />
+ <language ietfCode="de" name="Deutsch" />
+ <language ietfCode="es" name="Español" />
+ <language ietfCode="fr" name="Français" />
+ <language ietfCode="hr-HR" name="Hrvatski" />
+ <language ietfCode="id" name="Indonesia" />
+ <language ietfCode="it" name="Italiano" />
+ <language ietfCode="lv" name="Latvijas" />
+ <language ietfCode="lt" name="Lietuvos" />
+ <language ietfCode="hu-HU" name="Magyar" />
+ <language ietfCode="nl-NL" name="Nederlands" />
+ <language ietfCode="no" name="Norsk" />
+ <language ietfCode="pl-PL" name="Polski" />
+ <language ietfCode="pt-PT" name="Português" />
+ <language ietfCode="pt-BR" name="Português (Brasil)" />
+ <language ietfCode="ro" name="Română" />
+ <language ietfCode="sq-AL" name="Shqiptar" />
+ <language ietfCode="sl-SI" name="Slovenščina" />
+ <language ietfCode="sk-SK" name="Slovenčina" />
+ <language ietfCode="fi" name="Suomi" />
+ <language ietfCode="sv" name="Svenska" />
+ <language ietfCode="vi" name="Tiếng Việt" />
+ <language ietfCode="tr-TR" name="Türkçe" />
+ <language ietfCode="bg-BG" name="български" />
+ <language ietfCode="ru" name="Русский" />
+ <language ietfCode="sr" name="српски" />
+ <language ietfCode="uk" name="Український" />
+ <language ietfCode="grk" name="Ελληνικά" />
+ <language ietfCode="he" name="עברית" />
+ <language ietfCode="ar" name="العربية" />
+ <language ietfCode="pes-IR" name="فارسی" />
+ <language ietfCode="ur" name="اردو" />
+ <language ietfCode="mr" name="मराठी" />
+ <language ietfCode="si" name="Sඉන්හල" />
+ <language ietfCode="th-TH" name="ภาษาไทย" />
+ <language ietfCode="zh-CN" name="中文 (简体)" />
+ <language ietfCode="zh-TW" name="中文 (繁體)" />
+ <language ietfCode="ja-JP" name="日本語" />
+ <language ietfCode="ko" name="한국어" />
+</languages>
diff --git a/src/gui/res/lang/gui_af-ZA.ts b/src/gui/res/lang/gui_af-ZA.ts
index 7ff6304..5e0121a 100644
--- a/src/gui/res/lang/gui_af-ZA.ts
+++ b/src/gui/res/lang/gui_af-ZA.ts
@@ -648,12 +648,17 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
+ <source>All files (*.*)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
+ <source>Barrier Configurations (*.conf)</source>
<translation type="unfinished"></translation>
</message>
<message>
diff --git a/src/gui/res/lang/gui_ar.ts b/src/gui/res/lang/gui_ar.ts
index 84ae1e6..3882b6d 100644
--- a/src/gui/res/lang/gui_ar.ts
+++ b/src/gui/res/lang/gui_ar.ts
@@ -648,12 +648,17 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
+ <source>All files (*.*)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
+ <source>Barrier Configurations (*.conf)</source>
<translation type="unfinished"></translation>
</message>
<message>
diff --git a/src/gui/res/lang/gui_bg-BG.qm b/src/gui/res/lang/gui_bg-BG.qm
index 013137d..7d02c13 100644
--- a/src/gui/res/lang/gui_bg-BG.qm
+++ b/src/gui/res/lang/gui_bg-BG.qm
Binary files differ
diff --git a/src/gui/res/lang/gui_bg-BG.ts b/src/gui/res/lang/gui_bg-BG.ts
index 6a373d8..ea45271 100644
--- a/src/gui/res/lang/gui_bg-BG.ts
+++ b/src/gui/res/lang/gui_bg-BG.ts
@@ -648,13 +648,18 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
- <translation type="finished">Конфигурации на Синерджи (*.sgc);; Всички файлове (*.*)</translation>
+ <source>All files (*.*)</source>
+ <translation type="finished">Всички файлове (*.*)</translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
+ <translation type="finished">Конфигурации на Синерджи (*.sgc)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
- <translation type="finished">Конфигурации на Синерджи (*.conf);; Всички файлове (*.*)</translation>
+ <source>Barrier Configurations (*.conf)</source>
+ <translation type="finished">Конфигурации на Синерджи (*.conf)</translation>
</message>
<message>
<location filename="src/main.cpp" line="119"/>
diff --git a/src/gui/res/lang/gui_ca-AD.qm b/src/gui/res/lang/gui_ca-AD.qm
index 351c40d..755791b 100644
--- a/src/gui/res/lang/gui_ca-AD.qm
+++ b/src/gui/res/lang/gui_ca-AD.qm
Binary files differ
diff --git a/src/gui/res/lang/gui_ca-AD.ts b/src/gui/res/lang/gui_ca-AD.ts
index 34093d9..3cd7895 100644
--- a/src/gui/res/lang/gui_ca-AD.ts
+++ b/src/gui/res/lang/gui_ca-AD.ts
@@ -648,13 +648,18 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
- <translation type="finished">Configuracions Barrier (*.sgc);;Tots els arxius (*.*)</translation>
+ <source>All files (*.*)</source>
+ <translation type="finished">Tots els arxius (*.*)</translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
+ <translation type="finished">Configuracions Barrier (*.sgc)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
- <translation type="finished">Configuracions Barrier (*.conf);;Tots els arxius (*.*)</translation>
+ <source>Barrier Configurations (*.conf)</source>
+ <translation type="finished">Configuracions Barrier (*.conf)</translation>
</message>
<message>
<location filename="src/main.cpp" line="119"/>
@@ -900,8 +905,8 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<source>Drag new screens to the grid or move existing ones around.
Drag a screen to the trashcan to delete it.
Double click on a screen to edit its settings.</source>
- <translation type="finished">Arrossega noves pantalles a la graella o mou les actuals al voltant.
-Arrossega una pantalla a la paperera per eliminar-la.
+ <translation type="finished">Arrossega noves pantalles a la graella o mou les actuals al voltant.
+Arrossega una pantalla a la paperera per eliminar-la.
Fes doble clic a una pantalla per editar la seva configuració.</translation>
</message>
<message>
@@ -1330,7 +1335,7 @@ p, li { white-space: pre-wrap; }
Server response:
%1</source>
- <translation type="finished">Error inici de sessió, hi ha hagut un error.
+ <translation type="finished">Error inici de sessió, hi ha hagut un error.
Resposta del servidor:
%1</translation>
</message>
diff --git a/src/gui/res/lang/gui_cs-CZ.qm b/src/gui/res/lang/gui_cs-CZ.qm
index 1ac02c8..23ed7bd 100644
--- a/src/gui/res/lang/gui_cs-CZ.qm
+++ b/src/gui/res/lang/gui_cs-CZ.qm
Binary files differ
diff --git a/src/gui/res/lang/gui_cs-CZ.ts b/src/gui/res/lang/gui_cs-CZ.ts
index fd7b9c7..16142bf 100644
--- a/src/gui/res/lang/gui_cs-CZ.ts
+++ b/src/gui/res/lang/gui_cs-CZ.ts
@@ -648,13 +648,18 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
- <translation type="finished">Nastavení Barrier (*.sgc);;Všechny soubory (*.*)</translation>
+ <source>All files (*.*)</source>
+ <translation type="finished">Všechny soubory (*.*)</translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
+ <translation type="finished">Nastavení Barrier (*.sgc)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
- <translation type="finished">Nastavení Barrier (*.conf);;Všechny soubory (*.*)</translation>
+ <source>Barrier Configurations (*.conf)</source>
+ <translation type="finished">Nastavení Barrier (*.conf)</translation>
</message>
<message>
<location filename="src/main.cpp" line="119"/>
diff --git a/src/gui/res/lang/gui_cy.qm b/src/gui/res/lang/gui_cy.qm
index 87bc58c..0cdb24d 100644
--- a/src/gui/res/lang/gui_cy.qm
+++ b/src/gui/res/lang/gui_cy.qm
Binary files differ
diff --git a/src/gui/res/lang/gui_cy.ts b/src/gui/res/lang/gui_cy.ts
index be9cd1d..2478fee 100644
--- a/src/gui/res/lang/gui_cy.ts
+++ b/src/gui/res/lang/gui_cy.ts
@@ -648,13 +648,18 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
- <translation type="finished">Cyfluniadau Barrier (*.sgc);;Pob ffeil (*.*)</translation>
+ <source>All files (*.*)</source>
+ <translation type="finished">Pob ffeil (*.*)</translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
+ <translation type="finished">Cyfluniadau Barrier (*.sgc)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
- <translation type="finished">Cyfluniadau Barrier (*.conf);;Pob ffeil (*.*)</translation>
+ <source>Barrier Configurations (*.conf)</source>
+ <translation type="finished">Cyfluniadau Barrier (*.conf)</translation>
</message>
<message>
<location filename="src/main.cpp" line="119"/>
diff --git a/src/gui/res/lang/gui_da.qm b/src/gui/res/lang/gui_da.qm
index f78dbb7..dc7812b 100644
--- a/src/gui/res/lang/gui_da.qm
+++ b/src/gui/res/lang/gui_da.qm
Binary files differ
diff --git a/src/gui/res/lang/gui_da.ts b/src/gui/res/lang/gui_da.ts
index 2b17c0b..7bec518 100644
--- a/src/gui/res/lang/gui_da.ts
+++ b/src/gui/res/lang/gui_da.ts
@@ -648,13 +648,18 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
- <translation type="finished">Barrier-konfigurationer (*.sgc);;Alle filer (*.*)</translation>
+ <source>All files (*.*)</source>
+ <translation type="finished">Alle filer (*.*)</translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
+ <translation type="finished">Barrier-konfigurationer (*.sgc)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
- <translation type="finished">Barrier-konfigurationer (*.conf);;Alle filer (*.*)</translation>
+ <source>Barrier Configurations (*.conf)</source>
+ <translation type="finished">Barrier-konfigurationer (*.conf)</translation>
</message>
<message>
<location filename="src/main.cpp" line="119"/>
@@ -1329,7 +1334,7 @@ p, li { white-space: pre-wrap; }
Server response:
%1</source>
- <translation type="finished">Fejl i login, en fejl opstod.
+ <translation type="finished">Fejl i login, en fejl opstod.
Server svar:
%1</translation>
</message>
diff --git a/src/gui/res/lang/gui_de.qm b/src/gui/res/lang/gui_de.qm
index eb0bb40..2e4f300 100644
--- a/src/gui/res/lang/gui_de.qm
+++ b/src/gui/res/lang/gui_de.qm
Binary files differ
diff --git a/src/gui/res/lang/gui_de.ts b/src/gui/res/lang/gui_de.ts
index 67eb994..f43ee39 100644
--- a/src/gui/res/lang/gui_de.ts
+++ b/src/gui/res/lang/gui_de.ts
@@ -1,12 +1,14 @@
-<?xml version="1.0" encoding="utf-8"?><!DOCTYPE TS><TS language="de" sourcelanguage="en" version="2.0">
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de" sourcelanguage="en">
<context>
<name>AboutDialogBase</name>
<message>
<location filename="res/AboutDialogBase.ui" line="38"/>
<source>About Barrier</source>
- <translation type="finished">Über Barrier</translation>
+ <translation>Über Barrier</translation>
</message>
- <message utf8="true">
+ <message>
<location filename="res/AboutDialogBase.ui" line="53"/>
<source>&lt;p&gt;
Keyboard and mouse sharing application. Cross platform and open source.&lt;br /&gt;&lt;br /&gt;
@@ -26,22 +28,30 @@ Barrier is based on CosmoSynergy by Richard Lee and Adam Feder.&lt;br /&gt;
The Barrier GUI is based on QSynergy by Volker Lanz.&lt;br /&gt;&lt;br /&gt;
Visit our website for help and info (symless.com).
&lt;/p&gt;</oldsource>
- <translation type="unfinished"></translation>
+ <translation>&lt;p&gt;
+Anwendung zum Teilen von Tastatur und Maus. Betriebssystemübergreifend und Open Source.&lt;br /&gt;&lt;br /&gt;
+Copyright © 2012-2016 Symless Ltd.&lt;br /&gt;
+Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.&lt;br /&gt;&lt;br /&gt;
+Barrier wird herausgegeben unter der GNU General Public License (GPLv2).&lt;br /&gt;&lt;br /&gt;
+Barrier basiert auf CosmoSynergy von Richard Lee und Adam Feder.&lt;br /&gt;
+Die Barrier-GUI basiert auf QSynergy von Volker Lanz.&lt;br /&gt;&lt;br /&gt;
+Besuchen Sie unsere Website für Hilfe und Info (symless.com).
+&lt;/p&gt;</translation>
</message>
<message>
<location filename="res/AboutDialogBase.ui" line="140"/>
<source>Unknown</source>
- <translation type="finished">Unbekannt</translation>
+ <translation>Unbekannt</translation>
</message>
<message>
<location filename="res/AboutDialogBase.ui" line="124"/>
<source>Version:</source>
- <translation type="finished">Version:</translation>
+ <translation>Version:</translation>
</message>
<message>
<location filename="res/AboutDialogBase.ui" line="163"/>
<source>&amp;Ok</source>
- <translation type="finished">&amp;Ok</translation>
+ <translation>&amp;Ok</translation>
</message>
</context>
<context>
@@ -49,97 +59,97 @@ Visit our website for help and info (symless.com).
<message>
<location filename="res/ActionDialogBase.ui" line="14"/>
<source>Configure Action</source>
- <translation type="finished">Aktion konfigurieren</translation>
+ <translation>Aktion konfigurieren</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="20"/>
<source>Choose the action to perform</source>
- <translation type="finished">Wähle eine Aktion, die ausgeführt werden soll</translation>
+ <translation>Wähle eine Aktion, die ausgeführt werden soll</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="26"/>
<source>Press a hotkey</source>
- <translation type="finished">Hotkey drücken</translation>
+ <translation>Hotkey drücken</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="36"/>
<source>Release a hotkey</source>
- <translation type="finished">Hotkey loslassen</translation>
+ <translation>Hotkey loslassen</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="43"/>
<source>Press and release a hotkey</source>
- <translation type="finished">Hotkey drücken und loslassen</translation>
+ <translation>Hotkey drücken und loslassen</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="69"/>
<source>only on these screens</source>
- <translation type="finished">Nur auf diesen Bildschirmen</translation>
+ <translation>nur auf diesen Bildschirmen</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="119"/>
<source>Switch to screen</source>
- <translation type="finished">Zu Anzeige Wechseln</translation>
+ <translation>Zum Bildschirm wechseln</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="150"/>
<source>Switch in direction</source>
- <translation type="finished">In Richtung wechseln</translation>
+ <translation>In Richtung wechseln</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="174"/>
<source>left</source>
- <translation type="finished">links</translation>
+ <translation>links</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="179"/>
<source>right</source>
- <translation type="finished">rechts</translation>
+ <translation>rechts</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="184"/>
<source>up</source>
- <translation type="finished">hoch</translation>
+ <translation>hoch</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="189"/>
<source>down</source>
- <translation type="finished">runter</translation>
+ <translation>runter</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="201"/>
<source>Lock cursor to screen</source>
- <translation type="finished">Cursor auf Anzeige beschränken</translation>
+ <translation>Cursor auf Bildschirm beschränken</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="225"/>
<source>toggle</source>
- <translation type="finished">umschalten</translation>
+ <translation>umschalten</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="230"/>
<source>on</source>
- <translation type="finished">ein</translation>
+ <translation>ein</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="235"/>
<source>off</source>
- <translation type="finished">aus</translation>
+ <translation>aus</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="248"/>
<source>This action is performed when</source>
- <translation type="finished">Diese Aktion wird ausgeführt, wenn</translation>
+ <translation>Diese Aktion wird ausgeführt, wenn</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="254"/>
<source>the hotkey is pressed</source>
- <translation type="finished">wenn der Hotkey gedrückt wird</translation>
+ <translation>wenn der Hotkey gedrückt wird</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="264"/>
<source>the hotkey is released</source>
- <translation type="finished">wenn der Hotkey losgelassen wird</translation>
+ <translation>wenn der Hotkey losgelassen wird</translation>
</message>
</context>
<context>
@@ -147,17 +157,17 @@ Visit our website for help and info (symless.com).
<message>
<location filename="res/AddClientDialogBase.ui" line="20"/>
<source>Dialog</source>
- <translation type="unfinished"></translation>
+ <translation>Dialog</translation>
</message>
<message>
<location filename="res/AddClientDialogBase.ui" line="35"/>
<source>TextLabel</source>
- <translation type="unfinished"></translation>
+ <translation>TextLabel</translation>
</message>
<message>
<location filename="res/AddClientDialogBase.ui" line="83"/>
<source>Ignore auto connect clients</source>
- <translation type="unfinished"></translation>
+ <translation>Autoconnect-Clients ignorieren</translation>
</message>
</context>
<context>
@@ -165,12 +175,12 @@ Visit our website for help and info (symless.com).
<message>
<location filename="res/HotkeyDialogBase.ui" line="14"/>
<source>Hotkey</source>
- <translation type="finished">Hotkey</translation>
+ <translation>Hotkey</translation>
</message>
<message>
<location filename="res/HotkeyDialogBase.ui" line="20"/>
<source>Enter the specification for the hotkey:</source>
- <translation type="finished">Gib die Definition für den Hotkey ein:</translation>
+ <translation>Definition für den Hotkey eingeben:</translation>
</message>
</context>
<context>
@@ -178,189 +188,193 @@ Visit our website for help and info (symless.com).
<message>
<location filename="src/MainWindow.cpp" line="790"/>
<source>&amp;Start</source>
- <translation type="finished">&amp;Start</translation>
+ <translation>&amp;Start</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="237"/>
<source>&amp;File</source>
- <translation type="finished">&amp;Datei</translation>
+ <translation>&amp;Datei</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="238"/>
<source>&amp;Edit</source>
- <translation type="finished">&amp;Bearbeiten</translation>
+ <translation>&amp;Bearbeiten</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="239"/>
<source>&amp;Window</source>
- <translation type="finished">&amp;Fenster</translation>
+ <translation>&amp;Fenster</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="240"/>
<source>&amp;Help</source>
- <translation type="finished">&amp;Hilfe</translation>
+ <translation>&amp;Hilfe</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="364"/>
<source>&lt;p&gt;Your version of Barrier is out of date. Version &lt;b&gt;%1&lt;/b&gt; is now available to &lt;a href=&quot;%2&quot;&gt;download&lt;/a&gt;.&lt;/p&gt;</source>
<oldsource>&lt;p&gt;Version %1 is now available, &lt;a href=&quot;%2&quot;&gt;visit website&lt;/a&gt;.&lt;/p&gt;</oldsource>
- <translation type="finished">&lt;p&gt;Ihre Barrier Version ist veraltet. Version &lt;b&gt;%1&lt;/b&gt; ist jetzt zum &lt;a href=&quot;%2&quot;&gt;Download&lt;/a&gt; verfügbar.&lt;/p&gt;</translation>
+ <translation>&lt;p&gt;Ihre Barrier-Version ist veraltet. Version &lt;b&gt;%1&lt;/b&gt; ist jetzt zum &lt;a href=&quot;%2&quot;&gt;Download&lt;/a&gt; verfügbar.&lt;/p&gt;</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="577"/>
<source>Program can not be started</source>
- <translation type="finished">Das Programm konnte nicht gestartet werden</translation>
+ <translation>Programm konnte nicht gestartet werden</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="577"/>
<source>The executable&lt;br&gt;&lt;br&gt;%1&lt;br&gt;&lt;br&gt;could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program.</source>
- <translation type="finished">Die Anwendung&lt;br&gt;&lt;br&gt;%1&lt;br&gt;&lt;br&gt; konnte nicht gestartet werden, obwohl sie vorhanden ist. Bitte überprüfen sie, ob sie die benötigten Berechtigungen zur Ausführung der Anwendung haben,</translation>
+ <translation>Die Anwendung&lt;br&gt;&lt;br&gt;%1&lt;br&gt;&lt;br&gt; konnte nicht gestartet werden, obwohl sie vorhanden ist. Bitte überprüfen Sie, ob Sie ausreichende Rechte zur Ausführung der Anwendung haben.</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="596"/>
<source>Barrier client not found</source>
- <translation type="finished">Der Barrier Client wurde nicht gefunden</translation>
+ <translation>Barrier-Client wurde nicht gefunden</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="597"/>
<source>The executable for the barrier client does not exist.</source>
- <translation type="finished">Die ausführbare Datei für den Barrier Client existiert nicht.</translation>
+ <translation>Die Anwendung für den Barrier-Client existiert nicht.</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="625"/>
<source>Hostname is empty</source>
- <translation type="finished">Der Hostname is leer</translation>
+ <translation>Hostname ist leer</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="626"/>
<source>Please fill in a hostname for the barrier client to connect to.</source>
- <translation type="finished">Bitte tragen Sie einen Hostnamen ein, zu dem sich der Barrier-Client verbinden soll.</translation>
+ <translation>Bitte tragen Sie einen Hostnamen ein, zu dem sich der Barrier-Client verbinden soll.</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="646"/>
<source>Cannot write configuration file</source>
- <translation type="finished">Konfigurationsdatei konnte nicht geschrieben werden</translation>
+ <translation>Konfigurationsdatei konnte nicht geschrieben werden</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="646"/>
<source>The temporary configuration file required to start barrier can not be written.</source>
- <translation type="finished">Die temporäre Konfigurationsdatei konnte nicht geschrieben werden. Sie wird jedoch für den Start von Barrier benötigt.</translation>
+ <translation>Die für den Start von Barrier nötige temporäre Konfigurationsdatei kann nicht geschrieben werden.</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="659"/>
<source>Configuration filename invalid</source>
- <translation type="finished">Der Dateiname der Konfigurationsdatei ist ungültig.</translation>
+ <translation>Dateiname der Konfigurationsdatei ungültig</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="660"/>
<source>You have not filled in a valid configuration file for the barrier server. Do you want to browse for the configuration file now?</source>
- <translation type="finished">Sie haben keine gültige Konfigurationsdatei angegeben. Wollen sie jetzt nach dieser Datei suchen?</translation>
+ <translation>Sie haben keine gültige Konfigurationsdatei für den Barrier-Server angegeben. Wollen sie jetzt nach dieser Datei suchen?</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="688"/>
<source>Barrier server not found</source>
- <translation type="finished">Der Barrier Server wurde nicht gefunden.</translation>
+ <translation>Barrier-Server nicht gefunden</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="689"/>
<source>The executable for the barrier server does not exist.</source>
- <translation type="finished">Die ausführbare Datei für den Barrier Server existiert nicht.</translation>
+ <translation>Die Anwendung für den Barrier-Server existiert nicht.</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="764"/>
<source>Barrier terminated with an error</source>
- <translation type="finished">Barrier wurde mit einem Fehler beendet.</translation>
+ <translation>Barrier mit Fehler beendet</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="764"/>
<source>Barrier terminated unexpectedly with an exit code of %1.&lt;br&gt;&lt;br&gt;Please see the log output for details.</source>
- <translation type="finished">Barrier wurde unerwartet mit Abbruchcode %1 beendet. &lt;br&gt;&lt;br&gt; Weitere Informationen können dem Log entnommen werden.</translation>
+ <translation>Barrier unerwartet mit Exit-Code %1 beendet. &lt;br&gt;&lt;br&gt;Siehe Logausgabe für weitere Details.</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="783"/>
<source>&amp;Stop</source>
- <translation type="finished">&amp;Stopp</translation>
+ <translation>&amp;Stop</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="1038"/>
<source>Please add the server (%1) to the grid.</source>
- <translation type="unfinished"></translation>
+ <translation>Bitte Server (%1) zum Gitter hinzufügen.</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="1044"/>
<source>Please drag the new client screen (%1) to the desired position on the grid.</source>
- <translation type="unfinished"></translation>
+ <translation>Bitte den Bildschirm des neuen Clients zur gewünschten Position auf dem Gitter ziehen.</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="1147"/>
<source>Failed to detect system architecture.</source>
- <translation type="unfinished"></translation>
+ <translation>System-Architektur konnte nicht ermittelt werden.</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="1165"/>
<source>Cancel</source>
- <translation type="unfinished"></translation>
+ <translation>Abbrechen</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="1189"/>
<source>Failed to download Bonjour installer to location: %1</source>
- <translation type="unfinished"></translation>
+ <translation>Bonjour-Installer konnte nicht heruntergeladen werden nach: %1</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="1226"/>
<source>Do you want to enable auto config and install Bonjour?
This feature helps you establish the connection.</source>
- <translation type="unfinished"></translation>
+ <translation>Möchten Sie Bonjour installieren, um Autoconfig zu aktivieren?
+
+Diese Funktion hilft Ihnen beim Verbindungsaufbau.</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="1270"/>
<source>Auto config feature requires Bonjour.
Do you want to install Bonjour?</source>
- <translation type="unfinished"></translation>
+ <translation>Für die Autoconfig-Funktion ist Bonjour nötig.
+
+Möchten Sie Bonjour installieren?</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="815"/>
<source>Barrier is starting.</source>
- <translation type="finished">Barrier wird gestartet.</translation>
+ <translation>Barrier startet.</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="809"/>
<source>Barrier is running.</source>
- <translation type="finished">Barrier läuft.</translation>
+ <translation>Barrier läuft.</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="819"/>
<source>Barrier is not running.</source>
- <translation type="finished">Barrier wird nicht ausgeführt.</translation>
+ <translation>Barrier läuft nicht.</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="870"/>
<source>Unknown</source>
- <translation type="finished">Unbekannt</translation>
+ <translation>Unbekannt</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="1146"/>
<location filename="src/MainWindow.cpp" line="1225"/>
<location filename="src/MainWindow.cpp" line="1269"/>
<source>Barrier</source>
- <translation type="finished">Barrier</translation>
+ <translation>Barrier</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="987"/>
<source>Browse for a barriers config file</source>
- <translation type="finished">Nach einer Konfigurationsdatei für Barrier suchen.</translation>
+ <translation>Nach einer Konfigurationsdatei für Barrier suchen</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="408"/>
<source>Barrier is now connected, You can close the config window. Barrier will remain connected in the background.</source>
- <translation type="unfinished"></translation>
+ <translation>Barrier ist jetzt verbunden. Sie können das Konfigurationsfenster schließen. Barrier wird im Hintergrund verbunden bleiben.</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="434"/>
<source>Security question</source>
- <translation type="unfinished"></translation>
+ <translation>Sicherheitsfrage</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="435"/>
@@ -368,25 +382,31 @@ Do you want to install Bonjour?</source>
%1
-This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user).
+This is a server fingerprint. You should compare this fingerprint to the one on your server&apos;s screen. If the two don&apos;t match exactly, then it&apos;s probably not the server you&apos;re expecting (it could be a malicious user).
To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No.</source>
- <translation type="unfinished"></translation>
+ <translation>Vertrauen Sie diesem Fingerabdruck?
+
+%1
+
+Dies ist ein Server-Fingerabdruck. Sie sollten ihn mit dem Fingerabdruck auf dem Server-Bildschirm vergleichen. Wenn die zwei nicht identisch sind, handelt es sich wahrscheinlich nicht um den erwarteten Server (es könnte ein böswilliger User sein).
+
+Um diesem Fingerabdruck bei zukünftigen Verbindeungen automatisch zu vertrauen, klicken Sie auf Ja. Um diesen Fingerabdruck abzulehnen und die Verbindung vom Server zu trennen, klicken Sie auf Nein.</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="1000"/>
<source>Save configuration as...</source>
- <translation type="finished">Konfiguration speichern unter ...</translation>
+ <translation>Konfiguration speichern unter ...</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="1004"/>
<source>Save failed</source>
- <translation type="finished">Speichern fehlgeschlagen</translation>
+ <translation>Speichern fehlgeschlagen</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="1004"/>
<source>Could not save configuration to file.</source>
- <translation type="finished">Konfiguration konnte nicht in Datei gespeichert werden</translation>
+ <translation>Konfiguration konnte nicht in Datei gespeichert werden</translation>
</message>
</context>
<context>
@@ -394,168 +414,168 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<message>
<location filename="res/MainWindowBase.ui" line="26"/>
<source>Barrier</source>
- <translation type="finished">Barrier</translation>
+ <translation>Barrier</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="90"/>
- <source>Ser&amp;ver (share this computer's mouse and keyboard):</source>
- <translation type="unfinished"></translation>
+ <source>Ser&amp;ver (share this computer&apos;s mouse and keyboard):</source>
+ <translation>Ser&amp;ver (Maus und Tastatur dieses Rechners teilen):</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="243"/>
<source>Screen name:</source>
- <translation type="finished">Anzeigename:</translation>
+ <translation>Bildschirmname:</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="257"/>
<source>&amp;Server IP:</source>
- <translation type="finished">Server IP:</translation>
+ <translation>&amp;Server IP:</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="380"/>
<location filename="res/MainWindowBase.ui" line="409"/>
<source>&amp;Start</source>
- <translation type="finished">&amp;Start</translation>
+ <translation>&amp;Start</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="181"/>
<source>Use existing configuration:</source>
- <translation type="finished">Verwende bestehende Konfiguration:</translation>
+ <translation>Verwende bestehende Konfiguration:</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="190"/>
<source>&amp;Configuration file:</source>
- <translation type="finished">&amp;Konfigurationsdatei:</translation>
+ <translation>&amp;Konfigurationsdatei:</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="210"/>
<source>&amp;Browse...</source>
- <translation type="finished">&amp;Durchsuchen...</translation>
+ <translation>&amp;Durchsuchen ...</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="147"/>
<source>Configure interactively:</source>
- <translation type="finished">Interaktiv konfigurieren:</translation>
+ <translation>Interaktiv konfigurieren:</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="159"/>
<source>&amp;Configure Server...</source>
- <translation type="finished">Server &amp;konfigurieren...</translation>
+ <translation>Server &amp;konfigurieren ...</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="350"/>
<source>Ready</source>
- <translation type="finished">Fertig</translation>
+ <translation>Bereit</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="296"/>
<source>Log</source>
- <translation type="finished">Log</translation>
+ <translation>Log</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="373"/>
<source>&amp;Reload</source>
- <translation type="finished">&amp;Anwenden</translation>
+ <translation>&amp;Neu laden</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="107"/>
<source>IP addresses:</source>
- <translation type="finished">IP Adressen:</translation>
+ <translation>IP-Adressen:</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="131"/>
<source>Fingerprint:</source>
- <translation type="unfinished"></translation>
+ <translation>Fingerabdruck:</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="228"/>
- <source>&amp;Client (use another computer's mouse and keyboard):</source>
- <translation type="unfinished"></translation>
+ <source>&amp;Client (use another computer&apos;s mouse and keyboard):</source>
+ <translation>&amp;Client (Maus und Tastatur eines anderen Rechners benutzen):</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="270"/>
<source>Auto config</source>
- <translation type="unfinished"></translation>
+ <translation>Autoconfig</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="390"/>
<source>&amp;About Barrier...</source>
- <translation type="finished">&amp;Über Barrier...</translation>
+ <translation>&amp;Über Barrier ...</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="398"/>
<source>&amp;Quit</source>
- <translation type="finished">&amp;Beenden</translation>
+ <translation>&amp;Beenden</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="401"/>
<source>Quit</source>
- <translation type="finished">Beenden</translation>
+ <translation>Beenden</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="412"/>
<source>Run</source>
- <translation type="finished">Start</translation>
+ <translation>Start</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="423"/>
<source>S&amp;top</source>
- <translation type="finished">S&amp;topp</translation>
+ <translation>S&amp;top</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="426"/>
<source>Stop</source>
- <translation type="finished">Stop</translation>
+ <translation>Stop</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="434"/>
<source>S&amp;how Status</source>
- <translation type="finished">S&amp;tatus anzeigen</translation>
+ <translation>S&amp;tatus anzeigen</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="442"/>
<source>&amp;Hide</source>
- <translation type="finished">&amp;Verstecken</translation>
+ <translation>&amp;Verstecken</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="445"/>
<source>Hide</source>
- <translation type="finished">Verstecken</translation>
+ <translation>Verstecken</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="453"/>
<source>&amp;Show</source>
- <translation type="finished">&amp;Zeigen</translation>
+ <translation>An&amp;zeigen</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="456"/>
<source>Show</source>
- <translation type="finished">Anzeigen</translation>
+ <translation>Anzeigen</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="464"/>
<source>Save configuration &amp;as...</source>
- <translation type="finished">Configuration speichern &amp;unter ...</translation>
+ <translation>Konfiguration speichern &amp;unter ...</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="467"/>
<source>Save the interactively generated server configuration to a file.</source>
- <translation type="finished">Speichere die interaktiv erstellte Konfiguration in eine Datei.</translation>
+ <translation>Speichere die interaktiv erstellte Konfiguration in eine Datei.</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="475"/>
<source>Settings</source>
- <translation type="finished">Einstellungen</translation>
+ <translation>Einstellungen</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="478"/>
<source>Edit settings</source>
- <translation type="finished">Einstellungen bearbeiten</translation>
+ <translation>Einstellungen bearbeiten</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="486"/>
<source>Run Wizard</source>
- <translation type="finished">Assistent ausführen</translation>
+ <translation>Assistent ausführen</translation>
</message>
</context>
<context>
@@ -563,7 +583,7 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<message>
<location filename="src/NewScreenWidget.cpp" line="32"/>
<source>Unnamed</source>
- <translation type="finished">Unbenannt</translation>
+ <translation>Unbenannt</translation>
</message>
</context>
<context>
@@ -571,28 +591,29 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<message>
<location filename="src/PluginManager.cpp" line="58"/>
<source>Failed to get plugin directory.</source>
- <translation type="unfinished"></translation>
+ <translation>Plugin-Verzeichnis konnte nicht ermittelt werden.</translation>
</message>
<message>
<location filename="src/PluginManager.cpp" line="63"/>
<source>Failed to get profile directory.</source>
- <translation type="unfinished"></translation>
+ <translation>Profil-Verzeichnis konnte nicht ermittelt werden.</translation>
</message>
<message>
<location filename="src/PluginManager.cpp" line="136"/>
- <source>Failed to download plugin '%1' to: %2
+ <source>Failed to download plugin &apos;%1&apos; to: %2
%3</source>
- <translation type="unfinished"></translation>
+ <translation>Plugin &apos;%1&apos; konnte nicht runtergeladen werden nach: %2
+%3</translation>
</message>
<message>
<location filename="src/PluginManager.cpp" line="167"/>
<source>Could not get Windows architecture type.</source>
- <translation type="unfinished"></translation>
+ <translation>Art der Windows-Architektur konnte nicht ermittelt werden.</translation>
</message>
<message>
<location filename="src/PluginManager.cpp" line="191"/>
<source>Could not get Linux architecture type.</source>
- <translation type="unfinished"></translation>
+ <translation>Art der Linux-Architektur konnte nicht ermittelt werden.</translation>
</message>
</context>
<context>
@@ -600,66 +621,71 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<message>
<location filename="res/PluginWizardPageBase.ui" line="14"/>
<source>Setup Barrier</source>
- <translation type="finished">Barrier einrichten</translation>
+ <translation>Barrier einrichten</translation>
</message>
<message>
<location filename="res/PluginWizardPageBase.ui" line="101"/>
<source>Please wait...</source>
- <translation type="unfinished"></translation>
+ <translation>Bitte warten ...</translation>
</message>
<message>
<location filename="src/PluginWizardPage.cpp" line="72"/>
<source>Error: %1</source>
- <translation type="unfinished"></translation>
+ <translation>Fehler: %1</translation>
</message>
<message>
<location filename="src/PluginWizardPage.cpp" line="80"/>
<location filename="src/PluginWizardPage.cpp" line="201"/>
<source>Setup complete.</source>
- <translation type="unfinished"></translation>
+ <translation>Einrichtung abgeschlossen.</translation>
</message>
<message>
<location filename="src/PluginWizardPage.cpp" line="93"/>
- <source>Downloading '%1' plugin (%2/%3)...</source>
- <translation type="unfinished"></translation>
+ <source>Downloading &apos;%1&apos; plugin (%2/%3)...</source>
+ <translation>Lade Plugin &apos;%1&apos; herunter (%2/%3) ...</translation>
</message>
<message>
<location filename="src/PluginWizardPage.cpp" line="104"/>
<source>Plugins installed successfully.</source>
- <translation type="unfinished"></translation>
+ <translation>Plugins erfolgreich installiert.</translation>
</message>
<message>
<location filename="src/PluginWizardPage.cpp" line="120"/>
<source>Generating SSL certificate...</source>
- <translation type="unfinished"></translation>
+ <translation>Erzeuge SSL-Zertifikat ...</translation>
</message>
<message>
<location filename="src/PluginWizardPage.cpp" line="170"/>
<source>Downloading plugin: %1 (1/%2)</source>
- <translation type="unfinished"></translation>
+ <translation>Lade Plugin herunter: %1 (1/%2)</translation>
</message>
<message>
<location filename="src/PluginWizardPage.cpp" line="239"/>
<source>Getting plugin list...</source>
- <translation type="unfinished"></translation>
+ <translation>Ermittle Plugin-Liste ...</translation>
</message>
</context>
<context>
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
- <translation type="finished">Barrier Konfigurationen (*.sgc);;Alle Dateien (*.*)</translation>
+ <source>All files (*.*)</source>
+ <translation>Alle Dateien (*.*)</translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
+ <translation>Barrier-Konfigurationen (*.sgc)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
- <translation type="finished">Barrier Konfigurationen (*.conf);;Alle Dateien (*.*)</translation>
+ <source>Barrier Configurations (*.conf)</source>
+ <translation>Barrier-Konfigurationen (*.conf)</translation>
</message>
<message>
<location filename="src/main.cpp" line="119"/>
<source>System tray is unavailable, quitting.</source>
- <translation type="finished">Infobereich ist nicht verfügbar. Beende Programm.</translation>
+ <translation>Systemabschnitt ist nicht verfügbar, beende.</translation>
</message>
</context>
<context>
@@ -667,22 +693,22 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<message>
<location filename="src/ScreenSettingsDialog.cpp" line="67"/>
<source>Screen name is empty</source>
- <translation type="finished">Der Anzeigename ist leer</translation>
+ <translation>Bildschirmname ist leer</translation>
</message>
<message>
<location filename="src/ScreenSettingsDialog.cpp" line="68"/>
<source>The screen name cannot be empty. Please either fill in a name or cancel the dialog.</source>
- <translation type="finished">Der Bildschirmname darf nicht leer sein. Bitte trage einen Namen ein oder schließe das Fenster.</translation>
+ <translation>Der Bildschirmname darf nicht leer sein. Bitte einen Namen eintragen oder das Dialogfenster abbrechen.</translation>
</message>
<message>
<location filename="src/ScreenSettingsDialog.cpp" line="83"/>
<source>Screen name matches alias</source>
- <translation type="finished">Der Anzeigename passt zum Alias</translation>
+ <translation>Bildschirmname passt zum Alias</translation>
</message>
<message>
<location filename="src/ScreenSettingsDialog.cpp" line="84"/>
<source>The screen name cannot be the same as an alias. Please either remove the alias or change the screen name.</source>
- <translation type="finished">Der Anzeigename kann nicht derselbe sein wie der Alias. Bitte entfernen sie den Alias oder ändern sie den Anzeigenamen.</translation>
+ <translation>Der Bildschirmname kann nicht derselbe sein wie ein Alias. Bitte entfernen sie den Alias oder ändern sie den Bildschirmnamen.</translation>
</message>
</context>
<context>
@@ -690,37 +716,37 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="14"/>
<source>Screen Settings</source>
- <translation type="finished">Anzeigeeinstellungen</translation>
+ <translation>Bildschirmeinstellungen</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="22"/>
<source>Screen &amp;name:</source>
- <translation type="finished">Anzeige&amp;name:</translation>
+ <translation>Bildschirm&amp;name:</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="42"/>
<source>A&amp;liases</source>
- <translation type="finished">A&amp;liase</translation>
+ <translation>A&amp;liase</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="57"/>
<source>&amp;Add</source>
- <translation type="finished">&amp;Hinzufügen</translation>
+ <translation>&amp;Hinzufügen</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="74"/>
<source>&amp;Remove</source>
- <translation type="finished">&amp;Entfernen</translation>
+ <translation>&amp;Entfernen</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="97"/>
<source>&amp;Modifier keys</source>
- <translation type="finished">&amp;Zusatztasten</translation>
+ <translation>&amp;Zusatztasten</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="106"/>
<source>&amp;Shift:</source>
- <translation type="finished">Um&amp;schalt:</translation>
+ <translation>Um&amp;schalt:</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="117"/>
@@ -729,7 +755,7 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<location filename="res/ScreenSettingsDialogBase.ui" line="258"/>
<location filename="res/ScreenSettingsDialogBase.ui" line="305"/>
<source>Shift</source>
- <translation type="finished">Umschalt</translation>
+ <translation>Umschalt</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="122"/>
@@ -738,7 +764,7 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<location filename="res/ScreenSettingsDialogBase.ui" line="263"/>
<location filename="res/ScreenSettingsDialogBase.ui" line="310"/>
<source>Ctrl</source>
- <translation type="finished">Strg</translation>
+ <translation>Strg</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="127"/>
@@ -747,7 +773,7 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<location filename="res/ScreenSettingsDialogBase.ui" line="268"/>
<location filename="res/ScreenSettingsDialogBase.ui" line="315"/>
<source>Alt</source>
- <translation type="finished">Alt</translation>
+ <translation>Alt</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="132"/>
@@ -756,7 +782,7 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<location filename="res/ScreenSettingsDialogBase.ui" line="273"/>
<location filename="res/ScreenSettingsDialogBase.ui" line="320"/>
<source>Meta</source>
- <translation type="finished">Meta</translation>
+ <translation>Meta</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="137"/>
@@ -765,7 +791,7 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<location filename="res/ScreenSettingsDialogBase.ui" line="278"/>
<location filename="res/ScreenSettingsDialogBase.ui" line="325"/>
<source>Super</source>
- <translation type="finished">Windows</translation>
+ <translation>Windows</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="142"/>
@@ -774,82 +800,82 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<location filename="res/ScreenSettingsDialogBase.ui" line="283"/>
<location filename="res/ScreenSettingsDialogBase.ui" line="330"/>
<source>None</source>
- <translation type="finished">Keine</translation>
+ <translation>Keine</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="150"/>
<source>&amp;Ctrl:</source>
- <translation type="finished">&amp;Strg:</translation>
+ <translation>&amp;Strg:</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="197"/>
<source>Al&amp;t:</source>
- <translation type="finished">Al&amp;t:</translation>
+ <translation>Al&amp;t:</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="244"/>
<source>M&amp;eta:</source>
- <translation type="finished">M&amp;eta:</translation>
+ <translation>M&amp;eta:</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="291"/>
<source>S&amp;uper:</source>
- <translation type="finished">S&amp;uper:</translation>
+ <translation>S&amp;uper:</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="358"/>
<source>&amp;Dead corners</source>
- <translation type="finished">&quot;&amp;Tote&quot; Ecken</translation>
+ <translation>&quot;&amp;Tote&quot; Ecken</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="367"/>
<source>Top-left</source>
- <translation type="finished">Oben-links</translation>
+ <translation>Oben links</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="374"/>
<source>Top-right</source>
- <translation type="finished">Oben-rechts</translation>
+ <translation>Oben rechts</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="381"/>
<source>Bottom-left</source>
- <translation type="finished">Unten-links</translation>
+ <translation>Unten links</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="388"/>
<source>Bottom-right</source>
- <translation type="finished">Unten-rechts</translation>
+ <translation>Unten rechts</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="397"/>
<source>Corner Si&amp;ze:</source>
- <translation type="finished">&amp;Größe:</translation>
+ <translation>Ecken&amp;größe:</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="428"/>
<source>&amp;Fixes</source>
- <translation type="finished">&amp;Korrekturen</translation>
+ <translation>&amp;Korrekturen</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="437"/>
<source>Fix CAPS LOCK key</source>
- <translation type="finished">Korrektur für Feststelltaste</translation>
+ <translation>Korrektur für Feststelltaste</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="444"/>
<source>Fix NUM LOCK key</source>
- <translation type="finished">Korrektur für Num Lock</translation>
+ <translation>Korrektur für Num-Lock-Taste</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="451"/>
<source>Fix SCROLL LOCK key</source>
- <translation type="finished">Korrektur für Scroll Lock</translation>
+ <translation>Korrektur für Rollen-Taste</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="458"/>
<source>Fix XTest for Xinerama</source>
- <translation type="finished">Korrektur für XTest mit Xinerama</translation>
+ <translation>Korrektur für XTest für Xinerama</translation>
</message>
</context>
<context>
@@ -857,7 +883,7 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<message>
<location filename="src/ScreenSetupModel.cpp" line="51"/>
<source>&lt;center&gt;Screen: &lt;b&gt;%1&lt;/b&gt;&lt;/center&gt;&lt;br&gt;Double click to edit settings&lt;br&gt;Drag screen to the trashcan to remove it</source>
- <translation type="finished">&lt;center&gt;Anzeige: &lt;b&gt;%1&lt;/b&gt;&lt;/center&gt;&lt;br&gt;Klicken Sie doppelt um die Einstellungen zu ändern&lt;br&gt;Ziehen Sie die Anzeige in den Papierkorb um sie zu entfernen</translation>
+ <translation>&lt;center&gt;Bildschirm: &lt;b&gt;%1&lt;/b&gt;&lt;/center&gt;&lt;br&gt;Doppelklick, um die Einstellungen zu ändern&lt;br&gt;Bildschirm in den Papierkorb ziehen, um ihn zu entfernen</translation>
</message>
</context>
<context>
@@ -865,7 +891,7 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<message>
<location filename="src/ServerConfigDialog.cpp" line="75"/>
<source>Configure server</source>
- <translation type="unfinished"></translation>
+ <translation>Server konfigurieren</translation>
</message>
</context>
<context>
@@ -873,168 +899,168 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<message>
<location filename="res/ServerConfigDialogBase.ui" line="14"/>
<source>Server Configuration</source>
- <translation type="finished">Server Konfiguration</translation>
+ <translation>Server-Konfiguration</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="24"/>
<source>Screens and links</source>
- <translation type="finished">Anzeigen und Verbindungen</translation>
+ <translation>Bildschirme und Verbindungen</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="35"/>
<source>Drag a screen from the grid to the trashcan to remove it.</source>
- <translation type="finished">Ziehen Sie eine Anzeige vom Raster in den Papierkorb um sie zu entfernen.</translation>
+ <translation>Ziehen Sie einen Bildschirm auf dem Gitter in den Papierkorb, um ihn zu entfernen.</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="60"/>
<source>Configure the layout of your barrier server configuration.</source>
- <translation type="finished">Konfigurieren Sie die Anordnung Ihrer Barrier Server Konfiguration.</translation>
+ <translation>Konfigurieren Sie die Anordnung Ihrer Barrier-Server-Konfiguration.</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="73"/>
<source>Drag this button to the grid to add a new screen.</source>
- <translation type="finished">Ziehen diese Symbol auf das Raster um eine neue Anzeige hinzuzufügen.</translation>
+ <translation>Ziehen Sie dieses Symbol auf das Gitter, um einen neuen Bildschirm hinzuzufügen.</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="128"/>
<source>Drag new screens to the grid or move existing ones around.
Drag a screen to the trashcan to delete it.
Double click on a screen to edit its settings.</source>
- <translation type="finished">Ziehen Sie neue Anzeigen auf das Raster oder verschieben sie existierende.
-Ziehen Sie eine Anzeige in den Papierkorb um sie zu entfernen.
-Klicken sie doppelt auf eine Anzeige um die Einstellungen zu bearbeiten.</translation>
+ <translation>Ziehen Sie neue Bildschirme auf das Gitter oder verschieben sie existierende.
+Ziehen Sie einen Bildschirm in den Papierkorb, um ihn zu entfernen.
+Klicken Sie doppelt auf einen Bildschirm, um dessen Einstellungen zu bearbeiten.</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="157"/>
<source>Hotkeys</source>
- <translation type="finished">Hotkeys</translation>
+ <translation>Hotkeys</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="163"/>
<source>&amp;Hotkeys</source>
- <translation type="finished">&amp;Hotkeys</translation>
+ <translation>&amp;Hotkeys</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="175"/>
<source>&amp;New</source>
- <translation type="finished">&amp;Neu</translation>
+ <translation>&amp;Neu</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="185"/>
<source>&amp;Edit</source>
- <translation type="finished">&amp;Bearbeiten</translation>
+ <translation>&amp;Bearbeiten</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="195"/>
<source>&amp;Remove</source>
- <translation type="finished">&amp;Entfernen</translation>
+ <translation>&amp;Entfernen</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="218"/>
<source>A&amp;ctions</source>
- <translation type="finished">&amp;Befehle</translation>
+ <translation>&amp;Befehle</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="230"/>
<source>Ne&amp;w</source>
- <translation type="finished">Ne&amp;u</translation>
+ <translation>Ne&amp;u</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="240"/>
<source>E&amp;dit</source>
- <translation type="finished">Än&amp;dern</translation>
+ <translation>Än&amp;dern</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="250"/>
<source>Re&amp;move</source>
- <translation type="finished">&amp;Entfernen</translation>
+ <translation>&amp;Entfernen</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="274"/>
<source>Advanced server settings</source>
- <translation type="finished">Erwiterte Servereinstellungen</translation>
+ <translation>Erweiterte Server-Einstellungen</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="280"/>
<source>&amp;Switch</source>
- <translation type="finished">Wech&amp;sel</translation>
+ <translation>Wech&amp;seln</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="291"/>
<source>Switch &amp;after waiting</source>
- <translation type="finished">Wechsel n&amp;ach Wartezeit</translation>
+ <translation>Wechseln n&amp;ach Wartezeit</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="330"/>
<location filename="res/ServerConfigDialogBase.ui" line="383"/>
<location filename="res/ServerConfigDialogBase.ui" line="458"/>
<source>ms</source>
- <translation type="finished">ms</translation>
+ <translation>ms</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="344"/>
<source>Switch on double &amp;tap within</source>
- <translation type="finished">Wechsel nach doppel&amp;ter Randberührung innerhalb von</translation>
+ <translation>Wechsel nach doppel&amp;ter Randberührung innerhalb von</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="408"/>
<source>&amp;Options</source>
- <translation type="finished">&amp;Optionen</translation>
+ <translation>&amp;Optionen</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="419"/>
<source>&amp;Check clients every</source>
- <translation type="finished">Prüfe auf Meldungen vom &amp;Client aller</translation>
+ <translation>Prüfe &amp;Clients alle</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="470"/>
<source>Use &amp;relative mouse moves</source>
- <translation type="finished">Ve&amp;rwende relative Mausbewegungen</translation>
+ <translation>Ve&amp;rwende relative Mausbewegungen</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="480"/>
<source>S&amp;ynchronize screen savers</source>
- <translation type="finished">Bildschirmschoner s&amp;ynchronisieren</translation>
+ <translation>Bildschirmschoner s&amp;ynchronisieren</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="490"/>
- <source>Don't take &amp;foreground window on Windows servers</source>
- <translation type="finished">Auf Windows Servern &amp;Fenster im Vordergrund nicht aktivieren</translation>
+ <source>Don&apos;t take &amp;foreground window on Windows servers</source>
+ <translation>Auf Windows-Servern &amp;Fenster im Vordergrund nicht aktivieren</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="510"/>
<source>Ignore auto config clients</source>
- <translation type="unfinished"></translation>
+ <translation>Ignoriere Autoconfig-Clients</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="520"/>
<source>&amp;Dead corners</source>
- <translation type="finished">&quot;&amp;Tote&quot; Ecken</translation>
+ <translation>&quot;&amp;Tote&quot; Ecken</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="529"/>
<source>To&amp;p-left</source>
- <translation type="finished">O&amp;ben-links</translation>
+ <translation>O&amp;ben links</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="536"/>
<source>Top-rig&amp;ht</source>
- <translation type="finished">Oben-rec&amp;hts</translation>
+ <translation>Oben rec&amp;hts</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="543"/>
<source>&amp;Bottom-left</source>
- <translation type="finished">&amp;Unten-links</translation>
+ <translation>&amp;Unten links</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="550"/>
<source>Bottom-ri&amp;ght</source>
- <translation type="finished">Unten-rec&amp;hts</translation>
+ <translation>Unten rec&amp;hts</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="572"/>
<source>Cor&amp;ner Size:</source>
- <translation type="finished">&amp;Größe:</translation>
+ <translation>Ecken&amp;größe:</translation>
</message>
</context>
<context>
@@ -1042,20 +1068,20 @@ Klicken sie doppelt auf eine Anzeige um die Einstellungen zu bearbeiten.</transl
<message>
<location filename="src/SettingsDialog.cpp" line="131"/>
<source>Save log file to...</source>
- <translation type="finished">Speicherort des Logfiles</translation>
+ <translation>Logfile speichern nach ...</translation>
</message>
<message>
<location filename="src/SettingsDialog.cpp" line="151"/>
<source>Elevate Barrier</source>
- <translation type="finished">Barrier Befördern</translation>
+ <translation>Barrier als Admin ausführen</translation>
</message>
<message>
<location filename="src/SettingsDialog.cpp" line="152"/>
<source>Are you sure you want to elevate Barrier?
This allows Barrier to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Barrier only if you really need to.</source>
- <translation type="finished">Sind Sie sicher das Sie Barrier Erweiterte Benutzerrechte einräumen wollen?
-Das erlaubt Barrier mit Prozessen die höhere Rechte haben und dem UAC-Dialog zu interagieren, kann aber bei normalen Prozessen Probleme verursachen. Erweiterte Rechte an Barrier bitte nur vergeben wenn es unbedingt nötig ist.</translation>
+ <translation>Sind Sie sicher, dass Sie Barrier erweiterte Benutzerrechte einräumen wollen?
+Das erlaubt Barrier, mit Prozessen, die höhere Rechte haben, und dem UAC-Dialog zu interagieren, kann aber bei normalen Prozessen Probleme verursachen. Erweiterte Rechte an Barrier bitte nur vergeben, wenn es unbedingt nötig ist.</translation>
</message>
</context>
<context>
@@ -1063,107 +1089,107 @@ Das erlaubt Barrier mit Prozessen die höhere Rechte haben und dem UAC-Dialog zu
<message>
<location filename="res/SettingsDialogBase.ui" line="14"/>
<source>Settings</source>
- <translation type="finished">Einstellungen</translation>
+ <translation>Einstellungen</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="32"/>
<source>Sc&amp;reen name:</source>
- <translation type="finished">&amp;Anzeigename:</translation>
+ <translation>&amp;Bildschirmname:</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="49"/>
<source>P&amp;ort:</source>
- <translation type="finished">P&amp;ort:</translation>
+ <translation>P&amp;ort:</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="78"/>
<source>&amp;Interface:</source>
- <translation type="finished">Schn&amp;ittstelle</translation>
+ <translation>Schn&amp;ittstelle</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="120"/>
<source>Elevate mode</source>
- <translation type="unfinished"></translation>
+ <translation>Admin-Modus</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="127"/>
<source>&amp;Hide on startup</source>
- <translation type="unfinished"></translation>
+ <translation>Beim Starten &amp;verstecken</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="146"/>
<source>&amp;Network Security</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Netzwerksicherheit</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="155"/>
<source>Use &amp;SSL encryption (unique certificate)</source>
- <translation type="unfinished"></translation>
+ <translation>Verwende &amp;SSL-Verschlüsselung (eindeutiges Zertifikat)</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="184"/>
<source>Logging</source>
- <translation type="finished">Protokollierung</translation>
+ <translation>Protokollierung</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="202"/>
<source>&amp;Logging level:</source>
- <translation type="finished">&amp;Umfang:</translation>
+ <translation>&amp;Umfang:</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="251"/>
<source>Log to file:</source>
- <translation type="finished">In Datei:</translation>
+ <translation>Protokolliere in Datei:</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="268"/>
<source>Browse...</source>
- <translation type="finished">Durchsuchen...</translation>
+ <translation>Durchsuchen ...</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="213"/>
<source>Error</source>
- <translation type="finished">Fehler</translation>
+ <translation>Fehler</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="107"/>
<source>&amp;Language:</source>
- <translation type="finished">Sprache:</translation>
+ <translation>Sprache:</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="20"/>
<source>&amp;Miscellaneous</source>
- <translation type="finished">&amp;Sonstiges</translation>
+ <translation>&amp;Sonstiges</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="218"/>
<source>Warning</source>
- <translation type="finished">Warnung</translation>
+ <translation>Warnung</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="223"/>
<source>Note</source>
- <translation type="finished">Hinweis</translation>
+ <translation>Hinweis</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="228"/>
<source>Info</source>
- <translation type="finished">Info</translation>
+ <translation>Info</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="233"/>
<source>Debug</source>
- <translation type="finished">Debug</translation>
+ <translation>Debug</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="238"/>
<source>Debug1</source>
- <translation type="finished">Debug1</translation>
+ <translation>Debug1</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="243"/>
<source>Debug2</source>
- <translation type="finished">Debug2</translation>
+ <translation>Debug2</translation>
</message>
</context>
<context>
@@ -1171,17 +1197,17 @@ Das erlaubt Barrier mit Prozessen die höhere Rechte haben und dem UAC-Dialog zu
<message>
<location filename="src/SetupWizard.cpp" line="72"/>
<source>Setup Barrier</source>
- <translation type="finished">Barrier einrichten</translation>
+ <translation>Barrier einrichten</translation>
</message>
<message>
<location filename="src/SetupWizard.cpp" line="113"/>
<source>Please select an option.</source>
- <translation type="finished">Bitte wählen Sie eine option aus.</translation>
+ <translation>Bitte wählen Sie eine Option aus.</translation>
</message>
<message>
<location filename="src/SetupWizard.cpp" line="80"/>
<source>Please enter your email address and password.</source>
- <translation type="finished">Bitte geben Sie Ihre E-Mail Adresse und Ihr Passwort ein.</translation>
+ <translation>Bitte geben Sie Ihre E-Mail-Adresse und Ihr Passwort ein.</translation>
</message>
</context>
<context>
@@ -1189,85 +1215,93 @@ Das erlaubt Barrier mit Prozessen die höhere Rechte haben und dem UAC-Dialog zu
<message>
<location filename="res/SetupWizardBase.ui" line="26"/>
<source>Setup Barrier</source>
- <translation type="finished">Barrier einrichten</translation>
+ <translation>Barrier einrichten</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="30"/>
<source>Welcome</source>
- <translation type="finished">Willkommen</translation>
+ <translation>Willkommen</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="39"/>
<source>Thanks for installing Barrier!</source>
- <translation type="finished">Danke, dass du Barrier installiert hast!</translation>
+ <translation>Danke, dass Sie Barrier installiert haben!</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="114"/>
- <source>Barrier lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Barrier is cross-platform (works on Windows, Mac OS X and Linux).</source>
- <translation type="finished">Mit Barrier können Sie einfach Ihre Tastatur und Maus an mehreren Computern auf Ihrem Schreibtisch nutzen, und es ist Frei und Open Source. Bewegen Sie einfach ihre Maus über den Rand des Bildschirms eines Computers auf den Bildschirm eines anderen. Sie können sogar den Inhalt ihrer Zwischenablage an alle Computer verteilen. Alles was Sie brauchen ist ein Netzwerk-Anschluss. Barrier funktioniert auf Windows, Mac OS X und Linux.</translation>
+ <source>Barrier lets you easily share your mouse and keyboard between multiple computers on your desk, and it&apos;s Free and Open Source. Just move your mouse off the edge of one computer&apos;s screen on to another. You can even share all of your clipboards. All you need is a network connection. Barrier is cross-platform (works on Windows, Mac OS X and Linux).</source>
+ <translation>Mit Barrier können Sie einfach Ihre Tastatur und Maus mit mehreren Computern auf Ihrem Schreibtisch teilen, und es ist frei und Open Source. Bewegen Sie einfach ihre Maus über den Rand des Bildschirms eines Computers auf den Bildschirm eines anderen. Sie können sogar den Inhalt ihrer Zwischenablage teilen. Alles, was Sie brauchen, ist ein Netzwerk-Verbindung. Barrier ist betriebssystemübergreifend (funktioniert auf Windows, Mac OS X und Linux).</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="125"/>
<source>Activate</source>
- <translation type="unfinished"></translation>
+ <translation>Aktivieren</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="131"/>
<source>&amp;Activate now...</source>
- <translation type="unfinished"></translation>
+ <translation>Jetzt &amp;aktivieren ...</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="152"/>
<source>Email:</source>
- <translation type="unfinished"></translation>
+ <translation>E-Mail:</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="178"/>
<source>Password:</source>
- <translation type="unfinished"></translation>
+ <translation>Passwort:</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="204"/>
<source>&lt;a href=&quot;https://symless.com/account/reset/&quot;&gt;Forgot password&lt;/a&gt;</source>
- <translation type="unfinished"></translation>
+ <translation>&lt;a href=&quot;https://symless.com/account/reset/&quot;&gt;Passwort vergessen&lt;/a&gt;</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="232"/>
<source>&amp;Skip activation</source>
- <translation type="unfinished"></translation>
+ <translation>Aktivierung über&amp;springen</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="277"/>
- <source>&amp;Server (share this computer's mouse and keyboard)</source>
- <translation type="unfinished"></translation>
+ <source>&amp;Server (share this computer&apos;s mouse and keyboard)</source>
+ <translation>&amp;Server (Maus und Tastatur dieses Rechners teilen)</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="290"/>
<source>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
-&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
- <translation type="unfinished"></translation>
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer&apos;s screen. There can only be one server in your setup.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;Meine Haupt-Maus und -Tastatur sind mit diesem Rechner verbunden. Das ermöglicht Ihnen, den Mauszeiger zum Bildschirm eines anderen Rechners zu bewegen. Es kann nur ein Server in Ihren Einstellungen vorhanden sein.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="326"/>
- <source>&amp;Client (use another computer's mouse and keyboard)</source>
- <translation type="unfinished"></translation>
+ <source>&amp;Client (use another computer&apos;s mouse and keyboard)</source>
+ <translation>&amp;Client (Maus und Tastatur eines anderen Rechners benutzen)</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="339"/>
<source>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
-&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
- <translation type="unfinished"></translation>
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;You have already set up a server. This computer will be controlled using the server&apos;s mouse and keyboard. There can be many clients in your setup.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;Sie haben bereits einen Server eingerichtet. Dieser Rechner wird von der Maus und Tastatur des Servers kontrolliert. Es kann viele Clients in Ihren Einstellungen geben.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="262"/>
<source>Server or Client?</source>
- <translation type="finished">Server oder Client?</translation>
+ <translation>Server oder Client?</translation>
</message>
</context>
<context>
@@ -1275,22 +1309,22 @@ p, li { white-space: pre-wrap; }
<message>
<location filename="src/SslCertificate.cpp" line="42"/>
<source>Failed to get profile directory.</source>
- <translation type="unfinished"></translation>
+ <translation>Profil-Verzeichnis kann nicht ermittelt werden.</translation>
</message>
<message>
<location filename="src/SslCertificate.cpp" line="141"/>
<source>SSL certificate generated.</source>
- <translation type="unfinished"></translation>
+ <translation>SSZ-Zertifikat erzeugt.</translation>
</message>
<message>
<location filename="src/SslCertificate.cpp" line="170"/>
<source>SSL fingerprint generated.</source>
- <translation type="unfinished"></translation>
+ <translation>SSL-Fingerabdruck erzeugt.</translation>
</message>
<message>
<location filename="src/SslCertificate.cpp" line="173"/>
<source>Failed to find SSL fingerprint.</source>
- <translation type="unfinished"></translation>
+ <translation>SSL-Fingerabdruck kann nicht gefunden werden.</translation>
</message>
</context>
<context>
@@ -1298,7 +1332,7 @@ p, li { white-space: pre-wrap; }
<message>
<location filename="src/VersionChecker.cpp" line="102"/>
<source>Unknown</source>
- <translation type="finished">Unbekannt</translation>
+ <translation>Unbekannt</translation>
</message>
</context>
<context>
@@ -1308,19 +1342,22 @@ p, li { white-space: pre-wrap; }
<source>An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details.
%1</source>
- <translation type="unfinished"></translation>
+ <translation>Ein Fehler ist beim Einloggen aufgetreten. Bitte kontaktieren Sie das Helpdesk und halten Sie die folgenden Informationen bereit.
+
+%1</translation>
</message>
<message>
<location filename="src/WebClient.cpp" line="65"/>
<source>Login failed, invalid email or password.</source>
- <translation type="finished">Login fehlgeschlagen, falsche E-Mail Adresse oder Passwort.</translation>
+ <translation>Login fehlgeschlagen, E-Mail-Adresse oder Passwort ungültig.</translation>
</message>
<message>
<location filename="src/WebClient.cpp" line="78"/>
<source>Login failed, an error occurred.
%1</source>
- <translation type="finished">Login fehlgeschlagen, ein Fehler ist aufgetreten.
+ <translation>Login fehlgeschlagen, ein Fehler ist aufgetreten.
+
%1</translation>
</message>
<message>
@@ -1330,8 +1367,10 @@ p, li { white-space: pre-wrap; }
Server response:
%1</source>
- <translation type="finished">Login fehlgeschlagen, ein Fehler ist aufgetreten.
-Serverantwort:
+ <translation>Login fehlgeschlagen, ein Fehler ist aufgetreten.
+
+Server-Antwort:
+
%1</translation>
</message>
<message>
@@ -1339,19 +1378,23 @@ Serverantwort:
<source>An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details.
%1</source>
- <translation type="unfinished"></translation>
+ <translation>Ein error ist bei der Abfrage der Plugin-Liste aufgetreten. Bitte kontaktieren Sie das Helpdesk und halten Sie die folgenden Informationen bereit.
+
+%1</translation>
</message>
<message>
<location filename="src/WebClient.cpp" line="120"/>
<source>Get plugin list failed, invalid user email or password.</source>
- <translation type="unfinished"></translation>
+ <translation>Konnte Plugin-Liste nicht ermitteln, E-Mail-Adresse oder Passwort ungültig.</translation>
</message>
<message>
<location filename="src/WebClient.cpp" line="131"/>
<source>Get plugin list failed, an error occurred.
%1</source>
- <translation type="unfinished"></translation>
+ <translation>Konnte Plugin-Liste nicht ermitteln, ein Fehler ist aufgetreten.
+
+%1</translation>
</message>
<message>
<location filename="src/WebClient.cpp" line="137"/>
@@ -1360,7 +1403,11 @@ Serverantwort:
Server response:
%1</source>
- <translation type="unfinished"></translation>
+ <translation>Konnte Plugin-Liste nicht ermitteln, ein Fehler ist aufgetreten.
+
+Server-Antwort:
+
+%1</translation>
</message>
</context>
<context>
@@ -1368,44 +1415,44 @@ Server response:
<message>
<location filename="src/ZeroconfService.cpp" line="82"/>
<source>zeroconf server detected: %1</source>
- <translation type="unfinished"></translation>
+ <translation>Zeroconf-Server erkannt: %1</translation>
</message>
<message>
<location filename="src/ZeroconfService.cpp" line="91"/>
<source>zeroconf client detected: %1</source>
- <translation type="unfinished"></translation>
+ <translation>Zeroconf-Client erkannt: %1</translation>
</message>
<message>
<location filename="src/ZeroconfService.cpp" line="99"/>
<location filename="src/ZeroconfService.cpp" line="130"/>
<source>Zero configuration service</source>
- <translation type="unfinished"></translation>
+ <translation>Zero-Configuration-Dienst</translation>
</message>
<message>
<location filename="src/ZeroconfService.cpp" line="100"/>
<source>Error code: %1.</source>
- <translation type="unfinished"></translation>
+ <translation>Fehlercode: %1.</translation>
</message>
<message>
<location filename="src/ZeroconfService.cpp" line="131"/>
<source>Unable to start the zeroconf: %1.</source>
- <translation type="unfinished"></translation>
+ <translation>Zeroconf konnte nicht gestartet werden: %1.</translation>
</message>
<message>
<location filename="src/ZeroconfService.cpp" line="140"/>
<source>Barrier</source>
- <translation type="finished">Barrier</translation>
+ <translation>Barrier</translation>
</message>
<message>
<location filename="src/ZeroconfService.cpp" line="141"/>
<source>Failed to get local IP address. Please manually type in server address on your clients</source>
- <translation type="unfinished"></translation>
+ <translation>Lokale IP-Adresse nicht ermittelbar. Bitte die Server-Adresse an den Clients manuell eingeben</translation>
</message>
<message>
<location filename="src/ZeroconfService.cpp" line="147"/>
<location filename="src/ZeroconfService.cpp" line="154"/>
<source>%1</source>
- <translation type="unfinished"></translation>
+ <translation>%1</translation>
</message>
</context>
-</TS> \ No newline at end of file
+</TS>
diff --git a/src/gui/res/lang/gui_es.qm b/src/gui/res/lang/gui_es.qm
index d09974e..1a8735d 100644
--- a/src/gui/res/lang/gui_es.qm
+++ b/src/gui/res/lang/gui_es.qm
Binary files differ
diff --git a/src/gui/res/lang/gui_es.ts b/src/gui/res/lang/gui_es.ts
index 4b3523a..39fb569 100644
--- a/src/gui/res/lang/gui_es.ts
+++ b/src/gui/res/lang/gui_es.ts
@@ -648,13 +648,18 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
- <translation type="finished">Configuraciones Barrier (*.sgc);;Todos los archivos (*.*)</translation>
+ <source>All files (*.*)</source>
+ <translation type="finished">Todos los archivos (*.*)</translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
+ <translation type="finished">Configuraciones Barrier (*.sgc)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
- <translation type="finished">Configuraciones Barrier (*.conf);;Todos los archivos (*.*)</translation>
+ <source>Barrier Configurations (*.conf)</source>
+ <translation type="finished">Configuraciones Barrier (*.conf)</translation>
</message>
<message>
<location filename="src/main.cpp" line="119"/>
diff --git a/src/gui/res/lang/gui_et-EE.qm b/src/gui/res/lang/gui_et-EE.qm
index 7c2fc9b..2c8fe11 100644
--- a/src/gui/res/lang/gui_et-EE.qm
+++ b/src/gui/res/lang/gui_et-EE.qm
Binary files differ
diff --git a/src/gui/res/lang/gui_et-EE.ts b/src/gui/res/lang/gui_et-EE.ts
index 033b9d7..ddbf6f7 100644
--- a/src/gui/res/lang/gui_et-EE.ts
+++ b/src/gui/res/lang/gui_et-EE.ts
@@ -648,13 +648,18 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
- <translation type="finished">Barrier seaded (*.sgc);;kõik failid (*.*)</translation>
+ <source>All files (*.*)</source>
+ <translation type="finished">Kõik failid (*.*)</translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
+ <translation type="finished">Barrier seaded (*.sgc)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
- <translation type="finished">Barrier seaded (*.conf);;Kõik failid (*.*)</translation>
+ <source>Barrier Configurations (*.conf)</source>
+ <translation type="finished">Barrier seaded (*.conf)</translation>
</message>
<message>
<location filename="src/main.cpp" line="119"/>
diff --git a/src/gui/res/lang/gui_fi.qm b/src/gui/res/lang/gui_fi.qm
index 1e7178c..7a8ae49 100644
--- a/src/gui/res/lang/gui_fi.qm
+++ b/src/gui/res/lang/gui_fi.qm
Binary files differ
diff --git a/src/gui/res/lang/gui_fi.ts b/src/gui/res/lang/gui_fi.ts
index e5aea17..6609da9 100644
--- a/src/gui/res/lang/gui_fi.ts
+++ b/src/gui/res/lang/gui_fi.ts
@@ -648,13 +648,18 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
- <translation type="finished">Barrier Configuration (*.sgc);;Kaikki tiedostot (*.*)</translation>
+ <source>All files (*.*)</source>
+ <translation type="finished">Kaikki tiedostot (*.*)</translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
+ <translation type="finished">Barrier Configuration (*.sgc)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
- <translation type="finished">Barrier Configuration (*.conf);;Kaikki tiedostot (*.*)</translation>
+ <source>Barrier Configurations (*.conf)</source>
+ <translation type="finished">Barrier Configuration (*.conf)</translation>
</message>
<message>
<location filename="src/main.cpp" line="119"/>
diff --git a/src/gui/res/lang/gui_fr.qm b/src/gui/res/lang/gui_fr.qm
index 38116ce..a68df9d 100644
--- a/src/gui/res/lang/gui_fr.qm
+++ b/src/gui/res/lang/gui_fr.qm
Binary files differ
diff --git a/src/gui/res/lang/gui_fr.ts b/src/gui/res/lang/gui_fr.ts
index ed37997..66258ed 100644
--- a/src/gui/res/lang/gui_fr.ts
+++ b/src/gui/res/lang/gui_fr.ts
@@ -648,13 +648,18 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
- <translation type="finished">Configuration Barrier (*.sgc);; Tous les fichiers (*.*)</translation>
+ <source>All files (*.*)</source>
+ <translation type="finished">Tous les fichiers (*.*)</translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
+ <translation type="finished">Configuration Barrier (*.sgc)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
- <translation type="finished">Barrier Configurations (*.conf);;All files (*.*)</translation>
+ <source>Barrier Configurations (*.conf)</source>
+ <translation type="finished">Configuration Barrier (*.conf)</translation>
</message>
<message>
<location filename="src/main.cpp" line="119"/>
diff --git a/src/gui/res/lang/gui_gl.ts b/src/gui/res/lang/gui_gl.ts
index 2f89802..e0a95b7 100644
--- a/src/gui/res/lang/gui_gl.ts
+++ b/src/gui/res/lang/gui_gl.ts
@@ -648,12 +648,17 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
+ <source>All files (*.*)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
+ <source>Barrier Configurations (*.conf)</source>
<translation type="unfinished"></translation>
</message>
<message>
diff --git a/src/gui/res/lang/gui_grk.ts b/src/gui/res/lang/gui_grk.ts
index ffbede5..751db12 100644
--- a/src/gui/res/lang/gui_grk.ts
+++ b/src/gui/res/lang/gui_grk.ts
@@ -648,12 +648,17 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
+ <source>All files (*.*)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
+ <source>Barrier Configurations (*.conf)</source>
<translation type="unfinished"></translation>
</message>
<message>
diff --git a/src/gui/res/lang/gui_he.qm b/src/gui/res/lang/gui_he.qm
index 43fa7af..9bbf530 100644
--- a/src/gui/res/lang/gui_he.qm
+++ b/src/gui/res/lang/gui_he.qm
Binary files differ
diff --git a/src/gui/res/lang/gui_he.ts b/src/gui/res/lang/gui_he.ts
index 5a1ddcf..2850e83 100644
--- a/src/gui/res/lang/gui_he.ts
+++ b/src/gui/res/lang/gui_he.ts
@@ -648,13 +648,18 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
- <translation type="finished">קבצי הגדרות של Barrier (*.sgc);;All Files (*.*)</translation>
+ <source>All files (*.*)</source>
+ <translation type="finished">All Files (*.*)</translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
+ <translation type="finished">קבצי הגדרות של Barrier (*.sgc)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
- <translation type="finished">קבצי הגדרות של Barrier (*.conf);;All Files (*.*)</translation>
+ <source>Barrier Configurations (*.conf)</source>
+ <translation type="finished">קבצי הגדרות של Barrier (*.conf)</translation>
</message>
<message>
<location filename="src/main.cpp" line="119"/>
diff --git a/src/gui/res/lang/gui_hi.ts b/src/gui/res/lang/gui_hi.ts
index 57b409e..460a1bc 100644
--- a/src/gui/res/lang/gui_hi.ts
+++ b/src/gui/res/lang/gui_hi.ts
@@ -648,12 +648,17 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
+ <source>All files (*.*)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
+ <source>Barrier Configurations (*.conf)</source>
<translation type="unfinished"></translation>
</message>
<message>
diff --git a/src/gui/res/lang/gui_hr-HR.qm b/src/gui/res/lang/gui_hr-HR.qm
index a7e5563..9dd5d45 100644
--- a/src/gui/res/lang/gui_hr-HR.qm
+++ b/src/gui/res/lang/gui_hr-HR.qm
Binary files differ
diff --git a/src/gui/res/lang/gui_hr-HR.ts b/src/gui/res/lang/gui_hr-HR.ts
index 4695e4e..c9883ed 100644
--- a/src/gui/res/lang/gui_hr-HR.ts
+++ b/src/gui/res/lang/gui_hr-HR.ts
@@ -648,13 +648,18 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
- <translation type="finished">Barrier postavke (*.sgc);;Sve datoteke (*.*)</translation>
+ <source>All files (*.*)</source>
+ <translation type="finished">Sve datoteke (*.*)</translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
+ <translation type="finished">Barrier postavke (*.sgc)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
- <translation type="finished">Barrier postavke (*.conf);;Sve datoteke (*.*)</translation>
+ <source>Barrier Configurations (*.conf)</source>
+ <translation type="finished">Barrier postavke (*.conf)</translation>
</message>
<message>
<location filename="src/main.cpp" line="119"/>
diff --git a/src/gui/res/lang/gui_hu-HU.qm b/src/gui/res/lang/gui_hu-HU.qm
index 10361b7..678cc5c 100644
--- a/src/gui/res/lang/gui_hu-HU.qm
+++ b/src/gui/res/lang/gui_hu-HU.qm
Binary files differ
diff --git a/src/gui/res/lang/gui_hu-HU.ts b/src/gui/res/lang/gui_hu-HU.ts
index 7c26d46..536c904 100644
--- a/src/gui/res/lang/gui_hu-HU.ts
+++ b/src/gui/res/lang/gui_hu-HU.ts
@@ -648,13 +648,18 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
- <translation type="finished">Barrier konfiguráció (*.sgc);;Minden fájl (*.*)</translation>
+ <source>All files (*.*)</source>
+ <translation type="finished">Minden fájl (*.*)</translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
+ <translation type="finished">Barrier konfiguráció (*.sgc)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
- <translation type="finished">Barrier konfiguráció (*.conf);;Minden fájl (*.*)</translation>
+ <source>Barrier Configurations (*.conf)</source>
+ <translation type="finished">Barrier konfiguráció (*.conf)</translation>
</message>
<message>
<location filename="src/main.cpp" line="119"/>
diff --git a/src/gui/res/lang/gui_id.ts b/src/gui/res/lang/gui_id.ts
index ed52252..1552cb8 100644
--- a/src/gui/res/lang/gui_id.ts
+++ b/src/gui/res/lang/gui_id.ts
@@ -648,12 +648,17 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
+ <source>All files (*.*)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
+ <source>Barrier Configurations (*.conf)</source>
<translation type="unfinished"></translation>
</message>
<message>
diff --git a/src/gui/res/lang/gui_is-IS.ts b/src/gui/res/lang/gui_is-IS.ts
index 2764171..4a76edd 100644
--- a/src/gui/res/lang/gui_is-IS.ts
+++ b/src/gui/res/lang/gui_is-IS.ts
@@ -648,12 +648,17 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
+ <source>All files (*.*)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
+ <source>Barrier Configurations (*.conf)</source>
<translation type="unfinished"></translation>
</message>
<message>
diff --git a/src/gui/res/lang/gui_it.qm b/src/gui/res/lang/gui_it.qm
index bc8dc7e..9ba0ea0 100644
--- a/src/gui/res/lang/gui_it.qm
+++ b/src/gui/res/lang/gui_it.qm
Binary files differ
diff --git a/src/gui/res/lang/gui_it.ts b/src/gui/res/lang/gui_it.ts
index c1096dd..c0a6c58 100644
--- a/src/gui/res/lang/gui_it.ts
+++ b/src/gui/res/lang/gui_it.ts
@@ -648,13 +648,18 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
- <translation type="finished">Configurazioni di Barrier (*.sgc);;Tutti i files (*.*)</translation>
+ <source>All files (*.*)</source>
+ <translation type="finished">Tutti i files (*.*)</translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
+ <translation type="finished">Configurazioni di Barrier (*.sgc)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
- <translation type="finished">Configurazioni di Barrier (*.conf);;Tutti i files (*.*)</translation>
+ <source>Barrier Configurations (*.conf)</source>
+ <translation type="finished">Configurazioni di Barrier (*.conf)</translation>
</message>
<message>
<location filename="src/main.cpp" line="119"/>
diff --git a/src/gui/res/lang/gui_ja-JP.qm b/src/gui/res/lang/gui_ja-JP.qm
index 90ff995..7209979 100644
--- a/src/gui/res/lang/gui_ja-JP.qm
+++ b/src/gui/res/lang/gui_ja-JP.qm
Binary files differ
diff --git a/src/gui/res/lang/gui_ja-JP.ts b/src/gui/res/lang/gui_ja-JP.ts
index e7ff5bd..1d80d2d 100644
--- a/src/gui/res/lang/gui_ja-JP.ts
+++ b/src/gui/res/lang/gui_ja-JP.ts
@@ -1,12 +1,14 @@
-<?xml version="1.0" encoding="utf-8"?><!DOCTYPE TS><TS language="ja-JP" sourcelanguage="en" version="2.0">
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="ja_JP" sourcelanguage="en">
<context>
<name>AboutDialogBase</name>
<message>
<location filename="res/AboutDialogBase.ui" line="38"/>
<source>About Barrier</source>
- <translation type="finished">Barrierについて</translation>
+ <translation>Barrier について</translation>
</message>
- <message utf8="true">
+ <message>
<location filename="res/AboutDialogBase.ui" line="53"/>
<source>&lt;p&gt;
Keyboard and mouse sharing application. Cross platform and open source.&lt;br /&gt;&lt;br /&gt;
@@ -26,22 +28,30 @@ Barrier is based on CosmoSynergy by Richard Lee and Adam Feder.&lt;br /&gt;
The Barrier GUI is based on QSynergy by Volker Lanz.&lt;br /&gt;&lt;br /&gt;
Visit our website for help and info (symless.com).
&lt;/p&gt;</oldsource>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">&lt;p&gt;
+キーボードとマウスの共有ソフトウェアです。クロスプラットフォームでオープンソースです。&lt;br /&gt;&lt;br /&gt;
+Copyright © 2012-2016 Symless Ltd.&lt;br /&gt;
+Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.&lt;br /&gt;&lt;br /&gt;
+Barrier は GNU General Public (GPLv2). のライセンスで公開されています。&lt;br /&gt;&lt;br /&gt;
+Barrier のベースは CosmoSynergy (Richard Lee, Adam Feder 開発) です。&lt;br /&gt;
+Barrier の GUI は QSynergy (Volker Lanz 開発) がベースです。&lt;br /&gt;&lt;br /&gt;
+Visit our website for help and info (symless.com).
+&lt;/p&gt;</translation>
</message>
<message>
<location filename="res/AboutDialogBase.ui" line="140"/>
<source>Unknown</source>
- <translation type="finished">不明</translation>
+ <translation>不明</translation>
</message>
<message>
<location filename="res/AboutDialogBase.ui" line="124"/>
<source>Version:</source>
- <translation type="finished">バージョン:</translation>
+ <translation>バージョン:</translation>
</message>
<message>
<location filename="res/AboutDialogBase.ui" line="163"/>
<source>&amp;Ok</source>
- <translation type="finished">OK</translation>
+ <translation>OK(&amp;O)</translation>
</message>
</context>
<context>
@@ -49,97 +59,97 @@ Visit our website for help and info (symless.com).
<message>
<location filename="res/ActionDialogBase.ui" line="14"/>
<source>Configure Action</source>
- <translation type="finished">動作を構成</translation>
+ <translation>アクションの設定</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="20"/>
<source>Choose the action to perform</source>
- <translation type="finished">実行する動作を選択</translation>
+ <translation>実行するアクションを選択</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="26"/>
<source>Press a hotkey</source>
- <translation type="finished">ホットキーを押す</translation>
+ <translation>ホットキーを押す</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="36"/>
<source>Release a hotkey</source>
- <translation type="finished">ホットキーを離す</translation>
+ <translation>ホットキーを離す</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="43"/>
<source>Press and release a hotkey</source>
- <translation type="finished">ホットキーを押して離す</translation>
+ <translation>ホットキーを押して離す</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="69"/>
<source>only on these screens</source>
- <translation type="finished">これらの画面だけ</translation>
+ <translation>これらのモニターのみにする</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="119"/>
<source>Switch to screen</source>
- <translation type="finished">画面に切り替え</translation>
+ <translation>モニターを切り替え</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="150"/>
<source>Switch in direction</source>
- <translation type="finished">切り替える方向</translation>
+ <translation>切り替える方向</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="174"/>
<source>left</source>
- <translation type="finished">左</translation>
+ <translation>左</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="179"/>
<source>right</source>
- <translation type="finished">右</translation>
+ <translation>右</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="184"/>
<source>up</source>
- <translation type="finished">上</translation>
+ <translation>上</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="189"/>
<source>down</source>
- <translation type="finished">下</translation>
+ <translation>下</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="201"/>
<source>Lock cursor to screen</source>
- <translation type="finished">カーソルを画面に限定</translation>
+ <translation type="unfinished">カーソルを画面に限定</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="225"/>
<source>toggle</source>
- <translation type="finished">切り替え</translation>
+ <translation>切り替え</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="230"/>
<source>on</source>
- <translation type="finished">オン</translation>
+ <translation>オン</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="235"/>
<source>off</source>
- <translation type="finished">オフ</translation>
+ <translation>オフ</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="248"/>
<source>This action is performed when</source>
- <translation type="finished">この動作を実行する時: </translation>
+ <translation>このアクション実行のタイミング</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="254"/>
<source>the hotkey is pressed</source>
- <translation type="finished">ホットキーを押したとき</translation>
+ <translation>ホットキーを押したとき</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="264"/>
<source>the hotkey is released</source>
- <translation type="finished">ホットキーを離したとき</translation>
+ <translation>ホットキーを離したとき</translation>
</message>
</context>
<context>
@@ -147,7 +157,7 @@ Visit our website for help and info (symless.com).
<message>
<location filename="res/AddClientDialogBase.ui" line="20"/>
<source>Dialog</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">ダイアログ</translation>
</message>
<message>
<location filename="res/AddClientDialogBase.ui" line="35"/>
@@ -157,7 +167,7 @@ Visit our website for help and info (symless.com).
<message>
<location filename="res/AddClientDialogBase.ui" line="83"/>
<source>Ignore auto connect clients</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">クライアントの自動接続を無視</translation>
</message>
</context>
<context>
@@ -165,12 +175,30 @@ Visit our website for help and info (symless.com).
<message>
<location filename="res/HotkeyDialogBase.ui" line="14"/>
<source>Hotkey</source>
- <translation type="finished">ホットキー</translation>
+ <translation>ホットキー</translation>
</message>
<message>
<location filename="res/HotkeyDialogBase.ui" line="20"/>
<source>Enter the specification for the hotkey:</source>
- <translation type="finished">ホットキーの指定方法を入力してください:</translation>
+ <translation>ホットキーを入力してください:</translation>
+ </message>
+</context>
+<context>
+ <name>LogWindowBase</name>
+ <message>
+ <location filename="res/LogWindowBase.ui" line="26"/>
+ <source>Log - Barrier</source>
+ <translation>ログ - Barrier</translation>
+ </message>
+ <message>
+ <location filename="res/LogWindowBase.ui" line="71"/>
+ <source>&amp;Clear Log</source>
+ <translation>ログ消去(&amp;C)</translation>
+ </message>
+ <message>
+ <location filename="res/LogWindowBase.ui" line="78"/>
+ <source>&amp;Hide</source>
+ <translation>閉じる</translation>
</message>
</context>
<context>
@@ -178,189 +206,193 @@ Visit our website for help and info (symless.com).
<message>
<location filename="src/MainWindow.cpp" line="790"/>
<source>&amp;Start</source>
- <translation type="finished">開始</translation>
+ <translation type="unfinished">開始(&amp;S)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="237"/>
<source>&amp;File</source>
- <translation type="finished">ファイル</translation>
+ <translation type="unfinished">ファイル(&amp;F)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="238"/>
<source>&amp;Edit</source>
- <translation type="finished">編集</translation>
+ <translation type="unfinished">編集(&amp;E)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="239"/>
<source>&amp;Window</source>
- <translation type="finished">ウィンドウ</translation>
+ <translation type="unfinished">ウィンドウ(&amp;W)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="240"/>
<source>&amp;Help</source>
- <translation type="finished">ヘルプ</translation>
+ <translation type="unfinished">ヘルプ(&amp;H)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="364"/>
<source>&lt;p&gt;Your version of Barrier is out of date. Version &lt;b&gt;%1&lt;/b&gt; is now available to &lt;a href=&quot;%2&quot;&gt;download&lt;/a&gt;.&lt;/p&gt;</source>
<oldsource>&lt;p&gt;Version %1 is now available, &lt;a href=&quot;%2&quot;&gt;visit website&lt;/a&gt;.&lt;/p&gt;</oldsource>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">&lt;p&gt;お使いの Barrier のバージョンが古くなっています。 新しいバージョン &lt;b&gt;%1&lt;/b&gt; が&lt;a href=&quot;%2&quot;&gt;ダウンロード&lt;/a&gt;できます。&lt;/p&gt;</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="577"/>
<source>Program can not be started</source>
- <translation type="finished">プログラムを開始できません</translation>
+ <translation>プログラムを開始できません</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="577"/>
<source>The executable&lt;br&gt;&lt;br&gt;%1&lt;br&gt;&lt;br&gt;could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program.</source>
- <translation type="finished">実行ファイル&lt;br&gt;&lt;br&gt;%1&lt;br&gt;&lt;br&gt;は存在しますが、開始できませんでした。このプログラムを動作させる十分な権限があるかどうか確認してください。</translation>
+ <translation>実行ファイル&lt;br&gt;&lt;br&gt;%1&lt;br&gt;&lt;br&gt;は存在しますが、開始できませんでした。このプログラムを動作させる十分な権限があるかどうか確認してください。</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="596"/>
<source>Barrier client not found</source>
- <translation type="finished">Barrierクライアントが見つかりません</translation>
+ <translation>Barrier のクライアントが見つかりません</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="597"/>
<source>The executable for the barrier client does not exist.</source>
- <translation type="finished">Barrierクライアントの実行ファイルが存在しません。</translation>
+ <translation>Barrier のクライアントの実行ファイルが存在しません。</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="625"/>
<source>Hostname is empty</source>
- <translation type="finished">ホスト名が入力されていません</translation>
+ <translation>ホスト名がありません</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="626"/>
<source>Please fill in a hostname for the barrier client to connect to.</source>
- <translation type="finished">Barrierクライアントで接続するホスト名を入力してください。</translation>
+ <translation>Barrier のクライアントが接続するホスト名を入力してください。</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="646"/>
<source>Cannot write configuration file</source>
- <translation type="finished">構成ファイルに書き込めません</translation>
+ <translation>構成ファイルに書き込めません</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="646"/>
<source>The temporary configuration file required to start barrier can not be written.</source>
- <translation type="finished">Barrierの開始に必要な一時的な構成ファイルを書き込めません。</translation>
+ <translation>Barrier の開始に必要な一時的な構成ファイルに書き込めません。</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="659"/>
<source>Configuration filename invalid</source>
- <translation type="finished">構成ファイル名が正しくありません。</translation>
+ <translation>構成ファイルのファイル名が正しくありません</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="660"/>
<source>You have not filled in a valid configuration file for the barrier server. Do you want to browse for the configuration file now?</source>
- <translation type="finished">Barrierサーバーの正しい構成ファイルを書き込んでいません。今、構成ファイルを閲覧しますか?</translation>
+ <translation>Barrier のサーバー用の正しい構成ファイルではありません。構成ファイルを開きますか?</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="688"/>
<source>Barrier server not found</source>
- <translation type="finished">Barrierサーバーが見つかりません</translation>
+ <translation>Barrier のサーバーが見つかりません</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="689"/>
<source>The executable for the barrier server does not exist.</source>
- <translation type="finished">Barrierサーバーの実行ファイルが存在しません。</translation>
+ <translation>Barrier のサーバーの実行ファイルが存在しません。</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="764"/>
<source>Barrier terminated with an error</source>
- <translation type="finished">Barrierはエラーで終了しました</translation>
+ <translation>Barrier はエラーで終了しました</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="764"/>
<source>Barrier terminated unexpectedly with an exit code of %1.&lt;br&gt;&lt;br&gt;Please see the log output for details.</source>
- <translation type="finished">Barrierは予期しない終了コード%1で終了しました。&lt;br&gt;&lt;br&gt;詳細はログの出力を参照してください。</translation>
+ <translation>Barrier は予期しない終了コード %1 で終了しました。&lt;br&gt;&lt;br&gt;詳細はログの出力を参照してください。</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="783"/>
<source>&amp;Stop</source>
- <translation type="finished">停止</translation>
+ <translation>停止(&amp;S)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="1038"/>
<source>Please add the server (%1) to the grid.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">グリッドにサーバー (%1) を追加してください。</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="1044"/>
<source>Please drag the new client screen (%1) to the desired position on the grid.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">グリッド上の希望する位置に新しいクライアントのモニタ (%1) をドラッグしてください。</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="1147"/>
<source>Failed to detect system architecture.</source>
- <translation type="unfinished"></translation>
+ <translation>システムアーキテクチャの検出に失敗しました。</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="1165"/>
<source>Cancel</source>
- <translation type="unfinished"></translation>
+ <translation>キャンセル</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="1189"/>
<source>Failed to download Bonjour installer to location: %1</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">Bonjour のインストーラーのダウンロードに失敗。場所: %1</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="1226"/>
<source>Do you want to enable auto config and install Bonjour?
This feature helps you establish the connection.</source>
- <translation type="unfinished"></translation>
+ <translation>自動構成を有効にし、Bonjour をインストールしますか?
+
+この機能は接続を確立するためのお手伝いをします。</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="1270"/>
<source>Auto config feature requires Bonjour.
Do you want to install Bonjour?</source>
- <translation type="unfinished"></translation>
+ <translation>自動構成の機能には Bonjour が必要です。
+
+Bonjour をインストールしますか?</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="815"/>
<source>Barrier is starting.</source>
- <translation type="finished">Barrierを開始中です。</translation>
+ <translation>Barrier を開始中です。</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="809"/>
<source>Barrier is running.</source>
- <translation type="finished">Barrierは動作中です。</translation>
+ <translation>Barrier は動作中です。</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="819"/>
<source>Barrier is not running.</source>
- <translation type="finished">Barrierは動作していません。</translation>
+ <translation>Barrier は動作していません。</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="870"/>
<source>Unknown</source>
- <translation type="finished">不明</translation>
+ <translation>不明</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="1146"/>
<location filename="src/MainWindow.cpp" line="1225"/>
<location filename="src/MainWindow.cpp" line="1269"/>
<source>Barrier</source>
- <translation type="finished">Barrier</translation>
+ <translation>Barrier</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="987"/>
<source>Browse for a barriers config file</source>
- <translation type="finished">Barrierの設定ファイルを参照</translation>
+ <translation type="unfinished">Barrier の構成ファイルを参照</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="408"/>
<source>Barrier is now connected, You can close the config window. Barrier will remain connected in the background.</source>
- <translation type="unfinished"></translation>
+ <translation>ただいま Barrier は接続されました。設定ウインドウを閉じることができます。それでもバックグラウンドで接続を維持します。</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="434"/>
<source>Security question</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">セキュリティの質問</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="435"/>
@@ -368,25 +400,31 @@ Do you want to install Bonjour?</source>
%1
-This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user).
+This is a server fingerprint. You should compare this fingerprint to the one on your server&apos;s screen. If the two don&apos;t match exactly, then it&apos;s probably not the server you&apos;re expecting (it could be a malicious user).
To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">このフィンガープリントを信頼しますか?
+
+%1
+
+これはサーバーのフィンガープリントです。 このフィンガープリントを、サーバー側のモニタに表示されているフィンガープリントとで確認してください。その2つが一致しない場合、接続したいサーバーではありません (悪意のあるサーバの可能性があります)。
+
+「はい」で、今後の接続でも、このフィンガープリントを自動的に信頼します。「いいえ」で、このフィンガープリントを拒否しサーバーから接続を切断します。</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="1000"/>
<source>Save configuration as...</source>
- <translation type="finished">設定に名前をつけて保存</translation>
+ <translation>構成設定に名前をつけて保存</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="1004"/>
<source>Save failed</source>
- <translation type="finished">保存できませんでした</translation>
+ <translation>保存できませんでした</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="1004"/>
<source>Could not save configuration to file.</source>
- <translation type="finished">設定をファイルに保存できませんでした</translation>
+ <translation>構成設定をファイルに保存できませんでした。</translation>
</message>
</context>
<context>
@@ -394,168 +432,193 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<message>
<location filename="res/MainWindowBase.ui" line="26"/>
<source>Barrier</source>
- <translation type="finished">Barrier</translation>
+ <translation>Barrier</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="90"/>
- <source>Ser&amp;ver (share this computer's mouse and keyboard):</source>
- <translation type="unfinished"></translation>
+ <source>Ser&amp;ver (share this computer&apos;s mouse and keyboard):</source>
+ <translation>サーバー (このコンピューターのキーボードとマウスを共有する)(&amp;V):</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="243"/>
<source>Screen name:</source>
- <translation type="finished">画面の名前:</translation>
+ <translation>モニター名:</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="257"/>
<source>&amp;Server IP:</source>
- <translation type="finished">サーバー IP:</translation>
+ <translation type="unfinished">サーバー IP (&amp;S):</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="380"/>
<location filename="res/MainWindowBase.ui" line="409"/>
<source>&amp;Start</source>
- <translation type="finished">開始</translation>
+ <translation>開始(&amp;S)</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="181"/>
<source>Use existing configuration:</source>
- <translation type="finished">既存の設定を使用</translation>
+ <translation>既存の構成設定を使用:</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="190"/>
<source>&amp;Configuration file:</source>
- <translation type="finished">設定ファイル:</translation>
+ <translation type="unfinished">構成ファイル:(&amp;C):</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="210"/>
<source>&amp;Browse...</source>
- <translation type="finished">参照</translation>
+ <translation>参照(&amp;B)...</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="147"/>
<source>Configure interactively:</source>
- <translation type="finished">インタラクティブモードで設定:</translation>
+ <translation>手動で構成を設定:</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="159"/>
<source>&amp;Configure Server...</source>
- <translation type="finished">サーバーを設定</translation>
+ <translation>サーバーの構成設定(&amp;S)...</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="350"/>
<source>Ready</source>
- <translation type="finished">準備完了</translation>
+ <translation>準備完了</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="296"/>
<source>Log</source>
- <translation type="finished">ログ</translation>
+ <translation>ログ</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="373"/>
<source>&amp;Reload</source>
- <translation type="finished">適用</translation>
+ <translation type="unfinished">適用(&amp;R)</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="107"/>
<source>IP addresses:</source>
- <translation type="finished">IPアドレス:</translation>
+ <translation>IPアドレス:</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="131"/>
<source>Fingerprint:</source>
- <translation type="unfinished"></translation>
+ <translation>フィンガープリント:</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="228"/>
- <source>&amp;Client (use another computer's mouse and keyboard):</source>
- <translation type="unfinished"></translation>
+ <source>&amp;Client (use another computer&apos;s mouse and keyboard):</source>
+ <translation>クライアント (ほかのコンピューターのマウスとキーボードを使う)(&amp;C):</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="270"/>
<source>Auto config</source>
- <translation type="unfinished"></translation>
+ <translation>自動構成</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="390"/>
<source>&amp;About Barrier...</source>
- <translation type="finished">Barrierについて...</translation>
+ <translation>Barrier について(&amp;A)...</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="398"/>
<source>&amp;Quit</source>
- <translation type="finished">終了</translation>
+ <translation>終了(&amp;Q)</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="401"/>
<source>Quit</source>
- <translation type="finished">終了</translation>
+ <translation>終了(&amp;Q)</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="412"/>
<source>Run</source>
- <translation type="finished">実行</translation>
+ <translation>開始(&amp;R)</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="423"/>
<source>S&amp;top</source>
- <translation type="finished">停止</translation>
+ <translation>停止(&amp;S)</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="426"/>
<source>Stop</source>
- <translation type="finished">停止</translation>
+ <translation>停止(&amp;S)</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="434"/>
<source>S&amp;how Status</source>
- <translation type="finished">状態を表示</translation>
+ <translation>状態を表示(&amp;S)</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="442"/>
<source>&amp;Hide</source>
- <translation type="finished">隠す</translation>
+ <translation>隠す(&amp;H)</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="445"/>
<source>Hide</source>
- <translation type="finished">隠す</translation>
+ <translation>隠す(&amp;H)</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="453"/>
<source>&amp;Show</source>
- <translation type="finished">表示する</translation>
+ <translation>表示(&amp;S)</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="456"/>
<source>Show</source>
- <translation type="finished">表示する</translation>
+ <translation>表示(&amp;S)</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="464"/>
<source>Save configuration &amp;as...</source>
- <translation type="finished">設定に名前をつけて保存</translation>
+ <translation>構成設定に名前をつけて保存</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="467"/>
<source>Save the interactively generated server configuration to a file.</source>
- <translation type="finished">インタラクティブモードで生成したサーバ設定をファイルに保存</translation>
+ <translation>手動で設定したサーバーの構成をファイルに保存する。</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="475"/>
<source>Settings</source>
- <translation type="finished">設定</translation>
+ <translation>設定</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="478"/>
<source>Edit settings</source>
- <translation type="finished">設定を編集</translation>
+ <translation>設定を編集</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="486"/>
<source>Run Wizard</source>
- <translation type="finished">ウィザードを実行する</translation>
+ <translation>ウィザードを実行</translation>
+ </message>
+ <message>
+ <location filename="res/MainWindowBase.ui" line="367"/>
+ <source>S&amp;ave configuration</source>
+ <translation>構成設定の保存(&amp;A)</translation>
+ </message>
+ <message>
+ <location filename="res/MainWindowBase.ui" line="380"/>
+ <source>Change &amp;Settings</source>
+ <translation>設定の変更(&amp;S)</translation>
+ </message>
+ <message>
+ <location filename="res/MainWindowBase.ui" line="391"/>
+ <source>Show &amp;Log</source>
+ <translation>ログを表示(&amp;L)</translation>
+ </message>
+ <message>
+ <location filename="res/MainWindowBase.ui" line="394"/>
+ <source>Show Log</source>
+ <translation>ログを表示(&amp;L)</translation>
+ </message>
+ <message>
+ <location filename="res/MainWindowBase.ui" line="132"/>
+ <source>SSL Fingerprint:</source>
+ <translation>SSLフィンガープリント:</translation>
</message>
</context>
<context>
@@ -563,7 +626,7 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<message>
<location filename="src/NewScreenWidget.cpp" line="32"/>
<source>Unnamed</source>
- <translation type="finished">名前なし</translation>
+ <translation>名前なし</translation>
</message>
</context>
<context>
@@ -571,28 +634,29 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<message>
<location filename="src/PluginManager.cpp" line="58"/>
<source>Failed to get plugin directory.</source>
- <translation type="unfinished"></translation>
+ <translation>プラグインのフォルダ取得に失敗しました。</translation>
</message>
<message>
<location filename="src/PluginManager.cpp" line="63"/>
<source>Failed to get profile directory.</source>
- <translation type="unfinished"></translation>
+ <translation>プロファイルのフォルダ取得に失敗しました。</translation>
</message>
<message>
<location filename="src/PluginManager.cpp" line="136"/>
- <source>Failed to download plugin '%1' to: %2
+ <source>Failed to download plugin &apos;%1&apos; to: %2
%3</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">プラグイン「%1」の %2 へのダウンロードに失敗
+%3</translation>
</message>
<message>
<location filename="src/PluginManager.cpp" line="167"/>
<source>Could not get Windows architecture type.</source>
- <translation type="unfinished"></translation>
+ <translation>Windows のアーキテクチャの種類を取得できません。</translation>
</message>
<message>
<location filename="src/PluginManager.cpp" line="191"/>
<source>Could not get Linux architecture type.</source>
- <translation type="unfinished"></translation>
+ <translation>Linux のアーキテクチャの種類を取得できません。</translation>
</message>
</context>
<context>
@@ -600,66 +664,66 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<message>
<location filename="res/PluginWizardPageBase.ui" line="14"/>
<source>Setup Barrier</source>
- <translation type="finished">Barrierのセットアップ</translation>
+ <translation>Barrier のセットアップ</translation>
</message>
<message>
<location filename="res/PluginWizardPageBase.ui" line="101"/>
<source>Please wait...</source>
- <translation type="unfinished"></translation>
+ <translation>お待ちください...</translation>
</message>
<message>
<location filename="src/PluginWizardPage.cpp" line="72"/>
<source>Error: %1</source>
- <translation type="unfinished"></translation>
+ <translation>エラー: %1</translation>
</message>
<message>
<location filename="src/PluginWizardPage.cpp" line="80"/>
<location filename="src/PluginWizardPage.cpp" line="201"/>
<source>Setup complete.</source>
- <translation type="unfinished"></translation>
+ <translation>セットアップは完了しました。</translation>
</message>
<message>
<location filename="src/PluginWizardPage.cpp" line="93"/>
- <source>Downloading '%1' plugin (%2/%3)...</source>
- <translation type="unfinished"></translation>
+ <source>Downloading &apos;%1&apos; plugin (%2/%3)...</source>
+ <translation>プラグイン「%1」をダウンロード中 (%2/%3)...</translation>
</message>
<message>
<location filename="src/PluginWizardPage.cpp" line="104"/>
<source>Plugins installed successfully.</source>
- <translation type="unfinished"></translation>
+ <translation>プラグインは正常にインストールされました。</translation>
</message>
<message>
<location filename="src/PluginWizardPage.cpp" line="120"/>
<source>Generating SSL certificate...</source>
- <translation type="unfinished"></translation>
+ <translation>SSL 証明書を生成中...</translation>
</message>
<message>
<location filename="src/PluginWizardPage.cpp" line="170"/>
<source>Downloading plugin: %1 (1/%2)</source>
- <translation type="unfinished"></translation>
+ <translation>プラグインをダウンロード中: %1 (1/%2)</translation>
</message>
<message>
<location filename="src/PluginWizardPage.cpp" line="239"/>
<source>Getting plugin list...</source>
- <translation type="unfinished"></translation>
+ <translation>プラグイン一覧を取得中...</translation>
</message>
</context>
<context>
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
- <translation type="finished">Barrierの構成(*.sgc);;すべてのファイル(*.*)</translation>
+ <source>Barrier Configurations (*.sgc)</source>
+ <translation>Barrier 構成設定 (*.sgc)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
- <translation type="finished">Barrierの構成(*.conf);;すべてのファイル(*.*)</translation>
+ <source>Barrier Configurations (*.conf)</source>
+ <translation>Barrier 構成設定 (*.conf)</translation>
</message>
<message>
<location filename="src/main.cpp" line="119"/>
<source>System tray is unavailable, quitting.</source>
- <translation type="finished">タスクトレイを利用できません。終了します。</translation>
+ <translation>システムトレイを利用できません。終了します。</translation>
</message>
</context>
<context>
@@ -667,22 +731,22 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<message>
<location filename="src/ScreenSettingsDialog.cpp" line="67"/>
<source>Screen name is empty</source>
- <translation type="finished">画面の名前が空です。</translation>
+ <translation>モニター名がありません</translation>
</message>
<message>
<location filename="src/ScreenSettingsDialog.cpp" line="68"/>
<source>The screen name cannot be empty. Please either fill in a name or cancel the dialog.</source>
- <translation type="finished">画面の名前を空にすることはできません。名前を入力するかダイアログをキャンセルしてください。</translation>
+ <translation>モニター名を空にはできません。名前を入力するか、ダイアログをキャンセルしてください。</translation>
</message>
<message>
<location filename="src/ScreenSettingsDialog.cpp" line="83"/>
<source>Screen name matches alias</source>
- <translation type="finished">画面の名前は別名と一致</translation>
+ <translation>モニター名は別名に一致</translation>
</message>
<message>
<location filename="src/ScreenSettingsDialog.cpp" line="84"/>
<source>The screen name cannot be the same as an alias. Please either remove the alias or change the screen name.</source>
- <translation type="finished">画面の名前を別名と同じにすることは出来ません。別名を削除するか画面の名前を変更してください。</translation>
+ <translation>モニター名を別名と同じにできません。別名を削除するか、モニター名を変更してください。</translation>
</message>
</context>
<context>
@@ -690,37 +754,37 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="14"/>
<source>Screen Settings</source>
- <translation type="finished">画面の設定</translation>
+ <translation>モニターの設定</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="22"/>
<source>Screen &amp;name:</source>
- <translation type="finished">画面の名前</translation>
+ <translation>モニター名(&amp;N):</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="42"/>
<source>A&amp;liases</source>
- <translation type="finished">別名</translation>
+ <translation>別名(&amp;A)</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="57"/>
<source>&amp;Add</source>
- <translation type="finished">追加</translation>
+ <translation>追加(&amp;A)</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="74"/>
<source>&amp;Remove</source>
- <translation type="finished">削除</translation>
+ <translation>除去(&amp;R)</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="97"/>
<source>&amp;Modifier keys</source>
- <translation type="finished">修飾キー</translation>
+ <translation>修飾キー(&amp;M)</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="106"/>
<source>&amp;Shift:</source>
- <translation type="finished">シフト</translation>
+ <translation>Shift(&amp;S):</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="117"/>
@@ -729,7 +793,7 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<location filename="res/ScreenSettingsDialogBase.ui" line="258"/>
<location filename="res/ScreenSettingsDialogBase.ui" line="305"/>
<source>Shift</source>
- <translation type="finished">シフト</translation>
+ <translation></translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="122"/>
@@ -738,7 +802,7 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<location filename="res/ScreenSettingsDialogBase.ui" line="263"/>
<location filename="res/ScreenSettingsDialogBase.ui" line="310"/>
<source>Ctrl</source>
- <translation type="finished">コントロール</translation>
+ <translation></translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="127"/>
@@ -747,7 +811,7 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<location filename="res/ScreenSettingsDialogBase.ui" line="268"/>
<location filename="res/ScreenSettingsDialogBase.ui" line="315"/>
<source>Alt</source>
- <translation type="finished">Alt</translation>
+ <translation></translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="132"/>
@@ -756,7 +820,7 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<location filename="res/ScreenSettingsDialogBase.ui" line="273"/>
<location filename="res/ScreenSettingsDialogBase.ui" line="320"/>
<source>Meta</source>
- <translation type="finished">メタ</translation>
+ <translation>メタ</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="137"/>
@@ -765,7 +829,7 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<location filename="res/ScreenSettingsDialogBase.ui" line="278"/>
<location filename="res/ScreenSettingsDialogBase.ui" line="325"/>
<source>Super</source>
- <translation type="finished">スーパー</translation>
+ <translation>スーパー</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="142"/>
@@ -774,82 +838,87 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<location filename="res/ScreenSettingsDialogBase.ui" line="283"/>
<location filename="res/ScreenSettingsDialogBase.ui" line="330"/>
<source>None</source>
- <translation type="finished">なし</translation>
+ <translation>なし</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="150"/>
<source>&amp;Ctrl:</source>
- <translation type="finished">&amp;undefinedCtrl:</translation>
+ <translation>Ctrl (&amp;C):</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="197"/>
<source>Al&amp;t:</source>
- <translation type="finished">&amp;undefinedl&amp;t:</translation>
+ <translation>Alt (&amp;T):</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="244"/>
<source>M&amp;eta:</source>
- <translation type="finished">&amp;undefined&amp;eta:</translation>
+ <translation>メタ (&amp;E):</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="291"/>
<source>S&amp;uper:</source>
- <translation type="finished">&amp;undefined&amp;uper:</translation>
+ <translation>スーパー (&amp;S):</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="358"/>
<source>&amp;Dead corners</source>
- <translation type="finished">無効とする角</translation>
+ <translation>無効とする隅(&amp;D)</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="367"/>
<source>Top-left</source>
- <translation type="finished">左上</translation>
+ <translation>左上</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="374"/>
<source>Top-right</source>
- <translation type="finished">右上</translation>
+ <translation>右上</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="381"/>
<source>Bottom-left</source>
- <translation type="finished">左下</translation>
+ <translation>左下</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="388"/>
<source>Bottom-right</source>
- <translation type="finished">右下</translation>
+ <translation>右下</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="397"/>
<source>Corner Si&amp;ze:</source>
- <translation type="finished">角の大きさ</translation>
+ <translation>隅の大きさ(&amp;Z):</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="428"/>
<source>&amp;Fixes</source>
- <translation type="finished">修正</translation>
+ <translation>修正(&amp;F)</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="437"/>
<source>Fix CAPS LOCK key</source>
- <translation type="finished">CAPSロックキーを固定</translation>
+ <translation>CAPS ロックキーを固定</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="444"/>
<source>Fix NUM LOCK key</source>
- <translation type="finished">NUMロックキーを固定</translation>
+ <translation>NUM ロックキーを固定</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="451"/>
<source>Fix SCROLL LOCK key</source>
- <translation type="finished">SCROLLロックキーを固定</translation>
+ <translation>SCROLL ロックキーを固定</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="458"/>
<source>Fix XTest for Xinerama</source>
- <translation type="finished">Xinerama向けにXTestを修正</translation>
+ <translation>Xinerama 向けに XTest を修正</translation>
+ </message>
+ <message>
+ <location filename="res/ScreenSettingsDialogBase.ui" line="468"/>
+ <source>Fix Preserve Focus</source>
+ <translation>フォーカスの維持を修正</translation>
</message>
</context>
<context>
@@ -857,7 +926,7 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<message>
<location filename="src/ScreenSetupModel.cpp" line="51"/>
<source>&lt;center&gt;Screen: &lt;b&gt;%1&lt;/b&gt;&lt;/center&gt;&lt;br&gt;Double click to edit settings&lt;br&gt;Drag screen to the trashcan to remove it</source>
- <translation type="finished">&lt;center&gt;画面: &lt;b&gt;%1&lt;/b&gt;&lt;/center&gt;&lt;br&gt;ダブルクリックで設定を編集&lt;br&gt;削除するときは画面をゴミ箱にドラッグします</translation>
+ <translation>&lt;center&gt;モニター: &lt;b&gt;%1&lt;/b&gt;&lt;/center&gt;&lt;br&gt;ダブルクリックで設定を編集&lt;br&gt;削除するときは画面をゴミ箱にドラッグします</translation>
</message>
</context>
<context>
@@ -865,7 +934,7 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<message>
<location filename="src/ServerConfigDialog.cpp" line="75"/>
<source>Configure server</source>
- <translation type="unfinished"></translation>
+ <translation>サーバーの構成設定</translation>
</message>
</context>
<context>
@@ -873,168 +942,178 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<message>
<location filename="res/ServerConfigDialogBase.ui" line="14"/>
<source>Server Configuration</source>
- <translation type="finished">サーバーの構成</translation>
+ <translation>サーバーの構成設定</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="24"/>
<source>Screens and links</source>
- <translation type="finished">画面とリンク</translation>
+ <translation>モニタの結びつき</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="35"/>
<source>Drag a screen from the grid to the trashcan to remove it.</source>
- <translation type="finished">削除する時はグリッド内の画面をゴミ箱にドラッグしてください。</translation>
+ <translation>削除するには、グリッド内のモニターをゴミ箱にドラッグしてください。</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="60"/>
<source>Configure the layout of your barrier server configuration.</source>
- <translation type="finished">サーバ構成の配置を設定する</translation>
+ <translation type="unfinished">Barrier のサーバー構成の配置を設定します。</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="73"/>
<source>Drag this button to the grid to add a new screen.</source>
- <translation type="finished">新規画面の追加はこのボタンをグリッド内にドラッグします。</translation>
+ <translation>新規モニターの追加するには、このボタンをグリッド内にドラッグします。</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="128"/>
<source>Drag new screens to the grid or move existing ones around.
Drag a screen to the trashcan to delete it.
Double click on a screen to edit its settings.</source>
- <translation type="finished">新規画面をグリッド内にドラッグするか既存画面を移動してください。
-画面をゴミ箱にドラッグすると削除します。
-設定を編集する場合は画面上でダブルクリックしてください。</translation>
+ <translation>新規モニターをグリッド内にドラッグするか、既存のモニターを移動してください。
+削除するには、モニターをゴミ箱にドラッグします。
+モニターの設定を編集するには、モニターをダブルクリックします。</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="157"/>
<source>Hotkeys</source>
- <translation type="finished">ホットキー</translation>
+ <translation>ホットキー</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="163"/>
<source>&amp;Hotkeys</source>
- <translation type="finished">ホットキー</translation>
+ <translation>ホットキー(&amp;H)</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="175"/>
<source>&amp;New</source>
- <translation type="finished">新規</translation>
+ <translation>新規(&amp;N)</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="185"/>
<source>&amp;Edit</source>
- <translation type="finished">編集</translation>
+ <translation>編集(&amp;E)</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="195"/>
<source>&amp;Remove</source>
- <translation type="finished">削除</translation>
+ <translation>除去(&amp;R)</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="218"/>
<source>A&amp;ctions</source>
- <translation type="finished">アクション</translation>
+ <translation>アクション(&amp;A)</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="230"/>
<source>Ne&amp;w</source>
- <translation type="finished">新規</translation>
+ <translation>新規(&amp;W)</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="240"/>
<source>E&amp;dit</source>
- <translation type="finished">編集</translation>
+ <translation>編集(&amp;D)</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="250"/>
<source>Re&amp;move</source>
- <translation type="finished">削除</translation>
+ <translation>除去(&amp;M)</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="274"/>
<source>Advanced server settings</source>
- <translation type="finished">サーバーの詳細な設定</translation>
+ <translation>サーバーの詳細設定</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="280"/>
<source>&amp;Switch</source>
- <translation type="finished">切り替え</translation>
+ <translation>切り替え(&amp;S)</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="291"/>
<source>Switch &amp;after waiting</source>
- <translation type="finished">次の時間の後切り替え</translation>
+ <translation>次の時間の後切り替え(&amp;A)</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="330"/>
<location filename="res/ServerConfigDialogBase.ui" line="383"/>
<location filename="res/ServerConfigDialogBase.ui" line="458"/>
<source>ms</source>
- <translation type="finished">ミリ秒</translation>
+ <translation>ミリ秒</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="344"/>
<source>Switch on double &amp;tap within</source>
- <translation type="finished">次の時間内のダブルタップで切り替え</translation>
+ <translation>次の時間内のダブルタップで切り替え(&amp;T)</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="408"/>
<source>&amp;Options</source>
- <translation type="finished">オプション</translation>
+ <translation>オプション(&amp;O)</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="419"/>
<source>&amp;Check clients every</source>
- <translation type="finished">クライアント確認頻度</translation>
+ <translation>クライアント確認頻度(&amp;C)</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="470"/>
<source>Use &amp;relative mouse moves</source>
- <translation type="finished">マウスの相対的な動きを使用</translation>
+ <translation>相対的なマウスの移動を使用(&amp;R)</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="480"/>
<source>S&amp;ynchronize screen savers</source>
- <translation type="finished">スクリーンセーバーの同期</translation>
+ <translation>スクリーンセーバーの同期(&amp;Y)</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="490"/>
- <source>Don't take &amp;foreground window on Windows servers</source>
- <translation type="finished">Windowsサーバでウィンドウを前面に表示しない</translation>
+ <source>Don&apos;t take &amp;foreground window on Windows servers</source>
+ <translation>Windows サーバ上ではウィンドウを前面に表示しない(&amp;F)</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="510"/>
<source>Ignore auto config clients</source>
- <translation type="unfinished"></translation>
+ <translation>自動構成のクライアントを無視</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="520"/>
<source>&amp;Dead corners</source>
- <translation type="finished">無効とする角</translation>
+ <translation>無効とする隅(&amp;D)</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="529"/>
<source>To&amp;p-left</source>
- <translation type="finished">左上</translation>
+ <translation>左上(&amp;P)</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="536"/>
<source>Top-rig&amp;ht</source>
- <translation type="finished">右上</translation>
+ <translation>右上(&amp;H)</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="543"/>
<source>&amp;Bottom-left</source>
- <translation type="finished">左下</translation>
+ <translation>左下(&amp;B)</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="550"/>
<source>Bottom-ri&amp;ght</source>
- <translation type="finished">右下</translation>
+ <translation>右下(&amp;G)</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="572"/>
<source>Cor&amp;ner Size:</source>
- <translation type="finished">隅の大きさ:</translation>
+ <translation>隅の大きさ(&amp;N):</translation>
+ </message>
+ <message>
+ <location filename="res/ServerConfigDialogBase.ui" line="510"/>
+ <source>Enable drag and drop file transfers</source>
+ <translation>ドラッグアンドドロップでファイル転送する</translation>
+ </message>
+ <message>
+ <location filename="res/ServerConfigDialogBase.ui" line="524"/>
+ <source>Enable clipboard sharing</source>
+ <translation>クリップボードを共有</translation>
</message>
</context>
<context>
@@ -1042,20 +1121,20 @@ Double click on a screen to edit its settings.</source>
<message>
<location filename="src/SettingsDialog.cpp" line="131"/>
<source>Save log file to...</source>
- <translation type="finished">ログファイルの保存先</translation>
+ <translation>ログファイルの保存先</translation>
</message>
<message>
<location filename="src/SettingsDialog.cpp" line="151"/>
<source>Elevate Barrier</source>
- <translation type="finished">Barrierの権限昇格</translation>
+ <translation>Barrier の権限昇格</translation>
</message>
<message>
<location filename="src/SettingsDialog.cpp" line="152"/>
<source>Are you sure you want to elevate Barrier?
This allows Barrier to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Barrier only if you really need to.</source>
- <translation type="finished">本当に Barrier を昇格させてよろしいですか?
-これにより昇格されたプロセスや UAC dialog と、Barrier とが互いに作用しあうことができるようになる反面、昇格されていないプロセスとの間で問題を生じることもあり得ます。確かに必要であると判断できる場合にのみ Barrier の昇格を行ってください。</translation>
+ <translation type="unfinished">Barrier を昇格させてもよろしいですか?
+この許可により Barrier は権限を持つプロセスや UAC ダイアログやりとりできます。一方で、昇格されていないプロセスとのやり取りに問題が起こることもあります。確かに必要である場合にのみ Barrier を昇格させてください。</translation>
</message>
</context>
<context>
@@ -1063,107 +1142,162 @@ This allows Barrier to interact with elevated processes and the UAC dialog, but
<message>
<location filename="res/SettingsDialogBase.ui" line="14"/>
<source>Settings</source>
- <translation type="finished">設定</translation>
+ <translation>設定</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="32"/>
<source>Sc&amp;reen name:</source>
- <translation type="finished">スクリーン名:</translation>
+ <translation>モニター名(&amp;R):</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="49"/>
<source>P&amp;ort:</source>
- <translation type="finished">ポート:</translation>
+ <translation>ポート(&amp;O):</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="78"/>
<source>&amp;Interface:</source>
- <translation type="finished">インターフェース:</translation>
+ <translation>インターフェース(&amp;I):</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="120"/>
<source>Elevate mode</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">特権の状態</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="127"/>
<source>&amp;Hide on startup</source>
- <translation type="unfinished"></translation>
+ <translation>起動時に隠す(&amp;H)</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="146"/>
<source>&amp;Network Security</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">ネットワークのセキュリティ(&amp;N)</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="155"/>
<source>Use &amp;SSL encryption (unique certificate)</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">SSL 暗号化を使用 (固有の証明書)(&amp;S)</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="184"/>
<source>Logging</source>
- <translation type="finished">ログ</translation>
+ <translation>ログ記録</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="202"/>
<source>&amp;Logging level:</source>
- <translation type="finished">ログレベル:</translation>
+ <translation type="unfinished">ログ対象(&amp;L):</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="251"/>
<source>Log to file:</source>
- <translation type="finished">ログ記録先ファイル:</translation>
+ <translation>ログ記録ファイル:</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="268"/>
<source>Browse...</source>
- <translation type="finished">参照...</translation>
+ <translation>参照...</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="213"/>
<source>Error</source>
- <translation type="finished">エラー</translation>
+ <translation>エラー</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="107"/>
<source>&amp;Language:</source>
- <translation type="finished">言語</translation>
+ <translation>言語(&amp;L):</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="20"/>
<source>&amp;Miscellaneous</source>
- <translation type="finished">その他</translation>
+ <translation>その他(&amp;M)</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="218"/>
<source>Warning</source>
- <translation type="finished">警告</translation>
+ <translation>警告</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="223"/>
<source>Note</source>
- <translation type="finished">通知</translation>
+ <translation type="unfinished">通知</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="228"/>
<source>Info</source>
- <translation type="finished">情報</translation>
+ <translation>情報</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="233"/>
<source>Debug</source>
- <translation type="finished">デバッグ情報</translation>
+ <translation>デバッグ情報</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="238"/>
<source>Debug1</source>
- <translation type="finished">デバッグ情報1</translation>
+ <translation>デバッグ情報1</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="243"/>
<source>Debug2</source>
- <translation type="finished">デバッグ情報2</translation>
+ <translation>デバッグ情報2</translation>
+ </message>
+ <message>
+ <location filename="res/SettingsDialogBase.ui" line="29"/>
+ <source>General</source>
+ <translation>一般</translation>
+ </message>
+ <message>
+ <location filename="res/SettingsDialogBase.ui" line="86"/>
+ <source>Elevate</source>
+ <translation>権限昇格</translation>
+ </message>
+ <message>
+ <location filename="res/SettingsDialogBase.ui" line="93"/>
+ <source>Specify when the Barrier service should run at an elevated privilege level</source>
+ <translation>Barrier のサービスを昇格した権限で実行するタイミングの指定</translation>
+ </message>
+ <message>
+ <location filename="res/SettingsDialogBase.ui" line="100"/>
+ <source>As Needed</source>
+ <translation>必要に応じて</translation>
+ </message>
+ <message>
+ <location filename="res/SettingsDialogBase.ui" line="105"/>
+ <source>Always</source>
+ <translation>常に</translation>
+ </message>
+ <message>
+ <location filename="res/SettingsDialogBase.ui" line="110"/>
+ <source>Never</source>
+ <translation>なし</translation>
+ </message>
+ <message>
+ <location filename="res/SettingsDialogBase.ui" line="118"/>
+ <source>Minimize to System &amp;Tray</source>
+ <translation>システムトレイに最小化(&amp;T)</translation>
+ </message>
+ <message>
+ <location filename="res/SettingsDialogBase.ui" line="135"/>
+ <source>Networking</source>
+ <translation>ネットワーク</translation>
+ </message>
+ <message>
+ <location filename="res/SettingsDialogBase.ui" line="170"/>
+ <source>&amp;Address:</source>
+ <translation>アドレス(&amp;A):</translation>
+ </message>
+ <message>
+ <location filename="res/SettingsDialogBase.ui" line="187"/>
+ <source>Enable &amp;SSL</source>
+ <translation>SSLを使用(&amp;S)</translation>
+ </message>
+ <message>
+ <location filename="res/SettingsDialogBase.ui" line="132"/>
+ <source>Start &amp;Barrier on startup</source>
+ <translation type="unfinished">起動時に Barrier を開始する (&amp;B)</translation>
</message>
</context>
<context>
@@ -1171,17 +1305,17 @@ This allows Barrier to interact with elevated processes and the UAC dialog, but
<message>
<location filename="src/SetupWizard.cpp" line="72"/>
<source>Setup Barrier</source>
- <translation type="finished">Barrierのセットアップ</translation>
+ <translation>Barrier のセットアップ</translation>
</message>
<message>
<location filename="src/SetupWizard.cpp" line="113"/>
<source>Please select an option.</source>
- <translation type="finished">オプションを選択してください。</translation>
+ <translation>オプションを選択してください。</translation>
</message>
<message>
<location filename="src/SetupWizard.cpp" line="80"/>
<source>Please enter your email address and password.</source>
- <translation type="finished">メールアドレスとパスワードを入力してください。</translation>
+ <translation>メールアドレスとパスワードを入力してください。</translation>
</message>
</context>
<context>
@@ -1189,85 +1323,93 @@ This allows Barrier to interact with elevated processes and the UAC dialog, but
<message>
<location filename="res/SetupWizardBase.ui" line="26"/>
<source>Setup Barrier</source>
- <translation type="finished">Barrierのセットアップ</translation>
+ <translation>Barrier のセットアップ</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="30"/>
<source>Welcome</source>
- <translation type="finished">ようこそ</translation>
+ <translation>ようこそ</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="39"/>
<source>Thanks for installing Barrier!</source>
- <translation type="finished">Barrierをインストールしていただき、ありがとうございます!</translation>
+ <translation>Barrier をインストールしていただき、ありがとうございます!</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="114"/>
- <source>Barrier lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Barrier is cross-platform (works on Windows, Mac OS X and Linux).</source>
- <translation type="finished">Barrierは複数のコンピュータ間のマウスとキーボードを簡単に共有することができるフリーのオープンソースソフトウェアです。あるコンピュータの画面の端にマウスを移動すると別のコンピュータの画面に移ります。クリップボードを共有することもできます。必要なのは ネットワーク接続だけです。 BarrierはクロスプラットフォームでWindows, Mac OS X, Linux上で動作します。</translation>
+ <source>Barrier lets you easily share your mouse and keyboard between multiple computers on your desk, and it&apos;s Free and Open Source. Just move your mouse off the edge of one computer&apos;s screen on to another. You can even share all of your clipboards. All you need is a network connection. Barrier is cross-platform (works on Windows, Mac OS X and Linux).</source>
+ <translation>Barrier によって、複数のデスクトップパソコン間でマウスとキーボードを簡単に共有することができます。そしてこれは無料でオープンソースのソフトウェアです。あるコンピュータの画面の端にマウスを移動するだけで、別のコンピュータの画面に移ることができます。クリップボードを共有することもできます。必要なのはネットワーク接続だけです。 Barrier はクロスプラットフォームで Windows, Mac OS X, Linux で動作します。</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="125"/>
<source>Activate</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">アクティベート</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="131"/>
<source>&amp;Activate now...</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">今すぐアクティベート(&amp;A)...</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="152"/>
<source>Email:</source>
- <translation type="unfinished"></translation>
+ <translation>電子メール:</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="178"/>
<source>Password:</source>
- <translation type="unfinished"></translation>
+ <translation>パスワード:</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="204"/>
<source>&lt;a href=&quot;https://symless.com/account/reset/&quot;&gt;Forgot password&lt;/a&gt;</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">&lt;a href=&quot;https://symless.com/account/reset/&quot;&gt;パスワードを忘れた場合&lt;/a&gt;</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="232"/>
<source>&amp;Skip activation</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">アクティベートを省略(&amp;S)</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="277"/>
- <source>&amp;Server (share this computer's mouse and keyboard)</source>
- <translation type="unfinished"></translation>
+ <source>&amp;Server (share this computer&apos;s mouse and keyboard)</source>
+ <translation>サーバー (このコンピューターのキーボードとマウスを共有する)(&amp;V)</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="290"/>
<source>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
-&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
- <translation type="unfinished"></translation>
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer&apos;s screen. There can only be one server in your setup.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;使いたいマウスとキーボードがこのパソコンに接続されている場合、こちらを選択することで、別のパソコンのモニタへとマウスを移動することができます。サーバーは1つしか設置できません。&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="326"/>
- <source>&amp;Client (use another computer's mouse and keyboard)</source>
- <translation type="unfinished"></translation>
+ <source>&amp;Client (use another computer&apos;s mouse and keyboard)</source>
+ <translation>クライアント (ほかのコンピューターのマウスとキーボードを使う)(&amp;C)</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="339"/>
<source>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
-&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
- <translation type="unfinished"></translation>
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;You have already set up a server. This computer will be controlled using the server&apos;s mouse and keyboard. There can be many clients in your setup.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;既にサーバーを設置してある場合、このパソコンをサーバーに接続されたマウスとキーボードで制御できます。複数の数のクライアントを配置できます。&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="262"/>
<source>Server or Client?</source>
- <translation type="finished">サーバーまたはクライアント</translation>
+ <translation>サーバーにしますか?またはクライアントですか?</translation>
</message>
</context>
<context>
@@ -1275,22 +1417,22 @@ p, li { white-space: pre-wrap; }
<message>
<location filename="src/SslCertificate.cpp" line="42"/>
<source>Failed to get profile directory.</source>
- <translation type="unfinished"></translation>
+ <translation>プロファイルのフォルダ取得に失敗しました。</translation>
</message>
<message>
<location filename="src/SslCertificate.cpp" line="141"/>
<source>SSL certificate generated.</source>
- <translation type="unfinished"></translation>
+ <translation>SSL 証明書を生成しました。</translation>
</message>
<message>
<location filename="src/SslCertificate.cpp" line="170"/>
<source>SSL fingerprint generated.</source>
- <translation type="unfinished"></translation>
+ <translation>SSL フィンガープリントを生成しました。</translation>
</message>
<message>
<location filename="src/SslCertificate.cpp" line="173"/>
<source>Failed to find SSL fingerprint.</source>
- <translation type="unfinished"></translation>
+ <translation>SSL フィンガープリントが見つかりませんでした。</translation>
</message>
</context>
<context>
@@ -1298,7 +1440,7 @@ p, li { white-space: pre-wrap; }
<message>
<location filename="src/VersionChecker.cpp" line="102"/>
<source>Unknown</source>
- <translation type="finished">不明</translation>
+ <translation>不明</translation>
</message>
</context>
<context>
@@ -1308,19 +1450,21 @@ p, li { white-space: pre-wrap; }
<source>An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details.
%1</source>
- <translation type="unfinished"></translation>
+ <translation>サインイン時にエラーが発生しました。ヘルプデスクにお問い合わせの上、以下の詳細を報告してください。
+
+%1</translation>
</message>
<message>
<location filename="src/WebClient.cpp" line="65"/>
<source>Login failed, invalid email or password.</source>
- <translation type="finished">ログインは失敗しました。メールアドレスまたはパスワードが無効です。</translation>
+ <translation>ログインに失敗しました。メールアドレスまたはパスワードが無効です。</translation>
</message>
<message>
<location filename="src/WebClient.cpp" line="78"/>
<source>Login failed, an error occurred.
%1</source>
- <translation type="finished">エラーが発生し、ログインが失敗しました。
+ <translation>エラーが発生し、ログインに失敗しました。
%1</translation>
</message>
<message>
@@ -1330,8 +1474,8 @@ p, li { white-space: pre-wrap; }
Server response:
%1</source>
- <translation type="finished">エラーが発生し、ログインが失敗しました。
-サーバの応答:
+ <translation>エラーが発生し、ログインに失敗しました。
+サーバの応答:
%1</translation>
</message>
<message>
@@ -1339,19 +1483,23 @@ Server response:
<source>An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details.
%1</source>
- <translation type="unfinished"></translation>
+ <translation>プラグイン一覧の要求時にエラーが発生しました。ヘルプデスクにお問い合わせの上、以下の詳細を報告してください。
+
+%1</translation>
</message>
<message>
<location filename="src/WebClient.cpp" line="120"/>
<source>Get plugin list failed, invalid user email or password.</source>
- <translation type="unfinished"></translation>
+ <translation>プラグイン一覧の取得に失敗しました。メールアドレスまたはパスワードが無効です。</translation>
</message>
<message>
<location filename="src/WebClient.cpp" line="131"/>
<source>Get plugin list failed, an error occurred.
%1</source>
- <translation type="unfinished"></translation>
+ <translation>エラーが発生し、プラグイン一覧の取得に失敗しました。
+
+%1</translation>
</message>
<message>
<location filename="src/WebClient.cpp" line="137"/>
@@ -1360,7 +1508,11 @@ Server response:
Server response:
%1</source>
- <translation type="unfinished"></translation>
+ <translation>エラーが発生し、プラグイン一覧の取得に失敗しました。
+
+サーバの応答:
+
+%1</translation>
</message>
</context>
<context>
@@ -1368,44 +1520,44 @@ Server response:
<message>
<location filename="src/ZeroconfService.cpp" line="82"/>
<source>zeroconf server detected: %1</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">ゼロ構成のサーバーを検出: %1</translation>
</message>
<message>
<location filename="src/ZeroconfService.cpp" line="91"/>
<source>zeroconf client detected: %1</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">ゼロ構成のクライアントを検出: %1</translation>
</message>
<message>
<location filename="src/ZeroconfService.cpp" line="99"/>
<location filename="src/ZeroconfService.cpp" line="130"/>
<source>Zero configuration service</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">ゼロ構成のサービス</translation>
</message>
<message>
<location filename="src/ZeroconfService.cpp" line="100"/>
<source>Error code: %1.</source>
- <translation type="unfinished"></translation>
+ <translation>エラーコード: %1</translation>
</message>
<message>
<location filename="src/ZeroconfService.cpp" line="131"/>
<source>Unable to start the zeroconf: %1.</source>
- <translation type="unfinished"></translation>
+ <translation>ゼロ構成は開始できません: %1</translation>
</message>
<message>
<location filename="src/ZeroconfService.cpp" line="140"/>
<source>Barrier</source>
- <translation type="finished">Barrier</translation>
+ <translation>Barrier</translation>
</message>
<message>
<location filename="src/ZeroconfService.cpp" line="141"/>
<source>Failed to get local IP address. Please manually type in server address on your clients</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">ローカル IP アドレスの取得に失敗しました。クライアント上でサーバーのアドレスを手動で入力してください</translation>
</message>
<message>
<location filename="src/ZeroconfService.cpp" line="147"/>
<location filename="src/ZeroconfService.cpp" line="154"/>
<source>%1</source>
- <translation type="unfinished"></translation>
+ <translation></translation>
</message>
</context>
-</TS> \ No newline at end of file
+</TS>
diff --git a/src/gui/res/lang/gui_ko.qm b/src/gui/res/lang/gui_ko.qm
index 06612cb..54b9461 100644
--- a/src/gui/res/lang/gui_ko.qm
+++ b/src/gui/res/lang/gui_ko.qm
Binary files differ
diff --git a/src/gui/res/lang/gui_ko.ts b/src/gui/res/lang/gui_ko.ts
index 8c477fc..46f7223 100644
--- a/src/gui/res/lang/gui_ko.ts
+++ b/src/gui/res/lang/gui_ko.ts
@@ -204,7 +204,7 @@ Visit our website for help and info (symless.com).
<location filename="src/MainWindow.cpp" line="364"/>
<source>&lt;p&gt;Your version of Barrier is out of date. Version &lt;b&gt;%1&lt;/b&gt; is now available to &lt;a href=&quot;%2&quot;&gt;download&lt;/a&gt;.&lt;/p&gt;</source>
<oldsource>&lt;p&gt;Version %1 is now available, &lt;a href=&quot;%2&quot;&gt;visit website&lt;/a&gt;.&lt;/p&gt;</oldsource>
- <translation type="finished">&lt;p&gt;사용 중인 시너지는 최신 버전이 아닙니다. 새 버전(&lt;b&gt;%1&lt;/b&gt;)을 &lt;a href=&quot;%2&quot;&gt;다운로드&lt;/a&gt; 받을 수 있습니다.&lt;/p&gt;</translation>
+ <translation type="finished">&lt;p&gt;사용 중인 배리어는 최신 버전이 아닙니다. 새 버전(&lt;b&gt;%1&lt;/b&gt;)을 &lt;a href=&quot;%2&quot;&gt;다운로드&lt;/a&gt; 받을 수 있습니다.&lt;/p&gt;</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="577"/>
@@ -600,7 +600,7 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<message>
<location filename="res/PluginWizardPageBase.ui" line="14"/>
<source>Setup Barrier</source>
- <translation type="finished">시너지 설정</translation>
+ <translation type="finished">배리어 설정</translation>
</message>
<message>
<location filename="res/PluginWizardPageBase.ui" line="101"/>
@@ -648,13 +648,18 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
- <translation type="finished">Barrier 설정파일 (*.sgc);;모든 파일 (*.*)</translation>
+ <source>All files (*.*)</source>
+ <translation type="finished">모든 파일 (*.*)</translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
+ <translation type="finished">Barrier 설정파일 (*.sgc)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
- <translation type="finished">Barrier 설정파일 (*.conf);;모든 파일 (*.*)</translation>
+ <source>Barrier Configurations (*.conf)</source>
+ <translation type="finished">Barrier 설정파일 (*.conf)</translation>
</message>
<message>
<location filename="src/main.cpp" line="119"/>
@@ -1171,7 +1176,7 @@ This allows Barrier to interact with elevated processes and the UAC dialog, but
<message>
<location filename="src/SetupWizard.cpp" line="72"/>
<source>Setup Barrier</source>
- <translation type="finished">시너지 설정</translation>
+ <translation type="finished">배리어 설정</translation>
</message>
<message>
<location filename="src/SetupWizard.cpp" line="113"/>
@@ -1189,7 +1194,7 @@ This allows Barrier to interact with elevated processes and the UAC dialog, but
<message>
<location filename="res/SetupWizardBase.ui" line="26"/>
<source>Setup Barrier</source>
- <translation type="finished">시너지 설정</translation>
+ <translation type="finished">배리어 설정</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="30"/>
@@ -1199,7 +1204,7 @@ This allows Barrier to interact with elevated processes and the UAC dialog, but
<message>
<location filename="res/SetupWizardBase.ui" line="39"/>
<source>Thanks for installing Barrier!</source>
- <translation type="finished">시너지를 설치하여 주셔서 감사합니다.</translation>
+ <translation type="finished">배리어를 설치하여 주셔서 감사합니다.</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="114"/>
diff --git a/src/gui/res/lang/gui_lt.ts b/src/gui/res/lang/gui_lt.ts
index 66976b1..58e9101 100644
--- a/src/gui/res/lang/gui_lt.ts
+++ b/src/gui/res/lang/gui_lt.ts
@@ -648,12 +648,17 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
+ <source>All files (*.*)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
+ <source>Barrier Configurations (*.conf)</source>
<translation type="unfinished"></translation>
</message>
<message>
diff --git a/src/gui/res/lang/gui_lv.ts b/src/gui/res/lang/gui_lv.ts
index 27b74f0..4618c05 100644
--- a/src/gui/res/lang/gui_lv.ts
+++ b/src/gui/res/lang/gui_lv.ts
@@ -648,12 +648,17 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
+ <source>All files (*.*)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
+ <source>Barrier Configurations (*.conf)</source>
<translation type="unfinished"></translation>
</message>
<message>
diff --git a/src/gui/res/lang/gui_mr.ts b/src/gui/res/lang/gui_mr.ts
index b91bd19..a646004 100644
--- a/src/gui/res/lang/gui_mr.ts
+++ b/src/gui/res/lang/gui_mr.ts
@@ -648,12 +648,17 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
+ <source>All files (*.*)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
+ <source>Barrier Configurations (*.conf)</source>
<translation type="unfinished"></translation>
</message>
<message>
diff --git a/src/gui/res/lang/gui_nl-NL.qm b/src/gui/res/lang/gui_nl-NL.qm
index 102cec8..ac9a67c 100644
--- a/src/gui/res/lang/gui_nl-NL.qm
+++ b/src/gui/res/lang/gui_nl-NL.qm
Binary files differ
diff --git a/src/gui/res/lang/gui_nl-NL.ts b/src/gui/res/lang/gui_nl-NL.ts
index 5c5b490..4ea0ee8 100644
--- a/src/gui/res/lang/gui_nl-NL.ts
+++ b/src/gui/res/lang/gui_nl-NL.ts
@@ -648,13 +648,18 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
- <translation type="finished">Barrier Configuratie (*.sgc);;Alle bestanden (*.*)</translation>
+ <source>All files (*.*)</source>
+ <translation type="finished">Alle bestanden (*.*)</translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
+ <translation type="finished">Barrier Configuratie (*.sgc)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
- <translation type="finished">Barrier configuratie (*.conf);;Alle bestanden (*.*)</translation>
+ <source>Barrier Configurations (*.conf)</source>
+ <translation type="finished">Barrier configuratie (*.conf)</translation>
</message>
<message>
<location filename="src/main.cpp" line="119"/>
@@ -1329,7 +1334,7 @@ p, li { white-space: pre-wrap; }
Server response:
%1</source>
- <translation type="finished">Inloggen mislukt, er is een fout opgetreden.
+ <translation type="finished">Inloggen mislukt, er is een fout opgetreden.
Foutmelding:
%1</translation>
</message>
diff --git a/src/gui/res/lang/gui_no.qm b/src/gui/res/lang/gui_no.qm
index 903ae48..c4d1d81 100644
--- a/src/gui/res/lang/gui_no.qm
+++ b/src/gui/res/lang/gui_no.qm
Binary files differ
diff --git a/src/gui/res/lang/gui_no.ts b/src/gui/res/lang/gui_no.ts
index d27a620..0ccd61e 100644
--- a/src/gui/res/lang/gui_no.ts
+++ b/src/gui/res/lang/gui_no.ts
@@ -648,13 +648,18 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
- <translation type="finished">Barrier-oppsett (*.sgc);;Alle filer (*.*)</translation>
+ <source>All files (*.*)</source>
+ <translation type="finished">Alle filer (*.*)</translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
+ <translation type="finished">Barrier-oppsett (*.sgc)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
- <translation type="finished">Barrier-oppsett (*.conf);;Alle filer (*.*)</translation>
+ <source>Barrier Configurations (*.conf)</source>
+ <translation type="finished">Barrier-oppsett (*.conf)</translation>
</message>
<message>
<location filename="src/main.cpp" line="119"/>
diff --git a/src/gui/res/lang/gui_pes-IR.ts b/src/gui/res/lang/gui_pes-IR.ts
index 31d7a67..3aaffed 100644
--- a/src/gui/res/lang/gui_pes-IR.ts
+++ b/src/gui/res/lang/gui_pes-IR.ts
@@ -648,12 +648,17 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
+ <source>All files (*.*)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
+ <source>Barrier Configurations (*.conf)</source>
<translation type="unfinished"></translation>
</message>
<message>
diff --git a/src/gui/res/lang/gui_pl-PL.qm b/src/gui/res/lang/gui_pl-PL.qm
index 83e7352..65a2116 100644
--- a/src/gui/res/lang/gui_pl-PL.qm
+++ b/src/gui/res/lang/gui_pl-PL.qm
Binary files differ
diff --git a/src/gui/res/lang/gui_pl-PL.ts b/src/gui/res/lang/gui_pl-PL.ts
index 6fb96a0..7262a2a 100644
--- a/src/gui/res/lang/gui_pl-PL.ts
+++ b/src/gui/res/lang/gui_pl-PL.ts
@@ -648,13 +648,18 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
- <translation type="finished">Konfiguracje Barrier (*.sgc);;Wszystkie pliki (*.*)</translation>
+ <source>All files (*.*)</source>
+ <translation type="finished">Wszystkie pliki (*.*)</translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
+ <translation type="finished">Konfiguracje Barrier (*.sgc)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
- <translation type="finished">Konfiguracje Barrier (*.conf);;Wszystkie pliki (*.*)</translation>
+ <source>Barrier Configurations (*.conf)</source>
+ <translation type="finished">Konfiguracje Barrier (*.conf)</translation>
</message>
<message>
<location filename="src/main.cpp" line="119"/>
@@ -1320,7 +1325,7 @@ p, li { white-space: pre-wrap; }
<source>Login failed, an error occurred.
%1</source>
- <translation type="finished">Logowanie nie powiodło się, wystąpił błąd.
+ <translation type="finished">Logowanie nie powiodło się, wystąpił błąd.
%1</translation>
</message>
<message>
@@ -1330,7 +1335,7 @@ p, li { white-space: pre-wrap; }
Server response:
%1</source>
- <translation type="finished">Logowanie nie powiodło się, wystąpił błąd.
+ <translation type="finished">Logowanie nie powiodło się, wystąpił błąd.
Odpowiedź serwera:
%1</translation>
</message>
diff --git a/src/gui/res/lang/gui_pt-BR.qm b/src/gui/res/lang/gui_pt-BR.qm
index 1deecfd..0825fcf 100644
--- a/src/gui/res/lang/gui_pt-BR.qm
+++ b/src/gui/res/lang/gui_pt-BR.qm
Binary files differ
diff --git a/src/gui/res/lang/gui_pt-BR.ts b/src/gui/res/lang/gui_pt-BR.ts
index 6245bca..6e85dd8 100644
--- a/src/gui/res/lang/gui_pt-BR.ts
+++ b/src/gui/res/lang/gui_pt-BR.ts
@@ -648,13 +648,18 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
- <translation type="finished">Configurações do Barrier (*.sgc);;Todos os arquivos (*.*)</translation>
+ <source>All files (*.*)</source>
+ <translation type="finished">Todos os arquivos (*.*)</translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
+ <translation type="finished">Configurações do Barrier (*.sgc)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
- <translation type="finished">Configurações do Barrier (*.conf);;Todos os arquivos (*.*)</translation>
+ <source>Barrier Configurations (*.conf)</source>
+ <translation type="finished">Configurações do Barrier (*.conf)</translation>
</message>
<message>
<location filename="src/main.cpp" line="119"/>
diff --git a/src/gui/res/lang/gui_pt-PT.qm b/src/gui/res/lang/gui_pt-PT.qm
index 987d8ab..e824cce 100644
--- a/src/gui/res/lang/gui_pt-PT.qm
+++ b/src/gui/res/lang/gui_pt-PT.qm
Binary files differ
diff --git a/src/gui/res/lang/gui_pt-PT.ts b/src/gui/res/lang/gui_pt-PT.ts
index 03fc40d..9ae8899 100644
--- a/src/gui/res/lang/gui_pt-PT.ts
+++ b/src/gui/res/lang/gui_pt-PT.ts
@@ -648,13 +648,18 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
- <translation type="finished">Configuração de barrier (*.sgc);;Todos os ficheiros (*.*)</translation>
+ <source>All files (*.*)</source>
+ <translation type="finished">Todos os ficheiros (*.*)</translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
+ <translation type="finished">Configuração de barrier (*.sgc)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
- <translation type="finished">Configuração de barrier (*.conf);;Todos os ficheiros (*.*)</translation>
+ <source>Barrier Configurations (*.conf)</source>
+ <translation type="finished">Configuração de barrier (*.conf))</translation>
</message>
<message>
<location filename="src/main.cpp" line="119"/>
diff --git a/src/gui/res/lang/gui_ro.qm b/src/gui/res/lang/gui_ro.qm
index 6d1fdd2..1a69dad 100644
--- a/src/gui/res/lang/gui_ro.qm
+++ b/src/gui/res/lang/gui_ro.qm
Binary files differ
diff --git a/src/gui/res/lang/gui_ro.ts b/src/gui/res/lang/gui_ro.ts
index f82d128..c3c9c43 100644
--- a/src/gui/res/lang/gui_ro.ts
+++ b/src/gui/res/lang/gui_ro.ts
@@ -648,13 +648,18 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
- <translation type="finished">Configurații Barrier (*.sgc);;Toate Fișierele (*.*)</translation>
+ <source>All files (*.*)</source>
+ <translation type="finished">Toate Fișierele (*.*)</translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
+ <translation type="finished">Configurații Barrier (*.sgc)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
- <translation type="finished">Configurații Barrier (*.conf);;Toate Fișierele (*.*)</translation>
+ <source>Barrier Configurations (*.conf)</source>
+ <translation type="finished">Configurații Barrier (*.conf)</translation>
</message>
<message>
<location filename="src/main.cpp" line="119"/>
diff --git a/src/gui/res/lang/gui_ru.qm b/src/gui/res/lang/gui_ru.qm
index 30ed0a7..ef3852c 100644
--- a/src/gui/res/lang/gui_ru.qm
+++ b/src/gui/res/lang/gui_ru.qm
Binary files differ
diff --git a/src/gui/res/lang/gui_ru.ts b/src/gui/res/lang/gui_ru.ts
index 411272f..f984240 100644
--- a/src/gui/res/lang/gui_ru.ts
+++ b/src/gui/res/lang/gui_ru.ts
@@ -648,13 +648,18 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
- <translation type="finished">Конфигурация Barrier (*.sgc);;Все файлы (*.*)</translation>
+ <source>All files (*.*)</source>
+ <translation type="finished">Все файлы (*.*)</translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
+ <translation type="finished">Конфигурация Barrier (*.sgc)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
- <translation type="finished">Конфигурация Barrier (*.conf);;Все файлы (*.*)</translation>
+ <source>Barrier Configurations (*.conf)</source>
+ <translation type="finished">Конфигурация Barrier (*.conf)</translation>
</message>
<message>
<location filename="src/main.cpp" line="119"/>
@@ -1320,7 +1325,7 @@ p, li { white-space: pre-wrap; }
<source>Login failed, an error occurred.
%1</source>
- <translation type="finished">Войти не удалось, произошла ошибка.
+ <translation type="finished">Войти не удалось, произошла ошибка.
%1</translation>
</message>
@@ -1331,7 +1336,7 @@ p, li { white-space: pre-wrap; }
Server response:
%1</source>
- <translation type="finished">Войти не удалось, произошла ошибка.
+ <translation type="finished">Войти не удалось, произошла ошибка.
Ответ сервера:
diff --git a/src/gui/res/lang/gui_si.ts b/src/gui/res/lang/gui_si.ts
index 33597e9..9abc5df 100644
--- a/src/gui/res/lang/gui_si.ts
+++ b/src/gui/res/lang/gui_si.ts
@@ -648,12 +648,17 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
+ <source>All files (*.*)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
+ <source>Barrier Configurations (*.conf)</source>
<translation type="unfinished"></translation>
</message>
<message>
diff --git a/src/gui/res/lang/gui_sk-SK.qm b/src/gui/res/lang/gui_sk-SK.qm
index acdf4f6..0e5efca 100644
--- a/src/gui/res/lang/gui_sk-SK.qm
+++ b/src/gui/res/lang/gui_sk-SK.qm
Binary files differ
diff --git a/src/gui/res/lang/gui_sk-SK.ts b/src/gui/res/lang/gui_sk-SK.ts
index 3e63795..0bbeacf 100644
--- a/src/gui/res/lang/gui_sk-SK.ts
+++ b/src/gui/res/lang/gui_sk-SK.ts
@@ -1,12 +1,14 @@
-<?xml version="1.0" encoding="utf-8"?><!DOCTYPE TS><TS language="sk-SK" sourcelanguage="en" version="2.0">
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="sk_SK" sourcelanguage="en">
<context>
<name>AboutDialogBase</name>
<message>
<location filename="res/AboutDialogBase.ui" line="38"/>
<source>About Barrier</source>
- <translation type="unfinished"></translation>
+ <translation>O Barrier</translation>
</message>
- <message utf8="true">
+ <message>
<location filename="res/AboutDialogBase.ui" line="53"/>
<source>&lt;p&gt;
Keyboard and mouse sharing application. Cross platform and open source.&lt;br /&gt;&lt;br /&gt;
@@ -26,22 +28,30 @@ Barrier is based on CosmoSynergy by Richard Lee and Adam Feder.&lt;br /&gt;
The Barrier GUI is based on QSynergy by Volker Lanz.&lt;br /&gt;&lt;br /&gt;
Visit our website for help and info (symless.com).
&lt;/p&gt;</oldsource>
- <translation type="unfinished"></translation>
+ <translation>&lt;p&gt;
+Aplikácia na zdieľanie klávesnice a myši. Podporuje viacero platforiem a má otvorený zdrojový kód.&lt;br /&gt;&lt;br /&gt;
+Autorské práva © 2012-2016 Symless Ltd.&lt;br /&gt;
+Autorské práva © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.&lt;br /&gt;&lt;br /&gt;
+Barrier je vydaný pod licenciou GNU General Public License (GPLv2).&lt;br /&gt;&lt;br /&gt;
+Základom pre Barrier je CosmoSynergy od Richarda Lee-a a Adama Federa.&lt;br /&gt;
+Barrier GUI je postavené na QSynergy od Volkera Lanza.&lt;br /&gt;&lt;br /&gt;
+Pre pomoc a ďalšie informácie navštívte našu webovú stránku (symless.com).
+&lt;/p&gt;</translation>
</message>
<message>
<location filename="res/AboutDialogBase.ui" line="140"/>
<source>Unknown</source>
- <translation type="unfinished"></translation>
+ <translation>Neznáma</translation>
</message>
<message>
<location filename="res/AboutDialogBase.ui" line="124"/>
<source>Version:</source>
- <translation type="unfinished"></translation>
+ <translation>Verzia:</translation>
</message>
<message>
<location filename="res/AboutDialogBase.ui" line="163"/>
<source>&amp;Ok</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Ok</translation>
</message>
</context>
<context>
@@ -49,97 +59,97 @@ Visit our website for help and info (symless.com).
<message>
<location filename="res/ActionDialogBase.ui" line="14"/>
<source>Configure Action</source>
- <translation type="unfinished"></translation>
+ <translation>Nastaviť akciu</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="20"/>
<source>Choose the action to perform</source>
- <translation type="unfinished"></translation>
+ <translation>Vyberte akciu, ktorá sa má vykonať</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="26"/>
<source>Press a hotkey</source>
- <translation type="unfinished"></translation>
+ <translation>Stlačte klávesovú skratku</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="36"/>
<source>Release a hotkey</source>
- <translation type="unfinished"></translation>
+ <translation>Uvoľnite klávesovú skratku</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="43"/>
<source>Press and release a hotkey</source>
- <translation type="unfinished"></translation>
+ <translation>Stlačte a uvoľnite klávesovú skratku</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="69"/>
<source>only on these screens</source>
- <translation type="unfinished"></translation>
+ <translation>iba na týchto obrazovkách</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="119"/>
<source>Switch to screen</source>
- <translation type="unfinished"></translation>
+ <translation>Prepnúť na obrazovku</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="150"/>
<source>Switch in direction</source>
- <translation type="unfinished"></translation>
+ <translation>Prepnúť v smere</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="174"/>
<source>left</source>
- <translation type="unfinished"></translation>
+ <translation>doľava</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="179"/>
<source>right</source>
- <translation type="unfinished"></translation>
+ <translation>doprava</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="184"/>
<source>up</source>
- <translation type="unfinished"></translation>
+ <translation>hore</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="189"/>
<source>down</source>
- <translation type="unfinished"></translation>
+ <translation>dole</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="201"/>
<source>Lock cursor to screen</source>
- <translation type="unfinished"></translation>
+ <translation>Zamknúť kurzor na obrazovke</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="225"/>
<source>toggle</source>
- <translation type="unfinished"></translation>
+ <translation>prepnúť</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="230"/>
<source>on</source>
- <translation type="unfinished"></translation>
+ <translation>zap</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="235"/>
<source>off</source>
- <translation type="unfinished"></translation>
+ <translation>vyp</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="248"/>
<source>This action is performed when</source>
- <translation type="unfinished"></translation>
+ <translation>Táto akcia sa vykoná pri</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="254"/>
<source>the hotkey is pressed</source>
- <translation type="unfinished"></translation>
+ <translation>stlačení klávesovej skratky</translation>
</message>
<message>
<location filename="res/ActionDialogBase.ui" line="264"/>
<source>the hotkey is released</source>
- <translation type="unfinished"></translation>
+ <translation>uvoľnení klávesovej skratky</translation>
</message>
</context>
<context>
@@ -147,17 +157,17 @@ Visit our website for help and info (symless.com).
<message>
<location filename="res/AddClientDialogBase.ui" line="20"/>
<source>Dialog</source>
- <translation type="unfinished"></translation>
+ <translation>Dialógové okno</translation>
</message>
<message>
<location filename="res/AddClientDialogBase.ui" line="35"/>
<source>TextLabel</source>
- <translation type="unfinished"></translation>
+ <translation>TextovýPopis</translation>
</message>
<message>
<location filename="res/AddClientDialogBase.ui" line="83"/>
<source>Ignore auto connect clients</source>
- <translation type="unfinished"></translation>
+ <translation>Ignorovať automatické pripojenia klientov</translation>
</message>
</context>
<context>
@@ -165,12 +175,12 @@ Visit our website for help and info (symless.com).
<message>
<location filename="res/HotkeyDialogBase.ui" line="14"/>
<source>Hotkey</source>
- <translation type="unfinished"></translation>
+ <translation>Klávesová skratka</translation>
</message>
<message>
<location filename="res/HotkeyDialogBase.ui" line="20"/>
<source>Enter the specification for the hotkey:</source>
- <translation type="unfinished"></translation>
+ <translation>Vložte popis klávesovej skratky:</translation>
</message>
</context>
<context>
@@ -178,189 +188,193 @@ Visit our website for help and info (symless.com).
<message>
<location filename="src/MainWindow.cpp" line="790"/>
<source>&amp;Start</source>
- <translation type="unfinished"></translation>
+ <translation>S&amp;pustiť</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="237"/>
<source>&amp;File</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Súbor</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="238"/>
<source>&amp;Edit</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Upraviť</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="239"/>
<source>&amp;Window</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Okno</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="240"/>
<source>&amp;Help</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Pomocník</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="364"/>
<source>&lt;p&gt;Your version of Barrier is out of date. Version &lt;b&gt;%1&lt;/b&gt; is now available to &lt;a href=&quot;%2&quot;&gt;download&lt;/a&gt;.&lt;/p&gt;</source>
<oldsource>&lt;p&gt;Version %1 is now available, &lt;a href=&quot;%2&quot;&gt;visit website&lt;/a&gt;.&lt;/p&gt;</oldsource>
- <translation type="unfinished"></translation>
+ <translation>&lt;p&gt;Vaša verzia Barrier nie je aktuálna. Na &lt;a href=&quot;%2&quot;&gt;stiahnutie&lt;/a&gt; je k dispozícii verzia &lt;b&gt;%1&lt;/b&gt;.&lt;/p&gt;</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="577"/>
<source>Program can not be started</source>
- <translation type="unfinished"></translation>
+ <translation>Program sa nepodarilo spustiť</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="577"/>
<source>The executable&lt;br&gt;&lt;br&gt;%1&lt;br&gt;&lt;br&gt;could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program.</source>
- <translation type="unfinished"></translation>
+ <translation>Súbor &lt;br&gt;&lt;br&gt;%1&lt;br&gt;&lt;br&gt;sa nepodarilo spustiť aj napriek tomu, že existuje. Prosím, skontrolujte, či máte dostatočné práva na spustenie tohto programu.</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="596"/>
<source>Barrier client not found</source>
- <translation type="unfinished"></translation>
+ <translation>Nepodarilo sa nájsť klienta Barrier</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="597"/>
<source>The executable for the barrier client does not exist.</source>
- <translation type="unfinished"></translation>
+ <translation>Spustiteľný súbor klienta barrier neexistuje.</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="625"/>
<source>Hostname is empty</source>
- <translation type="unfinished"></translation>
+ <translation>Názov hostiteľa je prázdny</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="626"/>
<source>Please fill in a hostname for the barrier client to connect to.</source>
- <translation type="unfinished"></translation>
+ <translation>Prosím, vyplňte názov hostiteľa, ku ktorému sa klient barrier má pripojiť.</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="646"/>
<source>Cannot write configuration file</source>
- <translation type="unfinished"></translation>
+ <translation>Nepodarilo sa zapísať súbor s konfiguráciou</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="646"/>
<source>The temporary configuration file required to start barrier can not be written.</source>
- <translation type="unfinished"></translation>
+ <translation>Nepodarilo sa zapísať do dočasného súboru, ktorý je potrebný pre spustenie barrier.</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="659"/>
<source>Configuration filename invalid</source>
- <translation type="unfinished"></translation>
+ <translation>Neplatný názov konfiguračného súboru</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="660"/>
<source>You have not filled in a valid configuration file for the barrier server. Do you want to browse for the configuration file now?</source>
- <translation type="unfinished"></translation>
+ <translation>Nezadali ste platný konfiguračný súbor pre server barrier. Želáte si teraz vybrať súbor s konfiguráciou?</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="688"/>
<source>Barrier server not found</source>
- <translation type="unfinished"></translation>
+ <translation>Server barrier nebol nájdený</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="689"/>
<source>The executable for the barrier server does not exist.</source>
- <translation type="unfinished"></translation>
+ <translation>Spustiteľný súbor servera barrier neexistuje.</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="764"/>
<source>Barrier terminated with an error</source>
- <translation type="unfinished"></translation>
+ <translation>Barrier skončil s chybou</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="764"/>
<source>Barrier terminated unexpectedly with an exit code of %1.&lt;br&gt;&lt;br&gt;Please see the log output for details.</source>
- <translation type="unfinished"></translation>
+ <translation>Barrier bolo neočakávane ukončený s chybovým kódom %1.&lt;br&gt;&lt;br&gt;Podrobnosti nájdete v súbore s protokolom.</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="783"/>
<source>&amp;Stop</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Zastaviť</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="1038"/>
<source>Please add the server (%1) to the grid.</source>
- <translation type="unfinished"></translation>
+ <translation>Pridajte, prosím, server (%1) do mriežky.</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="1044"/>
<source>Please drag the new client screen (%1) to the desired position on the grid.</source>
- <translation type="unfinished"></translation>
+ <translation>Ťahaním presuňte obrazovku nového klienta (%1) na požadovanú pozíciu v mriežke.</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="1147"/>
<source>Failed to detect system architecture.</source>
- <translation type="unfinished"></translation>
+ <translation>Nepodarilo sa zistiť systémovú architektúru.</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="1165"/>
<source>Cancel</source>
- <translation type="unfinished"></translation>
+ <translation>Zrušiť</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="1189"/>
<source>Failed to download Bonjour installer to location: %1</source>
- <translation type="unfinished"></translation>
+ <translation>Nepodarilo sa stiahnuť inštalátor Bonjour do umiestnenia: %1</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="1226"/>
<source>Do you want to enable auto config and install Bonjour?
This feature helps you establish the connection.</source>
- <translation type="unfinished"></translation>
+ <translation>Želáte si povoliť autokonfiguráciu a nainštalovať Bonjour?
+
+Táto funkcia vám pomôže s nadväzovaním spojenia.</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="1270"/>
<source>Auto config feature requires Bonjour.
Do you want to install Bonjour?</source>
- <translation type="unfinished"></translation>
+ <translation>Funkcia autokonfigurácie vyžaduje Bonjour.
+
+Želáte si nainštalovať Bonjour?</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="815"/>
<source>Barrier is starting.</source>
- <translation type="unfinished"></translation>
+ <translation>Barrier sa spúšťa.</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="809"/>
<source>Barrier is running.</source>
- <translation type="unfinished"></translation>
+ <translation>Barrier je spustený.</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="819"/>
<source>Barrier is not running.</source>
- <translation type="unfinished"></translation>
+ <translation>Barrier nie je spustený.</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="870"/>
<source>Unknown</source>
- <translation type="unfinished"></translation>
+ <translation>Neznáma</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="1146"/>
<location filename="src/MainWindow.cpp" line="1225"/>
<location filename="src/MainWindow.cpp" line="1269"/>
<source>Barrier</source>
- <translation type="unfinished"></translation>
+ <translation>Barrier</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="987"/>
<source>Browse for a barriers config file</source>
- <translation type="unfinished"></translation>
+ <translation>Vybrať súbor s konfiguráciou barrier</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="408"/>
<source>Barrier is now connected, You can close the config window. Barrier will remain connected in the background.</source>
- <translation type="unfinished"></translation>
+ <translation>Barrier je pripojený, môžete zavrieť okno s nastaveniami. Barrier zostane bežať na pozadí.</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="434"/>
<source>Security question</source>
- <translation type="unfinished"></translation>
+ <translation>Bezpečnostná otázka</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="435"/>
@@ -368,25 +382,31 @@ Do you want to install Bonjour?</source>
%1
-This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user).
+This is a server fingerprint. You should compare this fingerprint to the one on your server&apos;s screen. If the two don&apos;t match exactly, then it&apos;s probably not the server you&apos;re expecting (it could be a malicious user).
To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No.</source>
- <translation type="unfinished"></translation>
+ <translation>Dôverujete tomuto otlačku?
+
+%1
+
+Toto je digitálny otlačok servera. Mali by ste ho porovnať s otlačkom na jednej z obrazoviek vášho servera. Ak nie sú rovnaké, potom sa pravdepodobne nepripájate na server, na ktorý chcete (môže sa jednať o zlomyselného používateľa).
+
+Ak chcete automaticky dôverovať tomuto otlačku pri ďalších spojeniach, kliknite na Áno. Pre odmietnutie tohto otlačku a odpojenie od servera kliknite na Nie.</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="1000"/>
<source>Save configuration as...</source>
- <translation type="unfinished"></translation>
+ <translation>Uložiť konfiguráciu ako...</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="1004"/>
<source>Save failed</source>
- <translation type="unfinished"></translation>
+ <translation>Chyba pri ukladaní</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="1004"/>
<source>Could not save configuration to file.</source>
- <translation type="unfinished"></translation>
+ <translation>Nepodarilo sa uložiť súbor s konfiguráciou do súboru.</translation>
</message>
</context>
<context>
@@ -394,168 +414,168 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<message>
<location filename="res/MainWindowBase.ui" line="26"/>
<source>Barrier</source>
- <translation type="unfinished"></translation>
+ <translation>Barrier</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="90"/>
- <source>Ser&amp;ver (share this computer's mouse and keyboard):</source>
- <translation type="unfinished"></translation>
+ <source>Ser&amp;ver (share this computer&apos;s mouse and keyboard):</source>
+ <translation>Ser&amp;ver (zdieľať klávesnicu a myš tohto počítača):</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="243"/>
<source>Screen name:</source>
- <translation type="unfinished"></translation>
+ <translation>Názov obrazovky:</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="257"/>
<source>&amp;Server IP:</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;IP servera:</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="380"/>
<location filename="res/MainWindowBase.ui" line="409"/>
<source>&amp;Start</source>
- <translation type="unfinished"></translation>
+ <translation>S&amp;pustiť</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="181"/>
<source>Use existing configuration:</source>
- <translation type="unfinished"></translation>
+ <translation>Použiť existujúcu konfiguráciu:</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="190"/>
<source>&amp;Configuration file:</source>
- <translation type="unfinished"></translation>
+ <translation>Sú&amp;bor s konfiguráciou:</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="210"/>
<source>&amp;Browse...</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Prechádzať...</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="147"/>
<source>Configure interactively:</source>
- <translation type="unfinished"></translation>
+ <translation>Interaktívna konfigurácia:</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="159"/>
<source>&amp;Configure Server...</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Konfigurovať server...</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="350"/>
<source>Ready</source>
- <translation type="unfinished"></translation>
+ <translation>Pripravené</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="296"/>
<source>Log</source>
- <translation type="unfinished"></translation>
+ <translation>Protokol</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="373"/>
<source>&amp;Reload</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Znovu načítať</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="107"/>
<source>IP addresses:</source>
- <translation type="unfinished"></translation>
+ <translation>IP adresy:</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="131"/>
<source>Fingerprint:</source>
- <translation type="unfinished"></translation>
+ <translation>Otlačok:</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="228"/>
- <source>&amp;Client (use another computer's mouse and keyboard):</source>
- <translation type="unfinished"></translation>
+ <source>&amp;Client (use another computer&apos;s mouse and keyboard):</source>
+ <translation>&amp;Klient (používa klávesnicu a myš iného počítača):</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="270"/>
<source>Auto config</source>
- <translation type="unfinished"></translation>
+ <translation>Automatická konfigurácia</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="390"/>
<source>&amp;About Barrier...</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;O Barrier...</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="398"/>
<source>&amp;Quit</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Ukončiť</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="401"/>
<source>Quit</source>
- <translation type="unfinished"></translation>
+ <translation>Ukončiť</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="412"/>
<source>Run</source>
- <translation type="unfinished"></translation>
+ <translation>Spustiť</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="423"/>
<source>S&amp;top</source>
- <translation type="unfinished"></translation>
+ <translation>Za&amp;staviť</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="426"/>
<source>Stop</source>
- <translation type="unfinished"></translation>
+ <translation>Zastaviť</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="434"/>
<source>S&amp;how Status</source>
- <translation type="unfinished"></translation>
+ <translation>Zo&amp;braziť stav</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="442"/>
<source>&amp;Hide</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Skryť</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="445"/>
<source>Hide</source>
- <translation type="unfinished"></translation>
+ <translation>Skryť</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="453"/>
<source>&amp;Show</source>
- <translation type="unfinished"></translation>
+ <translation>Z&amp;obraziť</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="456"/>
<source>Show</source>
- <translation type="unfinished"></translation>
+ <translation>Zobraziť</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="464"/>
<source>Save configuration &amp;as...</source>
- <translation type="unfinished"></translation>
+ <translation>Uložiť konfiguráciu &amp;ako...</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="467"/>
<source>Save the interactively generated server configuration to a file.</source>
- <translation type="unfinished"></translation>
+ <translation>Uložiť interaktívne vygenerovanú konfiguráciu serveru do súboru.</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="475"/>
<source>Settings</source>
- <translation type="unfinished"></translation>
+ <translation>Nastavenia</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="478"/>
<source>Edit settings</source>
- <translation type="unfinished"></translation>
+ <translation>Upraviť nastavenia</translation>
</message>
<message>
<location filename="res/MainWindowBase.ui" line="486"/>
<source>Run Wizard</source>
- <translation type="unfinished"></translation>
+ <translation>Spustiť sprievodcu</translation>
</message>
</context>
<context>
@@ -563,7 +583,7 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<message>
<location filename="src/NewScreenWidget.cpp" line="32"/>
<source>Unnamed</source>
- <translation type="unfinished"></translation>
+ <translation>Bezmena</translation>
</message>
</context>
<context>
@@ -571,28 +591,29 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<message>
<location filename="src/PluginManager.cpp" line="58"/>
<source>Failed to get plugin directory.</source>
- <translation type="unfinished"></translation>
+ <translation>Nepodarilo sa získať adresár s pluginmi.</translation>
</message>
<message>
<location filename="src/PluginManager.cpp" line="63"/>
<source>Failed to get profile directory.</source>
- <translation type="unfinished"></translation>
+ <translation>Nepodarilo sa získať adresár s profilom.</translation>
</message>
<message>
<location filename="src/PluginManager.cpp" line="136"/>
- <source>Failed to download plugin '%1' to: %2
+ <source>Failed to download plugin &apos;%1&apos; to: %2
%3</source>
- <translation type="unfinished"></translation>
+ <translation>Nepodarilo sa stiahnuť plugin &apos;%1&apos; do: %2
+%3</translation>
</message>
<message>
<location filename="src/PluginManager.cpp" line="167"/>
<source>Could not get Windows architecture type.</source>
- <translation type="unfinished"></translation>
+ <translation>Nepodarilo sa zistiť typ architektúry Windows.</translation>
</message>
<message>
<location filename="src/PluginManager.cpp" line="191"/>
<source>Could not get Linux architecture type.</source>
- <translation type="unfinished"></translation>
+ <translation>Nepodarilo sa zistiť typ architektúry Linuxu.</translation>
</message>
</context>
<context>
@@ -600,66 +621,71 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<message>
<location filename="res/PluginWizardPageBase.ui" line="14"/>
<source>Setup Barrier</source>
- <translation type="unfinished"></translation>
+ <translation>Nastaviť Barrier</translation>
</message>
<message>
<location filename="res/PluginWizardPageBase.ui" line="101"/>
<source>Please wait...</source>
- <translation type="unfinished"></translation>
+ <translation>Čakajte prosím...</translation>
</message>
<message>
<location filename="src/PluginWizardPage.cpp" line="72"/>
<source>Error: %1</source>
- <translation type="unfinished"></translation>
+ <translation>Chyba: %1</translation>
</message>
<message>
<location filename="src/PluginWizardPage.cpp" line="80"/>
<location filename="src/PluginWizardPage.cpp" line="201"/>
<source>Setup complete.</source>
- <translation type="unfinished"></translation>
+ <translation>Nastavovanie dokončené.</translation>
</message>
<message>
<location filename="src/PluginWizardPage.cpp" line="93"/>
- <source>Downloading '%1' plugin (%2/%3)...</source>
- <translation type="unfinished"></translation>
+ <source>Downloading &apos;%1&apos; plugin (%2/%3)...</source>
+ <translation>Sťahujem plugin &apos;%1&apos; (%2/%3)...</translation>
</message>
<message>
<location filename="src/PluginWizardPage.cpp" line="104"/>
<source>Plugins installed successfully.</source>
- <translation type="unfinished"></translation>
+ <translation>Pluginy úspešne nainštalované.</translation>
</message>
<message>
<location filename="src/PluginWizardPage.cpp" line="120"/>
<source>Generating SSL certificate...</source>
- <translation type="unfinished"></translation>
+ <translation>Generujem SSL certifikát...</translation>
</message>
<message>
<location filename="src/PluginWizardPage.cpp" line="170"/>
<source>Downloading plugin: %1 (1/%2)</source>
- <translation type="unfinished"></translation>
+ <translation>Sťahujem plugin: %1 (1/%2)</translation>
</message>
<message>
<location filename="src/PluginWizardPage.cpp" line="239"/>
<source>Getting plugin list...</source>
- <translation type="unfinished"></translation>
+ <translation>Získavam zoznam pluginov...</translation>
</message>
</context>
<context>
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
- <translation type="unfinished"></translation>
+ <source>All files (*.*)</source>
+ <translation>Všetky súbory (*.*)</translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
+ <translation>Konfiguračné súbory Barrier (*.sgc)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
- <translation type="unfinished"></translation>
+ <source>Barrier Configurations (*.conf)</source>
+ <translation>Konfiguračné súbory Barrier (*.conf)</translation>
</message>
<message>
<location filename="src/main.cpp" line="119"/>
<source>System tray is unavailable, quitting.</source>
- <translation type="unfinished"></translation>
+ <translation>Systémová oblasť nie je dostupná, končím.</translation>
</message>
</context>
<context>
@@ -667,22 +693,22 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<message>
<location filename="src/ScreenSettingsDialog.cpp" line="67"/>
<source>Screen name is empty</source>
- <translation type="unfinished"></translation>
+ <translation>Názov obrazovky je prázdny</translation>
</message>
<message>
<location filename="src/ScreenSettingsDialog.cpp" line="68"/>
<source>The screen name cannot be empty. Please either fill in a name or cancel the dialog.</source>
- <translation type="unfinished"></translation>
+ <translation>Názov obrazovky nemôže byť prázdny. Zadajte, prosím, názov alebo zrušte toto dialógové okno.</translation>
</message>
<message>
<location filename="src/ScreenSettingsDialog.cpp" line="83"/>
<source>Screen name matches alias</source>
- <translation type="unfinished"></translation>
+ <translation>Názov obrazovky koliduje s jej alternatívnym názvom</translation>
</message>
<message>
<location filename="src/ScreenSettingsDialog.cpp" line="84"/>
<source>The screen name cannot be the same as an alias. Please either remove the alias or change the screen name.</source>
- <translation type="unfinished"></translation>
+ <translation>Názov obrazovky nemôže byť rovnaký ako jej alternatívny názov. Prosím, odstráňte alternatívny názov alebo zmeňte názov obrazovky.</translation>
</message>
</context>
<context>
@@ -690,37 +716,37 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="14"/>
<source>Screen Settings</source>
- <translation type="unfinished"></translation>
+ <translation>Nastavenia obrazovky</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="22"/>
<source>Screen &amp;name:</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Názov obrazovky:</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="42"/>
<source>A&amp;liases</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Alternatívne názvy</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="57"/>
<source>&amp;Add</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Pridať</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="74"/>
<source>&amp;Remove</source>
- <translation type="unfinished"></translation>
+ <translation>O&amp;dstrániť</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="97"/>
<source>&amp;Modifier keys</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Modifikátory klávesov</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="106"/>
<source>&amp;Shift:</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Shift:</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="117"/>
@@ -729,7 +755,7 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<location filename="res/ScreenSettingsDialogBase.ui" line="258"/>
<location filename="res/ScreenSettingsDialogBase.ui" line="305"/>
<source>Shift</source>
- <translation type="unfinished"></translation>
+ <translation>Shift</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="122"/>
@@ -738,7 +764,7 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<location filename="res/ScreenSettingsDialogBase.ui" line="263"/>
<location filename="res/ScreenSettingsDialogBase.ui" line="310"/>
<source>Ctrl</source>
- <translation type="unfinished"></translation>
+ <translation>Ctrl</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="127"/>
@@ -747,7 +773,7 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<location filename="res/ScreenSettingsDialogBase.ui" line="268"/>
<location filename="res/ScreenSettingsDialogBase.ui" line="315"/>
<source>Alt</source>
- <translation type="unfinished"></translation>
+ <translation>Alt</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="132"/>
@@ -756,7 +782,7 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<location filename="res/ScreenSettingsDialogBase.ui" line="273"/>
<location filename="res/ScreenSettingsDialogBase.ui" line="320"/>
<source>Meta</source>
- <translation type="unfinished"></translation>
+ <translation>Meta</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="137"/>
@@ -765,7 +791,7 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<location filename="res/ScreenSettingsDialogBase.ui" line="278"/>
<location filename="res/ScreenSettingsDialogBase.ui" line="325"/>
<source>Super</source>
- <translation type="unfinished"></translation>
+ <translation>Super</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="142"/>
@@ -774,82 +800,82 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<location filename="res/ScreenSettingsDialogBase.ui" line="283"/>
<location filename="res/ScreenSettingsDialogBase.ui" line="330"/>
<source>None</source>
- <translation type="unfinished"></translation>
+ <translation>Žiadny</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="150"/>
<source>&amp;Ctrl:</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Ctrl:</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="197"/>
<source>Al&amp;t:</source>
- <translation type="unfinished"></translation>
+ <translation>Al&amp;t:</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="244"/>
<source>M&amp;eta:</source>
- <translation type="unfinished"></translation>
+ <translation>M&amp;eta:</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="291"/>
<source>S&amp;uper:</source>
- <translation type="unfinished"></translation>
+ <translation>S&amp;uper:</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="358"/>
<source>&amp;Dead corners</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Mŕtve rohy</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="367"/>
<source>Top-left</source>
- <translation type="unfinished"></translation>
+ <translation>Vľavo hore</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="374"/>
<source>Top-right</source>
- <translation type="unfinished"></translation>
+ <translation>Vpravo hore</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="381"/>
<source>Bottom-left</source>
- <translation type="unfinished"></translation>
+ <translation>Vľavo dole</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="388"/>
<source>Bottom-right</source>
- <translation type="unfinished"></translation>
+ <translation>Vpravo dole</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="397"/>
<source>Corner Si&amp;ze:</source>
- <translation type="unfinished"></translation>
+ <translation>Veľ&amp;kosť rohov:</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="428"/>
<source>&amp;Fixes</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Opravy</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="437"/>
<source>Fix CAPS LOCK key</source>
- <translation type="unfinished"></translation>
+ <translation>Opraviť správanie klávesu CAPS LOCK</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="444"/>
<source>Fix NUM LOCK key</source>
- <translation type="unfinished"></translation>
+ <translation>Opraviť správanie klávesu NUM LOCK</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="451"/>
<source>Fix SCROLL LOCK key</source>
- <translation type="unfinished"></translation>
+ <translation>Opraviť správanie klávesu SCROLL LOCK</translation>
</message>
<message>
<location filename="res/ScreenSettingsDialogBase.ui" line="458"/>
<source>Fix XTest for Xinerama</source>
- <translation type="unfinished"></translation>
+ <translation>Opravit XTest pre Xinerama</translation>
</message>
</context>
<context>
@@ -857,7 +883,7 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<message>
<location filename="src/ScreenSetupModel.cpp" line="51"/>
<source>&lt;center&gt;Screen: &lt;b&gt;%1&lt;/b&gt;&lt;/center&gt;&lt;br&gt;Double click to edit settings&lt;br&gt;Drag screen to the trashcan to remove it</source>
- <translation type="unfinished"></translation>
+ <translation>&lt;center&gt;Obrazovka: &lt;b&gt;%1&lt;/b&gt;&lt;/center&gt;&lt;br&gt;Dvojitým kliknutím upravíte nastavenia&lt;br&gt;Pre odstránenie obrazovky ju myšou presuňte do koša</translation>
</message>
</context>
<context>
@@ -865,7 +891,7 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<message>
<location filename="src/ServerConfigDialog.cpp" line="75"/>
<source>Configure server</source>
- <translation type="unfinished"></translation>
+ <translation>Konfigurovať server</translation>
</message>
</context>
<context>
@@ -873,166 +899,168 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<message>
<location filename="res/ServerConfigDialogBase.ui" line="14"/>
<source>Server Configuration</source>
- <translation type="unfinished"></translation>
+ <translation>Konfigurácia servera</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="24"/>
<source>Screens and links</source>
- <translation type="unfinished"></translation>
+ <translation>Obrazovky a prepojenia</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="35"/>
<source>Drag a screen from the grid to the trashcan to remove it.</source>
- <translation type="unfinished"></translation>
+ <translation>Pre odstránenie obrazovky ju chyťte a presuňte z mriežky do koša.</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="60"/>
<source>Configure the layout of your barrier server configuration.</source>
- <translation type="unfinished"></translation>
+ <translation>Nastaviť rozloženie konfigurácie vášho servera barrier.</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="73"/>
<source>Drag this button to the grid to add a new screen.</source>
- <translation type="unfinished"></translation>
+ <translation>Pre vytvorenie novej obrazovky presuňte toto tlačidlo do mriežky.</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="128"/>
<source>Drag new screens to the grid or move existing ones around.
Drag a screen to the trashcan to delete it.
Double click on a screen to edit its settings.</source>
- <translation type="unfinished"></translation>
+ <translation>Ťahaním pridajte nové obrazovky do mriežky alebo presuňte existujúce.
+Presuňte obrazovku do koša, ak ju chcete odstrániť.
+Dvojitým kliknutím na obrazovku upravíte jej nastavenia.</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="157"/>
<source>Hotkeys</source>
- <translation type="unfinished"></translation>
+ <translation>Klávesové skratky</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="163"/>
<source>&amp;Hotkeys</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Klávesové skratky</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="175"/>
<source>&amp;New</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Nový</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="185"/>
<source>&amp;Edit</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Upraviť</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="195"/>
<source>&amp;Remove</source>
- <translation type="unfinished"></translation>
+ <translation>O&amp;dstrániť</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="218"/>
<source>A&amp;ctions</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Akcie</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="230"/>
<source>Ne&amp;w</source>
- <translation type="unfinished"></translation>
+ <translation>No&amp;vý</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="240"/>
<source>E&amp;dit</source>
- <translation type="unfinished"></translation>
+ <translation>U&amp;praviť</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="250"/>
<source>Re&amp;move</source>
- <translation type="unfinished"></translation>
+ <translation>Ods&amp;trániť</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="274"/>
<source>Advanced server settings</source>
- <translation type="unfinished"></translation>
+ <translation>Pokročilé nastavenia serveru</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="280"/>
<source>&amp;Switch</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Prepnúť</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="291"/>
<source>Switch &amp;after waiting</source>
- <translation type="unfinished"></translation>
+ <translation>Prepnúť &amp;po prestávke</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="330"/>
<location filename="res/ServerConfigDialogBase.ui" line="383"/>
<location filename="res/ServerConfigDialogBase.ui" line="458"/>
<source>ms</source>
- <translation type="unfinished"></translation>
+ <translation>ms</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="344"/>
<source>Switch on double &amp;tap within</source>
- <translation type="unfinished"></translation>
+ <translation>Prepnúť po &amp;dvojitom ťuknutí počas</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="408"/>
<source>&amp;Options</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Možnosti</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="419"/>
<source>&amp;Check clients every</source>
- <translation type="unfinished"></translation>
+ <translation>K&amp;ontrolovať klientov každých</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="470"/>
<source>Use &amp;relative mouse moves</source>
- <translation type="unfinished"></translation>
+ <translation>Používať &amp;relatívne pohyby myši</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="480"/>
<source>S&amp;ynchronize screen savers</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Synchronizovať šetriče obrazovky</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="490"/>
- <source>Don't take &amp;foreground window on Windows servers</source>
- <translation type="unfinished"></translation>
+ <source>Don&apos;t take &amp;foreground window on Windows servers</source>
+ <translation>Na serveroch s &amp;Windows sa neprepínať do popredia</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="510"/>
<source>Ignore auto config clients</source>
- <translation type="unfinished"></translation>
+ <translation>Ignorovať klientov s autokonfiguráciou</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="520"/>
<source>&amp;Dead corners</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Mŕtve rohy</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="529"/>
<source>To&amp;p-left</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Vľavo hore</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="536"/>
<source>Top-rig&amp;ht</source>
- <translation type="unfinished"></translation>
+ <translation>Vpravo &amp;dole</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="543"/>
<source>&amp;Bottom-left</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Vľavo dole</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="550"/>
<source>Bottom-ri&amp;ght</source>
- <translation type="unfinished"></translation>
+ <translation>V&amp;pravo dole</translation>
</message>
<message>
<location filename="res/ServerConfigDialogBase.ui" line="572"/>
<source>Cor&amp;ner Size:</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Veľkost rohov:</translation>
</message>
</context>
<context>
@@ -1040,19 +1068,21 @@ Double click on a screen to edit its settings.</source>
<message>
<location filename="src/SettingsDialog.cpp" line="131"/>
<source>Save log file to...</source>
- <translation type="unfinished"></translation>
+ <translation>Uložiť súbor s protokolom do...</translation>
</message>
<message>
<location filename="src/SettingsDialog.cpp" line="151"/>
<source>Elevate Barrier</source>
- <translation type="unfinished"></translation>
+ <translation>Zvýšiť stupeň oprávnení pre Barrier</translation>
</message>
<message>
<location filename="src/SettingsDialog.cpp" line="152"/>
<source>Are you sure you want to elevate Barrier?
This allows Barrier to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Barrier only if you really need to.</source>
- <translation type="unfinished"></translation>
+ <translation>Naozaj chcete zvýšiť stupeň oprávnení pre Barrier?
+
+Toto umožní Barrier pracovať s procesmi, ktoré majú takisto vyšší stupeň oprávnení a s oknom riadenia používateľských účtov (UAC), ale môže to tiež spôsobiť problémy aplikáciam s bežnými oprávneniami. Túto možnosť by ste mali použiť iba, ak ju skutočne potrebujete.</translation>
</message>
</context>
<context>
@@ -1060,107 +1090,107 @@ This allows Barrier to interact with elevated processes and the UAC dialog, but
<message>
<location filename="res/SettingsDialogBase.ui" line="14"/>
<source>Settings</source>
- <translation type="unfinished"></translation>
+ <translation>Nastavenia</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="32"/>
<source>Sc&amp;reen name:</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Názov obrazovky:</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="49"/>
<source>P&amp;ort:</source>
- <translation type="unfinished"></translation>
+ <translation>P&amp;ort:</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="78"/>
<source>&amp;Interface:</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Používateľské rozhranie:</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="120"/>
<source>Elevate mode</source>
- <translation type="unfinished"></translation>
+ <translation>Režim oprávnení</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="127"/>
<source>&amp;Hide on startup</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Skryť pri spustení</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="146"/>
<source>&amp;Network Security</source>
- <translation type="unfinished"></translation>
+ <translation>Sieťová &amp;bezpečnosť</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="155"/>
<source>Use &amp;SSL encryption (unique certificate)</source>
- <translation type="unfinished"></translation>
+ <translation>Používať šifrovanie &amp;SSL (jedinečný certifikát)</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="184"/>
<source>Logging</source>
- <translation type="unfinished"></translation>
+ <translation>Protokolovanie</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="202"/>
<source>&amp;Logging level:</source>
- <translation type="unfinished"></translation>
+ <translation>Ú&amp;roveň protokolu:</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="251"/>
<source>Log to file:</source>
- <translation type="unfinished"></translation>
+ <translation>Protokol ukladať do súboru:</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="268"/>
<source>Browse...</source>
- <translation type="unfinished"></translation>
+ <translation>Prechádzať...</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="213"/>
<source>Error</source>
- <translation type="unfinished"></translation>
+ <translation>Chyba</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="107"/>
<source>&amp;Language:</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Jazyk:</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="20"/>
<source>&amp;Miscellaneous</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Rôzne</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="218"/>
<source>Warning</source>
- <translation type="unfinished"></translation>
+ <translation>Varovanie</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="223"/>
<source>Note</source>
- <translation type="unfinished"></translation>
+ <translation>Poznámka</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="228"/>
<source>Info</source>
- <translation type="finished">Informácie</translation>
+ <translation>Informácie</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="233"/>
<source>Debug</source>
- <translation type="unfinished"></translation>
+ <translation>Ladenie</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="238"/>
<source>Debug1</source>
- <translation type="unfinished"></translation>
+ <translation>Ladenie1</translation>
</message>
<message>
<location filename="res/SettingsDialogBase.ui" line="243"/>
<source>Debug2</source>
- <translation type="unfinished"></translation>
+ <translation>Ladenie2</translation>
</message>
</context>
<context>
@@ -1168,17 +1198,17 @@ This allows Barrier to interact with elevated processes and the UAC dialog, but
<message>
<location filename="src/SetupWizard.cpp" line="72"/>
<source>Setup Barrier</source>
- <translation type="unfinished"></translation>
+ <translation>Nastaviť Barrier</translation>
</message>
<message>
<location filename="src/SetupWizard.cpp" line="113"/>
<source>Please select an option.</source>
- <translation type="unfinished"></translation>
+ <translation>Prosím, vyberte si jednu z možností.</translation>
</message>
<message>
<location filename="src/SetupWizard.cpp" line="80"/>
<source>Please enter your email address and password.</source>
- <translation type="unfinished"></translation>
+ <translation>Zadajte, prosím, vašu emailovú adresu a heslo.</translation>
</message>
</context>
<context>
@@ -1186,85 +1216,93 @@ This allows Barrier to interact with elevated processes and the UAC dialog, but
<message>
<location filename="res/SetupWizardBase.ui" line="26"/>
<source>Setup Barrier</source>
- <translation type="unfinished"></translation>
+ <translation>Nastaviť Barrier</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="30"/>
<source>Welcome</source>
- <translation type="unfinished"></translation>
+ <translation>Vitajte</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="39"/>
<source>Thanks for installing Barrier!</source>
- <translation type="unfinished"></translation>
+ <translation>Ďakujeme, že ste sa rozhodli nainštalovať Barrier!</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="114"/>
- <source>Barrier lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Barrier is cross-platform (works on Windows, Mac OS X and Linux).</source>
- <translation type="finished">Barrier vám umožní ľahko zdieľať myš a klávesnicu medzi viacerými počítačmi na stole, je to zadarmo a Open Source. Len presunúť kurzor myši mimo okraj jedného počítača na obrazovke na ďalšie. Môžete dokonca zdieľať všetky vaše schránok. Všetko, čo potrebujete, je pripojenie k sieti. Barrier je cross-platformové (práca na Windows, Mac OS X a Linux).</translation>
+ <source>Barrier lets you easily share your mouse and keyboard between multiple computers on your desk, and it&apos;s Free and Open Source. Just move your mouse off the edge of one computer&apos;s screen on to another. You can even share all of your clipboards. All you need is a network connection. Barrier is cross-platform (works on Windows, Mac OS X and Linux).</source>
+ <translation>Barrier vám umožní ľahko zdieľať myš a klávesnicu medzi viacerými počítačmi, je zadarmo a má otvorený zdrojový kód. Stačí len presunúť kurzor myši mimo okraj obrazovky jedného počítača a presuniete sa na druhý počítač. Môžete dokonca zdieľať všetky vaše schránky. Všetko, čo potrebujete, je pripojenie k sieti. Barrier podporuje viacero platforiem (funguje vo Windowse, Mac OS X a Linuxe).</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="125"/>
<source>Activate</source>
- <translation type="unfinished"></translation>
+ <translation>Aktivovať</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="131"/>
<source>&amp;Activate now...</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Aktivovať teraz...</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="152"/>
<source>Email:</source>
- <translation type="unfinished"></translation>
+ <translation>Email:</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="178"/>
<source>Password:</source>
- <translation type="unfinished"></translation>
+ <translation>Heslo:</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="204"/>
<source>&lt;a href=&quot;https://symless.com/account/reset/&quot;&gt;Forgot password&lt;/a&gt;</source>
- <translation type="unfinished"></translation>
+ <translation>&lt;a href=&quot;https://symless.com/account/reset/&quot;&gt;Zabudnuté heslo&lt;/a&gt;</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="232"/>
<source>&amp;Skip activation</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Preskočiť aktiváciu</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="277"/>
- <source>&amp;Server (share this computer's mouse and keyboard)</source>
- <translation type="unfinished"></translation>
+ <source>&amp;Server (share this computer&apos;s mouse and keyboard)</source>
+ <translation>&amp;Server (zdieľať klávesnicu a myš tohto počítača)</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="290"/>
<source>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
-&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
- <translation type="unfinished"></translation>
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer&apos;s screen. There can only be one server in your setup.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;K tomuto počítaču je pripojená moja hlavná klávesnica a myš. Toto vám umožní presunúť kurzor myši na obrazovku iného počítača. V úlohe servera môže byť len jeden počítač.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="326"/>
- <source>&amp;Client (use another computer's mouse and keyboard)</source>
- <translation type="unfinished"></translation>
+ <source>&amp;Client (use another computer&apos;s mouse and keyboard)</source>
+ <translation>&amp;Klient (použiť klávesnicu a myš iného počítača)</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="339"/>
<source>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
-&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
- <translation type="unfinished"></translation>
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;You have already set up a server. This computer will be controlled using the server&apos;s mouse and keyboard. There can be many clients in your setup.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;Server už ste nastavili. Tento počítač bude ovládaný klávesnicou a myšou pripojenou k serveru. V roli klienta môže byť viacero počítačov.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="res/SetupWizardBase.ui" line="262"/>
<source>Server or Client?</source>
- <translation type="unfinished"></translation>
+ <translation>Server alebo klient?</translation>
</message>
</context>
<context>
@@ -1272,22 +1310,22 @@ p, li { white-space: pre-wrap; }
<message>
<location filename="src/SslCertificate.cpp" line="42"/>
<source>Failed to get profile directory.</source>
- <translation type="unfinished"></translation>
+ <translation>Nepodarilo sa získať adresár s profilom.</translation>
</message>
<message>
<location filename="src/SslCertificate.cpp" line="141"/>
<source>SSL certificate generated.</source>
- <translation type="unfinished"></translation>
+ <translation>SSL certifikát bol vygenerovaný.</translation>
</message>
<message>
<location filename="src/SslCertificate.cpp" line="170"/>
<source>SSL fingerprint generated.</source>
- <translation type="unfinished"></translation>
+ <translation>SSL otlačok bol vygenerovaný.</translation>
</message>
<message>
<location filename="src/SslCertificate.cpp" line="173"/>
<source>Failed to find SSL fingerprint.</source>
- <translation type="unfinished"></translation>
+ <translation>Nepodarilo sa nájsť otlačok SSL.</translation>
</message>
</context>
<context>
@@ -1295,7 +1333,7 @@ p, li { white-space: pre-wrap; }
<message>
<location filename="src/VersionChecker.cpp" line="102"/>
<source>Unknown</source>
- <translation type="unfinished"></translation>
+ <translation>Neznáma</translation>
</message>
</context>
<context>
@@ -1305,19 +1343,23 @@ p, li { white-space: pre-wrap; }
<source>An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details.
%1</source>
- <translation type="unfinished"></translation>
+ <translation>Počas pokusu o prihlásenie došlo k chybe. Prosím, kontaktujte zákaznickú podporu a poskytnite im nasledujúce údaje.
+
+%1</translation>
</message>
<message>
<location filename="src/WebClient.cpp" line="65"/>
<source>Login failed, invalid email or password.</source>
- <translation type="unfinished"></translation>
+ <translation>Prihlásenie nebolo úspešné, neplatná emailová adresa alebo heslo.</translation>
</message>
<message>
<location filename="src/WebClient.cpp" line="78"/>
<source>Login failed, an error occurred.
%1</source>
- <translation type="unfinished"></translation>
+ <translation>Prihlásenie nebolo úspešné, nastala chyba.
+
+%1</translation>
</message>
<message>
<location filename="src/WebClient.cpp" line="86"/>
@@ -1326,26 +1368,33 @@ p, li { white-space: pre-wrap; }
Server response:
%1</source>
- <translation type="unfinished"></translation>
+ <translation>Prihlásenie nebolo úspešné, nastala chyba.
+
+Odpoveď servera:
+%1</translation>
</message>
<message>
<location filename="src/WebClient.cpp" line="101"/>
<source>An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details.
%1</source>
- <translation type="unfinished"></translation>
+ <translation>Počas získavania zoznamu pluginov došlo k chybe. Prosím, kontaktujte zákaznickú podporu a poskytnite im nasledujúce údaje.
+
+%1</translation>
</message>
<message>
<location filename="src/WebClient.cpp" line="120"/>
<source>Get plugin list failed, invalid user email or password.</source>
- <translation type="unfinished"></translation>
+ <translation>Zlyhalo získavanie zoznamu pluginov, neplatná emailová adresa alebo heslo.</translation>
</message>
<message>
<location filename="src/WebClient.cpp" line="131"/>
<source>Get plugin list failed, an error occurred.
%1</source>
- <translation type="unfinished"></translation>
+ <translation>Zlyhalo získavanie zoznamu pluginov, nastala chyba.
+
+%1</translation>
</message>
<message>
<location filename="src/WebClient.cpp" line="137"/>
@@ -1354,7 +1403,10 @@ Server response:
Server response:
%1</source>
- <translation type="unfinished"></translation>
+ <translation>Zlyhalo získavanie zoznamu pluginov, nastala chyba.
+
+Odpoveď servera:
+%1</translation>
</message>
</context>
<context>
@@ -1362,44 +1414,44 @@ Server response:
<message>
<location filename="src/ZeroconfService.cpp" line="82"/>
<source>zeroconf server detected: %1</source>
- <translation type="unfinished"></translation>
+ <translation>detegovaný zeroconf server: %1</translation>
</message>
<message>
<location filename="src/ZeroconfService.cpp" line="91"/>
<source>zeroconf client detected: %1</source>
- <translation type="unfinished"></translation>
+ <translation>detegovaný zeroconf klient: %1</translation>
</message>
<message>
<location filename="src/ZeroconfService.cpp" line="99"/>
<location filename="src/ZeroconfService.cpp" line="130"/>
<source>Zero configuration service</source>
- <translation type="unfinished"></translation>
+ <translation>Služba Zero configuration</translation>
</message>
<message>
<location filename="src/ZeroconfService.cpp" line="100"/>
<source>Error code: %1.</source>
- <translation type="unfinished"></translation>
+ <translation>Kód chyby: %1.</translation>
</message>
<message>
<location filename="src/ZeroconfService.cpp" line="131"/>
<source>Unable to start the zeroconf: %1.</source>
- <translation type="unfinished"></translation>
+ <translation>Nepodarilo sa spustiť zeroconf: %1.</translation>
</message>
<message>
<location filename="src/ZeroconfService.cpp" line="140"/>
<source>Barrier</source>
- <translation type="unfinished"></translation>
+ <translation>Barrier</translation>
</message>
<message>
<location filename="src/ZeroconfService.cpp" line="141"/>
<source>Failed to get local IP address. Please manually type in server address on your clients</source>
- <translation type="unfinished"></translation>
+ <translation>Nepodarilo sa získať miestnu IP adresu. Zadajte, prosím, adresu servera ručne v nastaveniach vašich klientov</translation>
</message>
<message>
<location filename="src/ZeroconfService.cpp" line="147"/>
<location filename="src/ZeroconfService.cpp" line="154"/>
<source>%1</source>
- <translation type="unfinished"></translation>
+ <translation>%1</translation>
</message>
</context>
-</TS> \ No newline at end of file
+</TS>
diff --git a/src/gui/res/lang/gui_sl-SI.ts b/src/gui/res/lang/gui_sl-SI.ts
index 5aa6cde..181d5e2 100644
--- a/src/gui/res/lang/gui_sl-SI.ts
+++ b/src/gui/res/lang/gui_sl-SI.ts
@@ -648,12 +648,17 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
+ <source>All files (*.*)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
+ <source>Barrier Configurations (*.conf)</source>
<translation type="unfinished"></translation>
</message>
<message>
diff --git a/src/gui/res/lang/gui_sq-AL.qm b/src/gui/res/lang/gui_sq-AL.qm
index c80f8ab..b54bb6e 100644
--- a/src/gui/res/lang/gui_sq-AL.qm
+++ b/src/gui/res/lang/gui_sq-AL.qm
Binary files differ
diff --git a/src/gui/res/lang/gui_sq-AL.ts b/src/gui/res/lang/gui_sq-AL.ts
index 1fcd217..fa65c6c 100644
--- a/src/gui/res/lang/gui_sq-AL.ts
+++ b/src/gui/res/lang/gui_sq-AL.ts
@@ -648,13 +648,18 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
- <translation type="finished">Konfiguracioni i Barrier (*.sgc);;Te gjithe (*.*)</translation>
+ <source>All files (*.*)</source>
+ <translation type="finished">Te gjithe (*.*)</translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
+ <translation type="finished">Konfiguracioni i Barrier (*.sgc)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
- <translation type="finished">Konfiguracioni i Barrier (*.conf);;Te gjithe (*.*)</translation>
+ <source>Barrier Configurations (*.conf)</source>
+ <translation type="finished">Konfiguracioni i Barrier (*.conf)</translation>
</message>
<message>
<location filename="src/main.cpp" line="119"/>
diff --git a/src/gui/res/lang/gui_sr.ts b/src/gui/res/lang/gui_sr.ts
index 4ae87d8..d46168f 100644
--- a/src/gui/res/lang/gui_sr.ts
+++ b/src/gui/res/lang/gui_sr.ts
@@ -648,12 +648,17 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
+ <source>All files (*.*)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
+ <source>Barrier Configurations (*.conf)</source>
<translation type="unfinished"></translation>
</message>
<message>
diff --git a/src/gui/res/lang/gui_sv.qm b/src/gui/res/lang/gui_sv.qm
index f014cfd..897abe3 100644
--- a/src/gui/res/lang/gui_sv.qm
+++ b/src/gui/res/lang/gui_sv.qm
Binary files differ
diff --git a/src/gui/res/lang/gui_sv.ts b/src/gui/res/lang/gui_sv.ts
index f0c239e..d28810c 100644
--- a/src/gui/res/lang/gui_sv.ts
+++ b/src/gui/res/lang/gui_sv.ts
@@ -669,13 +669,18 @@ Klicka &quot;Ja&quot; för att automatiskt lita på fingeravtrycket i framtida a
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
- <translation>Barrier-konfigurationer (*.sgc);;Alla filer (*.*)</translation>
+ <source>All files (*.*)</source>
+ <translation>Alla filer (*.*)</translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
+ <translation>Barrier-konfigurationer (*.sgc)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
- <translation>Barrier-konfigurationer (*.conf);;Alla filer (*.*)</translation>
+ <source>Barrier Configurations (*.conf)</source>
+ <translation>Barrier-konfigurationer (*.conf)</translation>
</message>
<message>
<location filename="src/main.cpp" line="119"/>
diff --git a/src/gui/res/lang/gui_th-TH.ts b/src/gui/res/lang/gui_th-TH.ts
index 07c74b8..88d7894 100644
--- a/src/gui/res/lang/gui_th-TH.ts
+++ b/src/gui/res/lang/gui_th-TH.ts
@@ -648,12 +648,17 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
+ <source>All files (*.*)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
+ <source>Barrier Configurations (*.conf)</source>
<translation type="unfinished"></translation>
</message>
<message>
diff --git a/src/gui/res/lang/gui_tr-TR.ts b/src/gui/res/lang/gui_tr-TR.ts
index 01a681b..924662f 100644
--- a/src/gui/res/lang/gui_tr-TR.ts
+++ b/src/gui/res/lang/gui_tr-TR.ts
@@ -648,12 +648,17 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
+ <source>All files (*.*)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
+ <source>Barrier Configurations (*.conf)</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -900,8 +905,8 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<source>Drag new screens to the grid or move existing ones around.
Drag a screen to the trashcan to delete it.
Double click on a screen to edit its settings.</source>
- <translation type="finished">Izgaraya yeni ekranları sürükleyin veya çevresinde mevcut olanları taşıyın.
-Silmek için çöp tenekesine ekranı sürükleyin.
+ <translation type="finished">Izgaraya yeni ekranları sürükleyin veya çevresinde mevcut olanları taşıyın.
+Silmek için çöp tenekesine ekranı sürükleyin.
Kendi ayarlarınızı düzenlemek için bir ekran üzerine çift tıklayın.</translation>
</message>
<message>
diff --git a/src/gui/res/lang/gui_uk.qm b/src/gui/res/lang/gui_uk.qm
index 3e9c9c5..86cb8ef 100644
--- a/src/gui/res/lang/gui_uk.qm
+++ b/src/gui/res/lang/gui_uk.qm
Binary files differ
diff --git a/src/gui/res/lang/gui_uk.ts b/src/gui/res/lang/gui_uk.ts
index 1f2dffe..b7297c1 100644
--- a/src/gui/res/lang/gui_uk.ts
+++ b/src/gui/res/lang/gui_uk.ts
@@ -648,13 +648,18 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
- <translation type="finished">Конфігурація Barrier (*.sgc);;Всі файли (*.*)</translation>
+ <source>All files (*.*)</source>
+ <translation type="finished">Всі файли (*.*)</translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
+ <translation type="finished">Конфігурація Barrier (*.sgc)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
- <translation type="finished">Конфігурація Barrier (*.conf);;Всі файли (*.*)</translation>
+ <source>Barrier Configurations (*.conf)</source>
+ <translation type="finished">Конфігурація Barrier (*.conf)</translation>
</message>
<message>
<location filename="src/main.cpp" line="119"/>
diff --git a/src/gui/res/lang/gui_ur.ts b/src/gui/res/lang/gui_ur.ts
index 9b36dcf..c378089 100644
--- a/src/gui/res/lang/gui_ur.ts
+++ b/src/gui/res/lang/gui_ur.ts
@@ -648,12 +648,17 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
+ <source>All files (*.*)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
+ <source>Barrier Configurations (*.conf)</source>
<translation type="unfinished"></translation>
</message>
<message>
diff --git a/src/gui/res/lang/gui_vi.ts b/src/gui/res/lang/gui_vi.ts
index a3c6025..16d013a 100644
--- a/src/gui/res/lang/gui_vi.ts
+++ b/src/gui/res/lang/gui_vi.ts
@@ -648,12 +648,17 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
+ <source>All files (*.*)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
+ <source>Barrier Configurations (*.conf)</source>
<translation type="unfinished"></translation>
</message>
<message>
diff --git a/src/gui/res/lang/gui_zh-CN.qm b/src/gui/res/lang/gui_zh-CN.qm
index f11d0b5..21c874e 100644
--- a/src/gui/res/lang/gui_zh-CN.qm
+++ b/src/gui/res/lang/gui_zh-CN.qm
Binary files differ
diff --git a/src/gui/res/lang/gui_zh-CN.ts b/src/gui/res/lang/gui_zh-CN.ts
index 0c8522a..d7a331c 100644
--- a/src/gui/res/lang/gui_zh-CN.ts
+++ b/src/gui/res/lang/gui_zh-CN.ts
@@ -1,1411 +1,1323 @@
-<?xml version="1.0" encoding="utf-8"?><!DOCTYPE TS><TS language="zh-CN" sourcelanguage="en" version="2.0">
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="zh_CN" sourcelanguage="en">
<context>
<name>AboutDialogBase</name>
<message>
- <location filename="res/AboutDialogBase.ui" line="38"/>
+ <location filename="../../src/AboutDialogBase.ui" line="38"/>
<source>About Barrier</source>
- <translation type="finished">关于Barrier</translation>
+ <translation>关于 Barrier</translation>
</message>
- <message utf8="true">
- <location filename="res/AboutDialogBase.ui" line="53"/>
+ <message>
+ <location filename="../../src/AboutDialogBase.ui" line="140"/>
+ <location filename="../../src/AboutDialogBase.ui" line="174"/>
+ <source>Unknown</source>
+ <translation>未知</translation>
+ </message>
+ <message>
+ <location filename="../../src/AboutDialogBase.ui" line="124"/>
+ <source>Version:</source>
+ <translation>版本:</translation>
+ </message>
+ <message>
+ <location filename="../../src/AboutDialogBase.ui" line="194"/>
+ <source>&amp;Ok</source>
+ <translation>确定(&amp;O)</translation>
+ </message>
+ <message>
+ <location filename="../../src/AboutDialogBase.ui" line="53"/>
<source>&lt;p&gt;
Keyboard and mouse sharing application. Cross platform and open source.&lt;br /&gt;&lt;br /&gt;
+Copyright © 2018 Debauchee Open Source Group&lt;br /&gt;
Copyright © 2012-2016 Symless Ltd.&lt;br /&gt;
Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.&lt;br /&gt;&lt;br /&gt;
Barrier is released under the GNU General Public License (GPLv2).&lt;br /&gt;&lt;br /&gt;
Barrier is based on CosmoSynergy by Richard Lee and Adam Feder.&lt;br /&gt;
-The Barrier GUI is based on QSynergy by Volker Lanz.&lt;br /&gt;&lt;br /&gt;
-Visit our website for help and info (symless.com).
+The Barrier GUI is based on QSynergy by Volker Lanz.
&lt;/p&gt;</source>
- <oldsource>&lt;p&gt;
-Keyboard and mouse sharing application. Cross platform and open source.&lt;br /&gt;&lt;br /&gt;
+ <translation>&lt;p&gt;
+共享键盘和鼠标,跨平台并开源。&lt;br /&gt;&lt;br /&gt;
+Copyright © 2018 Debauchee Open Source Group&lt;br /&gt;
Copyright © 2012-2016 Symless Ltd.&lt;br /&gt;
Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.&lt;br /&gt;&lt;br /&gt;
-Barrier is released under the GNU General Public License (GPLv2).&lt;br /&gt;&lt;br /&gt;
-Barrier is based on CosmoSynergy by Richard Lee and Adam Feder.&lt;br /&gt;
-The Barrier GUI is based on QSynergy by Volker Lanz.&lt;br /&gt;&lt;br /&gt;
-Visit our website for help and info (symless.com).
-&lt;/p&gt;</oldsource>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="res/AboutDialogBase.ui" line="140"/>
- <source>Unknown</source>
- <translation type="finished">未知</translation>
- </message>
- <message>
- <location filename="res/AboutDialogBase.ui" line="124"/>
- <source>Version:</source>
- <translation type="finished">版本:</translation>
+Barrier 适用 GNU 通用公共许可证(GPLv2)。&lt;br /&gt;&lt;br /&gt;
+Barrier 基于 Richard Lee 和 Adam Feder 制作的 CosmoSynergy .&lt;br /&gt;
+Barrier GUI 基于 Volker Lanz 制作的 QSynergy.
+&lt;/p&gt;</translation>
</message>
<message>
- <location filename="res/AboutDialogBase.ui" line="163"/>
- <source>&amp;Ok</source>
- <translation type="finished">确定</translation>
+ <location filename="../../src/AboutDialogBase.ui" line="167"/>
+ <source>Build Date: </source>
+ <translation>日期:</translation>
</message>
</context>
<context>
<name>ActionDialogBase</name>
<message>
- <location filename="res/ActionDialogBase.ui" line="14"/>
+ <location filename="../../src/ActionDialogBase.ui" line="14"/>
<source>Configure Action</source>
- <translation type="finished">行为配置</translation>
+ <translation>配置动作</translation>
</message>
<message>
- <location filename="res/ActionDialogBase.ui" line="20"/>
+ <location filename="../../src/ActionDialogBase.ui" line="20"/>
<source>Choose the action to perform</source>
- <translation type="finished">选择要执行的行为</translation>
+ <translation>选择要执行的动作</translation>
</message>
<message>
- <location filename="res/ActionDialogBase.ui" line="26"/>
+ <location filename="../../src/ActionDialogBase.ui" line="26"/>
<source>Press a hotkey</source>
- <translation type="finished">按下热键</translation>
+ <translation>按下热键</translation>
</message>
<message>
- <location filename="res/ActionDialogBase.ui" line="36"/>
+ <location filename="../../src/ActionDialogBase.ui" line="36"/>
<source>Release a hotkey</source>
- <translation type="finished">松开热键</translation>
+ <translation>松开热键</translation>
</message>
<message>
- <location filename="res/ActionDialogBase.ui" line="43"/>
+ <location filename="../../src/ActionDialogBase.ui" line="43"/>
<source>Press and release a hotkey</source>
- <translation type="finished">按下一个键然后松开</translation>
+ <translation>单击热键</translation>
</message>
<message>
- <location filename="res/ActionDialogBase.ui" line="69"/>
+ <location filename="../../src/ActionDialogBase.ui" line="69"/>
<source>only on these screens</source>
- <translation type="finished">仅仅在这些屏幕上</translation>
+ <translation>仅在这些屏幕上</translation>
</message>
<message>
- <location filename="res/ActionDialogBase.ui" line="119"/>
+ <location filename="../../src/ActionDialogBase.ui" line="119"/>
<source>Switch to screen</source>
- <translation type="finished">切换到屏幕</translation>
+ <translation>切换到屏幕</translation>
</message>
<message>
- <location filename="res/ActionDialogBase.ui" line="150"/>
+ <location filename="../../src/ActionDialogBase.ui" line="161"/>
<source>Switch in direction</source>
- <translation type="finished">方向切换</translation>
+ <translation>切换方向</translation>
</message>
<message>
- <location filename="res/ActionDialogBase.ui" line="174"/>
+ <location filename="../../src/ActionDialogBase.ui" line="185"/>
<source>left</source>
- <translation type="finished">左</translation>
+ <translation>左</translation>
</message>
<message>
- <location filename="res/ActionDialogBase.ui" line="179"/>
+ <location filename="../../src/ActionDialogBase.ui" line="190"/>
<source>right</source>
- <translation type="finished">右侧</translation>
+ <translation>右侧</translation>
</message>
<message>
- <location filename="res/ActionDialogBase.ui" line="184"/>
+ <location filename="../../src/ActionDialogBase.ui" line="195"/>
<source>up</source>
- <translation type="finished">上方</translation>
+ <translation>上方</translation>
</message>
<message>
- <location filename="res/ActionDialogBase.ui" line="189"/>
+ <location filename="../../src/ActionDialogBase.ui" line="200"/>
<source>down</source>
- <translation type="finished">下方</translation>
+ <translation>下方</translation>
</message>
<message>
- <location filename="res/ActionDialogBase.ui" line="201"/>
+ <location filename="../../src/ActionDialogBase.ui" line="212"/>
<source>Lock cursor to screen</source>
- <translation type="finished">锁定指针于屏幕</translation>
+ <translation>锁定指针于屏幕</translation>
</message>
<message>
- <location filename="res/ActionDialogBase.ui" line="225"/>
+ <location filename="../../src/ActionDialogBase.ui" line="236"/>
<source>toggle</source>
- <translation type="finished">切换</translation>
+ <translation>切换</translation>
</message>
<message>
- <location filename="res/ActionDialogBase.ui" line="230"/>
+ <location filename="../../src/ActionDialogBase.ui" line="241"/>
<source>on</source>
- <translation type="finished">启用</translation>
+ <translation>启用</translation>
</message>
<message>
- <location filename="res/ActionDialogBase.ui" line="235"/>
+ <location filename="../../src/ActionDialogBase.ui" line="246"/>
<source>off</source>
- <translation type="finished">禁用</translation>
+ <translation>禁用</translation>
</message>
<message>
- <location filename="res/ActionDialogBase.ui" line="248"/>
+ <location filename="../../src/ActionDialogBase.ui" line="259"/>
<source>This action is performed when</source>
- <translation type="finished">当……时启用此行为</translation>
+ <translation>当……时启用此动作</translation>
</message>
<message>
- <location filename="res/ActionDialogBase.ui" line="254"/>
+ <location filename="../../src/ActionDialogBase.ui" line="265"/>
<source>the hotkey is pressed</source>
- <translation type="finished">热键被按下</translation>
+ <translation>热键被按下</translation>
</message>
<message>
- <location filename="res/ActionDialogBase.ui" line="264"/>
+ <location filename="../../src/ActionDialogBase.ui" line="275"/>
<source>the hotkey is released</source>
- <translation type="finished">热键被松开</translation>
+ <translation>热键被松开</translation>
+ </message>
+ <message>
+ <location filename="../../src/ActionDialogBase.ui" line="150"/>
+ <source>Toggle screen</source>
+ <translation>切换屏幕</translation>
</message>
</context>
<context>
<name>AddClientDialog</name>
<message>
- <location filename="res/AddClientDialogBase.ui" line="20"/>
+ <location filename="../../src/AddClientDialogBase.ui" line="20"/>
<source>Dialog</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="res/AddClientDialogBase.ui" line="35"/>
+ <location filename="../../src/AddClientDialogBase.ui" line="35"/>
<source>TextLabel</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="res/AddClientDialogBase.ui" line="83"/>
+ <location filename="../../src/AddClientDialogBase.ui" line="83"/>
<source>Ignore auto connect clients</source>
- <translation type="unfinished"></translation>
+ <translation>忽略自动连接的客户端</translation>
</message>
</context>
<context>
<name>HotkeyDialogBase</name>
<message>
- <location filename="res/HotkeyDialogBase.ui" line="14"/>
+ <location filename="../../src/HotkeyDialogBase.ui" line="14"/>
<source>Hotkey</source>
- <translation type="finished">热键</translation>
+ <translation>热键</translation>
</message>
<message>
- <location filename="res/HotkeyDialogBase.ui" line="20"/>
+ <location filename="../../src/HotkeyDialogBase.ui" line="20"/>
<source>Enter the specification for the hotkey:</source>
- <translation type="finished">输入热键的说明:</translation>
+ <translation>指定热键:</translation>
</message>
</context>
<context>
- <name>MainWindow</name>
+ <name>LogWindowBase</name>
<message>
- <location filename="src/MainWindow.cpp" line="790"/>
- <source>&amp;Start</source>
- <translation type="finished">开始</translation>
+ <location filename="../../src/LogWindowBase.ui" line="26"/>
+ <source>Log - Barrier</source>
+ <translation>日志 - Barrier</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="237"/>
- <source>&amp;File</source>
- <translation type="finished">文件</translation>
+ <location filename="../../src/LogWindowBase.ui" line="71"/>
+ <source>&amp;Clear Log</source>
+ <translation>清空(&amp;C)</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="238"/>
- <source>&amp;Edit</source>
- <translation type="finished">编辑</translation>
+ <location filename="../../src/LogWindowBase.ui" line="78"/>
+ <source>&amp;Hide</source>
+ <translation>隐藏(&amp;H)</translation>
</message>
+</context>
+<context>
+ <name>MainWindow</name>
<message>
- <location filename="src/MainWindow.cpp" line="239"/>
- <source>&amp;Window</source>
- <translation type="finished">窗口</translation>
+ <location filename="../../src/MainWindow.cpp" line="790"/>
+ <source>&amp;Start</source>
+ <translation>开始(&amp;S)</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="240"/>
+ <location filename="../../src/MainWindow.cpp" line="245"/>
<source>&amp;Help</source>
- <translation type="finished">帮助</translation>
- </message>
- <message>
- <location filename="src/MainWindow.cpp" line="364"/>
- <source>&lt;p&gt;Your version of Barrier is out of date. Version &lt;b&gt;%1&lt;/b&gt; is now available to &lt;a href=&quot;%2&quot;&gt;download&lt;/a&gt;.&lt;/p&gt;</source>
- <oldsource>&lt;p&gt;Version %1 is now available, &lt;a href=&quot;%2&quot;&gt;visit website&lt;/a&gt;.&lt;/p&gt;</oldsource>
- <translation type="finished">&lt;p&gt;您正在使用的Barrier版本有些过时了,有新版 &lt;b&gt;%1&lt;/b&gt; 可以 &lt;a href=&quot;%2&quot;&gt;下载&lt;/a&gt;。&lt;/p&gt;</translation>
+ <translation>帮助(&amp;S)</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="577"/>
+ <location filename="../../src/MainWindow.cpp" line="564"/>
<source>Program can not be started</source>
- <translation type="finished">程序无法启动</translation>
+ <translation>程序无法启动</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="577"/>
+ <location filename="../../src/MainWindow.cpp" line="564"/>
<source>The executable&lt;br&gt;&lt;br&gt;%1&lt;br&gt;&lt;br&gt;could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program.</source>
- <translation type="finished">可执行程序&lt;br&gt;&lt;br&gt;%1&lt;br&gt;&lt;br&gt;没有成功运行,虽然程序本身存在。请检查你是否有运行此程序的权限。</translation>
+ <translation>可执行程序&lt;br&gt;&lt;br&gt;%1&lt;br&gt;&lt;br&gt;没有成功运行,虽然程序本身存在。请检查你是否有运行此程序的权限。</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="596"/>
+ <location filename="../../src/MainWindow.cpp" line="583"/>
<source>Barrier client not found</source>
- <translation type="finished">未找到Barrier客户端</translation>
+ <translation>未找到Barrier客户端</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="597"/>
+ <location filename="../../src/MainWindow.cpp" line="584"/>
<source>The executable for the barrier client does not exist.</source>
- <translation type="finished">Barrier客户端的可执行程序不存在。</translation>
+ <translation>Barrier客户端的可执行程序不存在。</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="625"/>
+ <location filename="../../src/MainWindow.cpp" line="610"/>
<source>Hostname is empty</source>
- <translation type="finished">主机名为空</translation>
+ <translation>主机名为空</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="626"/>
+ <location filename="../../src/MainWindow.cpp" line="611"/>
<source>Please fill in a hostname for the barrier client to connect to.</source>
- <translation type="finished">请为Barrier客户端设置一个用于连接的主机名</translation>
+ <translation>请为Barrier客户端设置一个用于连接的主机名。</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="646"/>
+ <location filename="../../src/MainWindow.cpp" line="631"/>
<source>Cannot write configuration file</source>
- <translation type="finished">不能写入配置文件</translation>
+ <translation>不能写入配置文件</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="646"/>
+ <location filename="../../src/MainWindow.cpp" line="631"/>
<source>The temporary configuration file required to start barrier can not be written.</source>
- <translation type="finished">启动Barrier所需的临时配置文件不可写。</translation>
+ <translation>启动Barrier所需的临时配置文件不可写。</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="659"/>
+ <location filename="../../src/MainWindow.cpp" line="644"/>
<source>Configuration filename invalid</source>
- <translation type="finished">配置文件名非法</translation>
+ <translation>无效配置文件名</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="660"/>
+ <location filename="../../src/MainWindow.cpp" line="645"/>
<source>You have not filled in a valid configuration file for the barrier server. Do you want to browse for the configuration file now?</source>
- <translation type="finished">你没有为Barrier服务端设置一个可用的配置文件。需要现在浏览配置文件吗?</translation>
+ <translation>Barrier服务端缺少有效的配置文件。需要现在浏览配置文件吗?</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="688"/>
+ <location filename="../../src/MainWindow.cpp" line="675"/>
<source>Barrier server not found</source>
- <translation type="finished">未找到Barrier服务端</translation>
+ <translation>未找到Barrier服务端</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="689"/>
+ <location filename="../../src/MainWindow.cpp" line="676"/>
<source>The executable for the barrier server does not exist.</source>
- <translation type="finished">Barrier服务端可执行程序不存在。</translation>
- </message>
- <message>
- <location filename="src/MainWindow.cpp" line="764"/>
- <source>Barrier terminated with an error</source>
- <translation type="finished">Barrier因错终止运行</translation>
- </message>
- <message>
- <location filename="src/MainWindow.cpp" line="764"/>
- <source>Barrier terminated unexpectedly with an exit code of %1.&lt;br&gt;&lt;br&gt;Please see the log output for details.</source>
- <translation type="finished">Barrier意外终止运行,退出代码 %1。&lt;br&gt;&lt;br&gt;请查看输出日志了解详情。</translation>
+ <translation>Barrier服务端可执行程序不存在。</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="783"/>
+ <location filename="../../src/MainWindow.cpp" line="783"/>
<source>&amp;Stop</source>
- <translation type="finished">停止</translation>
+ <translation>停止(&amp;S)</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="1038"/>
+ <location filename="../../src/MainWindow.cpp" line="1036"/>
<source>Please add the server (%1) to the grid.</source>
- <translation type="unfinished"></translation>
+ <translation>请添加服务端(%1)到网格。</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="1044"/>
+ <location filename="../../src/MainWindow.cpp" line="1042"/>
<source>Please drag the new client screen (%1) to the desired position on the grid.</source>
- <translation type="unfinished"></translation>
+ <translation>请将新屏幕(%1)拖动到网格中的合适位置。</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="1147"/>
+ <location filename="../../src/MainWindow.cpp" line="1135"/>
<source>Failed to detect system architecture.</source>
- <translation type="unfinished"></translation>
+ <translation>检测系统架构失败</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="1165"/>
+ <location filename="../../src/MainWindow.cpp" line="1153"/>
<source>Cancel</source>
- <translation type="unfinished"></translation>
+ <translation>取消</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="1189"/>
+ <location filename="../../src/MainWindow.cpp" line="1181"/>
<source>Failed to download Bonjour installer to location: %1</source>
- <translation type="unfinished"></translation>
+ <translation>无法下载Bonjou安装包至 %1</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="1226"/>
+ <location filename="../../src/MainWindow.cpp" line="1218"/>
<source>Do you want to enable auto config and install Bonjour?
This feature helps you establish the connection.</source>
- <translation type="unfinished"></translation>
+ <translation>是否开启自动配置并下载Bonjour?
+
+此功能帮助你建立连接。</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="1270"/>
+ <location filename="../../src/MainWindow.cpp" line="1248"/>
<source>Auto config feature requires Bonjour.
Do you want to install Bonjour?</source>
- <translation type="unfinished"></translation>
+ <translation>自动配置需要Bonjour
+
+是否安装Bonjour?</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="815"/>
+ <location filename="../../src/MainWindow.cpp" line="818"/>
<source>Barrier is starting.</source>
- <translation type="finished">Barrier正在启动</translation>
+ <translation>Barrier正在启动</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="809"/>
+ <location filename="../../src/MainWindow.cpp" line="812"/>
<source>Barrier is running.</source>
- <translation type="finished">Barrier正在运行</translation>
+ <translation>Barrier正在运行</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="819"/>
+ <location filename="../../src/MainWindow.cpp" line="822"/>
<source>Barrier is not running.</source>
- <translation type="finished">Barrier没有运行</translation>
+ <translation>Barrier没有运行</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="870"/>
+ <location filename="../../src/MainWindow.cpp" line="878"/>
<source>Unknown</source>
- <translation type="finished">未知</translation>
+ <translation>未知</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="1146"/>
- <location filename="src/MainWindow.cpp" line="1225"/>
- <location filename="src/MainWindow.cpp" line="1269"/>
+ <location filename="../../src/MainWindow.cpp" line="1134"/>
+ <location filename="../../src/MainWindow.cpp" line="1217"/>
+ <location filename="../../src/MainWindow.cpp" line="1247"/>
<source>Barrier</source>
- <translation type="finished">Barrier</translation>
+ <translation>Barrier</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="987"/>
+ <location filename="../../src/MainWindow.cpp" line="993"/>
<source>Browse for a barriers config file</source>
- <translation type="finished">浏览Barrier配置文件</translation>
+ <translation>浏览Barrier配置文件</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="408"/>
- <source>Barrier is now connected, You can close the config window. Barrier will remain connected in the background.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="src/MainWindow.cpp" line="434"/>
+ <location filename="../../src/MainWindow.cpp" line="432"/>
<source>Security question</source>
- <translation type="unfinished"></translation>
+ <translation>安全确认</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="435"/>
+ <location filename="../../src/MainWindow.cpp" line="433"/>
<source>Do you trust this fingerprint?
%1
-This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user).
+This is a server fingerprint. You should compare this fingerprint to the one on your server&apos;s screen. If the two don&apos;t match exactly, then it&apos;s probably not the server you&apos;re expecting (it could be a malicious user).
To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No.</source>
- <translation type="unfinished"></translation>
+ <translation>是否信任此指纹?
+
+%1
+
+这是服务端的指纹,请将其与你服务端屏幕的指纹进行对比。如果两者不一致,你可能没有连接到预期的服务端,或是遇到了恶意攻击。
+
+点击确认以自动信任此指纹在未来的连接,点击停止来中断连接。</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="1000"/>
+ <location filename="../../src/MainWindow.cpp" line="1006"/>
<source>Save configuration as...</source>
- <translation type="finished">保存配置到文件</translation>
+ <translation>保存配置到文件</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="1004"/>
+ <location filename="../../src/MainWindow.cpp" line="1010"/>
<source>Save failed</source>
- <translation type="finished">保存失败</translation>
+ <translation>保存失败</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="1004"/>
+ <location filename="../../src/MainWindow.cpp" line="1010"/>
<source>Could not save configuration to file.</source>
- <translation type="finished">不能保存配置到文件</translation>
+ <translation>无法保存配置到文件</translation>
+ </message>
+ <message>
+ <location filename="../../src/MainWindow.cpp" line="244"/>
+ <source>&amp;Barrier</source>
+ <translation>&amp;Barrier</translation>
+ </message>
+ <message>
+ <location filename="../../src/MainWindow.cpp" line="402"/>
+ <source>Barrier is now connected. You can close the config window and Barrier will remain connected in the background.</source>
+ <translation>Barrier已连接。现在可以关闭窗口,Barrier会在后台保持连接。</translation>
</message>
</context>
<context>
<name>MainWindowBase</name>
<message>
- <location filename="res/MainWindowBase.ui" line="26"/>
+ <location filename="../../src/MainWindowBase.ui" line="26"/>
<source>Barrier</source>
- <translation type="finished">Barrier</translation>
+ <translation>Barrier</translation>
</message>
<message>
- <location filename="res/MainWindowBase.ui" line="90"/>
- <source>Ser&amp;ver (share this computer's mouse and keyboard):</source>
- <translation type="unfinished"></translation>
+ <location filename="../../src/MainWindowBase.ui" line="39"/>
+ <source>Ser&amp;ver (share this computer&apos;s mouse and keyboard):</source>
+ <translation>服务端 - 共享此电脑的鼠标和键盘</translation>
</message>
<message>
- <location filename="res/MainWindowBase.ui" line="243"/>
+ <location filename="../../src/MainWindowBase.ui" line="192"/>
<source>Screen name:</source>
- <translation type="finished">屏幕名:</translation>
+ <translation>屏幕名:</translation>
</message>
<message>
- <location filename="res/MainWindowBase.ui" line="257"/>
+ <location filename="../../src/MainWindowBase.ui" line="206"/>
<source>&amp;Server IP:</source>
- <translation type="finished">服务端IP</translation>
+ <translation>服务端IP:</translation>
</message>
<message>
- <location filename="res/MainWindowBase.ui" line="380"/>
- <location filename="res/MainWindowBase.ui" line="409"/>
+ <location filename="../../src/MainWindowBase.ui" line="293"/>
+ <location filename="../../src/MainWindowBase.ui" line="322"/>
<source>&amp;Start</source>
- <translation type="finished">开始</translation>
+ <translation>开始(&amp;S)</translation>
</message>
<message>
- <location filename="res/MainWindowBase.ui" line="181"/>
+ <location filename="../../src/MainWindowBase.ui" line="130"/>
<source>Use existing configuration:</source>
- <translation type="finished">使用已有的配置:</translation>
+ <translation>使用已有的配置:</translation>
</message>
<message>
- <location filename="res/MainWindowBase.ui" line="190"/>
+ <location filename="../../src/MainWindowBase.ui" line="139"/>
<source>&amp;Configuration file:</source>
- <translation type="finished">配置文件:</translation>
+ <translation>配置文件:</translation>
</message>
<message>
- <location filename="res/MainWindowBase.ui" line="210"/>
+ <location filename="../../src/MainWindowBase.ui" line="159"/>
<source>&amp;Browse...</source>
- <translation type="finished">浏览…</translation>
+ <translation>浏览(&amp;B)…</translation>
</message>
<message>
- <location filename="res/MainWindowBase.ui" line="147"/>
+ <location filename="../../src/MainWindowBase.ui" line="96"/>
<source>Configure interactively:</source>
- <translation type="finished">交互配置:</translation>
+ <translation>交互配置:</translation>
</message>
<message>
- <location filename="res/MainWindowBase.ui" line="159"/>
+ <location filename="../../src/MainWindowBase.ui" line="108"/>
<source>&amp;Configure Server...</source>
- <translation type="finished">设置服务端…</translation>
+ <translation>设置服务端(&amp;C)…</translation>
</message>
<message>
- <location filename="res/MainWindowBase.ui" line="350"/>
+ <location filename="../../src/MainWindowBase.ui" line="263"/>
<source>Ready</source>
- <translation type="finished">准备完毕</translation>
- </message>
- <message>
- <location filename="res/MainWindowBase.ui" line="296"/>
- <source>Log</source>
- <translation type="finished">日志</translation>
+ <translation>准备完毕</translation>
</message>
<message>
- <location filename="res/MainWindowBase.ui" line="373"/>
+ <location filename="../../src/MainWindowBase.ui" line="286"/>
<source>&amp;Reload</source>
- <translation type="finished">应用</translation>
+ <translation>应用(&amp;R)</translation>
</message>
<message>
- <location filename="res/MainWindowBase.ui" line="107"/>
+ <location filename="../../src/MainWindowBase.ui" line="56"/>
<source>IP addresses:</source>
- <translation type="finished">IP地址</translation>
+ <translation>IP地址:</translation>
</message>
<message>
- <location filename="res/MainWindowBase.ui" line="131"/>
- <source>Fingerprint:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="res/MainWindowBase.ui" line="228"/>
- <source>&amp;Client (use another computer's mouse and keyboard):</source>
- <translation type="unfinished"></translation>
+ <location filename="../../src/MainWindowBase.ui" line="177"/>
+ <source>&amp;Client (use another computer&apos;s mouse and keyboard):</source>
+ <translation>客户端 - 使用另一电脑的鼠标和键盘</translation>
</message>
<message>
- <location filename="res/MainWindowBase.ui" line="270"/>
+ <location filename="../../src/MainWindowBase.ui" line="219"/>
<source>Auto config</source>
- <translation type="unfinished"></translation>
+ <translation>自动配置</translation>
</message>
<message>
- <location filename="res/MainWindowBase.ui" line="390"/>
+ <location filename="../../src/MainWindowBase.ui" line="303"/>
<source>&amp;About Barrier...</source>
- <translation type="finished">关于Barrier…</translation>
+ <translation>关于Barrier(&amp;A)…</translation>
</message>
<message>
- <location filename="res/MainWindowBase.ui" line="398"/>
+ <location filename="../../src/MainWindowBase.ui" line="311"/>
<source>&amp;Quit</source>
- <translation type="finished">退出</translation>
+ <translation>退出(&amp;Q)</translation>
</message>
<message>
- <location filename="res/MainWindowBase.ui" line="401"/>
+ <location filename="../../src/MainWindowBase.ui" line="314"/>
<source>Quit</source>
- <translation type="finished">退出</translation>
+ <translation>退出</translation>
</message>
<message>
- <location filename="res/MainWindowBase.ui" line="412"/>
+ <location filename="../../src/MainWindowBase.ui" line="325"/>
<source>Run</source>
- <translation type="finished">运行</translation>
+ <translation>运行</translation>
</message>
<message>
- <location filename="res/MainWindowBase.ui" line="423"/>
+ <location filename="../../src/MainWindowBase.ui" line="336"/>
<source>S&amp;top</source>
- <translation type="finished">停止</translation>
+ <translation>停止(&amp;t)</translation>
</message>
<message>
- <location filename="res/MainWindowBase.ui" line="426"/>
+ <location filename="../../src/MainWindowBase.ui" line="339"/>
<source>Stop</source>
- <translation type="finished">停止</translation>
- </message>
- <message>
- <location filename="res/MainWindowBase.ui" line="434"/>
- <source>S&amp;how Status</source>
- <translation type="finished">显示状态</translation>
+ <translation>停止</translation>
</message>
<message>
- <location filename="res/MainWindowBase.ui" line="442"/>
+ <location filename="../../src/MainWindowBase.ui" line="347"/>
<source>&amp;Hide</source>
- <translation type="finished">隐藏</translation>
+ <translation>隐藏(&amp;H)</translation>
</message>
<message>
- <location filename="res/MainWindowBase.ui" line="445"/>
+ <location filename="../../src/MainWindowBase.ui" line="350"/>
<source>Hide</source>
- <translation type="finished">隐藏</translation>
+ <translation>隐藏</translation>
</message>
<message>
- <location filename="res/MainWindowBase.ui" line="453"/>
+ <location filename="../../src/MainWindowBase.ui" line="358"/>
<source>&amp;Show</source>
- <translation type="finished">显示</translation>
+ <translation>显示(&amp;S)</translation>
</message>
<message>
- <location filename="res/MainWindowBase.ui" line="456"/>
+ <location filename="../../src/MainWindowBase.ui" line="361"/>
<source>Show</source>
- <translation type="finished">显示</translation>
+ <translation>显示</translation>
</message>
<message>
- <location filename="res/MainWindowBase.ui" line="464"/>
- <source>Save configuration &amp;as...</source>
- <translation type="finished">保存配置到…</translation>
- </message>
- <message>
- <location filename="res/MainWindowBase.ui" line="467"/>
+ <location filename="../../src/MainWindowBase.ui" line="372"/>
<source>Save the interactively generated server configuration to a file.</source>
- <translation type="finished">保存通过交互配置生成的配置到文件。</translation>
- </message>
- <message>
- <location filename="res/MainWindowBase.ui" line="475"/>
- <source>Settings</source>
- <translation type="finished">设置</translation>
+ <translation>保存交互生成的配置到文件。</translation>
</message>
<message>
- <location filename="res/MainWindowBase.ui" line="478"/>
+ <location filename="../../src/MainWindowBase.ui" line="383"/>
<source>Edit settings</source>
- <translation type="finished">编辑设置</translation>
+ <translation>编辑设置</translation>
</message>
<message>
- <location filename="res/MainWindowBase.ui" line="486"/>
- <source>Run Wizard</source>
- <translation type="finished">运行向导</translation>
+ <location filename="../../src/MainWindowBase.ui" line="80"/>
+ <source>SSL Fingerprint:</source>
+ <translation>SSL指纹:</translation>
</message>
-</context>
-<context>
- <name>NewScreenWidget</name>
<message>
- <location filename="src/NewScreenWidget.cpp" line="32"/>
- <source>Unnamed</source>
- <translation type="finished">未命名</translation>
+ <location filename="../../src/MainWindowBase.ui" line="369"/>
+ <source>S&amp;ave configuration</source>
+ <translation>保存配置(&amp;a)</translation>
</message>
-</context>
-<context>
- <name>PluginManager</name>
<message>
- <location filename="src/PluginManager.cpp" line="58"/>
- <source>Failed to get plugin directory.</source>
- <translation type="unfinished"></translation>
+ <location filename="../../src/MainWindowBase.ui" line="380"/>
+ <source>Change &amp;Settings</source>
+ <translation>更改设置(&amp;S)</translation>
</message>
<message>
- <location filename="src/PluginManager.cpp" line="63"/>
- <source>Failed to get profile directory.</source>
- <translation type="unfinished"></translation>
+ <location filename="../../src/MainWindowBase.ui" line="391"/>
+ <source>Show &amp;Log</source>
+ <translation>显示日志(&amp;L)</translation>
</message>
<message>
- <location filename="src/PluginManager.cpp" line="136"/>
- <source>Failed to download plugin '%1' to: %2
-%3</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="src/PluginManager.cpp" line="167"/>
- <source>Could not get Windows architecture type.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="src/PluginManager.cpp" line="191"/>
- <source>Could not get Linux architecture type.</source>
- <translation type="unfinished"></translation>
+ <location filename="../../src/MainWindowBase.ui" line="394"/>
+ <source>Show Log</source>
+ <translation>显示日志</translation>
</message>
</context>
<context>
- <name>PluginWizardPage</name>
- <message>
- <location filename="res/PluginWizardPageBase.ui" line="14"/>
- <source>Setup Barrier</source>
- <translation type="finished">设置Barrier</translation>
- </message>
- <message>
- <location filename="res/PluginWizardPageBase.ui" line="101"/>
- <source>Please wait...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="src/PluginWizardPage.cpp" line="72"/>
- <source>Error: %1</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="src/PluginWizardPage.cpp" line="80"/>
- <location filename="src/PluginWizardPage.cpp" line="201"/>
- <source>Setup complete.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="src/PluginWizardPage.cpp" line="93"/>
- <source>Downloading '%1' plugin (%2/%3)...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="src/PluginWizardPage.cpp" line="104"/>
- <source>Plugins installed successfully.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="src/PluginWizardPage.cpp" line="120"/>
- <source>Generating SSL certificate...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="src/PluginWizardPage.cpp" line="170"/>
- <source>Downloading plugin: %1 (1/%2)</source>
- <translation type="unfinished"></translation>
- </message>
+ <name>NewScreenWidget</name>
<message>
- <location filename="src/PluginWizardPage.cpp" line="239"/>
- <source>Getting plugin list...</source>
- <translation type="unfinished"></translation>
+ <location filename="../../src/NewScreenWidget.cpp" line="32"/>
+ <source>Unnamed</source>
+ <translation>未命名</translation>
</message>
</context>
<context>
<name>QObject</name>
<message>
- <location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
- <translation type="finished">Barrier配置文件(*.sgc);;所有文件 (*.*)</translation>
+ <location filename="../../src/MainWindow.cpp" line="55"/>
+ <source>All files (*.*)</source>
+ <translation>所有文件 (*.*)</translation>
</message>
<message>
- <location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
- <translation type="finished">Barrier配置文件(*.conf);;所有文件 (*.*)</translation>
+ <location filename="../../src/MainWindow.cpp" line="58"/>
+ <source>Barrier Configurations (*.sgc)</source>
+ <translation>Barrier配置文件 (*.sgc)</translation>
</message>
<message>
- <location filename="src/main.cpp" line="119"/>
- <source>System tray is unavailable, quitting.</source>
- <translation type="finished">系统托盘不可用,程序退出。</translation>
+ <location filename="../../src/MainWindow.cpp" line="65"/>
+ <source>Barrier Configurations (*.conf)</source>
+ <translation>Barrier配置文件 (*.conf)</translation>
</message>
</context>
<context>
<name>ScreenSettingsDialog</name>
<message>
- <location filename="src/ScreenSettingsDialog.cpp" line="67"/>
+ <location filename="../../src/ScreenSettingsDialog.cpp" line="79"/>
<source>Screen name is empty</source>
- <translation type="finished">屏幕名为空</translation>
+ <translation>屏幕名为空</translation>
</message>
<message>
- <location filename="src/ScreenSettingsDialog.cpp" line="68"/>
+ <location filename="../../src/ScreenSettingsDialog.cpp" line="80"/>
<source>The screen name cannot be empty. Please either fill in a name or cancel the dialog.</source>
- <translation type="finished">屏幕名不能为空。请填入一个名字或者关闭对话框。</translation>
+ <translation>屏幕名不能为空。请填入一个名字或者关闭对话框。</translation>
</message>
<message>
- <location filename="src/ScreenSettingsDialog.cpp" line="83"/>
+ <location filename="../../src/ScreenSettingsDialog.cpp" line="95"/>
<source>Screen name matches alias</source>
- <translation type="finished">屏幕名对应别名</translation>
+ <translation>屏幕名对应别名</translation>
</message>
<message>
- <location filename="src/ScreenSettingsDialog.cpp" line="84"/>
+ <location filename="../../src/ScreenSettingsDialog.cpp" line="96"/>
<source>The screen name cannot be the same as an alias. Please either remove the alias or change the screen name.</source>
- <translation type="finished">屏幕名不能与别名相同,请取消或者更改别名。</translation>
+ <translation>屏幕名不能与别名相同,请取消或者更改别名。</translation>
</message>
</context>
<context>
<name>ScreenSettingsDialogBase</name>
<message>
- <location filename="res/ScreenSettingsDialogBase.ui" line="14"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="14"/>
<source>Screen Settings</source>
- <translation type="finished">屏幕设置</translation>
+ <translation>屏幕设置</translation>
</message>
<message>
- <location filename="res/ScreenSettingsDialogBase.ui" line="22"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="22"/>
<source>Screen &amp;name:</source>
- <translation type="finished">屏幕名:</translation>
+ <translation>屏幕名:</translation>
</message>
<message>
- <location filename="res/ScreenSettingsDialogBase.ui" line="42"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="42"/>
<source>A&amp;liases</source>
- <translation type="finished">别名</translation>
+ <translation>别名</translation>
</message>
<message>
- <location filename="res/ScreenSettingsDialogBase.ui" line="57"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="57"/>
<source>&amp;Add</source>
- <translation type="finished">添加</translation>
+ <translation>添加(&amp;A)</translation>
</message>
<message>
- <location filename="res/ScreenSettingsDialogBase.ui" line="74"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="74"/>
<source>&amp;Remove</source>
- <translation type="finished">删除</translation>
+ <translation>删除(&amp;R)</translation>
</message>
<message>
- <location filename="res/ScreenSettingsDialogBase.ui" line="97"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="97"/>
<source>&amp;Modifier keys</source>
- <translation type="finished">修改按键</translation>
+ <translation>修改按键</translation>
</message>
<message>
- <location filename="res/ScreenSettingsDialogBase.ui" line="106"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="106"/>
<source>&amp;Shift:</source>
- <translation type="finished">Shift:</translation>
+ <translation>Shift:</translation>
</message>
<message>
- <location filename="res/ScreenSettingsDialogBase.ui" line="117"/>
- <location filename="res/ScreenSettingsDialogBase.ui" line="164"/>
- <location filename="res/ScreenSettingsDialogBase.ui" line="211"/>
- <location filename="res/ScreenSettingsDialogBase.ui" line="258"/>
- <location filename="res/ScreenSettingsDialogBase.ui" line="305"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="117"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="164"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="211"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="258"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="305"/>
<source>Shift</source>
- <translation type="finished">Shift</translation>
+ <translation>Shift</translation>
</message>
<message>
- <location filename="res/ScreenSettingsDialogBase.ui" line="122"/>
- <location filename="res/ScreenSettingsDialogBase.ui" line="169"/>
- <location filename="res/ScreenSettingsDialogBase.ui" line="216"/>
- <location filename="res/ScreenSettingsDialogBase.ui" line="263"/>
- <location filename="res/ScreenSettingsDialogBase.ui" line="310"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="122"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="169"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="216"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="263"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="310"/>
<source>Ctrl</source>
- <translation type="finished">Ctrl</translation>
+ <translation>Ctrl</translation>
</message>
<message>
- <location filename="res/ScreenSettingsDialogBase.ui" line="127"/>
- <location filename="res/ScreenSettingsDialogBase.ui" line="174"/>
- <location filename="res/ScreenSettingsDialogBase.ui" line="221"/>
- <location filename="res/ScreenSettingsDialogBase.ui" line="268"/>
- <location filename="res/ScreenSettingsDialogBase.ui" line="315"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="127"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="174"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="221"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="268"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="315"/>
<source>Alt</source>
- <translation type="finished">Alt</translation>
+ <translation>Alt</translation>
</message>
<message>
- <location filename="res/ScreenSettingsDialogBase.ui" line="132"/>
- <location filename="res/ScreenSettingsDialogBase.ui" line="179"/>
- <location filename="res/ScreenSettingsDialogBase.ui" line="226"/>
- <location filename="res/ScreenSettingsDialogBase.ui" line="273"/>
- <location filename="res/ScreenSettingsDialogBase.ui" line="320"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="132"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="179"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="226"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="273"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="320"/>
<source>Meta</source>
- <translation type="finished">Meta</translation>
+ <translation>Meta</translation>
</message>
<message>
- <location filename="res/ScreenSettingsDialogBase.ui" line="137"/>
- <location filename="res/ScreenSettingsDialogBase.ui" line="184"/>
- <location filename="res/ScreenSettingsDialogBase.ui" line="231"/>
- <location filename="res/ScreenSettingsDialogBase.ui" line="278"/>
- <location filename="res/ScreenSettingsDialogBase.ui" line="325"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="137"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="184"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="231"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="278"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="325"/>
<source>Super</source>
- <translation type="finished">超级</translation>
+ <translation>超级</translation>
</message>
<message>
- <location filename="res/ScreenSettingsDialogBase.ui" line="142"/>
- <location filename="res/ScreenSettingsDialogBase.ui" line="189"/>
- <location filename="res/ScreenSettingsDialogBase.ui" line="236"/>
- <location filename="res/ScreenSettingsDialogBase.ui" line="283"/>
- <location filename="res/ScreenSettingsDialogBase.ui" line="330"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="142"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="189"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="236"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="283"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="330"/>
<source>None</source>
- <translation type="finished">无</translation>
+ <translation>无</translation>
</message>
<message>
- <location filename="res/ScreenSettingsDialogBase.ui" line="150"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="150"/>
<source>&amp;Ctrl:</source>
- <translation type="finished">Ctrl:</translation>
+ <translation>&amp;Ctrl:</translation>
</message>
<message>
- <location filename="res/ScreenSettingsDialogBase.ui" line="197"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="197"/>
<source>Al&amp;t:</source>
- <translation type="finished">Alt:</translation>
+ <translation>Al&amp;t:</translation>
</message>
<message>
- <location filename="res/ScreenSettingsDialogBase.ui" line="244"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="244"/>
<source>M&amp;eta:</source>
- <translation type="finished">Meta:</translation>
+ <translation>M&amp;eta:</translation>
</message>
<message>
- <location filename="res/ScreenSettingsDialogBase.ui" line="291"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="291"/>
<source>S&amp;uper:</source>
- <translation type="finished">Super:</translation>
+ <translation>S&amp;uper:</translation>
</message>
<message>
- <location filename="res/ScreenSettingsDialogBase.ui" line="358"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="358"/>
<source>&amp;Dead corners</source>
- <translation type="finished">死角</translation>
+ <translation>死角</translation>
</message>
<message>
- <location filename="res/ScreenSettingsDialogBase.ui" line="367"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="367"/>
<source>Top-left</source>
- <translation type="finished">左上角</translation>
+ <translation>左上角</translation>
</message>
<message>
- <location filename="res/ScreenSettingsDialogBase.ui" line="374"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="374"/>
<source>Top-right</source>
- <translation type="finished">右上角</translation>
+ <translation>右上角</translation>
</message>
<message>
- <location filename="res/ScreenSettingsDialogBase.ui" line="381"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="381"/>
<source>Bottom-left</source>
- <translation type="finished">左下角</translation>
+ <translation>左下角</translation>
</message>
<message>
- <location filename="res/ScreenSettingsDialogBase.ui" line="388"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="388"/>
<source>Bottom-right</source>
- <translation type="finished">右下角</translation>
+ <translation>右下角</translation>
</message>
<message>
- <location filename="res/ScreenSettingsDialogBase.ui" line="397"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="397"/>
<source>Corner Si&amp;ze:</source>
- <translation type="finished">死角大小</translation>
+ <translation>死角大小</translation>
</message>
<message>
- <location filename="res/ScreenSettingsDialogBase.ui" line="428"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="428"/>
<source>&amp;Fixes</source>
- <translation type="finished">修改</translation>
+ <translation>修改</translation>
</message>
<message>
- <location filename="res/ScreenSettingsDialogBase.ui" line="437"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="437"/>
<source>Fix CAPS LOCK key</source>
- <translation type="finished">修复caps lock键</translation>
+ <translation>修复caps lock键</translation>
</message>
<message>
- <location filename="res/ScreenSettingsDialogBase.ui" line="444"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="444"/>
<source>Fix NUM LOCK key</source>
- <translation type="finished">修复num lock键</translation>
+ <translation>修复num lock键</translation>
</message>
<message>
- <location filename="res/ScreenSettingsDialogBase.ui" line="451"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="451"/>
<source>Fix SCROLL LOCK key</source>
- <translation type="finished">修复scroll lock键</translation>
+ <translation>修复scroll lock键</translation>
</message>
<message>
- <location filename="res/ScreenSettingsDialogBase.ui" line="458"/>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="458"/>
<source>Fix XTest for Xinerama</source>
- <translation type="finished">修复Xinerama的XTest</translation>
+ <translation>修复Xinerama的XTest</translation>
+ </message>
+ <message>
+ <location filename="../../src/ScreenSettingsDialogBase.ui" line="468"/>
+ <source>Fix Preserve Focus</source>
+ <translation>修复焦点</translation>
</message>
</context>
<context>
<name>ScreenSetupModel</name>
<message>
- <location filename="src/ScreenSetupModel.cpp" line="51"/>
+ <location filename="../../src/ScreenSetupModel.cpp" line="51"/>
<source>&lt;center&gt;Screen: &lt;b&gt;%1&lt;/b&gt;&lt;/center&gt;&lt;br&gt;Double click to edit settings&lt;br&gt;Drag screen to the trashcan to remove it</source>
- <translation type="finished">&lt;center&gt;屏幕设置: &lt;b&gt;%1&lt;/b&gt;&lt;/center&gt;&lt;br&gt;双击以修改设置&lt;br&gt;将屏幕拖到废纸篓来移除</translation>
+ <translation>&lt;center&gt;屏幕设置: &lt;b&gt;%1&lt;/b&gt;&lt;/center&gt;&lt;br&gt;双击以修改设置&lt;br&gt;将屏幕拖到废纸篓来移除</translation>
+ </message>
+</context>
+<context>
+ <name>ScreenSetupView</name>
+ <message>
+ <location filename="../../src/ScreenSetupView.cpp" line="75"/>
+ <source>Unnamed</source>
+ <translation>未命名</translation>
</message>
</context>
<context>
<name>ServerConfigDialog</name>
<message>
- <location filename="src/ServerConfigDialog.cpp" line="75"/>
+ <location filename="../../src/ServerConfigDialog.cpp" line="80"/>
<source>Configure server</source>
- <translation type="unfinished"></translation>
+ <translation>设置服务端</translation>
</message>
</context>
<context>
<name>ServerConfigDialogBase</name>
<message>
- <location filename="res/ServerConfigDialogBase.ui" line="14"/>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="14"/>
<source>Server Configuration</source>
- <translation type="finished">服务端配置</translation>
+ <translation>服务端配置</translation>
</message>
<message>
- <location filename="res/ServerConfigDialogBase.ui" line="24"/>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="24"/>
<source>Screens and links</source>
- <translation type="finished">屏幕和联接</translation>
+ <translation>屏幕和联接</translation>
</message>
<message>
- <location filename="res/ServerConfigDialogBase.ui" line="35"/>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="35"/>
<source>Drag a screen from the grid to the trashcan to remove it.</source>
- <translation type="finished">从格子中拖动屏幕到垃圾桶进行删除。</translation>
+ <translation>从网格中拖动屏幕到垃圾桶进行删除。</translation>
</message>
<message>
- <location filename="res/ServerConfigDialogBase.ui" line="60"/>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="60"/>
<source>Configure the layout of your barrier server configuration.</source>
- <translation type="finished">设置Barrier服务端配置的屏幕布局。</translation>
+ <translation>配置Barrier服务端的屏幕布局。</translation>
</message>
<message>
- <location filename="res/ServerConfigDialogBase.ui" line="73"/>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="73"/>
<source>Drag this button to the grid to add a new screen.</source>
- <translation type="finished">拖动此按钮到格子中进行添加屏幕。</translation>
+ <translation>拖动此按钮到网格以添加屏幕。</translation>
</message>
<message>
- <location filename="res/ServerConfigDialogBase.ui" line="128"/>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="128"/>
<source>Drag new screens to the grid or move existing ones around.
Drag a screen to the trashcan to delete it.
Double click on a screen to edit its settings.</source>
- <translation type="finished">拖动屏幕(图标)到网格中或者移动已经在网格中的屏幕的位置。
+ <translation>拖动屏幕图标到网格,或者移动已经在网格中的屏幕。
拖动屏幕到垃圾桶进行删除。
双击屏幕编辑其设置。</translation>
</message>
<message>
- <location filename="res/ServerConfigDialogBase.ui" line="157"/>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="157"/>
<source>Hotkeys</source>
- <translation type="finished">热键</translation>
+ <translation>热键</translation>
</message>
<message>
- <location filename="res/ServerConfigDialogBase.ui" line="163"/>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="163"/>
<source>&amp;Hotkeys</source>
- <translation type="finished">热键</translation>
+ <translation>热键(&amp;H)</translation>
</message>
<message>
- <location filename="res/ServerConfigDialogBase.ui" line="175"/>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="175"/>
<source>&amp;New</source>
- <translation type="finished">新建</translation>
+ <translation>新建(&amp;N)</translation>
</message>
<message>
- <location filename="res/ServerConfigDialogBase.ui" line="185"/>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="185"/>
<source>&amp;Edit</source>
- <translation type="finished">编辑</translation>
+ <translation>编辑(&amp;E)</translation>
</message>
<message>
- <location filename="res/ServerConfigDialogBase.ui" line="195"/>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="195"/>
<source>&amp;Remove</source>
- <translation type="finished">删除</translation>
+ <translation>删除(&amp;R)</translation>
</message>
<message>
- <location filename="res/ServerConfigDialogBase.ui" line="218"/>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="218"/>
<source>A&amp;ctions</source>
- <translation type="finished">行为</translation>
+ <translation>动作</translation>
</message>
<message>
- <location filename="res/ServerConfigDialogBase.ui" line="230"/>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="230"/>
<source>Ne&amp;w</source>
- <translation type="finished">新建</translation>
+ <translation>新建(&amp;w)</translation>
</message>
<message>
- <location filename="res/ServerConfigDialogBase.ui" line="240"/>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="240"/>
<source>E&amp;dit</source>
- <translation type="finished">编辑</translation>
+ <translation>编辑(&amp;d)</translation>
</message>
<message>
- <location filename="res/ServerConfigDialogBase.ui" line="250"/>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="250"/>
<source>Re&amp;move</source>
- <translation type="finished">删除</translation>
+ <translation>删除(&amp;m)</translation>
</message>
<message>
- <location filename="res/ServerConfigDialogBase.ui" line="274"/>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="274"/>
<source>Advanced server settings</source>
- <translation type="finished">服务端高级设置</translation>
+ <translation>服务端高级设置</translation>
</message>
<message>
- <location filename="res/ServerConfigDialogBase.ui" line="280"/>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="280"/>
<source>&amp;Switch</source>
- <translation type="finished">切换</translation>
+ <translation>触边切换</translation>
</message>
<message>
- <location filename="res/ServerConfigDialogBase.ui" line="291"/>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="291"/>
<source>Switch &amp;after waiting</source>
- <translation type="finished">等待后切换</translation>
+ <translation>延时</translation>
</message>
<message>
- <location filename="res/ServerConfigDialogBase.ui" line="330"/>
- <location filename="res/ServerConfigDialogBase.ui" line="383"/>
- <location filename="res/ServerConfigDialogBase.ui" line="458"/>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="330"/>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="385"/>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="502"/>
<source>ms</source>
- <translation type="finished">毫秒</translation>
+ <translation>毫秒</translation>
</message>
<message>
- <location filename="res/ServerConfigDialogBase.ui" line="344"/>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="346"/>
<source>Switch on double &amp;tap within</source>
- <translation type="finished">双击tap切换</translation>
+ <translation>二次触边</translation>
</message>
<message>
- <location filename="res/ServerConfigDialogBase.ui" line="408"/>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="422"/>
<source>&amp;Options</source>
- <translation type="finished">选项</translation>
+ <translation>选项</translation>
</message>
<message>
- <location filename="res/ServerConfigDialogBase.ui" line="419"/>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="463"/>
<source>&amp;Check clients every</source>
- <translation type="finished">客户端检查周期</translation>
+ <translation>客户端检查周期</translation>
</message>
<message>
- <location filename="res/ServerConfigDialogBase.ui" line="470"/>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="441"/>
<source>Use &amp;relative mouse moves</source>
- <translation type="finished">使用相关的鼠标动作</translation>
+ <translation>使用相对的鼠标动作</translation>
</message>
<message>
- <location filename="res/ServerConfigDialogBase.ui" line="480"/>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="451"/>
<source>S&amp;ynchronize screen savers</source>
- <translation type="finished">同步屏幕保护</translation>
+ <translation>同步屏幕保护</translation>
</message>
<message>
- <location filename="res/ServerConfigDialogBase.ui" line="490"/>
- <source>Don't take &amp;foreground window on Windows servers</source>
- <translation type="finished">不要移动前台窗口在Windows服务器上</translation>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="431"/>
+ <source>Don&apos;t take &amp;foreground window on Windows servers</source>
+ <translation>不要在Windows服务端获取前台窗口</translation>
</message>
<message>
- <location filename="res/ServerConfigDialogBase.ui" line="510"/>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="531"/>
<source>Ignore auto config clients</source>
- <translation type="unfinished"></translation>
+ <translation>忽略自动配置的客户端</translation>
</message>
<message>
- <location filename="res/ServerConfigDialogBase.ui" line="520"/>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="551"/>
<source>&amp;Dead corners</source>
- <translation type="finished">死角</translation>
+ <translation>死角</translation>
</message>
<message>
- <location filename="res/ServerConfigDialogBase.ui" line="529"/>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="560"/>
<source>To&amp;p-left</source>
- <translation type="finished">左上角</translation>
+ <translation>左上角</translation>
</message>
<message>
- <location filename="res/ServerConfigDialogBase.ui" line="536"/>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="567"/>
<source>Top-rig&amp;ht</source>
- <translation type="finished">右上角</translation>
+ <translation>右上角</translation>
</message>
<message>
- <location filename="res/ServerConfigDialogBase.ui" line="543"/>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="574"/>
<source>&amp;Bottom-left</source>
- <translation type="finished">左下角</translation>
+ <translation>左下角</translation>
</message>
<message>
- <location filename="res/ServerConfigDialogBase.ui" line="550"/>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="581"/>
<source>Bottom-ri&amp;ght</source>
- <translation type="finished">右下角</translation>
+ <translation>右下角</translation>
</message>
<message>
- <location filename="res/ServerConfigDialogBase.ui" line="572"/>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="603"/>
<source>Cor&amp;ner Size:</source>
- <translation type="finished">死角大小</translation>
+ <translation>死角大小</translation>
</message>
-</context>
-<context>
- <name>SettingsDialog</name>
<message>
- <location filename="src/SettingsDialog.cpp" line="131"/>
- <source>Save log file to...</source>
- <translation type="finished">保存日志文件…</translation>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="394"/>
+ <source>Bump against the screen edge with the mouse pointer twice in quick succession.</source>
+ <translation>要触发二次触边,快速并连续地滑动指针到屏幕边缘。</translation>
</message>
<message>
- <location filename="src/SettingsDialog.cpp" line="151"/>
- <source>Elevate Barrier</source>
- <translation type="finished">评价Barrier</translation>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="524"/>
+ <source>Enable drag and drop file transfers</source>
+ <translation>启用拖放文件传输</translation>
</message>
<message>
- <location filename="src/SettingsDialog.cpp" line="152"/>
- <source>Are you sure you want to elevate Barrier?
-
-This allows Barrier to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Barrier only if you really need to.</source>
- <translation type="finished">您确定要elevate Barrier吗?
-这会允许Barrier和elevated进程交互和UAC对话框,但是可能引起一切和非elevated进程交互的问题。只有在你需要的时候才Elevate Barrier。</translation>
+ <location filename="../../src/ServerConfigDialogBase.ui" line="538"/>
+ <source>Enable clipboard sharing</source>
+ <translation>启用剪切板共享</translation>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <location filename="../../src/SettingsDialog.cpp" line="125"/>
+ <source>Save log file to...</source>
+ <translation>保存日志文件…</translation>
</message>
</context>
<context>
<name>SettingsDialogBase</name>
<message>
- <location filename="res/SettingsDialogBase.ui" line="14"/>
+ <location filename="../../src/SettingsDialogBase.ui" line="14"/>
<source>Settings</source>
- <translation type="finished">设置</translation>
+ <translation>设置</translation>
</message>
<message>
- <location filename="res/SettingsDialogBase.ui" line="32"/>
+ <location filename="../../src/SettingsDialogBase.ui" line="69"/>
<source>Sc&amp;reen name:</source>
- <translation type="finished">屏幕名称:</translation>
+ <translation>屏幕名称:</translation>
</message>
<message>
- <location filename="res/SettingsDialogBase.ui" line="49"/>
+ <location filename="../../src/SettingsDialogBase.ui" line="148"/>
<source>P&amp;ort:</source>
- <translation type="finished">端口:</translation>
- </message>
- <message>
- <location filename="res/SettingsDialogBase.ui" line="78"/>
- <source>&amp;Interface:</source>
- <translation type="finished">界面</translation>
+ <translation>端口:</translation>
</message>
<message>
- <location filename="res/SettingsDialogBase.ui" line="120"/>
- <source>Elevate mode</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="res/SettingsDialogBase.ui" line="127"/>
+ <location filename="../../src/SettingsDialogBase.ui" line="125"/>
<source>&amp;Hide on startup</source>
- <translation type="unfinished"></translation>
+ <translation>最小化启动</translation>
</message>
<message>
- <location filename="res/SettingsDialogBase.ui" line="146"/>
- <source>&amp;Network Security</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="res/SettingsDialogBase.ui" line="155"/>
- <source>Use &amp;SSL encryption (unique certificate)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="res/SettingsDialogBase.ui" line="184"/>
+ <location filename="../../src/SettingsDialogBase.ui" line="210"/>
<source>Logging</source>
- <translation type="finished">日志记录</translation>
+ <translation>日志</translation>
</message>
<message>
- <location filename="res/SettingsDialogBase.ui" line="202"/>
+ <location filename="../../src/SettingsDialogBase.ui" line="228"/>
<source>&amp;Logging level:</source>
- <translation type="finished">日志等级</translation>
+ <translation>日志等级</translation>
</message>
<message>
- <location filename="res/SettingsDialogBase.ui" line="251"/>
+ <location filename="../../src/SettingsDialogBase.ui" line="277"/>
<source>Log to file:</source>
- <translation type="finished">记录到文件</translation>
+ <translation>记录到文件</translation>
</message>
<message>
- <location filename="res/SettingsDialogBase.ui" line="268"/>
+ <location filename="../../src/SettingsDialogBase.ui" line="294"/>
<source>Browse...</source>
- <translation type="finished">浏览…</translation>
+ <translation>浏览…</translation>
</message>
<message>
- <location filename="res/SettingsDialogBase.ui" line="213"/>
+ <location filename="../../src/SettingsDialogBase.ui" line="239"/>
<source>Error</source>
- <translation type="finished">错误</translation>
+ <translation>错误</translation>
</message>
<message>
- <location filename="res/SettingsDialogBase.ui" line="107"/>
+ <location filename="../../src/SettingsDialogBase.ui" line="50"/>
<source>&amp;Language:</source>
- <translation type="finished">语言:</translation>
- </message>
- <message>
- <location filename="res/SettingsDialogBase.ui" line="20"/>
- <source>&amp;Miscellaneous</source>
- <translation type="finished">其他</translation>
+ <translation>语言:</translation>
</message>
<message>
- <location filename="res/SettingsDialogBase.ui" line="218"/>
+ <location filename="../../src/SettingsDialogBase.ui" line="244"/>
<source>Warning</source>
- <translation type="finished">警告</translation>
+ <translation>警告</translation>
</message>
<message>
- <location filename="res/SettingsDialogBase.ui" line="223"/>
+ <location filename="../../src/SettingsDialogBase.ui" line="249"/>
<source>Note</source>
- <translation type="finished">注意</translation>
+ <translation>注意</translation>
</message>
<message>
- <location filename="res/SettingsDialogBase.ui" line="228"/>
+ <location filename="../../src/SettingsDialogBase.ui" line="254"/>
<source>Info</source>
- <translation type="finished">信息</translation>
+ <translation>信息</translation>
</message>
<message>
- <location filename="res/SettingsDialogBase.ui" line="233"/>
+ <location filename="../../src/SettingsDialogBase.ui" line="259"/>
<source>Debug</source>
- <translation type="finished">调试</translation>
+ <translation>调试</translation>
</message>
<message>
- <location filename="res/SettingsDialogBase.ui" line="238"/>
+ <location filename="../../src/SettingsDialogBase.ui" line="264"/>
<source>Debug1</source>
- <translation type="finished">调试1</translation>
+ <translation>调试1</translation>
</message>
<message>
- <location filename="res/SettingsDialogBase.ui" line="243"/>
+ <location filename="../../src/SettingsDialogBase.ui" line="269"/>
<source>Debug2</source>
- <translation type="finished">调试2</translation>
+ <translation>调试2</translation>
</message>
-</context>
-<context>
- <name>SetupWizard</name>
<message>
- <location filename="src/SetupWizard.cpp" line="72"/>
- <source>Setup Barrier</source>
- <translation type="finished">设置Barrier</translation>
+ <location filename="../../src/SettingsDialogBase.ui" line="29"/>
+ <source>General</source>
+ <translation>通用</translation>
</message>
<message>
- <location filename="src/SetupWizard.cpp" line="113"/>
- <source>Please select an option.</source>
- <translation type="finished">请选择一个选项</translation>
+ <location filename="../../src/SettingsDialogBase.ui" line="86"/>
+ <source>Elevate</source>
+ <translation>提权</translation>
</message>
<message>
- <location filename="src/SetupWizard.cpp" line="80"/>
- <source>Please enter your email address and password.</source>
- <translation type="finished">请输入您的邮箱地址和密码。</translation>
+ <location filename="../../src/SettingsDialogBase.ui" line="93"/>
+ <source>Specify when the Barrier service should run at an elevated privilege level</source>
+ <translation>设置Barrier服务何时应该提权运行</translation>
</message>
-</context>
-<context>
- <name>SetupWizardBase</name>
<message>
- <location filename="res/SetupWizardBase.ui" line="26"/>
- <source>Setup Barrier</source>
- <translation type="finished">设置Barrier</translation>
+ <location filename="../../src/SettingsDialogBase.ui" line="100"/>
+ <source>As Needed</source>
+ <translation>按需</translation>
</message>
<message>
- <location filename="res/SetupWizardBase.ui" line="30"/>
- <source>Welcome</source>
- <translation type="finished">欢迎</translation>
+ <location filename="../../src/SettingsDialogBase.ui" line="105"/>
+ <source>Always</source>
+ <translation>总是</translation>
</message>
<message>
- <location filename="res/SetupWizardBase.ui" line="39"/>
- <source>Thanks for installing Barrier!</source>
- <translation type="finished">感谢您安装Barrier!</translation>
+ <location filename="../../src/SettingsDialogBase.ui" line="110"/>
+ <source>Never</source>
+ <translation>从不</translation>
</message>
<message>
- <location filename="res/SetupWizardBase.ui" line="114"/>
- <source>Barrier lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Barrier is cross-platform (works on Windows, Mac OS X and Linux).</source>
- <translation type="finished">Barrier允许你轻松地在你办公桌上多台计算机之间共享你的鼠标和键盘,它免费并且开放源代码。你只要将鼠标(指针)从一台计算机的屏幕边缘移出到另一个屏幕就行了。甚至可以共享你的剪贴板。你所需要的仅仅是一个网络连接。Barrier是跨平台的(可以运行于Windows,Mac OS X和Linux)。</translation>
+ <location filename="../../src/SettingsDialogBase.ui" line="118"/>
+ <source>Minimize to System &amp;Tray</source>
+ <translation>最小化到系统托盘</translation>
</message>
<message>
- <location filename="res/SetupWizardBase.ui" line="125"/>
- <source>Activate</source>
- <translation type="unfinished"></translation>
+ <location filename="../../src/SettingsDialogBase.ui" line="132"/>
+ <source>Start &amp;Barrier on startup</source>
+ <translation>自动启动</translation>
</message>
<message>
- <location filename="res/SetupWizardBase.ui" line="131"/>
- <source>&amp;Activate now...</source>
- <translation type="unfinished"></translation>
+ <location filename="../../src/SettingsDialogBase.ui" line="142"/>
+ <source>Networking</source>
+ <translation>网络</translation>
</message>
<message>
- <location filename="res/SetupWizardBase.ui" line="152"/>
- <source>Email:</source>
- <translation type="unfinished"></translation>
+ <location filename="../../src/SettingsDialogBase.ui" line="177"/>
+ <source>&amp;Address:</source>
+ <translation>地址:</translation>
</message>
<message>
- <location filename="res/SetupWizardBase.ui" line="178"/>
- <source>Password:</source>
- <translation type="unfinished"></translation>
+ <location filename="../../src/SettingsDialogBase.ui" line="194"/>
+ <source>Enable &amp;SSL</source>
+ <translation>开启SSL</translation>
</message>
+</context>
+<context>
+ <name>SetupWizard</name>
<message>
- <location filename="res/SetupWizardBase.ui" line="204"/>
- <source>&lt;a href=&quot;https://symless.com/account/reset/&quot;&gt;Forgot password&lt;/a&gt;</source>
- <translation type="unfinished"></translation>
+ <location filename="../../src/SetupWizard.cpp" line="63"/>
+ <source>Setup Barrier</source>
+ <translation>设置Barrier</translation>
</message>
<message>
- <location filename="res/SetupWizardBase.ui" line="232"/>
- <source>&amp;Skip activation</source>
- <translation type="unfinished"></translation>
+ <location filename="../../src/SetupWizard.cpp" line="73"/>
+ <source>Please select an option.</source>
+ <translation>请选择一个选项</translation>
+ </message>
+</context>
+<context>
+ <name>SetupWizardBase</name>
+ <message>
+ <location filename="../../src/SetupWizardBase.ui" line="26"/>
+ <source>Setup Barrier</source>
+ <translation>设置Barrier</translation>
</message>
<message>
- <location filename="res/SetupWizardBase.ui" line="277"/>
- <source>&amp;Server (share this computer's mouse and keyboard)</source>
- <translation type="unfinished"></translation>
+ <location filename="../../src/SetupWizardBase.ui" line="30"/>
+ <source>Welcome</source>
+ <translation>欢迎</translation>
+ </message>
+ <message>
+ <location filename="../../src/SetupWizardBase.ui" line="39"/>
+ <source>Thanks for installing Barrier!</source>
+ <translation>感谢您安装Barrier!</translation>
</message>
<message>
- <location filename="res/SetupWizardBase.ui" line="290"/>
+ <location filename="../../src/SetupWizardBase.ui" line="114"/>
+ <source>Barrier lets you easily share your mouse and keyboard between multiple computers on your desk, and it&apos;s Free and Open Source. Just move your mouse off the edge of one computer&apos;s screen on to another. You can even share all of your clipboards. All you need is a network connection. Barrier is cross-platform (works on Windows, Mac OS X and Linux).</source>
+ <translation>Barrier可以在多台计算机间轻松共享你的鼠标和键盘,它还是自由开源软件。将鼠标指针从计算机的屏幕边缘移出到另一个屏幕,并同时共享剪贴板,只要你有一个网络连接。Barrier是跨平台的(可以运行于Windows,Mac OS X和Linux)。</translation>
+ </message>
+ <message>
+ <location filename="../../src/SetupWizardBase.ui" line="146"/>
+ <source>&amp;Server (share this computer&apos;s mouse and keyboard)</source>
+ <translation>服务端 - 共享此电脑的鼠标和键盘</translation>
+ </message>
+ <message>
+ <location filename="../../src/SetupWizardBase.ui" line="159"/>
<source>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
-&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
- <translation type="unfinished"></translation>
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer&apos;s screen. There can only be one server in your setup.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;这台电脑连接了鼠标和键盘,需要共享给其他电脑。一套配置只能有一个服务端。&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
- <location filename="res/SetupWizardBase.ui" line="326"/>
- <source>&amp;Client (use another computer's mouse and keyboard)</source>
- <translation type="unfinished"></translation>
+ <location filename="../../src/SetupWizardBase.ui" line="195"/>
+ <source>&amp;Client (use another computer&apos;s mouse and keyboard)</source>
+ <translation>客户端 - 使用另一电脑的鼠标和键盘</translation>
</message>
<message>
- <location filename="res/SetupWizardBase.ui" line="339"/>
+ <location filename="../../src/SetupWizardBase.ui" line="208"/>
<source>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
-&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
- <translation type="unfinished"></translation>
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;You have already set up a server. This computer will be controlled using the server&apos;s mouse and keyboard. There can be many clients in your setup.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;已经配置了服务端,此电脑将由服务端的鼠标和键盘进行控制。可以配置多个客户端。&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
- <location filename="res/SetupWizardBase.ui" line="262"/>
+ <location filename="../../src/SetupWizardBase.ui" line="131"/>
<source>Server or Client?</source>
- <translation type="finished">(此计算机作为)服务端还是客户端?</translation>
+ <translation>服务端还是客户端?</translation>
</message>
</context>
<context>
<name>SslCertificate</name>
<message>
- <location filename="src/SslCertificate.cpp" line="42"/>
+ <location filename="../../src/SslCertificate.cpp" line="48"/>
<source>Failed to get profile directory.</source>
- <translation type="unfinished"></translation>
+ <translation>获取配置目录失败。</translation>
</message>
<message>
- <location filename="src/SslCertificate.cpp" line="141"/>
+ <location filename="../../src/SslCertificate.cpp" line="140"/>
<source>SSL certificate generated.</source>
- <translation type="unfinished"></translation>
+ <translation>SSL证书已生成。</translation>
</message>
<message>
- <location filename="src/SslCertificate.cpp" line="170"/>
+ <location filename="../../src/SslCertificate.cpp" line="171"/>
<source>SSL fingerprint generated.</source>
- <translation type="unfinished"></translation>
+ <translation>SSL指纹已生成。</translation>
</message>
<message>
- <location filename="src/SslCertificate.cpp" line="173"/>
+ <location filename="../../src/SslCertificate.cpp" line="174"/>
<source>Failed to find SSL fingerprint.</source>
- <translation type="unfinished"></translation>
+ <translation>无法找到SSL指纹。</translation>
</message>
-</context>
-<context>
- <name>VersionChecker</name>
<message>
- <location filename="src/VersionChecker.cpp" line="102"/>
- <source>Unknown</source>
- <translation type="finished">未知</translation>
+ <location filename="../../src/SslCertificate.cpp" line="198"/>
+ <source>Could not read from default certificate file.</source>
+ <translation>无法读取默认证书文件。</translation>
</message>
-</context>
-<context>
- <name>WebClient</name>
<message>
- <location filename="src/WebClient.cpp" line="44"/>
- <source>An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details.
-
-%1</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="src/WebClient.cpp" line="65"/>
- <source>Login failed, invalid email or password.</source>
- <translation type="finished">登录失败,邮箱地址或密码错误。</translation>
+ <location filename="../../src/SslCertificate.cpp" line="205"/>
+ <source>Error loading default certificate file to memory.</source>
+ <translation>读取默认证书文件失败。</translation>
</message>
<message>
- <location filename="src/WebClient.cpp" line="78"/>
- <source>Login failed, an error occurred.
-
-%1</source>
- <translation type="finished">登录失败,出错了。
-%1</translation>
+ <location filename="../../src/SslCertificate.cpp" line="212"/>
+ <source>Default certificate key file does not contain valid public key</source>
+ <translation>默认证书文件没有有效的公钥</translation>
</message>
<message>
- <location filename="src/WebClient.cpp" line="86"/>
- <source>Login failed, an error occurred.
-
-Server response:
-
-%1</source>
- <translation type="finished">登录失败,出错了。
-服务器回应:
-%1</translation>
+ <location filename="../../src/SslCertificate.cpp" line="220"/>
+ <source>Public key in default certificate key file is not RSA or DSA</source>
+ <translation>默认证书文件的公钥不是RSA或DSA</translation>
</message>
<message>
- <location filename="src/WebClient.cpp" line="101"/>
- <source>An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details.
-
-%1</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="src/WebClient.cpp" line="120"/>
- <source>Get plugin list failed, invalid user email or password.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="src/WebClient.cpp" line="131"/>
- <source>Get plugin list failed, an error occurred.
-
-%1</source>
- <translation type="unfinished"></translation>
+ <location filename="../../src/SslCertificate.cpp" line="230"/>
+ <source>Public key in default certificate key file is too small.</source>
+ <translation>默认证书文件位数不足。</translation>
</message>
+</context>
+<context>
+ <name>VersionChecker</name>
<message>
- <location filename="src/WebClient.cpp" line="137"/>
- <source>Get plugin list failed, an error occurred.
-
-Server response:
-
-%1</source>
- <translation type="unfinished"></translation>
+ <location filename="../../src/VersionChecker.cpp" line="110"/>
+ <source>Unknown</source>
+ <translation>未知</translation>
</message>
</context>
<context>
<name>ZeroconfService</name>
<message>
- <location filename="src/ZeroconfService.cpp" line="82"/>
+ <location filename="../../src/ZeroconfService.cpp" line="106"/>
<source>zeroconf server detected: %1</source>
- <translation type="unfinished"></translation>
+ <translation>检测到zeroconf服务端:%1</translation>
</message>
<message>
- <location filename="src/ZeroconfService.cpp" line="91"/>
+ <location filename="../../src/ZeroconfService.cpp" line="115"/>
<source>zeroconf client detected: %1</source>
- <translation type="unfinished"></translation>
+ <translation>检测到zeroconf客户端:%1</translation>
</message>
<message>
- <location filename="src/ZeroconfService.cpp" line="99"/>
- <location filename="src/ZeroconfService.cpp" line="130"/>
+ <location filename="../../src/ZeroconfService.cpp" line="123"/>
+ <location filename="../../src/ZeroconfService.cpp" line="154"/>
<source>Zero configuration service</source>
- <translation type="unfinished"></translation>
+ <translation>zeroconf服务</translation>
</message>
<message>
- <location filename="src/ZeroconfService.cpp" line="100"/>
+ <location filename="../../src/ZeroconfService.cpp" line="124"/>
<source>Error code: %1.</source>
- <translation type="unfinished"></translation>
+ <translation>错误代码:%1。</translation>
</message>
<message>
- <location filename="src/ZeroconfService.cpp" line="131"/>
+ <location filename="../../src/ZeroconfService.cpp" line="155"/>
<source>Unable to start the zeroconf: %1.</source>
- <translation type="unfinished"></translation>
+ <translation>无法启动zeroconf:%1。</translation>
</message>
<message>
- <location filename="src/ZeroconfService.cpp" line="140"/>
+ <location filename="../../src/ZeroconfService.cpp" line="164"/>
<source>Barrier</source>
- <translation type="finished">Barrier</translation>
+ <translation>Barrier</translation>
</message>
<message>
- <location filename="src/ZeroconfService.cpp" line="141"/>
+ <location filename="../../src/ZeroconfService.cpp" line="165"/>
<source>Failed to get local IP address. Please manually type in server address on your clients</source>
- <translation type="unfinished"></translation>
+ <translation>无法获取本地IP地址。请在客户端上手动输入服务端地址。</translation>
</message>
<message>
- <location filename="src/ZeroconfService.cpp" line="147"/>
- <location filename="src/ZeroconfService.cpp" line="154"/>
+ <location filename="../../src/ZeroconfService.cpp" line="171"/>
+ <location filename="../../src/ZeroconfService.cpp" line="178"/>
<source>%1</source>
- <translation type="unfinished"></translation>
+ <translation>%1</translation>
</message>
</context>
-</TS> \ No newline at end of file
+</TS>
diff --git a/src/gui/res/lang/gui_zh-TW.qm b/src/gui/res/lang/gui_zh-TW.qm
index 5cc8653..ac43686 100644
--- a/src/gui/res/lang/gui_zh-TW.qm
+++ b/src/gui/res/lang/gui_zh-TW.qm
Binary files differ
diff --git a/src/gui/res/lang/gui_zh-TW.ts b/src/gui/res/lang/gui_zh-TW.ts
index 902a444..d4d305a 100644
--- a/src/gui/res/lang/gui_zh-TW.ts
+++ b/src/gui/res/lang/gui_zh-TW.ts
@@ -648,13 +648,18 @@ To automatically trust this fingerprint for future connections, click Yes. To re
<name>QObject</name>
<message>
<location filename="src/MainWindow.cpp" line="60"/>
- <source>Barrier Configurations (*.sgc);;All files (*.*)</source>
- <translation type="finished">Barrier 設定檔 (*.sgc);;所有檔案 (*.*)</translation>
+ <source>All files (*.*)</source>
+ <translation type="finished">所有檔案 (*.*)</translation>
+ </message>
+ <message>
+ <location filename="src/MainWindow.cpp" line="60"/>
+ <source>Barrier Configurations (*.sgc)</source>
+ <translation type="finished">Barrier 設定檔 (*.sgc)</translation>
</message>
<message>
<location filename="src/MainWindow.cpp" line="67"/>
- <source>Barrier Configurations (*.conf);;All files (*.*)</source>
- <translation type="finished">Barrier 設定檔 (*.conf);;所有檔案 (*.*)</translation>
+ <source>Barrier Configurations (*.conf)</source>
+ <translation type="finished">Barrier 設定檔 (*.conf)</translation>
</message>
<message>
<location filename="src/main.cpp" line="119"/>
diff --git a/src/gui/res/win/Barrier.rc b/src/gui/res/win/Barrier.rc
index 9db2b3e..2825690 100644
--- a/src/gui/res/win/Barrier.rc
+++ b/src/gui/res/win/Barrier.rc
@@ -1 +1,112 @@
-IDI_ICON1 ICON DISCARDABLE "../icons/256x256/barrier.ico"
+// Microsoft Visual C++ generated resource script.
+//
+//#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include <winresrc.h>
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include <winresrc.h>\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION BARRIER_VERSION_MAJOR, BARRIER_VERSION_MINOR, BARRIER_VERSION_PATCH, BARRIER_BUILD_NUMBER
+ PRODUCTVERSION BARRIER_VERSION_MAJOR, BARRIER_VERSION_MINOR, BARRIER_VERSION_PATCH, BARRIER_BUILD_NUMBER
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS VOS_NT_WINDOWS32
+ FILETYPE VFT_APP
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "Debauchee Open Source Group"
+ VALUE "CompanyWeb", "https://github.com/debauchee/barrier/"
+ VALUE "FileVersion", BARRIER_VERSION
+ VALUE "LegalCopyright", "Copyright (C) 2018 Debauchee Open Source Group\nCopyright (C) 2012-2016 Symless Ltd.\nCopyright (C) 2008-2014 Nick Bolton\nCopyright (C) 2002-2014 Chris Schoeneman"
+ VALUE "ProductName", "Barrier"
+ VALUE "ProductVersion", BARRIER_VERSION
+ VALUE "OriginalFilename", "barrier.exe"
+ VALUE "FileDescription", "Open source KVM software"
+ VALUE "InternalName", "barrier"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_BARRIER ICON "../icons/256x256/barrier.ico"
+
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/src/gui/src/AboutDialog.cpp b/src/gui/src/AboutDialog.cpp
index 76ba26b..b594bee 100644
--- a/src/gui/src/AboutDialog.cpp
+++ b/src/gui/src/AboutDialog.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/gui/src/AboutDialog.h b/src/gui/src/AboutDialog.h
index 3c498b4..6fdb0a2 100644
--- a/src/gui/src/AboutDialog.h
+++ b/src/gui/src/AboutDialog.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -40,4 +40,3 @@ class AboutDialog : public QDialog, public Ui::AboutDialogBase
};
#endif
-
diff --git a/src/gui/src/Action.cpp b/src/gui/src/Action.cpp
index 909e983..f34d1e8 100644
--- a/src/gui/src/Action.cpp
+++ b/src/gui/src/Action.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -51,7 +51,7 @@ QString Action::text() const
* in the end but now argument inside. If you need a function with no
* argument, it can not have () in the end.
*/
- QString text = QString(m_ActionTypeNames[keySequence().isMouseButton() ?
+ QString text = QString(m_ActionTypeNames[m_KeySequence.isMouseButton() ?
type() + int(mouseDown) : type()]);
switch (type())
@@ -61,9 +61,9 @@ QString Action::text() const
case keystroke:
{
text += "(";
- text += keySequence().toString();
+ text += m_KeySequence.toString();
- if (!keySequence().isMouseButton())
+ if (!m_KeySequence.isMouseButton())
{
const QStringList& screens = typeScreenNames();
if (haveScreens() && !screens.isEmpty())
@@ -116,15 +116,15 @@ QString Action::text() const
void Action::loadSettings(QSettings& settings)
{
- keySequence().loadSettings(settings);
+ m_KeySequence.loadSettings(settings);
setType(settings.value("type", keyDown).toInt());
- typeScreenNames().clear();
+ m_TypeScreenNames.clear();
int numTypeScreens = settings.beginReadArray("typeScreenNames");
for (int i = 0; i < numTypeScreens; i++)
{
settings.setArrayIndex(i);
- typeScreenNames().append(settings.value("typeScreenName").toString());
+ m_TypeScreenNames.append(settings.value("typeScreenName").toString());
}
settings.endArray();
@@ -137,7 +137,7 @@ void Action::loadSettings(QSettings& settings)
void Action::saveSettings(QSettings& settings) const
{
- keySequence().saveSettings(settings);
+ m_KeySequence.saveSettings(settings);
settings.setValue("type", type());
settings.beginWriteArray("typeScreenNames");
@@ -164,4 +164,3 @@ QTextStream& operator<<(QTextStream& outStream, const Action& action)
return outStream;
}
-
diff --git a/src/gui/src/Action.h b/src/gui/src/Action.h
index b738f3b..c260bad 100644
--- a/src/gui/src/Action.h
+++ b/src/gui/src/Action.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -32,9 +32,6 @@ class QTextStream;
class Action
{
- friend class ActionDialog;
- friend QTextStream& operator<<(QTextStream& outStream, const Action& action);
-
public:
enum ActionType { keyDown, keyUp, keystroke,
switchToScreen, toggleScreen, switchInDirection,
@@ -48,25 +45,31 @@ class Action
public:
QString text() const;
const KeySequence& keySequence() const { return m_KeySequence; }
+ void setKeySequence(const KeySequence& seq) { m_KeySequence = seq; }
+
void loadSettings(QSettings& settings);
void saveSettings(QSettings& settings) const;
+
int type() const { return m_Type; }
+ void setType(int t) { m_Type = t; }
+
const QStringList& typeScreenNames() const { return m_TypeScreenNames; }
- const QString& switchScreenName() const { return m_SwitchScreenName; }
- int switchDirection() const { return m_SwitchDirection; }
- int lockCursorMode() const { return m_LockCursorMode; }
- bool activeOnRelease() const { return m_ActiveOnRelease; }
- bool haveScreens() const { return m_HasScreens; }
+ void appendTypeScreenName(QString name) { m_TypeScreenNames.append(name); }
+ void clearTypeScreenNames() { m_TypeScreenNames.clear(); }
- protected:
- KeySequence& keySequence() { return m_KeySequence; }
- void setKeySequence(const KeySequence& seq) { m_KeySequence = seq; }
- void setType(int t) { m_Type = t; }
- QStringList& typeScreenNames() { return m_TypeScreenNames; }
+ const QString& switchScreenName() const { return m_SwitchScreenName; }
void setSwitchScreenName(const QString& n) { m_SwitchScreenName = n; }
+
+ int switchDirection() const { return m_SwitchDirection; }
void setSwitchDirection(int d) { m_SwitchDirection = d; }
+
+ int lockCursorMode() const { return m_LockCursorMode; }
void setLockCursorMode(int m) { m_LockCursorMode = m; }
+
+ bool activeOnRelease() const { return m_ActiveOnRelease; }
void setActiveOnRelease(bool b) { m_ActiveOnRelease = b; }
+
+ bool haveScreens() const { return m_HasScreens; }
void setHaveScreens(bool b) { m_HasScreens = b; }
private:
@@ -84,8 +87,6 @@ class Action
static const char* m_LockCursorModeNames[];
};
-typedef QList<Action> ActionList;
-
QTextStream& operator<<(QTextStream& outStream, const Action& action);
#endif
diff --git a/src/gui/src/ActionDialog.cpp b/src/gui/src/ActionDialog.cpp
index 2796885..89a037e 100644
--- a/src/gui/src/ActionDialog.cpp
+++ b/src/gui/src/ActionDialog.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -58,7 +58,7 @@ ActionDialog::ActionDialog(QWidget* parent, ServerConfig& config, Hotkey& hotkey
m_pGroupBoxScreens->setChecked(m_Action.haveScreens());
int idx = 0;
- foreach(const Screen& screen, serverConfig().screens())
+ for (const Screen& screen : serverConfig().screens()) {
if (!screen.isNull())
{
QListWidgetItem *pListItem = new QListWidgetItem(screen.name());
@@ -72,6 +72,7 @@ ActionDialog::ActionDialog(QWidget* parent, ServerConfig& config, Hotkey& hotkey
idx++;
}
+ }
}
void ActionDialog::accept()
@@ -83,9 +84,10 @@ void ActionDialog::accept()
m_Action.setType(m_pButtonGroupType->checkedId());
m_Action.setHaveScreens(m_pGroupBoxScreens->isChecked());
- m_Action.typeScreenNames().clear();
- foreach(const QListWidgetItem* pItem, m_pListScreens->selectedItems())
- m_Action.typeScreenNames().append(pItem->text());
+ m_Action.clearTypeScreenNames();
+ for (const QListWidgetItem* pItem : m_pListScreens->selectedItems()) {
+ m_Action.appendTypeScreenName(pItem->text());
+ }
m_Action.setSwitchScreenName(m_pComboSwitchToScreen->currentText());
m_Action.setSwitchDirection(m_pComboSwitchInDirection->currentIndex());
diff --git a/src/gui/src/ActionDialog.h b/src/gui/src/ActionDialog.h
index 388be1f..ea476c5 100644
--- a/src/gui/src/ActionDialog.h
+++ b/src/gui/src/ActionDialog.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/gui/src/AppConfig.cpp b/src/gui/src/AppConfig.cpp
index 2f8779d..894ce49 100644
--- a/src/gui/src/AppConfig.cpp
+++ b/src/gui/src/AppConfig.cpp
@@ -60,6 +60,7 @@ AppConfig::AppConfig(QSettings* settings) :
m_AutoConfigPrompted(false),
m_CryptoEnabled(false),
m_AutoHide(false),
+ m_AutoStart(false),
m_MinimizeToTray(false)
{
Q_ASSERT(m_pSettings);
@@ -157,7 +158,10 @@ void AppConfig::loadSettings()
m_ElevateMode = static_cast<ElevateMode>(elevateMode.toInt());
m_AutoConfigPrompted = settings().value("autoConfigPrompted", false).toBool();
m_CryptoEnabled = settings().value("cryptoEnabled", true).toBool();
+ // TODO: set default value of requireClientCertificate to true on Barrier 2.5.0
+ m_RequireClientCertificate = settings().value("requireClientCertificate", false).toBool();
m_AutoHide = settings().value("autoHide", false).toBool();
+ m_AutoStart = settings().value("autoStart", false).toBool();
m_MinimizeToTray = settings().value("minimizeToTray", false).toBool();
}
@@ -179,7 +183,9 @@ void AppConfig::saveSettings()
settings().setValue("elevateModeEnum", static_cast<int>(m_ElevateMode));
settings().setValue("autoConfigPrompted", m_AutoConfigPrompted);
settings().setValue("cryptoEnabled", m_CryptoEnabled);
+ settings().setValue("requireClientCertificate", m_RequireClientCertificate);
settings().setValue("autoHide", m_AutoHide);
+ settings().setValue("autoStart", m_AutoStart);
settings().setValue("minimizeToTray", m_MinimizeToTray);
settings().sync();
}
@@ -208,7 +214,7 @@ void AppConfig::setElevateMode(ElevateMode em) { m_ElevateMode = em; }
void AppConfig::setAutoConfig(bool autoConfig) { m_AutoConfig = autoConfig; }
-bool AppConfig::autoConfigPrompted() { return m_AutoConfigPrompted; }
+bool AppConfig::autoConfigPrompted() { return m_AutoConfigPrompted; }
void AppConfig::setAutoConfigPrompted(bool prompted) { m_AutoConfigPrompted = prompted; }
@@ -222,10 +228,18 @@ void AppConfig::setCryptoEnabled(bool e) { m_CryptoEnabled = e; }
bool AppConfig::getCryptoEnabled() const { return m_CryptoEnabled; }
+void AppConfig::setRequireClientCertificate(bool e) { m_RequireClientCertificate = e; }
+
+bool AppConfig::getRequireClientCertificate() const { return m_RequireClientCertificate; }
+
void AppConfig::setAutoHide(bool b) { m_AutoHide = b; }
bool AppConfig::getAutoHide() { return m_AutoHide; }
+void AppConfig::setAutoStart(bool b) { m_AutoStart = b; }
+
+bool AppConfig::getAutoStart() { return m_AutoStart; }
+
void AppConfig::setMinimizeToTray(bool b) { m_MinimizeToTray = b; }
bool AppConfig::getMinimizeToTray() { return m_MinimizeToTray; }
diff --git a/src/gui/src/AppConfig.h b/src/gui/src/AppConfig.h
index c9ed38d..0dabb18 100644
--- a/src/gui/src/AppConfig.h
+++ b/src/gui/src/AppConfig.h
@@ -91,9 +91,15 @@ class AppConfig: public QObject
void setCryptoEnabled(bool e);
bool getCryptoEnabled() const;
+ void setRequireClientCertificate(bool e);
+ bool getRequireClientCertificate() const;
+
void setAutoHide(bool b);
bool getAutoHide();
+ void setAutoStart(bool b);
+ bool getAutoStart();
+
void setMinimizeToTray(bool b);
bool getMinimizeToTray();
@@ -129,7 +135,9 @@ protected:
ElevateMode m_ElevateMode;
bool m_AutoConfigPrompted;
bool m_CryptoEnabled;
+ bool m_RequireClientCertificate = false;
bool m_AutoHide;
+ bool m_AutoStart;
bool m_MinimizeToTray;
static const char m_BarriersName[];
diff --git a/src/gui/src/BaseConfig.cpp b/src/gui/src/BaseConfig.cpp
index 241f590..0f31493 100644
--- a/src/gui/src/BaseConfig.cpp
+++ b/src/gui/src/BaseConfig.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -44,4 +44,3 @@ const char* BaseConfig::m_SwitchCornerNames[] =
"bottom-left",
"bottom-right"
};
-
diff --git a/src/gui/src/BaseConfig.h b/src/gui/src/BaseConfig.h
index cf41ac6..9dc6b65 100644
--- a/src/gui/src/BaseConfig.h
+++ b/src/gui/src/BaseConfig.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/gui/src/Fingerprint.cpp b/src/gui/src/Fingerprint.cpp
deleted file mode 100644
index 24c8a1a..0000000
--- a/src/gui/src/Fingerprint.cpp
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * barrier -- mouse and keyboard sharing utility
- * Copyright (C) 2015-2016 Symless Ltd.
- *
- * This package is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * found in the file LICENSE that should have accompanied this file.
- *
- * This package is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "Fingerprint.h"
-
-#include "common/DataDirectories.h"
-
-#include <QDir>
-#include <QTextStream>
-
-static const char kDirName[] = "SSL/Fingerprints";
-static const char kLocalFilename[] = "Local.txt";
-static const char kTrustedServersFilename[] = "TrustedServers.txt";
-static const char kTrustedClientsFilename[] = "TrustedClients.txt";
-
-Fingerprint::Fingerprint(const QString& filename)
-{
- m_Filename = filename;
-}
-
-void Fingerprint::trust(const QString& fingerprintText, bool append)
-{
- Fingerprint::persistDirectory();
-
- QIODevice::OpenMode openMode;
- if (append) {
- openMode = QIODevice::Append;
- }
- else {
- openMode = QIODevice::WriteOnly;
- }
-
- QFile file(filePath());
- if (file.open(openMode))
- {
- QTextStream out(&file);
- out << fingerprintText << "\n";
- file.close();
- }
-}
-
-bool Fingerprint::fileExists() const
-{
- QString dirName = Fingerprint::directoryPath();
- if (!QDir(dirName).exists()) {
- return false;
- }
-
- QFile file(filePath());
- return file.exists();
-}
-
-bool Fingerprint::isTrusted(const QString& fingerprintText)
-{
- QStringList list = readList();
- foreach (QString trusted, list)
- {
- if (trusted == fingerprintText) {
- return true;
- }
- }
- return false;
-}
-
-QStringList Fingerprint::readList(const int readTo)
-{
- QStringList list;
-
- QString dirName = Fingerprint::directoryPath();
- if (!QDir(dirName).exists()) {
- return list;
- }
-
- QFile file(filePath());
-
- if (file.open(QIODevice::ReadOnly))
- {
- QTextStream in(&file);
- while (!in.atEnd())
- {
- list.append(in.readLine());
- if (list.size() == readTo) {
- break;
- }
- }
- file.close();
- }
-
- return list;
-}
-
-QString Fingerprint::readFirst()
-{
- QStringList list = readList(1);
- return list.at(0);
-}
-
-QString Fingerprint::filePath() const
-{
- QString dir = Fingerprint::directoryPath();
- return QString("%1/%2").arg(dir).arg(m_Filename);
-}
-
-void Fingerprint::persistDirectory()
-{
- QDir dir(Fingerprint::directoryPath());
- if (!dir.exists()) {
- dir.mkpath(".");
- }
-}
-
-QString Fingerprint::directoryPath()
-{
- auto profileDir = QString::fromStdString(DataDirectories::profile());
-
- return QString("%1/%2")
- .arg(profileDir)
- .arg(kDirName);
-}
-
-Fingerprint Fingerprint::local()
-{
- return Fingerprint(kLocalFilename);
-}
-
-Fingerprint Fingerprint::trustedServers()
-{
- return Fingerprint(kTrustedServersFilename);
-}
-
-Fingerprint Fingerprint::trustedClients()
-{
- return Fingerprint(kTrustedClientsFilename);
-}
diff --git a/src/gui/src/Fingerprint.h b/src/gui/src/Fingerprint.h
deleted file mode 100644
index 5a38d20..0000000
--- a/src/gui/src/Fingerprint.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * barrier -- mouse and keyboard sharing utility
- * Copyright (C) 2015-2016 Symless Ltd.
- *
- * This package is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * found in the file LICENSE that should have accompanied this file.
- *
- * This package is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#pragma once
-
-#include <QString>
-
-class Fingerprint
-{
-public:
- void trust(const QString& fingerprintText, bool append = true);
- bool isTrusted(const QString& fingerprintText);
- QStringList readList(const int readTo = -1);
- QString readFirst();
- QString filePath() const;
- bool fileExists() const;
-
- static Fingerprint local();
- static Fingerprint trustedServers();
- static Fingerprint trustedClients();
- static QString directoryPath();
- static void persistDirectory();
-
-private:
- Fingerprint(const QString& filename);
-
- QString m_Filename;
-};
diff --git a/src/gui/src/FingerprintAcceptDialog.cpp b/src/gui/src/FingerprintAcceptDialog.cpp
new file mode 100644
index 0000000..e0dc7e6
--- /dev/null
+++ b/src/gui/src/FingerprintAcceptDialog.cpp
@@ -0,0 +1,65 @@
+/*
+ barrier -- mouse and keyboard sharing utility
+ Copyright (C) Barrier contributors
+
+ This package is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ found in the file LICENSE that should have accompanied this file.
+
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "FingerprintAcceptDialog.h"
+#include "ui_FingerprintAcceptDialog.h"
+#include "net/SecureUtils.h"
+
+FingerprintAcceptDialog::FingerprintAcceptDialog(QWidget *parent,
+ BarrierType type,
+ const barrier::FingerprintData& fingerprint_sha1,
+ const barrier::FingerprintData& fingerprint_sha256) :
+ QDialog(parent),
+ ui_{std::make_unique<Ui::FingerprintAcceptDialog>()}
+{
+ ui_->setupUi(this);
+
+ if (type == BarrierType::Server) {
+ ui_->label_sha1->hide();
+ ui_->label_sha1_fingerprint_full->hide();
+ } else {
+ ui_->label_sha1_fingerprint_full->setText(
+ QString::fromStdString(barrier::format_ssl_fingerprint(fingerprint_sha1.data)));
+ }
+
+ ui_->label_sha256_fingerprint_full->setText(
+ QString::fromStdString(barrier::format_ssl_fingerprint_columns(fingerprint_sha256.data)));
+ ui_->label_sha256_fingerprint_randomart->setText(
+ QString::fromStdString(barrier::create_fingerprint_randomart(fingerprint_sha256.data)));
+
+ QString explanation;
+ if (type == BarrierType::Server) {
+ explanation = tr("This is a client fingerprint. You should compare this "
+ "fingerprint to the one on your client's screen. If the "
+ "two don't match exactly, then it's probably not the client "
+ "you're expecting (it could be a malicious user).\n\n"
+ "To automatically trust this fingerprint for future "
+ "connections, click Yes. To reject this fingerprint and "
+ "disconnect the client, click No.");
+ } else {
+ explanation = tr("This is a server fingerprint. You should compare this "
+ "fingerprint to the one on your server's screen. If the "
+ "two don't match exactly, then it's probably not the server "
+ "you're expecting (it could be a malicious user).\n\n"
+ "To automatically trust this fingerprint for future "
+ "connections, click Yes. To reject this fingerprint and "
+ "disconnect from the server, click No.");
+ }
+ ui_->label_explanation->setText(explanation);
+}
+
+FingerprintAcceptDialog::~FingerprintAcceptDialog() = default;
diff --git a/src/gui/src/FingerprintAcceptDialog.h b/src/gui/src/FingerprintAcceptDialog.h
new file mode 100644
index 0000000..da8884c
--- /dev/null
+++ b/src/gui/src/FingerprintAcceptDialog.h
@@ -0,0 +1,45 @@
+/*
+ barrier -- mouse and keyboard sharing utility
+ Copyright (C) Barrier contributors
+
+ This package is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ found in the file LICENSE that should have accompanied this file.
+
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef BARRIER_GUI_FINGERPRINT_ACCEPT_DIALOG_H
+#define BARRIER_GUI_FINGERPRINT_ACCEPT_DIALOG_H
+
+#include "net/FingerprintData.h"
+#include "barrier/BarrierType.h"
+#include <QDialog>
+#include <memory>
+
+namespace Ui {
+class FingerprintAcceptDialog;
+}
+
+class FingerprintAcceptDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit FingerprintAcceptDialog(QWidget* parent,
+ BarrierType type,
+ const barrier::FingerprintData& fingerprint_sha1,
+ const barrier::FingerprintData& fingerprint_sha256);
+ ~FingerprintAcceptDialog() override;
+
+private:
+ std::unique_ptr<Ui::FingerprintAcceptDialog> ui_;
+};
+
+#endif // BARRIER_GUI_FINGERPRINT_ACCEPT_DIALOG_H
diff --git a/src/gui/src/FingerprintAcceptDialog.ui b/src/gui/src/FingerprintAcceptDialog.ui
new file mode 100644
index 0000000..9c181ec
--- /dev/null
+++ b/src/gui/src/FingerprintAcceptDialog.ui
@@ -0,0 +1,174 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>FingerprintAcceptDialog</class>
+ <widget class="QDialog" name="FingerprintAcceptDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>600</width>
+ <height>400</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Ignored" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="windowTitle">
+ <string>Security question</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetFixedSize</enum>
+ </property>
+ <item row="6" column="0" colspan="2">
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::No|QDialogButtonBox::Yes</set>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" colspan="2">
+ <widget class="QLabel" name="label_sha1">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>SHA1 (deprecated, compare to old servers only)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0" colspan="2">
+ <widget class="QLabel" name="label_explanation">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ <property name="margin">
+ <number>10</number>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0" colspan="2">
+ <widget class="QLabel" name="label_sha1_fingerprint_full">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0" colspan="2">
+ <widget class="QLabel" name="label_title">
+ <property name="text">
+ <string>Do you trust this fingerprint?</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLabel" name="label_sha256_fingerprint_randomart">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <family>Courier</family>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_sha256_fingerprint_full">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" colspan="2">
+ <widget class="QLabel" name="label_sha256">
+ <property name="text">
+ <string>SHA256:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>FingerprintAcceptDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>FingerprintAcceptDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/gui/src/Hotkey.cpp b/src/gui/src/Hotkey.cpp
index c7138e7..4c008f8 100644
--- a/src/gui/src/Hotkey.cpp
+++ b/src/gui/src/Hotkey.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -28,9 +28,9 @@ Hotkey::Hotkey() :
QString Hotkey::text() const
{
- QString text = keySequence().toString();
+ QString text = m_KeySequence.toString();
- if (keySequence().isMouseButton())
+ if (m_KeySequence.isMouseButton())
return "mousebutton(" + text + ")";
return "keystroke(" + text + ")";
@@ -38,16 +38,16 @@ QString Hotkey::text() const
void Hotkey::loadSettings(QSettings& settings)
{
- keySequence().loadSettings(settings);
+ m_KeySequence.loadSettings(settings);
- actions().clear();
+ m_Actions.clear();
int num = settings.beginReadArray("actions");
for (int i = 0; i < num; i++)
{
settings.setArrayIndex(i);
Action a;
a.loadSettings(settings);
- actions().append(a);
+ m_Actions.push_back(a);
}
settings.endArray();
@@ -55,21 +55,33 @@ void Hotkey::loadSettings(QSettings& settings)
void Hotkey::saveSettings(QSettings& settings) const
{
- keySequence().saveSettings(settings);
+ m_KeySequence.saveSettings(settings);
settings.beginWriteArray("actions");
- for (int i = 0; i < actions().size(); i++)
+ for (int i = 0; i < m_Actions.size(); i++)
{
settings.setArrayIndex(i);
- actions()[i].saveSettings(settings);
+ m_Actions[i].saveSettings(settings);
}
settings.endArray();
}
QTextStream& operator<<(QTextStream& outStream, const Hotkey& hotkey)
{
- for (int i = 0; i < hotkey.actions().size(); i++)
- outStream << "\t" << hotkey.text() << " = " << hotkey.actions()[i] << endl;
+ // Don't write config if there are no actions
+ if (hotkey.actions().size() == 0) {
+ return outStream;
+ }
+
+ outStream << "\t" << hotkey.text() << " = ";
+ for (int i = 0; i < hotkey.actions().size(); i++) {
+ outStream << hotkey.actions()[i];
+ if (i != hotkey.actions().size() - 1) {
+ outStream << ", ";
+ }
+ }
+
+ outStream << "\n";
return outStream;
}
diff --git a/src/gui/src/Hotkey.h b/src/gui/src/Hotkey.h
index 475da02..5e6fc98 100644
--- a/src/gui/src/Hotkey.h
+++ b/src/gui/src/Hotkey.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -27,40 +27,35 @@
#include "Action.h"
#include "KeySequence.h"
+#include <vector>
+
class HotkeyDialog;
class ServerConfigDialog;
class QSettings;
class Hotkey
{
- friend class HotkeyDialog;
- friend class ServerConfigDialog;
- friend QTextStream& operator<<(QTextStream& outStream, const Hotkey& hotkey);
-
public:
Hotkey();
- public:
QString text() const;
const KeySequence& keySequence() const { return m_KeySequence; }
- const ActionList& actions() const { return m_Actions; }
+ void setKeySequence(const KeySequence& seq) { m_KeySequence = seq; }
+
+ const std::vector<Action>& actions() const { return m_Actions; }
+ void appendAction(const Action& action) { m_Actions.push_back(action); }
+ void setAction(int index, const Action& action) { m_Actions[index] = action; }
+ void removeAction(int index) { m_Actions.erase(m_Actions.begin() + index); }
void loadSettings(QSettings& settings);
void saveSettings(QSettings& settings) const;
- protected:
- KeySequence& keySequence() { return m_KeySequence; }
- void setKeySequence(const KeySequence& seq) { m_KeySequence = seq; }
- ActionList& actions() { return m_Actions; }
-
private:
KeySequence m_KeySequence;
- ActionList m_Actions;
+ std::vector<Action> m_Actions;
};
-typedef QList<Hotkey> HotkeyList;
-
QTextStream& operator<<(QTextStream& outStream, const Hotkey& hotkey);
#endif
diff --git a/src/gui/src/HotkeyDialog.cpp b/src/gui/src/HotkeyDialog.cpp
index ef25c3f..5b3e5a8 100644
--- a/src/gui/src/HotkeyDialog.cpp
+++ b/src/gui/src/HotkeyDialog.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/gui/src/HotkeyDialog.h b/src/gui/src/HotkeyDialog.h
index a13fc24..3a9967c 100644
--- a/src/gui/src/HotkeyDialog.h
+++ b/src/gui/src/HotkeyDialog.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/gui/src/IpcClient.h b/src/gui/src/IpcClient.h
index cd398b3..6040029 100644
--- a/src/gui/src/IpcClient.h
+++ b/src/gui/src/IpcClient.h
@@ -28,7 +28,7 @@ class IpcReader;
class IpcClient : public QObject
{
- Q_OBJECT
+ Q_OBJECT
public:
IpcClient();
diff --git a/src/gui/src/KeySequence.cpp b/src/gui/src/KeySequence.cpp
index cc74cb2..ddf7d33 100644
--- a/src/gui/src/KeySequence.cpp
+++ b/src/gui/src/KeySequence.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -55,6 +55,8 @@ static const struct
{ Qt::Key_Help, "Help" },
{ Qt::Key_Enter, "KP_Enter" },
{ Qt::Key_Clear, "Clear" },
+ { Qt::Key_Comma, "Comma" },
+ { Qt::Key_Semicolon, "Semicolon" },
{ Qt::Key_Back, "WWWBack" },
{ Qt::Key_Forward, "WWWForward" },
@@ -152,12 +154,12 @@ bool KeySequence::appendKey(int key, int modifiers)
void KeySequence::loadSettings(QSettings& settings)
{
- sequence().clear();
+ m_Sequence.clear();
int num = settings.beginReadArray("keys");
for (int i = 0; i < num; i++)
{
settings.setArrayIndex(i);
- sequence().append(settings.value("key", 0).toInt());
+ m_Sequence.append(settings.value("key", 0).toInt());
}
settings.endArray();
@@ -168,10 +170,10 @@ void KeySequence::loadSettings(QSettings& settings)
void KeySequence::saveSettings(QSettings& settings) const
{
settings.beginWriteArray("keys");
- for (int i = 0; i < sequence().size(); i++)
+ for (int i = 0; i < m_Sequence.size(); i++)
{
settings.setArrayIndex(i);
- settings.setValue("key", sequence()[i]);
+ settings.setValue("key", m_Sequence[i]);
}
settings.endArray();
}
@@ -211,23 +213,22 @@ QString KeySequence::keyToString(int key)
// treat key pad like normal keys (FIXME: we should have another lookup table for keypad keys instead)
key &= ~Qt::KeypadModifier;
+ // a special key?
+ int i = 0;
+ while (keyname[i].name) {
+ if (key == keyname[i].key)
+ return QString::fromUtf8(keyname[i].name);
+ i++;
+ }
+
// a printable 7 bit character?
- if (key < 0x80 && key != Qt::Key_Space)
+ if (key < 0x80)
return QChar(key & 0x7f).toLower();
// a function key?
if (key >= Qt::Key_F1 && key <= Qt::Key_F35)
return QString::fromUtf8("F%1").arg(key - Qt::Key_F1 + 1);
- // a special key?
- int i=0;
- while (keyname[i].name)
- {
- if (key == keyname[i].key)
- return QString::fromUtf8(keyname[i].name);
- i++;
- }
-
// representable in ucs2?
if (key < 0x10000)
return QString("\\u%1").arg(QChar(key).toLower().unicode(), 4, 16, QChar('0'));
diff --git a/src/gui/src/KeySequence.h b/src/gui/src/KeySequence.h
index 8d9706d..0331091 100644
--- a/src/gui/src/KeySequence.h
+++ b/src/gui/src/KeySequence.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -32,7 +32,7 @@ class KeySequence
public:
QString toString() const;
- bool appendKey(int modifiers, int key);
+ bool appendKey(int key, int modifiers);
bool appendMouseButton(int button);
bool isMouseButton() const;
bool valid() const { return m_IsValid; }
@@ -44,7 +44,6 @@ class KeySequence
private:
void setValid(bool b) { m_IsValid = b; }
void setModifiers(int i) { m_Modifiers = i; }
- QList<int>& sequence() { return m_Sequence; }
private:
QList<int> m_Sequence;
@@ -55,4 +54,3 @@ class KeySequence
};
#endif
-
diff --git a/src/gui/src/KeySequenceWidget.cpp b/src/gui/src/KeySequenceWidget.cpp
index e5823e1..067c5bf 100644
--- a/src/gui/src/KeySequenceWidget.cpp
+++ b/src/gui/src/KeySequenceWidget.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/gui/src/KeySequenceWidget.h b/src/gui/src/KeySequenceWidget.h
index eaef514..636375b 100644
--- a/src/gui/src/KeySequenceWidget.h
+++ b/src/gui/src/KeySequenceWidget.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -78,4 +78,3 @@ class KeySequenceWidget : public QPushButton
};
#endif
-
diff --git a/src/gui/src/MainWindow.cpp b/src/gui/src/MainWindow.cpp
index 01133bf..d17548a 100644
--- a/src/gui/src/MainWindow.cpp
+++ b/src/gui/src/MainWindow.cpp
@@ -20,18 +20,21 @@
#include "MainWindow.h"
-#include "Fingerprint.h"
#include "AboutDialog.h"
#include "ServerConfigDialog.h"
#include "SettingsDialog.h"
#include "ZeroconfService.h"
#include "DataDownloader.h"
#include "CommandProcess.h"
+#include "FingerprintAcceptDialog.h"
#include "QUtility.h"
#include "ProcessorArch.h"
#include "SslCertificate.h"
#include "ShutdownCh.h"
+#include "base/String.h"
#include "common/DataDirectories.h"
+#include "net/FingerprintDatabase.h"
+#include "net/SecureUtils.h"
#include <QtCore>
#include <QtGui>
@@ -53,17 +56,20 @@
#include <Windows.h>
#endif
+static const QString allFilesFilter(QObject::tr("All files (*.*)"));
#if defined(Q_OS_WIN)
static const char barrierConfigName[] = "barrier.sgc";
-static const QString barrierConfigFilter(QObject::tr("Barrier Configurations (*.sgc);;All files (*.*)"));
+static const QString barrierConfigFilter(QObject::tr("Barrier Configurations (*.sgc)"));
static QString bonjourBaseUrl = "http://binaries.symless.com/bonjour/";
static const char bonjourFilename32[] = "Bonjour.msi";
static const char bonjourFilename64[] = "Bonjour64.msi";
static const char bonjourTargetFilename[] = "Bonjour.msi";
#else
static const char barrierConfigName[] = "barrier.conf";
-static const QString barrierConfigFilter(QObject::tr("Barrier Configurations (*.conf);;All files (*.*)"));
+static const QString barrierConfigFilter(QObject::tr("Barrier Configurations (*.conf)"));
#endif
+static const QString barrierConfigOpenFilter(barrierConfigFilter + ";;" + allFilesFilter);
+static const QString barrierConfigSaveFilter(barrierConfigFilter);
static const char* barrierIconFiles[] =
{
@@ -80,6 +86,14 @@ static const char* barrierIconFiles[] =
#endif
};
+static const char* barrierIconNames[] =
+{
+ "barrier-disconnected",
+ "barrier-disconnected",
+ "barrier-connected",
+ "barrier-transfering"
+};
+
static const char* barrierLargeIcon = ":/res/icons/256x256/barrier.ico";
MainWindow::MainWindow(QSettings& settings, AppConfig& appConfig) :
@@ -145,9 +159,22 @@ MainWindow::MainWindow(QSettings& settings, AppConfig& appConfig) :
m_pComboServerList->hide();
m_pLabelPadlock->hide();
+ frame_fingerprint_details->hide();
updateSSLFingerprint();
+ connect(toolbutton_show_fingerprint, &QToolButton::clicked, [this](bool checked)
+ {
+ m_fingerprint_expanded = !m_fingerprint_expanded;
+ if (m_fingerprint_expanded) {
+ frame_fingerprint_details->show();
+ toolbutton_show_fingerprint->setArrowType(Qt::ArrowType::UpArrow);
+ } else {
+ frame_fingerprint_details->hide();
+ toolbutton_show_fingerprint->setArrowType(Qt::ArrowType::DownArrow);
+ }
+ });
+
// resize window to smallest reasonable size
resize(0, 0);
}
@@ -191,7 +218,7 @@ void MainWindow::open()
// only start if user has previously started. this stops the gui from
// auto hiding before the user has configured barrier (which of course
// confuses first time users, who think barrier has crashed).
- if (appConfig().startedBefore() && appConfig().processMode() == Desktop) {
+ if (appConfig().startedBefore() && appConfig().getAutoStart()) {
m_SuppressEmptyServerWarning = true;
startBarrier();
m_SuppressEmptyServerWarning = false;
@@ -296,7 +323,7 @@ void MainWindow::saveSettings()
void MainWindow::setIcon(qBarrierState state)
{
if (m_pTrayIcon) {
- QIcon icon = QIcon(barrierIconFiles[state]);
+ QIcon icon = QIcon::fromTheme(barrierIconNames[state], QIcon(barrierIconFiles[state]));
#if defined(Q_OS_MAC)
icon.setIsMask(true);
#endif
@@ -325,8 +352,7 @@ void MainWindow::logOutput()
if (m_pBarrier)
{
QString text(m_pBarrier->readAllStandardOutput());
- foreach(QString line, text.split(QRegExp("\r|\n|\r\n")))
- {
+ for (QString line : text.split(QRegExp("\r|\n|\r\n"))) {
if (!line.isEmpty())
{
appendLogRaw(line);
@@ -363,7 +389,7 @@ void MainWindow::appendLogError(const QString& text)
void MainWindow::appendLogRaw(const QString& text)
{
- foreach(QString line, text.split(QRegExp("\r|\n|\r\n"))) {
+ for (QString line : text.split(QRegExp("\r|\n|\r\n"))) {
if (!line.isEmpty()) {
m_pLogWindow->appendRaw(line);
updateFromLogLine(line);
@@ -402,41 +428,57 @@ void MainWindow::checkConnected(const QString& line)
void MainWindow::checkFingerprint(const QString& line)
{
- QRegExp fingerprintRegex(".*server fingerprint: ([A-F0-9:]+)");
+ QRegExp fingerprintRegex(".*peer fingerprint \\(SHA1\\): ([A-F0-9:]+) \\(SHA256\\): ([A-F0-9:]+)");
if (!fingerprintRegex.exactMatch(line)) {
return;
}
- QString fingerprint = fingerprintRegex.cap(1);
- if (Fingerprint::trustedServers().isTrusted(fingerprint)) {
+ barrier::FingerprintData fingerprint_sha1 = {
+ barrier::fingerprint_type_to_string(barrier::FingerprintType::SHA1),
+ barrier::string::from_hex(fingerprintRegex.cap(1).toStdString())
+ };
+
+ barrier::FingerprintData fingerprint_sha256 = {
+ barrier::fingerprint_type_to_string(barrier::FingerprintType::SHA256),
+ barrier::string::from_hex(fingerprintRegex.cap(2).toStdString())
+ };
+
+ bool is_client = barrier_type() == BarrierType::Client;
+
+ auto db_path = is_client
+ ? barrier::DataDirectories::trusted_servers_ssl_fingerprints_path()
+ : barrier::DataDirectories::trusted_clients_ssl_fingerprints_path();
+
+ auto db_dir = db_path.parent_path();
+ if (!barrier::fs::exists(db_dir)) {
+ barrier::fs::create_directories(db_dir);
+ }
+
+ // We compare only SHA256 fingerprints, but show both SHA1 and SHA256 so that the users can
+ // still verify fingerprints on old Barrier servers. This way the only time when we are exposed
+ // to SHA1 vulnerabilities is when the user is reconnecting again.
+ barrier::FingerprintDatabase db;
+ db.read(db_path);
+ if (db.is_trusted(fingerprint_sha256)) {
return;
}
static bool messageBoxAlreadyShown = false;
if (!messageBoxAlreadyShown) {
- stopBarrier();
+ if (is_client) {
+ stopBarrier();
+ }
messageBoxAlreadyShown = true;
- QMessageBox::StandardButton fingerprintReply =
- QMessageBox::information(
- this, tr("Security question"),
- tr("Do you trust this fingerprint?\n\n"
- "%1\n\n"
- "This is a server fingerprint. You should compare this "
- "fingerprint to the one on your server's screen. If the "
- "two don't match exactly, then it's probably not the server "
- "you're expecting (it could be a malicious user).\n\n"
- "To automatically trust this fingerprint for future "
- "connections, click Yes. To reject this fingerprint and "
- "disconnect from the server, click No.")
- .arg(fingerprint),
- QMessageBox::Yes | QMessageBox::No);
-
- if (fingerprintReply == QMessageBox::Yes) {
+ FingerprintAcceptDialog dialog{this, barrier_type(), fingerprint_sha1, fingerprint_sha256};
+ if (dialog.exec() == QDialog::Accepted) {
// restart core process after trusting fingerprint.
- Fingerprint::trustedServers().trust(fingerprint);
- startBarrier();
+ db.add_trusted(fingerprint_sha256);
+ db.write(db_path);
+ if (is_client) {
+ startBarrier();
+ }
}
messageBoxAlreadyShown = false;
@@ -506,8 +548,8 @@ void MainWindow::startBarrier()
#endif
- if (m_AppConfig->getCryptoEnabled()) {
- args << "--enable-crypto";
+ if (!m_AppConfig->getCryptoEnabled()) {
+ args << "--disable-crypto";
}
#if defined(Q_OS_WIN)
@@ -515,11 +557,11 @@ void MainWindow::startBarrier()
// launched the process (e.g. when launched with elevation). setting the
// profile dir on launch ensures it uses the same profile dir is used
// no matter how its relaunched.
- args << "--profile-dir" << QString::fromStdString("\"" + DataDirectories::profile() + "\"");
+ args << "--profile-dir" << QString::fromStdString("\"" + barrier::DataDirectories::profile().u8string() + "\"");
#endif
- if ((barrierType() == barrierClient && !clientArgs(args, app))
- || (barrierType() == barrierServer && !serverArgs(args, app)))
+ if ((barrier_type() == BarrierType::Client && !clientArgs(args, app))
+ || (barrier_type() == BarrierType::Server && !serverArgs(args, app)))
{
stopBarrier();
return;
@@ -534,7 +576,7 @@ void MainWindow::startBarrier()
m_pLogWindow->startNewInstance();
- appendLogInfo("starting " + QString(barrierType() == barrierServer ? "server" : "client"));
+ appendLogInfo("starting " + QString(barrier_type() == BarrierType::Server ? "server" : "client"));
qDebug() << args;
@@ -615,7 +657,7 @@ QString MainWindow::configFilename()
if (m_pRadioInternalConfig->isChecked())
{
// TODO: no need to use a temporary file, since we need it to
- // be permenant (since it'll be used for Windows services, etc).
+ // be permanent (since it'll be used for Windows services, etc).
m_pTempConfigFile = new QTemporaryFile();
if (!m_pTempConfigFile->open())
{
@@ -644,6 +686,11 @@ QString MainWindow::configFilename()
return filename;
}
+BarrierType MainWindow::barrier_type() const
+{
+ return m_pGroupClient->isChecked() ? BarrierType::Client : BarrierType::Server;
+}
+
QString MainWindow::address()
{
QString address = appConfig().networkInterface();
@@ -680,6 +727,10 @@ bool MainWindow::serverArgs(QStringList& args, QString& app)
args << "--log" << appConfig().logFilenameCmd();
}
+ if (!appConfig().getRequireClientCertificate()) {
+ args << "--disable-client-cert-checking";
+ }
+
QString configFilename = this->configFilename();
#if defined(Q_OS_WIN)
// wrap in quotes in case username contains spaces.
@@ -720,7 +771,7 @@ void MainWindow::stopBarrier()
void MainWindow::stopService()
{
- // send empty command to stop service from laucning anything.
+ // send empty command to stop service from launching anything.
m_IpcClient.sendCommand("", appConfig().elevateMode());
}
@@ -915,6 +966,14 @@ void MainWindow::changeEvent(QEvent* event)
QMainWindow::changeEvent(event);
}
+bool MainWindow::event(QEvent* event)
+{
+ if (event->type() == QEvent::LayoutRequest) {
+ setFixedSize(sizeHint());
+ }
+ return QMainWindow::event(event);
+}
+
void MainWindow::updateZeroconfService()
{
QMutexLocker locker(&m_UpdateZeroconfMutex);
@@ -926,7 +985,7 @@ void MainWindow::updateZeroconfService()
m_pZeroconfService = NULL;
}
- if (m_AppConfig->autoConfig() || barrierType() == barrierServer) {
+ if (m_AppConfig->autoConfig() || barrier_type() == BarrierType::Server) {
m_pZeroconfService = new ZeroconfService(this);
}
}
@@ -949,14 +1008,53 @@ void MainWindow::updateSSLFingerprint()
{
if (m_AppConfig->getCryptoEnabled() && m_pSslCertificate == nullptr) {
m_pSslCertificate = new SslCertificate(this);
+ connect(m_pSslCertificate, &SslCertificate::info, [&](QString info)
+ {
+ appendLogInfo(info);
+ });
m_pSslCertificate->generateCertificate();
}
- if (m_AppConfig->getCryptoEnabled() && Fingerprint::local().fileExists()) {
- m_pLabelLocalFingerprint->setText(Fingerprint::local().readFirst());
- m_pLabelLocalFingerprint->setTextInteractionFlags(Qt::TextSelectableByMouse);
- } else {
- m_pLabelLocalFingerprint->setText("Disabled");
+
+ toolbutton_show_fingerprint->setEnabled(false);
+ m_pLabelLocalFingerprint->setText("Disabled");
+
+ if (!m_AppConfig->getCryptoEnabled()) {
+ return;
+ }
+
+ auto local_path = barrier::DataDirectories::local_ssl_fingerprints_path();
+ if (!barrier::fs::exists(local_path)) {
+ return;
}
+
+ barrier::FingerprintDatabase db;
+ db.read(local_path);
+ if (db.fingerprints().size() != 2) {
+ return;
+ }
+
+ for (const auto& fingerprint : db.fingerprints()) {
+ if (fingerprint.algorithm == "sha1") {
+ auto fingerprint_str = barrier::format_ssl_fingerprint(fingerprint.data);
+ label_sha1_fingerprint_full->setText(QString::fromStdString(fingerprint_str));
+ continue;
+ }
+
+ if (fingerprint.algorithm == "sha256") {
+ auto fingerprint_str = barrier::format_ssl_fingerprint(fingerprint.data);
+ fingerprint_str.resize(40);
+ fingerprint_str += " ...";
+
+ auto fingerprint_str_cols = barrier::format_ssl_fingerprint_columns(fingerprint.data);
+ auto fingerprint_randomart = barrier::create_fingerprint_randomart(fingerprint.data);
+
+ m_pLabelLocalFingerprint->setText(QString::fromStdString(fingerprint_str));
+ label_sha256_fingerprint_full->setText(QString::fromStdString(fingerprint_str_cols));
+ label_sha256_randomart->setText(QString::fromStdString(fingerprint_randomart));
+ }
+ }
+
+ toolbutton_show_fingerprint->setEnabled(true);
}
void MainWindow::on_m_pGroupClient_toggled(bool on)
@@ -977,7 +1075,7 @@ void MainWindow::on_m_pGroupServer_toggled(bool on)
bool MainWindow::on_m_pButtonBrowseConfigFile_clicked()
{
- QString fileName = QFileDialog::getOpenFileName(this, tr("Browse for a barriers config file"), QString(), barrierConfigFilter);
+ QString fileName = QFileDialog::getOpenFileName(this, tr("Browse for a barriers config file"), QString(), barrierConfigOpenFilter);
if (!fileName.isEmpty())
{
@@ -988,9 +1086,9 @@ bool MainWindow::on_m_pButtonBrowseConfigFile_clicked()
return false;
}
-bool MainWindow::on_m_pActionSave_triggered()
+bool MainWindow::on_m_pActionSave_triggered()
{
- QString fileName = QFileDialog::getSaveFileName(this, tr("Save configuration as..."), QString(), tr("Barrier Configuration (*.sgc)"));
+ QString fileName = QFileDialog::getSaveFileName(this, tr("Save configuration as..."), QString(), barrierConfigSaveFilter);
if (!fileName.isEmpty() && !serverConfig().save(fileName))
{
diff --git a/src/gui/src/MainWindow.h b/src/gui/src/MainWindow.h
index c115b91..0c582c9 100644
--- a/src/gui/src/MainWindow.h
+++ b/src/gui/src/MainWindow.h
@@ -20,6 +20,8 @@
#define MAINWINDOW__H
+#include "barrier/BarrierType.h"
+
#include <QMainWindow>
#include <QSystemTrayIcon>
#include <QSettings>
@@ -76,12 +78,6 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase
barrierTransfering
};
- enum qBarrierType
- {
- barrierClient,
- barrierServer
- };
-
enum qLevel {
Error,
Info
@@ -98,7 +94,7 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase
public:
void setVisible(bool visible);
- int barrierType() const { return m_pGroupClient->isChecked() ? barrierClient : barrierServer; }
+ BarrierType barrier_type() const;
int barrierState() const { return m_BarrierState; }
QString hostname() const { return m_pLineEditHostname->text(); }
QString configFilename();
@@ -157,6 +153,7 @@ public slots:
void stopService();
void stopDesktop();
void changeEvent(QEvent* event);
+ bool event(QEvent* event);
void retranslateMenuBar();
#if defined(Q_OS_WIN)
bool isServiceRunning(QString name);
@@ -202,6 +199,8 @@ public slots:
QStringList m_PendingClientNames;
LogWindow *m_pLogWindow;
+ bool m_fingerprint_expanded = false;
+
private slots:
void on_m_pCheckBoxAutoConfig_toggled(bool checked);
void on_m_pComboServerList_currentIndexChanged(QString );
@@ -211,4 +210,3 @@ private slots:
};
#endif
-
diff --git a/src/gui/src/MainWindowBase.ui b/src/gui/src/MainWindowBase.ui
index 117405c..88994cf 100644
--- a/src/gui/src/MainWindowBase.ui
+++ b/src/gui/src/MainWindowBase.ui
@@ -2,31 +2,20 @@
<ui version="4.0">
<class>MainWindowBase</class>
<widget class="QMainWindow" name="MainWindowBase">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>600</width>
- <height>550</height>
- </rect>
- </property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
- <property name="minimumSize">
- <size>
- <width>600</width>
- <height>0</height>
- </size>
- </property>
<property name="windowTitle">
<string>Barrier</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout_2">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetFixedSize</enum>
+ </property>
<item>
<widget class="QGroupBox" name="m_pGroupServer">
<property name="sizePolicy">
@@ -67,30 +56,6 @@
</layout>
</item>
<item>
- <layout class="QHBoxLayout" name="horizontalLayout_3">
- <item>
- <widget class="QLabel" name="m_pLabelFingerprint">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string>SSL Fingerprint:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLabel" name="m_pLabelLocalFingerprint">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
<widget class="QRadioButton" name="m_pRadioInternalConfig">
<property name="text">
<string>Configure interactively:</string>
@@ -240,6 +205,107 @@
</widget>
</item>
<item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QLabel" name="m_pLabelFingerprint">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>SSL Fingerprint:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="m_pLabelLocalFingerprint">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="toolbutton_show_fingerprint">
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="arrowType">
+ <enum>Qt::DownArrow</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QFrame" name="frame_fingerprint_details">
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetMinimumSize</enum>
+ </property>
+ <item row="1" column="1">
+ <widget class="QLabel" name="label_sha256_randomart">
+ <property name="font">
+ <font>
+ <family>Courier</family>
+ </font>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" colspan="2">
+ <widget class="QLabel" name="label_sha1">
+ <property name="text">
+ <string>SHA1 (deprecated, compare to old clients and servers only):</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" colspan="2">
+ <widget class="QLabel" name="label_sha1_fingerprint_full">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0" colspan="2">
+ <widget class="QLabel" name="label_sha256">
+ <property name="text">
+ <string>SHA256:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_sha256_fingerprint_full">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
@@ -253,7 +319,7 @@
<string/>
</property>
<property name="pixmap">
- <pixmap resource="Barrier.qrc">:/res/icons/16x16/padlock.png</pixmap>
+ <pixmap resource="../res/Barrier.qrc">:/res/icons/16x16/padlock.png</pixmap>
</property>
</widget>
</item>
@@ -388,7 +454,7 @@
</action>
<action name="m_pActionShowLog">
<property name="text">
- <string>Show &amp;Log</string>
+ <string>Show &amp;Log</string>
</property>
<property name="toolTip">
<string>Show Log</string>
@@ -399,7 +465,7 @@
</action>
</widget>
<resources>
- <include location="Barrier.qrc"/>
+ <include location="../res/Barrier.qrc"/>
</resources>
<connections>
<connection>
diff --git a/src/gui/src/NewScreenWidget.cpp b/src/gui/src/NewScreenWidget.cpp
index 0336249..28e99fa 100644
--- a/src/gui/src/NewScreenWidget.cpp
+++ b/src/gui/src/NewScreenWidget.cpp
@@ -1,12 +1,12 @@
-/*
+/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -45,4 +45,3 @@ void NewScreenWidget::mousePressEvent(QMouseEvent* event)
pDrag->exec(Qt::CopyAction, Qt::CopyAction);
}
-
diff --git a/src/gui/src/NewScreenWidget.h b/src/gui/src/NewScreenWidget.h
index 34f3269..6e52795 100644
--- a/src/gui/src/NewScreenWidget.h
+++ b/src/gui/src/NewScreenWidget.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -37,4 +37,3 @@ class NewScreenWidget : public QLabel
};
#endif
-
diff --git a/src/gui/src/QBarrierApplication.cpp b/src/gui/src/QBarrierApplication.cpp
index f2da382..f9362c7 100644
--- a/src/gui/src/QBarrierApplication.cpp
+++ b/src/gui/src/QBarrierApplication.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -38,8 +38,7 @@ QBarrierApplication::~QBarrierApplication()
void QBarrierApplication::commitData(QSessionManager&)
{
- foreach(QWidget* widget, topLevelWidgets())
- {
+ for (QWidget* widget : topLevelWidgets()) {
MainWindow* mainWindow = qobject_cast<MainWindow*>(widget);
if (mainWindow)
mainWindow->saveSettings();
diff --git a/src/gui/src/QBarrierApplication.h b/src/gui/src/QBarrierApplication.h
index 95729b2..bd348b3 100644
--- a/src/gui/src/QBarrierApplication.h
+++ b/src/gui/src/QBarrierApplication.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -44,4 +44,3 @@ class QBarrierApplication : public QApplication
};
#endif
-
diff --git a/src/gui/src/QUtility.cpp b/src/gui/src/QUtility.cpp
index 7757adf..2d05fc3 100644
--- a/src/gui/src/QUtility.cpp
+++ b/src/gui/src/QUtility.cpp
@@ -51,8 +51,7 @@ QString hash(const QString& string)
QString getFirstMacAddress()
{
QString mac;
- foreach (const QNetworkInterface &interface, QNetworkInterface::allInterfaces())
- {
+ for (const QNetworkInterface &interface : QNetworkInterface::allInterfaces()) {
mac = interface.hardwareAddress();
if (mac.size() != 0)
{
diff --git a/src/gui/src/Screen.cpp b/src/gui/src/Screen.cpp
index 38d02e8..1e3b888 100644
--- a/src/gui/src/Screen.cpp
+++ b/src/gui/src/Screen.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -125,8 +125,9 @@ QTextStream& Screen::writeAliasesSection(QTextStream& outStream) const
{
outStream << "\t" << name() << ":" << endl;
- foreach (const QString& alias, aliases())
+ for (const QString& alias : aliases()) {
outStream << "\t\t" << alias << endl;
+ }
}
return outStream;
diff --git a/src/gui/src/Screen.h b/src/gui/src/Screen.h
index d728af1..6496221 100644
--- a/src/gui/src/Screen.h
+++ b/src/gui/src/Screen.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -101,10 +101,7 @@ class Screen : public BaseConfig
bool m_Swapped;
};
-typedef QList<Screen> ScreenList;
-
QDataStream& operator<<(QDataStream& outStream, const Screen& screen);
QDataStream& operator>>(QDataStream& inStream, Screen& screen);
#endif
-
diff --git a/src/gui/src/ScreenSettingsDialog.cpp b/src/gui/src/ScreenSettingsDialog.cpp
index 123bb8a..9055e35 100644
--- a/src/gui/src/ScreenSettingsDialog.cpp
+++ b/src/gui/src/ScreenSettingsDialog.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -152,4 +152,3 @@ void ScreenSettingsDialog::on_m_pListAliases_itemSelectionChanged()
{
m_pButtonRemoveAlias->setEnabled(!m_pListAliases->selectedItems().isEmpty());
}
-
diff --git a/src/gui/src/ScreenSettingsDialog.h b/src/gui/src/ScreenSettingsDialog.h
index 1c525d2..953d1f8 100644
--- a/src/gui/src/ScreenSettingsDialog.h
+++ b/src/gui/src/ScreenSettingsDialog.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -50,4 +50,3 @@ class ScreenSettingsDialog : public QDialog, public Ui::ScreenSettingsDialogBase
};
#endif
-
diff --git a/src/gui/src/ScreenSetupModel.cpp b/src/gui/src/ScreenSetupModel.cpp
index fce1a8c..5c933f8 100644
--- a/src/gui/src/ScreenSetupModel.cpp
+++ b/src/gui/src/ScreenSetupModel.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -24,7 +24,7 @@
const QString ScreenSetupModel::m_MimeType = "application/x-qbarrier-screen";
-ScreenSetupModel::ScreenSetupModel(ScreenList& screens, int numColumns, int numRows) :
+ScreenSetupModel::ScreenSetupModel(std::vector<Screen>& screens, int numColumns, int numRows) :
QAbstractTableModel(NULL),
m_Screens(screens),
m_NumColumns(numColumns),
@@ -71,7 +71,7 @@ Qt::ItemFlags ScreenSetupModel::flags(const QModelIndex& index) const
if (!screen(index).isNull())
return Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled;
- return Qt::ItemIsDropEnabled;
+ return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled;
}
Qt::DropActions ScreenSetupModel::supportedDropActions() const
@@ -91,9 +91,10 @@ QMimeData* ScreenSetupModel::mimeData(const QModelIndexList& indexes) const
QDataStream stream(&encodedData, QIODevice::WriteOnly);
- foreach (const QModelIndex& index, indexes)
+ for (const QModelIndex& index : indexes) {
if (index.isValid())
stream << index.column() << index.row() << screen(index);
+ }
pMimeData->setData(m_MimeType, encodedData);
@@ -109,7 +110,7 @@ bool ScreenSetupModel::dropMimeData(const QMimeData* data, Qt::DropAction action
return false;
if (!parent.isValid() || row != -1 || column != -1)
- return false;
+ return false;
QByteArray encodedData = data->data(m_MimeType);
QDataStream stream(&encodedData, QIODevice::ReadOnly);
@@ -140,4 +141,3 @@ bool ScreenSetupModel::dropMimeData(const QMimeData* data, Qt::DropAction action
return true;
}
-
diff --git a/src/gui/src/ScreenSetupModel.h b/src/gui/src/ScreenSetupModel.h
index ba46af3..0f558b4 100644
--- a/src/gui/src/ScreenSetupModel.h
+++ b/src/gui/src/ScreenSetupModel.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -38,7 +38,7 @@ class ScreenSetupModel : public QAbstractTableModel
friend class ServerConfigDialog;
public:
- ScreenSetupModel(ScreenList& screens, int numColumns, int numRows);
+ ScreenSetupModel(std::vector<Screen>& screens, int numColumns, int numRows);
public:
static const QString& mimeType() { return m_MimeType; }
@@ -60,7 +60,7 @@ class ScreenSetupModel : public QAbstractTableModel
Screen& screen(int column, int row) { return m_Screens[row * m_NumColumns + column]; }
private:
- ScreenList& m_Screens;
+ std::vector<Screen>& m_Screens;
const int m_NumColumns;
const int m_NumRows;
@@ -68,4 +68,3 @@ class ScreenSetupModel : public QAbstractTableModel
};
#endif
-
diff --git a/src/gui/src/ScreenSetupView.cpp b/src/gui/src/ScreenSetupView.cpp
index 46e7099..5459f23 100644
--- a/src/gui/src/ScreenSetupView.cpp
+++ b/src/gui/src/ScreenSetupView.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -30,6 +30,7 @@ ScreenSetupView::ScreenSetupView(QWidget* parent) :
setDropIndicatorShown(true);
setDragDropMode(DragDrop);
setSelectionMode(SingleSelection);
+ setTabKeyNavigation(false);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
@@ -65,18 +66,83 @@ void ScreenSetupView::resizeEvent(QResizeEvent* event)
event->ignore();
}
+void ScreenSetupView::enter(const QModelIndex& index)
+{
+ if (!index.isValid())
+ return;
+ Screen& screen = model()->screen(index);
+ if (screen.isNull())
+ screen = Screen(tr("Unnamed"));
+ ScreenSettingsDialog dlg(this, &screen);
+ dlg.exec();
+}
+
+void ScreenSetupView::remove(const QModelIndex& index)
+{
+ if (!index.isValid())
+ return;
+ Screen& screen = model()->screen(index);
+ if (!screen.isNull()) {
+ screen = Screen();
+ emit dataChanged(index, index);
+ }
+}
+
+void ScreenSetupView::keyPressEvent(QKeyEvent* event)
+{
+ if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Delete)
+ {
+ QModelIndexList indexes = selectedIndexes();
+ if (indexes.count() == 1 && indexes[0].isValid())
+ {
+ if (event->key() == Qt::Key_Return)
+ enter(indexes[0]);
+ else if (event->key() == Qt::Key_Delete)
+ remove(indexes[0]);
+ }
+ // Do not let base handle the event, at least not for return key because it
+ // results in next esc/return key in the opened Screen Settings dialog not
+ // only closing that but also the parent Server Configuration dialog.
+ }
+ else if ((event->modifiers() & Qt::ControlModifier)
+ && (event->key() == Qt::Key_Left || event->key() == Qt::Key_Right
+ || event->key() == Qt::Key_Up || event->key() == Qt::Key_Down))
+ {
+ QModelIndexList indexes = selectedIndexes();
+ if (indexes.count() == 1 && indexes[0].isValid())
+ {
+ const QModelIndex& fromIndex = indexes[0];
+ QModelIndex toIndex;
+
+ if (event->key() == Qt::Key_Left)
+ toIndex = fromIndex.sibling(fromIndex.row(), fromIndex.column() - 1);
+ else if (event->key() == Qt::Key_Right)
+ toIndex = fromIndex.sibling(fromIndex.row(), fromIndex.column() + 1);
+ else if (event->key() == Qt::Key_Up)
+ toIndex = fromIndex.sibling(fromIndex.row() - 1, fromIndex.column());
+ else if (event->key() == Qt::Key_Down)
+ toIndex = fromIndex.sibling(fromIndex.row() + 1, fromIndex.column());
+
+ if (toIndex.isValid() && fromIndex != toIndex)
+ std::swap(model()->screen(fromIndex), model()->screen(toIndex));
+ }
+ // In this case let base also handle the event, because it will proceed moving
+ // the selection to target, update the view according to model changes etc.
+ QTableView::keyPressEvent(event);
+ }
+ else
+ {
+ QTableView::keyPressEvent(event);
+ }
+}
+
void ScreenSetupView::mouseDoubleClickEvent(QMouseEvent* event)
{
if (event->buttons() & Qt::LeftButton)
{
int col = columnAt(event->pos().x());
int row = rowAt(event->pos().y());
-
- if (!model()->screen(col, row).isNull())
- {
- ScreenSettingsDialog dlg(this, &model()->screen(col, row));
- dlg.exec();
- }
+ enter(model()->createIndex(row, col));
}
else
event->ignore();
@@ -159,4 +225,3 @@ QStyleOptionViewItem ScreenSetupView::viewOptions() const
option.textElideMode = Qt::ElideMiddle;
return option;
}
-
diff --git a/src/gui/src/ScreenSetupView.h b/src/gui/src/ScreenSetupView.h
index a660511..64968a0 100644
--- a/src/gui/src/ScreenSetupView.h
+++ b/src/gui/src/ScreenSetupView.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -44,6 +44,7 @@ class ScreenSetupView : public QTableView
protected:
void mouseDoubleClickEvent(QMouseEvent*) override;
+ void keyPressEvent(QKeyEvent*) override;
void setTableSize();
void resizeEvent(QResizeEvent*) override;
void dragEnterEvent(QDragEnterEvent* event) override;
@@ -51,7 +52,9 @@ class ScreenSetupView : public QTableView
void startDrag(Qt::DropActions supportedActions) override;
QStyleOptionViewItem viewOptions() const override;
void scrollTo(const QModelIndex&, ScrollHint) override {}
+ private:
+ void enter(const QModelIndex&);
+ void remove(const QModelIndex&);
};
#endif
-
diff --git a/src/gui/src/ServerConfig.cpp b/src/gui/src/ServerConfig.cpp
index 9fedd1e..3392572 100644
--- a/src/gui/src/ServerConfig.cpp
+++ b/src/gui/src/ServerConfig.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -183,7 +183,7 @@ void ServerConfig::loadSettings()
settings().setArrayIndex(i);
Hotkey h;
h.loadSettings(settings());
- hotkeys().append(h);
+ hotkeys().push_back(h);
}
settings().endArray();
@@ -212,17 +212,19 @@ QTextStream& operator<<(QTextStream& outStream, const ServerConfig& config)
{
outStream << "section: screens" << endl;
- foreach (const Screen& s, config.screens())
+ for (const Screen& s : config.screens()) {
if (!s.isNull())
s.writeScreensSection(outStream);
+ }
outStream << "end" << endl << endl;
outStream << "section: aliases" << endl;
- foreach (const Screen& s, config.screens())
+ for (const Screen& s : config.screens()) {
if (!s.isNull())
s.writeAliasesSection(outStream);
+ }
outStream << "end" << endl << endl;
@@ -270,8 +272,9 @@ QTextStream& operator<<(QTextStream& outStream, const ServerConfig& config)
outStream << "\t" << "switchCornerSize = " << config.switchCornerSize() << endl;
- foreach(const Hotkey& hotkey, config.hotkeys())
+ for (const Hotkey& hotkey : config.hotkeys()) {
outStream << hotkey;
+ }
outStream << "end" << endl << endl;
@@ -282,9 +285,10 @@ int ServerConfig::numScreens() const
{
int rval = 0;
- foreach(const Screen& s, screens())
+ for (const Screen& s : screens()) {
if (!s.isNull())
rval++;
+ }
return rval;
}
diff --git a/src/gui/src/ServerConfig.h b/src/gui/src/ServerConfig.h
index c9648b0..9f3e2db 100644
--- a/src/gui/src/ServerConfig.h
+++ b/src/gui/src/ServerConfig.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -44,7 +44,7 @@ class ServerConfig : public BaseConfig
~ServerConfig();
public:
- const ScreenList& screens() const { return m_Screens; }
+ const std::vector<Screen>& screens() const { return m_Screens; }
int numColumns() const { return m_NumColumns; }
int numRows() const { return m_NumRows; }
bool hasHeartbeat() const { return m_HasHeartbeat; }
@@ -59,7 +59,7 @@ class ServerConfig : public BaseConfig
bool switchCorner(SwitchCorner c) const { return m_SwitchCorners[static_cast<int>(c)]; }
int switchCornerSize() const { return m_SwitchCornerSize; }
const QList<bool>& switchCorners() const { return m_SwitchCorners; }
- const HotkeyList& hotkeys() const { return m_Hotkeys; }
+ const std::vector<Hotkey>& hotkeys() const { return m_Hotkeys; }
bool ignoreAutoConfigClient() const { return m_IgnoreAutoConfigClient; }
bool enableDragAndDrop() const { return m_EnableDragAndDrop; }
bool clipboardSharing() const { return m_ClipboardSharing; }
@@ -73,9 +73,9 @@ class ServerConfig : public BaseConfig
protected:
QSettings& settings() { return *m_pSettings; }
- ScreenList& screens() { return m_Screens; }
- void setScreens(const ScreenList& screens) { m_Screens = screens; }
- void addScreen(const Screen& screen) { m_Screens.append(screen); }
+ std::vector<Screen>& screens() { return m_Screens; }
+ void setScreens(const std::vector<Screen>& screens) { m_Screens = screens; }
+ void addScreen(const Screen& screen) { m_Screens.push_back(screen); }
void setNumColumns(int n) { m_NumColumns = n; }
void setNumRows(int n) { m_NumRows = n; }
void haveHeartbeat(bool on) { m_HasHeartbeat = on; }
@@ -93,7 +93,7 @@ class ServerConfig : public BaseConfig
void setEnableDragAndDrop(bool on) { m_EnableDragAndDrop = on; }
void setClipboardSharing(bool on) { m_ClipboardSharing = on; }
QList<bool>& switchCorners() { return m_SwitchCorners; }
- HotkeyList& hotkeys() { return m_Hotkeys; }
+ std::vector<Hotkey>& hotkeys() { return m_Hotkeys; }
void init();
int adjacentScreenIndex(int idx, int deltaColumn, int deltaRow) const;
@@ -106,7 +106,7 @@ class ServerConfig : public BaseConfig
private:
QSettings* m_pSettings;
- ScreenList m_Screens;
+ std::vector<Screen> m_Screens;
int m_NumColumns;
int m_NumRows;
bool m_HasHeartbeat;
@@ -120,7 +120,7 @@ class ServerConfig : public BaseConfig
int m_SwitchDoubleTap;
int m_SwitchCornerSize;
QList<bool> m_SwitchCorners;
- HotkeyList m_Hotkeys;
+ std::vector<Hotkey> m_Hotkeys;
QString m_ServerName;
bool m_IgnoreAutoConfigClient;
bool m_EnableDragAndDrop;
@@ -138,4 +138,3 @@ enum {
};
#endif
-
diff --git a/src/gui/src/ServerConfigDialog.cpp b/src/gui/src/ServerConfigDialog.cpp
index 2e7ffc9..84c2047 100644
--- a/src/gui/src/ServerConfigDialog.cpp
+++ b/src/gui/src/ServerConfigDialog.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -60,8 +60,9 @@ ServerConfigDialog::ServerConfigDialog(QWidget* parent, ServerConfig& config, co
m_pCheckBoxEnableClipboard->setChecked(serverConfig().clipboardSharing());
- foreach(const Hotkey& hotkey, serverConfig().hotkeys())
+ for (const Hotkey& hotkey : serverConfig().hotkeys()) {
m_pListHotkeys->addItem(hotkey.text());
+ }
m_pScreenSetupView->setModel(&m_ScreenSetupModel);
@@ -75,7 +76,7 @@ void ServerConfigDialog::showEvent(QShowEvent* event)
if (!m_Message.isEmpty())
{
- // TODO: ideally this massage box should pop up after the dialog is shown
+ // TODO: ideally this message box should pop up after the dialog is shown
QMessageBox::information(this, tr("Configure server"), m_Message);
}
}
@@ -121,7 +122,7 @@ void ServerConfigDialog::on_m_pButtonNewHotkey_clicked()
HotkeyDialog dlg(this, hotkey);
if (dlg.exec() == QDialog::Accepted)
{
- serverConfig().hotkeys().append(hotkey);
+ serverConfig().hotkeys().push_back(hotkey);
m_pListHotkeys->addItem(hotkey.text());
}
}
@@ -140,7 +141,7 @@ void ServerConfigDialog::on_m_pButtonRemoveHotkey_clicked()
{
int idx = m_pListHotkeys->currentRow();
Q_ASSERT(idx >= 0 && idx < serverConfig().hotkeys().size());
- serverConfig().hotkeys().removeAt(idx);
+ serverConfig().hotkeys().erase(serverConfig().hotkeys().begin() + idx);
m_pListActions->clear();
delete m_pListHotkeys->item(idx);
}
@@ -168,8 +169,9 @@ void ServerConfigDialog::on_m_pListHotkeys_itemSelectionChanged()
Q_ASSERT(idx >= 0 && idx < serverConfig().hotkeys().size());
const Hotkey& hotkey = serverConfig().hotkeys()[idx];
- foreach(const Action& action, hotkey.actions())
+ for (const Action& action : hotkey.actions()) {
m_pListActions->addItem(action.text());
+ }
}
}
@@ -183,7 +185,7 @@ void ServerConfigDialog::on_m_pButtonNewAction_clicked()
ActionDialog dlg(this, serverConfig(), hotkey, action);
if (dlg.exec() == QDialog::Accepted)
{
- hotkey.actions().append(action);
+ hotkey.appendAction(action);
m_pListActions->addItem(action.text());
}
}
@@ -196,11 +198,13 @@ void ServerConfigDialog::on_m_pButtonEditAction_clicked()
int idxAction = m_pListActions->currentRow();
Q_ASSERT(idxAction >= 0 && idxAction < hotkey.actions().size());
- Action& action = hotkey.actions()[idxAction];
+ Action action = hotkey.actions()[idxAction];
ActionDialog dlg(this, serverConfig(), hotkey, action);
- if (dlg.exec() == QDialog::Accepted)
+ if (dlg.exec() == QDialog::Accepted) {
+ hotkey.setAction(idxAction, action);
m_pListActions->currentItem()->setText(action.text());
+ }
}
void ServerConfigDialog::on_m_pButtonRemoveAction_clicked()
@@ -212,7 +216,7 @@ void ServerConfigDialog::on_m_pButtonRemoveAction_clicked()
int idxAction = m_pListActions->currentRow();
Q_ASSERT(idxAction >= 0 && idxAction < hotkey.actions().size());
- hotkey.actions().removeAt(idxAction);
+ hotkey.removeAction(idxAction);
delete m_pListActions->currentItem();
}
diff --git a/src/gui/src/ServerConfigDialog.h b/src/gui/src/ServerConfigDialog.h
index 1ef17d1..91da51a 100644
--- a/src/gui/src/ServerConfigDialog.h
+++ b/src/gui/src/ServerConfigDialog.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -63,4 +63,3 @@ class ServerConfigDialog : public QDialog, public Ui::ServerConfigDialogBase
};
#endif
-
diff --git a/src/gui/src/SettingsDialog.cpp b/src/gui/src/SettingsDialog.cpp
index 24bb86c..8d01c77 100644
--- a/src/gui/src/SettingsDialog.cpp
+++ b/src/gui/src/SettingsDialog.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -48,8 +48,10 @@ SettingsDialog::SettingsDialog(QWidget* parent, AppConfig& config) :
m_pLineEditLogFilename->setText(appConfig().logFilename());
setIndexFromItemData(m_pComboLanguage, appConfig().language());
m_pCheckBoxAutoHide->setChecked(appConfig().getAutoHide());
+ m_pCheckBoxAutoStart->setChecked(appConfig().getAutoStart());
m_pCheckBoxMinimizeToTray->setChecked(appConfig().getMinimizeToTray());
m_pCheckBoxEnableCrypto->setChecked(m_appConfig.getCryptoEnabled());
+ checkbox_require_client_certificate->setChecked(m_appConfig.getRequireClientCertificate());
#if defined(Q_OS_WIN)
m_pComboElevate->setCurrentIndex(static_cast<int>(appConfig().elevateMode()));
@@ -66,12 +68,14 @@ void SettingsDialog::accept()
m_appConfig.setPort(m_pSpinBoxPort->value());
m_appConfig.setNetworkInterface(m_pLineEditInterface->text());
m_appConfig.setCryptoEnabled(m_pCheckBoxEnableCrypto->isChecked());
+ m_appConfig.setRequireClientCertificate(checkbox_require_client_certificate->isChecked());
m_appConfig.setLogLevel(m_pComboLogLevel->currentIndex());
m_appConfig.setLogToFile(m_pCheckBoxLogToFile->isChecked());
m_appConfig.setLogFilename(m_pLineEditLogFilename->text());
m_appConfig.setLanguage(m_pComboLanguage->itemData(m_pComboLanguage->currentIndex()).toString());
m_appConfig.setElevateMode(static_cast<ElevateMode>(m_pComboElevate->currentIndex()));
m_appConfig.setAutoHide(m_pCheckBoxAutoHide->isChecked());
+ m_appConfig.setAutoStart(m_pCheckBoxAutoStart->isChecked());
m_appConfig.setMinimizeToTray(m_pCheckBoxMinimizeToTray->isChecked());
m_appConfig.saveSettings();
QDialog::accept();
diff --git a/src/gui/src/SettingsDialog.h b/src/gui/src/SettingsDialog.h
index b733bcc..210b6c0 100644
--- a/src/gui/src/SettingsDialog.h
+++ b/src/gui/src/SettingsDialog.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/gui/src/SettingsDialogBase.ui b/src/gui/src/SettingsDialogBase.ui
index d75c18c..44ed98c 100644
--- a/src/gui/src/SettingsDialogBase.ui
+++ b/src/gui/src/SettingsDialogBase.ui
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>368</width>
- <height>380</height>
+ <height>428</height>
</rect>
</property>
<property name="windowTitle">
@@ -126,6 +126,13 @@
</property>
</widget>
</item>
+ <item row="5" column="0">
+ <widget class="QCheckBox" name="m_pCheckBoxAutoStart">
+ <property name="text">
+ <string>Start &amp;Barrier on startup</string>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
</item>
@@ -135,6 +142,16 @@
<string>Networking</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
+ <item row="1" column="0">
+ <widget class="QLabel" name="m_pLabel_21">
+ <property name="text">
+ <string>&amp;Address:</string>
+ </property>
+ <property name="buddy">
+ <cstring>m_pLineEditInterface</cstring>
+ </property>
+ </widget>
+ </item>
<item row="0" column="0">
<widget class="QLabel" name="m_pLabel_20">
<property name="text">
@@ -164,16 +181,6 @@
</property>
</widget>
</item>
- <item row="1" column="0">
- <widget class="QLabel" name="m_pLabel_21">
- <property name="text">
- <string>&amp;Address:</string>
- </property>
- <property name="buddy">
- <cstring>m_pLineEditInterface</cstring>
- </property>
- </widget>
- </item>
<item row="1" column="1">
<widget class="QLineEdit" name="m_pLineEditInterface">
<property name="enabled">
@@ -181,13 +188,20 @@
</property>
</widget>
</item>
- <item row="2" column="0">
+ <item row="2" column="0" colspan="2">
<widget class="QCheckBox" name="m_pCheckBoxEnableCrypto">
<property name="text">
<string>Enable &amp;SSL</string>
</property>
</widget>
</item>
+ <item row="3" column="0" colspan="2">
+ <widget class="QCheckBox" name="checkbox_require_client_certificate">
+ <property name="text">
+ <string>Require client certificate</string>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
</item>
@@ -209,19 +223,20 @@
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_2">
- <item row="0" column="0">
- <widget class="QLabel" name="m_pLabel_3">
- <property name="minimumSize">
- <size>
- <width>75</width>
- <height>0</height>
- </size>
- </property>
+ <item row="1" column="0">
+ <widget class="QCheckBox" name="m_pCheckBoxLogToFile">
<property name="text">
- <string>&amp;Logging level:</string>
+ <string>Log to file:</string>
</property>
- <property name="buddy">
- <cstring>m_pComboLogLevel</cstring>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <widget class="QPushButton" name="m_pButtonBrowseLog">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Browse...</string>
</property>
</widget>
</item>
@@ -264,10 +279,19 @@
</item>
</widget>
</item>
- <item row="1" column="0">
- <widget class="QCheckBox" name="m_pCheckBoxLogToFile">
+ <item row="0" column="0">
+ <widget class="QLabel" name="m_pLabel_3">
+ <property name="minimumSize">
+ <size>
+ <width>75</width>
+ <height>0</height>
+ </size>
+ </property>
<property name="text">
- <string>Log to file:</string>
+ <string>&amp;Logging level:</string>
+ </property>
+ <property name="buddy">
+ <cstring>m_pComboLogLevel</cstring>
</property>
</widget>
</item>
@@ -278,16 +302,6 @@
</property>
</widget>
</item>
- <item row="1" column="2">
- <widget class="QPushButton" name="m_pButtonBrowseLog">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="text">
- <string>Browse...</string>
- </property>
- </widget>
- </item>
</layout>
</widget>
</item>
@@ -322,6 +336,7 @@
<tabstop>m_pComboElevate</tabstop>
<tabstop>m_pCheckBoxMinimizeToTray</tabstop>
<tabstop>m_pCheckBoxAutoHide</tabstop>
+ <tabstop>m_pCheckBoxAutoStart</tabstop>
<tabstop>m_pSpinBoxPort</tabstop>
<tabstop>m_pLineEditInterface</tabstop>
<tabstop>m_pCheckBoxEnableCrypto</tabstop>
diff --git a/src/gui/src/SetupWizard.cpp b/src/gui/src/SetupWizard.cpp
index 0cfdb81..262d63c 100644
--- a/src/gui/src/SetupWizard.cpp
+++ b/src/gui/src/SetupWizard.cpp
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -14,7 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-
+
#include "SetupWizard.h"
#include "MainWindow.h"
#include "QBarrierApplication.h"
@@ -37,7 +37,7 @@ SetupWizard::SetupWizard(MainWindow& mainWindow, bool startMain) :
#elif defined(Q_OS_WIN)
- // when areo is disabled on windows, the next/back buttons
+ // when aero is disabled on windows, the next/back buttons
// are hidden (must be a qt bug) -- resizing the window
// to +1 of the original height seems to fix this.
// NOTE: calling setMinimumSize after this will break
@@ -58,7 +58,7 @@ SetupWizard::~SetupWizard()
}
bool SetupWizard::validateCurrentPage()
-{
+{
QMessageBox message;
message.setWindowTitle(tr("Setup Barrier"));
message.setIcon(QMessageBox::Information);
diff --git a/src/gui/src/SetupWizard.h b/src/gui/src/SetupWizard.h
index 80e19e9..73223b2 100644
--- a/src/gui/src/SetupWizard.h
+++ b/src/gui/src/SetupWizard.h
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/gui/src/ShutdownCh.h b/src/gui/src/ShutdownCh.h
index 2462cae..54ec84d 100644
--- a/src/gui/src/ShutdownCh.h
+++ b/src/gui/src/ShutdownCh.h
@@ -19,4 +19,3 @@
// included in both the GUI and the child apps (server & client)
const char ShutdownCh = 'S';
-
diff --git a/src/gui/src/SslCertificate.cpp b/src/gui/src/SslCertificate.cpp
index 80fdfc2..65ac08a 100644
--- a/src/gui/src/SslCertificate.cpp
+++ b/src/gui/src/SslCertificate.cpp
@@ -16,163 +16,111 @@
*/
#include "SslCertificate.h"
-#include "Fingerprint.h"
#include "common/DataDirectories.h"
+#include "base/finally.h"
+#include "io/filesystem.h"
+#include "net/FingerprintDatabase.h"
+#include "net/SecureUtils.h"
-#include <QProcess>
-#include <QDir>
-#include <QCoreApplication>
-
-static const char kCertificateLifetime[] = "365";
-static const char kCertificateSubjectInfo[] = "/CN=Barrier";
-static const char kCertificateFilename[] = "Barrier.pem";
-static const char kSslDir[] = "SSL";
-static const char kUnixOpenSslCommand[] = "openssl";
-
-#if defined(Q_OS_WIN)
-static const char kWinOpenSslBinary[] = "openssl.exe";
-static const char kConfigFile[] = "barrier.conf";
-#endif
+#include <openssl/bio.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+#include <openssl/x509.h>
SslCertificate::SslCertificate(QObject *parent) :
QObject(parent)
{
- m_ProfileDir = QString::fromStdString(DataDirectories::profile());
- if (m_ProfileDir.isEmpty()) {
+ if (barrier::DataDirectories::profile().empty()) {
emit error(tr("Failed to get profile directory."));
}
}
-bool SslCertificate::runTool(const QStringList& args)
+void SslCertificate::generateCertificate()
{
- QString program;
-#if defined(Q_OS_WIN)
- program = QCoreApplication::applicationDirPath();
- program.append("\\").append(kWinOpenSslBinary);
-#else
- program = kUnixOpenSslCommand;
-#endif
-
-
- QStringList environment;
-#if defined(Q_OS_WIN)
- environment << QString("OPENSSL_CONF=%1\\%2")
- .arg(QCoreApplication::applicationDirPath())
- .arg(kConfigFile);
-#endif
-
- QProcess process;
- process.setEnvironment(environment);
- process.start(program, args);
-
- bool success = process.waitForStarted();
-
- QString standardError;
- if (success && process.waitForFinished())
- {
- m_ToolOutput = process.readAllStandardOutput().trimmed();
- standardError = process.readAllStandardError().trimmed();
- }
+ auto cert_path = barrier::DataDirectories::ssl_certificate_path();
+
+ if (!barrier::fs::exists(cert_path) || !is_certificate_valid(cert_path)) {
+ try {
+ auto cert_dir = cert_path.parent_path();
+ if (!barrier::fs::exists(cert_dir)) {
+ barrier::fs::create_directories(cert_dir);
+ }
+
+ barrier::generate_pem_self_signed_cert(cert_path.u8string());
+ } catch (const std::exception& e) {
+ emit error(QString("SSL tool failed: %1").arg(e.what()));
+ return;
+ }
- int code = process.exitCode();
- if (!success || code != 0)
- {
- emit error(
- QString("SSL tool failed: %1\n\nCode: %2\nError: %3")
- .arg(program)
- .arg(process.exitCode())
- .arg(standardError.isEmpty() ? "Unknown" : standardError));
- return false;
+ emit info(tr("SSL certificate generated."));
}
- return true;
+ generate_fingerprint(cert_path);
+
+ emit generateFinished();
}
-void SslCertificate::generateCertificate()
+void SslCertificate::generate_fingerprint(const barrier::fs::path& cert_path)
{
- QString sslDirPath = QString("%1%2%3")
- .arg(m_ProfileDir)
- .arg(QDir::separator())
- .arg(kSslDir);
-
- QString filename = QString("%1%2%3")
- .arg(sslDirPath)
- .arg(QDir::separator())
- .arg(kCertificateFilename);
-
- QFile file(filename);
- if (!file.exists()) {
- QStringList arguments;
-
- // self signed certificate
- arguments.append("req");
- arguments.append("-x509");
- arguments.append("-nodes");
-
- // valide duration
- arguments.append("-days");
- arguments.append(kCertificateLifetime);
-
- // subject information
- arguments.append("-subj");
-
- QString subInfo(kCertificateSubjectInfo);
- arguments.append(subInfo);
-
- // private key
- arguments.append("-newkey");
- arguments.append("rsa:2048");
-
- QDir sslDir(sslDirPath);
- if (!sslDir.exists()) {
- sslDir.mkpath(".");
+ try {
+ auto local_path = barrier::DataDirectories::local_ssl_fingerprints_path();
+ auto local_dir = local_path.parent_path();
+ if (!barrier::fs::exists(local_dir)) {
+ barrier::fs::create_directories(local_dir);
}
- // key output filename
- arguments.append("-keyout");
- arguments.append(filename);
-
- // certificate output filename
- arguments.append("-out");
- arguments.append(filename);
+ barrier::FingerprintDatabase db;
+ db.add_trusted(barrier::get_pem_file_cert_fingerprint(cert_path.u8string(),
+ barrier::FingerprintType::SHA1));
+ db.add_trusted(barrier::get_pem_file_cert_fingerprint(cert_path.u8string(),
+ barrier::FingerprintType::SHA256));
+ db.write(local_path);
- if (!runTool(arguments)) {
- return;
- }
-
- emit info(tr("SSL certificate generated."));
+ emit info(tr("SSL fingerprint generated."));
+ } catch (const std::exception& e) {
+ emit error(tr("Failed to find SSL fingerprint.") + e.what());
}
-
- generateFingerprint(filename);
-
- emit generateFinished();
}
-void SslCertificate::generateFingerprint(const QString& certificateFilename)
+bool SslCertificate::is_certificate_valid(const barrier::fs::path& path)
{
- QStringList arguments;
- arguments.append("x509");
- arguments.append("-fingerprint");
- arguments.append("-sha1");
- arguments.append("-noout");
- arguments.append("-in");
- arguments.append(certificateFilename);
-
- if (!runTool(arguments)) {
- return;
+ OpenSSL_add_all_algorithms();
+ ERR_load_crypto_strings();
+
+ auto fp = barrier::fopen_utf8_path(path, "r");
+ if (!fp) {
+ emit info(tr("Could not read from default certificate file."));
+ return false;
}
+ auto file_close = barrier::finally([fp]() { std::fclose(fp); });
- // find the fingerprint from the tool output
- int i = m_ToolOutput.indexOf("=");
- if (i != -1) {
- i++;
- QString fingerprint = m_ToolOutput.mid(
- i, m_ToolOutput.size() - i);
+ auto* cert = PEM_read_X509(fp, nullptr, nullptr, nullptr);
+ if (!cert) {
+ emit info(tr("Error loading default certificate file to memory."));
+ return false;
+ }
+ auto cert_free = barrier::finally([cert]() { X509_free(cert); });
- Fingerprint::local().trust(fingerprint, false);
- emit info(tr("SSL fingerprint generated."));
+ auto* pubkey = X509_get_pubkey(cert);
+ if (!pubkey) {
+ emit info(tr("Default certificate key file does not contain valid public key"));
+ return false;
+ }
+ auto pubkey_free = barrier::finally([pubkey]() { EVP_PKEY_free(pubkey); });
+
+ auto type = EVP_PKEY_type(EVP_PKEY_id(pubkey));
+ if (type != EVP_PKEY_RSA && type != EVP_PKEY_DSA) {
+ emit info(tr("Public key in default certificate key file is not RSA or DSA"));
+ return false;
}
- else {
- emit error(tr("Failed to find SSL fingerprint."));
+
+ auto bits = EVP_PKEY_bits(pubkey);
+ if (bits < 2048) {
+ // We could have small keys in old barrier installations
+ emit info(tr("Public key in default certificate key file is too small."));
+ return false;
}
+
+ return true;
}
diff --git a/src/gui/src/SslCertificate.h b/src/gui/src/SslCertificate.h
index 8b20913..eae7fd6 100644
--- a/src/gui/src/SslCertificate.h
+++ b/src/gui/src/SslCertificate.h
@@ -18,10 +18,12 @@
#pragma once
#include <QObject>
+#include <string>
+#include "io/filesystem.h"
class SslCertificate : public QObject
{
-Q_OBJECT
+ Q_OBJECT
public:
explicit SslCertificate(QObject *parent = 0);
@@ -35,10 +37,7 @@ signals:
void generateFinished();
private:
- bool runTool(const QStringList& args);
- void generateFingerprint(const QString& certificateFilename);
+ void generate_fingerprint(const barrier::fs::path& cert_path);
-private:
- QString m_ProfileDir;
- QString m_ToolOutput;
+ bool is_certificate_valid(const barrier::fs::path& path);
};
diff --git a/src/gui/src/TrashScreenWidget.cpp b/src/gui/src/TrashScreenWidget.cpp
index 42a9d56..6f2abad 100644
--- a/src/gui/src/TrashScreenWidget.cpp
+++ b/src/gui/src/TrashScreenWidget.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -40,4 +40,3 @@ void TrashScreenWidget::dropEvent(QDropEvent* event)
else
event->ignore();
}
-
diff --git a/src/gui/src/TrashScreenWidget.h b/src/gui/src/TrashScreenWidget.h
index 7ab887e..967f73d 100644
--- a/src/gui/src/TrashScreenWidget.h
+++ b/src/gui/src/TrashScreenWidget.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -39,4 +39,3 @@ class TrashScreenWidget : public QLabel
};
#endif
-
diff --git a/src/gui/src/ZeroconfService.cpp b/src/gui/src/ZeroconfService.cpp
index 02902ee..fbb0ea1 100644
--- a/src/gui/src/ZeroconfService.cpp
+++ b/src/gui/src/ZeroconfService.cpp
@@ -66,7 +66,7 @@ ZeroconfService::ZeroconfService(MainWindow* mainWindow) :
m_ServiceRegistered(false)
{
silence_avahi_warning();
- if (m_pMainWindow->barrierType() == MainWindow::barrierServer) {
+ if (m_pMainWindow->barrier_type() == BarrierType::Server) {
if (registerService(true)) {
m_pZeroconfBrowser = new ZeroconfBrowser(this);
connect(m_pZeroconfBrowser, SIGNAL(
@@ -101,7 +101,7 @@ ZeroconfService::~ZeroconfService()
void ZeroconfService::serverDetected(const QList<ZeroconfRecord>& list)
{
- foreach (ZeroconfRecord record, list) {
+ for (ZeroconfRecord record : list) {
registerService(false);
m_pMainWindow->appendLogInfo(tr("zeroconf server detected: %1").arg(
record.serviceName));
@@ -111,7 +111,7 @@ void ZeroconfService::serverDetected(const QList<ZeroconfRecord>& list)
void ZeroconfService::clientDetected(const QList<ZeroconfRecord>& list)
{
- foreach (ZeroconfRecord record, list) {
+ for (ZeroconfRecord record : list) {
m_pMainWindow->appendLogInfo(tr("zeroconf client detected: %1").arg(
record.serviceName));
m_pMainWindow->autoAddScreen(record.serviceName);
@@ -127,15 +127,15 @@ void ZeroconfService::errorHandle(DNSServiceErrorType errorCode)
QString ZeroconfService::getLocalIPAddresses()
{
QStringList addresses;
- foreach (const QHostAddress& address, QNetworkInterface::allAddresses()) {
+ for (const QHostAddress& address : QNetworkInterface::allAddresses()) {
if (address.protocol() == QAbstractSocket::IPv4Protocol &&
address != QHostAddress(QHostAddress::LocalHost)) {
addresses.append(address.toString());
}
}
- foreach (const QString& preferedIP, preferedIPAddress) {
- foreach (const QString& address, addresses) {
+ for (const QString& preferedIP : preferedIPAddress) {
+ for (const QString& address : addresses) {
if (address.startsWith(preferedIP)) {
return address;
}
diff --git a/src/gui/src/main.cpp b/src/gui/src/main.cpp
index 73251d5..776b44d 100644
--- a/src/gui/src/main.cpp
+++ b/src/gui/src/main.cpp
@@ -97,6 +97,12 @@ int main(int argc, char* argv[])
QApplication::setQuitOnLastWindowClosed(false);
+ if (QGuiApplication::platformName() == "wayland") {
+ QMessageBox::warning(
+ NULL, "Barrier",
+ "You are using wayland session, which is currently not fully supported by Barrier.");
+ }
+
QSettings settings;
AppConfig appConfig (&settings);
diff --git a/src/gui/test/HotkeyTests.cpp b/src/gui/test/HotkeyTests.cpp
new file mode 100644
index 0000000..7607dfb
--- /dev/null
+++ b/src/gui/test/HotkeyTests.cpp
@@ -0,0 +1,320 @@
+/* barrier -- mouse and keyboard sharing utility
+ Copyright (C) 2021 Povilas Kanapickas <povilas@radix.lt>
+
+ This package is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ found in the file LICENSE that should have accompanied this file.
+
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "../src/Hotkey.h"
+#include <gtest/gtest.h>
+#include "Utils.h"
+
+#include <QtCore/QSettings>
+#include <QtCore/QTextStream>
+
+struct TestAction
+{
+ Action::ActionType type = Action::keyDown;
+ std::vector<TestKey> keys;
+ std::vector<std::string> type_screen_names;
+ std::string screen_name;
+ Action::SwitchDirection switch_direction;
+ Action::LockCursorMode lock_cursor_mode;
+
+ static TestAction createKeyAction(Action::ActionType type, const std::vector<TestKey>& keys,
+ const std::vector<std::string>& type_screen_names = {})
+ {
+ TestAction action;
+ action.type = Action::keyDown;
+ action.keys = keys;
+ action.type_screen_names = type_screen_names;
+ return action;
+ }
+
+ static TestAction createKeyDown(const std::vector<TestKey>& keys,
+ const std::vector<std::string>& type_screen_names = {})
+ {
+ return createKeyAction(Action::keyDown, keys, type_screen_names);
+ }
+
+ static TestAction createKeyUp(const std::vector<TestKey>& keys,
+ const std::vector<std::string>& type_screen_names = {})
+ {
+ return createKeyAction(Action::keyUp, keys, type_screen_names);
+ }
+
+ static TestAction createKeyStroke(const std::vector<TestKey>& keys,
+ const std::vector<std::string>& type_screen_names = {})
+ {
+ return createKeyAction(Action::keystroke, keys, type_screen_names);
+ }
+
+ static TestAction createSwitchToScreen(const std::string& screen_name)
+ {
+ TestAction action;
+ action.type = Action::switchToScreen;
+ action.screen_name = screen_name;
+ return action;
+ }
+
+ static TestAction createToggleScreen()
+ {
+ TestAction action;
+ action.type = Action::toggleScreen;
+ return action;
+ }
+
+ static TestAction createSwitchInDirection(Action::SwitchDirection switch_direction)
+ {
+ TestAction action;
+ action.type = Action::switchInDirection;
+ action.switch_direction = switch_direction;
+ return action;
+ }
+
+ static TestAction createLockCursorToScreen(Action::LockCursorMode lock_cursor_mode)
+ {
+ TestAction action;
+ action.type = Action::lockCursorToScreen;
+ action.lock_cursor_mode = lock_cursor_mode;
+ return action;
+ }
+};
+
+struct TestHotKey
+{
+ std::vector<TestKey> keys;
+ std::vector<TestAction> actions;
+};
+
+namespace {
+
+ Action createAction(const TestAction& test_action)
+ {
+ Action action;
+ action.setType(test_action.type);
+
+ switch (test_action.type) {
+ case Action::keyDown:
+ case Action::keyUp:
+ case Action::keystroke: {
+ KeySequence sequence;
+ for (auto key : test_action.keys) {
+ sequence.appendKey(key.key, key.modifier);
+ }
+ action.setKeySequence(sequence);
+ for (const auto& type_screen_name : test_action.type_screen_names) {
+ action.appendTypeScreenName(QString::fromStdString(type_screen_name));
+ }
+ break;
+ }
+ case Action::switchToScreen:
+ action.setSwitchScreenName(QString::fromStdString(test_action.screen_name));
+ break;
+ case Action::toggleScreen:
+ break;
+ case Action::switchInDirection:
+ action.setSwitchDirection(test_action.switch_direction);
+ break;
+ case Action::lockCursorToScreen:
+ action.setLockCursorMode(test_action.lock_cursor_mode);
+ break;
+ }
+ return action;
+ }
+
+ Hotkey createHotkey(const TestHotKey& test_hotkey)
+ {
+ Hotkey hotkey;
+ KeySequence sequence;
+ for (auto key : test_hotkey.keys) {
+ sequence.appendKey(key.key, key.modifier);
+ }
+ hotkey.setKeySequence(sequence);
+
+ for (auto action : test_hotkey.actions) {
+ hotkey.appendAction(createAction(action));
+ }
+ return hotkey;
+ }
+
+ std::string hotkeyToStringViaTextStream(const Hotkey& hotkey)
+ {
+ QString result;
+ QTextStream stream{&result};
+ stream << hotkey;
+ return result.toStdString();
+ }
+} // namespace
+
+void doHotkeyLoadSaveTest(const TestHotKey& test_hotkey)
+{
+ auto filename = getTemporaryFilename();
+
+ Hotkey hotkey_before, hotkey_after;
+ {
+ QSettings settings(filename, QSettings::NativeFormat);
+
+ hotkey_before = createHotkey(test_hotkey);
+
+ settings.beginGroup("test");
+ hotkey_before.saveSettings(settings);
+ settings.endGroup();
+ }
+ {
+ QSettings settings(filename, QSettings::NativeFormat);
+
+ settings.beginGroup("test");
+ hotkey_after.loadSettings(settings);
+ settings.endGroup();
+
+ ASSERT_EQ(hotkey_before.keySequence().sequence(), hotkey_after.keySequence().sequence());
+ ASSERT_EQ(hotkey_before.keySequence().modifiers(), hotkey_after.keySequence().modifiers());
+
+ const auto& actions_before = hotkey_before.actions();
+ const auto& actions_after = hotkey_after.actions();
+
+ ASSERT_EQ(actions_before.size(), actions_after.size());
+ for (int i = 0; i < actions_before.size(); ++i) {
+ const auto& action_before = actions_before[i];
+ const auto& action_after = actions_after[i];
+
+ ASSERT_EQ(action_before.keySequence().sequence(), action_after.keySequence().sequence());
+ ASSERT_EQ(action_before.keySequence().modifiers(), action_after.keySequence().modifiers());
+ ASSERT_EQ(action_before.type(), action_after.type());
+ ASSERT_EQ(action_before.typeScreenNames(), action_after.typeScreenNames());
+ ASSERT_EQ(action_before.switchScreenName(), action_after.switchScreenName());
+ ASSERT_EQ(action_before.switchDirection(), action_after.switchDirection());
+ ASSERT_EQ(action_before.lockCursorMode(), action_after.lockCursorMode());
+ ASSERT_EQ(action_before.activeOnRelease(), action_after.activeOnRelease());
+ ASSERT_EQ(action_before.haveScreens(), action_after.haveScreens());
+ }
+ }
+
+ QFile::remove(filename);
+}
+
+TEST(HotkeyLoadSaveTests, Empty)
+{
+ TestHotKey hotkey;
+ doHotkeyLoadSaveTest(hotkey);
+}
+
+TEST(HotkeyLoadSaveTests, KeysNoActions)
+{
+ TestHotKey hotkey = {{{Qt::Key_A, Qt::NoModifier}, {Qt::Key_B, Qt::NoModifier}}, {}};
+ doHotkeyLoadSaveTest(hotkey);
+}
+
+TEST(HotkeyLoadSaveTests, CommaKeyNoActions)
+{
+ TestHotKey hotkey = {
+ {
+ {Qt::Key_A, Qt::NoModifier},
+ {Qt::Key_Comma, Qt::NoModifier},
+ {Qt::Key_B, Qt::NoModifier}
+ }, {}};
+ doHotkeyLoadSaveTest(hotkey);
+}
+
+TEST(HotkeyLoadSaveTests, KeysSingleAction)
+{
+ TestHotKey hotkey = {
+ {
+ {Qt::Key_A, Qt::NoModifier},
+ {Qt::Key_B, Qt::NoModifier}
+ },
+ {
+ TestAction::createKeyDown({{Qt::Key_Z, Qt::NoModifier}})
+ }
+ };
+ doHotkeyLoadSaveTest(hotkey);
+}
+
+TEST(HotkeyLoadSaveTests, KeysMultipleAction)
+{
+ TestHotKey hotkey = {
+ {
+ {Qt::Key_A, Qt::NoModifier},
+ {Qt::Key_B, Qt::NoModifier}
+ },
+ {
+ TestAction::createKeyDown({{Qt::Key_Z, Qt::NoModifier}}),
+ TestAction::createSwitchToScreen("test_screen")
+ }
+ };
+ doHotkeyLoadSaveTest(hotkey);
+}
+
+TEST(HotkeyToTexStreamTests, Empty)
+{
+ TestHotKey hotkey;
+ ASSERT_EQ(hotkeyToStringViaTextStream(createHotkey(hotkey)), "");
+}
+
+TEST(HotkeyToTexStreamTests, KeysNoActions)
+{
+ TestHotKey hotkey = {
+ {
+ {Qt::Key_A, Qt::NoModifier},
+ {Qt::Key_B, Qt::NoModifier}
+ },
+ {}
+ };
+ ASSERT_EQ(hotkeyToStringViaTextStream(createHotkey(hotkey)), "");
+}
+
+TEST(HotkeyToTexStreamTests, KeysSingleAction)
+{
+ TestHotKey hotkey = {
+ {
+ {Qt::Key_A, Qt::NoModifier},
+ {Qt::Key_B, Qt::NoModifier}
+ },
+ {}
+ };
+ ASSERT_EQ(hotkeyToStringViaTextStream(createHotkey(hotkey)), "");
+}
+
+
+TEST(HotkeyToTexStreamTests, KeysCommaSingleAction)
+{
+ TestHotKey hotkey = {
+ {
+ {Qt::Key_A, Qt::NoModifier},
+ {Qt::Key_Comma, Qt::NoModifier},
+ {Qt::Key_B, Qt::NoModifier}
+ },
+ {
+ TestAction::createKeyDown({{Qt::Key_Z, Qt::NoModifier}})
+ }
+ };
+ ASSERT_EQ(hotkeyToStringViaTextStream(createHotkey(hotkey)),
+ "\tkeystroke(a+Comma+b) = keyDown(z,*)\n");
+}
+
+TEST(HotkeyToTexStreamTests, KeysMultipleAction)
+{
+ TestHotKey hotkey = {
+ {
+ {Qt::Key_A, Qt::NoModifier},
+ {Qt::Key_B, Qt::NoModifier}
+ },
+ {
+ TestAction::createKeyDown({{Qt::Key_Z, Qt::NoModifier}}),
+ TestAction::createSwitchToScreen("test_screen")
+ }
+ };
+ ASSERT_EQ(hotkeyToStringViaTextStream(createHotkey(hotkey)),
+ "\tkeystroke(a+b) = keyDown(z,*), switchToScreen(test_screen)\n");
+}
diff --git a/src/gui/test/KeySequenceTests.cpp b/src/gui/test/KeySequenceTests.cpp
new file mode 100644
index 0000000..9fa9273
--- /dev/null
+++ b/src/gui/test/KeySequenceTests.cpp
@@ -0,0 +1,145 @@
+/* barrier -- mouse and keyboard sharing utility
+ Copyright (C) 2021 Povilas Kanapickas <povilas@radix.lt>
+
+ This package is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ found in the file LICENSE that should have accompanied this file.
+
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "../src/KeySequence.h"
+#include "Utils.h"
+#include <gtest/gtest.h>
+#include <cstdio>
+
+#include <QtCore/QFile>
+#include <QtCore/QSettings>
+#include <QtCore/QTemporaryFile>
+
+namespace {
+
+ auto s_key_sequence_test_keys = {
+ Qt::Key_Space,
+ Qt::Key_Escape,
+ Qt::Key_Tab,
+ Qt::Key_Backtab,
+ Qt::Key_Backspace,
+ Qt::Key_Return,
+ Qt::Key_Insert,
+ Qt::Key_Delete,
+ Qt::Key_Pause,
+ Qt::Key_Print,
+ Qt::Key_SysReq,
+ Qt::Key_Home,
+ Qt::Key_End,
+ Qt::Key_Left,
+ Qt::Key_Up,
+ Qt::Key_Right,
+ Qt::Key_Down,
+ Qt::Key_Comma,
+ Qt::Key_Semicolon,
+ Qt::Key_PageUp,
+ Qt::Key_PageDown,
+ Qt::Key_CapsLock,
+ Qt::Key_NumLock,
+ Qt::Key_ScrollLock,
+ Qt::Key_Help,
+ Qt::Key_Enter,
+ Qt::Key_Clear,
+ Qt::Key_Back,
+ Qt::Key_Forward,
+ Qt::Key_Stop,
+ Qt::Key_Refresh,
+ Qt::Key_VolumeDown,
+ Qt::Key_VolumeMute,
+ Qt::Key_VolumeUp,
+ Qt::Key_MediaPlay,
+ Qt::Key_MediaStop,
+ Qt::Key_MediaPrevious,
+ Qt::Key_MediaNext,
+ Qt::Key_HomePage,
+ Qt::Key_Favorites,
+ Qt::Key_Search,
+ Qt::Key_Standby,
+ Qt::Key_LaunchMail,
+ Qt::Key_LaunchMedia,
+ Qt::Key_Launch0,
+ Qt::Key_Launch1,
+ Qt::Key_Select,
+ };
+
+ std::string keySequenceToString(const std::vector<TestKey>& key_pairs)
+ {
+ KeySequence sequence;
+ for (auto key_pair : key_pairs) {
+ sequence.appendKey(key_pair.key, key_pair.modifier);
+ }
+ return sequence.toString().toStdString();
+ }
+} // namespace
+
+class KeySequenceLoadSaveTestFixture :
+ public ::testing::TestWithParam<Qt::Key> {};
+
+TEST_P(KeySequenceLoadSaveTestFixture, SupportsSpecialSymbols)
+{
+ int key = GetParam();
+
+ auto filename = getTemporaryFilename();
+
+ {
+ QSettings settings(filename, QSettings::NativeFormat);
+ KeySequence sequence;
+
+ sequence.appendKey(key, 0);
+ sequence.appendKey(key, 0);
+ settings.beginGroup("test");
+ sequence.saveSettings(settings);
+ settings.endGroup();
+ }
+ {
+ QSettings settings(filename, QSettings::NativeFormat);
+ KeySequence sequence;
+
+ settings.beginGroup("test");
+ sequence.loadSettings(settings);
+ settings.endGroup();
+
+ const auto& data = sequence.sequence();
+ ASSERT_EQ(data.size(), 2);
+ ASSERT_EQ(data[0], key);
+ ASSERT_EQ(data[1], key);
+ }
+
+ QFile::remove(filename);
+}
+
+INSTANTIATE_TEST_CASE_P(
+ KeySequenceLoadSaveTests,
+ KeySequenceLoadSaveTestFixture,
+ ::testing::ValuesIn(s_key_sequence_test_keys));
+
+TEST(KeySequenceTests, ToString)
+{
+ ASSERT_EQ(keySequenceToString({{Qt::Key_Menu, Qt::MetaModifier}}),
+ "Meta");
+ ASSERT_EQ(keySequenceToString({{Qt::Key_A, 0}, {Qt::Key_B, 0}}),
+ "a+b");
+ ASSERT_EQ(keySequenceToString({{Qt::Key_A, 0}, {Qt::Key_Comma, 0}, {Qt::Key_B, 0}}),
+ "a+Comma+b");
+ ASSERT_EQ(keySequenceToString({{Qt::Key_A, 0}, {Qt::Key_Semicolon, 0}, {Qt::Key_B, 0}}),
+ "a+Semicolon+b");
+ ASSERT_EQ(keySequenceToString({{Qt::Key_A, 0}, {Qt::Key_Shift, Qt::ShiftModifier},
+ {Qt::Key_0, Qt::ShiftModifier}}),
+ "a+Shift+0");
+ ASSERT_EQ(keySequenceToString({{Qt::Key_A, 0}, {Qt::Key_Control, Qt::ControlModifier},
+ {Qt::Key_0, Qt::ControlModifier}}),
+ "a+Control+0");
+}
diff --git a/src/gui/test/Utils.h b/src/gui/test/Utils.h
new file mode 100644
index 0000000..da66ce7
--- /dev/null
+++ b/src/gui/test/Utils.h
@@ -0,0 +1,38 @@
+/* barrier -- mouse and keyboard sharing utility
+ Copyright (C) 2021 Povilas Kanapickas <povilas@radix.lt>
+
+ This package is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ found in the file LICENSE that should have accompanied this file.
+
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef BARRIER_GUI_TEST_UTILS_H
+#define BARRIER_GUI_TEST_UTILS_H
+
+#include <QtCore/QFile>
+#include <QtCore/QTemporaryFile>
+
+struct TestKey
+{
+ int key = 0;
+ int modifier = Qt::NoModifier;
+
+ TestKey(int key, int modifier) : key{key}, modifier{modifier} {}
+};
+
+inline QString getTemporaryFilename()
+{
+ QTemporaryFile temp_file;
+ temp_file.open();
+ return temp_file.fileName();
+}
+
+#endif // BARRIER_GUI_TEST_UTILS_H
diff --git a/src/gui/test/main.cpp b/src/gui/test/main.cpp
new file mode 100644
index 0000000..b57dd76
--- /dev/null
+++ b/src/gui/test/main.cpp
@@ -0,0 +1,23 @@
+/* barrier -- mouse and keyboard sharing utility
+ Copyright (C) 2021 Povilas Kanapickas <povilas@radix.lt>
+
+ This package is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ found in the file LICENSE that should have accompanied this file.
+
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <gtest/gtest.h>
+
+int main(int argc, char **argv)
+{
+ testing::InitGoogleTest(&argc, argv);
+ return (RUN_ALL_TESTS() == 1) ? 1 : 0;
+}
diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt
index 70a0629..fdec71c 100644
--- a/src/lib/CMakeLists.txt
+++ b/src/lib/CMakeLists.txt
@@ -1,11 +1,11 @@
# barrier -- mouse and keyboard sharing utility
# Copyright (C) 2012-2016 Symless Ltd.
# Copyright (C) 2009 Nick Bolton
-#
+#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
-#
+#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/Arch.cpp b/src/lib/arch/Arch.cpp
index 0a3b3e5..810b74f 100644
--- a/src/lib/arch/Arch.cpp
+++ b/src/lib/arch/Arch.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/Arch.h b/src/lib/arch/Arch.h
index 940a2e3..3b37617 100644
--- a/src/lib/arch/Arch.h
+++ b/src/lib/arch/Arch.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/ArchConsoleStd.cpp b/src/lib/arch/ArchConsoleStd.cpp
index f7f7691..2e188bb 100644
--- a/src/lib/arch/ArchConsoleStd.cpp
+++ b/src/lib/arch/ArchConsoleStd.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -30,4 +30,4 @@ ArchConsoleStd::writeConsole(ELevel level, const char* str)
std::cout << str << std::endl;
std::cout.flush();
-} \ No newline at end of file
+}
diff --git a/src/lib/arch/ArchConsoleStd.h b/src/lib/arch/ArchConsoleStd.h
index 8560fad..1d306e7 100644
--- a/src/lib/arch/ArchConsoleStd.h
+++ b/src/lib/arch/ArchConsoleStd.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/ArchDaemonNone.cpp b/src/lib/arch/ArchDaemonNone.cpp
index 1222549..5cb4681 100644
--- a/src/lib/arch/ArchDaemonNone.cpp
+++ b/src/lib/arch/ArchDaemonNone.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/ArchDaemonNone.h b/src/lib/arch/ArchDaemonNone.h
index e02405f..425ae56 100644
--- a/src/lib/arch/ArchDaemonNone.h
+++ b/src/lib/arch/ArchDaemonNone.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/CMakeLists.txt b/src/lib/arch/CMakeLists.txt
index db92634..5ff7b51 100644
--- a/src/lib/arch/CMakeLists.txt
+++ b/src/lib/arch/CMakeLists.txt
@@ -1,11 +1,11 @@
# barrier -- mouse and keyboard sharing utility
# Copyright (C) 2012-2016 Symless Ltd.
# Copyright (C) 2009 Nick Bolton
-#
+#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
-#
+#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/IArchConsole.h b/src/lib/arch/IArchConsole.h
index d115c50..41e3527 100644
--- a/src/lib/arch/IArchConsole.h
+++ b/src/lib/arch/IArchConsole.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/IArchDaemon.h b/src/lib/arch/IArchDaemon.h
index 23a34f2..6a4fb67 100644
--- a/src/lib/arch/IArchDaemon.h
+++ b/src/lib/arch/IArchDaemon.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -64,7 +64,7 @@ public:
Installs the default daemon.
*/
virtual void installDaemon() = 0;
-
+
//! Uninstall daemon
/*!
Uninstalls the default daemon.
@@ -76,7 +76,7 @@ public:
Daemonize. Throw XArchDaemonFailed on error. \c name is the name
of the daemon. Once daemonized, \c func is invoked and daemonize
returns when and what it does.
-
+
Exactly what happens when daemonizing depends on the platform.
<ul>
<li>unix:
diff --git a/src/lib/arch/IArchLog.h b/src/lib/arch/IArchLog.h
index 165b1df..704ad47 100644
--- a/src/lib/arch/IArchLog.h
+++ b/src/lib/arch/IArchLog.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/IArchMultithread.h b/src/lib/arch/IArchMultithread.h
index e8d358b..6a57694 100644
--- a/src/lib/arch/IArchMultithread.h
+++ b/src/lib/arch/IArchMultithread.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -19,8 +19,9 @@
#pragma once
#include "common/IInterface.h"
+#include <functional>
-/*!
+/*!
\class ArchCondImpl
\brief Internal condition variable data.
An architecture dependent type holding the necessary data for a
@@ -28,35 +29,35 @@ condition variable.
*/
class ArchCondImpl;
-/*!
+/*!
\var ArchCond
\brief Opaque condition variable type.
An opaque type representing a condition variable.
*/
typedef ArchCondImpl* ArchCond;
-/*!
+/*!
\class ArchMutexImpl
\brief Internal mutex data.
An architecture dependent type holding the necessary data for a mutex.
*/
class ArchMutexImpl;
-/*!
+/*!
\var ArchMutex
\brief Opaque mutex type.
An opaque type representing a mutex.
*/
typedef ArchMutexImpl* ArchMutex;
-/*!
+/*!
\class ArchThreadImpl
\brief Internal thread data.
An architecture dependent type holding the necessary data for a thread.
*/
class ArchThreadImpl;
-/*!
+/*!
\var ArchThread
\brief Opaque thread type.
An opaque type representing a thread.
@@ -71,7 +72,7 @@ barrier. Each architecture must implement this interface.
class IArchMultithread : public IInterface {
public:
//! Type of thread entry point
- typedef void* (*ThreadFunc)(void*);
+ typedef void (*ThreadFunc)(void*);
//! Type of thread identifier
typedef unsigned int ThreadID;
//! Types of signals
@@ -160,7 +161,7 @@ public:
Creates and starts a new thread, using \c func as the entry point
and passing it \c userData. The thread is an opaque data type.
*/
- virtual ArchThread newThread(ThreadFunc func, void* userData) = 0;
+ virtual ArchThread newThread(const std::function<void()>& func) = 0;
//! Get a reference to the calling thread
/*!
@@ -235,15 +236,6 @@ public:
*/
virtual bool isExitedThread(ArchThread thread) = 0;
- //! Returns the exit code of a thread
- /*!
- Waits indefinitely for \c thread to exit (if it hasn't yet) then
- returns the thread's exit code.
-
- (Cancellation point)
- */
- virtual void* getResultOfThread(ArchThread thread) = 0;
-
//! Returns an ID for a thread
/*!
Returns some ID number for \c thread. This is for logging purposes.
diff --git a/src/lib/arch/IArchNetwork.h b/src/lib/arch/IArchNetwork.h
index b859506..7eae63e 100644
--- a/src/lib/arch/IArchNetwork.h
+++ b/src/lib/arch/IArchNetwork.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -24,21 +24,21 @@
class ArchThreadImpl;
typedef ArchThreadImpl* ArchThread;
-/*!
+/*!
\class ArchSocketImpl
\brief Internal socket data.
An architecture dependent type holding the necessary data for a socket.
*/
class ArchSocketImpl;
-/*!
+/*!
\var ArchSocket
\brief Opaque socket type.
An opaque type representing a socket.
*/
typedef ArchSocketImpl* ArchSocket;
-/*!
+/*!
\class ArchNetAddressImpl
\brief Internal network address data.
An architecture dependent type holding the necessary data for a network
@@ -46,7 +46,7 @@ address.
*/
class ArchNetAddressImpl;
-/*!
+/*!
\var ArchNetAddress
\brief Opaque network address type.
An opaque type representing a network address.
diff --git a/src/lib/arch/IArchSleep.h b/src/lib/arch/IArchSleep.h
index 9999d0e..86c571f 100644
--- a/src/lib/arch/IArchSleep.h
+++ b/src/lib/arch/IArchSleep.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/IArchString.cpp b/src/lib/arch/IArchString.cpp
index 0f7f300..b1118ec 100644
--- a/src/lib/arch/IArchString.cpp
+++ b/src/lib/arch/IArchString.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2011 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/IArchString.h b/src/lib/arch/IArchString.h
index ea10b65..f1803d8 100644
--- a/src/lib/arch/IArchString.h
+++ b/src/lib/arch/IArchString.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -46,16 +46,6 @@ public:
//! @name manipulators
//@{
- //! printf() to limited size buffer with va_list
- /*!
- This method is equivalent to vsprintf() except it will not write
- more than \c n bytes to the buffer, returning -1 if the output
- was truncated and the number of bytes written not including the
- trailing NUL otherwise.
- */
- virtual int vsnprintf(char* str,
- int size, const char* fmt, va_list ap);
-
//! Convert multibyte string to wide character string
virtual int convStringMBToWC(wchar_t*,
const char*, UInt32 n, bool* errors);
diff --git a/src/lib/arch/IArchSystem.h b/src/lib/arch/IArchSystem.h
index 9446505..3e7aa98 100644
--- a/src/lib/arch/IArchSystem.h
+++ b/src/lib/arch/IArchSystem.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/IArchTaskBar.h b/src/lib/arch/IArchTaskBar.h
index 85a32d8..fc5f0d0 100644
--- a/src/lib/arch/IArchTaskBar.h
+++ b/src/lib/arch/IArchTaskBar.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2003 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/IArchTaskBarReceiver.h b/src/lib/arch/IArchTaskBarReceiver.h
index 997c8ae..b4f0d30 100644
--- a/src/lib/arch/IArchTaskBarReceiver.h
+++ b/src/lib/arch/IArchTaskBarReceiver.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2003 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/IArchTime.h b/src/lib/arch/IArchTime.h
index abb3cdd..297aab7 100644
--- a/src/lib/arch/IArchTime.h
+++ b/src/lib/arch/IArchTime.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/XArch.h b/src/lib/arch/XArch.h
index 8484d06..2fcf686 100644
--- a/src/lib/arch/XArch.h
+++ b/src/lib/arch/XArch.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -57,7 +57,7 @@ class XArchEval {
public:
XArchEval() { }
virtual ~XArchEval() noexcept { }
-
+
virtual std::string eval() const = 0;
};
diff --git a/src/lib/arch/multibyte.h b/src/lib/arch/multibyte.h
index 4a4e0ec..7812e0b 100644
--- a/src/lib/arch/multibyte.h
+++ b/src/lib/arch/multibyte.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/unix/ArchConsoleUnix.cpp b/src/lib/arch/unix/ArchConsoleUnix.cpp
index 79a4634..d5e8e1d 100644
--- a/src/lib/arch/unix/ArchConsoleUnix.cpp
+++ b/src/lib/arch/unix/ArchConsoleUnix.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/unix/ArchConsoleUnix.h b/src/lib/arch/unix/ArchConsoleUnix.h
index 8326ab5..136c606 100644
--- a/src/lib/arch/unix/ArchConsoleUnix.h
+++ b/src/lib/arch/unix/ArchConsoleUnix.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/unix/ArchDaemonUnix.cpp b/src/lib/arch/unix/ArchDaemonUnix.cpp
index a03bf7a..f1ac1d5 100644
--- a/src/lib/arch/unix/ArchDaemonUnix.cpp
+++ b/src/lib/arch/unix/ArchDaemonUnix.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -53,15 +53,15 @@ execSelfNonDaemonized()
{
extern char** NXArgv;
char** selfArgv = NXArgv;
-
+
setenv("_BARRIER_DAEMONIZED", "", 1);
-
+
execvp(selfArgv[0], selfArgv);
return 0;
}
bool alreadyDaemonized() {
- return getenv("_BARRIER_DAEMONIZED") != NULL;
+ return std::getenv("_BARRIER_DAEMONIZED") != NULL;
}
#endif
@@ -73,7 +73,7 @@ ArchDaemonUnix::daemonize(const char* name, DaemonFunc func)
if (alreadyDaemonized())
return func(1, &name);
#endif
-
+
// fork so shell thinks we're done and so we're not a process
// group leader
switch (fork()) {
@@ -92,7 +92,7 @@ ArchDaemonUnix::daemonize(const char* name, DaemonFunc func)
// become leader of a new session
setsid();
-
+
#ifndef __APPLE__
// NB: don't run chdir on apple; causes strange behaviour.
// chdir to root so we don't keep mounted filesystems points busy
@@ -115,18 +115,18 @@ ArchDaemonUnix::daemonize(const char* name, DaemonFunc func)
// of standard I/O safely goes in the bit bucket.
open("/dev/null", O_RDONLY);
open("/dev/null", O_RDWR);
-
+
int dupErr = dup(1);
if (dupErr < 0) {
// NB: file logging actually isn't working at this point!
LOG((CLOG_ERR "dup error: %i", dupErr));
}
-
+
#ifdef __APPLE__
return execSelfNonDaemonized();
#endif
-
+
// invoke function
return func(1, &name);
}
diff --git a/src/lib/arch/unix/ArchDaemonUnix.h b/src/lib/arch/unix/ArchDaemonUnix.h
index 530159a..52a531e 100644
--- a/src/lib/arch/unix/ArchDaemonUnix.h
+++ b/src/lib/arch/unix/ArchDaemonUnix.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/unix/ArchInternetUnix.cpp b/src/lib/arch/unix/ArchInternetUnix.cpp
index 76966dc..dcea2ae 100644
--- a/src/lib/arch/unix/ArchInternetUnix.cpp
+++ b/src/lib/arch/unix/ArchInternetUnix.cpp
@@ -94,16 +94,16 @@ std::string CurlFacade::get(const std::string& url)
userAgent << "Barrier ";
userAgent << kVersion;
curl_easy_setopt(m_curl, CURLOPT_USERAGENT, userAgent.str().c_str());
-
+
std::string result;
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &result);
-
+
CURLcode code = curl_easy_perform(m_curl);
if (code != CURLE_OK) {
LOG((CLOG_ERR "curl perform error: %s", curl_easy_strerror(code)));
throw XArch("CURL perform failed.");
}
-
+
return result;
}
@@ -114,7 +114,7 @@ std::string CurlFacade::urlEncode(const std::string& url)
if (resultCStr == NULL) {
throw XArch("CURL escape failed.");
}
-
+
std::string result(resultCStr);
curl_free(resultCStr);
diff --git a/src/lib/arch/unix/ArchLogUnix.cpp b/src/lib/arch/unix/ArchLogUnix.cpp
index b1f9089..2389f48 100644
--- a/src/lib/arch/unix/ArchLogUnix.cpp
+++ b/src/lib/arch/unix/ArchLogUnix.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/unix/ArchLogUnix.h b/src/lib/arch/unix/ArchLogUnix.h
index cdd733f..f37bab8 100644
--- a/src/lib/arch/unix/ArchLogUnix.h
+++ b/src/lib/arch/unix/ArchLogUnix.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/unix/ArchMultithreadPosix.cpp b/src/lib/arch/unix/ArchMultithreadPosix.cpp
index 4866edc..8400f9d 100644
--- a/src/lib/arch/unix/ArchMultithreadPosix.cpp
+++ b/src/lib/arch/unix/ArchMultithreadPosix.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -59,24 +59,19 @@ public:
int m_refCount;
IArchMultithread::ThreadID m_id;
pthread_t m_thread;
- IArchMultithread::ThreadFunc m_func;
- void* m_userData;
+ std::function<void()> func_;;
bool m_cancel;
bool m_cancelling;
bool m_exited;
- void* m_result;
void* m_networkData;
};
ArchThreadImpl::ArchThreadImpl() :
m_refCount(1),
m_id(0),
- m_func(NULL),
- m_userData(NULL),
m_cancel(false),
m_cancelling(false),
m_exited(false),
- m_result(NULL),
m_networkData(NULL)
{
// do nothing
@@ -319,11 +314,8 @@ ArchMultithreadPosix::unlockMutex(ArchMutex mutex)
}
}
-ArchThread
-ArchMultithreadPosix::newThread(ThreadFunc func, void* data)
+ArchThread ArchMultithreadPosix::newThread(const std::function<void()>& func)
{
- assert(func != NULL);
-
// initialize signal handler. we do this here instead of the
// constructor so we can avoid daemonizing (using fork())
// when there are multiple threads. clients can safely
@@ -341,8 +333,7 @@ ArchMultithreadPosix::newThread(ThreadFunc func, void* data)
// create thread impl for new thread
ArchThreadImpl* thread = new ArchThreadImpl;
- thread->m_func = func;
- thread->m_userData = data;
+ thread->func_ = func;
// create the thread. pthread_create() on RedHat 7.2 smp fails
// if passed a NULL attr so use a default attr.
@@ -389,7 +380,7 @@ ArchMultithreadPosix::closeThread(ArchThread thread)
// decrement ref count and clean up thread if no more references
if (--thread->m_refCount == 0) {
// detach from thread (unless it's the main thread)
- if (thread->m_func != NULL) {
+ if (thread->func_) {
pthread_detach(thread->m_thread);
}
@@ -526,13 +517,6 @@ ArchMultithreadPosix::isExitedThread(ArchThread thread)
return thread->m_exited;
}
-void*
-ArchMultithreadPosix::getResultOfThread(ArchThread thread)
-{
- std::lock_guard<std::mutex> lock(m_threadMutex);
- return thread->m_result;
-}
-
IArchMultithread::ThreadID
ArchMultithreadPosix::getIDOfThread(ArchThread thread)
{
@@ -549,7 +533,7 @@ ArchMultithreadPosix::setSignalHandler(
}
void
-ArchMultithreadPosix::raiseSignal(ESignal signal)
+ArchMultithreadPosix::raiseSignal(ESignal signal)
{
std::lock_guard<std::mutex> lock(m_threadMutex);
if (m_signalFunc[signal] != NULL) {
@@ -699,10 +683,8 @@ ArchMultithreadPosix::doThreadFunc(ArchThread thread)
std::lock_guard<std::mutex> lock(m_threadMutex);
}
- void* result = NULL;
try {
- // go
- result = (*thread->m_func)(thread->m_userData);
+ thread->func_();
}
catch (XThreadCancel&) {
@@ -721,7 +703,6 @@ ArchMultithreadPosix::doThreadFunc(ArchThread thread)
// thread has exited
{
std::lock_guard<std::mutex> lock(m_threadMutex);
- thread->m_result = result;
thread->m_exited = true;
}
diff --git a/src/lib/arch/unix/ArchMultithreadPosix.h b/src/lib/arch/unix/ArchMultithreadPosix.h
index 4bd879f..798147a 100644
--- a/src/lib/arch/unix/ArchMultithreadPosix.h
+++ b/src/lib/arch/unix/ArchMultithreadPosix.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -67,7 +67,7 @@ public:
virtual void closeMutex(ArchMutex);
virtual void lockMutex(ArchMutex);
virtual void unlockMutex(ArchMutex);
- virtual ArchThread newThread(ThreadFunc, void*);
+ virtual ArchThread newThread(const std::function<void()>& func);
virtual ArchThread newCurrentThread();
virtual ArchThread copyThread(ArchThread);
virtual void closeThread(ArchThread);
@@ -77,7 +77,6 @@ public:
virtual bool wait(ArchThread, double timeout);
virtual bool isSameThread(ArchThread, ArchThread);
virtual bool isExitedThread(ArchThread);
- virtual void* getResultOfThread(ArchThread);
virtual ThreadID getIDOfThread(ArchThread);
virtual void setSignalHandler(ESignal, SignalFunc, void*);
virtual void raiseSignal(ESignal);
diff --git a/src/lib/arch/unix/ArchNetworkBSD.cpp b/src/lib/arch/unix/ArchNetworkBSD.cpp
index 496c988..5507bfe 100644
--- a/src/lib/arch/unix/ArchNetworkBSD.cpp
+++ b/src/lib/arch/unix/ArchNetworkBSD.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/unix/ArchNetworkBSD.h b/src/lib/arch/unix/ArchNetworkBSD.h
index 3f5679a..e3f11d5 100644
--- a/src/lib/arch/unix/ArchNetworkBSD.h
+++ b/src/lib/arch/unix/ArchNetworkBSD.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/unix/ArchSleepUnix.cpp b/src/lib/arch/unix/ArchSleepUnix.cpp
index 48e2600..1f91c34 100644
--- a/src/lib/arch/unix/ArchSleepUnix.cpp
+++ b/src/lib/arch/unix/ArchSleepUnix.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/unix/ArchSleepUnix.h b/src/lib/arch/unix/ArchSleepUnix.h
index 3e307a5..d2cdbca 100644
--- a/src/lib/arch/unix/ArchSleepUnix.h
+++ b/src/lib/arch/unix/ArchSleepUnix.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/unix/ArchStringUnix.cpp b/src/lib/arch/unix/ArchStringUnix.cpp
index 591c826..dbb91c1 100644
--- a/src/lib/arch/unix/ArchStringUnix.cpp
+++ b/src/lib/arch/unix/ArchStringUnix.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -25,7 +25,6 @@
//
#include "arch/multibyte.h"
-#include "arch/vsnprintf.h"
ArchStringUnix::ArchStringUnix()
{
diff --git a/src/lib/arch/unix/ArchStringUnix.h b/src/lib/arch/unix/ArchStringUnix.h
index f7d0035..551f497 100644
--- a/src/lib/arch/unix/ArchStringUnix.h
+++ b/src/lib/arch/unix/ArchStringUnix.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/unix/ArchSystemUnix.cpp b/src/lib/arch/unix/ArchSystemUnix.cpp
index f51e47f..f956998 100644
--- a/src/lib/arch/unix/ArchSystemUnix.cpp
+++ b/src/lib/arch/unix/ArchSystemUnix.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/unix/ArchSystemUnix.h b/src/lib/arch/unix/ArchSystemUnix.h
index aa9c564..f3c2ad6 100644
--- a/src/lib/arch/unix/ArchSystemUnix.h
+++ b/src/lib/arch/unix/ArchSystemUnix.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/unix/ArchTaskBarXWindows.cpp b/src/lib/arch/unix/ArchTaskBarXWindows.cpp
index c3577ad..522c7fd 100644
--- a/src/lib/arch/unix/ArchTaskBarXWindows.cpp
+++ b/src/lib/arch/unix/ArchTaskBarXWindows.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2003 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/unix/ArchTaskBarXWindows.h b/src/lib/arch/unix/ArchTaskBarXWindows.h
index f2c8977..5b60a08 100644
--- a/src/lib/arch/unix/ArchTaskBarXWindows.h
+++ b/src/lib/arch/unix/ArchTaskBarXWindows.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2003 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/unix/ArchTimeUnix.cpp b/src/lib/arch/unix/ArchTimeUnix.cpp
index 24685aa..665a7eb 100644
--- a/src/lib/arch/unix/ArchTimeUnix.cpp
+++ b/src/lib/arch/unix/ArchTimeUnix.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/unix/ArchTimeUnix.h b/src/lib/arch/unix/ArchTimeUnix.h
index 3c5c0f8..c6a7dc6 100644
--- a/src/lib/arch/unix/ArchTimeUnix.h
+++ b/src/lib/arch/unix/ArchTimeUnix.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/unix/XArchUnix.cpp b/src/lib/arch/unix/XArchUnix.cpp
index fc7ff65..db2006d 100644
--- a/src/lib/arch/unix/XArchUnix.cpp
+++ b/src/lib/arch/unix/XArchUnix.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/unix/XArchUnix.h b/src/lib/arch/unix/XArchUnix.h
index 93d6d62..be2e689 100644
--- a/src/lib/arch/unix/XArchUnix.h
+++ b/src/lib/arch/unix/XArchUnix.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/vsnprintf.h b/src/lib/arch/vsnprintf.h
deleted file mode 100644
index 5a4e3dc..0000000
--- a/src/lib/arch/vsnprintf.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * barrier -- mouse and keyboard sharing utility
- * Copyright (C) 2012-2016 Symless Ltd.
- * Copyright (C) 2002 Chris Schoeneman
- *
- * This package is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * found in the file LICENSE that should have accompanied this file.
- *
- * This package is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "arch/IArchString.h"
-
-#if HAVE_VSNPRINTF
-
-#if !defined(ARCH_VSNPRINTF)
-# define ARCH_VSNPRINTF vsnprintf
-#endif
-
-int
-IArchString::vsnprintf(char* str, int size, const char* fmt, va_list ap)
-{
- int n = ::ARCH_VSNPRINTF(str, size, fmt, ap);
- if (n > size) {
- n = -1;
- }
- return n;
-}
-
-#elif SYSAPI_UNIX // !HAVE_VSNPRINTF
-
-#include <stdio.h>
-
-int
-IArchString::vsnprintf(char* str, int size, const char* fmt, va_list ap)
-{
- static FILE* bitbucket = fopen("/dev/null", "w");
- if (bitbucket == NULL) {
- // uh oh
- if (size > 0) {
- str[0] = '\0';
- }
- return 0;
- }
- else {
- // count the characters using the bitbucket
- int n = vfprintf(bitbucket, fmt, ap);
- if (n + 1 <= size) {
- // it'll fit so print it into str
- vsprintf(str, fmt, ap);
- }
- return n;
- }
-}
-
-#else // !HAVE_VSNPRINTF && !SYSAPI_UNIX
-
-#error vsnprintf not implemented
-
-#endif // !HAVE_VSNPRINTF
diff --git a/src/lib/arch/win32/ArchConsoleWindows.cpp b/src/lib/arch/win32/ArchConsoleWindows.cpp
index 4514555..2c61eb7 100644
--- a/src/lib/arch/win32/ArchConsoleWindows.cpp
+++ b/src/lib/arch/win32/ArchConsoleWindows.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/win32/ArchConsoleWindows.h b/src/lib/arch/win32/ArchConsoleWindows.h
index f1f0cc9..a6c6d68 100644
--- a/src/lib/arch/win32/ArchConsoleWindows.h
+++ b/src/lib/arch/win32/ArchConsoleWindows.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/win32/ArchDaemonWindows.cpp b/src/lib/arch/win32/ArchDaemonWindows.cpp
index efcf235..df0a4ce 100644
--- a/src/lib/arch/win32/ArchDaemonWindows.cpp
+++ b/src/lib/arch/win32/ArchDaemonWindows.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -441,7 +441,7 @@ ArchDaemonWindows::serviceMain(DWORD argc, LPTSTR* argvIn)
// create synchronization objects
m_serviceMutex = ARCH->newMutex();
m_serviceCondVar = ARCH->newCondVar();
-
+
// register our service handler function
m_statusHandle = RegisterServiceCtrlHandler(argv[0],
&ArchDaemonWindows::serviceHandlerEntry);
@@ -667,7 +667,7 @@ ArchDaemonWindows::stop(const char* name)
// ask the service to stop, asynchronously
SERVICE_STATUS ss;
if (!ControlService(service, SERVICE_CONTROL_STOP, &ss)) {
- DWORD dwErrCode = GetLastError();
+ DWORD dwErrCode = GetLastError();
if (dwErrCode != ERROR_SERVICE_NOT_ACTIVE) {
throw XArchDaemonFailed(new XArchEvalWindows());
}
@@ -681,7 +681,7 @@ ArchDaemonWindows::installDaemon()
if (!isDaemonInstalled(DEFAULT_DAEMON_NAME)) {
char path[MAX_PATH];
GetModuleFileName(ArchMiscWindows::instanceWin32(), path, MAX_PATH);
-
+
// wrap in quotes so a malicious user can't start \Program.exe as admin.
std::stringstream ss;
ss << '"';
diff --git a/src/lib/arch/win32/ArchDaemonWindows.h b/src/lib/arch/win32/ArchDaemonWindows.h
index 2db9792..7813f09 100644
--- a/src/lib/arch/win32/ArchDaemonWindows.h
+++ b/src/lib/arch/win32/ArchDaemonWindows.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/win32/ArchInternetWindows.cpp b/src/lib/arch/win32/ArchInternetWindows.cpp
index 8a28fde..fb75e7d 100644
--- a/src/lib/arch/win32/ArchInternetWindows.cpp
+++ b/src/lib/arch/win32/ArchInternetWindows.cpp
@@ -72,7 +72,7 @@ std::string ArchInternetWindows::urlEncode(const std::string& url)
std::string result(buffer);
- // the win32 url encoding funcitons are pretty useless (to us) and only
+ // the win32 url encoding functions are pretty useless (to us) and only
// escape "unsafe" chars, but not + or =, so we need to replace these
// manually (and probably many other chars).
barrier::string::findReplaceAll(result, "+", "%2B");
@@ -121,12 +121,12 @@ std::string WinINetRequest::send()
openSession();
connect();
openRequest();
-
+
std::string headers("Content-Type: text/html");
if (!HttpSendRequest(m_request, headers.c_str(), (DWORD)headers.length(), NULL, NULL)) {
throw XArch(new XArchEvalWindows());
}
-
+
std::stringstream result;
CHAR buffer[1025];
DWORD read = 0;
@@ -170,7 +170,7 @@ WinINetRequest::connect()
INTERNET_SERVICE_HTTP,
NULL,
NULL);
-
+
if (m_connect == NULL) {
throw XArch(new XArchEvalWindows());
}
diff --git a/src/lib/arch/win32/ArchLogWindows.cpp b/src/lib/arch/win32/ArchLogWindows.cpp
index bc17abf..1b8855a 100644
--- a/src/lib/arch/win32/ArchLogWindows.cpp
+++ b/src/lib/arch/win32/ArchLogWindows.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/win32/ArchLogWindows.h b/src/lib/arch/win32/ArchLogWindows.h
index 3a997f1..efc466f 100644
--- a/src/lib/arch/win32/ArchLogWindows.h
+++ b/src/lib/arch/win32/ArchLogWindows.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/win32/ArchMiscWindows.cpp b/src/lib/arch/win32/ArchMiscWindows.cpp
index 2c022b1..ab16daa 100644
--- a/src/lib/arch/win32/ArchMiscWindows.cpp
+++ b/src/lib/arch/win32/ArchMiscWindows.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -429,7 +429,7 @@ ArchMiscWindows::wakeupDisplay()
}
bool
-ArchMiscWindows::wasLaunchedAsService()
+ArchMiscWindows::wasLaunchedAsService()
{
std::string name;
if (!getParentProcessName(name)) {
@@ -441,9 +441,9 @@ ArchMiscWindows::wasLaunchedAsService()
}
bool ArchMiscWindows::getParentProcessName(std::string &name)
-{
+{
PROCESSENTRY32 parentEntry;
- if (!getParentProcessEntry(parentEntry)){
+ if (!getParentProcessEntry(parentEntry)) {
LOG((CLOG_ERR "could not get entry for parent process"));
return false;
}
@@ -452,14 +452,14 @@ bool ArchMiscWindows::getParentProcessName(std::string &name)
return true;
}
-BOOL WINAPI
+BOOL WINAPI
ArchMiscWindows::getSelfProcessEntry(PROCESSENTRY32& entry)
{
// get entry from current PID
return getProcessEntry(entry, GetCurrentProcessId());
}
-BOOL WINAPI
+BOOL WINAPI
ArchMiscWindows::getParentProcessEntry(PROCESSENTRY32& entry)
{
// get the current process, so we can get parent PID
@@ -472,24 +472,24 @@ ArchMiscWindows::getParentProcessEntry(PROCESSENTRY32& entry)
return getProcessEntry(entry, selfEntry.th32ParentProcessID);
}
-BOOL WINAPI
+BOOL WINAPI
ArchMiscWindows::getProcessEntry(PROCESSENTRY32& entry, DWORD processID)
{
// first we need to take a snapshot of the running processes
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (snapshot == INVALID_HANDLE_VALUE) {
- LOG((CLOG_ERR "could not get process snapshot (error: %i)",
+ LOG((CLOG_ERR "could not get process snapshot (error: %i)",
GetLastError()));
return FALSE;
}
entry.dwSize = sizeof(PROCESSENTRY32);
- // get the first process, and if we can't do that then it's
+ // get the first process, and if we can't do that then it's
// unlikely we can go any further
BOOL gotEntry = Process32First(snapshot, &entry);
if (!gotEntry) {
- LOG((CLOG_ERR "could not get first process entry (error: %i)",
+ LOG((CLOG_ERR "could not get first process entry (error: %i)",
GetLastError()));
return FALSE;
}
diff --git a/src/lib/arch/win32/ArchMiscWindows.h b/src/lib/arch/win32/ArchMiscWindows.h
index 91cd8f5..d5373a0 100644
--- a/src/lib/arch/win32/ArchMiscWindows.h
+++ b/src/lib/arch/win32/ArchMiscWindows.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -167,7 +167,7 @@ public:
static HINSTANCE instanceWin32();
static void setInstanceWin32(HINSTANCE instance);
-
+
static BOOL WINAPI getProcessEntry(PROCESSENTRY32& entry, DWORD processID);
static BOOL WINAPI getSelfProcessEntry(PROCESSENTRY32& entry);
static BOOL WINAPI getParentProcessEntry(PROCESSENTRY32& entry);
diff --git a/src/lib/arch/win32/ArchMultithreadWindows.cpp b/src/lib/arch/win32/ArchMultithreadWindows.cpp
index d3fd059..43a7374 100644
--- a/src/lib/arch/win32/ArchMultithreadWindows.cpp
+++ b/src/lib/arch/win32/ArchMultithreadWindows.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -49,12 +49,10 @@ public:
int m_refCount;
HANDLE m_thread;
DWORD m_id;
- IArchMultithread::ThreadFunc m_func;
- void* m_userData;
+ std::function<void()> func_;
HANDLE m_cancel;
bool m_cancelling;
HANDLE m_exit;
- void* m_result;
void* m_networkData;
};
@@ -62,10 +60,7 @@ ArchThreadImpl::ArchThreadImpl() :
m_refCount(1),
m_thread(NULL),
m_id(0),
- m_func(NULL),
- m_userData(NULL),
m_cancelling(false),
- m_result(NULL),
m_networkData(NULL)
{
m_exit = CreateEvent(NULL, TRUE, FALSE, NULL);
@@ -292,15 +287,13 @@ ArchMultithreadWindows::unlockMutex(ArchMutex mutex)
LeaveCriticalSection(&mutex->m_mutex);
}
-ArchThread
-ArchMultithreadWindows::newThread(ThreadFunc func, void* data)
+ArchThread ArchMultithreadWindows::newThread(const std::function<void()>& func)
{
lockMutex(m_threadMutex);
// create thread impl for new thread
ArchThreadImpl* thread = new ArchThreadImpl;
- thread->m_func = func;
- thread->m_userData = data;
+ thread->func_ = func;
// create thread
unsigned int id = 0;
@@ -523,15 +516,6 @@ ArchMultithreadWindows::isExitedThread(ArchThread thread)
return (WaitForSingleObject(thread->m_exit, 0) == WAIT_OBJECT_0);
}
-void*
-ArchMultithreadWindows::getResultOfThread(ArchThread thread)
-{
- lockMutex(m_threadMutex);
- void* result = thread->m_result;
- unlockMutex(m_threadMutex);
- return result;
-}
-
IArchMultithread::ThreadID
ArchMultithreadWindows::getIDOfThread(ArchThread thread)
{
@@ -678,10 +662,8 @@ ArchMultithreadWindows::doThreadFunc(ArchThread thread)
lockMutex(m_threadMutex);
unlockMutex(m_threadMutex);
- void* result = NULL;
try {
- // go
- result = (*thread->m_func)(thread->m_userData);
+ thread->func_();
}
catch (XThreadCancel&) {
@@ -695,9 +677,6 @@ ArchMultithreadWindows::doThreadFunc(ArchThread thread)
}
// thread has exited
- lockMutex(m_threadMutex);
- thread->m_result = result;
- unlockMutex(m_threadMutex);
SetEvent(thread->m_exit);
// done with thread
diff --git a/src/lib/arch/win32/ArchMultithreadWindows.h b/src/lib/arch/win32/ArchMultithreadWindows.h
index 99aa640..31a2b30 100644
--- a/src/lib/arch/win32/ArchMultithreadWindows.h
+++ b/src/lib/arch/win32/ArchMultithreadWindows.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -73,7 +73,7 @@ public:
virtual void closeMutex(ArchMutex);
virtual void lockMutex(ArchMutex);
virtual void unlockMutex(ArchMutex);
- virtual ArchThread newThread(ThreadFunc, void*);
+ virtual ArchThread newThread(const std::function<void()>& func);
virtual ArchThread newCurrentThread();
virtual ArchThread copyThread(ArchThread);
virtual void closeThread(ArchThread);
@@ -83,7 +83,6 @@ public:
virtual bool wait(ArchThread, double timeout);
virtual bool isSameThread(ArchThread, ArchThread);
virtual bool isExitedThread(ArchThread);
- virtual void* getResultOfThread(ArchThread);
virtual ThreadID getIDOfThread(ArchThread);
virtual void setSignalHandler(ESignal, SignalFunc, void*);
virtual void raiseSignal(ESignal);
diff --git a/src/lib/arch/win32/ArchNetworkWinsock.cpp b/src/lib/arch/win32/ArchNetworkWinsock.cpp
index 4bc61d8..2d444fd 100644
--- a/src/lib/arch/win32/ArchNetworkWinsock.cpp
+++ b/src/lib/arch/win32/ArchNetworkWinsock.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/win32/ArchNetworkWinsock.h b/src/lib/arch/win32/ArchNetworkWinsock.h
index 0b01671..7f65795 100644
--- a/src/lib/arch/win32/ArchNetworkWinsock.h
+++ b/src/lib/arch/win32/ArchNetworkWinsock.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/win32/ArchSleepWindows.cpp b/src/lib/arch/win32/ArchSleepWindows.cpp
index 69648a7..0395031 100644
--- a/src/lib/arch/win32/ArchSleepWindows.cpp
+++ b/src/lib/arch/win32/ArchSleepWindows.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -57,5 +57,5 @@ ArchSleepWindows::sleep(double timeout)
else {
Sleep((DWORD)(1000.0 * timeout));
}
- ARCH->testCancelThread();
+ ARCH->testCancelThread();
}
diff --git a/src/lib/arch/win32/ArchSleepWindows.h b/src/lib/arch/win32/ArchSleepWindows.h
index d673caf..da89cea 100644
--- a/src/lib/arch/win32/ArchSleepWindows.h
+++ b/src/lib/arch/win32/ArchSleepWindows.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/win32/ArchStringWindows.cpp b/src/lib/arch/win32/ArchStringWindows.cpp
index deaf536..0033659 100644
--- a/src/lib/arch/win32/ArchStringWindows.cpp
+++ b/src/lib/arch/win32/ArchStringWindows.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -26,11 +26,6 @@
// ArchStringWindows
//
-#include "arch/multibyte.h"
-#define HAVE_VSNPRINTF 1
-#define ARCH_VSNPRINTF _vsnprintf
-#include "arch/vsnprintf.h"
-
ArchStringWindows::ArchStringWindows()
{
}
diff --git a/src/lib/arch/win32/ArchStringWindows.h b/src/lib/arch/win32/ArchStringWindows.h
index 23812dc..b2869b4 100644
--- a/src/lib/arch/win32/ArchStringWindows.h
+++ b/src/lib/arch/win32/ArchStringWindows.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/win32/ArchSystemWindows.cpp b/src/lib/arch/win32/ArchSystemWindows.cpp
index cf3b066..badcf28 100644
--- a/src/lib/arch/win32/ArchSystemWindows.cpp
+++ b/src/lib/arch/win32/ArchSystemWindows.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/win32/ArchSystemWindows.h b/src/lib/arch/win32/ArchSystemWindows.h
index 3d45ee6..835560d 100644
--- a/src/lib/arch/win32/ArchSystemWindows.h
+++ b/src/lib/arch/win32/ArchSystemWindows.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/win32/ArchTaskBarWindows.cpp b/src/lib/arch/win32/ArchTaskBarWindows.cpp
index 731dc59..bf71b74 100644
--- a/src/lib/arch/win32/ArchTaskBarWindows.cpp
+++ b/src/lib/arch/win32/ArchTaskBarWindows.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2003 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -88,7 +88,7 @@ ArchTaskBarWindows::init()
// create a window on the current desktop with the current
// thread then the current thread won't be able to switch
// desktops if it needs to.
- m_thread = ARCH->newThread(&ArchTaskBarWindows::threadEntry, this);
+ m_thread = ARCH->newThread([this]() { threadMainLoop(); });
// wait for child thread
while (!m_ready) {
@@ -501,14 +501,7 @@ ArchTaskBarWindows::threadMainLoop()
UnregisterClass(className, instanceWin32());
}
-void*
-ArchTaskBarWindows::threadEntry(void* self)
-{
- static_cast<ArchTaskBarWindows*>(self)->threadMainLoop();
- return NULL;
-}
-
HINSTANCE ArchTaskBarWindows::instanceWin32()
{
return ArchMiscWindows::instanceWin32();
-} \ No newline at end of file
+}
diff --git a/src/lib/arch/win32/ArchTaskBarWindows.h b/src/lib/arch/win32/ArchTaskBarWindows.h
index 0edddf8..2b8b7ad 100644
--- a/src/lib/arch/win32/ArchTaskBarWindows.h
+++ b/src/lib/arch/win32/ArchTaskBarWindows.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2003 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -36,7 +36,7 @@ public:
virtual void init();
- //! Add a dialog window
+ //! Add a dialog window
/*!
Tell the task bar event loop about a dialog. Win32 annoyingly
requires messages destined for modeless dialog boxes to be
@@ -84,7 +84,6 @@ private:
static LRESULT CALLBACK
staticWndProc(HWND, UINT, WPARAM, LPARAM);
void threadMainLoop();
- static void* threadEntry(void*);
HINSTANCE instanceWin32();
diff --git a/src/lib/arch/win32/ArchTimeWindows.cpp b/src/lib/arch/win32/ArchTimeWindows.cpp
index 568a483..eae0c15 100644
--- a/src/lib/arch/win32/ArchTimeWindows.cpp
+++ b/src/lib/arch/win32/ArchTimeWindows.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/win32/ArchTimeWindows.h b/src/lib/arch/win32/ArchTimeWindows.h
index 42351a1..c695e79 100644
--- a/src/lib/arch/win32/ArchTimeWindows.h
+++ b/src/lib/arch/win32/ArchTimeWindows.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/arch/win32/XArchWindows.cpp b/src/lib/arch/win32/XArchWindows.cpp
index e116eda..eb3c151 100644
--- a/src/lib/arch/win32/XArchWindows.cpp
+++ b/src/lib/arch/win32/XArchWindows.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -57,58 +57,58 @@ XArchEvalWinsock::eval() const noexcept
// may not look up network error messages correctly. we'll have
// to do it ourself.
static const struct { int m_code; const char* m_msg; } s_netErrorCodes[] = {
- /* 10004 */{WSAEINTR, "The (blocking) call was canceled via WSACancelBlockingCall"},
- /* 10009 */{WSAEBADF, "Bad file handle"},
- /* 10013 */{WSAEACCES, "The requested address is a broadcast address, but the appropriate flag was not set"},
- /* 10014 */{WSAEFAULT, "WSAEFAULT"},
- /* 10022 */{WSAEINVAL, "WSAEINVAL"},
- /* 10024 */{WSAEMFILE, "No more file descriptors available"},
- /* 10035 */{WSAEWOULDBLOCK, "Socket is marked as non-blocking and no connections are present or the receive operation would block"},
- /* 10036 */{WSAEINPROGRESS, "A blocking Windows Sockets operation is in progress"},
+ /* 10004 */{WSAEINTR, "The (blocking) call was canceled via WSACancelBlockingCall"},
+ /* 10009 */{WSAEBADF, "Bad file handle"},
+ /* 10013 */{WSAEACCES, "The requested address is a broadcast address, but the appropriate flag was not set"},
+ /* 10014 */{WSAEFAULT, "WSAEFAULT"},
+ /* 10022 */{WSAEINVAL, "WSAEINVAL"},
+ /* 10024 */{WSAEMFILE, "No more file descriptors available"},
+ /* 10035 */{WSAEWOULDBLOCK, "Socket is marked as non-blocking and no connections are present or the receive operation would block"},
+ /* 10036 */{WSAEINPROGRESS, "A blocking Windows Sockets operation is in progress"},
/* 10037 */{WSAEALREADY, "The asynchronous routine being canceled has already completed"},
/* 10038 */{WSAENOTSOCK, "At least on descriptor is not a socket"},
/* 10039 */{WSAEDESTADDRREQ, "A destination address is required"},
/* 10040 */{WSAEMSGSIZE, "The datagram was too large to fit into the specified buffer and was truncated"},
- /* 10041 */{WSAEPROTOTYPE, "The specified protocol is the wrong type for this socket"},
- /* 10042 */{WSAENOPROTOOPT, "The option is unknown or unsupported"},
- /* 10043 */{WSAEPROTONOSUPPORT,"The specified protocol is not supported"},
- /* 10044 */{WSAESOCKTNOSUPPORT,"The specified socket type is not supported by this address family"},
- /* 10045 */{WSAEOPNOTSUPP, "The referenced socket is not a type that supports that operation"},
+ /* 10041 */{WSAEPROTOTYPE, "The specified protocol is the wrong type for this socket"},
+ /* 10042 */{WSAENOPROTOOPT, "The option is unknown or unsupported"},
+ /* 10043 */{WSAEPROTONOSUPPORT, "The specified protocol is not supported"},
+ /* 10044 */{WSAESOCKTNOSUPPORT, "The specified socket type is not supported by this address family"},
+ /* 10045 */{WSAEOPNOTSUPP, "The referenced socket is not a type that supports that operation"},
/* 10046 */{WSAEPFNOSUPPORT, "BSD: Protocol family not supported"},
/* 10047 */{WSAEAFNOSUPPORT, "The specified address family is not supported"},
- /* 10048 */{WSAEADDRINUSE, "The specified address is already in use"},
- /* 10049 */{WSAEADDRNOTAVAIL, "The specified address is not available from the local machine"},
+ /* 10048 */{WSAEADDRINUSE, "The specified address is already in use"},
+ /* 10049 */{WSAEADDRNOTAVAIL, "The specified address is not available from the local machine"},
/* 10050 */{WSAENETDOWN, "The Windows Sockets implementation has detected that the network subsystem has failed"},
- /* 10051 */{WSAENETUNREACH, "The network can't be reached from this host at this time"},
- /* 10052 */{WSAENETRESET, "The connection must be reset because the Windows Sockets implementation dropped it"},
+ /* 10051 */{WSAENETUNREACH, "The network can't be reached from this host at this time"},
+ /* 10052 */{WSAENETRESET, "The connection must be reset because the Windows Sockets implementation dropped it"},
/* 10053 */{WSAECONNABORTED, "The virtual circuit was aborted due to timeout or other failure"},
- /* 10054 */{WSAECONNRESET, "The virtual circuit was reset by the remote side"},
- /* 10055 */{WSAENOBUFS, "No buffer space is available or a buffer deadlock has occured. The socket cannot be created"},
- /* 10056 */{WSAEISCONN, "The socket is already connected"},
+ /* 10054 */{WSAECONNRESET, "The virtual circuit was reset by the remote side"},
+ /* 10055 */{WSAENOBUFS, "No buffer space is available or a buffer deadlock has occurred. The socket cannot be created"},
+ /* 10056 */{WSAEISCONN, "The socket is already connected"},
/* 10057 */{WSAENOTCONN, "The socket is not connected"},
- /* 10058 */{WSAESHUTDOWN, "The socket has been shutdown"},
+ /* 10058 */{WSAESHUTDOWN, "The socket has been shutdown"},
/* 10059 */{WSAETOOMANYREFS, "BSD: Too many references"},
- /* 10060 */{WSAETIMEDOUT, "Attempt to connect timed out without establishing a connection"},
+ /* 10060 */{WSAETIMEDOUT, "Attempt to connect timed out without establishing a connection"},
/* 10061 */{WSAECONNREFUSED, "Connection was refused"},
- /* 10062 */{WSAELOOP, "Undocumented WinSock error code used in BSD"},
+ /* 10062 */{WSAELOOP, "Undocumented WinSock error code used in BSD"},
/* 10063 */{WSAENAMETOOLONG, "Undocumented WinSock error code used in BSD"},
- /* 10064 */{WSAEHOSTDOWN, "Undocumented WinSock error code used in BSD"},
+ /* 10064 */{WSAEHOSTDOWN, "Undocumented WinSock error code used in BSD"},
/* 10065 */{WSAEHOSTUNREACH, "No route to host"},
- /* 10066 */{WSAENOTEMPTY, "Undocumented WinSock error code"},
+ /* 10066 */{WSAENOTEMPTY, "Undocumented WinSock error code"},
/* 10067 */{WSAEPROCLIM, "Undocumented WinSock error code"},
- /* 10068 */{WSAEUSERS, "Undocumented WinSock error code"},
- /* 10069 */{WSAEDQUOT, "Undocumented WinSock error code"},
- /* 10070 */{WSAESTALE, "Undocumented WinSock error code"},
- /* 10071 */{WSAEREMOTE, "Undocumented WinSock error code"},
- /* 10091 */{WSASYSNOTREADY, "Underlying network subsytem is not ready for network communication"},
- /* 10092 */{WSAVERNOTSUPPORTED, "The version of WinSock API support requested is not provided in this implementation"},
- /* 10093 */{WSANOTINITIALISED, "WinSock subsystem not properly initialized"},
- /* 10101 */{WSAEDISCON, "Virtual circuit has gracefully terminated connection"},
- /* 11001 */{WSAHOST_NOT_FOUND, "The specified host is unknown"},
- /* 11002 */{WSATRY_AGAIN, "A temporary error occurred on an authoritative name server"},
- /* 11003 */{WSANO_RECOVERY, "A non-recoverable name server error occurred"},
- /* 11004 */{WSANO_DATA, "The requested name is valid but does not have an IP address"},
- /* end */{0, NULL}
+ /* 10068 */{WSAEUSERS, "Undocumented WinSock error code"},
+ /* 10069 */{WSAEDQUOT, "Undocumented WinSock error code"},
+ /* 10070 */{WSAESTALE, "Undocumented WinSock error code"},
+ /* 10071 */{WSAEREMOTE, "Undocumented WinSock error code"},
+ /* 10091 */{WSASYSNOTREADY, "Underlying network subsystem is not ready for network communication"},
+ /* 10092 */{WSAVERNOTSUPPORTED, "The version of WinSock API support requested is not provided in this implementation"},
+ /* 10093 */{WSANOTINITIALISED, "WinSock subsystem not properly initialized"},
+ /* 10101 */{WSAEDISCON, "Virtual circuit has gracefully terminated connection"},
+ /* 11001 */{WSAHOST_NOT_FOUND, "The specified host is unknown"},
+ /* 11002 */{WSATRY_AGAIN, "A temporary error occurred on an authoritative name server"},
+ /* 11003 */{WSANO_RECOVERY, "A non-recoverable name server error occurred"},
+ /* 11004 */{WSANO_DATA, "The requested name is valid but does not have an IP address"},
+ /* end */{0, NULL}
};
for (unsigned int i = 0; s_netErrorCodes[i].m_code != 0; ++i) {
diff --git a/src/lib/arch/win32/XArchWindows.h b/src/lib/arch/win32/XArchWindows.h
index 4fb2a23..5ac71f2 100644
--- a/src/lib/arch/win32/XArchWindows.h
+++ b/src/lib/arch/win32/XArchWindows.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/barrier/App.cpp b/src/lib/barrier/App.cpp
index 8a79aa2..2b3eccc 100644
--- a/src/lib/barrier/App.cpp
+++ b/src/lib/barrier/App.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -34,7 +34,6 @@
#if SYSAPI_WIN32
#include "base/IEventQueue.h"
-#include "base/TMethodJob.h"
#endif
#include <iostream>
@@ -79,18 +78,18 @@ App::~App()
void
App::version()
{
- std::cout << argsBase().m_exename << " " << kVersion << std::endl;
- std::cout <<"Protocol version " << kProtocolMajorVersion << "." << kProtocolMinorVersion << std::endl;
- std::cout << kCopyright << std::endl;
+ std::cout << argsBase().m_exename << " " << kVersion << "\n";
+ std::cout <<"Protocol version " << kProtocolMajorVersion << "." << kProtocolMinorVersion << "\n";
+ std::cout << kCopyright << "\n";
}
int
App::run(int argc, char** argv)
-{
+{
#if MAC_OS_X_VERSION_10_7
// dock hide only supported on lion :(
ProcessSerialNumber psn = { 0, kCurrentProcess };
-
+
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
GetCurrentProcess(&psn);
@@ -101,7 +100,7 @@ App::run(int argc, char** argv)
// install application in to arch
appUtil().adoptApp(this);
-
+
// HACK: fail by default (saves us setting result in each catch)
int result = kExitFailed;
@@ -110,7 +109,7 @@ App::run(int argc, char** argv)
}
catch (XExitApp& e) {
// instead of showing a nasty error, just exit with the error code.
- // not sure if i like this behaviour, but it's probably better than
+ // not sure if i like this behaviour, but it's probably better than
// using the exit(int) function!
result = e.getCode();
}
@@ -122,7 +121,7 @@ App::run(int argc, char** argv)
}
appUtil().beforeAppExit();
-
+
return result;
}
@@ -137,7 +136,7 @@ App::daemonMainLoop(int, const char**)
return mainLoop();
}
-void
+void
App::setupFileLogging()
{
if (argsBase().m_logFile != NULL) {
@@ -147,24 +146,24 @@ App::setupFileLogging()
}
}
-void
+void
App::loggingFilterWarning()
{
if (CLOG->getFilter() > CLOG->getConsoleMaxLevel()) {
if (argsBase().m_logFile == NULL) {
- LOG((CLOG_WARN "log messages above %s are NOT sent to console (use file logging)",
+ LOG((CLOG_WARN "log messages above %s are NOT sent to console (use file logging)",
CLOG->getFilterName(CLOG->getConsoleMaxLevel())));
}
}
}
-void
+void
App::initApp(int argc, const char** argv)
{
// parse command line
parseArgs(argc, argv);
-
- DataDirectories::profile(argsBase().m_profileDirectory);
+
+ barrier::DataDirectories::profile(argsBase().m_profileDirectory);
// set log filter
if (!CLOG->setFilter(argsBase().m_logFilter)) {
@@ -173,9 +172,12 @@ App::initApp(int argc, const char** argv)
m_bye(kExitArgs);
}
loggingFilterWarning();
-
+
if (argsBase().m_enableDragDrop) {
LOG((CLOG_INFO "drag and drop enabled"));
+ if (!argsBase().m_dropTarget.empty()) {
+ LOG((CLOG_INFO "drop target: %s", argsBase().m_dropTarget.c_str()));
+ }
}
// setup file logging after parsing args
@@ -226,15 +228,14 @@ App::handleIpcMessage(const Event& e, void*)
}
}
-void
-App::runEventsLoop(void*)
+void App::run_events_loop()
{
m_events->loop();
-
+
#if defined(MAC_OS_X_VERSION_10_7)
-
+
stopCocoaLoop();
-
+
#endif
}
diff --git a/src/lib/barrier/App.h b/src/lib/barrier/App.h
index 8040da8..8e17a71 100644
--- a/src/lib/barrier/App.h
+++ b/src/lib/barrier/App.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -59,7 +59,7 @@ public:
// Parse command line arguments.
virtual void parseArgs(int argc, const char* const* argv) = 0;
-
+
int run(int argc, char** argv);
int daemonMainLoop(int, const char**);
@@ -90,11 +90,11 @@ public:
ARCH_APP_UTIL& appUtil() { return m_appUtil; }
- virtual IArchTaskBarReceiver* taskBarReceiver() const { return m_taskBarReceiver; }
+ virtual IArchTaskBarReceiver* taskBarReceiver() const { return m_taskBarReceiver; }
virtual void setByeFunc(void(*bye)(int)) { m_bye = bye; }
virtual void bye(int error) { m_bye(error); }
-
+
virtual IEventQueue* getEvents() const { return m_events; }
void setSocketMultiplexer(std::unique_ptr<SocketMultiplexer>&& sm) { m_socketMultiplexer = std::move(sm); }
@@ -108,7 +108,7 @@ private:
protected:
void initIpcClient();
void cleanupIpcClient();
- void runEventsLoop(void*);
+ void run_events_loop();
IArchTaskBarReceiver* m_taskBarReceiver;
bool m_suspended;
@@ -135,7 +135,7 @@ public:
virtual void startNode();
virtual int mainLoop();
virtual int foregroundStartup(int argc, char** argv);
- virtual barrier::Screen*
+ virtual barrier::Screen*
createScreen();
virtual void loadConfig();
virtual bool loadConfig(const String& pathname);
@@ -166,7 +166,10 @@ private:
" -l --log <file> write log messages to file.\n" \
" --no-tray disable the system tray icon.\n" \
" --enable-drag-drop enable file drag & drop.\n" \
- " --enable-crypto enable the crypto (ssl) plugin.\n"
+ " --enable-crypto enable the crypto (ssl) plugin (default, deprecated).\n" \
+ " --disable-crypto disable the crypto (ssl) plugin.\n" \
+ " --profile-dir <path> use named profile directory instead.\n" \
+ " --drop-dir <path> use named drop target directory instead.\n"
#define HELP_COMMON_INFO_2 \
" -h, --help display this help and exit.\n" \
@@ -191,12 +194,11 @@ private:
// windows args
# define HELP_SYS_ARGS \
- " [--service <action>] [--relaunch] [--exit-pause]"
+ " [--exit-pause]"
# define HELP_SYS_INFO \
" --service <action> manage the windows service, valid options are:\n" \
" install/uninstall/start/stop\n" \
- " --relaunch persistently relaunches process in current user \n" \
- " session (useful for vista and upward).\n" \
+ " (obsolete, use barrierd instead)\n" \
" --exit-pause wait for key press on exit, can be useful for\n" \
" reading error messages that occur on exit.\n"
#endif
diff --git a/src/lib/barrier/AppUtil.cpp b/src/lib/barrier/AppUtil.cpp
index 3298d7b..d615648 100644
--- a/src/lib/barrier/AppUtil.cpp
+++ b/src/lib/barrier/AppUtil.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -15,11 +15,11 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-
+
#include "barrier/AppUtil.h"
AppUtil* AppUtil::s_instance = nullptr;
-
+
AppUtil::AppUtil() :
m_app(nullptr)
{
diff --git a/src/lib/barrier/AppUtil.h b/src/lib/barrier/AppUtil.h
index 6f5f073..097c7f2 100644
--- a/src/lib/barrier/AppUtil.h
+++ b/src/lib/barrier/AppUtil.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-
+
#pragma once
#include "barrier/IAppUtil.h"
@@ -33,7 +33,7 @@ public:
static AppUtil& instance();
static void exitAppStatic(int code) { instance().exitApp(code); }
virtual void beforeAppExit() {}
-
+
private:
IApp* m_app;
static AppUtil* s_instance;
diff --git a/src/lib/barrier/ArgParser.cpp b/src/lib/barrier/ArgParser.cpp
index ec3991c..99cd803 100644
--- a/src/lib/barrier/ArgParser.cpp
+++ b/src/lib/barrier/ArgParser.cpp
@@ -24,7 +24,7 @@
#include "barrier/ArgsBase.h"
#include "base/Log.h"
#include "base/String.h"
-#include "common/PathUtilities.h"
+#include "io/filesystem.h"
#ifdef WINAPI_MSWINDOWS
#include <VersionHelpers.h>
@@ -65,7 +65,9 @@ ArgParser::parseServerArgs(ServerArgs& args, int argc, const char* const* argv)
// save screen change script path
args.m_screenChangeScript = argv[++i];
}
- else {
+ else if (isArg(i, argc, argv, nullptr, "--disable-client-cert-checking")) {
+ args.check_client_certificates = false;
+ } else {
LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE, args.m_exename.c_str(), argv[i], args.m_exename.c_str()));
return false;
}
@@ -133,10 +135,10 @@ ArgParser::parseClientArgs(ClientArgs& args, int argc, const char* const* argv)
return true;
}
+#if WINAPI_MSWINDOWS
bool
-ArgParser::parsePlatformArg(ArgsBase& argsBase, const int& argc, const char* const* argv, int& i)
+ArgParser::parseMSWindowsArg(ArgsBase& argsBase, const int& argc, const char* const* argv, int& i)
{
-#if WINAPI_MSWINDOWS
if (isArg(i, argc, argv, NULL, "--service")) {
LOG((CLOG_WARN "obsolete argument --service, use barrierd instead."));
argsBase.m_shouldExit = true;
@@ -153,25 +155,46 @@ ArgParser::parsePlatformArg(ArgsBase& argsBase, const int& argc, const char* con
}
return true;
-#elif WINAPI_XWINDOWS
+}
+#endif
+
+#if WINAPI_CARBON
+bool
+ArgParser::parseCarbonArg(ArgsBase& argsBase, const int& argc, const char* const* argv, int& i)
+{
+ // no options for carbon
+ return false;
+}
+#endif
+
+#if WINAPI_XWINDOWS
+bool
+ArgParser::parseXWindowsArg(ArgsBase& argsBase, const int& argc, const char* const* argv, int& i)
+{
if (isArg(i, argc, argv, "-display", "--display", 1)) {
// use alternative display
argsBase.m_display = argv[++i];
}
-
else if (isArg(i, argc, argv, NULL, "--no-xinitthreads")) {
argsBase.m_disableXInitThreads = true;
- }
-
- else {
+ } else {
// option not supported here
return false;
}
return true;
+}
+#endif
+
+bool
+ArgParser::parsePlatformArg(ArgsBase& argsBase, const int& argc, const char* const* argv, int& i)
+{
+#if WINAPI_MSWINDOWS
+ return parseMSWindowsArg(argsBase, argc, argv, i);
#elif WINAPI_CARBON
- // no options for carbon
- return false;
+ return parseCarbonArg(argsBase, argc, argv, i);
+#elif WINAPI_XWINDOWS
+ return parseXWindowsArg(argsBase, argc, argv, i);
#endif
}
@@ -257,14 +280,20 @@ ArgParser::parseGenericArgs(int argc, const char* const* argv, int& i)
argsBase().m_enableDragDrop = true;
}
}
+ else if (isArg(i, argc, argv, NULL, "--drop-dir")) {
+ argsBase().m_dropTarget = argv[++i];
+ }
else if (isArg(i, argc, argv, NULL, "--enable-crypto")) {
- argsBase().m_enableCrypto = true;
+ LOG((CLOG_INFO "--enable-crypto is used by default. The option is deprecated."));
+ }
+ else if (isArg(i, argc, argv, NULL, "--disable-crypto")) {
+ argsBase().m_enableCrypto = false;
}
else if (isArg(i, argc, argv, NULL, "--profile-dir", 1)) {
- argsBase().m_profileDirectory = argv[++i];
+ argsBase().m_profileDirectory = barrier::fs::u8path(argv[++i]);
}
else if (isArg(i, argc, argv, NULL, "--plugin-dir", 1)) {
- argsBase().m_pluginDirectory = argv[++i];
+ argsBase().m_pluginDirectory = barrier::fs::u8path(argv[++i]);
}
else {
// option not supported here
@@ -349,7 +378,7 @@ ArgParser::splitCommandString(String& command, std::vector<String>& argv)
if (space > leftDoubleQuote && space < rightDoubleQuote) {
ignoreThisSpace = true;
}
- else if (space > rightDoubleQuote){
+ else if (space > rightDoubleQuote) {
searchDoubleQuotes(command, leftDoubleQuote, rightDoubleQuote, rightDoubleQuote + 1);
}
@@ -460,7 +489,13 @@ void
ArgParser::updateCommonArgs(const char* const* argv)
{
argsBase().m_name = ARCH->getHostName();
- argsBase().m_exename = PathUtilities::basename(argv[0]);
+ argsBase().m_exename = parse_exename(argv[0]);
+}
+
+std::string ArgParser::parse_exename(const char* arg)
+{
+ // FIXME: we assume UTF-8 encoding, but on Windows this is not correct
+ return barrier::fs::u8path(arg).filename().u8string();
}
bool
diff --git a/src/lib/barrier/ArgParser.h b/src/lib/barrier/ArgParser.h
index 32300c6..472d93a 100644
--- a/src/lib/barrier/ArgParser.h
+++ b/src/lib/barrier/ArgParser.h
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2014-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -14,7 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-
+
#pragma once
#include "base/String.h"
@@ -41,21 +41,27 @@ public:
const char* name1, const char* name2,
int minRequiredParameters = 0);
static void splitCommandString(String& command, std::vector<String>& argv);
- static bool searchDoubleQuotes(String& command, size_t& left,
+ static bool searchDoubleQuotes(String& command, size_t& left,
size_t& right, size_t startPos = 0);
static void removeDoubleQuotes(String& arg);
static const char** getArgv(std::vector<String>& argsArray);
- static String assembleCommand(std::vector<String>& argsArray,
+ static String assembleCommand(std::vector<String>& argsArray,
String ignoreArg = "", int parametersRequired = 0);
+ static std::string parse_exename(const char* arg);
+
private:
void updateCommonArgs(const char* const* argv);
bool checkUnexpectedArgs();
-
+
static ArgsBase& argsBase() { return *m_argsBase; }
+ bool parseMSWindowsArg(ArgsBase& argsBase, const int& argc, const char* const* argv, int& i);
+ bool parseCarbonArg(ArgsBase& argsBase, const int& argc, const char* const* argv, int& i);
+ bool parseXWindowsArg(ArgsBase& argsBase, const int& argc, const char* const* argv, int& i);
+
private:
App* m_app;
-
+
static ArgsBase* m_argsBase;
};
diff --git a/src/lib/barrier/ArgsBase.cpp b/src/lib/barrier/ArgsBase.cpp
index eb63150..e3e3803 100644
--- a/src/lib/barrier/ArgsBase.cpp
+++ b/src/lib/barrier/ArgsBase.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -39,10 +39,11 @@ m_display(NULL),
m_disableTray(false),
m_enableIpc(false),
m_enableDragDrop(false),
+m_dropTarget(""),
m_shouldExit(false),
m_barrierAddress(),
-m_enableCrypto(false),
-m_profileDirectory(""),
+ m_enableCrypto(true),
+m_profileDirectory(),
m_pluginDirectory("")
{
}
diff --git a/src/lib/barrier/ArgsBase.h b/src/lib/barrier/ArgsBase.h
index 99929b3..cdb5092 100644
--- a/src/lib/barrier/ArgsBase.h
+++ b/src/lib/barrier/ArgsBase.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -19,6 +19,7 @@
#pragma once
#include "base/String.h"
+#include "io/filesystem.h"
class ArgsBase {
public:
@@ -38,6 +39,7 @@ public:
bool m_disableTray;
bool m_enableIpc;
bool m_enableDragDrop;
+ String m_dropTarget;
#if SYSAPI_WIN32
bool m_debugServiceWait;
bool m_pauseOnExit;
@@ -49,6 +51,6 @@ public:
bool m_shouldExit;
String m_barrierAddress;
bool m_enableCrypto;
- String m_profileDirectory;
- String m_pluginDirectory;
+ barrier::fs::path m_profileDirectory;
+ barrier::fs::path m_pluginDirectory;
};
diff --git a/src/lib/barrier/BarrierType.h b/src/lib/barrier/BarrierType.h
new file mode 100644
index 0000000..0a18477
--- /dev/null
+++ b/src/lib/barrier/BarrierType.h
@@ -0,0 +1,26 @@
+/*
+ barrier -- mouse and keyboard sharing utility
+ Copyright (C) Barrier contributors
+
+ This package is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ found in the file LICENSE that should have accompanied this file.
+
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef BARRIER_LIB_BARRIER_BARRIER_TYPE_H
+#define BARRIER_LIB_BARRIER_BARRIER_TYPE_H
+
+enum class BarrierType {
+ Server,
+ Client
+};
+
+#endif // BARRIER_LIB_BARRIER_BARRIER_TYPE_H
diff --git a/src/lib/barrier/CMakeLists.txt b/src/lib/barrier/CMakeLists.txt
index 6978aef..b60936d 100644
--- a/src/lib/barrier/CMakeLists.txt
+++ b/src/lib/barrier/CMakeLists.txt
@@ -1,11 +1,11 @@
# barrier -- mouse and keyboard sharing utility
# Copyright (C) 2012-2016 Symless Ltd.
# Copyright (C) 2009 Nick Bolton
-#
+#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
-#
+#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/barrier/Chunk.cpp b/src/lib/barrier/Chunk.cpp
index f11bff5..fd69cdb 100644
--- a/src/lib/barrier/Chunk.cpp
+++ b/src/lib/barrier/Chunk.cpp
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2015-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/barrier/Chunk.h b/src/lib/barrier/Chunk.h
index 42b85bf..26a343d 100644
--- a/src/lib/barrier/Chunk.h
+++ b/src/lib/barrier/Chunk.h
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2015-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -17,7 +17,7 @@
#pragma once
-#include "common/basic_types.h"
+#include <cstddef>
class Chunk {
public:
diff --git a/src/lib/barrier/ClientApp.cpp b/src/lib/barrier/ClientApp.cpp
index b1a7661..4b0ef61 100644
--- a/src/lib/barrier/ClientApp.cpp
+++ b/src/lib/barrier/ClientApp.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -37,10 +37,8 @@
#include "base/TMethodEventJob.h"
#include "base/log_outputters.h"
#include "base/EventQueue.h"
-#include "base/TMethodJob.h"
#include "base/Log.h"
#include "common/Version.h"
-#include "common/PathUtilities.h"
#if WINAPI_MSWINDOWS
#include "platform/MSWindowsScreen.h"
@@ -118,23 +116,23 @@ ClientApp::help()
#endif
std::ostringstream buffer;
- buffer << "Start the barrier client and connect to a remote server component." << std::endl
- << std::endl
+ buffer << "Start the barrier client and connect to a remote server component.\n"
+ << "\n"
<< "Usage: " << args().m_exename << " [--yscroll <delta>]" << WINAPI_ARG << HELP_SYS_ARGS
- << HELP_COMMON_ARGS << " <server-address>" << std::endl
- << std::endl
- << "Options:" << std::endl
+ << HELP_COMMON_ARGS << " <server-address>\n"
+ << "\n"
+ << "Options:\n"
<< HELP_COMMON_INFO_1 << WINAPI_INFO << HELP_SYS_INFO
- << " --yscroll <delta> defines the vertical scrolling delta, which is" << std::endl
- << " 120 by default." << std::endl
+ << " --yscroll <delta> defines the vertical scrolling delta, which is\n"
+ << " 120 by default.\n"
<< HELP_COMMON_INFO_2
- << std::endl
- << "Default options are marked with a *" << std::endl
- << std::endl
- << "The server address is of the form: [<hostname>][:<port>]. The hostname" << std::endl
- << "must be the address or hostname of the server. Placing brackets around" << std::endl
- << "an IPv6 address is required when also specifying a port number and " << std::endl
- << "optional otherwise. The default port number is " << kDefaultPort << "." << std::endl;
+ << "\n"
+ << "Default options are marked with a *\n"
+ << "\n"
+ << "The server address is of the form: [<hostname>][:<port>]. The hostname\n"
+ << "must be the address or hostname of the server. Placing brackets around\n"
+ << "an IPv6 address is required when also specifying a port number and \n"
+ << "optional otherwise. The default port number is " << kDefaultPort << ".\n";
LOG((CLOG_PRINT "%s", buffer.str().c_str()));
}
@@ -235,6 +233,9 @@ barrier::Screen*
ClientApp::openClientScreen()
{
barrier::Screen* screen = createScreen();
+ if (!argsBase().m_dropTarget.empty()) {
+ screen->setDropTarget(argsBase().m_dropTarget);
+ }
screen->setEnableDragDrop(argsBase().m_enableDragDrop);
m_events->adoptHandler(m_events->forIScreen().error(),
screen->getEventTarget(),
@@ -449,7 +450,7 @@ ClientApp::mainLoop()
// start client, etc
appUtil().startNode();
-
+
// init ipc client after node start, since create a new screen wipes out
// the event queue (the screen ctors call adoptBuffer).
if (argsBase().m_enableIpc) {
@@ -460,24 +461,21 @@ ClientApp::mainLoop()
// later. the timer installed by startClient() will take care of
// that.
DAEMON_RUNNING(true);
-
+
#if defined(MAC_OS_X_VERSION_10_7)
-
- Thread thread(
- new TMethodJob<ClientApp>(
- this, &ClientApp::runEventsLoop,
- NULL));
-
+
+ Thread thread([this](){ run_events_loop(); });
+
// wait until carbon loop is ready
OSXScreen* screen = dynamic_cast<OSXScreen*>(
m_clientScreen->getPlatformScreen());
screen->waitForCarbonLoop();
-
+
runCocoaApp();
#else
m_events->loop();
#endif
-
+
DAEMON_RUNNING(false);
// close down
@@ -519,7 +517,7 @@ ClientApp::runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc
{
// general initialization
m_serverAddress = new NetworkAddress;
- args().m_exename = PathUtilities::basename(argv[0]);
+ argsBase().m_exename = ArgParser::parse_exename(argv[0]);
// install caller's output filter
if (outputter != NULL) {
@@ -548,7 +546,7 @@ ClientApp::runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc
return result;
}
-void
+void
ClientApp::startNode()
{
// start the client. if this return false then we've failed and
diff --git a/src/lib/barrier/ClientApp.h b/src/lib/barrier/ClientApp.h
index 777f3d3..d1db8d0 100644
--- a/src/lib/barrier/ClientApp.h
+++ b/src/lib/barrier/ClientApp.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -24,7 +24,6 @@ namespace barrier { class Screen; }
class Event;
class Client;
class NetworkAddress;
-class Thread;
class ClientArgs;
class ClientApp : public App {
@@ -64,7 +63,7 @@ public:
void handleClientConnected(const Event&, void*);
void handleClientFailed(const Event& e, void*);
void handleClientDisconnected(const Event&, void*);
- Client* openClient(const String& name, const NetworkAddress& address,
+ Client* openClient(const String& name, const NetworkAddress& address,
barrier::Screen* screen);
void closeClient(Client* client);
bool startClient();
diff --git a/src/lib/barrier/ClientArgs.cpp b/src/lib/barrier/ClientArgs.cpp
index 5c9ed88..9d1d37a 100644
--- a/src/lib/barrier/ClientArgs.cpp
+++ b/src/lib/barrier/ClientArgs.cpp
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2014-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/barrier/ClientArgs.h b/src/lib/barrier/ClientArgs.h
index 70285fa..c11fa28 100644
--- a/src/lib/barrier/ClientArgs.h
+++ b/src/lib/barrier/ClientArgs.h
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2014-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/barrier/ClientTaskBarReceiver.cpp b/src/lib/barrier/ClientTaskBarReceiver.cpp
index 2ea6566..ea29f3d 100644
--- a/src/lib/barrier/ClientTaskBarReceiver.cpp
+++ b/src/lib/barrier/ClientTaskBarReceiver.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2003 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/barrier/ClientTaskBarReceiver.h b/src/lib/barrier/ClientTaskBarReceiver.h
index da15154..b79b958 100644
--- a/src/lib/barrier/ClientTaskBarReceiver.h
+++ b/src/lib/barrier/ClientTaskBarReceiver.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2003 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/barrier/Clipboard.cpp b/src/lib/barrier/Clipboard.cpp
index a6a166d..d7ad0b8 100644
--- a/src/lib/barrier/Clipboard.cpp
+++ b/src/lib/barrier/Clipboard.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/barrier/Clipboard.h b/src/lib/barrier/Clipboard.h
index 23bea75..5365a8c 100644
--- a/src/lib/barrier/Clipboard.h
+++ b/src/lib/barrier/Clipboard.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/barrier/ClipboardChunk.cpp b/src/lib/barrier/ClipboardChunk.cpp
index bc71471..c2ffab0 100644
--- a/src/lib/barrier/ClipboardChunk.cpp
+++ b/src/lib/barrier/ClipboardChunk.cpp
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2015-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -74,7 +74,7 @@ ClipboardChunk::end(ClipboardID id, UInt32 sequence)
{
ClipboardChunk* end = new ClipboardChunk(CLIPBOARD_CHUNK_META_SIZE);
char* chunk = end->m_chunk;
-
+
chunk[0] = id;
std::memcpy (&chunk[1], &sequence, 4);
chunk[5] = kDataEnd;
@@ -95,7 +95,7 @@ ClipboardChunk::assemble(barrier::IStream* stream,
if (!ProtocolUtil::readf(stream, kMsgDClipboard + 4, &id, &sequence, &mark, &data)) {
return kError;
}
-
+
if (mark == kDataStart) {
s_expectedSize = barrier::string::stringToSizeType(data);
LOG((CLOG_DEBUG "start receiving clipboard data"));
diff --git a/src/lib/barrier/ClipboardChunk.h b/src/lib/barrier/ClipboardChunk.h
index 6402aca..a96877f 100644
--- a/src/lib/barrier/ClipboardChunk.h
+++ b/src/lib/barrier/ClipboardChunk.h
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2015-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/barrier/DragInformation.cpp b/src/lib/barrier/DragInformation.cpp
index db28f3d..5a46678 100644
--- a/src/lib/barrier/DragInformation.cpp
+++ b/src/lib/barrier/DragInformation.cpp
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2013-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -41,7 +41,7 @@ DragInformation::parseDragInfo(DragFileList& dragFileList, UInt32 fileNum, Strin
if (data.find("/", startPos) != string::npos) {
slash = "/";
}
-
+
UInt32 index = 0;
while (index < fileNum) {
findResult1 = data.find(',', startPos);
@@ -51,7 +51,7 @@ DragInformation::parseDragInfo(DragFileList& dragFileList, UInt32 fileNum, Strin
//TODO: file number does not match, something goes wrong
break;
}
-
+
// set filename
if (findResult1 - findResult2 > 1) {
String filename = data.substr(findResult2 + 1,
@@ -61,7 +61,7 @@ DragInformation::parseDragInfo(DragFileList& dragFileList, UInt32 fileNum, Strin
dragFileList.push_back(di);
}
startPos = findResult1 + 1;
-
+
//set filesize
findResult2 = data.find(',', startPos);
if (findResult2 - findResult1 > 1) {
@@ -71,7 +71,7 @@ DragInformation::parseDragInfo(DragFileList& dragFileList, UInt32 fileNum, Strin
dragFileList.at(index).setFilesize(size);
}
startPos = findResult1 + 1;
-
+
++index;
}
@@ -151,8 +151,8 @@ DragInformation::getFileSize(String& filename)
stringstream ss;
ss << size;
-
+
file. close();
-
+
return ss.str();
}
diff --git a/src/lib/barrier/DragInformation.h b/src/lib/barrier/DragInformation.h
index b985bd1..a5d76b0 100644
--- a/src/lib/barrier/DragInformation.h
+++ b/src/lib/barrier/DragInformation.h
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2013-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -28,12 +28,12 @@ class DragInformation {
public:
DragInformation();
~DragInformation() { }
-
+
String& getFilename() { return m_filename; }
void setFilename(String& name) { m_filename = name; }
size_t getFilesize() { return m_filesize; }
void setFilesize(size_t size) { m_filesize = size; }
-
+
static void parseDragInfo(DragFileList& dragFileList, UInt32 fileNum, String data);
static String getDragFileExtension(String filename);
// helper function to setup drag info
diff --git a/src/lib/barrier/DropHelper.cpp b/src/lib/barrier/DropHelper.cpp
index ee5e5ee..af22b52 100644
--- a/src/lib/barrier/DropHelper.cpp
+++ b/src/lib/barrier/DropHelper.cpp
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2014-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -18,6 +18,7 @@
#include "barrier/DropHelper.h"
#include "base/Log.h"
+#include "io/filesystem.h"
#include <fstream>
@@ -35,15 +36,15 @@ DropHelper::writeToDir(const String& destination, DragFileList& fileList, String
dropTarget.append("/");
#endif
dropTarget.append(fileList.at(0).getFilename());
- file.open(dropTarget.c_str(), std::ios::out | std::ios::binary);
+ barrier::open_utf8_path(file, dropTarget, std::ios::out | std::ios::binary);
if (!file.is_open()) {
LOG((CLOG_ERR "drop file failed: can not open %s", dropTarget.c_str()));
}
-
+
file.write(data.c_str(), data.size());
file.close();
- LOG((CLOG_DEBUG "%s is saved to %s", fileList.at(0).getFilename().c_str(), destination.c_str()));
+ LOG((CLOG_INFO "dropped file \"%s\" in \"%s\"", fileList.at(0).getFilename().c_str(), destination.c_str()));
fileList.clear();
}
diff --git a/src/lib/barrier/DropHelper.h b/src/lib/barrier/DropHelper.h
index 67facbb..801779c 100644
--- a/src/lib/barrier/DropHelper.h
+++ b/src/lib/barrier/DropHelper.h
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2014-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/barrier/FileChunk.cpp b/src/lib/barrier/FileChunk.cpp
index 3a98568..08c489b 100644
--- a/src/lib/barrier/FileChunk.cpp
+++ b/src/lib/barrier/FileChunk.cpp
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2015-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/barrier/FileChunk.h b/src/lib/barrier/FileChunk.h
index bdc2f64..bdb5006 100644
--- a/src/lib/barrier/FileChunk.h
+++ b/src/lib/barrier/FileChunk.h
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2015-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/barrier/IApp.h b/src/lib/barrier/IApp.h
index 3a8cd56..0c516b9 100644
--- a/src/lib/barrier/IApp.h
+++ b/src/lib/barrier/IApp.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/barrier/IAppUtil.h b/src/lib/barrier/IAppUtil.h
index 39df65d..521bfce 100644
--- a/src/lib/barrier/IAppUtil.h
+++ b/src/lib/barrier/IAppUtil.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-
+
#pragma once
#include "common/IInterface.h"
diff --git a/src/lib/barrier/IClient.h b/src/lib/barrier/IClient.h
index d9b2194..e1382b7 100644
--- a/src/lib/barrier/IClient.h
+++ b/src/lib/barrier/IClient.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/barrier/IClipboard.cpp b/src/lib/barrier/IClipboard.cpp
index 19b4b56..d484121 100644
--- a/src/lib/barrier/IClipboard.cpp
+++ b/src/lib/barrier/IClipboard.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -66,13 +66,13 @@ IClipboard::unmarshall(IClipboard* clipboard, const String& data, Time time)
String
IClipboard::marshall(const IClipboard* clipboard)
{
- // return data format:
+ // return data format:
// 4 bytes => number of formats included
// 4 bytes => format enum
// 4 bytes => clipboard data size n
// n bytes => clipboard data
// back to the second 4 bytes if there is another format
-
+
assert(clipboard != NULL);
String data;
diff --git a/src/lib/barrier/IClipboard.h b/src/lib/barrier/IClipboard.h
index e11b264..436b21b 100644
--- a/src/lib/barrier/IClipboard.h
+++ b/src/lib/barrier/IClipboard.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/barrier/IKeyState.cpp b/src/lib/barrier/IKeyState.cpp
index 5d1114c..e89c0e9 100644
--- a/src/lib/barrier/IKeyState.cpp
+++ b/src/lib/barrier/IKeyState.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/barrier/IKeyState.h b/src/lib/barrier/IKeyState.h
index b9d4706..e7f88fa 100644
--- a/src/lib/barrier/IKeyState.h
+++ b/src/lib/barrier/IKeyState.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2003 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -122,14 +122,14 @@ public:
complete and false if normal key processing should continue.
*/
virtual bool fakeCtrlAltDel() = 0;
-
+
//! Fake a media key
/*!
Synthesizes a media key down and up. Only Mac would implement this by
use cocoa appkit framework.
*/
virtual bool fakeMediaKey(KeyID id) = 0;
-
+
//@}
//! @name accessors
//@{
diff --git a/src/lib/barrier/INode.h b/src/lib/barrier/INode.h
index 2e78f7c..02fd9de 100644
--- a/src/lib/barrier/INode.h
+++ b/src/lib/barrier/INode.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -21,5 +21,5 @@
#include "common/IInterface.h"
class INode : IInterface {
-
+
};
diff --git a/src/lib/barrier/IPlatformScreen.cpp b/src/lib/barrier/IPlatformScreen.cpp
index d1d9f78..a037f75 100644
--- a/src/lib/barrier/IPlatformScreen.cpp
+++ b/src/lib/barrier/IPlatformScreen.cpp
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2016 Symless.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/barrier/IPlatformScreen.h b/src/lib/barrier/IPlatformScreen.h
index 440e218..995ff73 100644
--- a/src/lib/barrier/IPlatformScreen.h
+++ b/src/lib/barrier/IPlatformScreen.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -197,7 +197,8 @@ public:
virtual void fakeDraggingFiles(DragFileList fileList) = 0;
virtual const String&
getDropTarget() const = 0;
-
+ virtual void setDropTarget(const String&) = 0;
+
protected:
//! Handle system event
/*!
diff --git a/src/lib/barrier/IPrimaryScreen.cpp b/src/lib/barrier/IPrimaryScreen.cpp
index 4954e4f..2220212 100644
--- a/src/lib/barrier/IPrimaryScreen.cpp
+++ b/src/lib/barrier/IPrimaryScreen.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/barrier/IPrimaryScreen.h b/src/lib/barrier/IPrimaryScreen.h
index 7f3fa9c..0cf3688 100644
--- a/src/lib/barrier/IPrimaryScreen.h
+++ b/src/lib/barrier/IPrimaryScreen.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2003 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/barrier/IScreen.h b/src/lib/barrier/IScreen.h
index 47d6578..a1e7c47 100644
--- a/src/lib/barrier/IScreen.h
+++ b/src/lib/barrier/IScreen.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2003 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -66,6 +66,6 @@ public:
Return the current position of the cursor in \c x and \c y.
*/
virtual void getCursorPos(SInt32& x, SInt32& y) const = 0;
-
+
//@}
};
diff --git a/src/lib/barrier/IScreenSaver.h b/src/lib/barrier/IScreenSaver.h
index fc21ac5..2099f6d 100644
--- a/src/lib/barrier/IScreenSaver.h
+++ b/src/lib/barrier/IScreenSaver.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -56,7 +56,7 @@ public:
//! Deactivate screen saver
/*!
- Deactivate (i.e. hide) the screen saver, reseting the screen saver
+ Deactivate (i.e. hide) the screen saver, resetting the screen saver
timer.
*/
virtual void deactivate() = 0;
diff --git a/src/lib/barrier/ISecondaryScreen.h b/src/lib/barrier/ISecondaryScreen.h
index 527ca2e..85da511 100644
--- a/src/lib/barrier/ISecondaryScreen.h
+++ b/src/lib/barrier/ISecondaryScreen.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2003 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/barrier/KeyMap.cpp b/src/lib/barrier/KeyMap.cpp
index 621e747..7d53deb 100644
--- a/src/lib/barrier/KeyMap.cpp
+++ b/src/lib/barrier/KeyMap.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2005 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -733,7 +733,7 @@ KeyMap::keyForModifier(KeyButton button, SInt32 group,
assert(modifierBit >= 0 && modifierBit < kKeyModifierNumBits);
assert(group >= 0 && group < getNumGroups());
- // find a key that generates the given modifier in the given group
+ // find a key that generates the given modifier in the given group
// but doesn't use the given button, presumably because we're trying
// to generate a KeyID that's only bound the the given button.
// this is important when a shift button is modified by shift; we
@@ -989,7 +989,7 @@ KeyMap::addKeystrokes(EKeystroke type, const KeyItem& keyItem,
}
}
break;
-
+
case kKeystrokeRelease:
keystrokes.push_back(Keystroke(button, false, false, data));
if (keyItem.m_generates != 0 && !keyItem.m_lock) {
@@ -1011,19 +1011,19 @@ KeyMap::addKeystrokes(EKeystroke type, const KeyItem& keyItem,
}
}
break;
-
+
case kKeystrokeRepeat:
keystrokes.push_back(Keystroke(button, false, true, data));
keystrokes.push_back(Keystroke(button, true, true, data));
// no modifier changes on key repeat
break;
-
+
case kKeystrokeClick:
keystrokes.push_back(Keystroke(button, true, false, data));
keystrokes.push_back(Keystroke(button, false, false, data));
// no modifier changes on key click
break;
-
+
case kKeystrokeModify:
case kKeystrokeUnmodify:
if (keyItem.m_lock) {
diff --git a/src/lib/barrier/KeyMap.h b/src/lib/barrier/KeyMap.h
index b6eb865..bc72020 100644
--- a/src/lib/barrier/KeyMap.h
+++ b/src/lib/barrier/KeyMap.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2005 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -24,7 +24,9 @@
#include "common/stdset.h"
#include "common/stdvector.h"
+#ifdef BARRIER_TEST_ENV
#include <gtest/gtest_prod.h>
+#endif
namespace barrier {
@@ -320,13 +322,14 @@ public:
Converts a string into a modifier mask. Returns \c true on success
and \c false if the string cannot be parsed. The modifiers plus any
remaining leading and trailing whitespace is stripped from the input
- string.
+ string.
*/
static bool parseModifiers(String&, KeyModifierMask&);
//@}
private:
+#ifdef BARRIER_TEST_ENV
FRIEND_TEST(KeyMapTests,
findBestKey_requiredDown_matchExactFirstItem);
FRIEND_TEST(KeyMapTests,
@@ -340,6 +343,7 @@ private:
FRIEND_TEST(KeyMapTests,
findBestKey_onlyOneRequiredDown_matchTwoRequiredChangesItem);
FRIEND_TEST(KeyMapTests, findBestKey_noRequiredDown_cannotMatch);
+#endif
private:
//! Ways to synthesize a key
@@ -351,7 +355,7 @@ private:
kKeystrokeModify, //!< Synthesize pressing a modifier
kKeystrokeUnmodify //!< Synthesize releasing a modifier
};
-
+
// A list of ways to synthesize a KeyID
typedef std::vector<KeyItemList> KeyEntryList;
diff --git a/src/lib/barrier/KeyState.cpp b/src/lib/barrier/KeyState.cpp
index fc5579d..4c04277 100644
--- a/src/lib/barrier/KeyState.cpp
+++ b/src/lib/barrier/KeyState.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -529,7 +529,7 @@ KeyState::addActiveModifierCB(KeyID, SInt32 group,
(keyItem.m_generates & context->m_mask) != 0) {
context->m_activeModifiers.insert(std::make_pair(
keyItem.m_generates, keyItem));
- }
+ }
}
void
@@ -581,10 +581,10 @@ KeyState::fakeKeyDown(KeyID id, KeyModifierMask mask, KeyButton serverID)
LOG((CLOG_DEBUG1 "emulating media key"));
fakeMediaKey(id);
}
-
+
return;
}
-
+
KeyButton localID = (KeyButton)(keyItem->m_button & kButtonMask);
updateModifierKeyState(localID, oldActiveModifiers, m_activeModifiers);
if (localID != 0) {
diff --git a/src/lib/barrier/KeyState.h b/src/lib/barrier/KeyState.h
index 737d515..6f32b5d 100644
--- a/src/lib/barrier/KeyState.h
+++ b/src/lib/barrier/KeyState.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -74,7 +74,7 @@ public:
virtual void fakeAllKeysUp();
virtual bool fakeCtrlAltDel() = 0;
virtual bool fakeMediaKey(KeyID id);
-
+
virtual bool isKeyDown(KeyButton) const;
virtual KeyModifierMask
getActiveModifiers() const;
@@ -157,7 +157,7 @@ public:
AddActiveModifierContext& operator=(const AddActiveModifierContext&);
};
private:
-
+
class ButtonToKeyLess {
public:
bool operator()(const barrier::KeyMap::ButtonToKeyMap::value_type& a,
diff --git a/src/lib/barrier/PacketStreamFilter.cpp b/src/lib/barrier/PacketStreamFilter.cpp
index 16f0fe7..5955b6c 100644
--- a/src/lib/barrier/PacketStreamFilter.cpp
+++ b/src/lib/barrier/PacketStreamFilter.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -17,6 +17,7 @@
*/
#include "barrier/PacketStreamFilter.h"
+#include "barrier/protocol_types.h"
#include "base/IEventQueue.h"
#include "mt/Lock.h"
#include "base/TMethodEventJob.h"
@@ -133,8 +134,7 @@ PacketStreamFilter::isReadyNoLock() const
return (m_size != 0 && m_buffer.getSize() >= m_size);
}
-void
-PacketStreamFilter::readPacketSize()
+bool PacketStreamFilter::readPacketSize()
{
// note -- m_mutex must be locked on entry
@@ -146,7 +146,13 @@ PacketStreamFilter::readPacketSize()
((UInt32)buffer[1] << 16) |
((UInt32)buffer[2] << 8) |
(UInt32)buffer[3];
+
+ if (m_size > PROTOCOL_MAX_MESSAGE_LENGTH) {
+ m_events->addEvent(Event(m_events->forIStream().inputFormatError(), getEventTarget()));
+ return false;
+ }
}
+ return true;
}
bool
@@ -160,13 +166,17 @@ PacketStreamFilter::readMore()
UInt32 n = getStream()->read(buffer, sizeof(buffer));
while (n > 0) {
m_buffer.write(buffer, n);
+
+ // if we don't yet have the next packet size then get it, if possible.
+ // Note that we can't wait for whole pending data to arrive because it may be huge in
+ // case of malicious or erroneous peer.
+ if (!readPacketSize()) {
+ break;
+ }
+
n = getStream()->read(buffer, sizeof(buffer));
}
- // if we don't yet have the next packet size then get it,
- // if possible.
- readPacketSize();
-
// note if we now have a whole packet
bool isReady = isReadyNoLock();
diff --git a/src/lib/barrier/PacketStreamFilter.h b/src/lib/barrier/PacketStreamFilter.h
index bcbd604..0c4bb04 100644
--- a/src/lib/barrier/PacketStreamFilter.h
+++ b/src/lib/barrier/PacketStreamFilter.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -24,7 +24,7 @@
class IEventQueue;
-//! Packetizing stream filter
+//! Packetizing stream filter
/*!
Filters a stream to read and write packets.
*/
@@ -47,7 +47,9 @@ protected:
private:
bool isReadyNoLock() const;
- void readPacketSize();
+
+ // returns false on erroneous packet size
+ bool readPacketSize();
bool readMore();
private:
diff --git a/src/lib/barrier/PlatformScreen.cpp b/src/lib/barrier/PlatformScreen.cpp
index b0fdc75..d72e69a 100644
--- a/src/lib/barrier/PlatformScreen.cpp
+++ b/src/lib/barrier/PlatformScreen.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/barrier/PlatformScreen.h b/src/lib/barrier/PlatformScreen.h
index 38bf8de..19a3da1 100644
--- a/src/lib/barrier/PlatformScreen.h
+++ b/src/lib/barrier/PlatformScreen.h
@@ -101,6 +101,7 @@ public:
virtual void fakeDraggingFiles(DragFileList fileList) { throw std::runtime_error("fakeDraggingFiles not implemented"); }
virtual const String&
getDropTarget() const { throw std::runtime_error("getDropTarget not implemented"); }
+ virtual void setDropTarget(const String&) { throw std::runtime_error("setDropTarget not implemented"); }
protected:
//! Update mouse buttons
diff --git a/src/lib/barrier/PortableTaskBarReceiver.cpp b/src/lib/barrier/PortableTaskBarReceiver.cpp
index 384cacd..e9a5f40 100644
--- a/src/lib/barrier/PortableTaskBarReceiver.cpp
+++ b/src/lib/barrier/PortableTaskBarReceiver.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2003 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -111,7 +111,7 @@ PortableTaskBarReceiver::getToolTip() const
case kNotWorking:
return barrier::string::sprintf("%s: %s",
kAppVersion, m_errorMessage.c_str());
-
+
case kNotConnected:
return barrier::string::sprintf("%s: Unknown", kAppVersion);
diff --git a/src/lib/barrier/PortableTaskBarReceiver.h b/src/lib/barrier/PortableTaskBarReceiver.h
index d335e44..3db27ba 100644
--- a/src/lib/barrier/PortableTaskBarReceiver.h
+++ b/src/lib/barrier/PortableTaskBarReceiver.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2003 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/barrier/ProtocolUtil.cpp b/src/lib/barrier/ProtocolUtil.cpp
index e742687..5a71010 100644
--- a/src/lib/barrier/ProtocolUtil.cpp
+++ b/src/lib/barrier/ProtocolUtil.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -19,6 +19,8 @@
#include "barrier/ProtocolUtil.h"
#include "io/IStream.h"
#include "base/Log.h"
+#include "barrier/protocol_types.h"
+#include "barrier/XBarrier.h"
#include "common/stdvector.h"
#include "base/String.h"
@@ -80,7 +82,7 @@ ProtocolUtil::vwritef(barrier::IStream* stream,
// fill buffer
UInt8* buffer = new UInt8[size];
- writef(buffer, fmt, args);
+ writef_void(buffer, fmt, args);
try {
// write buffer
@@ -159,6 +161,10 @@ ProtocolUtil::vreadf(barrier::IStream* stream, const char* fmt, va_list args)
(static_cast<UInt32>(buffer[2]) << 8) |
static_cast<UInt32>(buffer[3]);
+ if (n > PROTOCOL_MAX_LIST_LENGTH) {
+ throw XBadClient("Too long message received");
+ }
+
// convert it
void* v = va_arg(args, void*);
switch (len) {
@@ -211,6 +217,10 @@ ProtocolUtil::vreadf(barrier::IStream* stream, const char* fmt, va_list args)
(static_cast<UInt32>(buffer[2]) << 8) |
static_cast<UInt32>(buffer[3]);
+ if (len > PROTOCOL_MAX_STRING_LENGTH) {
+ throw XBadClient("Too long message received");
+ }
+
// use a fixed size buffer if its big enough
const bool useFixed = (len <= sizeof(buffer));
@@ -339,7 +349,7 @@ ProtocolUtil::getLength(const char* fmt, va_list args)
}
void
-ProtocolUtil::writef(void* buffer, const char* fmt, va_list args)
+ProtocolUtil::writef_void(void* buffer, const char* fmt, va_list args)
{
UInt8* dst = static_cast<UInt8*>(buffer);
diff --git a/src/lib/barrier/ProtocolUtil.h b/src/lib/barrier/ProtocolUtil.h
index 9930cfc..af4fea8 100644
--- a/src/lib/barrier/ProtocolUtil.h
+++ b/src/lib/barrier/ProtocolUtil.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -38,7 +38,7 @@ public:
regular characters and format specifiers. Format specifiers
begin with \%. All characters not part of a format specifier
are regular and are transmitted unchanged.
-
+
Format specifiers are:
- \%\% -- literal `\%'
- \%1i -- converts integer argument to 1 byte integer
@@ -58,7 +58,7 @@ public:
Read formatted binary data from a buffer. This performs the
reverse operation of writef(). Returns true if the entire
format was successfully parsed, false otherwise.
-
+
Format specifiers are:
- \%\% -- read (and discard) a literal `\%'
- \%1i -- reads a 1 byte integer; argument is a SInt32* or UInt32*
@@ -79,7 +79,7 @@ private:
const char* fmt, va_list);
static UInt32 getLength(const char* fmt, va_list);
- static void writef(void*, const char* fmt, va_list);
+ static void writef_void(void*, const char* fmt, va_list);
static UInt32 eatLength(const char** fmt);
static void read(barrier::IStream*, void*, UInt32);
};
diff --git a/src/lib/barrier/Screen.cpp b/src/lib/barrier/Screen.cpp
index 32442f6..2a2c877 100644
--- a/src/lib/barrier/Screen.cpp
+++ b/src/lib/barrier/Screen.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2003 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -376,7 +376,7 @@ Screen::isLockedToScreen() const
if (buttonID != kButtonLeft) {
LOG((CLOG_DEBUG "locked by mouse buttonID: %d", buttonID));
}
-
+
if (m_enableDragDrop) {
return (buttonID == kButtonLeft) ? false : true;
}
@@ -466,6 +466,12 @@ Screen::getDropTarget() const
return m_screen->getDropTarget();
}
+void
+Screen::setDropTarget(const String& target)
+{
+ return m_screen->setDropTarget(target);
+}
+
void*
Screen::getEventTarget() const
{
diff --git a/src/lib/barrier/Screen.h b/src/lib/barrier/Screen.h
index b16feff..1c8e7de 100644
--- a/src/lib/barrier/Screen.h
+++ b/src/lib/barrier/Screen.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -42,7 +42,7 @@ public:
Screen(IPlatformScreen* platformScreen, IEventQueue* events);
virtual ~Screen();
-#ifdef TEST_ENV
+#ifdef BARRIER_TEST_ENV
Screen() : m_mock(true) { }
#endif
@@ -223,7 +223,7 @@ public:
//! Change dragging status
void setDraggingStarted(bool started);
-
+
//! Fake a files dragging operation
void startDraggingFiles(DragFileList& fileList);
@@ -278,7 +278,7 @@ public:
//! Test if file is dragged on primary screen
bool isDraggingStarted() const;
-
+
//! Test if file is dragged on secondary screen
bool isFakeDraggingStarted() const;
@@ -290,6 +290,8 @@ public:
//! Get the drop target directory
const String& getDropTarget() const;
+ //! Set the drop target directory
+ void setDropTarget(const String&);
//@}
@@ -299,7 +301,7 @@ public:
virtual void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const;
virtual void getCursorPos(SInt32& x, SInt32& y) const;
-
+
IPlatformScreen* getPlatformScreen() { return m_screen; }
protected:
diff --git a/src/lib/barrier/ServerApp.cpp b/src/lib/barrier/ServerApp.cpp
index 18cf935..71158ce 100644
--- a/src/lib/barrier/ServerApp.cpp
+++ b/src/lib/barrier/ServerApp.cpp
@@ -34,13 +34,11 @@
#include "base/EventQueue.h"
#include "base/log_outputters.h"
#include "base/FunctionEventJob.h"
-#include "base/TMethodJob.h"
#include "base/IEventQueue.h"
#include "base/Log.h"
#include "base/TMethodEventJob.h"
#include "common/Version.h"
#include "common/DataDirectories.h"
-#include "common/PathUtilities.h"
#if SYSAPI_WIN32
#include "arch/win32/ArchMiscWindows.h"
@@ -128,30 +126,43 @@ ServerApp::help()
# define WINAPI_INFO ""
#endif
+ // refer to custom profile directory even if not saved yet
+ barrier::fs::path profile_path = argsBase().m_profileDirectory;
+ if (profile_path.empty()) {
+ profile_path = barrier::DataDirectories::profile();
+ }
+
+ auto usr_config_path = (profile_path / barrier::fs::u8path(USR_CONFIG_NAME)).u8string();
+ auto sys_config_path = (barrier::DataDirectories::systemconfig() /
+ barrier::fs::u8path(SYS_CONFIG_NAME)).u8string();
+
std::ostringstream buffer;
- buffer << "Start the barrier server component." << std::endl
- << std::endl
+ buffer << "Start the barrier server component.\n"
+ << "\n"
<< "Usage: " << args().m_exename
<< " [--address <address>]"
<< " [--config <pathname>]"
- << WINAPI_ARGS << HELP_SYS_ARGS << HELP_COMMON_ARGS << std::endl
- << std::endl
- << "Options:" << std::endl
- << " -a, --address <address> listen for clients on the given address." << std::endl
- << " -c, --config <pathname> use the named configuration file instead." << std::endl
- << HELP_COMMON_INFO_1 << WINAPI_INFO << HELP_SYS_INFO << HELP_COMMON_INFO_2 << std::endl
- << "Default options are marked with a *" << std::endl
- << std::endl
- << "The argument for --address is of the form: [<hostname>][:<port>]. The" << std::endl
- << "hostname must be the address or hostname of an interface on the system." << std::endl
- << "Placing brackets around an IPv6 address is required when also specifying " << std::endl
- << "a port number and optional otherwise. The default is to listen on all" << std::endl
- << "interfaces using port number " << kDefaultPort << "." << std::endl
- << std::endl
- << "If no configuration file pathname is provided then the first of the" << std::endl
- << "following to load successfully sets the configuration:" << std::endl
- << " " << PathUtilities::concat(DataDirectories::profile(), USR_CONFIG_NAME) << std::endl
- << " " << PathUtilities::concat(DataDirectories::systemconfig(), SYS_CONFIG_NAME) << std::endl;
+ << WINAPI_ARGS << HELP_SYS_ARGS << HELP_COMMON_ARGS << "\n"
+ << "\n"
+ << "Options:\n"
+ << " -a, --address <address> listen for clients on the given address.\n"
+ << " -c, --config <pathname> use the named configuration file instead.\n"
+ << HELP_COMMON_INFO_1
+ << " --disable-client-cert-checking disable client SSL certificate \n"
+ " checking (deprecated)\n"
+ << WINAPI_INFO << HELP_SYS_INFO << HELP_COMMON_INFO_2 << "\n"
+ << "Default options are marked with a *\n"
+ << "\n"
+ << "The argument for --address is of the form: [<hostname>][:<port>]. The\n"
+ << "hostname must be the address or hostname of an interface on the system.\n"
+ << "Placing brackets around an IPv6 address is required when also specifying \n"
+ << "a port number and optional otherwise. The default is to listen on all\n"
+ << "interfaces using port number " << kDefaultPort << ".\n"
+ << "\n"
+ << "If no configuration file pathname is provided then the first of the\n"
+ << "following to load successfully sets the configuration:\n"
+ << " " << usr_config_path << "\n"
+ << " " << sys_config_path << "\n";
LOG((CLOG_PRINT "%s", buffer.str().c_str()));
}
@@ -188,25 +199,25 @@ ServerApp::loadConfig()
// load the default configuration if no explicit file given
else {
- String path = DataDirectories::profile();
+ auto path = barrier::DataDirectories::profile();
if (!path.empty()) {
// complete path
- path = PathUtilities::concat(path, USR_CONFIG_NAME);
+ path /= barrier::fs::u8path(USR_CONFIG_NAME);
// now try loading the user's configuration
- if (loadConfig(path)) {
+ if (loadConfig(path.u8string())) {
loaded = true;
- args().m_configFile = path;
+ args().m_configFile = path.u8string();
}
}
if (!loaded) {
// try the system-wide config file
- path = DataDirectories::systemconfig();
+ path = barrier::DataDirectories::systemconfig();
if (!path.empty()) {
- path = PathUtilities::concat(path, SYS_CONFIG_NAME);
- if (loadConfig(path)) {
+ path /= barrier::fs::u8path(SYS_CONFIG_NAME);
+ if (loadConfig(path.u8string())) {
loaded = true;
- args().m_configFile = path;
+ args().m_configFile = path.u8string();
}
}
}
@@ -496,6 +507,9 @@ barrier::Screen*
ServerApp::openServerScreen()
{
barrier::Screen* screen = createScreen();
+ if (!argsBase().m_dropTarget.empty()) {
+ screen->setDropTarget(argsBase().m_dropTarget);
+ }
screen->setEnableDragDrop(argsBase().m_enableDragDrop);
m_events->adoptHandler(m_events->forIScreen().error(),
screen->getEventTarget(),
@@ -643,11 +657,18 @@ ServerApp::handleResume(const Event&, void*)
ClientListener*
ServerApp::openClientListener(const NetworkAddress& address)
{
+ auto security_level = ConnectionSecurityLevel::PLAINTEXT;
+ if (args().m_enableCrypto) {
+ security_level = ConnectionSecurityLevel::ENCRYPTED;
+ if (args().check_client_certificates) {
+ security_level = ConnectionSecurityLevel::ENCRYPTED_AUTHENTICATED;
+ }
+ }
+
ClientListener* listen = new ClientListener(
address,
new TCPSocketFactory(m_events, getSocketMultiplexer()),
- m_events,
- args().m_enableCrypto);
+ m_events, security_level);
m_events->adoptHandler(
m_events->forClientListener().connected(), listen,
@@ -775,10 +796,7 @@ ServerApp::mainLoop()
#if defined(MAC_OS_X_VERSION_10_7)
- Thread thread(
- new TMethodJob<ServerApp>(
- this, &ServerApp::runEventsLoop,
- NULL));
+ Thread thread([this](){ run_events_loop(); });
// wait until carbon loop is ready
OSXScreen* screen = dynamic_cast<OSXScreen*>(
@@ -823,7 +841,7 @@ ServerApp::runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc
// general initialization
m_barrierAddress = new NetworkAddress;
args().m_config = new Config(m_events);
- args().m_exename = PathUtilities::basename(argv[0]);
+ args().m_exename = ArgParser::parse_exename(argv[0]);
// install caller's output filter
if (outputter != NULL) {
diff --git a/src/lib/barrier/ServerApp.h b/src/lib/barrier/ServerApp.h
index 528aa24..ca38568 100644
--- a/src/lib/barrier/ServerApp.h
+++ b/src/lib/barrier/ServerApp.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -51,7 +51,7 @@ class ServerApp : public App {
public:
ServerApp(IEventQueue* events, CreateTaskBarReceiverFunc createTaskBarReceiver);
virtual ~ServerApp();
-
+
// Parse server specific command line arguments.
void parseArgs(int argc, const char* const* argv);
@@ -104,7 +104,7 @@ public:
static ServerApp& instance() { return (ServerApp&)App::instance(); }
Server* getServerPtr() { return m_server; }
-
+
Server* m_server;
EServerState m_serverState;
barrier::Screen* m_serverScreen;
diff --git a/src/lib/barrier/ServerArgs.h b/src/lib/barrier/ServerArgs.h
index 6d91233..6323705 100644
--- a/src/lib/barrier/ServerArgs.h
+++ b/src/lib/barrier/ServerArgs.h
@@ -30,4 +30,5 @@ public:
String m_configFile;
Config* m_config;
String m_screenChangeScript;
+ bool check_client_certificates = true;
};
diff --git a/src/lib/barrier/ServerTaskBarReceiver.cpp b/src/lib/barrier/ServerTaskBarReceiver.cpp
index b427cd1..c3ba7cf 100644
--- a/src/lib/barrier/ServerTaskBarReceiver.cpp
+++ b/src/lib/barrier/ServerTaskBarReceiver.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2003 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -125,7 +125,7 @@ ServerTaskBarReceiver::getToolTip() const
case kNotWorking:
return barrier::string::sprintf("%s: %s",
kAppVersion, m_errorMessage.c_str());
-
+
case kNotConnected:
return barrier::string::sprintf("%s: Waiting for clients", kAppVersion);
diff --git a/src/lib/barrier/ServerTaskBarReceiver.h b/src/lib/barrier/ServerTaskBarReceiver.h
index 3cef9c0..086de8c 100644
--- a/src/lib/barrier/ServerTaskBarReceiver.h
+++ b/src/lib/barrier/ServerTaskBarReceiver.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2003 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/barrier/StreamChunker.cpp b/src/lib/barrier/StreamChunker.cpp
index 579d02f..0f6c0a9 100644
--- a/src/lib/barrier/StreamChunker.cpp
+++ b/src/lib/barrier/StreamChunker.cpp
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2013-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -42,14 +42,13 @@ bool StreamChunker::s_interruptFile = false;
Mutex* StreamChunker::s_interruptMutex = NULL;
void
-StreamChunker::sendFile(
- char* filename,
+StreamChunker::sendFile(const char* filename,
IEventQueue* events,
void* eventTarget)
{
s_isChunkingFile = true;
-
- std::fstream file(static_cast<char*>(filename), std::ios::in | std::ios::binary);
+
+ std::fstream file(filename, std::ios::in | std::ios::binary);
if (!file.is_open()) {
throw runtime_error("failed to open file");
@@ -76,9 +75,9 @@ StreamChunker::sendFile(
LOG((CLOG_DEBUG "file transmission interrupted"));
break;
}
-
+
events->addEvent(Event(events->forFile().keepAlive(), eventTarget));
-
+
// make sure we don't read too much from the mock data.
if (sentLength + chunkSize > size) {
chunkSize = size - sentLength;
@@ -106,7 +105,7 @@ StreamChunker::sendFile(
events->addEvent(Event(events->forFile().fileChunkSending(), eventTarget, end));
file.close();
-
+
s_isChunkingFile = false;
}
@@ -122,16 +121,16 @@ StreamChunker::sendClipboard(
// send first message (data size)
String dataSize = barrier::string::sizeTypeToString(size);
ClipboardChunk* sizeMessage = ClipboardChunk::start(id, sequence, dataSize);
-
+
events->addEvent(Event(events->forClipboard().clipboardSending(), eventTarget, sizeMessage));
// send clipboard chunk with a fixed size
size_t sentLength = 0;
size_t chunkSize = g_chunkSize;
-
+
while (true) {
events->addEvent(Event(events->forFile().keepAlive(), eventTarget));
-
+
// make sure we don't read too much from the mock data.
if (sentLength + chunkSize > size) {
chunkSize = size - sentLength;
@@ -139,7 +138,7 @@ StreamChunker::sendClipboard(
String chunk(data.substr(sentLength, chunkSize).c_str(), chunkSize);
ClipboardChunk* dataChunk = ClipboardChunk::data(id, sequence, chunk);
-
+
events->addEvent(Event(events->forClipboard().clipboardSending(), eventTarget, dataChunk));
sentLength += chunkSize;
@@ -152,7 +151,7 @@ StreamChunker::sendClipboard(
ClipboardChunk* end = ClipboardChunk::end(id, sequence);
events->addEvent(Event(events->forClipboard().clipboardSending(), eventTarget, end));
-
+
LOG((CLOG_DEBUG "sent clipboard size=%d", sentLength));
}
diff --git a/src/lib/barrier/StreamChunker.h b/src/lib/barrier/StreamChunker.h
index ab57c7e..ed5d83c 100644
--- a/src/lib/barrier/StreamChunker.h
+++ b/src/lib/barrier/StreamChunker.h
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2013-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -25,10 +25,7 @@ class Mutex;
class StreamChunker {
public:
- static void sendFile(
- char* filename,
- IEventQueue* events,
- void* eventTarget);
+ static void sendFile(const char* filename, IEventQueue* events, void* eventTarget);
static void sendClipboard(
String& data,
size_t size,
@@ -37,7 +34,7 @@ public:
IEventQueue* events,
void* eventTarget);
static void interruptFile();
-
+
private:
static bool s_isChunkingFile;
static bool s_interruptFile;
diff --git a/src/lib/barrier/XBarrier.cpp b/src/lib/barrier/XBarrier.cpp
index 7fe3577..44593d1 100644
--- a/src/lib/barrier/XBarrier.cpp
+++ b/src/lib/barrier/XBarrier.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -118,6 +118,6 @@ int XExitApp::getCode() const noexcept
String XExitApp::getWhat() const noexcept
{
return format(
- "XExitApp", "exiting with code %{1}",
+ "XExitApp", "exiting with code %{1}",
barrier::string::sprintf("%d", m_code).c_str());
}
diff --git a/src/lib/barrier/XBarrier.h b/src/lib/barrier/XBarrier.h
index fef931e..b7a3891 100644
--- a/src/lib/barrier/XBarrier.h
+++ b/src/lib/barrier/XBarrier.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -113,8 +113,8 @@ private:
//! Generic exit eception
/*!
-Thrown when we want to abort, with the opportunity to clean up. This is a
-little bit of a hack, but it's a better way of exiting, than just calling
+Thrown when we want to abort, with the opportunity to clean up. This is a
+little bit of a hack, but it's a better way of exiting, than just calling
exit(int).
*/
class XExitApp : public XBarrier {
@@ -127,7 +127,7 @@ public:
protected:
virtual std::string getWhat() const noexcept;
-
+
private:
int m_code;
};
diff --git a/src/lib/barrier/XScreen.cpp b/src/lib/barrier/XScreen.cpp
index 3398423..bb5c860 100644
--- a/src/lib/barrier/XScreen.cpp
+++ b/src/lib/barrier/XScreen.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/barrier/XScreen.h b/src/lib/barrier/XScreen.h
index f8fe7a7..7033556 100644
--- a/src/lib/barrier/XScreen.h
+++ b/src/lib/barrier/XScreen.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/barrier/clipboard_types.h b/src/lib/barrier/clipboard_types.h
index 54f2732..7de608c 100644
--- a/src/lib/barrier/clipboard_types.h
+++ b/src/lib/barrier/clipboard_types.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/barrier/key_types.cpp b/src/lib/barrier/key_types.cpp
index 902670d..33ee3eb 100644
--- a/src/lib/barrier/key_types.cpp
+++ b/src/lib/barrier/key_types.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -17,6 +17,7 @@
*/
#include "barrier/key_types.h"
+#include <cstddef>
const KeyNameMapEntry kKeyNameMap[] = {
{ "AltGr", kKeyAltGr },
@@ -43,6 +44,7 @@ const KeyNameMapEntry kKeyNameMap[] = {
{ "Control_R", kKeyControl_R },
{ "Delete", kKeyDelete },
{ "Down", kKeyDown },
+ { "EisuToggle", kKeyEisuToggle },
{ "Eject", kKeyEject },
{ "End", kKeyEnd },
{ "Escape", kKeyEscape },
@@ -89,6 +91,7 @@ const KeyNameMapEntry kKeyNameMap[] = {
{ "Hyper_L", kKeyHyper_L },
{ "Hyper_R", kKeyHyper_R },
{ "Insert", kKeyInsert },
+ { "Kana", kKeyKana },
{ "KP_0", kKeyKP_0 },
{ "KP_1", kKeyKP_1 },
{ "KP_2", kKeyKP_2 },
@@ -130,6 +133,7 @@ const KeyNameMapEntry kKeyNameMap[] = {
{ "Menu", kKeyMenu },
{ "Meta_L", kKeyMeta_L },
{ "Meta_R", kKeyMeta_R },
+ { "Muhenkan", kKeyMuhenkan },
{ "NumLock", kKeyNumLock },
{ "PageDown", kKeyPageDown },
{ "PageUp", kKeyPageUp },
@@ -191,6 +195,12 @@ const KeyNameMapEntry kKeyNameMap[] = {
{ "Bar", 0x007c },
{ "BraceR", 0x007d },
{ "Tilde", 0x007e },
+ { "Copy", kKeyCopy },
+ { "Cut", kKeyCut },
+ { "Open", kKeyOpen },
+ { "Paste", kKeyPaste },
+ { "Props", kKeyProps },
+ { "Front", kKeyFront },
{ NULL, 0 },
};
diff --git a/src/lib/barrier/key_types.h b/src/lib/barrier/key_types.h
index 7a8ea53..863dc17 100644
--- a/src/lib/barrier/key_types.h
+++ b/src/lib/barrier/key_types.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -109,11 +109,13 @@ static const KeyID kKeyPause = 0xEF13; /* Pause, hold */
static const KeyID kKeyScrollLock = 0xEF14;
static const KeyID kKeySysReq = 0xEF15;
static const KeyID kKeyEscape = 0xEF1B;
+static const KeyID kKeyMuhenkan = 0xEF22; /* Cancel Conversion */
static const KeyID kKeyHenkan = 0xEF23; /* Start/Stop Conversion */
static const KeyID kKeyKana = 0xEF26; /* Kana */
static const KeyID kKeyHiraganaKatakana = 0xEF27; /* Hiragana/Katakana toggle */
static const KeyID kKeyZenkaku = 0xEF2A; /* Zenkaku/Hankaku */
static const KeyID kKeyKanzi = 0xEF2A; /* Kanzi */
+static const KeyID kKeyEisuToggle = 0xEF30; /* Alphanumeric toggle */
static const KeyID kKeyHangul = 0xEF31; /* Hangul */
static const KeyID kKeyHanja = 0xEF34; /* Hanja */
static const KeyID kKeyDelete = 0xEFFF; /* Delete, rubout */
@@ -170,7 +172,7 @@ static const KeyID kKeyKP_Separator= 0xEFAC; /* separator, often comma */
static const KeyID kKeyKP_Subtract = 0xEFAD;
static const KeyID kKeyKP_Decimal = 0xEFAE;
static const KeyID kKeyKP_Divide = 0xEFAF;
-static const KeyID kKeyKP_0 = 0xEFB0;
+static const KeyID kKeyKP_0 = 0xEFB0;
static const KeyID kKeyKP_1 = 0xEFB1;
static const KeyID kKeyKP_2 = 0xEFB2;
static const KeyID kKeyKP_3 = 0xEFB3;
@@ -234,6 +236,13 @@ static const KeyID kKeySuper_R = 0xEFEC; /* Right super */
static const KeyID kKeyHyper_L = 0xEFED; /* Left hyper */
static const KeyID kKeyHyper_R = 0xEFEE; /* Right hyper */
+static const KeyID kKeyCopy = 0x1008EF57;
+static const KeyID kKeyCut = 0x1008EF58;
+static const KeyID kKeyOpen = 0x1008EF6b;
+static const KeyID kKeyPaste = 0x1008EF6d;
+static const KeyID kKeyProps = 0x1005EF70;
+static const KeyID kKeyFront = 0x1005EF71;
+
// multi-key character composition
static const KeyID kKeyCompose = 0xEF20;
static const KeyID kKeyDeadGrave = 0x0300;
@@ -284,6 +293,8 @@ static const KeyID kKeyAppUser1 = 0xE0B6;
static const KeyID kKeyAppUser2 = 0xE0B7;
static const KeyID kKeyBrightnessDown = 0xE0B8;
static const KeyID kKeyBrightnessUp = 0xE0B9;
+static const KeyID kKeyKbdBrightnessDown = 0xE0BA;
+static const KeyID kKeyKbdBrightnessUp = 0xE0BB;
static const KeyID kKeyMissionControl = 0xE0C0;
static const KeyID kKeyLaunchpad = 0xE0C1;
diff --git a/src/lib/barrier/mouse_types.h b/src/lib/barrier/mouse_types.h
index 62a2396..ccb18ac 100644
--- a/src/lib/barrier/mouse_types.h
+++ b/src/lib/barrier/mouse_types.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/barrier/option_types.h b/src/lib/barrier/option_types.h
index 6323e37..42103d4 100644
--- a/src/lib/barrier/option_types.h
+++ b/src/lib/barrier/option_types.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/barrier/protocol_types.cpp b/src/lib/barrier/protocol_types.cpp
index 07acf61..9710841 100644
--- a/src/lib/barrier/protocol_types.cpp
+++ b/src/lib/barrier/protocol_types.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/barrier/protocol_types.h b/src/lib/barrier/protocol_types.h
index bc5e037..f730606 100644
--- a/src/lib/barrier/protocol_types.h
+++ b/src/lib/barrier/protocol_types.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -20,6 +20,8 @@
#include "base/EventTypes.h"
+#include <cstdint>
+
// protocol version number
// 1.0: initial protocol
// 1.1: adds KeyCode to key press, release, and repeat
@@ -51,6 +53,12 @@ static const double kKeepAlivesUntilDeath = 3.0;
static const double kHeartRate = -1.0;
static const double kHeartBeatsUntilDeath = 3.0;
+// Messages of very large size indicate a likely protocol error. We don't parse such messages and
+// drop connection instead. Note that e.g. the clipboard messages are already limited to 32kB.
+static constexpr std::uint32_t PROTOCOL_MAX_MESSAGE_LENGTH = 4 * 1024 * 1024;
+static constexpr std::uint32_t PROTOCOL_MAX_LIST_LENGTH = 1024 * 1024;
+static constexpr std::uint32_t PROTOCOL_MAX_STRING_LENGTH = 1024 * 1024;
+
// direction constants
enum EDirection {
kNoDirection,
@@ -267,8 +275,8 @@ extern const char* kMsgDSetOptions;
// 2 means the file transfer is finished.
extern const char* kMsgDFileTransfer;
-// drag infomation: primary <-> secondary
-// transfer drag infomation. The first 2 bytes are used for storing
+// drag information: primary <-> secondary
+// transfer drag information. The first 2 bytes are used for storing
// the number of dragging objects. Then the following string consists
// of each object's directory.
extern const char* kMsgDDragInfo;
diff --git a/src/lib/barrier/unix/AppUtilUnix.cpp b/src/lib/barrier/unix/AppUtilUnix.cpp
index a1548d8..272dcf4 100644
--- a/src/lib/barrier/unix/AppUtilUnix.cpp
+++ b/src/lib/barrier/unix/AppUtilUnix.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/barrier/unix/AppUtilUnix.h b/src/lib/barrier/unix/AppUtilUnix.h
index fefcfea..9555ccd 100644
--- a/src/lib/barrier/unix/AppUtilUnix.h
+++ b/src/lib/barrier/unix/AppUtilUnix.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -28,7 +28,7 @@ class AppUtilUnix : public AppUtil {
public:
AppUtilUnix(IEventQueue* events);
virtual ~AppUtilUnix();
-
+
int run(int argc, char** argv);
void startNode();
};
diff --git a/src/lib/barrier/win32/AppUtilWindows.cpp b/src/lib/barrier/win32/AppUtilWindows.cpp
index 560b029..b19cf15 100644
--- a/src/lib/barrier/win32/AppUtilWindows.cpp
+++ b/src/lib/barrier/win32/AppUtilWindows.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -60,13 +60,13 @@ BOOL WINAPI AppUtilWindows::consoleHandler(DWORD)
}
static
-int
-mainLoopStatic()
+int
+mainLoopStatic()
{
return AppUtil::instance().app().mainLoop();
}
-int
+int
AppUtilWindows::daemonNTMainLoop(int argc, const char** argv)
{
app().initApp(argc, argv);
@@ -74,11 +74,11 @@ AppUtilWindows::daemonNTMainLoop(int argc, const char** argv)
// NB: what the hell does this do?!
app().argsBase().m_backend = false;
-
+
return ArchMiscWindows::runDaemon(mainLoopStatic);
}
-void
+void
AppUtilWindows::exitApp(int code)
{
switch (m_exitMode) {
@@ -97,7 +97,7 @@ int daemonNTMainLoopStatic(int argc, const char** argv)
return AppUtilWindows::instance().daemonNTMainLoop(argc, argv);
}
-int
+int
AppUtilWindows::daemonNTStartup(int, char**)
{
SystemLogger sysLogger(app().daemonName(), false);
@@ -126,7 +126,7 @@ AppUtilWindows::beforeAppExit()
// a new console window, and will normally close on exit (making it so
// that we can't see error messages).
if (app().argsBase().m_pauseOnExit) {
- std::cout << std::endl << "press any key to exit..." << std::endl;
+ std::cout << "\n" << "press any key to exit...\n";
int c = _getch();
}
}
@@ -155,13 +155,13 @@ AppUtilWindows::run(int argc, char** argv)
return app().runInner(argc, argv, NULL, startup);
}
-AppUtilWindows&
+AppUtilWindows&
AppUtilWindows::instance()
{
return (AppUtilWindows&)AppUtil::instance();
}
-void
+void
AppUtilWindows::debugServiceWait()
{
if (app().argsBase().m_debugServiceWait)
@@ -169,8 +169,8 @@ AppUtilWindows::debugServiceWait()
while(true)
{
// this code is only executed when the process is launched via the
- // windows service controller (and --debug-service-wait arg is
- // used). to debug, set a breakpoint on this line so that
+ // windows service controller (and --debug-service-wait arg is
+ // used). to debug, set a breakpoint on this line so that
// execution is delayed until the debugger is attached.
ARCH->sleep(1);
LOG((CLOG_INFO "waiting for debugger to attach"));
@@ -178,7 +178,7 @@ AppUtilWindows::debugServiceWait()
}
}
-void
+void
AppUtilWindows::startNode()
{
app().startNode();
diff --git a/src/lib/barrier/win32/AppUtilWindows.h b/src/lib/barrier/win32/AppUtilWindows.h
index c5da228..23e7919 100644
--- a/src/lib/barrier/win32/AppUtilWindows.h
+++ b/src/lib/barrier/win32/AppUtilWindows.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -39,7 +39,7 @@ public:
virtual ~AppUtilWindows();
int daemonNTStartup(int, char**);
-
+
int daemonNTMainLoop(int argc, const char** argv);
void debugServiceWait();
diff --git a/src/lib/barrier/win32/DaemonApp.cpp b/src/lib/barrier/win32/DaemonApp.cpp
index 482c465..81ec5ff 100644
--- a/src/lib/barrier/win32/DaemonApp.cpp
+++ b/src/lib/barrier/win32/DaemonApp.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -28,7 +28,6 @@
#include "net/SocketMultiplexer.h"
#include "arch/XArch.h"
#include "base/Log.h"
-#include "base/TMethodJob.h"
#include "base/TMethodEventJob.h"
#include "base/EventQueue.h"
#include "base/log_outputters.h"
@@ -87,7 +86,7 @@ DaemonApp::run(int argc, char** argv)
{
// win32 instance needed for threading, etc.
ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL));
-
+
Arch arch;
arch.init();
@@ -174,7 +173,7 @@ DaemonApp::mainLoop(bool daemonized)
try
{
DAEMON_RUNNING(true);
-
+
if (daemonized) {
m_fileLogOutputter = new FileLogOutputter(logFilename().c_str());
CLOG->insert(m_fileLogOutputter);
@@ -190,19 +189,19 @@ DaemonApp::mainLoop(bool daemonized)
// send logging to gui via ipc, log system adopts outputter.
m_ipcLogOutputter = new IpcLogOutputter(*m_ipcServer, kIpcClientGui, true);
CLOG->insert(m_ipcLogOutputter);
-
+
m_watchdog = new MSWindowsWatchdog(daemonized, false, *m_ipcServer, *m_ipcLogOutputter);
m_watchdog->setFileLogOutputter(m_fileLogOutputter);
-
+
m_events->adoptHandler(
m_events->forIpcServer().messageReceived(), m_ipcServer,
new TMethodEventJob<DaemonApp>(this, &DaemonApp::handleIpcMessage));
m_ipcServer->listen();
-
+
// install the platform event queue to handle service stop events.
m_events->adoptBuffer(new MSWindowsEventQueueBuffer(m_events));
-
+
String command = ARCH->setting("Command");
bool elevate = ARCH->setting("Elevate") == "1";
if (command != "") {
@@ -219,11 +218,11 @@ DaemonApp::mainLoop(bool daemonized)
m_events->removeHandler(
m_events->forIpcServer().messageReceived(), m_ipcServer);
-
+
CLOG->remove(m_ipcLogOutputter);
delete m_ipcLogOutputter;
delete m_ipcServer;
-
+
DAEMON_RUNNING(false);
}
catch (std::exception& e) {
@@ -245,7 +244,7 @@ DaemonApp::logFilename()
{
string logFilename = ARCH->setting("LogFilename");
if (logFilename.empty())
- logFilename = DataDirectories::global() + "\\" + LOG_FILENAME;
+ logFilename = (barrier::DataDirectories::global() / LOG_FILENAME).u8string();
MSWindowsUtil::createDirectory(logFilename, true);
return logFilename;
}
@@ -287,7 +286,7 @@ DaemonApp::handleIpcMessage(const Event& e, void*)
}
delete[] argv;
-
+
String logLevel(argBase->m_logFilter);
if (!logLevel.empty()) {
try {
diff --git a/src/lib/barrier/win32/DaemonApp.h b/src/lib/barrier/win32/DaemonApp.h
index 2a8484b..e0eb385 100644
--- a/src/lib/barrier/win32/DaemonApp.h
+++ b/src/lib/barrier/win32/DaemonApp.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-
+
#pragma once
#include "arch/Arch.h"
diff --git a/src/lib/base/CMakeLists.txt b/src/lib/base/CMakeLists.txt
index 66ba5a6..9bd4472 100644
--- a/src/lib/base/CMakeLists.txt
+++ b/src/lib/base/CMakeLists.txt
@@ -1,11 +1,11 @@
# barrier -- mouse and keyboard sharing utility
# Copyright (C) 2012-2016 Symless Ltd.
# Copyright (C) 2009 Nick Bolton
-#
+#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
-#
+#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/base/ELevel.h b/src/lib/base/ELevel.h
index ec0f94f..45b51d7 100644
--- a/src/lib/base/ELevel.h
+++ b/src/lib/base/ELevel.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2011 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/base/Event.cpp b/src/lib/base/Event.cpp
index f2c1a12..cc548fc 100644
--- a/src/lib/base/Event.cpp
+++ b/src/lib/base/Event.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/base/Event.h b/src/lib/base/Event.h
index 2741813..38a2cf1 100644
--- a/src/lib/base/Event.h
+++ b/src/lib/base/Event.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -71,7 +71,7 @@ public:
Deletes event data for the given event (using free()).
*/
static void deleteData(const Event&);
-
+
//! Set data (non-POD)
/*!
Set non-POD (non plain old data), where delete is called when the event
@@ -114,7 +114,7 @@ public:
Returns the event flags.
*/
Flags getFlags() const;
-
+
//@}
private:
diff --git a/src/lib/base/EventQueue.cpp b/src/lib/base/EventQueue.cpp
index 2429522..7764ed8 100644
--- a/src/lib/base/EventQueue.cpp
+++ b/src/lib/base/EventQueue.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -100,7 +100,7 @@ EventQueue::~EventQueue()
delete m_buffer;
delete m_readyCondVar;
delete m_readyMutex;
-
+
ARCH->setSignalHandler(Arch::kINTERRUPT, NULL, NULL);
ARCH->setSignalHandler(Arch::kTERMINATE, NULL, NULL);
}
@@ -121,7 +121,7 @@ EventQueue::loop()
addEventToBuffer(event);
m_pending.pop();
}
-
+
Event event;
getEvent(event);
while (event.getType() != Event::kQuit) {
@@ -298,7 +298,7 @@ EventQueue::addEvent(const Event& event)
default:
break;
}
-
+
if ((event.getFlags() & Event::kDeliverImmediately) != 0) {
dispatchEvent(event);
Event::deleteData(event);
@@ -315,10 +315,10 @@ void
EventQueue::addEventToBuffer(const Event& event)
{
std::lock_guard<std::mutex> lock(m_mutex);
-
+
// store the event's data locally
UInt32 eventID = saveEvent(event);
-
+
// add it
if (!m_buffer->addEvent(eventID)) {
// failed to send event
@@ -568,7 +568,7 @@ EventQueue::waitForReady() const
{
double timeout = ARCH->time() + 10;
Lock lock(m_readyMutex);
-
+
while (!m_readyCondVar->wait()) {
if (ARCH->time() > timeout) {
throw std::runtime_error("event queue is not ready within 5 sec");
diff --git a/src/lib/base/EventQueue.h b/src/lib/base/EventQueue.h
index 842c5ca..55b6fce 100644
--- a/src/lib/base/EventQueue.h
+++ b/src/lib/base/EventQueue.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -71,7 +71,7 @@ private:
double getNextTimerTimeout() const;
void addEventToBuffer(const Event& event);
bool parent_requests_shutdown() const;
-
+
private:
class Timer {
public:
diff --git a/src/lib/base/EventTypes.cpp b/src/lib/base/EventTypes.cpp
index 2ba2077..173a0a9 100644
--- a/src/lib/base/EventTypes.cpp
+++ b/src/lib/base/EventTypes.cpp
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2013-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -56,6 +56,7 @@ REGISTER_EVENT(IStream, outputFlushed)
REGISTER_EVENT(IStream, outputError)
REGISTER_EVENT(IStream, inputShutdown)
REGISTER_EVENT(IStream, outputShutdown)
+REGISTER_EVENT(IStream, inputFormatError)
//
// IpcClient
diff --git a/src/lib/base/EventTypes.h b/src/lib/base/EventTypes.h
index f81617e..995490e 100644
--- a/src/lib/base/EventTypes.h
+++ b/src/lib/base/EventTypes.h
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2013-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -133,14 +133,20 @@ public:
*/
Event::Type outputShutdown();
+ /** Get input format error event type
+
+ This is sent when a stream receives an irrecoverable input format error.
+ */
+ Event::Type inputFormatError();
//@}
-
+
private:
Event::Type m_inputReady;
Event::Type m_outputFlushed;
Event::Type m_outputError;
Event::Type m_inputShutdown;
Event::Type m_outputShutdown;
+ Event::Type m_inputFormatError;
};
class IpcClientEvents : public EventTypes {
@@ -159,7 +165,7 @@ public:
Event::Type messageReceived();
//@}
-
+
private:
Event::Type m_connected;
Event::Type m_messageReceived;
@@ -179,7 +185,7 @@ public:
//! Raised when the client disconnects from the server.
Event::Type disconnected();
-
+
//@}
private:
@@ -198,7 +204,7 @@ public:
//! Raised when we have created the client proxy.
Event::Type clientConnected();
-
+
//! Raised when a message is received through a client proxy.
Event::Type messageReceived();
@@ -242,7 +248,7 @@ public:
event when a remote connection has been established.
*/
Event::Type connected();
-
+
//! Get secure connected event type
/*!
Returns the secure socket connected event type. A secure socket sends
@@ -342,14 +348,14 @@ public:
//! @name accessors
//@{
-
+
//! Get accepted event type
/*!
Returns the accepted event type. This is sent whenever a server
accepts a client.
*/
Event::Type accepted();
-
+
//! Get connected event type
/*!
Returns the connected event type. This is sent whenever a
@@ -419,7 +425,7 @@ public:
Event::Type failure();
//@}
-
+
private:
Event::Type m_success;
Event::Type m_failure;
@@ -510,7 +516,7 @@ public:
Event::Type screenSwitched();
//@}
-
+
private:
Event::Type m_error;
Event::Type m_connected;
@@ -529,16 +535,16 @@ public:
m_reloadConfig(Event::kUnknown),
m_forceReconnect(Event::kUnknown),
m_resetServer(Event::kUnknown) { }
-
+
//! @name accessors
//@{
-
+
Event::Type reloadConfig();
Event::Type forceReconnect();
Event::Type resetServer();
//@}
-
+
private:
Event::Type m_reloadConfig;
Event::Type m_forceReconnect;
@@ -565,7 +571,7 @@ public:
Event::Type keyRepeat();
//@}
-
+
private:
Event::Type m_keyDown;
Event::Type m_keyUp;
@@ -589,7 +595,7 @@ public:
//! @name accessors
//@{
-
+
//! button down event type. Event data is ButtonInfo*.
Event::Type buttonDown();
@@ -677,7 +683,7 @@ public:
to sleep or a user session is deactivated (fast user switching).
*/
Event::Type suspend();
-
+
//! Get resume event type
/*!
Returns the resume event type. This is sent whenever the system wakes
@@ -686,7 +692,7 @@ public:
Event::Type resume();
//@}
-
+
private:
Event::Type m_error;
Event::Type m_shapeChanged;
@@ -722,7 +728,7 @@ public:
//! Clipboard sending event type
/*!
- Returns the clipboard sending event type. This is used to send
+ Returns the clipboard sending event type. This is used to send
clipboard chunks.
*/
Event::Type clipboardSending();
diff --git a/src/lib/base/FunctionEventJob.cpp b/src/lib/base/FunctionEventJob.cpp
index 705e058..751b50d 100644
--- a/src/lib/base/FunctionEventJob.cpp
+++ b/src/lib/base/FunctionEventJob.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/base/FunctionEventJob.h b/src/lib/base/FunctionEventJob.h
index 4b2c2fc..3d9acaa 100644
--- a/src/lib/base/FunctionEventJob.h
+++ b/src/lib/base/FunctionEventJob.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/base/FunctionJob.cpp b/src/lib/base/FunctionJob.cpp
deleted file mode 100644
index 859010e..0000000
--- a/src/lib/base/FunctionJob.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * barrier -- mouse and keyboard sharing utility
- * Copyright (C) 2012-2016 Symless Ltd.
- * Copyright (C) 2002 Chris Schoeneman
- *
- * This package is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * found in the file LICENSE that should have accompanied this file.
- *
- * This package is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "base/FunctionJob.h"
-
-//
-// FunctionJob
-//
-
-FunctionJob::FunctionJob(void (*func)(void*), void* arg) :
- m_func(func),
- m_arg(arg)
-{
- // do nothing
-}
-
-FunctionJob::~FunctionJob()
-{
- // do nothing
-}
-
-void
-FunctionJob::run()
-{
- if (m_func != NULL) {
- m_func(m_arg);
- }
-}
diff --git a/src/lib/base/FunctionJob.h b/src/lib/base/FunctionJob.h
deleted file mode 100644
index 9cdfa9d..0000000
--- a/src/lib/base/FunctionJob.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * barrier -- mouse and keyboard sharing utility
- * Copyright (C) 2012-2016 Symless Ltd.
- * Copyright (C) 2002 Chris Schoeneman
- *
- * This package is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * found in the file LICENSE that should have accompanied this file.
- *
- * This package is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#pragma once
-
-#include "base/IJob.h"
-
-//! Use a function as a job
-/*!
-A job class that invokes a function.
-*/
-class FunctionJob : public IJob {
-public:
- //! run() invokes \c func(arg)
- FunctionJob(void (*func)(void*), void* arg = NULL);
- virtual ~FunctionJob();
-
- // IJob overrides
- virtual void run();
-
-private:
- void (*m_func)(void*);
- void* m_arg;
-};
diff --git a/src/lib/base/IEventJob.h b/src/lib/base/IEventJob.h
index 3e4a420..844cc4a 100644
--- a/src/lib/base/IEventJob.h
+++ b/src/lib/base/IEventJob.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/base/IEventQueue.h b/src/lib/base/IEventQueue.h
index 150595c..833081c 100644
--- a/src/lib/base/IEventQueue.h
+++ b/src/lib/base/IEventQueue.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -184,7 +184,7 @@ public:
be added.
*/
virtual void waitForReady() const = 0;
-
+
//@}
//! @name accessors
//@{
@@ -216,7 +216,7 @@ public:
virtual void* getSystemTarget() = 0;
//@}
-
+
//
// Event type providers.
//
diff --git a/src/lib/base/IEventQueueBuffer.h b/src/lib/base/IEventQueueBuffer.h
index b594436..f25cc66 100644
--- a/src/lib/base/IEventQueueBuffer.h
+++ b/src/lib/base/IEventQueueBuffer.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -38,7 +38,7 @@ public:
//! @name manipulators
//@{
-
+
//! Initialize
/*!
Useful for platform-specific initialisation from a specific thread.
diff --git a/src/lib/base/IJob.h b/src/lib/base/IJob.h
index f966ec0..29aa941 100644
--- a/src/lib/base/IJob.h
+++ b/src/lib/base/IJob.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/base/ILogOutputter.h b/src/lib/base/ILogOutputter.h
index ab218fc..e11f9e2 100644
--- a/src/lib/base/ILogOutputter.h
+++ b/src/lib/base/ILogOutputter.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/base/Log.cpp b/src/lib/base/Log.cpp
index a3b328d..8f52a80 100644
--- a/src/lib/base/Log.cpp
+++ b/src/lib/base/Log.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -25,7 +25,7 @@
#include <cstdio>
#include <cstring>
#include <iostream>
-#include <ctime>
+#include <ctime>
// names of priorities
static const char* g_priority[] = {
@@ -62,7 +62,7 @@ Log::Log()
{
assert(s_log == NULL);
- // other initalization
+ // other initialization
m_maxPriority = g_defaultMaxPriority;
m_maxNewlineLength = 0;
insert(new ConsoleLogOutputter);
@@ -145,7 +145,7 @@ Log::print(const char* file, int line, const char* fmt, ...)
// try printing into the buffer
va_list args;
va_start(args, fmt);
- int n = ARCH->vsnprintf(buffer, len - sPad, fmt, args);
+ int n = std::vsnprintf(buffer, len - sPad, fmt, args);
va_end(args);
// if the buffer wasn't big enough then make it bigger and try again
diff --git a/src/lib/base/Log.h b/src/lib/base/Log.h
index 0ed458f..22224b9 100644
--- a/src/lib/base/Log.h
+++ b/src/lib/base/Log.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -91,7 +91,7 @@ public:
then it simply returns true.
*/
bool setFilter(const char* name);
-
+
//! Set the minimum priority filter (by ordinal).
void setFilter(int);
@@ -193,9 +193,9 @@ otherwise it expands to a call that doesn't.
#define CLOG_TRACE __FILE__, __LINE__,
#endif
-// the CLOG_* defines are line and file plus %z and an octal number (060=0,
-// 071=9), but the limitation is that once we run out of numbers at either
-// end, then we resort to using non-numerical chars. this still works (since
+// the CLOG_* defines are line and file plus %z and an octal number (060=0,
+// 071=9), but the limitation is that once we run out of numbers at either
+// end, then we resort to using non-numerical chars. this still works (since
// to deduce the number we subtract octal \060, so '/' is -1, and ':' is 10
#define CLOG_PRINT CLOG_TRACE "%z\057" // char is '/'
diff --git a/src/lib/base/PriorityQueue.h b/src/lib/base/PriorityQueue.h
index d2ca70e..8aac88c 100644
--- a/src/lib/base/PriorityQueue.h
+++ b/src/lib/base/PriorityQueue.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2003 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/base/SimpleEventQueueBuffer.cpp b/src/lib/base/SimpleEventQueueBuffer.cpp
index b55fe55..a26f255 100644
--- a/src/lib/base/SimpleEventQueueBuffer.cpp
+++ b/src/lib/base/SimpleEventQueueBuffer.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/base/SimpleEventQueueBuffer.h b/src/lib/base/SimpleEventQueueBuffer.h
index 4aa76d3..db6a502 100644
--- a/src/lib/base/SimpleEventQueueBuffer.h
+++ b/src/lib/base/SimpleEventQueueBuffer.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -28,7 +28,7 @@ An event queue buffer provides a queue of events for an IEventQueue.
*/
class SimpleEventQueueBuffer : public IEventQueueBuffer {
public:
- SimpleEventQueueBuffer();
+ SimpleEventQueueBuffer();
~SimpleEventQueueBuffer();
// IEventQueueBuffer overrides
diff --git a/src/lib/base/Stopwatch.cpp b/src/lib/base/Stopwatch.cpp
index b9ceb85..a174ea6 100644
--- a/src/lib/base/Stopwatch.cpp
+++ b/src/lib/base/Stopwatch.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/base/Stopwatch.h b/src/lib/base/Stopwatch.h
index dda74ea..81098fd 100644
--- a/src/lib/base/Stopwatch.h
+++ b/src/lib/base/Stopwatch.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -88,7 +88,7 @@ public:
*/
bool isStopped() const;
- // return the time since the last reset().
+ // return the time since the last reset().
//! Get elapsed time
/*!
Returns the time since the last reset(). This cannot trigger the
diff --git a/src/lib/base/String.cpp b/src/lib/base/String.cpp
index 1ab3623..adbb11d 100644
--- a/src/lib/base/String.cpp
+++ b/src/lib/base/String.cpp
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2014-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -35,6 +35,42 @@
namespace barrier {
namespace string {
+namespace {
+
+// returns negative in case of non-matching character
+int hex_to_number(char ch)
+{
+ switch (ch) {
+ case '0': return 0;
+ case '1': return 1;
+ case '2': return 2;
+ case '3': return 3;
+ case '4': return 4;
+ case '5': return 5;
+ case '6': return 6;
+ case '7': return 7;
+ case '8': return 8;
+ case '9': return 9;
+
+ case 'a': return 10;
+ case 'b': return 11;
+ case 'c': return 12;
+ case 'd': return 13;
+ case 'e': return 14;
+ case 'f': return 15;
+
+ case 'A': return 10;
+ case 'B': return 11;
+ case 'C': return 12;
+ case 'D': return 13;
+ case 'E': return 14;
+ case 'F': return 15;
+ }
+ return -1;
+}
+
+} // namespace
+
std::string
format(const char* fmt, ...)
{
@@ -135,7 +171,7 @@ sprintf(const char* fmt, ...)
// try printing into the buffer
va_list args;
va_start(args, fmt);
- int n = ARCH->vsnprintf(buffer, len, fmt, args);
+ int n = std::vsnprintf(buffer, len, fmt, args);
va_end(args);
// if the buffer wasn't big enough then make it bigger and try again
@@ -185,16 +221,42 @@ removeFileExt(std::string filename)
return filename.substr(0, dot);
}
-void
-toHex(std::string& subject, int width, const char fill)
+std::string to_hex(const std::vector<std::uint8_t>& subject, int width, const char fill)
{
std::stringstream ss;
ss << std::hex;
- for (unsigned int i = 0; i < subject.length(); i++) {
- ss << std::setw(width) << std::setfill(fill) << (int)(unsigned char)subject[i];
+ for (unsigned int i = 0; i < subject.size(); i++) {
+ ss << std::setw(width) << std::setfill(fill) << static_cast<int>(subject[i]);
}
- subject = ss.str();
+ return ss.str();
+}
+
+std::vector<std::uint8_t> from_hex(const std::string& data)
+{
+ std::vector<std::uint8_t> result;
+ result.reserve(data.size() / 2);
+
+ std::size_t i = 0;
+ while (i < data.size()) {
+ if (data[i] == ':') {
+ i++;
+ continue;
+ }
+
+ if (i + 2 > data.size()) {
+ return {}; // uneven character count follows, it's unclear how to interpret it
+ }
+
+ auto high = hex_to_number(data[i]);
+ auto low = hex_to_number(data[i + 1]);
+ if (high < 0 || low < 0) {
+ return {};
+ }
+ result.push_back(high * 16 + low);
+ i += 2;
+ }
+ return result;
}
void
diff --git a/src/lib/base/String.h b/src/lib/base/String.h
index 73526b4..9c5a53b 100644
--- a/src/lib/base/String.h
+++ b/src/lib/base/String.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -75,7 +75,10 @@ std::string removeFileExt(std::string filename);
/*!
Convert each character in \c subject into hexdecimal form with \c width
*/
-void toHex(std::string& subject, int width, const char fill = '0');
+std::string to_hex(const std::vector<std::uint8_t>& subject, int width, const char fill = '0');
+
+/// Convert binary data from hexadecimal
+std::vector<std::uint8_t> from_hex(const std::string& data);
//! Convert to all uppercase
/*!
diff --git a/src/lib/base/TMethodEventJob.h b/src/lib/base/TMethodEventJob.h
index a65f8c9..04a36fd 100644
--- a/src/lib/base/TMethodEventJob.h
+++ b/src/lib/base/TMethodEventJob.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/base/TMethodJob.h b/src/lib/base/TMethodJob.h
deleted file mode 100644
index ec88f05..0000000
--- a/src/lib/base/TMethodJob.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * barrier -- mouse and keyboard sharing utility
- * Copyright (C) 2012-2016 Symless Ltd.
- * Copyright (C) 2002 Chris Schoeneman
- *
- * This package is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * found in the file LICENSE that should have accompanied this file.
- *
- * This package is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#pragma once
-
-#include "IJob.h"
-
-//! Use a function as a job
-/*!
-A job class that invokes a member function.
-*/
-template <class T>
-class TMethodJob : public IJob {
-public:
- //! run() invokes \c object->method(arg)
- TMethodJob(T* object, void (T::*method)(void*), void* arg = NULL);
- virtual ~TMethodJob();
-
- // IJob overrides
- virtual void run();
-
-private:
- T* m_object;
- void (T::*m_method)(void*);
- void* m_arg;
-};
-
-template <class T>
-inline
-TMethodJob<T>::TMethodJob(T* object, void (T::*method)(void*), void* arg) :
- m_object(object),
- m_method(method),
- m_arg(arg)
-{
- // do nothing
-}
-
-template <class T>
-inline
-TMethodJob<T>::~TMethodJob()
-{
- // do nothing
-}
-
-template <class T>
-inline
-void
-TMethodJob<T>::run()
-{
- if (m_object != NULL) {
- (m_object->*m_method)(m_arg);
- }
-}
diff --git a/src/lib/base/Unicode.cpp b/src/lib/base/Unicode.cpp
index 05b0212..2bd0360 100644
--- a/src/lib/base/Unicode.cpp
+++ b/src/lib/base/Unicode.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/base/Unicode.h b/src/lib/base/Unicode.h
index 9bf83ae..430bb1b 100644
--- a/src/lib/base/Unicode.h
+++ b/src/lib/base/Unicode.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/base/XBase.cpp b/src/lib/base/XBase.cpp
index cb0db2e..b7a7baf 100644
--- a/src/lib/base/XBase.cpp
+++ b/src/lib/base/XBase.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/base/XBase.h b/src/lib/base/XBase.h
index 59b700e..0b46750 100644
--- a/src/lib/base/XBase.h
+++ b/src/lib/base/XBase.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/base/finally.h b/src/lib/base/finally.h
new file mode 100644
index 0000000..f3be617
--- /dev/null
+++ b/src/lib/base/finally.h
@@ -0,0 +1,61 @@
+/*
+ barrier -- mouse and keyboard sharing utility
+ Copyright (C) Barrier contributors
+
+ This package is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ found in the file LICENSE that should have accompanied this file.
+
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef BARRIER_LIB_BASE_FINALLY_H
+#define BARRIER_LIB_BASE_FINALLY_H
+
+#include <utility>
+
+namespace barrier {
+
+// this implements a common pattern of executing an action at the end of function
+
+template<class Callable>
+class final_action {
+public:
+ final_action() noexcept {}
+ final_action(Callable callable) noexcept : callable_{callable} {}
+
+ ~final_action() noexcept
+ {
+ if (!invoked_) {
+ callable_();
+ }
+ }
+
+ final_action(final_action&& other) noexcept :
+ callable_{std::move(other.callable_)}
+ {
+ std::swap(invoked_, other.invoked_);
+ }
+
+ final_action(const final_action&) = delete;
+ final_action& operator=(const final_action&) = delete;
+private:
+ bool invoked_ = false;
+ Callable callable_;
+};
+
+template<class Callable>
+inline final_action<Callable> finally(Callable&& callable) noexcept
+{
+ return final_action<Callable>(std::forward<Callable>(callable));
+}
+
+} // namespace barrier
+
+#endif // BARRIER_LIB_BASE_FINALLY_H
diff --git a/src/lib/base/log_outputters.cpp b/src/lib/base/log_outputters.cpp
index af53192..176af2d 100644
--- a/src/lib/base/log_outputters.cpp
+++ b/src/lib/base/log_outputters.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -17,10 +17,9 @@
*/
#include "base/log_outputters.h"
-#include "base/TMethodJob.h"
#include "arch/Arch.h"
#include "base/String.h"
-
+#include "io/filesystem.h"
#include <fstream>
enum EFileLogOutputter {
@@ -260,7 +259,7 @@ FileLogOutputter::write(ELevel level, const char *message)
bool moveFile = false;
std::ofstream m_handle;
- m_handle.open(m_fileName.c_str(), std::fstream::app);
+ barrier::open_utf8_path(m_handle, m_fileName, std::fstream::app);
if (m_handle.is_open() && m_handle.fail() != true) {
m_handle << message << std::endl;
@@ -305,7 +304,7 @@ MesssageBoxLogOutputter::~MesssageBoxLogOutputter()
}
void
-MesssageBoxLogOutputter::open(const char* title)
+MesssageBoxLogOutputter::open(const char* title)
{
// do nothing
}
diff --git a/src/lib/base/log_outputters.h b/src/lib/base/log_outputters.h
index 15f1e7a..2a84170 100644
--- a/src/lib/base/log_outputters.h
+++ b/src/lib/base/log_outputters.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/client/CMakeLists.txt b/src/lib/client/CMakeLists.txt
index 97dc9db..033876f 100644
--- a/src/lib/client/CMakeLists.txt
+++ b/src/lib/client/CMakeLists.txt
@@ -1,11 +1,11 @@
# barrier -- mouse and keyboard sharing utility
# Copyright (C) 2012-2016 Symless Ltd.
# Copyright (C) 2009 Nick Bolton
-#
+#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
-#
+#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/client/Client.cpp b/src/lib/client/Client.cpp
index 96d2c67..a7b15cf 100644
--- a/src/lib/client/Client.cpp
+++ b/src/lib/client/Client.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -37,7 +37,6 @@
#include "base/Log.h"
#include "base/IEventQueue.h"
#include "base/TMethodEventJob.h"
-#include "base/TMethodJob.h"
#include <cstring>
#include <cstdlib>
@@ -127,6 +126,12 @@ Client::connect()
return;
}
+ auto security_level = ConnectionSecurityLevel::PLAINTEXT;
+ if (m_useSecureNetwork) {
+ // client always authenticates server
+ security_level = ConnectionSecurityLevel::ENCRYPTED_AUTHENTICATED;
+ }
+
try {
// resolve the server hostname. do this every time we connect
// in case we couldn't resolve the address earlier or the address
@@ -134,20 +139,19 @@ Client::connect()
// being shuttled between various networks). patch by Brent
// Priddy.
m_serverAddress.resolve();
-
+
// m_serverAddress will be null if the hostname address is not reolved
if (m_serverAddress.getAddress() != NULL) {
// to help users troubleshoot, show server host name (issue: 60)
- LOG((CLOG_NOTE "connecting to '%s': %s:%i",
+ LOG((CLOG_NOTE "connecting to '%s': %s:%i",
m_serverAddress.getHostname().c_str(),
ARCH->addrToString(m_serverAddress.getAddress()).c_str(),
m_serverAddress.getPort()));
}
// create the socket
- IDataSocket* socket = m_socketFactory->create(
- ARCH->getAddrFamily(m_serverAddress.getAddress()),
- m_useSecureNetwork);
+ IDataSocket* socket = m_socketFactory->create(ARCH->getAddrFamily(m_serverAddress.getAddress()),
+ security_level);
m_socket = dynamic_cast<TCPSocket*>(socket);
// filter socket messages, including a packetizing filter
@@ -255,7 +259,7 @@ Client::leave()
m_active = false;
m_screen->leave();
-
+
if (m_enableClipboard) {
// send clipboards that we own and that have changed
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
@@ -755,9 +759,7 @@ void
Client::onFileRecieveCompleted()
{
if (isReceivedFileSizeValid()) {
- m_writeToDropDirThread = new Thread(
- new TMethodJob<Client>(
- this, &Client::writeToDropDirThread));
+ m_writeToDropDirThread = new Thread([this](){ write_to_drop_dir_thread(); });
}
}
@@ -767,15 +769,14 @@ Client::handleStopRetry(const Event&, void*)
m_args.m_restartable = false;
}
-void
-Client::writeToDropDirThread(void*)
+void Client::write_to_drop_dir_thread()
{
LOG((CLOG_DEBUG "starting write to drop dir thread"));
while (m_screen->isFakeDraggingStarted()) {
ARCH->sleep(.1f);
}
-
+
DropHelper::writeToDir(m_screen->getDropTarget(), m_dragFileList,
m_receivedFileData);
}
@@ -790,7 +791,7 @@ Client::dragInfoReceived(UInt32 fileNum, std::string data)
}
DragInformation::parseDragInfo(m_dragFileList, fileNum, data);
-
+
m_screen->startDraggingFiles(m_dragFileList);
}
@@ -806,19 +807,14 @@ Client::sendFileToServer(const char* filename)
if (m_sendFileThread != NULL) {
StreamChunker::interruptFile();
}
-
- m_sendFileThread = new Thread(
- new TMethodJob<Client>(
- this, &Client::sendFileThread,
- static_cast<void*>(const_cast<char*>(filename))));
+
+ m_sendFileThread = new Thread([this, filename]() { send_file_thread(filename); });
}
-void
-Client::sendFileThread(void* filename)
+void Client::send_file_thread(const char* filename)
{
try {
- char* name = static_cast<char*>(filename);
- StreamChunker::sendFile(name, m_events, this);
+ StreamChunker::sendFile(filename, m_events, this);
}
catch (std::runtime_error& error) {
LOG((CLOG_ERR "failed sending file chunks: %s", error.what()));
diff --git a/src/lib/client/Client.h b/src/lib/client/Client.h
index 7e566be..c172af2 100644
--- a/src/lib/client/Client.h
+++ b/src/lib/client/Client.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -90,11 +90,11 @@ public:
//! Create a new thread and use it to send file to Server
void sendFileToServer(const char* filename);
-
+
//! Send dragging file information back to server
void sendDragInfo(UInt32 fileCount, std::string& info, size_t size);
-
+
//@}
//! @name accessors
//@{
@@ -118,8 +118,8 @@ public:
to connect) to.
*/
NetworkAddress getServerAddress() const;
-
- //! Return true if recieved file size is valid
+
+ //! Return true if received file size is valid
bool isReceivedFileSizeValid();
//! Return expected file size
@@ -167,8 +167,8 @@ private:
void sendEvent(Event::Type, void*);
void sendConnectionFailedEvent(const char* msg);
void sendFileChunk(const void* data);
- void sendFileThread(void*);
- void writeToDropDirThread(void*);
+ void send_file_thread(const char* filename);
+ void write_to_drop_dir_thread();
void setupConnecting();
void setupConnection();
void setupScreen();
diff --git a/src/lib/client/ServerProxy.cpp b/src/lib/client/ServerProxy.cpp
index c067f13..c6e3576 100644
--- a/src/lib/client/ServerProxy.cpp
+++ b/src/lib/client/ServerProxy.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -26,6 +26,7 @@
#include "barrier/ProtocolUtil.h"
#include "barrier/option_types.h"
#include "barrier/protocol_types.h"
+#include "barrier/XBarrier.h"
#include "io/IStream.h"
#include "base/Log.h"
#include "base/IEventQueue.h"
@@ -124,17 +125,27 @@ ServerProxy::handleData(const Event&, void*)
// parse message
LOG((CLOG_DEBUG2 "msg from server: %c%c%c%c", code[0], code[1], code[2], code[3]));
- switch ((this->*m_parser)(code)) {
- case kOkay:
- break;
-
- case kUnknown:
- LOG((CLOG_ERR "invalid message from server: %c%c%c%c", code[0], code[1], code[2], code[3]));
+ try {
+ switch ((this->*m_parser)(code)) {
+ case kOkay:
+ break;
+
+ case kUnknown:
+ LOG((CLOG_ERR "invalid message from server: %c%c%c%c", code[0], code[1], code[2], code[3]));
+ m_client->disconnect("invalid message from server");
+ return;
+
+ case kDisconnect:
+ return;
+ }
+ } catch (const XBadClient& e) {
+ // TODO: disconnect handling is currently dispersed across both parseMessage() and
+ // handleData() functions, we should collect that to a single place
+
+ LOG((CLOG_ERR "protocol error from server: %s", e.what()));
+ ProtocolUtil::writef(m_stream, kMsgEBad);
m_client->disconnect("invalid message from server");
return;
-
- case kDisconnect:
- return;
}
// next message
@@ -553,7 +564,7 @@ ServerProxy::setClipboard()
static std::string dataCached;
ClipboardID id;
UInt32 seq;
-
+
int r = ClipboardChunk::assemble(m_stream, dataCached, id, seq);
if (r == kStart) {
@@ -562,7 +573,7 @@ ServerProxy::setClipboard()
}
else if (r == kFinish) {
LOG((CLOG_DEBUG "received clipboard %d size=%d", id, dataCached.size()));
-
+
// forward
Clipboard clipboard;
clipboard.unmarshall(dataCached, 0);
diff --git a/src/lib/client/ServerProxy.h b/src/lib/client/ServerProxy.h
index abca4c3..12a3226 100644
--- a/src/lib/client/ServerProxy.h
+++ b/src/lib/client/ServerProxy.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -58,8 +58,8 @@ public:
// sending dragging information to server
void sendDragInfo(UInt32 fileCount, const char* info, size_t size);
-
-#ifdef TEST_ENV
+
+#ifdef BARRIER_TEST_ENV
void handleDataForTest() { handleData(Event(), NULL); }
#endif
diff --git a/src/lib/common/CMakeLists.txt b/src/lib/common/CMakeLists.txt
index b3791c1..82ca614 100644
--- a/src/lib/common/CMakeLists.txt
+++ b/src/lib/common/CMakeLists.txt
@@ -1,11 +1,11 @@
# barrier -- mouse and keyboard sharing utility
# Copyright (C) 2012-2016 Symless Ltd.
# Copyright (C) 2009 Nick Bolton
-#
+#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
-#
+#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/common/DataDirectories.h b/src/lib/common/DataDirectories.h
index 6b990c2..4550211 100644
--- a/src/lib/common/DataDirectories.h
+++ b/src/lib/common/DataDirectories.h
@@ -15,27 +15,36 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#pragma once
+#ifndef BARRIER_LIB_COMMON_DATA_DIRECTORIES_H
+#define BARRIER_LIB_COMMON_DATA_DIRECTORIES_H
-#include <string>
+#include "io/filesystem.h"
+
+namespace barrier {
class DataDirectories
{
public:
- static const std::string& profile();
- static const std::string& profile(const std::string& path);
+ static const fs::path& profile();
+ static const fs::path& profile(const fs::path& path);
- static const std::string& global();
- static const std::string& global(const std::string& path);
+ static const fs::path& global();
+ static const fs::path& global(const fs::path& path);
- static const std::string& systemconfig();
- static const std::string& systemconfig(const std::string& path);
+ static const fs::path& systemconfig();
+ static const fs::path& systemconfig(const fs::path& path);
+ static fs::path ssl_fingerprints_path();
+ static fs::path local_ssl_fingerprints_path();
+ static fs::path trusted_servers_ssl_fingerprints_path();
+ static fs::path trusted_clients_ssl_fingerprints_path();
+ static fs::path ssl_certificate_path();
private:
- // static class
- DataDirectories() {}
-
- static std::string _profile;
- static std::string _global;
- static std::string _systemconfig;
+ static fs::path _profile;
+ static fs::path _global;
+ static fs::path _systemconfig;
};
+
+} // namespace barrier
+
+#endif
diff --git a/src/lib/common/DataDirectories_static.cpp b/src/lib/common/DataDirectories_static.cpp
index 48dccb6..47f88e7 100644
--- a/src/lib/common/DataDirectories_static.cpp
+++ b/src/lib/common/DataDirectories_static.cpp
@@ -17,7 +17,40 @@
#include "DataDirectories.h"
-// static member
-std::string DataDirectories::_profile;
-std::string DataDirectories::_global;
-std::string DataDirectories::_systemconfig;
+namespace barrier {
+
+fs::path DataDirectories::_profile;
+fs::path DataDirectories::_global;
+fs::path DataDirectories::_systemconfig;
+
+static const char kFingerprintsDirName[] = "SSL/Fingerprints";
+static const char kFingerprintsLocalFilename[] = "Local.txt";
+static const char kFingerprintsTrustedServersFilename[] = "TrustedServers.txt";
+static const char kFingerprintsTrustedClientsFilename[] = "TrustedClients.txt";
+
+fs::path DataDirectories::ssl_fingerprints_path()
+{
+ return profile() / kFingerprintsDirName;
+}
+
+fs::path DataDirectories::local_ssl_fingerprints_path()
+{
+ return ssl_fingerprints_path() / kFingerprintsLocalFilename;
+}
+
+fs::path DataDirectories::trusted_servers_ssl_fingerprints_path()
+{
+ return ssl_fingerprints_path() / kFingerprintsTrustedServersFilename;
+}
+
+fs::path DataDirectories::trusted_clients_ssl_fingerprints_path()
+{
+ return ssl_fingerprints_path() / kFingerprintsTrustedClientsFilename;
+}
+
+fs::path DataDirectories::ssl_certificate_path()
+{
+ return profile() / "SSL" / "Barrier.pem";
+}
+
+} // namespace barrier
diff --git a/src/lib/common/IInterface.h b/src/lib/common/IInterface.h
index 84a76a9..65ede4d 100644
--- a/src/lib/common/IInterface.h
+++ b/src/lib/common/IInterface.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/common/MacOSXPrecomp.h b/src/lib/common/MacOSXPrecomp.h
deleted file mode 100644
index 7dbc8d0..0000000
--- a/src/lib/common/MacOSXPrecomp.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * barrier -- mouse and keyboard sharing utility
- * Copyright (C) 2012-2016 Symless Ltd.
- * Copyright (C) 2002 Chris Schoeneman
- *
- * This package is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * found in the file LICENSE that should have accompanied this file.
- *
- * This package is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
- //
-// Prefix header for all source files of the 'deleteme' target in the 'deleteme' project.
-//
-
-#include <Carbon/Carbon.h>
diff --git a/src/lib/common/PathUtilities.cpp b/src/lib/common/PathUtilities.cpp
deleted file mode 100644
index a2ab38a..0000000
--- a/src/lib/common/PathUtilities.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
-* barrier -- mouse and keyboard sharing utility
-* Copyright (C) 2018 Debauchee Open Source Group
-*
-* This package is free software; you can redistribute it and/or
-* modify it under the terms of the GNU General Public License
-* found in the file LICENSE that should have accompanied this file.
-*
-* This package is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/*
-
-These functions cover the vast majority of cases for different paths across
-windows and unixes. They are not, however, fullproof and probably don't cover
-fringe cases very well. The library below might be used as an alternative if
-these implementations prove to be insufficient. As the library's readme states
-it is simply a temporary band-aid until std::filesystem is integrated (C++17
-has it in std::experimental) and this class should also be treated as such.
-
-https://github.com/wjakob/filesystem/
-
-*/
-
-#include "PathUtilities.h"
-
-// keep the default platform delimiter as the first in the list
-#ifdef _WIN32
-static const char *Delimiters = "\\/";
-#else
-static const char *Delimiters = "/";
-#endif
-
-static const char DefaultDelimiter = Delimiters[0];
-
-std::string PathUtilities::basename(const std::string& path)
-{
- return path.substr(path.find_last_of(Delimiters) + 1);
-}
-
-std::string PathUtilities::concat(const std::string& left, const std::string& right)
-{
- // although npos is usually (-1) we can't count on that so handle it explicitly
- auto leftEnd = left.find_last_not_of(Delimiters);
- if (leftEnd == std::string::npos)
- leftEnd = 0;
- else
- ++leftEnd;
- auto rightStart = right.find_first_not_of(Delimiters, 0);
- if (rightStart == std::string::npos) {
- // both left/right are empty
- if (left.size() == 0 && right.size() == 0)
- return "";
- // right is full of delims, left is okay
- if (leftEnd > 0)
- return left.substr(0, leftEnd);
- // both left/right useless but at least one has delims
- return std::string(1, DefaultDelimiter);
- }
- if (leftEnd == 0) {
- // right is okay and not prefixed with delims, left is empty
- if (left.size() == 0 && rightStart == 0)
- return right.substr(rightStart);
- // (right is okay and prefixed with delims) OR left is full of delims
- return DefaultDelimiter + right.substr(rightStart);
- }
- // concatenation using both left and right
- return left.substr(0, leftEnd) + DefaultDelimiter + right.substr(rightStart);
-}
diff --git a/src/lib/common/PathUtilities.h b/src/lib/common/PathUtilities.h
deleted file mode 100644
index 70b85b4..0000000
--- a/src/lib/common/PathUtilities.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
-* barrier -- mouse and keyboard sharing utility
-* Copyright (C) 2018 Debauchee Open Source Group
-*
-* This package is free software; you can redistribute it and/or
-* modify it under the terms of the GNU General Public License
-* found in the file LICENSE that should have accompanied this file.
-*
-* This package is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#pragma once
-
-#include <string>
-
-class PathUtilities
-{
-public:
- static std::string basename(const std::string& path);
- static std::string concat(const std::string& left, const std::string& right);
-
-private:
- // static class
- PathUtilities() {}
-};
diff --git a/src/lib/common/Version.cpp b/src/lib/common/Version.cpp
index 94d6c5d..41d2804 100644
--- a/src/lib/common/Version.cpp
+++ b/src/lib/common/Version.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/common/Version.h b/src/lib/common/Version.h
index 66bb2e2..ad4a3e7 100644
--- a/src/lib/common/Version.h
+++ b/src/lib/common/Version.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/common/basic_types.h b/src/lib/common/basic_types.h
index f84550c..1882e57 100644
--- a/src/lib/common/basic_types.h
+++ b/src/lib/common/basic_types.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -18,49 +18,7 @@
#pragma once
-#include "common/common.h"
-
-//
-// pick types of particular sizes
-//
-
-#if !defined(TYPE_OF_SIZE_1)
-# if SIZEOF_CHAR == 1
-# define TYPE_OF_SIZE_1 char
-# endif
-#endif
-
-#if !defined(TYPE_OF_SIZE_2)
-# if SIZEOF_INT == 2
-# define TYPE_OF_SIZE_2 int
-# else
-# define TYPE_OF_SIZE_2 short
-# endif
-#endif
-
-#if !defined(TYPE_OF_SIZE_4)
- // Carbon defines SInt32 and UInt32 in terms of long
-# if SIZEOF_INT == 4 && !defined(__APPLE__)
-# define TYPE_OF_SIZE_4 int
-# else
-# define TYPE_OF_SIZE_4 long
-# endif
-#endif
-
- //
-// verify existence of required types
-//
-
-#if !defined(TYPE_OF_SIZE_1)
-# error No 1 byte integer type
-#endif
-#if !defined(TYPE_OF_SIZE_2)
-# error No 2 byte integer type
-#endif
-#if !defined(TYPE_OF_SIZE_4)
-# error No 4 byte integer type
-#endif
-
+#include <cstdint>
//
// make typedefs
@@ -75,18 +33,11 @@
#if defined(__APPLE__)
#include <CoreServices/CoreServices.h>
#else
-typedef signed TYPE_OF_SIZE_1 SInt8;
-typedef signed TYPE_OF_SIZE_2 SInt16;
-typedef signed TYPE_OF_SIZE_4 SInt32;
-typedef unsigned TYPE_OF_SIZE_1 UInt8;
-typedef unsigned TYPE_OF_SIZE_2 UInt16;
-typedef unsigned TYPE_OF_SIZE_4 UInt32;
+using SInt8 = std::int8_t;
+using SInt16 = std::int16_t;
+using SInt32 = std::int32_t;
+using UInt8 = std::uint8_t;
+using UInt16 = std::uint16_t;
+using UInt32 = std::uint32_t;
#endif
#endif
-//
-// clean up
-//
-
-#undef TYPE_OF_SIZE_1
-#undef TYPE_OF_SIZE_2
-#undef TYPE_OF_SIZE_4
diff --git a/src/lib/common/common.h b/src/lib/common/common.h
index 5ea215f..3946256 100644
--- a/src/lib/common/common.h
+++ b/src/lib/common/common.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -18,26 +18,8 @@
#pragma once
-#if defined(_WIN32)
-# define SYSAPI_WIN32 1
-# define WINAPI_MSWINDOWS 1
-#elif HAVE_CONFIG_H
+#if HAVE_CONFIG_H
# include "config.h"
-#else
-# error "config.h missing"
-#endif
-
-// VC++ has built-in sized types
-#if defined(_MSC_VER)
-# include <wchar.h>
-# define TYPE_OF_SIZE_1 __int8
-# define TYPE_OF_SIZE_2 __int16
-# define TYPE_OF_SIZE_4 __int32
-#else
-# define SIZE_OF_CHAR 1
-# define SIZE_OF_SHORT 2
-# define SIZE_OF_INT 4
-# define SIZE_OF_LONG 4
#endif
// define NULL
diff --git a/src/lib/common/stdbitset.h b/src/lib/common/stdbitset.h
index 1096249..65433ac 100644
--- a/src/lib/common/stdbitset.h
+++ b/src/lib/common/stdbitset.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/common/stddeque.h b/src/lib/common/stddeque.h
index ffaed24..5033826 100644
--- a/src/lib/common/stddeque.h
+++ b/src/lib/common/stddeque.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/common/stdfstream.h b/src/lib/common/stdfstream.h
index e9aa263..0328a4b 100644
--- a/src/lib/common/stdfstream.h
+++ b/src/lib/common/stdfstream.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/common/stdistream.h b/src/lib/common/stdistream.h
index b19e2ab..2e9c3cc 100644
--- a/src/lib/common/stdistream.h
+++ b/src/lib/common/stdistream.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/common/stdlist.h b/src/lib/common/stdlist.h
index d530e57..f1c03e2 100644
--- a/src/lib/common/stdlist.h
+++ b/src/lib/common/stdlist.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/common/stdmap.h b/src/lib/common/stdmap.h
index 2351074..7a1040e 100644
--- a/src/lib/common/stdmap.h
+++ b/src/lib/common/stdmap.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/common/stdostream.h b/src/lib/common/stdostream.h
index bb82285..10b65d0 100644
--- a/src/lib/common/stdostream.h
+++ b/src/lib/common/stdostream.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/common/stdpost.h b/src/lib/common/stdpost.h
index 8046da0..d7f0f9c 100644
--- a/src/lib/common/stdpost.h
+++ b/src/lib/common/stdpost.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/common/stdpre.h b/src/lib/common/stdpre.h
index 8ccd308..bf8b9bf 100644
--- a/src/lib/common/stdpre.h
+++ b/src/lib/common/stdpre.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/common/stdset.h b/src/lib/common/stdset.h
index 1c98971..e247745 100644
--- a/src/lib/common/stdset.h
+++ b/src/lib/common/stdset.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/common/stdsstream.h b/src/lib/common/stdsstream.h
index 43671ff..1bfdd7e 100644
--- a/src/lib/common/stdsstream.h
+++ b/src/lib/common/stdsstream.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/common/stdstring.h b/src/lib/common/stdstring.h
index f320ca8..3b3ba0e 100644
--- a/src/lib/common/stdstring.h
+++ b/src/lib/common/stdstring.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/common/stdvector.h b/src/lib/common/stdvector.h
index ab4b853..4dd263d 100644
--- a/src/lib/common/stdvector.h
+++ b/src/lib/common/stdvector.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/common/unix/DataDirectories.cpp b/src/lib/common/unix/DataDirectories.cpp
index 72e510a..cf3ca24 100644
--- a/src/lib/common/unix/DataDirectories.cpp
+++ b/src/lib/common/unix/DataDirectories.cpp
@@ -18,11 +18,11 @@
#include "../DataDirectories.h"
#include <unistd.h> // sysconf
-#include <stdlib.h> // getenv
+#include <cstdlib> // getenv
#include <sys/types.h> // getpwuid(_r)
#include <pwd.h> // getpwuid(_r)
-const std::string ProfileSubdir = "/barrier";
+namespace barrier {
static std::string pw_dir(struct passwd* pwentp)
{
@@ -33,7 +33,7 @@ static std::string pw_dir(struct passwd* pwentp)
#ifdef HAVE_GETPWUID_R
-static std::string unix_home()
+static fs::path unix_home()
{
long size = -1;
#if defined(_SC_GETPW_R_SIZE_MAX)
@@ -46,47 +46,47 @@ static std::string unix_home()
struct passwd* pwentp;
std::string buffer(size, 0);
getpwuid_r(getuid(), &pwent, &buffer[0], size, &pwentp);
- return pw_dir(pwentp);
+ return fs::u8path(pw_dir(pwentp));
}
#else // not HAVE_GETPWUID_R
-static std::string unix_home()
+static fs::path unix_home()
{
- return pw_dir(getpwuid(getuid()));
+ return fs::u8path(pw_dir(getpwuid(getuid())));
}
#endif // HAVE_GETPWUID_R
-static std::string profile_basedir()
+static fs::path profile_basedir()
{
#ifdef WINAPI_XWINDOWS
// linux/bsd adheres to freedesktop standards
// https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
- const char* dir = getenv("XDG_DATA_HOME");
+ const char* dir = std::getenv("XDG_DATA_HOME");
if (dir != NULL)
- return dir;
- return unix_home() + "/.local/share";
+ return fs::u8path(dir);
+ return unix_home() / ".local/share";
#else
// macos has its own standards
// https://developer.apple.com/library/content/documentation/General/Conceptual/MOSXAppProgrammingGuide/AppRuntime/AppRuntime.html
- return unix_home() + "/Library/Application Support";
+ return unix_home() / "Library/Application Support";
#endif
}
-const std::string& DataDirectories::profile()
+const fs::path& DataDirectories::profile()
{
if (_profile.empty())
- _profile = profile_basedir() + ProfileSubdir;
+ _profile = profile_basedir() / "barrier";
return _profile;
}
-const std::string& DataDirectories::profile(const std::string& path)
+const fs::path& DataDirectories::profile(const fs::path& path)
{
_profile = path;
return _profile;
}
-const std::string& DataDirectories::global()
+const fs::path& DataDirectories::global()
{
if (_global.empty())
// TODO: where on a unix system should public/global shared data go?
@@ -94,21 +94,23 @@ const std::string& DataDirectories::global()
_global = "/tmp";
return _global;
}
-const std::string& DataDirectories::global(const std::string& path)
+const fs::path& DataDirectories::global(const fs::path& path)
{
_global = path;
return _global;
}
-const std::string& DataDirectories::systemconfig()
+const fs::path& DataDirectories::systemconfig()
{
if (_systemconfig.empty())
_systemconfig = "/etc";
return _systemconfig;
}
-const std::string& DataDirectories::systemconfig(const std::string& path)
+const fs::path& DataDirectories::systemconfig(const fs::path& path)
{
_systemconfig = path;
return _systemconfig;
}
+
+} // namespace barrier
diff --git a/src/lib/common/win32/DataDirectories.cpp b/src/lib/common/win32/DataDirectories.cpp
index 15cb64e..31a428f 100644
--- a/src/lib/common/win32/DataDirectories.cpp
+++ b/src/lib/common/win32/DataDirectories.cpp
@@ -16,66 +16,62 @@
*/
#include "../DataDirectories.h"
+#include "encoding_utilities.h"
#include <Shlobj.h>
-std::string unicode_to_mb(const WCHAR* utfStr)
-{
- int utfLength = lstrlenW(utfStr);
- int mbLength = WideCharToMultiByte(CP_UTF8, 0, utfStr, utfLength, NULL, 0, NULL, NULL);
- std::string mbStr(mbLength, 0);
- WideCharToMultiByte(CP_UTF8, 0, utfStr, utfLength, &mbStr[0], mbLength, NULL, NULL);
- return mbStr;
-}
+namespace barrier {
-std::string known_folder_path(const KNOWNFOLDERID& id)
+fs::path known_folder_path(const KNOWNFOLDERID& id)
{
- std::string path;
+ fs::path path;
WCHAR* buffer;
HRESULT result = SHGetKnownFolderPath(id, 0, NULL, &buffer);
if (result == S_OK) {
- path = unicode_to_mb(buffer);
+ path = fs::path(std::wstring(buffer));
CoTaskMemFree(buffer);
}
return path;
}
-const std::string& DataDirectories::profile()
+const fs::path& DataDirectories::profile()
{
if (_profile.empty())
- _profile = known_folder_path(FOLDERID_LocalAppData) + "\\Barrier";
+ _profile = known_folder_path(FOLDERID_LocalAppData) / "Barrier";
return _profile;
}
-const std::string& DataDirectories::profile(const std::string& path)
+const fs::path& DataDirectories::profile(const fs::path& path)
{
_profile = path;
return _profile;
}
-const std::string& DataDirectories::global()
+const fs::path& DataDirectories::global()
{
if (_global.empty())
- _global = known_folder_path(FOLDERID_ProgramData) + "\\Barrier";
+ _global = known_folder_path(FOLDERID_ProgramData) / "Barrier";
return _global;
}
-const std::string& DataDirectories::global(const std::string& path)
+const fs::path& DataDirectories::global(const fs::path& path)
{
_global = path;
return _global;
}
-const std::string& DataDirectories::systemconfig()
+const fs::path& DataDirectories::systemconfig()
{
// systemconfig() is a special case in that it will track the current value
- // of global() unless and until it is explictly set otherwise
+ // of global() unless and until it is explicitly set otherwise
// previously it would default to the windows folder which was horrible!
if (_systemconfig.empty())
return global();
return _systemconfig;
}
-const std::string& DataDirectories::systemconfig(const std::string& path)
+const fs::path& DataDirectories::systemconfig(const fs::path& path)
{
_systemconfig = path;
return _systemconfig;
}
+
+} // namespace barrier
diff --git a/src/lib/common/win32/encoding_utilities.cpp b/src/lib/common/win32/encoding_utilities.cpp
new file mode 100644
index 0000000..11781d3
--- /dev/null
+++ b/src/lib/common/win32/encoding_utilities.cpp
@@ -0,0 +1,37 @@
+/*
+ barrier -- mouse and keyboard sharing utility
+ Copyright (C) Barrier contributors
+
+ This package is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ found in the file LICENSE that should have accompanied this file.
+
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "encoding_utilities.h"
+#include <stringapiset.h>
+
+std::string win_wchar_to_utf8(const WCHAR* utfStr)
+{
+ int utfLength = lstrlenW(utfStr);
+ int mbLength = WideCharToMultiByte(CP_UTF8, 0, utfStr, utfLength, NULL, 0, NULL, NULL);
+ std::string mbStr(mbLength, 0);
+ WideCharToMultiByte(CP_UTF8, 0, utfStr, utfLength, &mbStr[0], mbLength, NULL, NULL);
+ return mbStr;
+}
+
+std::vector<WCHAR> utf8_to_win_char(const std::string& str)
+{
+ int result_len = MultiByteToWideChar(CP_UTF8, 0, str.data(), str.size(), NULL, 0);
+ std::vector<WCHAR> result;
+ result.resize(result_len + 1, 0);
+ MultiByteToWideChar(CP_UTF8, 0, str.data(), str.size(), result.data(), result_len);
+ return result;
+}
diff --git a/src/lib/common/win32/encoding_utilities.h b/src/lib/common/win32/encoding_utilities.h
new file mode 100644
index 0000000..747371e
--- /dev/null
+++ b/src/lib/common/win32/encoding_utilities.h
@@ -0,0 +1,28 @@
+/*
+ barrier -- mouse and keyboard sharing utility
+ Copyright (C) Barrier contributors
+
+ This package is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ found in the file LICENSE that should have accompanied this file.
+
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef BARRIER_LIB_COMMON_WIN32_ENCODING_UTILITIES_H
+#define BARRIER_LIB_COMMON_WIN32_ENCODING_UTILITIES_H
+
+#include <windows.h>
+#include <string>
+#include <vector>
+
+std::string win_wchar_to_utf8(const WCHAR* utfStr);
+std::vector<WCHAR> utf8_to_win_char(const std::string& str);
+
+#endif
diff --git a/src/lib/io/CMakeLists.txt b/src/lib/io/CMakeLists.txt
index 32ae7ec..10b79df 100644
--- a/src/lib/io/CMakeLists.txt
+++ b/src/lib/io/CMakeLists.txt
@@ -1,11 +1,11 @@
# barrier -- mouse and keyboard sharing utility
# Copyright (C) 2012-2016 Symless Ltd.
# Copyright (C) 2009 Nick Bolton
-#
+#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
-#
+#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/io/IStream.h b/src/lib/io/IStream.h
index cf93ac4..7601fc4 100644
--- a/src/lib/io/IStream.h
+++ b/src/lib/io/IStream.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/io/StreamBuffer.cpp b/src/lib/io/StreamBuffer.cpp
index 61f05ba..8abbbb8 100644
--- a/src/lib/io/StreamBuffer.cpp
+++ b/src/lib/io/StreamBuffer.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -22,6 +22,8 @@
// StreamBuffer
//
+#include <cassert>
+
const UInt32 StreamBuffer::kChunkSize = 4096;
StreamBuffer::StreamBuffer() :
diff --git a/src/lib/io/StreamBuffer.h b/src/lib/io/StreamBuffer.h
index 49b666b..364175f 100644
--- a/src/lib/io/StreamBuffer.h
+++ b/src/lib/io/StreamBuffer.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/io/StreamFilter.cpp b/src/lib/io/StreamFilter.cpp
index 170e237..dca0a69 100644
--- a/src/lib/io/StreamFilter.cpp
+++ b/src/lib/io/StreamFilter.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/io/StreamFilter.h b/src/lib/io/StreamFilter.h
index e578e0c..55d481e 100644
--- a/src/lib/io/StreamFilter.h
+++ b/src/lib/io/StreamFilter.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/io/XIO.cpp b/src/lib/io/XIO.cpp
index 911fa87..f78e031 100644
--- a/src/lib/io/XIO.cpp
+++ b/src/lib/io/XIO.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/io/XIO.h b/src/lib/io/XIO.h
index 4964441..5803388 100644
--- a/src/lib/io/XIO.h
+++ b/src/lib/io/XIO.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/io/filesystem.cpp b/src/lib/io/filesystem.cpp
new file mode 100644
index 0000000..46ae06d
--- /dev/null
+++ b/src/lib/io/filesystem.cpp
@@ -0,0 +1,71 @@
+/*
+ barrier -- mouse and keyboard sharing utility
+ Copyright (C) Barrier contributors
+
+ This package is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ found in the file LICENSE that should have accompanied this file.
+
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+// this header must come first so that it picks up the filesystem implementation
+#include <ghc/fs_impl.hpp>
+
+#include "filesystem.h"
+#if SYSAPI_WIN32
+#include "common/win32/encoding_utilities.h"
+#endif
+#include <fstream>
+
+namespace barrier {
+
+namespace {
+
+template<class Stream>
+void open_utf8_path_impl(Stream& stream, const fs::path& path, std::ios_base::openmode mode)
+{
+#if SYSAPI_WIN32
+ // on Windows we need to use a non-standard constructor from wchar_t* string
+ // which fs::path::native() returns
+ stream.open(path.native().c_str(), mode);
+#else
+ stream.open(path.native().c_str(), mode);
+#endif
+}
+
+} // namespace
+
+void open_utf8_path(std::ifstream& stream, const fs::path& path, std::ios_base::openmode mode)
+{
+ open_utf8_path_impl(stream, path, mode);
+}
+
+void open_utf8_path(std::ofstream& stream, const fs::path& path, std::ios_base::openmode mode)
+{
+ open_utf8_path_impl(stream, path, mode);
+}
+
+void open_utf8_path(std::fstream& stream, const fs::path& path, std::ios_base::openmode mode)
+{
+ open_utf8_path_impl(stream, path, mode);
+}
+
+std::FILE* fopen_utf8_path(const fs::path& path, const std::string& mode)
+{
+#if SYSAPI_WIN32
+ auto wchar_mode = utf8_to_win_char(mode);
+ return _wfopen(path.native().c_str(),
+ reinterpret_cast<wchar_t*>(wchar_mode.data()));
+#else
+ return std::fopen(path.native().c_str(), mode.c_str());
+#endif
+}
+
+} // namespace barrier
diff --git a/src/lib/io/filesystem.h b/src/lib/io/filesystem.h
new file mode 100644
index 0000000..78e3423
--- /dev/null
+++ b/src/lib/io/filesystem.h
@@ -0,0 +1,41 @@
+/*
+ barrier -- mouse and keyboard sharing utility
+ Copyright (C) Barrier contributors
+
+ This package is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ found in the file LICENSE that should have accompanied this file.
+
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef BARRIER_LIB_IO_FILESYSTEM_H
+#define BARRIER_LIB_IO_FILESYSTEM_H
+
+#include <cstdio>
+#include <iosfwd>
+#include <ios>
+#include <ghc/fs_fwd.hpp>
+
+namespace barrier {
+
+namespace fs = ghc::filesystem;
+
+void open_utf8_path(std::ifstream& stream, const fs::path& path,
+ std::ios_base::openmode mode = std::ios_base::in);
+void open_utf8_path(std::ofstream& stream, const fs::path& path,
+ std::ios_base::openmode mode = std::ios_base::out);
+void open_utf8_path(std::fstream& stream, const fs::path& path,
+ std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out);
+
+std::FILE* fopen_utf8_path(const fs::path& path, const std::string& mode);
+
+} // namespace barrier
+
+#endif // BARRIER_LIB_IO_FILESYSTEM_H
diff --git a/src/lib/ipc/CMakeLists.txt b/src/lib/ipc/CMakeLists.txt
index 3c7302a..e7ada8f 100644
--- a/src/lib/ipc/CMakeLists.txt
+++ b/src/lib/ipc/CMakeLists.txt
@@ -1,11 +1,11 @@
# barrier -- mouse and keyboard sharing utility
# Copyright (C) 2012-2016 Symless Ltd.
# Copyright (C) 2009 Nick Bolton
-#
+#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
-#
+#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/ipc/Ipc.h b/src/lib/ipc/Ipc.h
index bc69c08..65e7aaf 100644
--- a/src/lib/ipc/Ipc.h
+++ b/src/lib/ipc/Ipc.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/ipc/IpcClient.cpp b/src/lib/ipc/IpcClient.cpp
index 4eeae5b..ea5eee1 100644
--- a/src/lib/ipc/IpcClient.cpp
+++ b/src/lib/ipc/IpcClient.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/ipc/IpcClient.h b/src/lib/ipc/IpcClient.h
index 1e9bca6..900b46c 100644
--- a/src/lib/ipc/IpcClient.h
+++ b/src/lib/ipc/IpcClient.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -42,7 +42,7 @@ public:
//! Connects to the IPC server at localhost.
void connect();
-
+
//! Disconnects from the IPC server.
void disconnect();
diff --git a/src/lib/ipc/IpcClientProxy.cpp b/src/lib/ipc/IpcClientProxy.cpp
index 432cc8c..cedfa5b 100644
--- a/src/lib/ipc/IpcClientProxy.cpp
+++ b/src/lib/ipc/IpcClientProxy.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -67,7 +67,7 @@ IpcClientProxy::~IpcClientProxy()
m_events->forIStream().inputShutdown(), m_stream.getEventTarget());
m_events->removeHandler(
m_events->forIStream().outputShutdown(), m_stream.getEventTarget());
-
+
// don't delete the stream while it's being used.
{
std::lock_guard<std::mutex> lock_read(m_readMutex);
@@ -145,7 +145,7 @@ IpcClientProxy::send(const IpcMessage& message)
ProtocolUtil::writef(&m_stream, kIpcMsgLogLine, &logLine);
break;
}
-
+
case kIpcShutdown:
ProtocolUtil::writef(&m_stream, kIpcMsgShutdown);
break;
diff --git a/src/lib/ipc/IpcClientProxy.h b/src/lib/ipc/IpcClientProxy.h
index eb9f1e9..dbd0846 100644
--- a/src/lib/ipc/IpcClientProxy.h
+++ b/src/lib/ipc/IpcClientProxy.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -46,7 +46,7 @@ private:
IpcHelloMessage* parseHello();
IpcCommandMessage* parseCommand();
void disconnect();
-
+
private:
barrier::IStream& m_stream;
EIpcClientType m_clientType;
diff --git a/src/lib/ipc/IpcLogOutputter.cpp b/src/lib/ipc/IpcLogOutputter.cpp
index 44ecdba..5118a0a 100644
--- a/src/lib/ipc/IpcLogOutputter.cpp
+++ b/src/lib/ipc/IpcLogOutputter.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -28,7 +28,6 @@
#include "base/Event.h"
#include "base/EventQueue.h"
#include "base/TMethodEventJob.h"
-#include "base/TMethodJob.h"
enum EIpcLogOutputter {
kBufferMaxSize = 1000,
@@ -54,8 +53,7 @@ IpcLogOutputter::IpcLogOutputter(IpcServer& ipcServer, EIpcClientType clientType
m_clientType(clientType)
{
if (useThread) {
- m_bufferThread = new Thread(new TMethodJob<IpcLogOutputter>(
- this, &IpcLogOutputter::bufferThread));
+ m_bufferThread = new Thread([this](){ buffer_thread(); });
}
}
@@ -142,8 +140,7 @@ IpcLogOutputter::isRunning()
return m_running;
}
-void
-IpcLogOutputter::bufferThread(void*)
+void IpcLogOutputter::buffer_thread()
{
m_bufferThreadId = m_bufferThread->getID();
m_running = true;
diff --git a/src/lib/ipc/IpcLogOutputter.h b/src/lib/ipc/IpcLogOutputter.h
index cc7b2fe..3f3ab0a 100644
--- a/src/lib/ipc/IpcLogOutputter.h
+++ b/src/lib/ipc/IpcLogOutputter.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -50,7 +50,7 @@ public:
virtual void close();
virtual void show(bool showIfEmpty);
virtual bool write(ELevel level, const char* message);
-
+
//! @name manipulators
//@{
@@ -76,23 +76,23 @@ public:
when threaded mode is on.
*/
void sendBuffer();
-
+
//@}
-
+
//! @name accessors
//@{
-
+
//! Get the buffer size
/*!
Returns the maximum size of the buffer.
*/
UInt16 bufferMaxSize() const;
-
+
//@}
private:
void init();
- void bufferThread(void*);
+ void buffer_thread();
std::string getChunk(size_t count);
void appendBuffer(const std::string& text);
bool isRunning();
diff --git a/src/lib/ipc/IpcMessage.cpp b/src/lib/ipc/IpcMessage.cpp
index 9c321cb..f1b13b1 100644
--- a/src/lib/ipc/IpcMessage.cpp
+++ b/src/lib/ipc/IpcMessage.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/ipc/IpcMessage.h b/src/lib/ipc/IpcMessage.h
index d37ebc3..06ca08a 100644
--- a/src/lib/ipc/IpcMessage.h
+++ b/src/lib/ipc/IpcMessage.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/ipc/IpcServer.cpp b/src/lib/ipc/IpcServer.cpp
index 8df98d1..da201c1 100644
--- a/src/lib/ipc/IpcServer.cpp
+++ b/src/lib/ipc/IpcServer.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/ipc/IpcServer.h b/src/lib/ipc/IpcServer.h
index 179bad8..f6227f2 100644
--- a/src/lib/ipc/IpcServer.h
+++ b/src/lib/ipc/IpcServer.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -73,7 +73,7 @@ private:
private:
typedef std::list<IpcClientProxy*> ClientList;
-
+
bool m_mock;
IEventQueue* m_events;
SocketMultiplexer* m_socketMultiplexer;
@@ -82,7 +82,7 @@ private:
ClientList m_clients;
mutable std::mutex m_clientsMutex;
-#ifdef TEST_ENV
+#ifdef BARRIER_TEST_ENV
public:
IpcServer() :
m_mock(true),
diff --git a/src/lib/ipc/IpcServerProxy.cpp b/src/lib/ipc/IpcServerProxy.cpp
index 49b3e00..073f7e7 100644
--- a/src/lib/ipc/IpcServerProxy.cpp
+++ b/src/lib/ipc/IpcServerProxy.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -56,7 +56,7 @@ IpcServerProxy::handleData(const Event&, void*)
LOG((CLOG_DEBUG "ipc read: %c%c%c%c",
code[0], code[1], code[2], code[3]));
-
+
IpcMessage* m = nullptr;
if (memcmp(code, kIpcMsgLogLine, 4) == 0) {
m = parseLogLine();
@@ -68,7 +68,7 @@ IpcServerProxy::handleData(const Event&, void*)
LOG((CLOG_ERR "invalid ipc message"));
disconnect();
}
-
+
// don't delete with this event; the data is passed to a new event.
Event e(m_events->forIpcServerProxy().messageReceived(), this, NULL, Event::kDontFreeData);
e.setDataObject(m);
@@ -76,7 +76,7 @@ IpcServerProxy::handleData(const Event&, void*)
n = m_stream.read(code, 4);
}
-
+
LOG((CLOG_DEBUG "finished ipc handle data"));
}
@@ -110,7 +110,7 @@ IpcServerProxy::parseLogLine()
{
std::string logLine;
ProtocolUtil::readf(&m_stream, kIpcMsgLogLine + 4, &logLine);
-
+
// must be deleted by event handler.
return new IpcLogLineMessage(logLine);
}
diff --git a/src/lib/ipc/IpcServerProxy.h b/src/lib/ipc/IpcServerProxy.h
index f2218a4..f724f97 100644
--- a/src/lib/ipc/IpcServerProxy.h
+++ b/src/lib/ipc/IpcServerProxy.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/mt/CMakeLists.txt b/src/lib/mt/CMakeLists.txt
index 9ee5ea4..19d1829 100644
--- a/src/lib/mt/CMakeLists.txt
+++ b/src/lib/mt/CMakeLists.txt
@@ -1,11 +1,11 @@
# barrier -- mouse and keyboard sharing utility
# Copyright (C) 2012-2016 Symless Ltd.
# Copyright (C) 2009 Nick Bolton
-#
+#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
-#
+#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/mt/CondVar.cpp b/src/lib/mt/CondVar.cpp
index 11318f9..b9cf565 100644
--- a/src/lib/mt/CondVar.cpp
+++ b/src/lib/mt/CondVar.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -24,7 +24,7 @@
// CondVarBase
//
-CondVarBase::CondVarBase(Mutex* mutex) :
+CondVarBase::CondVarBase(Mutex* mutex) :
m_mutex(mutex)
{
assert(m_mutex != NULL);
diff --git a/src/lib/mt/CondVar.h b/src/lib/mt/CondVar.h
index 0ab956b..fc18748 100644
--- a/src/lib/mt/CondVar.h
+++ b/src/lib/mt/CondVar.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -78,7 +78,7 @@ public:
signalled, otherwise up to \c timeout seconds or until signalled,
whichever comes first. Returns true if the object was signalled
during the wait, false otherwise.
-
+
The proper way to wait for a condition is:
\code
cv.lock();
diff --git a/src/lib/mt/Lock.cpp b/src/lib/mt/Lock.cpp
index 80721b9..6614858 100644
--- a/src/lib/mt/Lock.cpp
+++ b/src/lib/mt/Lock.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/mt/Lock.h b/src/lib/mt/Lock.h
index 4a3f311..e4bbacf 100644
--- a/src/lib/mt/Lock.h
+++ b/src/lib/mt/Lock.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/mt/Mutex.cpp b/src/lib/mt/Mutex.cpp
index e9a62e8..02d34c9 100644
--- a/src/lib/mt/Mutex.cpp
+++ b/src/lib/mt/Mutex.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/mt/Mutex.h b/src/lib/mt/Mutex.h
index 51a9649..53b8f45 100644
--- a/src/lib/mt/Mutex.h
+++ b/src/lib/mt/Mutex.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/mt/Thread.cpp b/src/lib/mt/Thread.cpp
index 7474c16..755c0e6 100644
--- a/src/lib/mt/Thread.cpp
+++ b/src/lib/mt/Thread.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -28,12 +28,10 @@
// Thread
//
-Thread::Thread(IJob* job)
+Thread::Thread(const std::function<void()>& fun)
{
- m_thread = ARCH->newThread(&Thread::threadFunc, job);
+ m_thread = ARCH->newThread([=](){ threadFunc(fun); });
if (m_thread == NULL) {
- // couldn't create thread
- delete job;
throw XMTThreadUnavailable();
}
}
@@ -69,7 +67,7 @@ Thread::operator=(const Thread& thread)
void
Thread::exit(void* result)
{
- throw XThreadExit(result);
+ throw XThreadExit();
}
void
@@ -108,15 +106,6 @@ Thread::wait(double timeout) const
return ARCH->wait(m_thread, timeout);
}
-void*
-Thread::getResult() const
-{
- if (wait())
- return ARCH->getResultOfThread(m_thread);
- else
- return NULL;
-}
-
IArchMultithread::ThreadID
Thread::getID() const
{
@@ -135,8 +124,7 @@ Thread::operator!=(const Thread& thread) const
return !ARCH->isSameThread(m_thread, thread.m_thread);
}
-void*
-Thread::threadFunc(void* vjob)
+void Thread::threadFunc(const std::function<void()>& func)
{
// get this thread's id for logging
IArchMultithread::ThreadID id;
@@ -146,42 +134,26 @@ Thread::threadFunc(void* vjob)
ARCH->closeThread(thread);
}
- // get job
- IJob* job = static_cast<IJob*>(vjob);
-
- // run job
- void* result = NULL;
try {
// go
LOG((CLOG_DEBUG1 "thread 0x%08x entry", id));
- job->run();
+ func();
LOG((CLOG_DEBUG1 "thread 0x%08x exit", id));
}
catch (XThreadCancel&) {
// client called cancel()
LOG((CLOG_DEBUG1 "caught cancel on thread 0x%08x", id));
- delete job;
throw;
}
- catch (XThreadExit& e) {
- // client called exit()
- result = e.m_result;
- LOG((CLOG_DEBUG1 "caught exit on thread 0x%08x, result %p", id, result));
+ catch (XThreadExit&) {
+ LOG((CLOG_DEBUG1 "caught exit on thread 0x%08x", id));
}
catch (XBase& e) {
LOG((CLOG_ERR "exception on thread 0x%08x: %s", id, e.what()));
- delete job;
throw;
}
catch (...) {
LOG((CLOG_ERR "exception on thread 0x%08x: <unknown>", id));
- delete job;
throw;
}
-
- // done with job
- delete job;
-
- // return exit result
- return result;
}
diff --git a/src/lib/mt/Thread.h b/src/lib/mt/Thread.h
index a7434fd..141d59f 100644
--- a/src/lib/mt/Thread.h
+++ b/src/lib/mt/Thread.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -19,13 +19,12 @@
#pragma once
#include "arch/IArchMultithread.h"
-
-class IJob;
+#include <functional>
//! Thread handle
/*!
Creating a Thread creates a new context of execution (i.e. thread) that
-runs simulatenously with the calling thread. A Thread is only a handle
+runs simultaneously with the calling thread. A Thread is only a handle
to a thread; deleting a Thread does not cancel or destroy the thread it
refers to and multiple Thread objects can refer to the same thread.
@@ -44,10 +43,9 @@ class Thread {
public:
//! Run \c adoptedJob in a new thread
/*!
- Create and start a new thread executing the \c adoptedJob. The
- new thread takes ownership of \c adoptedJob and will delete it.
+ Create and start a new thread executing the \c fun.
*/
- Thread(IJob* adoptedJob);
+ Thread(const std::function<void()>& fun);
//! Duplicate a thread handle
/*!
@@ -79,8 +77,7 @@ public:
/*!
Terminate the calling thread. This function does not return but
the stack is unwound and automatic objects are destroyed, as if
- exit() threw an exception (which is, in fact, what it does). The
- argument is saved as the result returned by getResult(). If you
+ exit() threw an exception (which is, in fact, what it does). If you
have \c catch(...) blocks then you should add the following before
each to avoid catching the exit:
\code
@@ -98,7 +95,7 @@ public:
enabled. If cancellation is disabled then the cancel is
remembered but not acted on until the first call to a
cancellation point after cancellation is enabled.
-
+
A cancellation point is a function that can act on cancellation.
A cancellation point does not return if there's a cancel pending.
Instead, it unwinds the stack and destroys automatic objects, as
@@ -110,7 +107,7 @@ public:
objects (like Lock). Clients are strongly encouraged to do the latter.
During cancellation, further cancel() calls are ignored (i.e.
a thread cannot be interrupted by a cancel during cancellation).
-
+
Clients that \c catch(XThreadCancel) must always rethrow the
exception. Clients that \c catch(...) must either rethrow the
exception or include a \c catch(XThreadCancel) handler that
@@ -122,7 +119,7 @@ public:
/*!
Change the priority of the thread. Normal priority is 0, 1 is
the next lower, etc. -1 is the next higher, etc. but boosting
- the priority may not be permitted and will be silenty ignored.
+ the priority may not be permitted and will be silently ignored.
*/
void setPriority(int n);
@@ -167,16 +164,6 @@ public:
*/
bool wait(double timeout = -1.0) const;
- //! Get the exit result
- /*!
- Returns the exit result. This does an implicit wait(). It returns
- NULL immediately if called by a thread on itself or on a thread that
- was cancelled.
-
- (cancellation point)
- */
- void* getResult() const;
-
//! Get the thread id
/*!
Returns an integer id for this thread. This id must not be used to
@@ -203,7 +190,7 @@ public:
private:
Thread(ArchThread);
- static void* threadFunc(void*);
+ static void threadFunc(const std::function<void()>& func);
private:
ArchThread m_thread;
diff --git a/src/lib/mt/XMT.cpp b/src/lib/mt/XMT.cpp
index 2274a6b..2282d63 100644
--- a/src/lib/mt/XMT.cpp
+++ b/src/lib/mt/XMT.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/mt/XMT.h b/src/lib/mt/XMT.h
index 9e48fd9..ec4a683 100644
--- a/src/lib/mt/XMT.h
+++ b/src/lib/mt/XMT.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/mt/XThread.h b/src/lib/mt/XThread.h
index acc32e3..41172b3 100644
--- a/src/lib/mt/XThread.h
+++ b/src/lib/mt/XThread.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -26,12 +26,4 @@ Thrown by Thread::exit() to exit a thread. Clients of Thread
must not throw this type but must rethrow it if caught (by
XThreadExit, XThread, or ...).
*/
-class XThreadExit : public XThread {
-public:
- //! \c result is the result of the thread
- XThreadExit(void* result) : m_result(result) { }
- ~XThreadExit() { }
-
-public:
- void* m_result;
-};
+class XThreadExit : public XThread {};
diff --git a/src/lib/net/CMakeLists.txt b/src/lib/net/CMakeLists.txt
index 5439450..8c12ed9 100644
--- a/src/lib/net/CMakeLists.txt
+++ b/src/lib/net/CMakeLists.txt
@@ -1,11 +1,11 @@
# barrier -- mouse and keyboard sharing utility
# Copyright (C) 2012-2016 Symless Ltd.
# Copyright (C) 2009 Nick Bolton
-#
+#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
-#
+#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/net/ConnectionSecurityLevel.h b/src/lib/net/ConnectionSecurityLevel.h
new file mode 100644
index 0000000..913c2fd
--- /dev/null
+++ b/src/lib/net/ConnectionSecurityLevel.h
@@ -0,0 +1,27 @@
+/*
+ barrier -- mouse and keyboard sharing utility
+ Copyright (C) Barrier contributors
+
+ This package is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ found in the file LICENSE that should have accompanied this file.
+
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef BARRIER_LIB_NET_CONNECTION_SECURITY_LEVEL_H
+#define BARRIER_LIB_NET_CONNECTION_SECURITY_LEVEL_H
+
+enum class ConnectionSecurityLevel {
+ PLAINTEXT,
+ ENCRYPTED,
+ ENCRYPTED_AUTHENTICATED
+};
+
+#endif // BARRIER_LIB_NET_CONNECTION_SECURITY_LEVEL_H
diff --git a/src/lib/net/FingerprintData.cpp b/src/lib/net/FingerprintData.cpp
new file mode 100644
index 0000000..460b39b
--- /dev/null
+++ b/src/lib/net/FingerprintData.cpp
@@ -0,0 +1,52 @@
+/*
+ barrier -- mouse and keyboard sharing utility
+ Copyright (C) Barrier contributors
+
+ This package is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ found in the file LICENSE that should have accompanied this file.
+
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "base/String.h"
+#include "FingerprintDatabase.h"
+#include "io/filesystem.h"
+#include <algorithm>
+#include <fstream>
+
+namespace barrier {
+
+bool FingerprintData::operator==(const FingerprintData& other) const
+{
+ return algorithm == other.algorithm && data == other.data;
+}
+
+const char* fingerprint_type_to_string(FingerprintType type)
+{
+ switch (type) {
+ case FingerprintType::INVALID: return "invalid";
+ case FingerprintType::SHA1: return "sha1";
+ case FingerprintType::SHA256: return "sha256";
+ }
+ return "invalid";
+}
+
+FingerprintType fingerprint_type_from_string(const std::string& type)
+{
+ if (type == "sha1") {
+ return FingerprintType::SHA1;
+ }
+ if (type == "sha256") {
+ return FingerprintType::SHA256;
+ }
+ return FingerprintType::INVALID;
+}
+
+} // namespace barrier
diff --git a/src/lib/net/FingerprintData.h b/src/lib/net/FingerprintData.h
new file mode 100644
index 0000000..938a695
--- /dev/null
+++ b/src/lib/net/FingerprintData.h
@@ -0,0 +1,46 @@
+/*
+ barrier -- mouse and keyboard sharing utility
+ Copyright (C) Barrier contributors
+
+ This package is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ found in the file LICENSE that should have accompanied this file.
+
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef BARRIER_LIB_NET_FINGERPRINT_DATA_H
+#define BARRIER_LIB_NET_FINGERPRINT_DATA_H
+
+#include <string>
+#include <vector>
+
+namespace barrier {
+
+enum FingerprintType {
+ INVALID,
+ SHA1, // deprecated
+ SHA256,
+};
+
+struct FingerprintData {
+ std::string algorithm;
+ std::vector<std::uint8_t> data;
+
+ bool valid() const { return !algorithm.empty(); }
+
+ bool operator==(const FingerprintData& other) const;
+};
+
+const char* fingerprint_type_to_string(FingerprintType type);
+FingerprintType fingerprint_type_from_string(const std::string& type);
+
+} // namespace barrier
+
+#endif // BARRIER_LIB_NET_FINGERPRINT_TYPE_H
diff --git a/src/lib/net/FingerprintDatabase.cpp b/src/lib/net/FingerprintDatabase.cpp
new file mode 100644
index 0000000..def0de9
--- /dev/null
+++ b/src/lib/net/FingerprintDatabase.cpp
@@ -0,0 +1,135 @@
+/*
+ barrier -- mouse and keyboard sharing utility
+ Copyright (C) Barrier contributors
+
+ This package is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ found in the file LICENSE that should have accompanied this file.
+
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "base/String.h"
+#include "FingerprintDatabase.h"
+#include "io/filesystem.h"
+#include <algorithm>
+#include <fstream>
+
+namespace barrier {
+
+void FingerprintDatabase::read(const fs::path& path)
+{
+ std::ifstream file;
+ open_utf8_path(file, path, std::ios_base::in);
+ read_stream(file);
+}
+
+void FingerprintDatabase::write(const fs::path& path)
+{
+ std::ofstream file;
+ open_utf8_path(file, path, std::ios_base::out);
+ write_stream(file);
+}
+
+void FingerprintDatabase::read_stream(std::istream& stream)
+{
+ if (!stream.good()) {
+ return;
+ }
+
+ std::string line;
+ while (std::getline(stream, line)) {
+ if (line.empty()) {
+ continue;
+ }
+
+ auto fingerprint = parse_db_line(line);
+ if (!fingerprint.valid()) {
+ continue;
+ }
+
+ fingerprints_.push_back(fingerprint);
+ }
+}
+
+void FingerprintDatabase::write_stream(std::ostream& stream)
+{
+ if (!stream.good()) {
+ return;
+ }
+
+ for (const auto& fingerprint : fingerprints_) {
+ stream << to_db_line(fingerprint) << "\n";
+ }
+}
+
+void FingerprintDatabase::clear()
+{
+ fingerprints_.clear();
+}
+
+void FingerprintDatabase::add_trusted(const FingerprintData& fingerprint)
+{
+ if (is_trusted(fingerprint)) {
+ return;
+ }
+ fingerprints_.push_back(fingerprint);
+}
+
+bool FingerprintDatabase::is_trusted(const FingerprintData& fingerprint)
+{
+ auto found_it = std::find(fingerprints_.begin(), fingerprints_.end(), fingerprint);
+ return found_it != fingerprints_.end();
+}
+
+FingerprintData FingerprintDatabase::parse_db_line(const std::string& line)
+{
+ FingerprintData result;
+
+ // legacy v1 certificate handling
+ if (std::count(line.begin(), line.end(), ':') == 19 && line.size() == 40 + 19) {
+ auto data = string::from_hex(line);
+ if (data.empty()) {
+ return result;
+ }
+ result.algorithm = fingerprint_type_to_string(FingerprintType::SHA1);
+ result.data = data;
+ return result;
+ }
+
+ auto version_end_pos = line.find(':');
+ if (version_end_pos == std::string::npos) {
+ return result;
+ }
+ if (line.substr(0, version_end_pos) != "v2") {
+ return result;
+ }
+ auto algo_start_pos = version_end_pos + 1;
+ auto algo_end_pos = line.find(':', algo_start_pos);
+ if (algo_end_pos == std::string::npos) {
+ return result;
+ }
+ auto algorithm = line.substr(algo_start_pos, algo_end_pos - algo_start_pos);
+ auto data = string::from_hex(line.substr(algo_end_pos + 1));
+
+ if (data.empty()) {
+ return result;
+ }
+
+ result.algorithm = algorithm;
+ result.data = data;
+ return result;
+}
+
+std::string FingerprintDatabase::to_db_line(const FingerprintData& fingerprint)
+{
+ return "v2:" + fingerprint.algorithm + ":" + string::to_hex(fingerprint.data, 2);
+}
+
+} // namespace barrier
diff --git a/src/lib/net/FingerprintDatabase.h b/src/lib/net/FingerprintDatabase.h
new file mode 100644
index 0000000..4927265
--- /dev/null
+++ b/src/lib/net/FingerprintDatabase.h
@@ -0,0 +1,53 @@
+/*
+ barrier -- mouse and keyboard sharing utility
+ Copyright (C) Barrier contributors
+
+ This package is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ found in the file LICENSE that should have accompanied this file.
+
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef BARRIER_LIB_NET_FINGERPRINT_DATABASE_H
+#define BARRIER_LIB_NET_FINGERPRINT_DATABASE_H
+
+#include "FingerprintData.h"
+#include "io/filesystem.h"
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+namespace barrier {
+
+class FingerprintDatabase {
+public:
+ void read(const fs::path& path);
+ void write(const fs::path& path);
+
+ void read_stream(std::istream& stream);
+ void write_stream(std::ostream& stream);
+
+ void clear();
+ void add_trusted(const FingerprintData& fingerprint);
+ bool is_trusted(const FingerprintData& fingerprint);
+
+ const std::vector<FingerprintData>& fingerprints() const { return fingerprints_; }
+
+ static FingerprintData parse_db_line(const std::string& line);
+ static std::string to_db_line(const FingerprintData& fingerprint);
+
+private:
+
+ std::vector<FingerprintData> fingerprints_;
+};
+
+} // namespace barrier
+
+#endif // BARRIER_LIB_NET_FINGERPRINT_DATABASE_H
diff --git a/src/lib/net/IDataSocket.cpp b/src/lib/net/IDataSocket.cpp
index cc679c3..30e00f4 100644
--- a/src/lib/net/IDataSocket.cpp
+++ b/src/lib/net/IDataSocket.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/net/IDataSocket.h b/src/lib/net/IDataSocket.h
index c77a99c..0fc41bb 100644
--- a/src/lib/net/IDataSocket.h
+++ b/src/lib/net/IDataSocket.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/net/IListenSocket.h b/src/lib/net/IListenSocket.h
index 73dcc6e..5452a37 100644
--- a/src/lib/net/IListenSocket.h
+++ b/src/lib/net/IListenSocket.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -41,7 +41,7 @@ public:
*/
virtual IDataSocket*
accept() = 0;
-
+
//@}
// ISocket overrides
diff --git a/src/lib/net/ISocket.h b/src/lib/net/ISocket.h
index 0e9688b..f41fd55 100644
--- a/src/lib/net/ISocket.h
+++ b/src/lib/net/ISocket.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/net/ISocketFactory.h b/src/lib/net/ISocketFactory.h
index e440953..edfc8c9 100644
--- a/src/lib/net/ISocketFactory.h
+++ b/src/lib/net/ISocketFactory.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -20,6 +20,7 @@
#include "common/IInterface.h"
#include "arch/IArchNetwork.h"
+#include "net/ConnectionSecurityLevel.h"
class IDataSocket;
class IListenSocket;
@@ -35,14 +36,12 @@ public:
//@{
//! Create data socket
- virtual IDataSocket* create(
- IArchNetwork::EAddressFamily family,
- bool secure) const = 0;
+ virtual IDataSocket* create(IArchNetwork::EAddressFamily family,
+ ConnectionSecurityLevel security_level) const = 0;
//! Create listen socket
- virtual IListenSocket* createListen(
- IArchNetwork::EAddressFamily family,
- bool secure) const = 0;
+ virtual IListenSocket* createListen(IArchNetwork::EAddressFamily family,
+ ConnectionSecurityLevel security_level) const = 0;
//@}
};
diff --git a/src/lib/net/ISocketMultiplexerJob.h b/src/lib/net/ISocketMultiplexerJob.h
index c27fce2..2dab87e 100644
--- a/src/lib/net/ISocketMultiplexerJob.h
+++ b/src/lib/net/ISocketMultiplexerJob.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/net/NetworkAddress.cpp b/src/lib/net/NetworkAddress.cpp
index c8ea9c6..3526fc0 100644
--- a/src/lib/net/NetworkAddress.cpp
+++ b/src/lib/net/NetworkAddress.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/net/NetworkAddress.h b/src/lib/net/NetworkAddress.h
index 87dc1e4..3a006af 100644
--- a/src/lib/net/NetworkAddress.h
+++ b/src/lib/net/NetworkAddress.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -43,7 +43,7 @@ public:
If \c hostname can be parsed as a numerical address then that's how
it's used, otherwise it's used as a host name. If \c hostname ends
in ":[0-9]+" then that suffix is extracted and used as the port,
- overridding the port parameter. The resulting port must be a valid
+ overriding the port parameter. The resulting port must be a valid
port number (zero is not a valid port number) otherwise \c XSocketAddress
is thrown with an error of \c XSocketAddress::kBadPort. The hostname
is not resolved by the c'tor; use \c resolve to do that.
diff --git a/src/lib/net/SecureListenSocket.cpp b/src/lib/net/SecureListenSocket.cpp
index a137f39..11efc5c 100644
--- a/src/lib/net/SecureListenSocket.cpp
+++ b/src/lib/net/SecureListenSocket.cpp
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2015-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -20,23 +20,16 @@
#include "SecureSocket.h"
#include "net/NetworkAddress.h"
#include "net/SocketMultiplexer.h"
-#include "net/TSocketMultiplexerMethodJob.h"
+#include "arch/Arch.h"
#include "arch/XArch.h"
#include "common/DataDirectories.h"
#include "base/String.h"
-static const char s_certificateDir[] = { "SSL" };
-static const char s_certificateFilename[] = { "Barrier.pem" };
-
-//
-// SecureListenSocket
-//
-
-SecureListenSocket::SecureListenSocket(
- IEventQueue* events,
- SocketMultiplexer* socketMultiplexer,
- IArchNetwork::EAddressFamily family) :
- TCPListenSocket(events, socketMultiplexer, family)
+SecureListenSocket::SecureListenSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer,
+ IArchNetwork::EAddressFamily family,
+ ConnectionSecurityLevel security_level) :
+ TCPListenSocket(events, socketMultiplexer, family),
+ security_level_{security_level}
{
}
@@ -45,22 +38,15 @@ SecureListenSocket::accept()
{
SecureSocket* socket = NULL;
try {
- socket = new SecureSocket(
- m_events,
- m_socketMultiplexer,
- ARCH->acceptSocket(m_socket, NULL));
+ socket = new SecureSocket(m_events, m_socketMultiplexer,
+ ARCH->acceptSocket(m_socket, NULL), security_level_);
socket->initSsl(true);
if (socket != NULL) {
setListeningJob();
}
- std::string certificateFilename = barrier::string::sprintf("%s/%s/%s",
- DataDirectories::profile().c_str(),
- s_certificateDir,
- s_certificateFilename);
-
- bool loaded = socket->loadCertificates(certificateFilename);
+ bool loaded = socket->load_certificates(barrier::DataDirectories::ssl_certificate_path());
if (!loaded) {
delete socket;
return NULL;
diff --git a/src/lib/net/SecureListenSocket.h b/src/lib/net/SecureListenSocket.h
index d0c6e23..a0e792a 100644
--- a/src/lib/net/SecureListenSocket.h
+++ b/src/lib/net/SecureListenSocket.h
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2015-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -19,18 +19,21 @@
#include "net/TCPListenSocket.h"
#include "common/stdset.h"
+#include "ConnectionSecurityLevel.h"
class IEventQueue;
class SocketMultiplexer;
class IDataSocket;
-class SecureListenSocket : public TCPListenSocket{
+class SecureListenSocket : public TCPListenSocket {
public:
- SecureListenSocket(IEventQueue* events,
- SocketMultiplexer* socketMultiplexer,
- IArchNetwork::EAddressFamily family);
+ SecureListenSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer,
+ IArchNetwork::EAddressFamily family,
+ ConnectionSecurityLevel security_level);
// IListenSocket overrides
virtual IDataSocket*
accept();
+private:
+ ConnectionSecurityLevel security_level_;
};
diff --git a/src/lib/net/SecureSocket.cpp b/src/lib/net/SecureSocket.cpp
index 855e16b..85e1d38 100644
--- a/src/lib/net/SecureSocket.cpp
+++ b/src/lib/net/SecureSocket.cpp
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2015-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -16,6 +16,7 @@
*/
#include "SecureSocket.h"
+#include "SecureUtils.h"
#include "net/TSocketMultiplexerMethodJob.h"
#include "base/TMethodEventJob.h"
@@ -25,6 +26,8 @@
#include "base/Log.h"
#include "base/String.h"
#include "common/DataDirectories.h"
+#include "io/filesystem.h"
+#include "net/FingerprintDatabase.h"
#include <openssl/ssl.h>
#include <openssl/err.h>
@@ -40,41 +43,36 @@
#define MAX_ERROR_SIZE 65535
+static const std::size_t MAX_INPUT_BUFFER_SIZE = 1024 * 1024;
static const float s_retryDelay = 0.01f;
enum {
kMsgSize = 128
};
-static const char kFingerprintDirName[] = "SSL/Fingerprints";
-//static const char kFingerprintLocalFilename[] = "Local.txt";
-static const char kFingerprintTrustedServersFilename[] = "TrustedServers.txt";
-//static const char kFingerprintTrustedClientsFilename[] = "TrustedClients.txt";
-
struct Ssl {
SSL_CTX* m_context;
SSL* m_ssl;
};
-SecureSocket::SecureSocket(
- IEventQueue* events,
- SocketMultiplexer* socketMultiplexer,
- IArchNetwork::EAddressFamily family) :
+SecureSocket::SecureSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer,
+ IArchNetwork::EAddressFamily family,
+ ConnectionSecurityLevel security_level) :
TCPSocket(events, socketMultiplexer, family),
m_ssl(nullptr),
m_secureReady(false),
- m_fatal(false)
+ m_fatal(false),
+ security_level_{security_level}
{
}
-SecureSocket::SecureSocket(
- IEventQueue* events,
- SocketMultiplexer* socketMultiplexer,
- ArchSocket socket) :
+SecureSocket::SecureSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer,
+ ArchSocket socket, ConnectionSecurityLevel security_level) :
TCPSocket(events, socketMultiplexer, socket),
m_ssl(nullptr),
m_secureReady(false),
- m_fatal(false)
+ m_fatal(false),
+ security_level_{security_level}
{
}
@@ -103,6 +101,8 @@ SecureSocket::close()
void SecureSocket::freeSSLResources()
{
+ std::lock_guard<std::mutex> ssl_lock{ssl_mutex_};
+
if (m_ssl->m_ssl != NULL) {
SSL_shutdown(m_ssl->m_ssl);
SSL_free(m_ssl->m_ssl);
@@ -133,30 +133,30 @@ std::unique_ptr<ISocketMultiplexerJob> SecureSocket::newJob()
if (m_connected && !m_secureReady) {
return {};
}
-
+
return TCPSocket::newJob();
}
void
SecureSocket::secureConnect()
{
- setJob(std::make_unique<TSocketMultiplexerMethodJob<SecureSocket>>(
- this, &SecureSocket::serviceConnect,
- getSocket(), isReadable(), isWritable()));
+ setJob(std::make_unique<TSocketMultiplexerMethodJob>([this](auto j, auto r, auto w, auto e)
+ { return serviceConnect(j, r, w, e); },
+ getSocket(), isReadable(), isWritable()));
}
void
SecureSocket::secureAccept()
{
- setJob(std::make_unique<TSocketMultiplexerMethodJob<SecureSocket>>(
- this, &SecureSocket::serviceAccept,
- getSocket(), isReadable(), isWritable()));
+ setJob(std::make_unique<TSocketMultiplexerMethodJob>([this](auto j, auto r, auto w, auto e)
+ { return serviceAccept(j, r, w, e); },
+ getSocket(), isReadable(), isWritable()));
}
TCPSocket::EJobResult
SecureSocket::doRead()
{
- static UInt8 buffer[4096];
+ UInt8 buffer[4096];
memset(buffer, 0, sizeof(buffer));
int bytesRead = 0;
int status = 0;
@@ -173,20 +173,24 @@ SecureSocket::doRead()
else {
return kRetry;
}
-
+
if (bytesRead > 0) {
bool wasEmpty = (m_inputBuffer.getSize() == 0);
-
+
// slurp up as much as possible
do {
m_inputBuffer.write(buffer, bytesRead);
-
+
+ if (m_inputBuffer.getSize() > MAX_INPUT_BUFFER_SIZE) {
+ break;
+ }
+
status = secureRead(buffer, sizeof(buffer), bytesRead);
if (status < 0) {
return kBreak;
}
} while (bytesRead > 0 || status > 0);
-
+
// send input ready if input buffer was empty
if (wasEmpty) {
sendEvent(m_events->forIStream().inputReady());
@@ -204,18 +208,13 @@ SecureSocket::doRead()
m_readable = false;
return kNew;
}
-
+
return kRetry;
}
TCPSocket::EJobResult
SecureSocket::doWrite()
{
- static bool s_retry = false;
- static int s_retrySize = 0;
- static std::unique_ptr<char[]> s_staticBuffer;
- static std::size_t s_staticBufferSize = 0;
-
// write data
int bufferSize = 0;
int bytesWrote = 0;
@@ -224,34 +223,34 @@ SecureSocket::doWrite()
if (!isSecureReady())
return kRetry;
- if (s_retry) {
- bufferSize = s_retrySize;
+ if (do_write_retry_) {
+ bufferSize = do_write_retry_size_;
} else {
bufferSize = m_outputBuffer.getSize();
- if (bufferSize > s_staticBufferSize) {
- s_staticBuffer.reset(new char[bufferSize]);
- s_staticBufferSize = bufferSize;
+ if (bufferSize > do_write_retry_buffer_size_) {
+ do_write_retry_buffer_.reset(new char[bufferSize]);
+ do_write_retry_buffer_size_ = bufferSize;
}
if (bufferSize > 0) {
- memcpy(s_staticBuffer.get(), m_outputBuffer.peek(bufferSize), bufferSize);
+ std::memcpy(do_write_retry_buffer_.get(), m_outputBuffer.peek(bufferSize), bufferSize);
}
}
-
+
if (bufferSize == 0) {
return kRetry;
}
- status = secureWrite(s_staticBuffer.get(), bufferSize, bytesWrote);
+ status = secureWrite(do_write_retry_buffer_.get(), bufferSize, bytesWrote);
if (status > 0) {
- s_retry = false;
+ do_write_retry_ = false;
} else if (status < 0) {
return kBreak;
} else if (status == 0) {
- s_retry = true;
- s_retrySize = bufferSize;
+ do_write_retry_ = true;
+ do_write_retry_size_ = bufferSize;
return kNew;
}
-
+
if (bytesWrote > 0) {
discardWrittenData(bytesWrote);
return kNew;
@@ -263,16 +262,16 @@ SecureSocket::doWrite()
int
SecureSocket::secureRead(void* buffer, int size, int& read)
{
+ std::lock_guard<std::mutex> ssl_lock{ssl_mutex_};
+
if (m_ssl->m_ssl != NULL) {
LOG((CLOG_DEBUG2 "reading secure socket"));
read = SSL_read(m_ssl->m_ssl, buffer, size);
-
- static int retry;
// Check result will cleanup the connection in the case of a fatal
- checkResult(read, retry);
-
- if (retry) {
+ checkResult(read, secure_read_retry_);
+
+ if (secure_read_retry_) {
return 0;
}
@@ -289,17 +288,17 @@ SecureSocket::secureRead(void* buffer, int size, int& read)
int
SecureSocket::secureWrite(const void* buffer, int size, int& wrote)
{
+ std::lock_guard<std::mutex> ssl_lock{ssl_mutex_};
+
if (m_ssl->m_ssl != NULL) {
LOG((CLOG_DEBUG2 "writing secure socket:%p", this));
wrote = SSL_write(m_ssl->m_ssl, buffer, size);
-
- static int retry;
// Check result will cleanup the connection in the case of a fatal
- checkResult(wrote, retry);
+ checkResult(wrote, secure_write_retry_);
- if (retry) {
+ if (secure_write_retry_) {
return 0;
}
@@ -322,6 +321,8 @@ SecureSocket::isSecureReady()
void
SecureSocket::initSsl(bool server)
{
+ std::lock_guard<std::mutex> ssl_lock{ssl_mutex_};
+
m_ssl = new Ssl();
m_ssl->m_context = NULL;
m_ssl->m_ssl = NULL;
@@ -329,54 +330,57 @@ SecureSocket::initSsl(bool server)
initContext(server);
}
-bool SecureSocket::loadCertificates(std::string& filename)
+bool SecureSocket::load_certificates(const barrier::fs::path& path)
{
- if (filename.empty()) {
+ std::lock_guard<std::mutex> ssl_lock{ssl_mutex_};
+
+ if (path.empty()) {
showError("ssl certificate is not specified");
return false;
}
else {
- std::ifstream file(filename.c_str());
- bool exist = file.good();
- file.close();
-
- if (!exist) {
- std::string errorMsg("ssl certificate doesn't exist: ");
- errorMsg.append(filename);
- showError(errorMsg.c_str());
+ if (!barrier::fs::is_regular_file(path)) {
+ showError("ssl certificate doesn't exist: " + path.u8string());
return false;
}
}
int r = 0;
- r = SSL_CTX_use_certificate_file(m_ssl->m_context, filename.c_str(), SSL_FILETYPE_PEM);
+ r = SSL_CTX_use_certificate_file(m_ssl->m_context, path.u8string().c_str(), SSL_FILETYPE_PEM);
if (r <= 0) {
- showError("could not use ssl certificate");
+ showError("could not use ssl certificate: " + path.u8string());
return false;
}
- r = SSL_CTX_use_PrivateKey_file(m_ssl->m_context, filename.c_str(), SSL_FILETYPE_PEM);
+ r = SSL_CTX_use_PrivateKey_file(m_ssl->m_context, path.u8string().c_str(), SSL_FILETYPE_PEM);
if (r <= 0) {
- showError("could not use ssl private key");
+ showError("could not use ssl private key: " + path.u8string());
return false;
}
r = SSL_CTX_check_private_key(m_ssl->m_context);
if (!r) {
- showError("could not verify ssl private key");
+ showError("could not verify ssl private key: " + path.u8string());
return false;
}
return true;
}
+static int cert_verify_ignore_callback(X509_STORE_CTX*, void*)
+{
+ return 1;
+}
+
void
SecureSocket::initContext(bool server)
{
+ // ssl_mutex_ is assumed to be acquired
+
SSL_library_init();
const SSL_METHOD* method;
-
+
// load & register all cryptos, etc.
OpenSSL_add_all_algorithms();
@@ -394,7 +398,7 @@ SecureSocket::initContext(bool server)
else {
method = SSLv23_client_method();
}
-
+
// create new context from method
SSL_METHOD* m = const_cast<SSL_METHOD*>(method);
m_ssl->m_context = SSL_CTX_new(m);
@@ -403,13 +407,23 @@ SecureSocket::initContext(bool server)
SSL_CTX_set_options(m_ssl->m_context, SSL_OP_NO_SSLv3);
if (m_ssl->m_context == NULL) {
- showError();
+ showError("");
+ }
+
+ if (security_level_ == ConnectionSecurityLevel::ENCRYPTED_AUTHENTICATED) {
+ // We want to ask for peer certificate, but not verify it. If we don't ask for peer
+ // certificate, e.g. client won't send it.
+ SSL_CTX_set_verify(m_ssl->m_context, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+ nullptr);
+ SSL_CTX_set_cert_verify_callback(m_ssl->m_context, cert_verify_ignore_callback, nullptr);
}
}
void
SecureSocket::createSSL()
{
+ // ssl_mutex_ is assumed to be acquired
+
// I assume just one instance is needed
// get new SSL state with context
if (m_ssl->m_ssl == NULL) {
@@ -421,17 +435,17 @@ SecureSocket::createSSL()
int
SecureSocket::secureAccept(int socket)
{
+ std::lock_guard<std::mutex> ssl_lock{ssl_mutex_};
+
createSSL();
// set connection socket to SSL state
SSL_set_fd(m_ssl->m_ssl, socket);
-
+
LOG((CLOG_DEBUG2 "accepting secure socket"));
int r = SSL_accept(m_ssl->m_ssl);
-
- static int retry;
- checkResult(r, retry);
+ checkResult(r, secure_accept_retry_);
if (isFatal()) {
// tell user and sleep so the socket isn't hammered.
@@ -439,12 +453,30 @@ SecureSocket::secureAccept(int socket)
LOG((CLOG_INFO "client connection may not be secure"));
m_secureReady = false;
ARCH->sleep(1);
- retry = 0;
+ secure_accept_retry_ = 0;
return -1; // Failed, error out
}
// If not fatal and no retry, state is good
- if (retry == 0) {
+ if (secure_accept_retry_ == 0) {
+ if (security_level_ == ConnectionSecurityLevel::ENCRYPTED_AUTHENTICATED) {
+ if (verify_cert_fingerprint(
+ barrier::DataDirectories::trusted_clients_ssl_fingerprints_path())) {
+ LOG((CLOG_INFO "accepted secure socket"));
+ if (!ensure_peer_certificate()) {
+ secure_accept_retry_ = 0;
+ disconnect();
+ return -1;// Cert fail, error
+ }
+ }
+ else {
+ LOG((CLOG_ERR "failed to verify server certificate fingerprint"));
+ secure_accept_retry_ = 0;
+ disconnect();
+ return -1; // Fingerprint failed, error
+ }
+ }
+
m_secureReady = true;
LOG((CLOG_INFO "accepted secure socket"));
if (CLOG->getFilter() >= kDEBUG1) {
@@ -455,7 +487,7 @@ SecureSocket::secureAccept(int socket)
}
// If not fatal and retry is set, not ready, and return retry
- if (retry > 0) {
+ if (secure_accept_retry_ > 0) {
LOG((CLOG_DEBUG2 "retry accepting secure socket"));
m_secureReady = false;
ARCH->sleep(s_retryDelay);
@@ -470,38 +502,45 @@ SecureSocket::secureAccept(int socket)
int
SecureSocket::secureConnect(int socket)
{
+ // note that load_certificates acquires ssl_mutex_
+ if (!load_certificates(barrier::DataDirectories::ssl_certificate_path())) {
+ LOG((CLOG_ERR "could not load client certificates"));
+ // FIXME: this is fatal error, but we current don't disconnect because whole logic in this
+ // function needs to be cleaned up
+ }
+
+ std::lock_guard<std::mutex> ssl_lock{ssl_mutex_};
+
createSSL();
// attach the socket descriptor
SSL_set_fd(m_ssl->m_ssl, socket);
-
+
LOG((CLOG_DEBUG2 "connecting secure socket"));
int r = SSL_connect(m_ssl->m_ssl);
-
- static int retry;
- checkResult(r, retry);
+ checkResult(r, secure_connect_retry_);
if (isFatal()) {
LOG((CLOG_ERR "failed to connect secure socket"));
- retry = 0;
+ secure_connect_retry_ = 0;
return -1;
}
// If we should retry, not ready and return 0
- if (retry > 0) {
+ if (secure_connect_retry_ > 0) {
LOG((CLOG_DEBUG2 "retry connect secure socket"));
m_secureReady = false;
ARCH->sleep(s_retryDelay);
return 0;
}
- retry = 0;
+ secure_connect_retry_ = 0;
// No error, set ready, process and return ok
m_secureReady = true;
- if (verifyCertFingerprint()) {
+ if (verify_cert_fingerprint(barrier::DataDirectories::trusted_servers_ssl_fingerprints_path())) {
LOG((CLOG_INFO "connected to secure socket"));
- if (!showCertificate()) {
+ if (!ensure_peer_certificate()) {
disconnect();
return -1;// Cert fail, error
}
@@ -520,21 +559,22 @@ SecureSocket::secureConnect(int socket)
}
bool
-SecureSocket::showCertificate()
+SecureSocket::ensure_peer_certificate()
{
+ // ssl_mutex_ is assumed to be acquired
X509* cert;
char* line;
-
+
// get the server's certificate
cert = SSL_get_peer_certificate(m_ssl->m_ssl);
if (cert != NULL) {
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
- LOG((CLOG_INFO "server ssl certificate info: %s", line));
+ LOG((CLOG_INFO "peer ssl certificate info: %s", line));
OPENSSL_free(line);
X509_free(cert);
}
else {
- showError("server has no ssl certificate");
+ showError("peer has no ssl certificate");
return false;
}
@@ -544,6 +584,8 @@ SecureSocket::showCertificate()
void
SecureSocket::checkResult(int status, int& retry)
{
+ // ssl_mutex_ is assumed to be acquired
+
// ssl errors are a little quirky. the "want" errors are normal and
// should result in a retry.
@@ -568,7 +610,7 @@ SecureSocket::checkResult(int status, int& retry)
case SSL_ERROR_WANT_WRITE:
// Need to make sure the socket is known to be writable so the impending
- // select action actually triggers on a write. This isn't necessary for
+ // select action actually triggers on a write. This isn't necessary for
// m_readable because the socket logic is always readable
m_writable = true;
retry++;
@@ -618,16 +660,15 @@ SecureSocket::checkResult(int status, int& retry)
if (isFatal()) {
retry = 0;
- showError();
+ showError("");
disconnect();
}
}
-void
-SecureSocket::showError(const char* reason)
+void SecureSocket::showError(const std::string& reason)
{
- if (reason != NULL) {
- LOG((CLOG_ERR "%s", reason));
+ if (!reason.empty()) {
+ LOG((CLOG_ERR "%s", reason.c_str()));
}
std::string error = getError();
@@ -658,83 +699,49 @@ SecureSocket::disconnect()
sendEvent(getEvents()->forIStream().inputShutdown());
}
-void SecureSocket::formatFingerprint(std::string& fingerprint, bool hex, bool separator)
+bool SecureSocket::verify_cert_fingerprint(const barrier::fs::path& fingerprint_db_path)
{
- if (hex) {
- // to hexidecimal
- barrier::string::toHex(fingerprint, 2);
- }
-
- // all uppercase
- barrier::string::uppercase(fingerprint);
+ // ssl_mutex_ is assumed to be acquired
- if (separator) {
- // add colon to separate each 2 charactors
- size_t separators = fingerprint.size() / 2;
- for (size_t i = 1; i < separators; i++) {
- fingerprint.insert(i * 3 - 1, ":");
- }
- }
-}
-
-bool
-SecureSocket::verifyCertFingerprint()
-{
// calculate received certificate fingerprint
- X509 *cert = cert = SSL_get_peer_certificate(m_ssl->m_ssl);
- EVP_MD* tempDigest;
- unsigned char tempFingerprint[EVP_MAX_MD_SIZE];
- unsigned int tempFingerprintLen;
- tempDigest = (EVP_MD*)EVP_sha1();
- int digestResult = X509_digest(cert, tempDigest, tempFingerprint, &tempFingerprintLen);
-
- if (digestResult <= 0) {
- LOG((CLOG_ERR "failed to calculate fingerprint, digest result: %d", digestResult));
+ barrier::FingerprintData fingerprint_sha1, fingerprint_sha256;
+ try {
+ auto* cert = SSL_get_peer_certificate(m_ssl->m_ssl);
+ fingerprint_sha1 = barrier::get_ssl_cert_fingerprint(cert,
+ barrier::FingerprintType::SHA1);
+ fingerprint_sha256 = barrier::get_ssl_cert_fingerprint(cert,
+ barrier::FingerprintType::SHA256);
+ } catch (const std::exception& e) {
+ LOG((CLOG_ERR "%s", e.what()));
return false;
}
- // format fingerprint into hexdecimal format with colon separator
- std::string fingerprint(reinterpret_cast<char*>(tempFingerprint), tempFingerprintLen);
- formatFingerprint(fingerprint);
- LOG((CLOG_NOTE "server fingerprint: %s", fingerprint.c_str()));
-
- std::string trustedServersFilename;
- trustedServersFilename = barrier::string::sprintf(
- "%s/%s/%s",
- DataDirectories::profile().c_str(),
- kFingerprintDirName,
- kFingerprintTrustedServersFilename);
+ // note: the GUI parses the following two lines of logs, don't change unnecessarily
+ LOG((CLOG_NOTE "peer fingerprint (SHA1): %s (SHA256): %s",
+ barrier::format_ssl_fingerprint(fingerprint_sha1.data).c_str(),
+ barrier::format_ssl_fingerprint(fingerprint_sha256.data).c_str()));
// Provide debug hint as to what file is being used to verify fingerprint trust
- LOG((CLOG_NOTE "trustedServersFilename: %s", trustedServersFilename.c_str() ));
+ LOG((CLOG_NOTE "fingerprint_db_path: %s", fingerprint_db_path.u8string().c_str()));
- // check if this fingerprint exist
- std::string fileLine;
- std::ifstream file;
- file.open(trustedServersFilename.c_str());
+ barrier::FingerprintDatabase db;
+ db.read(fingerprint_db_path);
- if (!file.is_open()) {
- LOG((CLOG_NOTE "Unable to open trustedServersFile: %s", trustedServersFilename.c_str() ));
+ if (!db.fingerprints().empty()) {
+ LOG((CLOG_NOTE "Read %d fingerprints from: %s", db.fingerprints().size(),
+ fingerprint_db_path.u8string().c_str()));
} else {
- LOG((CLOG_NOTE "Opened trustedServersFilename: %s", trustedServersFilename.c_str() ));
+ LOG((CLOG_NOTE "Could not read fingerprints from: %s",
+ fingerprint_db_path.u8string().c_str()));
}
- bool isValid = false;
- while (!file.eof() && file.is_open()) {
- getline(file,fileLine);
- if (!fileLine.empty()) {
- if (fileLine.compare(fingerprint) == 0) {
- LOG((CLOG_NOTE "Fingerprint matches trusted fingerprint"));
- isValid = true;
- break;
- } else {
- LOG((CLOG_NOTE "Fingerprint does not match trusted fingerprint"));
- }
- }
+ if (db.is_trusted(fingerprint_sha256)) {
+ LOG((CLOG_NOTE "Fingerprint matches trusted fingerprint"));
+ return true;
+ } else {
+ LOG((CLOG_NOTE "Fingerprint does not match trusted fingerprint"));
+ return false;
}
-
- file.close();
- return isValid;
}
MultiplexerJobStatus SecureSocket::serviceConnect(ISocketMultiplexerJob* job,
@@ -765,9 +772,9 @@ MultiplexerJobStatus SecureSocket::serviceConnect(ISocketMultiplexerJob* job,
// Retry case
return {
true,
- std::make_unique<TSocketMultiplexerMethodJob<SecureSocket>>(
- this, &SecureSocket::serviceConnect,
- getSocket(), isReadable(), isWritable())
+ std::make_unique<TSocketMultiplexerMethodJob>([this](auto j, auto r, auto w, auto e)
+ { return serviceConnect(j, r, w, e); },
+ getSocket(), isReadable(), isWritable())
};
}
@@ -795,9 +802,12 @@ MultiplexerJobStatus SecureSocket::serviceAccept(ISocketMultiplexerJob* job,
}
// Retry case
- return {true, std::make_unique<TSocketMultiplexerMethodJob<SecureSocket>>(
- this, &SecureSocket::serviceAccept,
- getSocket(), isReadable(), isWritable())};
+ return {
+ true,
+ std::make_unique<TSocketMultiplexerMethodJob>([this](auto j, auto r, auto w, auto e)
+ { return serviceAccept(j, r, w, e); },
+ getSocket(), isReadable(), isWritable())
+ };
}
void
@@ -822,6 +832,8 @@ showCipherStackDesc(STACK_OF(SSL_CIPHER) * stack) {
void
SecureSocket::showSecureCipherInfo()
{
+ // ssl_mutex_ is assumed to be acquired
+
STACK_OF(SSL_CIPHER) * sStack = SSL_get_ciphers(m_ssl->m_ssl);
if (sStack == NULL) {
@@ -832,8 +844,8 @@ SecureSocket::showSecureCipherInfo()
showCipherStackDesc(sStack);
}
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
- // m_ssl->m_ssl->session->ciphers is not forward compatable,
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ // m_ssl->m_ssl->session->ciphers is not forward compatible,
// In future release of OpenSSL, it's not visible,
STACK_OF(SSL_CIPHER) * cStack = m_ssl->m_ssl->session->ciphers;
#else
@@ -864,6 +876,8 @@ SecureSocket::showSecureLibInfo()
void
SecureSocket::showSecureConnectInfo()
{
+ // ssl_mutex_ is assumed to be acquired
+
const SSL_CIPHER* cipher = SSL_get_current_cipher(m_ssl->m_ssl);
if (cipher != NULL) {
diff --git a/src/lib/net/SecureSocket.h b/src/lib/net/SecureSocket.h
index c602e2d..be7dc0d 100644
--- a/src/lib/net/SecureSocket.h
+++ b/src/lib/net/SecureSocket.h
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2015-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -17,8 +17,11 @@
#pragma once
+#include "ConnectionSecurityLevel.h"
#include "net/TCPSocket.h"
#include "net/XSocket.h"
+#include "io/filesystem.h"
+#include <mutex>
class IEventQueue;
class SocketMultiplexer;
@@ -32,10 +35,10 @@ A secure socket using SSL.
*/
class SecureSocket : public TCPSocket {
public:
- SecureSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer, IArchNetwork::EAddressFamily family);
- SecureSocket(IEventQueue* events,
- SocketMultiplexer* socketMultiplexer,
- ArchSocket socket);
+ SecureSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer,
+ IArchNetwork::EAddressFamily family, ConnectionSecurityLevel security_level);
+ SecureSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer,
+ ArchSocket socket, ConnectionSecurityLevel security_level);
~SecureSocket();
// ISocket overrides
@@ -43,7 +46,7 @@ public:
// IDataSocket overrides
virtual void connect(const NetworkAddress&) override;
-
+
std::unique_ptr<ISocketMultiplexerJob> newJob() override;
bool isFatal() const override { return m_fatal; }
void isFatal(bool b) { m_fatal = b; }
@@ -55,35 +58,56 @@ public:
EJobResult doRead() override;
EJobResult doWrite() override;
void initSsl(bool server);
- bool loadCertificates(std::string& CertFile);
+ bool load_certificates(const barrier::fs::path& path);
private:
// SSL
- void initContext(bool server);
- void createSSL();
+ void initContext(bool server); // may only be called with ssl_mutex_ acquired
+ void createSSL(); // may only be called with ssl_mutex_ acquired.
int secureAccept(int s);
int secureConnect(int s);
- bool showCertificate();
- void checkResult(int n, int& retry);
- void showError(const char* reason = NULL);
+ bool ensure_peer_certificate(); // may only be called with ssl_mutex_ acquired
+
+ void checkResult(int n, int& retry); // may only be called with m_ssl_mutex_ acquired.
+
+ void showError(const std::string& reason);
std::string getError();
void disconnect();
- void formatFingerprint(std::string& fingerprint, bool hex = true, bool separator = true);
- bool verifyCertFingerprint();
+
+ // may only be called with ssl_mutex_ acquired
+ bool verify_cert_fingerprint(const barrier::fs::path& fingerprint_db_path);
MultiplexerJobStatus serviceConnect(ISocketMultiplexerJob*, bool, bool, bool);
MultiplexerJobStatus serviceAccept(ISocketMultiplexerJob*, bool, bool, bool);
- void showSecureConnectInfo();
- void showSecureLibInfo();
- void showSecureCipherInfo();
-
+ void showSecureConnectInfo(); // may only be called with ssl_mutex_ acquired
+ void showSecureLibInfo();
+ void showSecureCipherInfo(); // may only be called with ssl_mutex_ acquired
+
void handleTCPConnected(const Event& event, void*);
void freeSSLResources();
private:
+ // all accesses to m_ssl must be protected by this mutex. The only function that is called
+ // from outside SocketMultiplexer thread is close(), so we mostly care about things accessed
+ // by it.
+ std::mutex ssl_mutex_;
+
Ssl* m_ssl;
bool m_secureReady;
bool m_fatal;
+ ConnectionSecurityLevel security_level_ = ConnectionSecurityLevel::ENCRYPTED;
+
+ int secure_accept_retry_ = 0; // used only in secureAccept()
+ int secure_connect_retry_ = 0; // used only in secureConnect()
+ int secure_read_retry_ = 0; // used only in secureRead()
+ int secure_write_retry_ = 0; // used only in secureWrite()
+
+ // The following are used only from doWrite()
+ // FIXME: using std::vector would simplify logic significantly.
+ bool do_write_retry_ = false;
+ int do_write_retry_size_ = 0;
+ std::unique_ptr<char[]> do_write_retry_buffer_;
+ std::size_t do_write_retry_buffer_size_ = 0;
};
diff --git a/src/lib/net/SecureUtils.cpp b/src/lib/net/SecureUtils.cpp
new file mode 100644
index 0000000..c581dd4
--- /dev/null
+++ b/src/lib/net/SecureUtils.cpp
@@ -0,0 +1,312 @@
+/*
+ barrier -- mouse and keyboard sharing utility
+ Copyright (C) Barrier contributors
+
+ This package is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ found in the file LICENSE that should have accompanied this file.
+
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ -----------------------------------------------------------------------
+ create_fingerprint_randomart() has been taken from the OpenSSH project.
+ Copyright information follows.
+
+ Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
+ Copyright (c) 2008 Alexander von Gernler. All rights reserved.
+ Copyright (c) 2010,2011 Damien Miller. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "SecureUtils.h"
+#include "base/String.h"
+#include "base/finally.h"
+#include "io/filesystem.h"
+
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/pem.h>
+#include <algorithm>
+#include <cstdio>
+#include <cstring>
+#include <stdexcept>
+
+#if SYSAPI_WIN32
+// Windows builds require a shim that makes it possible to link to different
+// versions of the Win32 C runtime. See OpenSSL FAQ.
+#include <openssl/applink.c>
+#endif
+
+namespace barrier {
+
+namespace {
+
+const EVP_MD* get_digest_for_type(FingerprintType type)
+{
+ switch (type) {
+ case FingerprintType::SHA1: return EVP_sha1();
+ case FingerprintType::SHA256: return EVP_sha256();
+ }
+ throw std::runtime_error("Unknown fingerprint type " + std::to_string(static_cast<int>(type)));
+}
+
+} // namespace
+
+std::string format_ssl_fingerprint(const std::vector<uint8_t>& fingerprint, bool separator)
+{
+ std::string result = barrier::string::to_hex(fingerprint, 2);
+
+ // all uppercase
+ barrier::string::uppercase(result);
+
+ if (separator) {
+ // add colon to separate each 2 characters
+ size_t separators = result.size() / 2;
+ for (size_t i = 1; i < separators; i++) {
+ result.insert(i * 3 - 1, ":");
+ }
+ }
+ return result;
+}
+
+std::string format_ssl_fingerprint_columns(const std::vector<uint8_t>& fingerprint)
+{
+ auto max_columns = 8;
+
+ std::string hex = barrier::string::to_hex(fingerprint, 2);
+ barrier::string::uppercase(hex);
+ if (hex.empty() || hex.size() % 2 != 0) {
+ return hex;
+ }
+
+ std::string separated;
+ for (std::size_t i = 0; i < hex.size(); i += max_columns * 2) {
+ for (std::size_t j = i; j < i + 16 && j < hex.size() - 1; j += 2) {
+ separated.push_back(hex[j]);
+ separated.push_back(hex[j + 1]);
+ separated.push_back(':');
+ }
+ separated.push_back('\n');
+ }
+ separated.pop_back(); // we don't need last newline character
+ return separated;
+}
+
+FingerprintData get_ssl_cert_fingerprint(X509* cert, FingerprintType type)
+{
+ if (!cert) {
+ throw std::runtime_error("certificate is null");
+ }
+
+ unsigned char digest[EVP_MAX_MD_SIZE];
+ unsigned int digest_length = 0;
+ int result = X509_digest(cert, get_digest_for_type(type), digest, &digest_length);
+
+ if (result <= 0) {
+ throw std::runtime_error("failed to calculate fingerprint, digest result: " +
+ std::to_string(result));
+ }
+
+ std::vector<std::uint8_t> digest_vec;
+ digest_vec.assign(reinterpret_cast<std::uint8_t*>(digest),
+ reinterpret_cast<std::uint8_t*>(digest) + digest_length);
+ return {fingerprint_type_to_string(type), digest_vec};
+}
+
+FingerprintData get_pem_file_cert_fingerprint(const std::string& path, FingerprintType type)
+{
+ auto fp = fopen_utf8_path(path, "r");
+ if (!fp) {
+ throw std::runtime_error("Could not open certificate path");
+ }
+ auto file_close = finally([fp]() { std::fclose(fp); });
+
+ X509* cert = PEM_read_X509(fp, nullptr, nullptr, nullptr);
+ if (!cert) {
+ throw std::runtime_error("Certificate could not be parsed");
+ }
+ auto cert_free = finally([cert]() { X509_free(cert); });
+
+ return get_ssl_cert_fingerprint(cert, type);
+}
+
+void generate_pem_self_signed_cert(const std::string& path)
+{
+ auto expiration_days = 365;
+
+ auto* private_key = EVP_PKEY_new();
+ if (!private_key) {
+ throw std::runtime_error("Could not allocate private key for certificate");
+ }
+ auto private_key_free = finally([private_key](){ EVP_PKEY_free(private_key); });
+
+ auto* rsa = RSA_generate_key(2048, RSA_F4, nullptr, nullptr);
+ if (!rsa) {
+ throw std::runtime_error("Failed to generate RSA key");
+ }
+ EVP_PKEY_assign_RSA(private_key, rsa);
+
+ auto* cert = X509_new();
+ if (!cert) {
+ throw std::runtime_error("Could not allocate certificate");
+ }
+ auto cert_free = finally([cert]() { X509_free(cert); });
+
+ ASN1_INTEGER_set(X509_get_serialNumber(cert), 1);
+ X509_gmtime_adj(X509_get_notBefore(cert), 0);
+ X509_gmtime_adj(X509_get_notAfter(cert), expiration_days * 24 * 3600);
+ X509_set_pubkey(cert, private_key);
+
+ auto* name = X509_get_subject_name(cert);
+ X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
+ reinterpret_cast<const unsigned char *>("Barrier"), -1, -1, 0);
+ X509_set_issuer_name(cert, name);
+
+ X509_sign(cert, private_key, EVP_sha256());
+
+ auto fp = fopen_utf8_path(path.c_str(), "r");
+ if (!fp) {
+ throw std::runtime_error("Could not open certificate output path");
+ }
+ auto file_close = finally([fp]() { std::fclose(fp); });
+
+ PEM_write_PrivateKey(fp, private_key, nullptr, nullptr, 0, nullptr, nullptr);
+ PEM_write_X509(fp, cert);
+}
+
+/*
+ Draw an ASCII-Art representing the fingerprint so human brain can
+ profit from its built-in pattern recognition ability.
+ This technique is called "random art" and can be found in some
+ scientific publications like this original paper:
+
+ "Hash Visualization: a New Technique to improve Real-World Security",
+ Perrig A. and Song D., 1999, International Workshop on Cryptographic
+ Techniques and E-Commerce (CrypTEC '99)
+ sparrow.ece.cmu.edu/~adrian/projects/validation/validation.pdf
+
+ The subject came up in a talk by Dan Kaminsky, too.
+
+ If you see the picture is different, the key is different.
+ If the picture looks the same, you still know nothing.
+
+ The algorithm used here is a worm crawling over a discrete plane,
+ leaving a trace (augmenting the field) everywhere it goes.
+ Movement is taken from dgst_raw 2bit-wise. Bumping into walls
+ makes the respective movement vector be ignored for this turn.
+ Graphs are not unambiguous, because circles in graphs can be
+walked in either direction.
+ */
+
+/*
+ Field sizes for the random art. Have to be odd, so the starting point
+ can be in the exact middle of the picture, and FLDBASE should be >=8 .
+ Else pictures would be too dense, and drawing the frame would
+ fail, too, because the key type would not fit in anymore.
+*/
+#define FLDBASE 8
+#define FLDSIZE_Y (FLDBASE + 1)
+#define FLDSIZE_X (FLDBASE * 2 + 1)
+
+std::string create_fingerprint_randomart(const std::vector<std::uint8_t>& dgst_raw)
+{
+ /*
+ * Chars to be used after each other every time the worm
+ * intersects with itself. Matter of taste.
+ */
+ const char* augmentation_string = " .o+=*BOX@%&#/^SE";
+ char *p;
+ std::uint8_t field[FLDSIZE_X][FLDSIZE_Y];
+ std::size_t i;
+ std::uint32_t b;
+ int x, y;
+ std::size_t len = strlen(augmentation_string) - 1;
+
+ std::vector<char> retval;
+ retval.reserve((FLDSIZE_X + 3) * (FLDSIZE_Y + 2));
+
+ auto add_char = [&retval](char ch) { retval.push_back(ch); };
+
+ /* initialize field */
+ std::memset(field, 0, FLDSIZE_X * FLDSIZE_Y * sizeof(char));
+ x = FLDSIZE_X / 2;
+ y = FLDSIZE_Y / 2;
+
+ /* process raw key */
+ for (i = 0; i < dgst_raw.size(); i++) {
+ /* each byte conveys four 2-bit move commands */
+ int input = dgst_raw[i];
+ for (b = 0; b < 4; b++) {
+ /* evaluate 2 bit, rest is shifted later */
+ x += (input & 0x1) ? 1 : -1;
+ y += (input & 0x2) ? 1 : -1;
+
+ /* assure we are still in bounds */
+ x = std::max(x, 0);
+ y = std::max(y, 0);
+ x = std::min(x, FLDSIZE_X - 1);
+ y = std::min(y, FLDSIZE_Y - 1);
+
+ /* augment the field */
+ if (field[x][y] < len - 2)
+ field[x][y]++;
+ input = input >> 2;
+ }
+ }
+
+ /* mark starting point and end point*/
+ field[FLDSIZE_X / 2][FLDSIZE_Y / 2] = len - 1;
+ field[x][y] = len;
+
+ /* output upper border */
+ add_char('+');
+ for (i = 0; i < FLDSIZE_X; i++)
+ add_char('-');
+ add_char('+');
+ add_char('\n');
+
+ /* output content */
+ for (y = 0; y < FLDSIZE_Y; y++) {
+ add_char('|');
+ for (x = 0; x < FLDSIZE_X; x++)
+ add_char(augmentation_string[std::min<int>(field[x][y], len)]);
+ add_char('|');
+ add_char('\n');
+ }
+
+ /* output lower border */
+ add_char('+');
+ for (i = 0; i < FLDSIZE_X; i++)
+ add_char('-');
+ add_char('+');
+
+ return std::string{retval.data(), retval.size()};
+}
+
+} // namespace barrier
diff --git a/src/lib/net/SecureUtils.h b/src/lib/net/SecureUtils.h
new file mode 100644
index 0000000..c4d51f3
--- /dev/null
+++ b/src/lib/net/SecureUtils.h
@@ -0,0 +1,43 @@
+/*
+ barrier -- mouse and keyboard sharing utility
+ Copyright (C) Barrier contributors
+
+ This package is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ found in the file LICENSE that should have accompanied this file.
+
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef BARRIER_LIB_NET_SECUREUTILS_H
+#define BARRIER_LIB_NET_SECUREUTILS_H
+
+#include "FingerprintData.h"
+#include <openssl/ossl_typ.h>
+#include <cstdint>
+#include <string>
+#include <vector>
+
+namespace barrier {
+
+std::string format_ssl_fingerprint(const std::vector<std::uint8_t>& fingerprint,
+ bool separator = true);
+std::string format_ssl_fingerprint_columns(const std::vector<uint8_t>& fingerprint);
+
+FingerprintData get_ssl_cert_fingerprint(X509* cert, FingerprintType type);
+
+FingerprintData get_pem_file_cert_fingerprint(const std::string& path, FingerprintType type);
+
+void generate_pem_self_signed_cert(const std::string& path);
+
+std::string create_fingerprint_randomart(const std::vector<std::uint8_t>& dgst_raw);
+
+} // namespace barrier
+
+#endif // BARRIER_LIB_NET_SECUREUTILS_H
diff --git a/src/lib/net/SocketMultiplexer.cpp b/src/lib/net/SocketMultiplexer.cpp
index cdb9039..5a2328e 100644
--- a/src/lib/net/SocketMultiplexer.cpp
+++ b/src/lib/net/SocketMultiplexer.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -26,7 +26,6 @@
#include "arch/Arch.h"
#include "arch/XArch.h"
#include "base/Log.h"
-#include "base/TMethodJob.h"
#include "common/stdvector.h"
//
@@ -58,8 +57,7 @@ SocketMultiplexer::SocketMultiplexer() :
m_jobListLockLocker(NULL)
{
// start thread
- m_thread = new Thread(new TMethodJob<SocketMultiplexer>(
- this, &SocketMultiplexer::serviceThread));
+ m_thread = new Thread([this](){ service_thread(); });
}
SocketMultiplexer::~SocketMultiplexer()
@@ -95,7 +93,7 @@ void SocketMultiplexer::addSocket(ISocket* socket, std::unique_ptr<ISocketMultip
if (i == m_socketJobMap.end()) {
// we *must* put the job at the end so the order of jobs in
// the list continue to match the order of jobs in pfds in
- // serviceThread().
+ // service_thread().
JobCursor j = m_socketJobs.insert(m_socketJobs.end(), std::move(job));
m_update = true;
m_socketJobMap.insert(std::make_pair(socket, j));
@@ -125,7 +123,7 @@ SocketMultiplexer::removeSocket(ISocket* socket)
// remove job. rather than removing it from the map we put NULL
// in the list instead so the order of jobs in the list continues
- // to match the order of jobs in pfds in serviceThread().
+ // to match the order of jobs in pfds in service_thread().
SocketJobMap::iterator i = m_socketJobMap.find(socket);
if (i != m_socketJobMap.end()) {
if (*(i->second)) {
@@ -138,8 +136,7 @@ SocketMultiplexer::removeSocket(ISocket* socket)
unlockJobList();
}
-void
-SocketMultiplexer::serviceThread(void*)
+void SocketMultiplexer::service_thread()
{
std::vector<IArchNetwork::PollEntry> pfds;
IArchNetwork::PollEntry pfd;
@@ -179,7 +176,7 @@ SocketMultiplexer::serviceThread(void*)
pfd.m_events |= IArchNetwork::kPOLLOUT;
}
pfds.push_back(pfd);
- }
+ }
jobCursor = nextCursor(cursor);
}
deleteCursor(cursor);
diff --git a/src/lib/net/SocketMultiplexer.h b/src/lib/net/SocketMultiplexer.h
index 9891558..b13c725 100644
--- a/src/lib/net/SocketMultiplexer.h
+++ b/src/lib/net/SocketMultiplexer.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -67,7 +67,7 @@ private:
// and m_update while m_pollable and m_polling are true. all other
// threads must only modify these when m_pollable and m_polling are
// false. only the service thread sets m_polling.
- void serviceThread(void*);
+ void service_thread();
// create, iterate, and destroy a cursor. a cursor is used to
// safely iterate through the job list while other threads modify
diff --git a/src/lib/net/TCPListenSocket.cpp b/src/lib/net/TCPListenSocket.cpp
index 26f03b0..2c305fc 100644
--- a/src/lib/net/TCPListenSocket.cpp
+++ b/src/lib/net/TCPListenSocket.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -70,8 +70,10 @@ TCPListenSocket::bind(const NetworkAddress& addr)
ARCH->bindSocket(m_socket, addr.getAddress());
ARCH->listenOnSocket(m_socket);
- auto new_job = std::make_unique<TSocketMultiplexerMethodJob<TCPListenSocket>>(
- this, &TCPListenSocket::serviceListening, m_socket, true, false);
+ auto new_job = std::make_unique<TSocketMultiplexerMethodJob>(
+ [this](auto j, auto r, auto w, auto e)
+ { return serviceListening(j, r, w, e); },
+ m_socket, true, false);
m_socketMultiplexer->addSocket(this, std::move(new_job));
}
@@ -136,8 +138,10 @@ TCPListenSocket::accept()
void
TCPListenSocket::setListeningJob()
{
- auto new_job = std::make_unique<TSocketMultiplexerMethodJob<TCPListenSocket>>(
- this, &TCPListenSocket::serviceListening, m_socket, true, false);
+ auto new_job = std::make_unique<TSocketMultiplexerMethodJob>(
+ [this](auto j, auto r, auto w, auto e)
+ { return serviceListening(j, r, w, e); },
+ m_socket, true, false);
m_socketMultiplexer->addSocket(this, std::move(new_job));
}
diff --git a/src/lib/net/TCPListenSocket.h b/src/lib/net/TCPListenSocket.h
index f3ababc..109c1c3 100644
--- a/src/lib/net/TCPListenSocket.h
+++ b/src/lib/net/TCPListenSocket.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/net/TCPSocket.cpp b/src/lib/net/TCPSocket.cpp
index 09a8f17..fa7edcc 100644
--- a/src/lib/net/TCPSocket.cpp
+++ b/src/lib/net/TCPSocket.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -33,9 +33,7 @@
#include <cstdlib>
#include <memory>
-//
-// TCPSocket
-//
+static const std::size_t MAX_INPUT_BUFFER_SIZE = 1024 * 1024;
TCPSocket::TCPSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer, IArchNetwork::EAddressFamily family) :
IDataSocket(events),
@@ -335,19 +333,23 @@ TCPSocket::doRead()
UInt8 buffer[4096];
memset(buffer, 0, sizeof(buffer));
size_t bytesRead = 0;
-
+
bytesRead = ARCH->readSocket(m_socket, buffer, sizeof(buffer));
-
+
if (bytesRead > 0) {
bool wasEmpty = (m_inputBuffer.getSize() == 0);
-
+
// slurp up as much as possible
do {
m_inputBuffer.write(buffer, (UInt32)bytesRead);
+ if (m_inputBuffer.getSize() > MAX_INPUT_BUFFER_SIZE) {
+ break;
+ }
+
bytesRead = ARCH->readSocket(m_socket, buffer, sizeof(buffer));
} while (bytesRead > 0);
-
+
// send input ready if input buffer was empty
if (wasEmpty) {
sendEvent(m_events->forIStream().inputReady());
@@ -365,7 +367,7 @@ TCPSocket::doRead()
m_readable = false;
return kNew;
}
-
+
return kRetry;
}
@@ -384,7 +386,7 @@ TCPSocket::doWrite()
discardWrittenData(bytesWrote);
return kNew;
}
-
+
return kRetry;
}
@@ -424,18 +426,20 @@ std::unique_ptr<ISocketMultiplexerJob> TCPSocket::newJob()
if (!(m_readable || m_writable)) {
return {};
}
- return std::make_unique<TSocketMultiplexerMethodJob<TCPSocket>>(
- this, &TCPSocket::serviceConnecting,
- m_socket, m_readable, m_writable);
+ return std::make_unique<TSocketMultiplexerMethodJob>(
+ [this](auto j, auto r, auto w, auto e)
+ { return serviceConnecting(j, r, w, e); },
+ m_socket, m_readable, m_writable);
}
else {
- if (!(m_readable || (m_writable && (m_outputBuffer.getSize() > 0)))) {
+ auto writable = m_writable && (m_outputBuffer.getSize() > 0);
+ if (!(m_readable || writable)) {
return {};
}
- return std::make_unique<TSocketMultiplexerMethodJob<TCPSocket>>(
- this, &TCPSocket::serviceConnected,
- m_socket, m_readable,
- m_writable && (m_outputBuffer.getSize() > 0));
+ return std::make_unique<TSocketMultiplexerMethodJob>(
+ [this](auto j, auto r, auto w, auto e)
+ { return serviceConnected(j, r, w, e); },
+ m_socket, m_readable, writable);
}
}
diff --git a/src/lib/net/TCPSocket.h b/src/lib/net/TCPSocket.h
index 0b98888..45aed07 100644
--- a/src/lib/net/TCPSocket.h
+++ b/src/lib/net/TCPSocket.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -59,7 +59,7 @@ public:
// IDataSocket overrides
virtual void connect(const NetworkAddress&);
-
+
virtual std::unique_ptr<ISocketMultiplexerJob> newJob();
protected:
@@ -68,7 +68,7 @@ protected:
kRetry, //!< Retry the same job
kNew //!< Require a new job
};
-
+
ArchSocket getSocket() { return m_socket; }
IEventQueue* getEvents() { return m_events; }
virtual EJobResult doRead();
@@ -105,7 +105,7 @@ protected:
IEventQueue* m_events;
StreamBuffer m_inputBuffer;
StreamBuffer m_outputBuffer;
-
+
private:
Mutex m_mutex;
ArchSocket m_socket;
diff --git a/src/lib/net/TCPSocketFactory.cpp b/src/lib/net/TCPSocketFactory.cpp
index 6ff4ef8..30e930e 100644
--- a/src/lib/net/TCPSocketFactory.cpp
+++ b/src/lib/net/TCPSocketFactory.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -40,11 +40,12 @@ TCPSocketFactory::~TCPSocketFactory()
// do nothing
}
-IDataSocket*
-TCPSocketFactory::create(IArchNetwork::EAddressFamily family, bool secure) const
+IDataSocket* TCPSocketFactory::create(IArchNetwork::EAddressFamily family,
+ ConnectionSecurityLevel security_level) const
{
- if (secure) {
- SecureSocket* secureSocket = new SecureSocket(m_events, m_socketMultiplexer, family);
+ if (security_level != ConnectionSecurityLevel::PLAINTEXT) {
+ SecureSocket* secureSocket = new SecureSocket(m_events, m_socketMultiplexer, family,
+ security_level);
secureSocket->initSsl (false);
return secureSocket;
}
@@ -53,12 +54,12 @@ TCPSocketFactory::create(IArchNetwork::EAddressFamily family, bool secure) const
}
}
-IListenSocket*
-TCPSocketFactory::createListen(IArchNetwork::EAddressFamily family, bool secure) const
+IListenSocket* TCPSocketFactory::createListen(IArchNetwork::EAddressFamily family,
+ ConnectionSecurityLevel security_level) const
{
IListenSocket* socket = NULL;
- if (secure) {
- socket = new SecureListenSocket(m_events, m_socketMultiplexer, family);
+ if (security_level != ConnectionSecurityLevel::PLAINTEXT) {
+ socket = new SecureListenSocket(m_events, m_socketMultiplexer, family, security_level);
}
else {
socket = new TCPListenSocket(m_events, m_socketMultiplexer, family);
diff --git a/src/lib/net/TCPSocketFactory.h b/src/lib/net/TCPSocketFactory.h
index 0195ec4..ac21cab 100644
--- a/src/lib/net/TCPSocketFactory.h
+++ b/src/lib/net/TCPSocketFactory.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -31,12 +31,11 @@ public:
virtual ~TCPSocketFactory();
// ISocketFactory overrides
- virtual IDataSocket* create(
- IArchNetwork::EAddressFamily family,
- bool secure) const;
- virtual IListenSocket* createListen(
- IArchNetwork::EAddressFamily family,
- bool secure) const;
+ virtual IDataSocket* create(IArchNetwork::EAddressFamily family,
+ ConnectionSecurityLevel security_level) const;
+
+ virtual IListenSocket* createListen(IArchNetwork::EAddressFamily family,
+ ConnectionSecurityLevel security_level) const;
private:
IEventQueue* m_events;
diff --git a/src/lib/net/TSocketMultiplexerMethodJob.h b/src/lib/net/TSocketMultiplexerMethodJob.h
index 9e74cdd..4b571ab 100644
--- a/src/lib/net/TSocketMultiplexerMethodJob.h
+++ b/src/lib/net/TSocketMultiplexerMethodJob.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -25,81 +25,43 @@
/*!
A socket multiplexer job class that invokes a member function.
*/
-template <class T>
class TSocketMultiplexerMethodJob : public ISocketMultiplexerJob {
public:
- using Method = MultiplexerJobStatus (T::*)(ISocketMultiplexerJob*, bool, bool, bool);
+ using RunFunction = std::function<MultiplexerJobStatus(ISocketMultiplexerJob*, bool, bool, bool)>;
//! run() invokes \c object->method(arg)
- TSocketMultiplexerMethodJob(T* object, Method method,
- ArchSocket socket, bool readable, bool writeable);
- virtual ~TSocketMultiplexerMethodJob();
+ TSocketMultiplexerMethodJob(const RunFunction& func,
+ ArchSocket socket, bool readable, bool writable) :
+ func_{func},
+ m_socket(ARCH->copySocket(socket)),
+ m_readable(readable),
+ m_writable(writable)
+ {
+ }
+
+ ~TSocketMultiplexerMethodJob() override
+ {
+ ARCH->closeSocket(m_socket);
+ }
// IJob overrides
- virtual MultiplexerJobStatus run(bool readable, bool writable, bool error) override;
- virtual ArchSocket getSocket() const override;
- virtual bool isReadable() const override;
- virtual bool isWritable() const override;
+ virtual MultiplexerJobStatus run(bool readable, bool writable, bool error) override
+ {
+ if (func_) {
+ return func_(this, readable, writable, error);
+ }
+ return {false, {}};
+ }
+
+ virtual ArchSocket getSocket() const override { return m_socket; }
+ virtual bool isReadable() const override { return m_readable; }
+ virtual bool isWritable() const override { return m_writable; }
private:
- T* m_object;
- Method m_method;
+ RunFunction func_;
ArchSocket m_socket;
bool m_readable;
bool m_writable;
- void* m_arg;
};
-template <class T>
-inline
-TSocketMultiplexerMethodJob<T>::TSocketMultiplexerMethodJob(T* object,
- Method method, ArchSocket socket,
- bool readable, bool writable) :
- m_object(object),
- m_method(method),
- m_socket(ARCH->copySocket(socket)),
- m_readable(readable),
- m_writable(writable)
-{
- // do nothing
-}
-
-template <class T>
-inline
-TSocketMultiplexerMethodJob<T>::~TSocketMultiplexerMethodJob()
-{
- ARCH->closeSocket(m_socket);
-}
-
-template <class T>
-inline MultiplexerJobStatus TSocketMultiplexerMethodJob<T>::run(bool read, bool write, bool error)
-{
- if (m_object != NULL) {
- return (m_object->*m_method)(this, read, write, error);
- }
- return {false, {}};
-}
-
-template <class T>
-inline
-ArchSocket
-TSocketMultiplexerMethodJob<T>::getSocket() const
-{
- return m_socket;
-}
-
-template <class T>
-inline
-bool
-TSocketMultiplexerMethodJob<T>::isReadable() const
-{
- return m_readable;
-}
-template <class T>
-inline
-bool
-TSocketMultiplexerMethodJob<T>::isWritable() const
-{
- return m_writable;
-}
diff --git a/src/lib/net/XSocket.cpp b/src/lib/net/XSocket.cpp
index eed7a26..6a50537 100644
--- a/src/lib/net/XSocket.cpp
+++ b/src/lib/net/XSocket.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -63,7 +63,7 @@ std::string XSocketAddress::getWhat() const noexcept
"invalid port" // m_port may not be set to the bad port
};
return format(s_errorID[m_error], s_errorMsg[m_error],
- m_hostname.c_str(),
+ m_hostname.c_str(),
barrier::string::sprintf("%d", m_port).c_str());
}
diff --git a/src/lib/net/XSocket.h b/src/lib/net/XSocket.h
index d12278e..cafe59c 100644
--- a/src/lib/net/XSocket.h
+++ b/src/lib/net/XSocket.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/CMakeLists.txt b/src/lib/platform/CMakeLists.txt
index a1718a1..75551b7 100644
--- a/src/lib/platform/CMakeLists.txt
+++ b/src/lib/platform/CMakeLists.txt
@@ -1,11 +1,11 @@
# barrier -- mouse and keyboard sharing utility
# Copyright (C) 2012-2016 Symless Ltd.
# Copyright (C) 2009 Nick Bolton
-#
+#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
-#
+#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/IMSWindowsClipboardFacade.h b/src/lib/platform/IMSWindowsClipboardFacade.h
index 03c6248..d848184 100644
--- a/src/lib/platform/IMSWindowsClipboardFacade.h
+++ b/src/lib/platform/IMSWindowsClipboardFacade.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -33,4 +33,4 @@ public:
virtual ~IMSWindowsClipboardFacade() { }
};
-#endif \ No newline at end of file
+#endif
diff --git a/src/lib/platform/IOSXKeyResource.cpp b/src/lib/platform/IOSXKeyResource.cpp
index 0c5abe7..1866968 100644
--- a/src/lib/platform/IOSXKeyResource.cpp
+++ b/src/lib/platform/IOSXKeyResource.cpp
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -128,7 +128,7 @@ IOSXKeyResource::getKeyID(UInt8 c)
// encoding with char value 214). if it did then make no key,
// otherwise CFStringCreateMutableCopy() will crash.
if (cfString == NULL) {
- return kKeyNone;
+ return kKeyNone;
}
// convert to precomposed
diff --git a/src/lib/platform/IOSXKeyResource.h b/src/lib/platform/IOSXKeyResource.h
index fc190ef..b032bd9 100644
--- a/src/lib/platform/IOSXKeyResource.h
+++ b/src/lib/platform/IOSXKeyResource.h
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -27,10 +27,10 @@ public:
virtual UInt32 getNumButtons() const = 0;
virtual UInt32 getTableForModifier(UInt32 mask) const = 0;
virtual KeyID getKey(UInt32 table, UInt32 button) const = 0;
-
+
// Convert a character in the current script to the equivalent KeyID
static KeyID getKeyID(UInt8);
-
+
// Convert a unicode character to the equivalent KeyID.
static KeyID unicharToKeyID(UniChar);
};
diff --git a/src/lib/platform/IXWindowsImpl.h b/src/lib/platform/IXWindowsImpl.h
index ddcaf2f..37c59b2 100644
--- a/src/lib/platform/IXWindowsImpl.h
+++ b/src/lib/platform/IXWindowsImpl.h
@@ -3,39 +3,31 @@
#include "config.h"
-#if X_DISPLAY_MISSING
-# error X11 is required to build barrier
-#else
-# include <X11/X.h>
-# include <X11/Xutil.h>
-# define XK_MISCELLANY
-# define XK_XKB_KEYS
-# include <X11/keysymdef.h>
-# if HAVE_X11_EXTENSIONS_DPMS_H
- extern "C" {
-# include <X11/extensions/dpms.h>
- }
-# endif
-# if HAVE_X11_EXTENSIONS_XTEST_H
-# include <X11/extensions/XTest.h>
-# else
-# error The XTest extension is required to build barrier
-# endif
-# if HAVE_X11_EXTENSIONS_XINERAMA_H
- // Xinerama.h may lack extern "C" for inclusion by C++
- extern "C" {
-# include <X11/extensions/Xinerama.h>
- }
-# endif
-# if HAVE_X11_EXTENSIONS_XRANDR_H
-# include <X11/extensions/Xrandr.h>
-# endif
-# if HAVE_XKB_EXTENSION
-# include <X11/XKBlib.h>
-# endif
-# ifdef HAVE_XI2
-# include <X11/extensions/XInput2.h>
-# endif
+#include <X11/X.h>
+#include <X11/Xutil.h>
+#define XK_MISCELLANY
+#define XK_XKB_KEYS
+#include <X11/keysymdef.h>
+#if HAVE_X11_EXTENSIONS_DPMS_H
+ extern "C" {
+# include <X11/extensions/dpms.h>
+ }
+#endif
+#include <X11/extensions/XTest.h>
+#if HAVE_X11_EXTENSIONS_XINERAMA_H
+ // Xinerama.h may lack extern "C" for inclusion by C++
+ extern "C" {
+# include <X11/extensions/Xinerama.h>
+ }
+#endif
+#if HAVE_X11_EXTENSIONS_XRANDR_H
+# include <X11/extensions/Xrandr.h>
+#endif
+#if HAVE_XKB_EXTENSION
+# include <X11/XKBlib.h>
+#endif
+#ifdef HAVE_XI2
+# include <X11/extensions/XInput2.h>
#endif
class IXWindowsImpl {
diff --git a/src/lib/platform/ImmuneKeysReader.cpp b/src/lib/platform/ImmuneKeysReader.cpp
index 72baed3..eaeedc1 100644
--- a/src/lib/platform/ImmuneKeysReader.cpp
+++ b/src/lib/platform/ImmuneKeysReader.cpp
@@ -50,4 +50,4 @@ static void add_key(const char * const buffer, std::vector<DWORD> &keys)
}
}
return true;
-} \ No newline at end of file
+}
diff --git a/src/lib/platform/ImmuneKeysReader.h b/src/lib/platform/ImmuneKeysReader.h
index b46cbbe..536dd45 100644
--- a/src/lib/platform/ImmuneKeysReader.h
+++ b/src/lib/platform/ImmuneKeysReader.h
@@ -27,8 +27,4 @@ class ImmuneKeysReader
{
public:
static bool get_list(const char * const path, std::vector<DWORD> &keys, std::string &badLine);
-
-private:
- // static class
- explicit ImmuneKeysReader() {}
};
diff --git a/src/lib/platform/MSWindowsClipboard.cpp b/src/lib/platform/MSWindowsClipboard.cpp
index 20445d4..fa59c3e 100644
--- a/src/lib/platform/MSWindowsClipboard.cpp
+++ b/src/lib/platform/MSWindowsClipboard.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -70,7 +70,7 @@ MSWindowsClipboard::emptyUnowned()
// empty the clipboard (and take ownership)
if (!EmptyClipboard()) {
- // unable to cause this in integ tests, but this error has never
+ // unable to cause this in integ tests, but this error has never
// actually been reported by users.
LOG((CLOG_DEBUG "failed to grab clipboard"));
return false;
diff --git a/src/lib/platform/MSWindowsClipboard.h b/src/lib/platform/MSWindowsClipboard.h
index 35ccb56..415f31c 100644
--- a/src/lib/platform/MSWindowsClipboard.h
+++ b/src/lib/platform/MSWindowsClipboard.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/MSWindowsClipboardAnyTextConverter.cpp b/src/lib/platform/MSWindowsClipboardAnyTextConverter.cpp
index 85a7dbe..e46b1de 100644
--- a/src/lib/platform/MSWindowsClipboardAnyTextConverter.cpp
+++ b/src/lib/platform/MSWindowsClipboardAnyTextConverter.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/MSWindowsClipboardAnyTextConverter.h b/src/lib/platform/MSWindowsClipboardAnyTextConverter.h
index 622d281..463a24a 100644
--- a/src/lib/platform/MSWindowsClipboardAnyTextConverter.h
+++ b/src/lib/platform/MSWindowsClipboardAnyTextConverter.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/MSWindowsClipboardBitmapConverter.cpp b/src/lib/platform/MSWindowsClipboardBitmapConverter.cpp
index 7d38fda..bac8cb6 100644
--- a/src/lib/platform/MSWindowsClipboardBitmapConverter.cpp
+++ b/src/lib/platform/MSWindowsClipboardBitmapConverter.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/MSWindowsClipboardBitmapConverter.h b/src/lib/platform/MSWindowsClipboardBitmapConverter.h
index 2733884..9ca27ee 100644
--- a/src/lib/platform/MSWindowsClipboardBitmapConverter.h
+++ b/src/lib/platform/MSWindowsClipboardBitmapConverter.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/MSWindowsClipboardFacade.cpp b/src/lib/platform/MSWindowsClipboardFacade.cpp
index 3b6478f..a6e1207 100644
--- a/src/lib/platform/MSWindowsClipboardFacade.cpp
+++ b/src/lib/platform/MSWindowsClipboardFacade.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/MSWindowsClipboardFacade.h b/src/lib/platform/MSWindowsClipboardFacade.h
index a95e835..cdbd796 100644
--- a/src/lib/platform/MSWindowsClipboardFacade.h
+++ b/src/lib/platform/MSWindowsClipboardFacade.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/MSWindowsClipboardHTMLConverter.cpp b/src/lib/platform/MSWindowsClipboardHTMLConverter.cpp
index a1f1212..d2ac3dd 100644
--- a/src/lib/platform/MSWindowsClipboardHTMLConverter.cpp
+++ b/src/lib/platform/MSWindowsClipboardHTMLConverter.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/MSWindowsClipboardHTMLConverter.h b/src/lib/platform/MSWindowsClipboardHTMLConverter.h
index 51607a7..87d7fda 100644
--- a/src/lib/platform/MSWindowsClipboardHTMLConverter.h
+++ b/src/lib/platform/MSWindowsClipboardHTMLConverter.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/MSWindowsClipboardTextConverter.cpp b/src/lib/platform/MSWindowsClipboardTextConverter.cpp
index 1500e7e..15f2cc2 100644
--- a/src/lib/platform/MSWindowsClipboardTextConverter.cpp
+++ b/src/lib/platform/MSWindowsClipboardTextConverter.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/MSWindowsClipboardTextConverter.h b/src/lib/platform/MSWindowsClipboardTextConverter.h
index 6e265a2..4ebfa36 100644
--- a/src/lib/platform/MSWindowsClipboardTextConverter.h
+++ b/src/lib/platform/MSWindowsClipboardTextConverter.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/MSWindowsClipboardUTF16Converter.cpp b/src/lib/platform/MSWindowsClipboardUTF16Converter.cpp
index 4b72717..52c6d4c 100644
--- a/src/lib/platform/MSWindowsClipboardUTF16Converter.cpp
+++ b/src/lib/platform/MSWindowsClipboardUTF16Converter.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/MSWindowsClipboardUTF16Converter.h b/src/lib/platform/MSWindowsClipboardUTF16Converter.h
index 1a9d435..7314678 100644
--- a/src/lib/platform/MSWindowsClipboardUTF16Converter.h
+++ b/src/lib/platform/MSWindowsClipboardUTF16Converter.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/MSWindowsDebugOutputter.cpp b/src/lib/platform/MSWindowsDebugOutputter.cpp
index 43c38ad..22442ad 100644
--- a/src/lib/platform/MSWindowsDebugOutputter.cpp
+++ b/src/lib/platform/MSWindowsDebugOutputter.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/MSWindowsDebugOutputter.h b/src/lib/platform/MSWindowsDebugOutputter.h
index 01fd97e..e8ba5e6 100644
--- a/src/lib/platform/MSWindowsDebugOutputter.h
+++ b/src/lib/platform/MSWindowsDebugOutputter.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-
+
#pragma once
#include "base/ILogOutputter.h"
diff --git a/src/lib/platform/MSWindowsDesks.cpp b/src/lib/platform/MSWindowsDesks.cpp
index 768ccb4..d126e13 100644
--- a/src/lib/platform/MSWindowsDesks.cpp
+++ b/src/lib/platform/MSWindowsDesks.cpp
@@ -3,11 +3,11 @@
* Copyright (C) 2018 Debauchee Open Source Group
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -27,9 +27,7 @@
#include "arch/win32/ArchMiscWindows.h"
#include "base/Log.h"
#include "base/IEventQueue.h"
-#include "base/IJob.h"
#include "base/TMethodEventJob.h"
-#include "base/TMethodJob.h"
#include "base/IEventQueue.h"
#include <malloc.h>
@@ -97,10 +95,9 @@
// MSWindowsDesks
//
-MSWindowsDesks::MSWindowsDesks(
- bool isPrimary, bool noHooks,
+MSWindowsDesks::MSWindowsDesks(bool isPrimary, bool noHooks,
const IScreenSaver* screensaver, IEventQueue* events,
- IJob* updateKeys, bool stopOnDeskSwitch) :
+ const std::function<void()>& updateKeys, bool stopOnDeskSwitch) :
m_isPrimary(isPrimary),
m_noHooks(noHooks),
m_isOnScreen(m_isPrimary),
@@ -130,7 +127,6 @@ MSWindowsDesks::~MSWindowsDesks()
disable();
destroyClass(m_deskClass);
destroyCursor(m_cursor);
- delete m_updateKeys;
}
void
@@ -602,13 +598,11 @@ MSWindowsDesks::deskLeave(Desk* desk, HKL keyLayout)
}
}
-void
-MSWindowsDesks::deskThread(void* vdesk)
+void MSWindowsDesks::desk_thread(Desk* desk)
{
MSG msg;
// use given desktop for this thread
- Desk* desk = static_cast<Desk*>(vdesk);
desk->m_threadID = GetCurrentThreadId();
desk->m_window = NULL;
desk->m_foregroundWindow = NULL;
@@ -709,7 +703,7 @@ MSWindowsDesks::deskThread(void* vdesk)
}
case BARRIER_MSG_SYNC_KEYS:
- m_updateKeys->run();
+ m_updateKeys();
break;
case BARRIER_MSG_SCREENSAVER:
@@ -752,8 +746,7 @@ MSWindowsDesks::Desk* MSWindowsDesks::addDesk(const std::string& name, HDESK hde
desk->m_name = name;
desk->m_desk = hdesk;
desk->m_targetID = GetCurrentThreadId();
- desk->m_thread = new Thread(new TMethodJob<MSWindowsDesks>(
- this, &MSWindowsDesks::deskThread, desk));
+ desk->m_thread = new Thread([this, desk]() { desk_thread(desk); });
waitForDesk();
m_desks.insert(std::make_pair(name, desk));
return desk;
@@ -793,7 +786,7 @@ MSWindowsDesks::checkDesk()
desk = index->second;
}
- // if we are told to shut down on desk switch, and this is not the
+ // if we are told to shut down on desk switch, and this is not the
// first switch, then shut down.
if (m_stopOnDeskSwitch && m_activeDesk != NULL && name != m_activeDeskName) {
LOG((CLOG_DEBUG "shutting down because of desk switch to \"%s\"", name.c_str()));
@@ -803,7 +796,7 @@ MSWindowsDesks::checkDesk()
// if active desktop changed then tell the old and new desk threads
// about the change. don't switch desktops when the screensaver is
- // active becaue we'd most likely switch to the screensaver desktop
+ // active because we'd most likely switch to the screensaver desktop
// which would have the side effect of forcing the screensaver to
// stop.
if (name != m_activeDeskName && !m_screensaver->isActive()) {
diff --git a/src/lib/platform/MSWindowsDesks.h b/src/lib/platform/MSWindowsDesks.h
index 6e5e709..6292f98 100644
--- a/src/lib/platform/MSWindowsDesks.h
+++ b/src/lib/platform/MSWindowsDesks.h
@@ -3,11 +3,11 @@
* Copyright (C) 2018 Debauchee Open Source Group
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -26,15 +26,16 @@
#include "mt/CondVar.h"
#include "mt/Mutex.h"
#include "common/stdmap.h"
+#include <functional>
#include <string>
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
+
class Event;
class EventQueueTimer;
class Thread;
-class IJob;
class IScreenSaver;
class IEventQueue;
@@ -68,7 +69,7 @@ public:
MSWindowsDesks(
bool isPrimary, bool noHooks,
const IScreenSaver* screensaver, IEventQueue* events,
- IJob* updateKeys, bool stopOnDeskSwitch);
+ const std::function<void()>& updateKeys, bool stopOnDeskSwitch);
~MSWindowsDesks();
//! @name manipulators
@@ -219,7 +220,7 @@ private:
void deskMouseRelativeMove(SInt32 dx, SInt32 dy) const;
void deskEnter(Desk* desk);
void deskLeave(Desk* desk, HKL keyLayout);
- void deskThread(void* vdesk);
+ void desk_thread(Desk* desk);
// desk switch checking and handling
Desk* addDesk(const std::string& name, HDESK hdesk);
@@ -284,7 +285,7 @@ private:
Desks m_desks;
// keyboard stuff
- IJob* m_updateKeys;
+ std::function<void()> m_updateKeys;
HKL m_keyLayout;
// options
diff --git a/src/lib/platform/MSWindowsDropTarget.cpp b/src/lib/platform/MSWindowsDropTarget.cpp
index d647808..095ab53 100644
--- a/src/lib/platform/MSWindowsDropTarget.cpp
+++ b/src/lib/platform/MSWindowsDropTarget.cpp
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2014-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -53,7 +53,7 @@ MSWindowsDropTarget::DragEnter(IDataObject* dataObject, DWORD keyState, POINTL p
if (m_allowDrop) {
getDropData(dataObject);
}
-
+
*effect = DROPEFFECT_NONE;
return S_OK;
@@ -132,7 +132,7 @@ getDropData(IDataObject* dataObject)
wcstombs(filename, wcData, wcslen(wcData));
MSWindowsDropTarget::instance().setDraggingFilename(filename);
-
+
GlobalUnlock(stgMed.hGlobal);
// release the data using the COM API
@@ -167,7 +167,7 @@ ULONG __stdcall
MSWindowsDropTarget::Release(void)
{
LONG count = InterlockedDecrement(&m_refCount);
-
+
if (count == 0) {
delete this;
return 0;
diff --git a/src/lib/platform/MSWindowsDropTarget.h b/src/lib/platform/MSWindowsDropTarget.h
index 6d60845..6c3bf69 100644
--- a/src/lib/platform/MSWindowsDropTarget.h
+++ b/src/lib/platform/MSWindowsDropTarget.h
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2014-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -44,7 +44,7 @@ public:
std::string getDraggingFilename();
void clearDraggingFilename();
- static MSWindowsDropTarget&
+ static MSWindowsDropTarget&
instance();
private:
@@ -53,7 +53,7 @@ private:
long m_refCount;
bool m_allowDrop;
std::string m_dragFilename;
-
+
static MSWindowsDropTarget*
s_instance;
};
diff --git a/src/lib/platform/MSWindowsEventQueueBuffer.cpp b/src/lib/platform/MSWindowsEventQueueBuffer.cpp
index 3111367..709d814 100644
--- a/src/lib/platform/MSWindowsEventQueueBuffer.cpp
+++ b/src/lib/platform/MSWindowsEventQueueBuffer.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/MSWindowsEventQueueBuffer.h b/src/lib/platform/MSWindowsEventQueueBuffer.h
index bc9bde1..6f918d4 100644
--- a/src/lib/platform/MSWindowsEventQueueBuffer.h
+++ b/src/lib/platform/MSWindowsEventQueueBuffer.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/MSWindowsHook.cpp b/src/lib/platform/MSWindowsHook.cpp
index b9b9740..3230d24 100644
--- a/src/lib/platform/MSWindowsHook.cpp
+++ b/src/lib/platform/MSWindowsHook.cpp
@@ -3,11 +3,11 @@
* Copyright (C) 2018 Debauchee Open Source Group
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2011 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -56,14 +56,13 @@ static BYTE g_deadKeyState[256] = { 0 };
static BYTE g_keyState[256] = { 0 };
static bool g_fakeServerInput = false;
static std::vector<DWORD> g_immuneKeys;
-
-static const std::string ImmuneKeysPath = DataDirectories::profile() + "\\ImmuneKeys.txt";
+static std::string g_immuneKeysPath;
static std::vector<DWORD> immune_keys_list()
{
std::vector<DWORD> keys;
std::string badLine;
- if (!ImmuneKeysReader::get_list(ImmuneKeysPath.c_str(), keys, badLine))
+ if (!ImmuneKeysReader::get_list(g_immuneKeysPath.c_str(), keys, badLine))
LOG((CLOG_ERR "Reading immune keys stopped at: %s", badLine.c_str()));
return keys;
}
@@ -144,9 +143,9 @@ keyboardGetState(BYTE keys[256], DWORD vkCode, bool kf_up)
static
WPARAM
-makeKeyMsg(UINT virtKey, char c, bool noAltGr)
+makeKeyMsg(UINT virtKey, WCHAR wc, bool noAltGr)
{
- return MAKEWPARAM(MAKEWORD(virtKey & 0xff, (BYTE)c), noAltGr ? 1 : 0);
+ return MAKEWPARAM((WORD)wc, MAKEWORD(virtKey & 0xff, noAltGr ? 1 : 0));
}
static
@@ -193,7 +192,7 @@ keyboardHookHandler(WPARAM wParam, LPARAM lParam)
(lParam & 0x80000000u) != 0) {
g_deadRelease = 0;
PostThreadMessage(g_threadID, BARRIER_MSG_DEBUG,
- wParam | 0x04000000, lParam);
+ wParam | 0x40000000, lParam);
return false;
}
@@ -245,19 +244,19 @@ keyboardHookHandler(WPARAM wParam, LPARAM lParam)
}
}
- WORD c = 0;
+ WCHAR wc[2] = { 0, 0 };
// map the key event to a character. we have to put the dead
// key back first and this has the side effect of removing it.
if (g_deadVirtKey != 0) {
- if (ToAscii((UINT)g_deadVirtKey, (g_deadLParam & 0x10ff0000u) >> 16,
- g_deadKeyState, &c, flags) == 2) {
- // If ToAscii returned 2, it means that we accidentally removed
+ if (ToUnicode((UINT)g_deadVirtKey, (g_deadLParam & 0x10ff0000u) >> 16,
+ g_deadKeyState, wc, 2, flags) == 2) {
+ // If ToUnicode returned 2, it means that we accidentally removed
// a double dead key instead of restoring it. Thus, we call
- // ToAscii again with the same parameters to restore the
+ // ToUnicode again with the same parameters to restore the
// internal dead key state.
- ToAscii((UINT)g_deadVirtKey, (g_deadLParam & 0x10ff0000u) >> 16,
- g_deadKeyState, &c, flags);
+ ToUnicode((UINT)g_deadVirtKey, (g_deadLParam & 0x10ff0000u) >> 16,
+ g_deadKeyState, wc, 2, flags);
// We need to keep track of this because g_deadVirtKey will be
// cleared later on; this would cause the dead key release to
@@ -267,7 +266,7 @@ keyboardHookHandler(WPARAM wParam, LPARAM lParam)
}
UINT scanCode = ((lParam & 0x10ff0000u) >> 16);
- int n = ToAscii((UINT)wParam, scanCode, keys, &c, flags);
+ int n = ToUnicode((UINT)wParam, scanCode, keys, wc, 2, flags);
// if mapping failed and ctrl and alt are pressed then try again
// with both not pressed. this handles the case where ctrl and
@@ -279,12 +278,12 @@ keyboardHookHandler(WPARAM wParam, LPARAM lParam)
if (n == 0 && (control & 0x80) != 0 && (menu & 0x80) != 0) {
noAltGr = true;
PostThreadMessage(g_threadID, BARRIER_MSG_DEBUG,
- wParam | 0x05000000, lParam);
+ wParam | 0x50000000, lParam);
if (g_deadVirtKey != 0) {
- if (ToAscii((UINT)g_deadVirtKey, (g_deadLParam & 0x10ff0000u) >> 16,
- g_deadKeyState, &c, flags) == 2) {
- ToAscii((UINT)g_deadVirtKey, (g_deadLParam & 0x10ff0000u) >> 16,
- g_deadKeyState, &c, flags);
+ if (ToUnicode((UINT)g_deadVirtKey, (g_deadLParam & 0x10ff0000u) >> 16,
+ g_deadKeyState, wc, 2, flags) == 2) {
+ ToUnicode((UINT)g_deadVirtKey, (g_deadLParam & 0x10ff0000u) >> 16,
+ g_deadKeyState, wc, 2, flags);
g_deadRelease = g_deadVirtKey;
}
}
@@ -298,12 +297,12 @@ keyboardHookHandler(WPARAM wParam, LPARAM lParam)
keys2[VK_LMENU] = 0;
keys2[VK_RMENU] = 0;
keys2[VK_MENU] = 0;
- n = ToAscii((UINT)wParam, scanCode, keys2, &c, flags);
+ n = ToUnicode((UINT)wParam, scanCode, keys2, wc, 2, flags);
}
PostThreadMessage(g_threadID, BARRIER_MSG_DEBUG,
- wParam | ((c & 0xff) << 8) |
- ((n & 0xff) << 16) | 0x06000000,
+ (wc[0] & 0xffff) | ((wParam & 0xff) << 16) |
+ ((n & 0xf) << 24) | 0x60000000,
lParam);
WPARAM charAndVirtKey = 0;
bool clearDeadKey = false;
@@ -329,12 +328,12 @@ keyboardHookHandler(WPARAM wParam, LPARAM lParam)
case 0:
// key doesn't map to a character. this can happen if
// non-character keys are pressed after a dead key.
- charAndVirtKey = makeKeyMsg((UINT)wParam, (char)0, noAltGr);
+ charAndVirtKey = makeKeyMsg((UINT)wParam, (WCHAR)0, noAltGr);
break;
case 1:
// key maps to a character composed with dead key
- charAndVirtKey = makeKeyMsg((UINT)wParam, (char)LOBYTE(c), noAltGr);
+ charAndVirtKey = makeKeyMsg((UINT)wParam, wc[0], noAltGr);
clearDeadKey = true;
break;
@@ -342,14 +341,14 @@ keyboardHookHandler(WPARAM wParam, LPARAM lParam)
// previous dead key not composed. send a fake key press
// and release for the dead key to our window.
WPARAM deadCharAndVirtKey =
- makeKeyMsg((UINT)g_deadVirtKey, (char)LOBYTE(c), noAltGr);
+ makeKeyMsg((UINT)g_deadVirtKey, wc[0], noAltGr);
PostThreadMessage(g_threadID, BARRIER_MSG_KEY,
deadCharAndVirtKey, g_deadLParam & 0x7fffffffu);
PostThreadMessage(g_threadID, BARRIER_MSG_KEY,
deadCharAndVirtKey, g_deadLParam | 0x80000000u);
// use uncomposed character
- charAndVirtKey = makeKeyMsg((UINT)wParam, (char)HIBYTE(c), noAltGr);
+ charAndVirtKey = makeKeyMsg((UINT)wParam, wc[1], noAltGr);
clearDeadKey = true;
break;
}
@@ -357,8 +356,8 @@ keyboardHookHandler(WPARAM wParam, LPARAM lParam)
// put back the dead key, if any, for the application to use
if (g_deadVirtKey != 0) {
- ToAscii((UINT)g_deadVirtKey, (g_deadLParam & 0x10ff0000u) >> 16,
- g_deadKeyState, &c, flags);
+ ToUnicode((UINT)g_deadVirtKey, (g_deadLParam & 0x10ff0000u) >> 16,
+ g_deadKeyState, wc, 2, flags);
}
// clear out old dead key state
@@ -375,7 +374,7 @@ keyboardHookHandler(WPARAM wParam, LPARAM lParam)
// forwarding.
if (charAndVirtKey != 0) {
PostThreadMessage(g_threadID, BARRIER_MSG_DEBUG,
- charAndVirtKey | 0x07000000, lParam);
+ charAndVirtKey | 0x70000000, lParam);
PostThreadMessage(g_threadID, BARRIER_MSG_KEY, charAndVirtKey, lParam);
}
@@ -575,8 +574,9 @@ MSWindowsHook::install()
g_fakeServerInput = false;
// setup immune keys
+ g_immuneKeysPath = (barrier::DataDirectories::profile() / "ImmuneKeys.txt").u8string();
g_immuneKeys = immune_keys_list();
- LOG((CLOG_DEBUG "Found %u immune keys in %s", g_immuneKeys.size(), ImmuneKeysPath.c_str()));
+ LOG((CLOG_DEBUG "Found %u immune keys in %s", g_immuneKeys.size(), g_immuneKeysPath.c_str()));
#if NO_GRAB_KEYBOARD
// we only need the mouse hook
@@ -638,4 +638,4 @@ void
MSWindowsHook::uninstallScreenSaver()
{
g_hkMessage.unset();
-} \ No newline at end of file
+}
diff --git a/src/lib/platform/MSWindowsHook.h b/src/lib/platform/MSWindowsHook.h
index 7b2121c..c6d91a2 100644
--- a/src/lib/platform/MSWindowsHook.h
+++ b/src/lib/platform/MSWindowsHook.h
@@ -3,11 +3,11 @@
* Copyright (C) 2018 Debauchee Open Source Group
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2011 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/MSWindowsHookResource.cpp b/src/lib/platform/MSWindowsHookResource.cpp
index ced5ff1..c6349ab 100644
--- a/src/lib/platform/MSWindowsHookResource.cpp
+++ b/src/lib/platform/MSWindowsHookResource.cpp
@@ -30,4 +30,4 @@ bool WindowsHookResource::unset()
}
bool WindowsHookResource::is_set() const { return _hook != NULL; }
-WindowsHookResource::operator HHOOK() const { return _hook; } \ No newline at end of file
+WindowsHookResource::operator HHOOK() const { return _hook; }
diff --git a/src/lib/platform/MSWindowsHookResource.h b/src/lib/platform/MSWindowsHookResource.h
index b66c4b8..a3c9d83 100644
--- a/src/lib/platform/MSWindowsHookResource.h
+++ b/src/lib/platform/MSWindowsHookResource.h
@@ -17,4 +17,4 @@ public:
private:
HHOOK _hook;
-}; \ No newline at end of file
+};
diff --git a/src/lib/platform/MSWindowsKeyState.cpp b/src/lib/platform/MSWindowsKeyState.cpp
index 2f29f72..c723d19 100644
--- a/src/lib/platform/MSWindowsKeyState.cpp
+++ b/src/lib/platform/MSWindowsKeyState.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2003 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -21,7 +21,6 @@
#include "platform/MSWindowsDesks.h"
#include "mt/Thread.h"
#include "arch/win32/ArchMiscWindows.h"
-#include "base/FunctionJob.h"
#include "base/Log.h"
#include "base/String.h"
#include "base/IEventQueue.h"
@@ -61,17 +60,17 @@ const KeyID MSWindowsKeyState::s_virtualKey[] =
/* 0x012 */ { kKeyAlt_L }, // VK_MENU
/* 0x013 */ { kKeyPause }, // VK_PAUSE
/* 0x014 */ { kKeyCapsLock }, // VK_CAPITAL
- /* 0x015 */ { kKeyKana }, // VK_HANGUL, VK_KANA
- /* 0x016 */ { kKeyNone }, // undefined
+ /* 0x015 */ { kKeyNone }, // undefined
+ /* 0x016 */ { kKeyKana }, // VK_HANGUL, VK_KANA, VK_IME_ON
/* 0x017 */ { kKeyNone }, // VK_JUNJA
/* 0x018 */ { kKeyNone }, // VK_FINAL
/* 0x019 */ { kKeyKanzi }, // VK_HANJA, VK_KANJI
- /* 0x01a */ { kKeyNone }, // undefined
+ /* 0x01a */ { kKeyEisuToggle }, // VK_IME_OFF
/* 0x01b */ { kKeyEscape }, // VK_ESCAPE
- /* 0x01c */ { kKeyHenkan }, // VK_CONVERT
- /* 0x01d */ { kKeyNone }, // VK_NONCONVERT
- /* 0x01e */ { kKeyNone }, // VK_ACCEPT
- /* 0x01f */ { kKeyNone }, // VK_MODECHANGE
+ /* 0x01c */ { kKeyHenkan }, // VK_CONVERT
+ /* 0x01d */ { kKeyMuhenkan }, // VK_NONCONVERT
+ /* 0x01e */ { kKeyNone }, // VK_ACCEPT
+ /* 0x01f */ { kKeyNone }, // VK_MODECHANGE
/* 0x020 */ { kKeyNone }, // VK_SPACE
/* 0x021 */ { kKeyKP_PageUp }, // VK_PRIOR
/* 0x022 */ { kKeyKP_PageDown },// VK_NEXT
@@ -286,15 +285,15 @@ const KeyID MSWindowsKeyState::s_virtualKey[] =
/* 0x0f3 */ { kKeyZenkaku }, // VK_OEM_AUTO
/* 0x0f4 */ { kKeyZenkaku }, // VK_OEM_ENLW
/* 0x0f5 */ { kKeyNone }, // OEM specific
- /* 0x0f6 */ { kKeyNone }, // VK_ATTN
- /* 0x0f7 */ { kKeyNone }, // VK_CRSEL
- /* 0x0f8 */ { kKeyNone }, // VK_EXSEL
- /* 0x0f9 */ { kKeyNone }, // VK_EREOF
- /* 0x0fa */ { kKeyNone }, // VK_PLAY
- /* 0x0fb */ { kKeyNone }, // VK_ZOOM
+ /* 0x0f6 */ { kKeyNone }, // VK_ATTN
+ /* 0x0f7 */ { kKeyNone }, // VK_CRSEL
+ /* 0x0f8 */ { kKeyNone }, // VK_EXSEL
+ /* 0x0f9 */ { kKeyNone }, // VK_EREOF
+ /* 0x0fa */ { kKeyNone }, // VK_PLAY
+ /* 0x0fb */ { kKeyNone }, // VK_ZOOM
/* 0x0fc */ { kKeyNone }, // reserved
- /* 0x0fd */ { kKeyNone }, // VK_PA1
- /* 0x0fe */ { kKeyNone }, // VK_OEM_CLEAR
+ /* 0x0fd */ { kKeyNone }, // VK_PA1
+ /* 0x0fe */ { kKeyNone }, // VK_OEM_CLEAR
/* 0x0ff */ { kKeyNone }, // reserved
/* 0x100 */ { kKeyNone }, // reserved
@@ -320,15 +319,15 @@ const KeyID MSWindowsKeyState::s_virtualKey[] =
/* 0x114 */ { kKeyNone }, // VK_CAPITAL
/* 0x115 */ { kKeyHangul }, // VK_HANGUL
/* 0x116 */ { kKeyNone }, // undefined
- /* 0x117 */ { kKeyNone }, // VK_JUNJA
- /* 0x118 */ { kKeyNone }, // VK_FINAL
+ /* 0x117 */ { kKeyNone }, // VK_JUNJA
+ /* 0x118 */ { kKeyNone }, // VK_FINAL
/* 0x119 */ { kKeyHanja }, // VK_HANJA
/* 0x11a */ { kKeyNone }, // undefined
/* 0x11b */ { kKeyNone }, // VK_ESCAPE
- /* 0x11c */ { kKeyNone }, // VK_CONVERT
- /* 0x11d */ { kKeyNone }, // VK_NONCONVERT
- /* 0x11e */ { kKeyNone }, // VK_ACCEPT
- /* 0x11f */ { kKeyNone }, // VK_MODECHANGE
+ /* 0x11c */ { kKeyNone }, // VK_CONVERT
+ /* 0x11d */ { kKeyNone }, // VK_NONCONVERT
+ /* 0x11e */ { kKeyNone }, // VK_ACCEPT
+ /* 0x11f */ { kKeyNone }, // VK_MODECHANGE
/* 0x120 */ { kKeyNone }, // VK_SPACE
/* 0x121 */ { kKeyPageUp }, // VK_PRIOR
/* 0x122 */ { kKeyPageDown }, // VK_NEXT
@@ -543,15 +542,15 @@ const KeyID MSWindowsKeyState::s_virtualKey[] =
/* 0x1f3 */ { kKeyNone }, // VK_OEM_AUTO
/* 0x1f4 */ { kKeyNone }, // VK_OEM_ENLW
/* 0x1f5 */ { kKeyNone }, // OEM specific
- /* 0x1f6 */ { kKeyNone }, // VK_ATTN
- /* 0x1f7 */ { kKeyNone }, // VK_CRSEL
- /* 0x1f8 */ { kKeyNone }, // VK_EXSEL
- /* 0x1f9 */ { kKeyNone }, // VK_EREOF
- /* 0x1fa */ { kKeyNone }, // VK_PLAY
- /* 0x1fb */ { kKeyNone }, // VK_ZOOM
+ /* 0x1f6 */ { kKeyNone }, // VK_ATTN
+ /* 0x1f7 */ { kKeyNone }, // VK_CRSEL
+ /* 0x1f8 */ { kKeyNone }, // VK_EXSEL
+ /* 0x1f9 */ { kKeyNone }, // VK_EREOF
+ /* 0x1fa */ { kKeyNone }, // VK_PLAY
+ /* 0x1fb */ { kKeyNone }, // VK_ZOOM
/* 0x1fc */ { kKeyNone }, // reserved
- /* 0x1fd */ { kKeyNone }, // VK_PA1
- /* 0x1fe */ { kKeyNone }, // VK_OEM_CLEAR
+ /* 0x1fd */ { kKeyNone }, // VK_PA1
+ /* 0x1fe */ { kKeyNone }, // VK_OEM_CLEAR
/* 0x1ff */ { kKeyNone } // reserved
};
@@ -688,34 +687,17 @@ MSWindowsKeyState::mapKeyFromEvent(WPARAM charAndVirtKey,
KeyModifierControl | KeyModifierAlt;
// extract character, virtual key, and if we didn't use AltGr
- char c = (char)((charAndVirtKey & 0xff00u) >> 8);
- UINT vkCode = (charAndVirtKey & 0xffu);
- bool noAltGr = ((charAndVirtKey & 0xff0000u) != 0);
+ WCHAR wc = (WCHAR)(charAndVirtKey & 0xffffu);
+ UINT vkCode = ((charAndVirtKey >> 16) & 0xffu);
+ bool noAltGr = ((charAndVirtKey & 0xff000000u) != 0);
// handle some keys via table lookup
KeyID id = getKeyID(vkCode, (KeyButton)((info >> 16) & 0x1ffu));
// check if not in table; map character to key id
- if (id == kKeyNone && c != 0) {
- if ((c & 0x80u) == 0) {
- // ASCII
- id = static_cast<KeyID>(c) & 0xffu;
- }
- else {
- // character is not really ASCII. instead it's some
- // character in the current ANSI code page. try to
- // convert that to a Unicode character. if we fail
- // then use the single byte character as is.
- char src = c;
- wchar_t unicode;
- if (MultiByteToWideChar(CP_THREAD_ACP, MB_PRECOMPOSED,
- &src, 1, &unicode, 1) > 0) {
- id = static_cast<KeyID>(unicode);
- }
- else {
- id = static_cast<KeyID>(c) & 0xffu;
- }
- }
+ if (id == kKeyNone && wc != 0) {
+ // UTF16
+ id = static_cast<KeyID>(wc) & 0xffffu;
}
// set modifier mask
@@ -821,15 +803,14 @@ MSWindowsKeyState::fakeCtrlAltDel()
CloseHandle(hEvtSendSas);
}
else {
- Thread cad(new FunctionJob(&MSWindowsKeyState::ctrlAltDelThread));
+ Thread cad([this](){ ctrl_alt_del_thread(); });
cad.wait();
}
return true;
}
-void
-MSWindowsKeyState::ctrlAltDelThread(void*)
+void MSWindowsKeyState::ctrl_alt_del_thread()
{
// get the Winlogon desktop at whatever privilege we can
HDESK desk = OpenDesktop("Winlogon", 0, FALSE, MAXIMUM_ALLOWED);
@@ -959,7 +940,7 @@ MSWindowsKeyState::getKeyMap(barrier::KeyMap& keyMap)
// deal with certain virtual keys specially
switch (vk) {
case VK_SHIFT:
- // this is important for sending the correct modifier to the
+ // this is important for sending the correct modifier to the
// client, a patch from bug #242 (right shift broken for ms
// remote desktop) removed this to just use left shift, which
// caused bug #2799 (right shift broken for osx).
@@ -1176,7 +1157,7 @@ MSWindowsKeyState::getKeyMap(barrier::KeyMap& keyMap)
}
}
}
-
+
// save each key. the map will automatically discard
// duplicates, like an unshift and shifted version of
// a key that's insensitive to shift.
@@ -1347,7 +1328,7 @@ MSWindowsKeyState::getKeyID(UINT virtualKey, KeyButton button) const
if ((LOWORD(m_keyLayout) & 0xffffu) == 0x0412u) { // 0x0412 : Korean Locale ID
if (virtualKey == VK_HANGUL || virtualKey == VK_HANJA) {
// If shift-space is used to change the input mode,
- // the extented bit is not set. So add it to get right key id.
+ // the extended bit is not set. So add it to get right key id.
button |= 0x100u;
}
}
@@ -1374,7 +1355,7 @@ MSWindowsKeyState::getIDForKey(barrier::KeyMap::KeyItem& item,
virtualKey, button, keyState, unicode,
sizeof(unicode) / sizeof(unicode[0]), 0, hkl);
KeyID id = static_cast<KeyID>(unicode[0]);
-
+
switch (n) {
case -1:
return barrier::KeyMap::getDeadKey(id);
diff --git a/src/lib/platform/MSWindowsKeyState.h b/src/lib/platform/MSWindowsKeyState.h
index 3c5fa40..eedcd85 100644
--- a/src/lib/platform/MSWindowsKeyState.h
+++ b/src/lib/platform/MSWindowsKeyState.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2003 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -169,7 +169,7 @@ private:
typedef std::vector<HKL> GroupList;
// send ctrl+alt+del hotkey event on NT family
- static void ctrlAltDelThread(void*);
+ static void ctrl_alt_del_thread();
bool getGroups(GroupList&) const;
void setWindowGroup(SInt32 group);
diff --git a/src/lib/platform/MSWindowsScreen.cpp b/src/lib/platform/MSWindowsScreen.cpp
index df10270..c995a40 100644
--- a/src/lib/platform/MSWindowsScreen.cpp
+++ b/src/lib/platform/MSWindowsScreen.cpp
@@ -3,11 +3,11 @@
* Copyright (C) 2018 Debauchee Open Source Group
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -36,11 +36,9 @@
#include "mt/Thread.h"
#include "arch/win32/ArchMiscWindows.h"
#include "arch/Arch.h"
-#include "base/FunctionJob.h"
#include "base/Log.h"
#include "base/IEventQueue.h"
#include "base/TMethodEventJob.h"
-#include "base/TMethodJob.h"
#include <string.h>
#include <Shlobj.h>
@@ -134,8 +132,7 @@ MSWindowsScreen::MSWindowsScreen(
m_noHooks,
m_screensaver,
m_events,
- new TMethodJob<MSWindowsScreen>(
- this, &MSWindowsScreen::updateKeysCB),
+ [this]() { updateKeysCB(); },
stopOnDeskSwitch);
m_keyState = new MSWindowsKeyState(m_desks, getEventTarget(), m_events);
@@ -145,16 +142,6 @@ MSWindowsScreen::MSWindowsScreen(
forceShowCursor();
LOG((CLOG_DEBUG "screen shape: %d,%d %dx%d %s", m_x, m_y, m_w, m_h, m_multimon ? "(multi-monitor)" : ""));
LOG((CLOG_DEBUG "window is 0x%08x", m_window));
-
- // SHGetFolderPath is deprecated in vista, but use it for xp support.
- char desktopPath[MAX_PATH];
- if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_DESKTOP, NULL, 0, desktopPath))) {
- m_desktopPath = std::string(desktopPath);
- LOG((CLOG_DEBUG "using desktop for drop target: %s", m_desktopPath.c_str()));
- }
- else {
- LOG((CLOG_ERR "failed to get desktop path, no drop target available, error=%d", GetLastError()));
- }
OleInitialize(0);
m_dropWindow = createDropWindow(m_class, "DropWindow");
@@ -365,17 +352,13 @@ MSWindowsScreen::leave()
forceShowCursor();
if (isDraggingStarted() && !m_isPrimary) {
- m_sendDragThread = new Thread(
- new TMethodJob<MSWindowsScreen>(
- this,
- &MSWindowsScreen::sendDragThread));
+ m_sendDragThread = new Thread([this](){ send_drag_thread(); });
}
return true;
}
-void
-MSWindowsScreen::sendDragThread(void*)
+void MSWindowsScreen::send_drag_thread()
{
std::string& draggingFilename = getDraggingFilename();
size_t size = draggingFilename.size();
@@ -389,7 +372,7 @@ MSWindowsScreen::sendDragThread(void*)
LOG((CLOG_DEBUG "send dragging file to server"));
client->sendFileToServer(draggingFilename.c_str());
}
-
+
m_draggingStarted = false;
}
@@ -636,7 +619,7 @@ MSWindowsScreen::registerHotKey(KeyID key, KeyModifierMask mask)
LOG((CLOG_WARN "failed to register hotkey %s (id=%04x mask=%04x)", barrier::KeyMap::formatKey(key, mask).c_str(), key, mask));
return 0;
}
-
+
LOG((CLOG_DEBUG "registered hotkey %s (id=%04x mask=%04x) as id=%d", barrier::KeyMap::formatKey(key, mask).c_str(), key, mask, id));
return id;
}
@@ -1114,7 +1097,7 @@ MSWindowsScreen::onKey(WPARAM wParam, LPARAM lParam)
static const KeyModifierMask s_ctrlAlt =
KeyModifierControl | KeyModifierAlt;
- LOG((CLOG_DEBUG1 "event: Key char=%d, vk=0x%02x, nagr=%d, lParam=0x%08x", (wParam & 0xff00u) >> 8, wParam & 0xffu, (wParam & 0x10000u) ? 1 : 0, lParam));
+ LOG((CLOG_DEBUG1 "event: Key char=%d, vk=0x%02x, nagr=%d, lParam=0x%08x", wParam & 0xffffu, (wParam >> 16) & 0xffu, (wParam & 0x1000000u) ? 1 : 0, lParam));
// get event info
KeyButton button = (KeyButton)((lParam & 0x01ff0000) >> 16);
@@ -1132,7 +1115,7 @@ MSWindowsScreen::onKey(WPARAM wParam, LPARAM lParam)
// that maps mouse buttons to keys is known to do this.
// alternatively, we could just throw these events out.
if (button == 0) {
- button = m_keyState->virtualKeyToButton(wParam & 0xffu);
+ button = m_keyState->virtualKeyToButton((wParam >> 16) & 0xffu);
if (button == 0) {
return true;
}
@@ -1198,7 +1181,7 @@ MSWindowsScreen::onKey(WPARAM wParam, LPARAM lParam)
if (!ignore()) {
// check for ctrl+alt+del. we do not want to pass that to the
// client. the user can use ctrl+alt+pause to emulate it.
- UINT virtKey = (wParam & 0xffu);
+ UINT virtKey = (wParam >> 16) & 0xffu;
if (virtKey == VK_DELETE && (state & s_ctrlAlt) == s_ctrlAlt) {
LOG((CLOG_DEBUG "discard ctrl+alt+del"));
return true;
@@ -1212,9 +1195,9 @@ MSWindowsScreen::onKey(WPARAM wParam, LPARAM lParam)
// pressed or released. when mapping the key we require that
// we not use AltGr (the 0x10000 flag in wParam) and we not
// use the keypad delete key (the 0x01000000 flag in lParam).
- wParam = VK_DELETE | 0x00010000u;
+ wParam = (VK_DELETE << 16) | 0x01000000u;
lParam &= 0xfe000000;
- lParam |= m_keyState->virtualKeyToButton(wParam & 0xffu) << 16;
+ lParam |= m_keyState->virtualKeyToButton(VK_DELETE) << 16;
lParam |= 0x01000001;
}
@@ -1242,7 +1225,7 @@ MSWindowsScreen::onHotKey(WPARAM wParam, LPARAM lParam)
{
// get the key info
KeyModifierMask state = getActiveModifiers();
- UINT virtKey = (wParam & 0xffu);
+ UINT virtKey = (wParam >> 16) & 0xffu;
UINT modifiers = 0;
if ((state & KeyModifierShift) != 0) {
modifiers |= MOD_SHIFT;
@@ -1360,7 +1343,7 @@ MSWindowsScreen::onMouseMove(SInt32 mx, SInt32 my)
saveMousePosition(mx, my);
if (m_isOnScreen) {
-
+
// motion on primary screen
sendEvent(
m_events->forIPrimaryScreen().motionOnPrimary(),
@@ -1370,15 +1353,15 @@ MSWindowsScreen::onMouseMove(SInt32 mx, SInt32 my)
m_draggingStarted = true;
}
}
- else
+ else
{
// the motion is on the secondary screen, so we warp mouse back to
- // center on the server screen. if we don't do this, then the mouse
- // will always try to return to the original entry point on the
+ // center on the server screen. if we don't do this, then the mouse
+ // will always try to return to the original entry point on the
// secondary screen.
LOG((CLOG_DEBUG5 "warping server cursor to center: %+d,%+d", m_xCenter, m_yCenter));
warpCursorNoFlush(m_xCenter, m_yCenter);
-
+
// examine the motion. if it's about the distance
// from the center of the screen to an edge then
// it's probably a bogus motion that we want to
@@ -1389,7 +1372,7 @@ MSWindowsScreen::onMouseMove(SInt32 mx, SInt32 my)
x + bogusZoneSize > m_x + m_w - m_xCenter ||
-y + bogusZoneSize > m_yCenter - m_y ||
y + bogusZoneSize > m_y + m_h - m_yCenter) {
-
+
LOG((CLOG_DEBUG "dropped bogus delta motion: %+d,%+d", x, y));
}
else {
@@ -1521,8 +1504,8 @@ MSWindowsScreen::warpCursorNoFlush(SInt32 x, SInt32 y)
POINT cursorPos;
GetCursorPos(&cursorPos);
- // there is a bug or round error in SetCursorPos and GetCursorPos on
- // a high DPI setting. The check here is for Vista/7 login screen.
+ // there is a bug or round error in SetCursorPos and GetCursorPos on
+ // a high DPI setting. The check here is for Vista/7 login screen.
// since this feature is mainly for client, so only check on client.
if (!isPrimary()) {
if ((cursorPos.x != x) && (cursorPos.y != y)) {
@@ -1531,7 +1514,7 @@ MSWindowsScreen::warpCursorNoFlush(SInt32 x, SInt32 y)
// when at Vista/7 login screen, SetCursorPos does not work (which could be
// an MS security feature). instead we can use fakeMouseMove, which calls
// mouse_event.
- // IMPORTANT: as of implementing this function, it has an annoying side
+ // IMPORTANT: as of implementing this function, it has an annoying side
// effect; instead of the mouse returning to the correct exit point, it
// returns to the center of the screen. this could have something to do with
// the center screen warping technique used (see comments for onMouseMove
@@ -1723,7 +1706,7 @@ MSWindowsScreen::mapPressFromEvent(WPARAM msg, LPARAM) const
}
void
-MSWindowsScreen::updateKeysCB(void*)
+MSWindowsScreen::updateKeysCB()
{
// record which keys we think are down
bool down[IKeyState::kNumButtons];
@@ -1888,6 +1871,7 @@ std::string& MSWindowsScreen::getDraggingFilename()
SWP_SHOWWINDOW);
// TODO: fake these keys properly
+ ARCH->sleep(.05f); // A tiny sleep here makes the DragEnter event on m_dropWindow trigger much more consistently
fakeKeyDown(kKeyEscape, 8192, 1);
fakeKeyUp(1);
fakeMouseButton(kButtonLeft, false);
@@ -1909,21 +1893,39 @@ std::string& MSWindowsScreen::getDraggingFilename()
m_draggingFilename = filename;
}
else {
- LOG((CLOG_DEBUG "drag file name is invalid: %s", filename.c_str()));
+ LOG((CLOG_ERR "drag file name is invalid: %s", filename.c_str()));
}
}
if (m_draggingFilename.empty()) {
- LOG((CLOG_DEBUG "failed to get drag file name from OLE"));
+ LOG((CLOG_ERR "failed to get drag file name from OLE"));
}
}
return m_draggingFilename;
}
-const std::string& MSWindowsScreen::getDropTarget() const
+const std::string&
+MSWindowsScreen::getDropTarget() const
+{
+ if (m_dropTargetPath.empty()) {
+ // SHGetFolderPath is deprecated in vista, but use it for xp support.
+ char desktopPath[MAX_PATH];
+ if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_DESKTOP, NULL, 0, desktopPath))) {
+ m_dropTargetPath = std::string(desktopPath);
+ LOG((CLOG_INFO "using desktop for drop target: %s", m_dropTargetPath.c_str()));
+ }
+ else {
+ LOG((CLOG_ERR "failed to get desktop path, no drop target available, error=%d", GetLastError()));
+ }
+ }
+ return m_dropTargetPath;
+}
+
+void
+MSWindowsScreen::setDropTarget(const std::string& target)
{
- return m_desktopPath;
+ m_dropTargetPath = target;
}
bool
@@ -1932,7 +1934,7 @@ MSWindowsScreen::isModifierRepeat(KeyModifierMask oldState, KeyModifierMask stat
bool result = false;
if (oldState == state && state != 0) {
- UINT virtKey = (wParam & 0xffu);
+ UINT virtKey = (wParam >> 16) & 0xffu;
if ((state & KeyModifierShift) != 0
&& (virtKey == VK_LSHIFT || virtKey == VK_RSHIFT)) {
result = true;
diff --git a/src/lib/platform/MSWindowsScreen.h b/src/lib/platform/MSWindowsScreen.h
index 49e09df..eaa7b88 100644
--- a/src/lib/platform/MSWindowsScreen.h
+++ b/src/lib/platform/MSWindowsScreen.h
@@ -3,11 +3,11 @@
* Copyright (C) 2018 Debauchee Open Source Group
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -120,6 +120,7 @@ public:
virtual void fakeDraggingFiles(DragFileList fileList);
virtual std::string& getDraggingFilename();
virtual const std::string& getDropTarget() const;
+ virtual void setDropTarget(const std::string&);
protected:
// IPlatformScreen overrides
@@ -198,7 +199,7 @@ private: // HACK
bool mapPressFromEvent(WPARAM msg, LPARAM button) const;
// job to update the key state
- void updateKeysCB(void*);
+ void updateKeysCB();
// determine whether the mouse is hidden by the system and force
// it to be displayed if user has entered this secondary screen.
@@ -212,16 +213,16 @@ private: // HACK
// our window proc
static LRESULT CALLBACK wndProc(HWND, UINT, WPARAM, LPARAM);
-
+
// save last position of mouse to compute next delta movement
void saveMousePosition(SInt32 x, SInt32 y);
// check if it is a modifier key repeating message
- bool isModifierRepeat(KeyModifierMask oldState,
+ bool isModifierRepeat(KeyModifierMask oldState,
KeyModifierMask state, WPARAM wParam) const;
// send drag info and data back to server
- void sendDragThread(void*);
+ void send_drag_thread();
private:
struct HotKeyItem {
@@ -324,15 +325,15 @@ private:
bool m_gotOldMouseKeys;
MOUSEKEYS m_mouseKeys;
MOUSEKEYS m_oldMouseKeys;
-
+
MSWindowsHook m_hook;
static MSWindowsScreen*
s_screen;
-
+
IEventQueue* m_events;
- std::string m_desktopPath;
+ mutable std::string m_dropTargetPath;
MSWindowsDropTarget*
m_dropTarget;
diff --git a/src/lib/platform/MSWindowsScreenSaver.cpp b/src/lib/platform/MSWindowsScreenSaver.cpp
index f9c15fb..9f93792 100644
--- a/src/lib/platform/MSWindowsScreenSaver.cpp
+++ b/src/lib/platform/MSWindowsScreenSaver.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -23,7 +23,6 @@
#include "arch/Arch.h"
#include "arch/win32/ArchMiscWindows.h"
#include "base/Log.h"
-#include "base/TMethodJob.h"
#include <malloc.h>
#include <tchar.h>
@@ -223,8 +222,7 @@ MSWindowsScreenSaver::watchDesktop()
// watch desktop in another thread
LOG((CLOG_DEBUG "watching screen saver desktop"));
m_active = true;
- m_watch = new Thread(new TMethodJob<MSWindowsScreenSaver>(this,
- &MSWindowsScreenSaver::watchDesktopThread));
+ m_watch = new Thread([this](){ watch_desktop_thread(); });
}
void
@@ -238,8 +236,7 @@ MSWindowsScreenSaver::watchProcess(HANDLE process)
LOG((CLOG_DEBUG "watching screen saver process"));
m_process = process;
m_active = true;
- m_watch = new Thread(new TMethodJob<MSWindowsScreenSaver>(this,
- &MSWindowsScreenSaver::watchProcessThread));
+ m_watch = new Thread([this](){ watch_process_thread(); });
}
}
@@ -260,8 +257,7 @@ MSWindowsScreenSaver::unwatchProcess()
}
}
-void
-MSWindowsScreenSaver::watchDesktopThread(void*)
+void MSWindowsScreenSaver::watch_desktop_thread()
{
DWORD reserved = 0;
TCHAR* name = NULL;
@@ -283,8 +279,7 @@ MSWindowsScreenSaver::watchDesktopThread(void*)
}
}
-void
-MSWindowsScreenSaver::watchProcessThread(void*)
+void MSWindowsScreenSaver::watch_process_thread()
{
for (;;) {
Thread::testCancel();
diff --git a/src/lib/platform/MSWindowsScreenSaver.h b/src/lib/platform/MSWindowsScreenSaver.h
index a117370..4f1dd5f 100644
--- a/src/lib/platform/MSWindowsScreenSaver.h
+++ b/src/lib/platform/MSWindowsScreenSaver.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -64,8 +64,8 @@ private:
void watchDesktop();
void watchProcess(HANDLE process);
void unwatchProcess();
- void watchDesktopThread(void*);
- void watchProcessThread(void*);
+ void watch_desktop_thread();
+ void watch_process_thread();
void setSecure(bool secure, bool saveSecureAsInt);
bool isSecure(bool* wasSecureAnInt) const;
diff --git a/src/lib/platform/MSWindowsSession.cpp b/src/lib/platform/MSWindowsSession.cpp
index 8d4f8ce..daa9276 100644
--- a/src/lib/platform/MSWindowsSession.cpp
+++ b/src/lib/platform/MSWindowsSession.cpp
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2013-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -45,7 +45,7 @@ MSWindowsSession::isProcessInSession(const char* name, PHANDLE process = NULL)
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);
- // get the first process, and if we can't do that then it's
+ // get the first process, and if we can't do that then it's
// unlikely we can go any further
BOOL gotEntry = Process32First(snapshot, &entry);
if (!gotEntry) {
@@ -94,7 +94,7 @@ MSWindowsSession::isProcessInSession(const char* name, PHANDLE process = NULL)
}
std::string nameListJoin;
- for(std::list<std::string>::iterator it = nameList.begin();
+ for (std::list<std::string>::iterator it = nameList.begin();
it != nameList.end(); it++) {
nameListJoin.append(*it);
nameListJoin.append(", ");
@@ -119,7 +119,7 @@ MSWindowsSession::isProcessInSession(const char* name, PHANDLE process = NULL)
}
}
-HANDLE
+HANDLE
MSWindowsSession::getUserToken(LPSECURITY_ATTRIBUTES security)
{
HANDLE sourceToken;
@@ -127,7 +127,7 @@ MSWindowsSession::getUserToken(LPSECURITY_ATTRIBUTES security)
LOG((CLOG_ERR "could not get token from session %d", m_activeSessionId));
throw XArch(new XArchEvalWindows);
}
-
+
HANDLE newToken;
if (!DuplicateTokenEx(
sourceToken, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, security,
@@ -136,7 +136,7 @@ MSWindowsSession::getUserToken(LPSECURITY_ATTRIBUTES security)
LOG((CLOG_ERR "could not duplicate token"));
throw XArch(new XArchEvalWindows);
}
-
+
LOG((CLOG_DEBUG "duplicated, new token: %i", newToken));
return newToken;
}
diff --git a/src/lib/platform/MSWindowsSession.h b/src/lib/platform/MSWindowsSession.h
index e14d7e2..c3fff9d 100644
--- a/src/lib/platform/MSWindowsSession.h
+++ b/src/lib/platform/MSWindowsSession.h
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2013-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -33,7 +33,7 @@ public:
Returns true if the session ID has changed since updateActiveSession was called.
*/
BOOL hasChanged();
-
+
bool isProcessInSession(const char* name, PHANDLE process);
HANDLE getUserToken(LPSECURITY_ATTRIBUTES security);
diff --git a/src/lib/platform/MSWindowsUtil.cpp b/src/lib/platform/MSWindowsUtil.cpp
index b6b809f..5a0778e 100644
--- a/src/lib/platform/MSWindowsUtil.cpp
+++ b/src/lib/platform/MSWindowsUtil.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/MSWindowsUtil.h b/src/lib/platform/MSWindowsUtil.h
index 59f2eac..df80f3f 100644
--- a/src/lib/platform/MSWindowsUtil.h
+++ b/src/lib/platform/MSWindowsUtil.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/MSWindowsWatchdog.cpp b/src/lib/platform/MSWindowsWatchdog.cpp
index 0aa5505..2d9a61c 100644
--- a/src/lib/platform/MSWindowsWatchdog.cpp
+++ b/src/lib/platform/MSWindowsWatchdog.cpp
@@ -6,7 +6,7 @@
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -29,7 +29,6 @@
#include "arch/win32/XArchWindows.h"
#include "arch/Arch.h"
#include "base/log_outputters.h"
-#include "base/TMethodJob.h"
#include "base/Log.h"
#include "common/Version.h"
@@ -81,21 +80,18 @@ MSWindowsWatchdog::MSWindowsWatchdog(
{
}
-void
+void
MSWindowsWatchdog::startAsync()
{
- m_thread = new Thread(new TMethodJob<MSWindowsWatchdog>(
- this, &MSWindowsWatchdog::mainLoop, nullptr));
-
- m_outputThread = new Thread(new TMethodJob<MSWindowsWatchdog>(
- this, &MSWindowsWatchdog::outputLoop, nullptr));
+ m_thread = new Thread([this](){ main_loop(); });
+ m_outputThread = new Thread([this](){ output_loop(); });
}
void
MSWindowsWatchdog::stop()
{
m_monitoring = false;
-
+
m_thread->wait(5);
delete m_thread;
@@ -117,7 +113,7 @@ MSWindowsWatchdog::duplicateProcessToken(HANDLE process, LPSECURITY_ATTRIBUTES s
LOG((CLOG_ERR "could not open token, process handle: %d", process));
throw XArch(new XArchEvalWindows());
}
-
+
LOG((CLOG_DEBUG "got token %i, duplicating", sourceToken));
HANDLE newToken;
@@ -129,22 +125,22 @@ MSWindowsWatchdog::duplicateProcessToken(HANDLE process, LPSECURITY_ATTRIBUTES s
LOG((CLOG_ERR "could not duplicate token %i", sourceToken));
throw XArch(new XArchEvalWindows());
}
-
+
LOG((CLOG_DEBUG "duplicated, new token: %i", newToken));
return newToken;
}
-HANDLE
+HANDLE
MSWindowsWatchdog::getUserToken(LPSECURITY_ATTRIBUTES security)
{
- // always elevate if we are at the vista/7 login screen. we could also
+ // always elevate if we are at the vista/7 login screen. we could also
// elevate for the uac dialog (consent.exe) but this would be pointless,
// since barrier would re-launch as non-elevated after the desk switch,
// and so would be unusable with the new elevated process taking focus.
if (m_elevateProcess || m_autoElevated) {
LOG((CLOG_DEBUG "getting elevated token, %s",
(m_elevateProcess ? "elevation required" : "at login screen")));
-
+
HANDLE process;
if (!m_session.isProcessInSession("winlogon.exe", &process)) {
throw XMSWindowsWatchdogError("cannot get user token without winlogon.exe");
@@ -157,8 +153,7 @@ MSWindowsWatchdog::getUserToken(LPSECURITY_ATTRIBUTES security)
}
}
-void
-MSWindowsWatchdog::mainLoop(void*)
+void MSWindowsWatchdog::main_loop()
{
shutdownExistingProcesses();
@@ -169,10 +164,10 @@ MSWindowsWatchdog::mainLoop(void*)
sendSasFunc = (SendSas)GetProcAddress(sasLib, "SendSAS");
}
- SECURITY_ATTRIBUTES saAttr;
- saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
- saAttr.bInheritHandle = TRUE;
- saAttr.lpSecurityDescriptor = NULL;
+ SECURITY_ATTRIBUTES saAttr;
+ saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
+ saAttr.bInheritHandle = TRUE;
+ saAttr.lpSecurityDescriptor = NULL;
if (!CreatePipe(&m_stdOutRead, &m_stdOutWrite, &saAttr, 0)) {
throw XArch(new XArchEvalWindows());
@@ -196,7 +191,7 @@ MSWindowsWatchdog::mainLoop(void*)
LOG((CLOG_INFO "backing off, wait=%ds, failures=%d", timeout, m_processFailures));
ARCH->sleep(timeout);
}
-
+
if (!getCommand().empty() && ((m_processFailures != 0) || m_session.hasChanged() || m_commandChanged)) {
startProcess();
}
@@ -205,7 +200,7 @@ MSWindowsWatchdog::mainLoop(void*)
m_processFailures++;
m_processRunning = false;
-
+
LOG((CLOG_WARN "detected application not running, pid=%d",
m_processInfo.dwProcessId));
}
@@ -228,7 +223,7 @@ MSWindowsWatchdog::mainLoop(void*)
// if the sas event failed, wait by sleeping.
ARCH->sleep(1);
-
+
}
catch (std::exception& e) {
LOG((CLOG_ERR "failed to launch, error: %s", e.what()));
@@ -248,7 +243,7 @@ MSWindowsWatchdog::mainLoop(void*)
LOG((CLOG_DEBUG "terminated running process on exit"));
shutdownProcess(m_processInfo.hProcess, m_processInfo.dwProcessId, 20);
}
-
+
LOG((CLOG_DEBUG "watchdog main thread finished"));
}
@@ -260,7 +255,7 @@ MSWindowsWatchdog::isProcessActive()
return exitCode == STILL_ACTIVE;
}
-void
+void
MSWindowsWatchdog::setFileLogOutputter(FileLogOutputter* outputter)
{
m_fileLogOutputter = outputter;
@@ -367,7 +362,7 @@ BOOL MSWindowsWatchdog::doStartProcessAsUser(std::string& command, HANDLE userTo
throw XArch(new XArchEvalWindows);
}
- DWORD creationFlags =
+ DWORD creationFlags =
NORMAL_PRIORITY_CLASS |
CREATE_NO_WINDOW |
CREATE_UNICODE_ENVIRONMENT;
@@ -421,14 +416,13 @@ MSWindowsWatchdog::getCommand() const
return cmd;
}
-void
-MSWindowsWatchdog::outputLoop(void*)
+void MSWindowsWatchdog::output_loop()
{
// +1 char for \0
CHAR buffer[kOutputBufferSize + 1];
while (m_monitoring) {
-
+
DWORD bytesRead;
BOOL success = ReadFile(m_stdOutRead, buffer, kOutputBufferSize, &bytesRead, NULL);
@@ -443,7 +437,7 @@ MSWindowsWatchdog::outputLoop(void*)
if (m_fileLogOutputter != NULL) {
m_fileLogOutputter->write(kINFO, buffer);
}
- }
+ }
}
}
@@ -470,7 +464,7 @@ MSWindowsWatchdog::shutdownProcess(HANDLE handle, DWORD pid, int timeout)
break;
}
else {
-
+
double elapsed = (ARCH->time() - start);
if (elapsed > timeout) {
// if timeout reached, kill forcefully.
@@ -500,7 +494,7 @@ MSWindowsWatchdog::shutdownExistingProcesses()
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);
- // get the first process, and if we can't do that then it's
+ // get the first process, and if we can't do that then it's
// unlikely we can go any further
BOOL gotEntry = Process32First(snapshot, &entry);
if (!gotEntry) {
@@ -517,7 +511,7 @@ MSWindowsWatchdog::shutdownExistingProcesses()
if (_stricmp(entry.szExeFile, "barrierc.exe") == 0 ||
_stricmp(entry.szExeFile, "barriers.exe") == 0) {
-
+
HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);
shutdownProcess(handle, entry.th32ProcessID, 10);
}
diff --git a/src/lib/platform/MSWindowsWatchdog.h b/src/lib/platform/MSWindowsWatchdog.h
index 0a81521..0595ca0 100644
--- a/src/lib/platform/MSWindowsWatchdog.h
+++ b/src/lib/platform/MSWindowsWatchdog.h
@@ -6,7 +6,7 @@
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -48,8 +48,8 @@ public:
void setFileLogOutputter(FileLogOutputter* outputter);
private:
- void mainLoop(void*);
- void outputLoop(void*);
+ void main_loop();
+ void output_loop();
void shutdownProcess(HANDLE handle, DWORD pid, int timeout);
void shutdownExistingProcesses();
HANDLE duplicateProcessToken(HANDLE process, LPSECURITY_ATTRIBUTES security);
@@ -81,7 +81,7 @@ private:
//! Relauncher error
/*!
-An error occured in the process watchdog.
+An error occurred in the process watchdog.
*/
class XMSWindowsWatchdogError : public XBarrier {
public:
diff --git a/src/lib/platform/OSXClipboard.cpp b/src/lib/platform/OSXClipboard.cpp
index e55c8e0..ff1779c 100644
--- a/src/lib/platform/OSXClipboard.cpp
+++ b/src/lib/platform/OSXClipboard.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -52,7 +52,7 @@ OSXClipboard::OSXClipboard() :
OSStatus syncErr = PasteboardSynchronize(m_pboard);
if (syncErr != noErr) {
- LOG((CLOG_DEBUG "failed to syncronize clipboard: error %i", syncErr));
+ LOG((CLOG_DEBUG "failed to synchronize clipboard: error %i", syncErr));
}
}
@@ -90,7 +90,7 @@ OSXClipboard::synchronize()
return true;
}
return false;
-}
+}
void OSXClipboard::add(EFormat format, const std::string& data)
{
@@ -126,15 +126,15 @@ void OSXClipboard::add(EFormat format, const std::string& data)
flavorType,
dataRef,
kPasteboardFlavorNoFlags);
-
+
LOG((CLOG_DEBUG "added %d bytes to clipboard format: %d", data.size(), format));
}
-
+
}
}
bool
-OSXClipboard::open(Time time) const
+OSXClipboard::open(Time time) const
{
if (m_pboard == NULL)
return false;
diff --git a/src/lib/platform/OSXClipboard.h b/src/lib/platform/OSXClipboard.h
index b1f9801..9d66600 100644
--- a/src/lib/platform/OSXClipboard.h
+++ b/src/lib/platform/OSXClipboard.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/OSXClipboardAnyTextConverter.cpp b/src/lib/platform/OSXClipboardAnyTextConverter.cpp
index ae8dc4a..2513db5 100644
--- a/src/lib/platform/OSXClipboardAnyTextConverter.cpp
+++ b/src/lib/platform/OSXClipboardAnyTextConverter.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/OSXClipboardAnyTextConverter.h b/src/lib/platform/OSXClipboardAnyTextConverter.h
index f057bae..987f2c5 100644
--- a/src/lib/platform/OSXClipboardAnyTextConverter.h
+++ b/src/lib/platform/OSXClipboardAnyTextConverter.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/OSXClipboardHTMLConverter.cpp b/src/lib/platform/OSXClipboardHTMLConverter.cpp
index 46a3d0f..0a2f5ec 100644
--- a/src/lib/platform/OSXClipboardHTMLConverter.cpp
+++ b/src/lib/platform/OSXClipboardHTMLConverter.cpp
@@ -66,7 +66,7 @@ std::string OSXClipboardHTMLConverter::convertString(const std::string& data,
CFRelease(stringRef);
return {};
}
-
+
CFStringGetBytes(stringRef, entireString, toEncoding,
0, false, (UInt8*)buffer, buffSize, NULL);
diff --git a/src/lib/platform/OSXClipboardTextConverter.cpp b/src/lib/platform/OSXClipboardTextConverter.cpp
index a68258d..a4fb6ae 100644
--- a/src/lib/platform/OSXClipboardTextConverter.cpp
+++ b/src/lib/platform/OSXClipboardTextConverter.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -24,7 +24,7 @@
// OSXClipboardTextConverter
//
-OSXClipboardTextConverter::OSXClipboardTextConverter()
+OSXClipboardTextConverter::OSXClipboardTextConverter()
{
// do nothing
}
@@ -59,12 +59,12 @@ std::string OSXClipboardTextConverter::convertString(const std::string& data,
0, false, NULL, 0, &buffSize);
char* buffer = new char[buffSize];
-
+
if (buffer == NULL) {
CFRelease(stringRef);
return {};
}
-
+
CFStringGetBytes(stringRef, entireString, toEncoding,
0, false, (UInt8*)buffer, buffSize, NULL);
@@ -72,7 +72,7 @@ std::string OSXClipboardTextConverter::convertString(const std::string& data,
delete[] buffer;
CFRelease(stringRef);
-
+
return result;
}
diff --git a/src/lib/platform/OSXClipboardTextConverter.h b/src/lib/platform/OSXClipboardTextConverter.h
index 8211f1e..5a4b51f 100644
--- a/src/lib/platform/OSXClipboardTextConverter.h
+++ b/src/lib/platform/OSXClipboardTextConverter.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/OSXClipboardUTF16Converter.cpp b/src/lib/platform/OSXClipboardUTF16Converter.cpp
index 8411e92..4f13cc0 100644
--- a/src/lib/platform/OSXClipboardUTF16Converter.cpp
+++ b/src/lib/platform/OSXClipboardUTF16Converter.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/OSXClipboardUTF16Converter.h b/src/lib/platform/OSXClipboardUTF16Converter.h
index b279c99..5e448df 100644
--- a/src/lib/platform/OSXClipboardUTF16Converter.h
+++ b/src/lib/platform/OSXClipboardUTF16Converter.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/OSXDragSimulator.h b/src/lib/platform/OSXDragSimulator.h
index cb361ca..6dd73f4 100644
--- a/src/lib/platform/OSXDragSimulator.h
+++ b/src/lib/platform/OSXDragSimulator.h
@@ -28,7 +28,7 @@ void runCocoaApp();
void stopCocoaLoop();
void fakeDragging(const char* str, int cursorX, int cursorY);
CFStringRef getCocoaDropTarget();
-
+
#if defined(__cplusplus)
}
#endif
diff --git a/src/lib/platform/OSXDragSimulator.m b/src/lib/platform/OSXDragSimulator.mm
index affed38..735aa4a 100644
--- a/src/lib/platform/OSXDragSimulator.m
+++ b/src/lib/platform/OSXDragSimulator.mm
@@ -30,9 +30,9 @@ void
runCocoaApp()
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
-
+
[NSApplication sharedApplication];
-
+
NSWindow* window = [[NSWindow alloc]
initWithContentRect: NSMakeRect(0, 0, 3, 3)
styleMask: NSBorderlessWindowMask
@@ -41,16 +41,16 @@ runCocoaApp()
[window setTitle: @""];
[window setAlphaValue:0.1];
[window makeKeyAndOrderFront:nil];
-
+
OSXDragView* dragView = [[OSXDragView alloc] initWithFrame:NSMakeRect(0, 0, 3, 3)];
-
+
g_dragWindow = window;
g_dragView = dragView;
[window setContentView: dragView];
-
+
NSLog(@"starting cocoa loop");
[NSApp run];
-
+
NSLog(@"cocoa: release");
[pool release];
}
@@ -65,25 +65,25 @@ void
fakeDragging(const char* str, int cursorX, int cursorY)
{
g_ext = [NSString stringWithUTF8String:str];
-
+
dispatch_async(dispatch_get_main_queue(), ^{
NSRect screen = [[NSScreen mainScreen] frame];
- NSLog ( @"screen size: witdh = %f height = %f", screen.size.width, screen.size.height);
+ NSLog ( @"screen size: width = %f height = %f", screen.size.width, screen.size.height);
NSLog ( @"mouseLocation: %d %d", cursorX, cursorY);
-
+
int newPosX = 0;
int newPosY = 0;
newPosX = cursorX - 1;
newPosY = screen.size.height - cursorY - 1;
-
+
NSRect rect = NSMakeRect(newPosX, newPosY, 3, 3);
NSLog ( @"newPosX: %d", newPosX);
NSLog ( @"newPosY: %d", newPosY);
-
+
[g_dragWindow setFrame:rect display:NO];
[g_dragWindow makeKeyAndOrderFront:nil];
[NSApp activateIgnoringOtherApps:YES];
-
+
[g_dragView setFileExt:g_ext];
CGEventRef down = CGEventCreateMouseEvent(CGEventSourceCreate(kCGEventSourceStateHIDSystemState), kCGEventLeftMouseDown, CGPointMake(cursorX, cursorY), kCGMouseButtonLeft);
diff --git a/src/lib/platform/OSXDragView.m b/src/lib/platform/OSXDragView.mm
index 67dac56..67dac56 100644
--- a/src/lib/platform/OSXDragView.m
+++ b/src/lib/platform/OSXDragView.mm
diff --git a/src/lib/platform/OSXEventQueueBuffer.cpp b/src/lib/platform/OSXEventQueueBuffer.cpp
index 8e18afc..e012c89 100644
--- a/src/lib/platform/OSXEventQueueBuffer.cpp
+++ b/src/lib/platform/OSXEventQueueBuffer.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -83,11 +83,11 @@ OSXEventQueueBuffer::getEvent(Event& event, UInt32& dataID)
else {
UInt32 eventClass = GetEventClass(m_event);
switch (eventClass) {
- case 'Syne':
+ case 'Syne':
dataID = GetEventKind(m_event);
return kUser;
- default:
+ default:
event = Event(Event::kSystem,
m_eventQueue->getSystemTarget(), &m_event);
return kSystem;
@@ -101,24 +101,24 @@ OSXEventQueueBuffer::addEvent(UInt32 dataID)
EventRef event;
OSStatus error = CreateEvent(
kCFAllocatorDefault,
- 'Syne',
+ 'Syne',
dataID,
0,
kEventAttributeNone,
&event);
if (error == noErr) {
-
+
assert(m_carbonEventQueue != NULL);
-
+
error = PostEventToQueue(
m_carbonEventQueue,
event,
kEventPriorityStandard);
-
+
ReleaseEvent(event);
}
-
+
return (error == noErr);
}
diff --git a/src/lib/platform/OSXEventQueueBuffer.h b/src/lib/platform/OSXEventQueueBuffer.h
index 28c4a5d..8e0c903 100644
--- a/src/lib/platform/OSXEventQueueBuffer.h
+++ b/src/lib/platform/OSXEventQueueBuffer.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/OSXKeyState.cpp b/src/lib/platform/OSXKeyState.cpp
index 9db3c5d..aad2072 100644
--- a/src/lib/platform/OSXKeyState.cpp
+++ b/src/lib/platform/OSXKeyState.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -43,6 +43,9 @@ static const UInt32 s_launchpadVK = 131;
static const UInt32 s_osxNumLock = 1 << 16;
+static const UInt32 s_int4VK = 0x8a; // international4
+static const UInt32 s_int5VK = 0x8b; // international5
+
struct KeyEntry {
public:
KeyID m_keyID;
@@ -97,7 +100,7 @@ static const KeyEntry s_controlKeys[] = {
{ kKeyKP_Divide, kVK_ANSI_KeypadDivide },
{ kKeyKP_Subtract, kVK_ANSI_KeypadMinus },
{ kKeyKP_Enter, kVK_ANSI_KeypadEnter },
-
+
// virtual key 110 is fn+enter and i have no idea what that's supposed
// to map to. also the enter key with numlock on is a modifier but i
// don't know which.
@@ -118,11 +121,18 @@ static const KeyEntry s_controlKeys[] = {
// toggle modifiers
{ kKeyNumLock, s_numLockVK },
{ kKeyCapsLock, s_capsLockVK },
-
+
{ kKeyMissionControl, s_missionControlVK },
{ kKeyLaunchpad, s_launchpadVK },
{ kKeyBrightnessUp, s_brightnessUp },
- { kKeyBrightnessDown, s_brightnessDown }
+ { kKeyBrightnessDown, s_brightnessDown },
+
+ // JIS keyboards only
+ { kKeyEisuToggle, kVK_JIS_Eisu },
+ { kKeyKana, kVK_JIS_Kana },
+ { kKeyMuhenkan, s_int5VK },
+ { kKeyHenkan, s_int4VK },
+ { kKeyZenkaku, kVK_ANSI_Grave }
};
@@ -159,7 +169,7 @@ OSXKeyState::init()
// build virtual key map
for (size_t i = 0; i < sizeof(s_controlKeys) / sizeof(s_controlKeys[0]);
++i) {
-
+
m_virtualKeyMap[s_controlKeys[i].m_virtualKey] =
s_controlKeys[i].m_keyID;
}
@@ -214,11 +224,11 @@ OSXKeyState::mapModifiersToCarbon(UInt32 mask) const
if ((mask & kCGEventFlagMaskNumericPad) != 0) {
outMask |= s_osxNumLock;
}
-
+
return outMask;
}
-KeyButton
+KeyButton
OSXKeyState::mapKeyFromEvent(KeyIDs& ids,
KeyModifierMask* maskOut, CGEventRef event) const
{
@@ -253,7 +263,7 @@ OSXKeyState::mapKeyFromEvent(KeyIDs& ids,
}
// get keyboard info
- TISInputSourceRef currentKeyboardLayout = TISCopyCurrentKeyboardLayoutInputSource();
+ TISInputSourceRef currentKeyboardLayout = TISCopyCurrentKeyboardLayoutInputSource();
if (currentKeyboardLayout == NULL) {
return kKeyNone;
@@ -338,27 +348,27 @@ CGEventFlags
OSXKeyState::getModifierStateAsOSXFlags()
{
CGEventFlags modifiers = CGEventFlags(0);
-
+
if (m_shiftPressed) {
modifiers |= CGEventFlags(kCGEventFlagMaskShift);
}
-
+
if (m_controlPressed) {
modifiers |= CGEventFlags(kCGEventFlagMaskControl);
}
-
+
if (m_altPressed) {
modifiers |= CGEventFlags(kCGEventFlagMaskAlternate);
}
-
+
if (m_superPressed) {
modifiers |= CGEventFlags(kCGEventFlagMaskCommand);
}
-
+
if (m_capsPressed) {
modifiers |= CGEventFlags(kCGEventFlagMaskAlphaShift);
}
-
+
return modifiers;
}
@@ -400,12 +410,12 @@ OSXKeyState::pollActiveGroup() const
TISInputSourceRef keyboardLayout = TISCopyCurrentKeyboardLayoutInputSource();
CFDataRef id = (CFDataRef)TISGetInputSourceProperty(
keyboardLayout, kTISPropertyInputSourceID);
-
+
GroupMap::const_iterator i = m_groupMap.find(id);
if (i != m_groupMap.end()) {
return i->second;
}
-
+
LOG((CLOG_DEBUG "can't get the active group, use the first group instead"));
return 0;
@@ -447,7 +457,7 @@ OSXKeyState::getKeyMap(barrier::KeyMap& keyMap)
const void* resource;
bool layoutValid = false;
-
+
// add regular keys
// try uchr resource first
CFDataRef resourceRef = (CFDataRef)TISGetInputSourceProperty(
@@ -475,19 +485,19 @@ static io_connect_t getEventDriver(void)
static mach_port_t sEventDrvrRef = 0;
mach_port_t masterPort, service, iter;
kern_return_t kr;
-
+
if (!sEventDrvrRef) {
// Get master device port
kr = IOMasterPort(bootstrap_port, &masterPort);
assert(KERN_SUCCESS == kr);
-
+
kr = IOServiceGetMatchingServices(masterPort,
IOServiceMatching(kIOHIDSystemClass), &iter);
assert(KERN_SUCCESS == kr);
-
+
service = IOIteratorNext(iter);
assert(service);
-
+
kr = IOServiceOpen(service, mach_task_self(),
kIOHIDParamConnectType, &sEventDrvrRef);
assert(KERN_SUCCESS == kr);
@@ -495,7 +505,7 @@ static io_connect_t getEventDriver(void)
IOObjectRelease(service);
IOObjectRelease(iter);
}
-
+
return sEventDrvrRef;
}
@@ -504,7 +514,7 @@ OSXKeyState::postHIDVirtualKey(const UInt8 virtualKeyCode,
const bool postDown)
{
static UInt32 modifiers = 0;
-
+
NXEventData event;
IOGPoint loc = { 0, 0 };
UInt32 modifiersDelta = 0;
@@ -541,7 +551,7 @@ OSXKeyState::postHIDVirtualKey(const UInt8 virtualKeyCode,
m_capsPressed = postDown;
break;
}
-
+
// update the modifier bit
if (postDown) {
modifiers |= modifiersDelta;
@@ -549,7 +559,7 @@ OSXKeyState::postHIDVirtualKey(const UInt8 virtualKeyCode,
else {
modifiers &= ~modifiersDelta;
}
-
+
kern_return_t kr;
event.key.keyCode = virtualKeyCode;
kr = IOHIDPostEvent(getEventDriver(), NX_FLAGSCHANGED, loc,
@@ -575,11 +585,11 @@ OSXKeyState::fakeKey(const Keystroke& keystroke)
{
switch (keystroke.m_type) {
case Keystroke::kButton: {
-
+
KeyButton button = keystroke.m_data.m_button.m_button;
bool keyDown = keystroke.m_data.m_button.m_press;
CGKeyCode virtualKey = mapKeyButtonToVirtualKey(button);
-
+
LOG((CLOG_DEBUG1
" button=0x%04x virtualKey=0x%04x keyDown=%s",
button, virtualKey, keyDown ? "down" : "up"));
@@ -763,7 +773,7 @@ OSXKeyState::mapBarrierHotKeyToMac(KeyID key, KeyModifierMask mask,
return false;
}
macVirtualKey = mapKeyButtonToVirtualKey(button);
-
+
// calculate modifier mask
macModifierMask = 0;
if ((mask & KeyModifierShift) != 0) {
@@ -784,10 +794,10 @@ OSXKeyState::mapBarrierHotKeyToMac(KeyID key, KeyModifierMask mask,
if ((mask & KeyModifierNumLock) != 0) {
macModifierMask |= s_osxNumLock;
}
-
+
return true;
}
-
+
void
OSXKeyState::handleModifierKeys(void* target,
KeyModifierMask oldMask, KeyModifierMask newMask)
@@ -855,7 +865,7 @@ OSXKeyState::getGroups(GroupList& groups) const
groups.clear();
for (CFIndex i = 0; i < n; ++i) {
bool addToGroups = true;
- TISInputSourceRef keyboardLayout =
+ TISInputSourceRef keyboardLayout =
(TISInputSourceRef)CFArrayGetValueAtIndex(kbds, i);
if (addToGroups)
diff --git a/src/lib/platform/OSXKeyState.h b/src/lib/platform/OSXKeyState.h
index 4d92860..e688394 100644
--- a/src/lib/platform/OSXKeyState.h
+++ b/src/lib/platform/OSXKeyState.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -67,7 +67,7 @@ public:
Still required in a few places for translation calls.
*/
KeyModifierMask mapModifiersToCarbon(UInt32 mask) const;
-
+
//! Map key event to keys
/*!
Converts a key event into a sequence of KeyIDs and the shadow modifier
@@ -149,7 +149,7 @@ private:
static UInt32 mapKeyButtonToVirtualKey(KeyButton keyButton);
void init();
-
+
// Post a key event to HID manager. It posts an event to HID client, a
// much lower level than window manager which's the target from carbon
// CGEventPost
diff --git a/src/lib/platform/OSXMediaKeySimulator.m b/src/lib/platform/OSXMediaKeySimulator.mm
index 5aacd10..efc4251 100644
--- a/src/lib/platform/OSXMediaKeySimulator.m
+++ b/src/lib/platform/OSXMediaKeySimulator.mm
@@ -85,8 +85,8 @@ fakeNativeMediaKey(KeyID id)
data2:-1];
CGEventRef upEvent = [upRef CGEvent];
- CGEventPost(0, downEvent);
- CGEventPost(0, upEvent);
+ CGEventPost(kCGHIDEventTap, downEvent);
+ CGEventPost(kCGHIDEventTap, upEvent);
return true;
}
diff --git a/src/lib/platform/OSXMediaKeySupport.m b/src/lib/platform/OSXMediaKeySupport.mm
index 9c9dbc3..a4d5767 100644
--- a/src/lib/platform/OSXMediaKeySupport.m
+++ b/src/lib/platform/OSXMediaKeySupport.mm
@@ -147,8 +147,8 @@ fakeNativeMediaKey(KeyID id)
data2:-1];
CGEventRef upEvent = [upRef CGEvent];
- CGEventPost(0, downEvent);
- CGEventPost(0, upEvent);
+ CGEventPost(kCGHIDEventTap, downEvent);
+ CGEventPost(kCGHIDEventTap, upEvent);
return true;
}
diff --git a/src/lib/platform/OSXPasteboardPeeker.h b/src/lib/platform/OSXPasteboardPeeker.h
index 5105262..b69dba8 100644
--- a/src/lib/platform/OSXPasteboardPeeker.h
+++ b/src/lib/platform/OSXPasteboardPeeker.h
@@ -26,7 +26,7 @@ extern "C" {
#endif
CFStringRef getDraggedFileURL();
-
+
#if defined(__cplusplus)
}
#endif
diff --git a/src/lib/platform/OSXPasteboardPeeker.m b/src/lib/platform/OSXPasteboardPeeker.mm
index ab39e26..ab39e26 100644
--- a/src/lib/platform/OSXPasteboardPeeker.m
+++ b/src/lib/platform/OSXPasteboardPeeker.mm
diff --git a/src/lib/platform/OSXScreen.h b/src/lib/platform/OSXScreen.h
index 68c7c68..691b74c 100644
--- a/src/lib/platform/OSXScreen.h
+++ b/src/lib/platform/OSXScreen.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -37,7 +37,7 @@ extern "C" {
typedef int CGSConnectionID;
CGError CGSSetConnectionProperty(CGSConnectionID cid, CGSConnectionID targetCID, CFStringRef key, CFTypeRef value);
int _CGSDefaultConnection();
-}
+}
template <class T>
@@ -98,10 +98,10 @@ public:
virtual bool isPrimary() const;
virtual void fakeDraggingFiles(DragFileList fileList);
virtual std::string& getDraggingFilename();
-
+
const std::string& getDropTarget() const { return m_dropTarget; }
void waitForCarbonLoop() const;
-
+
protected:
// IPlatformScreen overrides
virtual void handleSystemEvent(const Event&, void*);
@@ -112,7 +112,7 @@ private:
void updateScreenShape();
void updateScreenShape(const CGDirectDisplayID, const CGDisplayChangeSummaryFlags);
void postMouseEvent(CGPoint&) const;
-
+
// convenience function to send events
void sendEvent(Event::Type type, void* = NULL) const;
void sendClipboardEvent(Event::Type type, ClipboardID id) const;
@@ -124,16 +124,16 @@ private:
// of the button pressed using the mac button mapping.
bool onMouseButton(bool pressed, UInt16 macButton);
bool onMouseWheel(SInt32 xDelta, SInt32 yDelta) const;
-
+
void constructMouseButtonEventMap();
bool onKey(CGEventRef event);
void onMediaKey(CGEventRef event);
-
+
bool onHotKey(EventRef event) const;
-
- // Added here to allow the carbon cursor hack to be called.
+
+ // Added here to allow the carbon cursor hack to be called.
void showCursor();
void hideCursor();
@@ -172,9 +172,9 @@ private:
static pascal OSStatus
userSwitchCallback(EventHandlerCallRef nextHandler,
EventRef theEvent, void* inUserData);
-
+
// sleep / wakeup support
- void watchSystemPowerThread(void*);
+ void watchSystemPowerThread();
static void testCanceled(CFRunLoopTimerRef timer, void*info);
static void powerChangeCallback(void* refcon, io_service_t service,
natural_t messageType, void* messageArgument);
@@ -182,12 +182,12 @@ private:
void* messageArgument);
void handleConfirmSleep(const Event& event, void*);
-
+
// global hotkey operating mode
static bool isGlobalHotKeyOperatingModeAvailable();
static void setGlobalHotKeysEnabled(bool enabled);
static bool getGlobalHotKeysEnabled();
-
+
// Quartz event tap support
static CGEventRef handleCGInputEvent(CGEventTapProxy proxy,
CGEventType type,
@@ -197,12 +197,12 @@ private:
CGEventType type,
CGEventRef event,
void* refcon);
-
+
// convert CFString to char*
static char* CFStringRefToUTF8String(CFStringRef aString);
-
- void getDropTargetThread(void*);
-
+
+ void get_drop_target_thread();
+
private:
struct HotKeyItem {
public:
@@ -225,13 +225,13 @@ private:
kMouseButtonDown,
kMouseButtonStateMax
};
-
+
class MouseButtonState {
public:
void set(UInt32 button, EMouseButtonState state);
bool any();
- void reset();
+ void reset();
void overwrite(UInt32 buttons);
bool test(UInt32 button) const;
@@ -262,7 +262,7 @@ private:
// mouse state
mutable SInt32 m_xCursor, m_yCursor;
mutable bool m_cursorPosValid;
-
+
/* FIXME: this data structure is explicitly marked mutable due
to a need to track the state of buttons since the remote
side only lets us know of change events, and because the
@@ -321,7 +321,7 @@ private:
// global hotkey operating mode
static bool s_testedForGHOM;
static bool s_hasGHOM;
-
+
// Quartz input event support
CFMachPortRef m_eventTapPort;
CFRunLoopSourceRef m_eventTapRLSR;
@@ -336,10 +336,10 @@ private:
bool m_autoShowHideCursor;
IEventQueue* m_events;
-
+
Thread* m_getDropTargetThread;
std::string m_dropTarget;
-
+
#if defined(MAC_OS_X_VERSION_10_7)
Mutex* m_carbonLoopMutex;
CondVar<bool>* m_carbonLoopReady;
diff --git a/src/lib/platform/OSXScreen.mm b/src/lib/platform/OSXScreen.mm
index 2b4594f..d41e321 100644
--- a/src/lib/platform/OSXScreen.mm
+++ b/src/lib/platform/OSXScreen.mm
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -38,7 +38,6 @@
#include "base/Log.h"
#include "base/IEventQueue.h"
#include "base/TMethodEventJob.h"
-#include "base/TMethodJob.h"
#include <math.h>
#include <mach-o/dyld.h>
@@ -110,10 +109,10 @@ OSXScreen::OSXScreen(IEventQueue* events, bool isPrimary, bool autoShowHideCurso
updateScreenShape(m_displayID, 0);
m_screensaver = new OSXScreenSaver(m_events, getEventTarget());
m_keyState = new OSXKeyState(m_events);
-
+
// only needed when running as a server.
if (m_isPrimary) {
-
+
#if defined(MAC_OS_X_VERSION_10_9)
// we can't pass options to show the dialog, this must be done by the gui.
if (!AXIsProcessTrusted()) {
@@ -126,7 +125,7 @@ OSXScreen::OSXScreen(IEventQueue* events, bool isPrimary, bool autoShowHideCurso
}
#endif
}
-
+
// install display manager notification handler
CGDisplayRegisterReconfigurationCallback(displayReconfigurationCallback, this);
@@ -157,8 +156,7 @@ OSXScreen::OSXScreen(IEventQueue* events, bool isPrimary, bool autoShowHideCurso
m_carbonLoopReady = new CondVar<bool>(m_carbonLoopMutex, false);
#endif
LOG((CLOG_DEBUG "starting watchSystemPowerThread"));
- m_pmWatchThread = new Thread(new TMethodJob<OSXScreen>
- (this, &OSXScreen::watchSystemPowerThread));
+ m_pmWatchThread = new Thread([this](){ watchSystemPowerThread(); });
}
catch (...) {
m_events->removeHandler(m_events->forOSXScreen().confirmSleep(),
@@ -166,7 +164,7 @@ OSXScreen::OSXScreen(IEventQueue* events, bool isPrimary, bool autoShowHideCurso
if (m_switchEventHandlerRef != 0) {
RemoveEventHandler(m_switchEventHandlerRef);
}
-
+
CGDisplayRemoveReconfigurationCallback(displayReconfigurationCallback, this);
delete m_keyState;
@@ -217,7 +215,7 @@ OSXScreen::~OSXScreen()
delete m_keyState;
delete m_screensaver;
-
+
#if defined(MAC_OS_X_VERSION_10_7)
delete m_carbonLoopMutex;
delete m_carbonLoopReady;
@@ -273,7 +271,7 @@ OSXScreen::warpCursor(SInt32 x, SInt32 y)
pos.x = x;
pos.y = y;
CGWarpMouseCursorPosition(pos);
-
+
// save new cursor position
m_xCursor = x;
m_yCursor = y;
@@ -325,7 +323,7 @@ OSXScreen::registerHotKey(KeyID key, KeyModifierMask mask)
LOG((CLOG_DEBUG "could not map hotkey id=%04x mask=%04x", key, mask));
return 0;
}
-
+
// choose hotkey id
UInt32 id;
if (!m_oldHotKeyIDs.empty()) {
@@ -351,7 +349,7 @@ OSXScreen::registerHotKey(KeyID key, KeyModifierMask mask)
}
else {
EventHotKeyID hkid = { 'SNRG', (UInt32)id };
- OSStatus status = RegisterEventHotKey(macKey, macMask, hkid,
+ OSStatus status = RegisterEventHotKey(macKey, macMask, hkid,
GetApplicationEventTarget(), 0,
&ref);
okay = (status == noErr);
@@ -366,7 +364,7 @@ OSXScreen::registerHotKey(KeyID key, KeyModifierMask mask)
}
m_hotKeys.insert(std::make_pair(id, HotKeyItem(ref, macKey, macMask)));
-
+
LOG((CLOG_DEBUG "registered hotkey %s (id=%04x mask=%04x) as id=%d", barrier::KeyMap::formatKey(key, mask).c_str(), key, mask, id));
return id;
}
@@ -468,7 +466,7 @@ OSXScreen::postMouseEvent(CGPoint& pos) const
}
}
}
-
+
CGEventType type = kCGEventMouseMoved;
SInt8 button = m_buttonState.getFirstButtonDown();
@@ -478,10 +476,10 @@ OSXScreen::postMouseEvent(CGPoint& pos) const
}
CGEventRef event = CGEventCreateMouseEvent(NULL, type, pos, static_cast<CGMouseButton>(button));
-
+
// Dragging events also need the click state
CGEventSetIntegerValueField(event, kCGMouseEventClickState, m_clickState);
-
+
// Fix for sticky keys
CGEventFlags modifiers = m_keyState->getModifierStateAsOSXFlags();
CGEventSetFlags(event, modifiers);
@@ -503,7 +501,7 @@ OSXScreen::postMouseEvent(CGPoint& pos) const
CGEventSetDoubleValueField(event, kCGMouseEventDeltaY, deltaFY);
CGEventPost(kCGHIDEventTap, event);
-
+
CFRelease(event);
}
@@ -515,7 +513,7 @@ OSXScreen::fakeMouseButton(ButtonID id, bool press)
if (index >= NumButtonIDs) {
return;
}
-
+
CGPoint pos;
if (!m_cursorPosValid) {
SInt32 x, y;
@@ -533,79 +531,77 @@ OSXScreen::fakeMouseButton(ButtonID id, bool press)
// since we don't have double click distance in NX APIs
// we define our own defaults.
const double maxDiff = sqrt(2) + 0.0001;
-
+
double clickTime = [NSEvent doubleClickInterval];
-
+
// As long as the click is within the time window and distance window
// increase clickState (double click, triple click, etc)
- // This will allow for higher than triple click but the quartz documenation
+ // This will allow for higher than triple click but the quartz documentation
// does not specify that this should be limited to triple click
if (press) {
- if ((ARCH->time() - m_lastClickTime) <= clickTime && diff <= maxDiff){
+ if ((ARCH->time() - m_lastClickTime) <= clickTime && diff <= maxDiff) {
m_clickState++;
}
else {
m_clickState = 1;
}
-
+
m_lastClickTime = ARCH->time();
}
-
- if (m_clickState == 1){
+
+ if (m_clickState == 1) {
m_lastSingleClickXCursor = m_xCursor;
m_lastSingleClickYCursor = m_yCursor;
}
-
+
EMouseButtonState state = press ? kMouseButtonDown : kMouseButtonUp;
-
+
LOG((CLOG_DEBUG1 "faking mouse button id: %d press: %s", index, press ? "pressed" : "released"));
-
+
MouseButtonEventMapType thisButtonMap = MouseButtonEventMap[index];
CGEventType type = thisButtonMap[state];
CGEventRef event = CGEventCreateMouseEvent(NULL, type, pos, static_cast<CGMouseButton>(index));
-
+
CGEventSetIntegerValueField(event, kCGMouseEventClickState, m_clickState);
-
+
// Fix for sticky keys
CGEventFlags modifiers = m_keyState->getModifierStateAsOSXFlags();
CGEventSetFlags(event, modifiers);
-
+
m_buttonState.set(index, state);
CGEventPost(kCGHIDEventTap, event);
-
+
CFRelease(event);
-
+
if (!press && (id == kButtonLeft)) {
if (m_fakeDraggingStarted) {
- m_getDropTargetThread = new Thread(new TMethodJob<OSXScreen>(
- this, &OSXScreen::getDropTargetThread));
+ m_getDropTargetThread = new Thread([this](){ get_drop_target_thread(); });
}
-
+
m_draggingStarted = false;
}
}
-void
-OSXScreen::getDropTargetThread(void*)
+void OSXScreen::get_drop_target_thread()
{
#if defined(MAC_OS_X_VERSION_10_7)
char* cstr = NULL;
-
+
// wait for 5 secs for the drop destinaiton string to be filled.
UInt32 timeout = ARCH->time() + 5;
-
+
while (ARCH->time() < timeout) {
CFStringRef cfstr = getCocoaDropTarget();
cstr = CFStringRefToUTF8String(cfstr);
CFRelease(cfstr);
-
+
if (cstr != NULL) {
break;
}
ARCH->sleep(.1f);
}
-
+
if (cstr != NULL) {
LOG((CLOG_DEBUG "drop target: %s", cstr));
m_dropTarget = cstr;
@@ -626,12 +622,12 @@ OSXScreen::fakeMouseMove(SInt32 x, SInt32 y)
if (m_fakeDraggingStarted) {
m_buttonState.set(0, kMouseButtonDown);
}
-
+
// index 0 means left mouse button
if (m_buttonState.test(0)) {
m_draggingStarted = true;
}
-
+
// synthesize event
CGPoint pos;
pos.x = x;
@@ -679,11 +675,11 @@ OSXScreen::fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const
NULL, kCGScrollEventUnitLine, 2,
mapScrollWheelFromBarrier(yDelta),
-mapScrollWheelFromBarrier(xDelta));
-
+
// Fix for sticky keys
CGEventFlags modifiers = m_keyState->getModifierStateAsOSXFlags();
CGEventSetFlags(scrollEvent, modifiers);
-
+
CGEventPost(kCGHIDEventTap, scrollEvent);
CFRelease(scrollEvent);
}
@@ -754,11 +750,11 @@ OSXScreen::enable()
if (m_isPrimary) {
// FIXME -- start watching jump zones
-
+
// kCGEventTapOptionDefault = 0x00000000 (Missing in 10.4, so specified literally)
m_eventTapPort = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault,
- kCGEventMaskForAllEvents,
- handleCGInputEvent,
+ kCGEventMaskForAllEvents,
+ handleCGInputEvent,
this);
}
else {
@@ -773,10 +769,10 @@ OSXScreen::enable()
// there may be a better way to do this, but we register an event handler even if we're
// not on the primary display (acting as a client). This way, if a local event comes in
- // (either keyboard or mouse), we can make sure to show the cursor if we've hidden it.
+ // (either keyboard or mouse), we can make sure to show the cursor if we've hidden it.
m_eventTapPort = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault,
- kCGEventMaskForAllEvents,
- handleCGInputEventSecondary,
+ kCGEventMaskForAllEvents,
+ handleCGInputEventSecondary,
this);
}
@@ -798,9 +794,9 @@ OSXScreen::disable()
if (m_autoShowHideCursor) {
showCursor();
}
-
+
// FIXME -- stop watching jump zones, stop capturing input
-
+
if (m_eventTapRLSR) {
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m_eventTapRLSR, kCFRunLoopDefaultMode);
CFRelease(m_eventTapRLSR);
@@ -846,7 +842,7 @@ OSXScreen::enter()
io_registry_entry_t entry = IORegistryEntryFromPath(
kIOMasterPortDefault,
"IOService:/IOResources/IODisplayWrangler");
-
+
if (entry != MACH_PORT_NULL) {
IORegistryEntrySetCFProperty(entry, CFSTR("IORequestIdle"), kCFBooleanFalse);
IOObjectRelease(entry);
@@ -863,15 +859,15 @@ bool
OSXScreen::leave()
{
hideCursor();
-
+
if (isDraggingStarted()) {
String& fileList = getDraggingFilename();
-
+
if (!m_isPrimary) {
if (fileList.empty() == false) {
ClientApp& app = ClientApp::instance();
Client* client = app.getClientPtr();
-
+
DragInformation di;
di.setFilename(fileList);
DragFileList dragFileList;
@@ -881,7 +877,7 @@ OSXScreen::leave()
dragFileList, info);
client->sendDragInfo(fileCount, info, info.size());
LOG((CLOG_DEBUG "send dragging file to server"));
-
+
// TODO: what to do with multiple file or even
// a folder
client->sendFileToServer(fileList.c_str());
@@ -889,7 +885,7 @@ OSXScreen::leave()
}
m_draggingStarted = false;
}
-
+
if (m_isPrimary) {
avoidHesitatingCursor();
@@ -906,8 +902,8 @@ OSXScreen::setClipboard(ClipboardID, const IClipboard* src)
{
if (src != NULL) {
LOG((CLOG_DEBUG "setting clipboard"));
- Clipboard::copy(&m_pasteboard, src);
- }
+ Clipboard::copy(&m_pasteboard, src);
+ }
return true;
}
@@ -1036,16 +1032,16 @@ OSXScreen::handleSystemEvent(const Event& event, void*)
}
break;
- case kEventClassKeyboard:
+ case kEventClassKeyboard:
switch (GetEventKind(*carbonEvent)) {
case kEventHotKeyPressed:
case kEventHotKeyReleased:
onHotKey(*carbonEvent);
break;
}
-
+
break;
-
+
case kEventClassWindow:
// 2nd param was formerly GetWindowEventTarget(m_userInputWindow) which is 32-bit only,
// however as m_userInputWindow is never initialized to anything we can take advantage of
@@ -1076,7 +1072,7 @@ OSXScreen::handleSystemEvent(const Event& event, void*)
}
}
-bool
+bool
OSXScreen::onMouseMove(CGFloat mx, CGFloat my)
{
LOG((CLOG_DEBUG2 "mouse move %+f,%+f", mx, my));
@@ -1140,7 +1136,7 @@ OSXScreen::onMouseMove(CGFloat mx, CGFloat my)
return true;
}
-bool
+bool
OSXScreen::onMouseButton(bool pressed, UInt16 macButton)
{
// Buttons 2 and 3 are inverted on the mac
@@ -1176,7 +1172,7 @@ OSXScreen::onMouseButton(bool pressed, UInt16 macButton)
}
}
}
-
+
if (macButton == kButtonLeft) {
EMouseButtonState state = pressed ? kMouseButtonDown : kMouseButtonUp;
m_buttonState.set(kButtonLeft - 1, state);
@@ -1186,10 +1182,9 @@ OSXScreen::onMouseButton(bool pressed, UInt16 macButton)
}
else {
if (m_fakeDraggingStarted) {
- m_getDropTargetThread = new Thread(new TMethodJob<OSXScreen>(
- this, &OSXScreen::getDropTargetThread));
+ m_getDropTargetThread = new Thread([this](){ get_drop_target_thread(); });
}
-
+
m_draggingStarted = false;
}
}
@@ -1218,16 +1213,16 @@ OSXScreen::displayReconfigurationCallback(CGDirectDisplayID displayID, CGDisplay
// Closing or opening the lid when an external monitor is
// connected causes an kCGDisplayBeginConfigurationFlag event
- CGDisplayChangeSummaryFlags mask = kCGDisplayBeginConfigurationFlag | kCGDisplayMovedFlag |
- kCGDisplaySetModeFlag | kCGDisplayAddFlag | kCGDisplayRemoveFlag |
- kCGDisplayEnabledFlag | kCGDisplayDisabledFlag |
- kCGDisplayMirrorFlag | kCGDisplayUnMirrorFlag |
+ CGDisplayChangeSummaryFlags mask = kCGDisplayBeginConfigurationFlag | kCGDisplayMovedFlag |
+ kCGDisplaySetModeFlag | kCGDisplayAddFlag | kCGDisplayRemoveFlag |
+ kCGDisplayEnabledFlag | kCGDisplayDisabledFlag |
+ kCGDisplayMirrorFlag | kCGDisplayUnMirrorFlag |
kCGDisplayDesktopShapeChangedFlag;
-
+
LOG((CLOG_DEBUG1 "event: display was reconfigured: %x %x %x", flags, mask, flags & mask));
if (flags & mask) { /* Something actually did change */
-
+
LOG((CLOG_DEBUG1 "event: screen changed shape; refreshing dimensions"));
screen->updateScreenShape(displayID, flags);
}
@@ -1274,7 +1269,7 @@ OSXScreen::onKey(CGEventRef event)
m_activeModifierHotKeyMask = 0;
}
}
-
+
return true;
}
@@ -1342,7 +1337,7 @@ OSXScreen::onKey(CGEventRef event)
}
void
-OSXScreen::onMediaKey(CGEventRef event)
+OSXScreen::onMediaKey(CGEventRef event)
{
KeyID keyID;
bool down;
@@ -1405,7 +1400,7 @@ OSXScreen::mapBarrierButtonToMac(UInt16 button) const
return static_cast<ButtonID>(button);
}
-ButtonID
+ButtonID
OSXScreen::mapMacButtonToBarrier(UInt16 macButton) const
{
switch (macButton) {
@@ -1418,7 +1413,7 @@ OSXScreen::mapMacButtonToBarrier(UInt16 macButton) const
case 3:
return kButtonMiddle;
}
-
+
return static_cast<ButtonID>(macButton);
}
@@ -1445,8 +1440,8 @@ OSXScreen::getScrollSpeed() const
double scaling = 0.0;
CFPropertyListRef pref = ::CFPreferencesCopyValue(
- CFSTR("com.apple.scrollwheel.scaling") ,
- kCFPreferencesAnyApplication,
+ CFSTR("com.apple.scrollwheel.scaling") ,
+ kCFPreferencesAnyApplication,
kCFPreferencesCurrentUser,
kCFPreferencesAnyHost);
if (pref != NULL) {
@@ -1535,7 +1530,7 @@ OSXScreen::updateScreenShape()
if (CGGetActiveDisplayList(0, NULL, &displayCount) != CGDisplayNoErr) {
return;
}
-
+
if (displayCount == 0) {
return;
}
@@ -1579,13 +1574,13 @@ OSXScreen::updateScreenShape()
(displayCount == 1) ? "display" : "displays"));
}
-#pragma mark -
+#pragma mark -
//
// FAST USER SWITCH NOTIFICATION SUPPORT
//
// OSXScreen::userSwitchCallback(void*)
-//
+//
// gets called if a fast user switch occurs
//
@@ -1611,18 +1606,17 @@ OSXScreen::userSwitchCallback(EventHandlerCallRef nextHandler,
return (CallNextEventHandler(nextHandler, theEvent));
}
-#pragma mark -
+#pragma mark -
//
// SLEEP/WAKEUP NOTIFICATION SUPPORT
//
// OSXScreen::watchSystemPowerThread(void*)
-//
-// main of thread monitoring system power (sleep/wakup) using a CFRunLoop
+//
+// main of thread monitoring system power (sleep/wakeup) using a CFRunLoop
//
-void
-OSXScreen::watchSystemPowerThread(void*)
+void OSXScreen::watchSystemPowerThread()
{
io_object_t notifier;
IONotificationPortRef notificationPortRef;
@@ -1641,7 +1635,7 @@ OSXScreen::watchSystemPowerThread(void*)
CFRunLoopAddSource(m_pmRunloop, runloopSourceRef,
kCFRunLoopCommonModes);
}
-
+
// thread is ready
{
Lock lock(m_pmMutex);
@@ -1658,15 +1652,15 @@ OSXScreen::watchSystemPowerThread(void*)
}
LOG((CLOG_DEBUG "started watchSystemPowerThread"));
-
+
LOG((CLOG_DEBUG "waiting for event loop"));
m_events->waitForReady();
-
+
#if defined(MAC_OS_X_VERSION_10_7)
{
Lock lockCarbon(m_carbonLoopMutex);
if (*m_carbonLoopReady == false) {
-
+
// we signalling carbon loop ready before starting
// unless we know how to do it within the loop
LOG((CLOG_DEBUG "signalling carbon loop ready"));
@@ -1676,12 +1670,12 @@ OSXScreen::watchSystemPowerThread(void*)
}
}
#endif
-
+
// start the run loop
LOG((CLOG_DEBUG "starting carbon loop"));
CFRunLoopRun();
LOG((CLOG_DEBUG "carbon loop has stopped"));
-
+
// cleanup
if (notificationPortRef) {
CFRunLoopRemoveSource(m_pmRunloop,
@@ -1716,7 +1710,7 @@ OSXScreen::handlePowerChangeRequest(natural_t messageType, void* messageArg)
getEventTarget(), messageArg,
Event::kDontFreeData));
return;
-
+
case kIOMessageSystemHasPoweredOn:
LOG((CLOG_DEBUG "system wakeup"));
m_events->addEvent(Event(m_events->forIScreen().resume(),
@@ -1742,16 +1736,16 @@ OSXScreen::handleConfirmSleep(const Event& event, void*)
if (m_pmRootPort != 0) {
// deliver suspend event immediately.
m_events->addEvent(Event(m_events->forIScreen().suspend(),
- getEventTarget(), NULL,
+ getEventTarget(), NULL,
Event::kDeliverImmediately));
-
+
LOG((CLOG_DEBUG "system will sleep"));
IOAllowPowerChange(m_pmRootPort, messageArg);
}
}
}
-#pragma mark -
+#pragma mark -
//
// GLOBAL HOTKEY OPERATING MODE SUPPORT (10.3)
@@ -1941,7 +1935,7 @@ OSXScreen::handleCGInputEvent(CGEventTapProxy proxy,
case kCGEventMouseMoved:
pos = CGEventGetLocation(event);
screen->onMouseMove(pos.x, pos.y);
-
+
// The system ignores our cursor-centering calls if
// we don't return the event. This should be harmless,
// but might register as slight movement to other apps
@@ -1980,10 +1974,10 @@ OSXScreen::handleCGInputEvent(CGEventTapProxy proxy,
}
break;
}
-
+
LOG((CLOG_DEBUG3 "unknown quartz event type: 0x%02x", type));
}
-
+
if (screen->m_isOnScreen) {
return event;
} else {
@@ -1992,38 +1986,38 @@ OSXScreen::handleCGInputEvent(CGEventTapProxy proxy,
}
void
-OSXScreen::MouseButtonState::set(UInt32 button, EMouseButtonState state)
+OSXScreen::MouseButtonState::set(UInt32 button, EMouseButtonState state)
{
bool newState = (state == kMouseButtonDown);
m_buttons.set(button, newState);
}
bool
-OSXScreen::MouseButtonState::any()
+OSXScreen::MouseButtonState::any()
{
return m_buttons.any();
}
void
-OSXScreen::MouseButtonState::reset()
+OSXScreen::MouseButtonState::reset()
{
m_buttons.reset();
}
void
-OSXScreen::MouseButtonState::overwrite(UInt32 buttons)
+OSXScreen::MouseButtonState::overwrite(UInt32 buttons)
{
m_buttons = std::bitset<NumButtonIDs>(buttons);
}
bool
-OSXScreen::MouseButtonState::test(UInt32 button) const
+OSXScreen::MouseButtonState::test(UInt32 button) const
{
return m_buttons.test(button);
}
SInt8
-OSXScreen::MouseButtonState::getFirstButtonDown() const
+OSXScreen::MouseButtonState::getFirstButtonDown() const
{
if (m_buttons.any()) {
for (unsigned short button = 0; button < m_buttons.size(); button++) {
@@ -2041,7 +2035,7 @@ OSXScreen::CFStringRefToUTF8String(CFStringRef aString)
if (aString == NULL) {
return NULL;
}
-
+
CFIndex length = CFStringGetLength(aString);
CFIndex maxSize = CFStringGetMaximumSizeForEncoding(
length,
diff --git a/src/lib/platform/OSXScreenSaver.cpp b/src/lib/platform/OSXScreenSaver.cpp
index a0282d9..4af761a 100644
--- a/src/lib/platform/OSXScreenSaver.cpp
+++ b/src/lib/platform/OSXScreenSaver.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -48,17 +48,17 @@ OSXScreenSaver::OSXScreenSaver(IEventQueue* events, void* eventTarget) :
launchEventTypes[0].eventKind = kEventAppLaunched;
launchEventTypes[1].eventClass = kEventClassApplication;
launchEventTypes[1].eventKind = kEventAppTerminated;
-
+
EventHandlerUPP launchTerminationEventHandler =
NewEventHandlerUPP(launchTerminationCallback);
InstallApplicationEventHandler(launchTerminationEventHandler, 2,
launchEventTypes, this,
&m_launchTerminationEventHandlerRef);
DisposeEventHandlerUPP(launchTerminationEventHandler);
-
+
m_screenSaverPSN.highLongOfPSN = 0;
m_screenSaverPSN.lowLongOfPSN = 0;
-
+
if (isActive()) {
getProcessSerialNumber("ScreenSaverEngine", m_screenSaverPSN);
}
@@ -128,7 +128,7 @@ OSXScreenSaver::processTerminated(ProcessSerialNumber psn)
Event(m_events->forIPrimaryScreen().screensaverDeactivated(),
m_eventTarget));
}
-
+
m_screenSaverPSN.highLongOfPSN = 0;
m_screenSaverPSN.lowLongOfPSN = 0;
}
@@ -140,7 +140,7 @@ OSXScreenSaver::launchTerminationCallback(
EventRef theEvent, void* userData)
{
OSStatus result;
- ProcessSerialNumber psn;
+ ProcessSerialNumber psn;
EventParamType actualType;
ByteCount actualSize;
diff --git a/src/lib/platform/OSXScreenSaver.h b/src/lib/platform/OSXScreenSaver.h
index 07f2a7b..9a040a7 100644
--- a/src/lib/platform/OSXScreenSaver.h
+++ b/src/lib/platform/OSXScreenSaver.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -36,11 +36,11 @@ public:
virtual void activate();
virtual void deactivate();
virtual bool isActive() const;
-
+
private:
void processLaunched(ProcessSerialNumber psn);
void processTerminated(ProcessSerialNumber psn);
-
+
static pascal OSStatus
launchTerminationCallback(
EventHandlerCallRef nextHandler,
diff --git a/src/lib/platform/OSXScreenSaverControl.h b/src/lib/platform/OSXScreenSaverControl.h
index 76f8875..ff9d4f0 100644
--- a/src/lib/platform/OSXScreenSaverControl.h
+++ b/src/lib/platform/OSXScreenSaverControl.h
@@ -6,7 +6,7 @@
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/OSXScreenSaverUtil.h b/src/lib/platform/OSXScreenSaverUtil.h
index 045553d..2ccb3c0 100644
--- a/src/lib/platform/OSXScreenSaverUtil.h
+++ b/src/lib/platform/OSXScreenSaverUtil.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/OSXScreenSaverUtil.m b/src/lib/platform/OSXScreenSaverUtil.mm
index 6d82f10..6d82f10 100644
--- a/src/lib/platform/OSXScreenSaverUtil.m
+++ b/src/lib/platform/OSXScreenSaverUtil.mm
diff --git a/src/lib/platform/OSXUchrKeyResource.cpp b/src/lib/platform/OSXUchrKeyResource.cpp
index e0230e9..8d16bfb 100644
--- a/src/lib/platform/OSXUchrKeyResource.cpp
+++ b/src/lib/platform/OSXUchrKeyResource.cpp
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/OSXUchrKeyResource.h b/src/lib/platform/OSXUchrKeyResource.h
index 47b63c9..8e1a813 100644
--- a/src/lib/platform/OSXUchrKeyResource.h
+++ b/src/lib/platform/OSXUchrKeyResource.h
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -27,7 +27,7 @@ typedef TISInputSourceRef KeyLayout;
class OSXUchrKeyResource : public IOSXKeyResource {
public:
OSXUchrKeyResource(const void*, UInt32 keyboardType);
-
+
// KeyResource overrides
virtual bool isValid() const;
virtual UInt32 getNumModifierCombinations() const;
@@ -35,15 +35,15 @@ public:
virtual UInt32 getNumButtons() const;
virtual UInt32 getTableForModifier(UInt32 mask) const;
virtual KeyID getKey(UInt32 table, UInt32 button) const;
-
+
private:
typedef std::vector<KeyID> KeySequence;
-
+
bool getDeadKey(KeySequence& keys, UInt16 index) const;
bool getKeyRecord(KeySequence& keys,
UInt16 index, UInt16& state) const;
bool addSequence(KeySequence& keys, UCKeyCharSeq c) const;
-
+
private:
const UCKeyboardLayout* m_resource;
const UCKeyModifiersToTableNum* m_m;
diff --git a/src/lib/platform/XWindowsClipboard.cpp b/src/lib/platform/XWindowsClipboard.cpp
index b0da695..27321e5 100644
--- a/src/lib/platform/XWindowsClipboard.cpp
+++ b/src/lib/platform/XWindowsClipboard.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -84,10 +84,14 @@ XWindowsClipboard::XWindowsClipboard(IXWindowsImpl* impl, Display* display,
// add converters, most desired first
m_converters.push_back(new XWindowsClipboardHTMLConverter(m_display,
"text/html"));
+ m_converters.push_back(new XWindowsClipboardHTMLConverter(m_display,
+ "application/x-moz-nativehtml"));
m_converters.push_back(new XWindowsClipboardBMPConverter(m_display));
m_converters.push_back(new XWindowsClipboardUTF8Converter(m_display,
"text/plain;charset=UTF-8"));
m_converters.push_back(new XWindowsClipboardUTF8Converter(m_display,
+ "text/plain;charset=utf-8"));
+ m_converters.push_back(new XWindowsClipboardUTF8Converter(m_display,
"UTF8_STRING"));
m_converters.push_back(new XWindowsClipboardUCS2Converter(m_display,
"text/plain;charset=ISO-10646-UCS-2"));
diff --git a/src/lib/platform/XWindowsClipboard.h b/src/lib/platform/XWindowsClipboard.h
index 091036e..5f1b6cb 100644
--- a/src/lib/platform/XWindowsClipboard.h
+++ b/src/lib/platform/XWindowsClipboard.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -25,11 +25,7 @@
#include "common/stdvector.h"
#include "XWindowsImpl.h"
-#if X_DISPLAY_MISSING
-# error X11 is required to build barrier
-#else
-# include <X11/Xlib.h>
-#endif
+#include <X11/Xlib.h>
class IXWindowsClipboardConverter;
diff --git a/src/lib/platform/XWindowsClipboardAnyBitmapConverter.cpp b/src/lib/platform/XWindowsClipboardAnyBitmapConverter.cpp
index f6fed1c..0190f1d 100644
--- a/src/lib/platform/XWindowsClipboardAnyBitmapConverter.cpp
+++ b/src/lib/platform/XWindowsClipboardAnyBitmapConverter.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/XWindowsClipboardAnyBitmapConverter.h b/src/lib/platform/XWindowsClipboardAnyBitmapConverter.h
index 861b1b6..375d8cc 100644
--- a/src/lib/platform/XWindowsClipboardAnyBitmapConverter.h
+++ b/src/lib/platform/XWindowsClipboardAnyBitmapConverter.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/XWindowsClipboardBMPConverter.cpp b/src/lib/platform/XWindowsClipboardBMPConverter.cpp
index fcfdc69..fd3325e 100644
--- a/src/lib/platform/XWindowsClipboardBMPConverter.cpp
+++ b/src/lib/platform/XWindowsClipboardBMPConverter.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/XWindowsClipboardBMPConverter.h b/src/lib/platform/XWindowsClipboardBMPConverter.h
index 4afa788..12716d1 100644
--- a/src/lib/platform/XWindowsClipboardBMPConverter.h
+++ b/src/lib/platform/XWindowsClipboardBMPConverter.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/XWindowsClipboardHTMLConverter.cpp b/src/lib/platform/XWindowsClipboardHTMLConverter.cpp
index 6ae98a7..a13e80e 100644
--- a/src/lib/platform/XWindowsClipboardHTMLConverter.cpp
+++ b/src/lib/platform/XWindowsClipboardHTMLConverter.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/XWindowsClipboardHTMLConverter.h b/src/lib/platform/XWindowsClipboardHTMLConverter.h
index 9a4ce61..b2a1a1e 100644
--- a/src/lib/platform/XWindowsClipboardHTMLConverter.h
+++ b/src/lib/platform/XWindowsClipboardHTMLConverter.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/XWindowsClipboardTextConverter.cpp b/src/lib/platform/XWindowsClipboardTextConverter.cpp
index 2e18d91..ee34f13 100644
--- a/src/lib/platform/XWindowsClipboardTextConverter.cpp
+++ b/src/lib/platform/XWindowsClipboardTextConverter.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/XWindowsClipboardTextConverter.h b/src/lib/platform/XWindowsClipboardTextConverter.h
index 99cdbcb..14e6c0f 100644
--- a/src/lib/platform/XWindowsClipboardTextConverter.h
+++ b/src/lib/platform/XWindowsClipboardTextConverter.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/XWindowsClipboardUCS2Converter.cpp b/src/lib/platform/XWindowsClipboardUCS2Converter.cpp
index d3d5e04..75dd70e 100644
--- a/src/lib/platform/XWindowsClipboardUCS2Converter.cpp
+++ b/src/lib/platform/XWindowsClipboardUCS2Converter.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/XWindowsClipboardUCS2Converter.h b/src/lib/platform/XWindowsClipboardUCS2Converter.h
index 16d880a..0bedb7a 100644
--- a/src/lib/platform/XWindowsClipboardUCS2Converter.h
+++ b/src/lib/platform/XWindowsClipboardUCS2Converter.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/XWindowsClipboardUTF8Converter.cpp b/src/lib/platform/XWindowsClipboardUTF8Converter.cpp
index f470cf1..a452706 100644
--- a/src/lib/platform/XWindowsClipboardUTF8Converter.cpp
+++ b/src/lib/platform/XWindowsClipboardUTF8Converter.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/XWindowsClipboardUTF8Converter.h b/src/lib/platform/XWindowsClipboardUTF8Converter.h
index 2219ed2..bb6cafb 100644
--- a/src/lib/platform/XWindowsClipboardUTF8Converter.h
+++ b/src/lib/platform/XWindowsClipboardUTF8Converter.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/platform/XWindowsEventQueueBuffer.cpp b/src/lib/platform/XWindowsEventQueueBuffer.cpp
index 8b8c3b5..397973f 100644
--- a/src/lib/platform/XWindowsEventQueueBuffer.cpp
+++ b/src/lib/platform/XWindowsEventQueueBuffer.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -104,7 +104,7 @@ XWindowsEventQueueBuffer::waitForEvent(double dtimeout)
char buf[16];
ssize_t read_response = read(m_pipefd[0], buf, 15);
-
+
// with linux automake, warnings are treated as errors by default
if (read_response < 0)
{
@@ -181,7 +181,7 @@ XWindowsEventQueueBuffer::waitForEvent(double dtimeout)
retval = poll(pfds, 2, TIMEOUT_DELAY); //16ms = 60hz, but we make it > to play nicely with the cpu
if (pfds[1].revents & POLLIN) {
ssize_t read_response = read(m_pipefd[0], buf, 15);
-
+
// with linux automake, warnings are treated as errors by default
if (read_response < 0)
{
diff --git a/src/lib/platform/XWindowsEventQueueBuffer.h b/src/lib/platform/XWindowsEventQueueBuffer.h
index 13f6b16..dc35bf0 100644
--- a/src/lib/platform/XWindowsEventQueueBuffer.h
+++ b/src/lib/platform/XWindowsEventQueueBuffer.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -23,11 +23,7 @@
#include "common/stdvector.h"
#include "XWindowsImpl.h"
-#if X_DISPLAY_MISSING
-# error X11 is required to build barrier
-#else
-# include <X11/Xlib.h>
-#endif
+#include <X11/Xlib.h>
class IEventQueue;
diff --git a/src/lib/platform/XWindowsKeyState.cpp b/src/lib/platform/XWindowsKeyState.cpp
index 9fb71ca..088adc6 100644
--- a/src/lib/platform/XWindowsKeyState.cpp
+++ b/src/lib/platform/XWindowsKeyState.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2003 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -24,18 +24,14 @@
#include <cstddef>
#include <algorithm>
-#if X_DISPLAY_MISSING
-# error X11 is required to build barrier
-#else
-# include <X11/X.h>
-# include <X11/Xutil.h>
-# define XK_MISCELLANY
-# define XK_XKB_KEYS
-# include <X11/keysymdef.h>
+#include <X11/X.h>
+#include <X11/Xutil.h>
+#define XK_MISCELLANY
+#define XK_XKB_KEYS
+#include <X11/keysymdef.h>
#if HAVE_XKB_EXTENSION
# include <X11/XKBlib.h>
#endif
-#endif
static const size_t ModifiersFromXDefaultSize = 32;
@@ -348,7 +344,7 @@ XWindowsKeyState::updateKeysymMap(barrier::KeyMap& keyMap)
else {
tmpKeysyms[maxKeysyms * i + j] = NoSymbol;
}
- }
+ }
}
m_impl->XFree(allKeysyms);
allKeysyms = tmpKeysyms;
diff --git a/src/lib/platform/XWindowsKeyState.h b/src/lib/platform/XWindowsKeyState.h
index f790390..ef35dd4 100644
--- a/src/lib/platform/XWindowsKeyState.h
+++ b/src/lib/platform/XWindowsKeyState.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2003 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -23,18 +23,10 @@
#include "common/stdvector.h"
#include "XWindowsImpl.h"
-#if X_DISPLAY_MISSING
-# error X11 is required to build barrier
-#else
-# include <X11/Xlib.h>
-# if HAVE_X11_EXTENSIONS_XTEST_H
-# include <X11/extensions/XTest.h>
-# else
-# error The XTest extension is required to build barrier
-# endif
-# if HAVE_XKB_EXTENSION
-# include <X11/extensions/XKBstr.h>
-# endif
+#include <X11/Xlib.h>
+#include <X11/extensions/XTest.h>
+#if HAVE_XKB_EXTENSION
+# include <X11/extensions/XKBstr.h>
#endif
class IEventQueue;
@@ -136,7 +128,7 @@ private:
bool m_lock;
};
-#ifdef TEST_ENV
+#ifdef BARRIER_TEST_ENV
public: // yuck
#endif
typedef std::vector<KeyModifierMask> KeyModifierMaskList;
@@ -169,7 +161,7 @@ private:
// autorepeat state
XKeyboardState m_keyboardState;
-#ifdef TEST_ENV
+#ifdef BARRIER_TEST_ENV
public:
SInt32 group() const { return m_group; }
void group(const SInt32& group) { m_group = group; }
diff --git a/src/lib/platform/XWindowsScreen.cpp b/src/lib/platform/XWindowsScreen.cpp
index 5f1724c..8fb3569 100644
--- a/src/lib/platform/XWindowsScreen.cpp
+++ b/src/lib/platform/XWindowsScreen.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -97,7 +97,7 @@ XWindowsScreen::XWindowsScreen(
if (mouseScrollDelta==0) m_mouseScrollDelta=120;
s_screen = this;
-
+
if (!disableXInitThreads) {
// initializes Xlib support for concurrent threads.
if (m_impl->XInitThreads() == 0)
@@ -266,14 +266,14 @@ XWindowsScreen::enter()
m_impl->DPMSForceLevel(m_display, DPMSModeOn);
}
#endif
-
+
// unmap the hider/grab window. this also ungrabs the mouse and
// keyboard if they're grabbed.
m_impl->XUnmapWindow(m_display, m_window);
/* maybe call this if entering for the screensaver
// set keyboard focus to root window. the screensaver should then
- // pick up key events for when the user enters a password to unlock.
+ // pick up key events for when the user enters a password to unlock.
XSetInputFocus(m_display, PointerRoot, PointerRoot, CurrentTime);
*/
@@ -877,7 +877,7 @@ XWindowsScreen::openDisplay(const char* displayName)
{
// get the DISPLAY
if (displayName == NULL) {
- displayName = getenv("DISPLAY");
+ displayName = std::getenv("DISPLAY");
if (displayName == NULL) {
displayName = ":0.0";
}
diff --git a/src/lib/platform/XWindowsScreen.h b/src/lib/platform/XWindowsScreen.h
index 5573839..581e91f 100644
--- a/src/lib/platform/XWindowsScreen.h
+++ b/src/lib/platform/XWindowsScreen.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -24,11 +24,7 @@
#include "common/stdvector.h"
#include "XWindowsImpl.h"
-#if X_DISPLAY_MISSING
-# error X11 is required to build barrier
-#else
-# include <X11/Xlib.h>
-#endif
+#include <X11/Xlib.h>
class XWindowsClipboard;
class XWindowsKeyState;
diff --git a/src/lib/platform/XWindowsScreenSaver.cpp b/src/lib/platform/XWindowsScreenSaver.cpp
index 5c4ef91..d8787ab 100644
--- a/src/lib/platform/XWindowsScreenSaver.cpp
+++ b/src/lib/platform/XWindowsScreenSaver.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -26,31 +26,11 @@
#include "base/TMethodEventJob.h"
#include <X11/Xatom.h>
-#if HAVE_X11_EXTENSIONS_XTEST_H
-# include <X11/extensions/XTest.h>
-#else
-# error The XTest extension is required to build barrier
-#endif
+#include <X11/extensions/XTest.h>
#if HAVE_X11_EXTENSIONS_DPMS_H
extern "C" {
# include <X11/Xmd.h>
# include <X11/extensions/dpms.h>
-# if !HAVE_DPMS_PROTOTYPES
-# undef DPMSModeOn
-# undef DPMSModeStandby
-# undef DPMSModeSuspend
-# undef DPMSModeOff
-# define DPMSModeOn 0
-# define DPMSModeStandby 1
-# define DPMSModeSuspend 2
-# define DPMSModeOff 3
-extern Bool DPMSQueryExtension(Display *, int *, int *);
-extern Bool DPMSCapable(Display *);
-extern Status DPMSEnable(Display *);
-extern Status DPMSDisable(Display *);
-extern Status DPMSForceLevel(Display *, CARD16);
-extern Status DPMSInfo(Display *, CARD16 *, BOOL *);
-# endif
}
#endif
@@ -490,7 +470,7 @@ XWindowsScreenSaver::addWatchXScreenSaver(Window window)
}
// if successful and window uses override_redirect (like xscreensaver
- // does) then watch it for property changes.
+ // does) then watch it for property changes.
if (!error && attr.override_redirect == True) {
error = false;
{
diff --git a/src/lib/platform/XWindowsScreenSaver.h b/src/lib/platform/XWindowsScreenSaver.h
index 1761db2..00285ec 100644
--- a/src/lib/platform/XWindowsScreenSaver.h
+++ b/src/lib/platform/XWindowsScreenSaver.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -23,11 +23,7 @@
#include "common/stdmap.h"
#include "XWindowsImpl.h"
-#if X_DISPLAY_MISSING
-# error X11 is required to build barrier
-#else
-# include <X11/Xlib.h>
-#endif
+#include <X11/Xlib.h>
class Event;
class EventQueueTimer;
@@ -119,7 +115,7 @@ private:
// the X display
Display* m_display;
- // window to receive xscreensaver repsonses
+ // window to receive xscreensaver responses
Window m_xscreensaverSink;
// the target for the events we generate
diff --git a/src/lib/platform/XWindowsUtil.cpp b/src/lib/platform/XWindowsUtil.cpp
index 3c90bd6..7d4bb63 100644
--- a/src/lib/platform/XWindowsUtil.cpp
+++ b/src/lib/platform/XWindowsUtil.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -1250,7 +1250,7 @@ XK_uhorn
// map "Internet" keys to KeyIDs
static const KeySym s_map1008FF[] =
{
- /* 0x00 */ 0, 0, kKeyBrightnessUp, kKeyBrightnessDown, 0, 0, 0, 0,
+ /* 0x00 */ 0, 0, kKeyBrightnessUp, kKeyBrightnessDown, 0, kKeyKbdBrightnessUp, kKeyKbdBrightnessDown, 0,
/* 0x08 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x10 */ 0, kKeyAudioDown, kKeyAudioMute, kKeyAudioUp,
/* 0x14 */ kKeyAudioPlay, kKeyAudioStop, kKeyAudioPrev, kKeyAudioNext,
@@ -1285,6 +1285,45 @@ static const KeySym s_map1008FF[] =
/* 0xf8 */ 0, 0, 0, 0, 0, 0, 0, 0
};
+// map Sun keyboard keys to KeyIDs
+// This is based on the the "Internet" keymap plus the missing keys
+// Copy/Cut/Open/Paste/Props/Front
+static const KeySym s_map1009FF[] =
+{
+ /* 0x00 */ 0, 0, kKeyBrightnessUp, kKeyBrightnessDown, 0, 0, 0, 0,
+ /* 0x08 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x10 */ 0, kKeyAudioDown, kKeyAudioMute, kKeyAudioUp,
+ /* 0x14 */ kKeyAudioPlay, kKeyAudioStop, kKeyAudioPrev, kKeyAudioNext,
+ /* 0x18 */ kKeyWWWHome, kKeyAppMail, 0, kKeyWWWSearch, 0, 0, 0, 0,
+ /* 0x20 */ 0, 0, 0, 0, 0, 0, kKeyWWWBack, kKeyWWWForward,
+ /* 0x28 */ kKeyWWWStop, kKeyWWWRefresh, 0, 0, kKeyEject, 0, 0, 0,
+ /* 0x30 */ kKeyWWWFavorites, 0, kKeyAppMedia, 0, 0, 0, 0, 0,
+ /* 0x38 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x40 */ kKeyAppUser1, kKeyAppUser2, 0, 0, 0, 0, 0, 0,
+ /* 0x48 */ 0, 0, kKeyMissionControl, kKeyLaunchpad, 0, 0, 0, 0,
+ /* 0x50 */ 0, 0, 0, 0, 0, 0, 0, kKeyCopy,
+ /* 0x58 */ kKeyCut, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x60 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x68 */ 0, 0, 0, kKeyOpen, 0, kKeyPaste, 0, 0,
+ /* 0x70 */ kKeyProps, kKeyFront, 0, 0, 0, 0, 0, 0,
+ /* 0x78 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x80 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x88 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x90 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x98 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xa0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xa8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xb0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xb8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xc0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xc8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xd0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xd8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xe0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xe8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xf0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xf8 */ 0, 0, 0, 0, 0, 0, 0, 0
+};
//
// XWindowsUtil
@@ -1546,6 +1585,10 @@ XWindowsUtil::mapKeySymToKeyID(KeySym k)
// "Internet" keys
return s_map1008FF[k & 0xff];
+ case 0x1009ff00:
+ // Additional Left-side keys provided by Sun Microsystems USB keyboards
+ return s_map1009FF[k & 0xff];
+
default: {
// lookup character in table
KeySymMap::const_iterator index = s_keySymToUCS4.find(k);
diff --git a/src/lib/platform/XWindowsUtil.h b/src/lib/platform/XWindowsUtil.h
index f5b3ea8..938c332 100644
--- a/src/lib/platform/XWindowsUtil.h
+++ b/src/lib/platform/XWindowsUtil.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -22,11 +22,7 @@
#include "common/stdmap.h"
#include "common/stdvector.h"
-#if X_DISPLAY_MISSING
-# error X11 is required to build barrier
-#else
-# include <X11/Xlib.h>
-#endif
+#include <X11/Xlib.h>
#include <string>
@@ -123,7 +119,7 @@ public:
This class sets an X error handler in the c'tor and restores the
previous error handler in the d'tor. A lock should only be
installed while the display is locked by the thread.
-
+
ErrorLock() ignores errors
ErrorLock(bool* flag) sets *flag to true if any error occurs
*/
diff --git a/src/lib/platform/synwinhk.h b/src/lib/platform/synwinhk.h
index 4b2d8e3..8fc4290 100644
--- a/src/lib/platform/synwinhk.h
+++ b/src/lib/platform/synwinhk.h
@@ -3,11 +3,11 @@
* Copyright (C) 2018 Debauchee Open Source Group
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/server/BaseClientProxy.cpp b/src/lib/server/BaseClientProxy.cpp
index 6ccd251..78c4220 100644
--- a/src/lib/server/BaseClientProxy.cpp
+++ b/src/lib/server/BaseClientProxy.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2006 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/server/BaseClientProxy.h b/src/lib/server/BaseClientProxy.h
index a2c9459..5d5dc06 100644
--- a/src/lib/server/BaseClientProxy.h
+++ b/src/lib/server/BaseClientProxy.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/server/CMakeLists.txt b/src/lib/server/CMakeLists.txt
index 5242d6d..e1ed692 100644
--- a/src/lib/server/CMakeLists.txt
+++ b/src/lib/server/CMakeLists.txt
@@ -1,11 +1,11 @@
# barrier -- mouse and keyboard sharing utility
# Copyright (C) 2012-2016 Symless Ltd.
# Copyright (C) 2009 Nick Bolton
-#
+#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
-#
+#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/server/ClientListener.cpp b/src/lib/server/ClientListener.cpp
index 00067ba..75724bc 100644
--- a/src/lib/server/ClientListener.cpp
+++ b/src/lib/server/ClientListener.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -36,25 +36,24 @@
ClientListener::ClientListener(const NetworkAddress& address,
ISocketFactory* socketFactory,
IEventQueue* events,
- bool enableCrypto) :
+ ConnectionSecurityLevel security_level) :
m_socketFactory(socketFactory),
m_server(NULL),
m_events(events),
- m_useSecureNetwork(enableCrypto)
+ security_level_{security_level}
{
assert(m_socketFactory != NULL);
try {
- m_listen = m_socketFactory->createListen(
- ARCH->getAddrFamily(address.getAddress()),
- m_useSecureNetwork);
+ m_listen = m_socketFactory->createListen(ARCH->getAddrFamily(address.getAddress()),
+ security_level);
// setup event handler
m_events->adoptHandler(m_events->forIListenSocket().connecting(),
m_listen,
new TMethodEventJob<ClientListener>(this,
&ClientListener::handleClientConnecting));
-
+
// bind listen address
LOG((CLOG_DEBUG1 "binding listen socket"));
m_listen->bind(address);
@@ -130,17 +129,17 @@ ClientListener::handleClientConnecting(const Event&, void*)
if (socket == NULL) {
return;
}
-
+
m_clientSockets.insert(socket);
m_events->adoptHandler(m_events->forClientListener().accepted(),
socket->getEventTarget(),
new TMethodEventJob<ClientListener>(this,
&ClientListener::handleClientAccepted, socket));
-
+
// When using non SSL, server accepts clients immediately, while SSL
// has to call secure accept which may require retry
- if (!m_useSecureNetwork) {
+ if (security_level_ == ConnectionSecurityLevel::PLAINTEXT) {
m_events->addEvent(Event(m_events->forClientListener().accepted(),
socket->getEventTarget()));
}
@@ -152,7 +151,7 @@ ClientListener::handleClientAccepted(const Event&, void* vsocket)
LOG((CLOG_NOTE "accepted client connection"));
IDataSocket* socket = static_cast<IDataSocket*>(vsocket);
-
+
// filter socket messages, including a packetizing filter
barrier::IStream* stream = new PacketStreamFilter(m_events, socket, false);
assert(m_server != NULL);
@@ -184,7 +183,6 @@ ClientListener::handleUnknownClient(const Event&, void* vclient)
// get the real client proxy and install it
ClientProxy* client = unknownClient->orphanClientProxy();
- bool handshakeOk = true;
if (client != NULL) {
// handshake was successful
m_waitingClients.push_back(client);
@@ -196,20 +194,17 @@ ClientListener::handleUnknownClient(const Event&, void* vclient)
new TMethodEventJob<ClientListener>(this,
&ClientListener::handleClientDisconnected,
client));
- }
- else {
- handshakeOk = false;
+ } else {
+ auto* stream = unknownClient->getStream();
+ if (stream) {
+ stream->close();
+ }
}
// now finished with unknown client
m_events->removeHandler(m_events->forClientProxyUnknown().success(), client);
m_events->removeHandler(m_events->forClientProxyUnknown().failure(), client);
m_newClients.erase(unknownClient);
- PacketStreamFilter* streamFileter = dynamic_cast<PacketStreamFilter*>(unknownClient->getStream());
- IDataSocket* socket = NULL;
- if (streamFileter != NULL) {
- socket = dynamic_cast<IDataSocket*>(streamFileter->getStream());
- }
delete unknownClient;
}
diff --git a/src/lib/server/ClientListener.h b/src/lib/server/ClientListener.h
index b02cbb1..1debc2b 100644
--- a/src/lib/server/ClientListener.h
+++ b/src/lib/server/ClientListener.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -23,6 +23,7 @@
#include "base/Event.h"
#include "common/stddeque.h"
#include "common/stdset.h"
+#include "net/ConnectionSecurityLevel.h"
class ClientProxy;
class ClientProxyUnknown;
@@ -36,10 +37,8 @@ class IDataSocket;
class ClientListener {
public:
// The factories are adopted.
- ClientListener(const NetworkAddress&,
- ISocketFactory*,
- IEventQueue* events,
- bool enableCrypto);
+ ClientListener(const NetworkAddress&, ISocketFactory*, IEventQueue* events,
+ ConnectionSecurityLevel security_level);
~ClientListener();
//! @name manipulators
@@ -86,6 +85,6 @@ private:
WaitingClients m_waitingClients;
Server* m_server;
IEventQueue* m_events;
- bool m_useSecureNetwork;
+ ConnectionSecurityLevel security_level_;
ClientSockets m_clientSockets;
};
diff --git a/src/lib/server/ClientProxy.cpp b/src/lib/server/ClientProxy.cpp
index d91e186..76cdfa6 100644
--- a/src/lib/server/ClientProxy.cpp
+++ b/src/lib/server/ClientProxy.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/server/ClientProxy.h b/src/lib/server/ClientProxy.h
index a3d87cb..b641011 100644
--- a/src/lib/server/ClientProxy.h
+++ b/src/lib/server/ClientProxy.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/server/ClientProxy1_0.cpp b/src/lib/server/ClientProxy1_0.cpp
index 5cbaac2..33b0f15 100644
--- a/src/lib/server/ClientProxy1_0.cpp
+++ b/src/lib/server/ClientProxy1_0.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -51,6 +51,10 @@ ClientProxy1_0::ClientProxy1_0(const std::string& name, barrier::IStream* stream
stream->getEventTarget(),
new TMethodEventJob<ClientProxy1_0>(this,
&ClientProxy1_0::handleDisconnect, NULL));
+ m_events->adoptHandler(m_events->forIStream().inputFormatError(),
+ stream->getEventTarget(),
+ new TMethodEventJob<ClientProxy1_0>(this,
+ &ClientProxy1_0::handleDisconnect, NULL));
m_events->adoptHandler(m_events->forIStream().outputShutdown(),
stream->getEventTarget(),
new TMethodEventJob<ClientProxy1_0>(this,
@@ -90,6 +94,8 @@ ClientProxy1_0::removeHandlers()
getStream()->getEventTarget());
m_events->removeHandler(m_events->forIStream().outputShutdown(),
getStream()->getEventTarget());
+ m_events->removeHandler(m_events->forIStream().inputFormatError(),
+ getStream()->getEventTarget());
m_events->removeHandler(Event::kTimer, this);
// remove timer
@@ -148,9 +154,18 @@ ClientProxy1_0::handleData(const Event&, void*)
}
// parse message
- LOG((CLOG_DEBUG2 "msg from \"%s\": %c%c%c%c", getName().c_str(), code[0], code[1], code[2], code[3]));
- if (!(this->*m_parser)(code)) {
- LOG((CLOG_ERR "invalid message from client \"%s\": %c%c%c%c", getName().c_str(), code[0], code[1], code[2], code[3]));
+ try {
+ LOG((CLOG_DEBUG2 "msg from \"%s\": %c%c%c%c", getName().c_str(), code[0], code[1], code[2], code[3]));
+ if (!(this->*m_parser)(code)) {
+ LOG((CLOG_ERR "invalid message from client \"%s\": %c%c%c%c", getName().c_str(), code[0], code[1], code[2], code[3]));
+ disconnect();
+ return;
+ }
+ } catch (const XBadClient& e) {
+ // TODO: disconnect handling is currently dispersed across both parseMessage() and
+ // handleData() functions, we should collect that to a single place
+
+ LOG((CLOG_ERR "protocol error from client: %s", e.what()));
disconnect();
return;
}
@@ -173,6 +188,8 @@ ClientProxy1_0::parseHandshakeMessage(const UInt8* code)
}
else if (memcmp(code, kMsgDInfo, 4) == 0) {
// future messages get parsed by parseMessage
+ // NOTE: we're taking address of virtual function here,
+ // not ClientProxy1_0 implementation of it.
m_parser = &ClientProxy1_0::parseMessage;
if (recvInfo()) {
m_events->addEvent(Event(m_events->forClientProxy().ready(), getEventTarget()));
diff --git a/src/lib/server/ClientProxy1_0.h b/src/lib/server/ClientProxy1_0.h
index 98c68f3..45d7541 100644
--- a/src/lib/server/ClientProxy1_0.h
+++ b/src/lib/server/ClientProxy1_0.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/server/ClientProxy1_1.cpp b/src/lib/server/ClientProxy1_1.cpp
index bb33ac1..6d2e007 100644
--- a/src/lib/server/ClientProxy1_1.cpp
+++ b/src/lib/server/ClientProxy1_1.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/server/ClientProxy1_1.h b/src/lib/server/ClientProxy1_1.h
index ada4dcc..38fda52 100644
--- a/src/lib/server/ClientProxy1_1.h
+++ b/src/lib/server/ClientProxy1_1.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/server/ClientProxy1_2.cpp b/src/lib/server/ClientProxy1_2.cpp
index e9527ef..5457dc0 100644
--- a/src/lib/server/ClientProxy1_2.cpp
+++ b/src/lib/server/ClientProxy1_2.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/server/ClientProxy1_2.h b/src/lib/server/ClientProxy1_2.h
index 12d6b92..08b32fb 100644
--- a/src/lib/server/ClientProxy1_2.h
+++ b/src/lib/server/ClientProxy1_2.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/server/ClientProxy1_3.cpp b/src/lib/server/ClientProxy1_3.cpp
index d0031ce..5012a4e 100644
--- a/src/lib/server/ClientProxy1_3.cpp
+++ b/src/lib/server/ClientProxy1_3.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2006 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/server/ClientProxy1_3.h b/src/lib/server/ClientProxy1_3.h
index ad46cea..a459e1e 100644
--- a/src/lib/server/ClientProxy1_3.h
+++ b/src/lib/server/ClientProxy1_3.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2006 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/server/ClientProxy1_4.cpp b/src/lib/server/ClientProxy1_4.cpp
index 9b12976..bc58626 100644
--- a/src/lib/server/ClientProxy1_4.cpp
+++ b/src/lib/server/ClientProxy1_4.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2011 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/server/ClientProxy1_4.h b/src/lib/server/ClientProxy1_4.h
index cda090b..fa88234 100644
--- a/src/lib/server/ClientProxy1_4.h
+++ b/src/lib/server/ClientProxy1_4.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2011 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/server/ClientProxy1_5.cpp b/src/lib/server/ClientProxy1_5.cpp
index 40bba08..72c0bf8 100644
--- a/src/lib/server/ClientProxy1_5.cpp
+++ b/src/lib/server/ClientProxy1_5.cpp
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2013-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -86,7 +86,7 @@ ClientProxy1_5::fileChunkReceived()
getStream(),
server->getReceivedFileData(),
server->getExpectedFileSize());
-
+
if (result == kFinish) {
m_events->addEvent(Event(m_events->forFile().fileRecieveCompleted(), server));
@@ -106,6 +106,6 @@ ClientProxy1_5::dragInfoReceived()
UInt32 fileNum = 0;
std::string content;
ProtocolUtil::readf(getStream(), kMsgDDragInfo + 4, &fileNum, &content);
-
+
m_server->dragInfoReceived(fileNum, content);
}
diff --git a/src/lib/server/ClientProxy1_5.h b/src/lib/server/ClientProxy1_5.h
index 4087730..2051f3c 100644
--- a/src/lib/server/ClientProxy1_5.h
+++ b/src/lib/server/ClientProxy1_5.h
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2013-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/server/ClientProxy1_6.cpp b/src/lib/server/ClientProxy1_6.cpp
index c829e84..29f3ce4 100644
--- a/src/lib/server/ClientProxy1_6.cpp
+++ b/src/lib/server/ClientProxy1_6.cpp
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2015-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -88,7 +88,7 @@ ClientProxy1_6::recvClipboard()
// save clipboard
m_clipboard[id].m_clipboard.unmarshall(dataCached, 0);
m_clipboard[id].m_sequenceNumber = seq;
-
+
// notify
ClipboardInfo* info = new ClipboardInfo;
info->m_id = id;
diff --git a/src/lib/server/ClientProxy1_6.h b/src/lib/server/ClientProxy1_6.h
index 830696a..a4c2e5d 100644
--- a/src/lib/server/ClientProxy1_6.h
+++ b/src/lib/server/ClientProxy1_6.h
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2015-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/server/ClientProxyUnknown.cpp b/src/lib/server/ClientProxyUnknown.cpp
index dc79da7..f9da361 100644
--- a/src/lib/server/ClientProxyUnknown.cpp
+++ b/src/lib/server/ClientProxyUnknown.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -118,6 +118,10 @@ ClientProxyUnknown::addStreamHandlers()
m_stream->getEventTarget(),
new TMethodEventJob<ClientProxyUnknown>(this,
&ClientProxyUnknown::handleDisconnect));
+ m_events->adoptHandler(m_events->forIStream().inputFormatError(),
+ m_stream->getEventTarget(),
+ new TMethodEventJob<ClientProxyUnknown>(this,
+ &ClientProxyUnknown::handleDisconnect));
m_events->adoptHandler(m_events->forIStream().outputShutdown(),
m_stream->getEventTarget(),
new TMethodEventJob<ClientProxyUnknown>(this,
@@ -149,6 +153,8 @@ ClientProxyUnknown::removeHandlers()
m_stream->getEventTarget());
m_events->removeHandler(m_events->forIStream().inputShutdown(),
m_stream->getEventTarget());
+ m_events->removeHandler(m_events->forIStream().inputFormatError(),
+ m_stream->getEventTarget());
m_events->removeHandler(m_events->forIStream().outputShutdown(),
m_stream->getEventTarget());
}
diff --git a/src/lib/server/ClientProxyUnknown.h b/src/lib/server/ClientProxyUnknown.h
index 5d59402..efb1b2b 100644
--- a/src/lib/server/ClientProxyUnknown.h
+++ b/src/lib/server/ClientProxyUnknown.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/server/Config.cpp b/src/lib/server/Config.cpp
index a47a391..bcdb88c 100644
--- a/src/lib/server/Config.cpp
+++ b/src/lib/server/Config.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -1748,10 +1748,10 @@ std::ostream&
operator<<(std::ostream& s, const Config& config)
{
// screens section
- s << "section: screens" << std::endl;
+ s << "section: screens\n";
for (Config::const_iterator screen = config.begin();
screen != config.end(); ++screen) {
- s << "\t" << screen->c_str() << ":" << std::endl;
+ s << "\t" << screen->c_str() << ":\n";
const Config::ScreenOptions* options = config.getOptions(*screen);
if (options != NULL && options->size() > 0) {
for (Config::ScreenOptions::const_iterator
@@ -1760,31 +1760,31 @@ operator<<(std::ostream& s, const Config& config)
const char* name = Config::getOptionName(option->first);
std::string value = Config::getOptionValue(option->first, option->second);
if (name != NULL && !value.empty()) {
- s << "\t\t" << name << " = " << value << std::endl;
+ s << "\t\t" << name << " = " << value << "\n";
}
}
}
}
- s << "end" << std::endl;
+ s << "end\n";
// links section
std::string neighbor;
- s << "section: links" << std::endl;
+ s << "section: links\n";
for (Config::const_iterator screen = config.begin();
screen != config.end(); ++screen) {
- s << "\t" << screen->c_str() << ":" << std::endl;
+ s << "\t" << screen->c_str() << ":\n";
for (Config::link_const_iterator
link = config.beginNeighbor(*screen),
- nend = config.endNeighbor(*screen); link != nend; ++link) {
+ nend = config.endNeighbor(*screen); link != nend; ++link) {
s << "\t\t" << Config::dirName(link->first.getSide()) <<
Config::formatInterval(link->first.getInterval()) <<
" = " << link->second.getName().c_str() <<
Config::formatInterval(link->second.getInterval()) <<
- std::endl;
+ "\n";
}
}
- s << "end" << std::endl;
+ s << "end\n";
// aliases section (if there are any)
if (config.m_map.size() != config.m_nameToCanonicalName.size()) {
@@ -1802,20 +1802,20 @@ operator<<(std::ostream& s, const Config& config)
// dump it
std::string screen;
- s << "section: aliases" << std::endl;
+ s << "section: aliases\n";
for (CMNameMap::const_iterator index = aliases.begin();
index != aliases.end(); ++index) {
if (index->first != screen) {
screen = index->first;
- s << "\t" << screen.c_str() << ":" << std::endl;
+ s << "\t" << screen.c_str() << ":\n";
}
- s << "\t\t" << index->second.c_str() << std::endl;
+ s << "\t\t" << index->second.c_str() << "\n";
}
- s << "end" << std::endl;
+ s << "end\n";
}
// options section
- s << "section: options" << std::endl;
+ s << "section: options\n";
const Config::ScreenOptions* options = config.getOptions("");
if (options != NULL && options->size() > 0) {
for (Config::ScreenOptions::const_iterator
@@ -1824,16 +1824,16 @@ operator<<(std::ostream& s, const Config& config)
const char* name = Config::getOptionName(option->first);
std::string value = Config::getOptionValue(option->first, option->second);
if (name != NULL && !value.empty()) {
- s << "\t" << name << " = " << value << std::endl;
+ s << "\t" << name << " = " << value << "\n";
}
}
}
if (config.m_barrierAddress.isValid()) {
s << "\taddress = " <<
- config.m_barrierAddress.getHostname().c_str() << std::endl;
+ config.m_barrierAddress.getHostname().c_str() << "\n";
}
s << config.m_inputFilter.format("\t");
- s << "end" << std::endl;
+ s << "end\n";
return s;
}
diff --git a/src/lib/server/Config.h b/src/lib/server/Config.h
index c459393..17756a0 100644
--- a/src/lib/server/Config.h
+++ b/src/lib/server/Config.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -174,7 +174,7 @@ public:
Config(IEventQueue* events);
virtual ~Config();
-#ifdef TEST_ENV
+#ifdef BARRIER_TEST_ENV
Config() : m_inputFilter(NULL) { }
#endif
diff --git a/src/lib/server/InputFilter.cpp b/src/lib/server/InputFilter.cpp
index 38d9a84..a0dce17 100644
--- a/src/lib/server/InputFilter.cpp
+++ b/src/lib/server/InputFilter.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2005 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -191,7 +191,7 @@ std::string InputFilter::MouseButtonCondition::format() const
return barrier::string::sprintf("mousebutton(%s%d)", key.c_str(), m_button);
}
-InputFilter::EFilterStatus
+InputFilter::EFilterStatus
InputFilter::MouseButtonCondition::match(const Event& event)
{
static const KeyModifierMask s_ignoreMask =
@@ -252,7 +252,7 @@ InputFilter::EFilterStatus
InputFilter::ScreenConnectedCondition::match(const Event& event)
{
if (event.getType() == m_events->forServer().connected()) {
- Server::ScreenConnectedInfo* info =
+ Server::ScreenConnectedInfo* info =
static_cast<Server::ScreenConnectedInfo*>(event.getData());
if (m_screen == info->m_screen || m_screen.empty()) {
return kActivate;
@@ -312,7 +312,7 @@ InputFilter::LockCursorToScreenAction::perform(const Event& event)
};
// send event
- Server::LockCursorToScreenInfo* info =
+ Server::LockCursorToScreenInfo* info =
Server::LockCursorToScreenInfo::alloc(s_state[m_mode]);
m_events->addEvent(Event(m_events->forServer().lockCursorToScreen(),
event.getTarget(), info,
@@ -350,7 +350,7 @@ InputFilter::SwitchToScreenAction::perform(const Event& event)
// event if it has one.
std::string screen = m_screen;
if (screen.empty() && event.getType() == m_events->forServer().connected()) {
- Server::ScreenConnectedInfo* info =
+ Server::ScreenConnectedInfo* info =
static_cast<Server::ScreenConnectedInfo*>(event.getData());
screen = info->m_screen;
}
@@ -493,7 +493,7 @@ InputFilter::KeyboardBroadcastAction::perform(const Event& event)
};
// send event
- Server::KeyboardBroadcastInfo* info =
+ Server::KeyboardBroadcastInfo* info =
Server::KeyboardBroadcastInfo::alloc(s_state[m_mode], m_screens);
m_events->addEvent(Event(m_events->forServer().keyboardBroadcast(),
event.getTarget(), info,
@@ -569,7 +569,7 @@ InputFilter::KeystrokeAction::perform(const Event& event)
Event::Type type = m_press ?
m_events->forIKeyState().keyDown() :
m_events->forIKeyState().keyUp();
-
+
m_events->addEvent(Event(m_events->forIPrimaryScreen().fakeInputBegin(),
event.getTarget(), NULL,
Event::kDeliverImmediately));
diff --git a/src/lib/server/InputFilter.h b/src/lib/server/InputFilter.h
index 0cb99da..5e6ef9c 100644
--- a/src/lib/server/InputFilter.h
+++ b/src/lib/server/InputFilter.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2005 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -53,7 +53,7 @@ public:
virtual void enablePrimary(PrimaryClient*);
virtual void disablePrimary(PrimaryClient*);
};
-
+
// KeystrokeCondition
class KeystrokeCondition : public Condition {
public:
@@ -118,7 +118,7 @@ public:
// -------------------------------------------------------------------------
// Input Filter Action Classes
// -------------------------------------------------------------------------
-
+
class Action {
public:
Action();
@@ -129,7 +129,7 @@ public:
virtual void perform(const Event&) = 0;
};
-
+
// LockCursorToScreenAction
class LockCursorToScreenAction : public Action {
public:
@@ -148,7 +148,7 @@ public:
Mode m_mode;
IEventQueue* m_events;
};
-
+
// SwitchToScreenAction
class SwitchToScreenAction : public Action {
public:
@@ -165,7 +165,7 @@ public:
std::string m_screen;
IEventQueue* m_events;
};
-
+
// ToggleScreenAction
class ToggleScreenAction : public Action {
public:
@@ -196,7 +196,7 @@ public:
EDirection m_direction;
IEventQueue* m_events;
};
-
+
// KeyboardBroadcastAction
class KeyboardBroadcastAction : public Action {
public:
@@ -333,7 +333,7 @@ public:
InputFilter(const InputFilter&);
virtual ~InputFilter();
-#ifdef TEST_ENV
+#ifdef BARRIER_TEST_ENV
InputFilter() : m_primaryClient(NULL) { }
#endif
diff --git a/src/lib/server/PrimaryClient.cpp b/src/lib/server/PrimaryClient.cpp
index 04ae86c..6583e5d 100644
--- a/src/lib/server/PrimaryClient.cpp
+++ b/src/lib/server/PrimaryClient.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/lib/server/PrimaryClient.h b/src/lib/server/PrimaryClient.h
index 68b91e3..13be838 100644
--- a/src/lib/server/PrimaryClient.h
+++ b/src/lib/server/PrimaryClient.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -37,7 +37,7 @@ public:
PrimaryClient(const std::string& name, barrier::Screen* screen);
~PrimaryClient();
-#ifdef TEST_ENV
+#ifdef BARRIER_TEST_ENV
PrimaryClient() : BaseClientProxy("") { }
#endif
@@ -96,12 +96,12 @@ public:
the edges of the screen, typically the center.
*/
void getCursorCenter(SInt32& x, SInt32& y) const;
-
+
//! Get toggle key state
/*!
Returns the primary screen's current toggle modifier key state.
*/
- virtual KeyModifierMask
+ virtual KeyModifierMask
getToggleMask() const;
//! Get screen lock state
diff --git a/src/lib/server/Server.cpp b/src/lib/server/Server.cpp
index 334049c..a169db1 100644
--- a/src/lib/server/Server.cpp
+++ b/src/lib/server/Server.cpp
@@ -39,7 +39,6 @@
#include "net/XSocket.h"
#include "mt/Thread.h"
#include "arch/Arch.h"
-#include "base/TMethodJob.h"
#include "base/IEventQueue.h"
#include "base/Log.h"
#include "base/TMethodEventJob.h"
@@ -1136,9 +1135,9 @@ Server::processOptions()
return;
}
- m_switchNeedsShift = false; // it seems if i don't add these
+ m_switchNeedsShift = false; // it seems if I don't add these
m_switchNeedsControl = false; // lines, the 'reload config' option
- m_switchNeedsAlt = false; // doesnt' work correct.
+ m_switchNeedsAlt = false; // doesn't work correct.
bool newRelativeMoves = m_relativeMoves;
for (Config::ScreenOptions::const_iterator index = options->begin();
@@ -1824,10 +1823,8 @@ Server::onMouseMovePrimary(SInt32 x, SInt32 y)
&& m_active != newScreen
&& m_waitDragInfoThread) {
if (m_sendDragInfoThread == NULL) {
- m_sendDragInfoThread = new Thread(
- new TMethodJob<Server>(
- this,
- &Server::sendDragInfoThread, newScreen));
+ m_sendDragInfoThread = new Thread([this, newScreen]()
+ { send_drag_info_thread(newScreen); });
}
return false;
@@ -1843,11 +1840,8 @@ Server::onMouseMovePrimary(SInt32 x, SInt32 y)
return false;
}
-void
-Server::sendDragInfoThread(void* arg)
+void Server::send_drag_info_thread(BaseClientProxy* newScreen)
{
- BaseClientProxy* newScreen = static_cast<BaseClientProxy*>(arg);
-
m_dragFileList.clear();
std::string& dragFileList = m_screen->getDraggingFilename();
if (!dragFileList.empty()) {
@@ -2087,14 +2081,11 @@ void
Server::onFileRecieveCompleted()
{
if (isReceivedFileSizeValid()) {
- m_writeToDropDirThread = new Thread(
- new TMethodJob<Server>(
- this, &Server::writeToDropDirThread));
+ m_writeToDropDirThread = new Thread([this]() { write_to_drop_dir_thread(); });
}
}
-void
-Server::writeToDropDirThread(void*)
+void Server::write_to_drop_dir_thread()
{
LOG((CLOG_DEBUG "starting write to drop dir thread"));
@@ -2394,17 +2385,12 @@ Server::sendFileToClient(const char* filename)
StreamChunker::interruptFile();
}
- m_sendFileThread = new Thread(
- new TMethodJob<Server>(
- this, &Server::sendFileThread,
- static_cast<void*>(const_cast<char*>(filename))));
+ m_sendFileThread = new Thread([this, filename]() { send_file_thread(filename); });
}
-void
-Server::sendFileThread(void* data)
+void Server::send_file_thread(const char* filename)
{
try {
- char* filename = static_cast<char*>(data);
LOG((CLOG_DEBUG "sending file to client, filename=%s", filename));
StreamChunker::sendFile(filename, m_events, this);
}
diff --git a/src/lib/server/Server.h b/src/lib/server/Server.h
index bfd0a7d..ae8b2bd 100644
--- a/src/lib/server/Server.h
+++ b/src/lib/server/Server.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -110,7 +110,7 @@ public:
barrier::Screen* screen, IEventQueue* events, ServerArgs const& args);
~Server();
-#ifdef TEST_ENV
+#ifdef BARRIER_TEST_ENV
Server() : m_mock(true), m_config(NULL) { }
void setActive(BaseClientProxy* active) { m_active = active; }
#endif
@@ -150,7 +150,7 @@ public:
//! Store ClientListener pointer
void setListener(ClientListener* p) { m_clientListener = p; }
-
+
//@}
//! @name accessors
//@{
@@ -166,8 +166,8 @@ public:
Set the \c list to the names of the currently connected clients.
*/
void getClients(std::vector<std::string>& list) const;
-
- //! Return true if recieved file size is valid
+
+ //! Return true if received file size is valid
bool isReceivedFileSizeValid();
//! Return expected file data size
@@ -356,15 +356,15 @@ private:
// force the cursor off of \p client
void forceLeaveClient(BaseClientProxy* client);
-
- // thread funciton for sending file
- void sendFileThread(void*);
-
+
+ // thread function for sending file
+ void send_file_thread(const char* filename);
+
// thread function for writing file to drop directory
- void writeToDropDirThread(void*);
+ void write_to_drop_dir_thread();
// thread function for sending drag information
- void sendDragInfoThread(void*);
+ void send_drag_info_thread(BaseClientProxy* newScreen);
// send drag info to new client screen
void sendDragInfo(BaseClientProxy* newScreen);
@@ -448,7 +448,7 @@ private:
bool m_switchNeedsShift;
bool m_switchNeedsControl;
bool m_switchNeedsAlt;
-
+
// relative mouse move option
bool m_relativeMoves;
diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt
deleted file mode 100644
index daecb31..0000000
--- a/src/test/CMakeLists.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-# barrier -- mouse and keyboard sharing utility
-# Copyright (C) 2012-2016 Symless Ltd.
-# Copyright (C) 2011 Nick Bolton
-#
-# This package is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# found in the file LICENSE that should have accompanied this file.
-#
-# This package is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-include_directories(
- ../../ext/gtest
- ../../ext/gtest/include
- ../../ext/gmock
- ../../ext/gmock/include)
-
-add_library(gtest STATIC ../../ext/gtest/src/gtest-all.cc)
-add_library(gmock STATIC ../../ext/gmock/src/gmock-all.cc)
-
-if (UNIX)
- # ignore warnings in gtest and gmock
- set_target_properties(gtest PROPERTIES COMPILE_FLAGS "-w")
- set_target_properties(gmock PROPERTIES COMPILE_FLAGS "-w")
-endif()
-
-add_subdirectory(integtests)
-add_subdirectory(unittests)
diff --git a/src/test/global/TestEventQueue.cpp b/src/test/global/TestEventQueue.cpp
index 4dd01e7..253e9ab 100644
--- a/src/test/global/TestEventQueue.cpp
+++ b/src/test/global/TestEventQueue.cpp
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2013-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -23,7 +23,7 @@
#include <stdexcept>
void
-TestEventQueue::raiseQuitEvent()
+TestEventQueue::raiseQuitEvent()
{
addEvent(Event(Event::kQuit));
}
diff --git a/src/test/global/TestEventQueue.h b/src/test/global/TestEventQueue.h
index b932508..14568b6 100644
--- a/src/test/global/TestEventQueue.h
+++ b/src/test/global/TestEventQueue.h
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2013-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/test/global/TestUtils.cpp b/src/test/global/TestUtils.cpp
new file mode 100644
index 0000000..6a3193b
--- /dev/null
+++ b/src/test/global/TestUtils.cpp
@@ -0,0 +1,37 @@
+/*
+ barrier -- mouse and keyboard sharing utility
+ Copyright (C) Barrier contributors
+
+ This package is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ found in the file LICENSE that should have accompanied this file.
+
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "TestUtils.h"
+#include <random>
+
+namespace barrier {
+
+std::vector<std::uint8_t> generate_pseudo_random_bytes(std::size_t seed, std::size_t size)
+{
+ std::mt19937_64 engine{seed};
+ std::uniform_int_distribution<int> dist{0, 255};
+ std::vector<std::uint8_t> bytes;
+
+ bytes.reserve(size);
+ for (std::size_t i = 0; i < size; ++i) {
+ bytes.push_back(dist(engine));
+ }
+
+ return bytes;
+}
+
+} // namespace barrier
diff --git a/src/test/global/TestUtils.h b/src/test/global/TestUtils.h
new file mode 100644
index 0000000..31050ec
--- /dev/null
+++ b/src/test/global/TestUtils.h
@@ -0,0 +1,30 @@
+/*
+ barrier -- mouse and keyboard sharing utility
+ Copyright (C) Barrier contributors
+
+ This package is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ found in the file LICENSE that should have accompanied this file.
+
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef BARRIER_TEST_GLOBAL_TEST_UTILS_H
+#define BARRIER_TEST_GLOBAL_TEST_UTILS_H
+
+#include <cstdint>
+#include <vector>
+
+namespace barrier {
+
+std::vector<std::uint8_t> generate_pseudo_random_bytes(std::size_t seed, std::size_t size);
+
+} // namespace barrier
+
+#endif // BARRIER_TEST_GLOBAL_TEST_UTILS_H
diff --git a/src/test/global/gmock.h b/src/test/global/gmock.h
index 64597f4..8a27440 100644
--- a/src/test/global/gmock.h
+++ b/src/test/global/gmock.h
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2014-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/test/global/gtest.h b/src/test/global/gtest.h
index 0b2acbc..55cb10f 100644
--- a/src/test/global/gtest.h
+++ b/src/test/global/gtest.h
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2014-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/test/guitests/src/VersionCheckerTests.cpp b/src/test/guitests/src/VersionCheckerTests.cpp
index 0efc5f9..82212a7 100644
--- a/src/test/guitests/src/VersionCheckerTests.cpp
+++ b/src/test/guitests/src/VersionCheckerTests.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/test/guitests/src/VersionCheckerTests.h b/src/test/guitests/src/VersionCheckerTests.h
index 7884f3a..4273701 100644
--- a/src/test/guitests/src/VersionCheckerTests.h
+++ b/src/test/guitests/src/VersionCheckerTests.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/test/guitests/src/main.cpp b/src/test/guitests/src/main.cpp
index 2ff6e72..6b7677e 100644
--- a/src/test/guitests/src/main.cpp
+++ b/src/test/guitests/src/main.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/test/integtests/CMakeLists.txt b/src/test/integtests/CMakeLists.txt
index 0460d8d..cdb8844 100644
--- a/src/test/integtests/CMakeLists.txt
+++ b/src/test/integtests/CMakeLists.txt
@@ -1,11 +1,11 @@
# barrier -- mouse and keyboard sharing utility
# Copyright (C) 2012-2016 Symless Ltd.
# Copyright (C) 2009 Nick Bolton
-#
+#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
-#
+#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -68,8 +68,6 @@ endif()
include_directories(
../../
- ../../../ext/gtest/include
- ../../../ext/gmock/include
)
if (UNIX)
@@ -80,4 +78,4 @@ endif()
add_executable(integtests ${sources})
target_link_libraries(integtests
- arch base client common io ipc mt net platform server synlib gtest gmock ${libs} ${OPENSSL_LIBS})
+ arch base client common io ipc mt net platform server synlib ${GTEST_LIBRARIES} ${GMOCK_LIBRARIES} ${libs} ${OPENSSL_LIBS})
diff --git a/src/test/integtests/Main.cpp b/src/test/integtests/Main.cpp
index 76b42b6..f4eaca7 100644
--- a/src/test/integtests/Main.cpp
+++ b/src/test/integtests/Main.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2011 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -44,7 +44,7 @@ main(int argc, char **argv)
Arch arch;
arch.init();
-
+
Log log;
log.setFilter(kDEBUG2);
@@ -67,7 +67,7 @@ main(int argc, char **argv)
if (!lockFile.empty()) {
unlock(lockFile);
}
-
+
// gtest seems to randomly finish with error codes (e.g. -1, -1073741819)
// even when no tests have failed. not sure what causes this, but it
// happens on all platforms and keeps leading to false positives.
@@ -80,7 +80,7 @@ void
lock(string lockFile)
{
double start = ARCH->time();
-
+
// keep checking until timeout is reached.
while ((ARCH->time() - start) < LOCK_TIMEOUT) {
@@ -102,7 +102,7 @@ lock(string lockFile)
}
void
-unlock(string lockFile)
+unlock(string lockFile)
{
remove(lockFile.c_str());
}
diff --git a/src/test/integtests/ipc/IpcTests.cpp b/src/test/integtests/ipc/IpcTests.cpp
index a0ee241..ce15d59 100644
--- a/src/test/integtests/ipc/IpcTests.cpp
+++ b/src/test/integtests/ipc/IpcTests.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -19,7 +19,7 @@
// TODO: fix, tests failing intermittently on mac.
#ifndef WINAPI_CARBON
-#define TEST_ENV
+#define BARRIER_TEST_ENV
#include "test/global/TestEventQueue.h"
#include "ipc/IpcServer.h"
@@ -31,7 +31,6 @@
#include "net/SocketMultiplexer.h"
#include "mt/Thread.h"
#include "arch/Arch.h"
-#include "base/TMethodJob.h"
#include "base/String.h"
#include "base/Log.h"
#include "base/EventQueue.h"
@@ -46,7 +45,7 @@ class IpcTests : public ::testing::Test
public:
IpcTests();
virtual ~IpcTests();
-
+
void connectToServer_handleMessageReceived(const Event&, void*);
void sendMessageToServer_serverHandleMessageReceived(const Event&, void*);
void sendMessageToClient_serverHandleClientConnected(const Event&, void*);
@@ -76,15 +75,15 @@ TEST_F(IpcTests, connectToServer)
m_events.forIpcServer().messageReceived(), &server,
new TMethodEventJob<IpcTests>(
this, &IpcTests::connectToServer_handleMessageReceived));
-
+
IpcClient client(&m_events, &socketMultiplexer, TEST_IPC_PORT);
client.connect();
-
+
m_events.initQuitTimeout(5);
m_events.loop();
m_events.removeHandler(m_events.forIpcServer().messageReceived(), &server);
m_events.cleanupQuitTimeout();
-
+
EXPECT_EQ(true, m_connectToServer_helloMessageReceived);
EXPECT_EQ(true, m_connectToServer_hasClientNode);
}
@@ -94,13 +93,13 @@ TEST_F(IpcTests, sendMessageToServer)
SocketMultiplexer socketMultiplexer;
IpcServer server(&m_events, &socketMultiplexer, TEST_IPC_PORT);
server.listen();
-
+
// event handler sends "test" command to server.
m_events.adoptHandler(
m_events.forIpcServer().messageReceived(), &server,
new TMethodEventJob<IpcTests>(
this, &IpcTests::sendMessageToServer_serverHandleMessageReceived));
-
+
IpcClient client(&m_events, &socketMultiplexer, TEST_IPC_PORT);
client.connect();
m_sendMessageToServer_client = &client;
@@ -128,7 +127,7 @@ TEST_F(IpcTests, sendMessageToClient)
IpcClient client(&m_events, &socketMultiplexer, TEST_IPC_PORT);
client.connect();
-
+
m_events.adoptHandler(
m_events.forIpcClient().messageReceived(), &client,
new TMethodEventJob<IpcTests>(
diff --git a/src/test/integtests/net/NetworkTests.cpp b/src/test/integtests/net/NetworkTests.cpp
index d404abc..92767bf 100644
--- a/src/test/integtests/net/NetworkTests.cpp
+++ b/src/test/integtests/net/NetworkTests.cpp
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2013-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -18,7 +18,7 @@
// TODO: fix, tests failing intermittently on mac.
#ifndef WINAPI_CARBON
-#define TEST_ENV
+#define BARRIER_TEST_ENV
#include "test/mock/server/MockConfig.h"
#include "test/mock/server/MockPrimaryClient.h"
@@ -36,7 +36,6 @@
#include "net/TCPSocketFactory.h"
#include "mt/Thread.h"
#include "base/TMethodEventJob.h"
-#include "base/TMethodJob.h"
#include "base/Log.h"
#include <stdexcept>
@@ -84,19 +83,19 @@ public:
}
void sendMockData(void* eventTarget);
-
+
void sendToClient_mockData_handleClientConnected(const Event&, void* vlistener);
void sendToClient_mockData_fileRecieveCompleted(const Event&, void*);
-
+
void sendToClient_mockFile_handleClientConnected(const Event&, void* vlistener);
void sendToClient_mockFile_fileRecieveCompleted(const Event& event, void*);
-
+
void sendToServer_mockData_handleClientConnected(const Event&, void* vlistener);
void sendToServer_mockData_fileRecieveCompleted(const Event& event, void*);
void sendToServer_mockFile_handleClientConnected(const Event&, void* vlistener);
void sendToServer_mockFile_fileRecieveCompleted(const Event& event, void*);
-
+
public:
TestEventQueue m_events;
UInt8* m_mockData;
@@ -111,16 +110,17 @@ TEST_F(NetworkTests, sendToClient_mockData)
NetworkAddress serverAddress(TEST_HOST, TEST_PORT);
serverAddress.resolve();
-
+
// server
SocketMultiplexer serverSocketMultiplexer;
TCPSocketFactory* serverSocketFactory = new TCPSocketFactory(&m_events, &serverSocketMultiplexer);
- ClientListener listener(serverAddress, serverSocketFactory, &m_events, false);
+ ClientListener listener(serverAddress, serverSocketFactory, &m_events,
+ ConnectionSecurityLevel::PLAINTEXT);
NiceMock<MockScreen> serverScreen;
NiceMock<MockPrimaryClient> primaryClient;
NiceMock<MockConfig> serverConfig;
NiceMock<MockInputFilter> serverInputFilter;
-
+
m_events.adoptHandler(
m_events.forClientListener().connected(), &listener,
new TMethodEventJob<NetworkTests>(
@@ -128,7 +128,7 @@ TEST_F(NetworkTests, sendToClient_mockData)
ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true));
ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter));
-
+
ServerArgs serverArgs;
serverArgs.m_enableDragDrop = true;
Server server(serverConfig, &primaryClient, &serverScreen, &m_events, serverArgs);
@@ -139,7 +139,7 @@ TEST_F(NetworkTests, sendToClient_mockData)
NiceMock<MockScreen> clientScreen;
SocketMultiplexer clientSocketMultiplexer;
TCPSocketFactory* clientSocketFactory = new TCPSocketFactory(&m_events, &clientSocketMultiplexer);
-
+
ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape));
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos));
@@ -148,7 +148,7 @@ TEST_F(NetworkTests, sendToClient_mockData)
clientArgs.m_enableDragDrop = true;
clientArgs.m_enableCrypto = false;
Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, clientArgs);
-
+
m_events.adoptHandler(
m_events.forFile().fileRecieveCompleted(), &client,
new TMethodEventJob<NetworkTests>(
@@ -169,16 +169,17 @@ TEST_F(NetworkTests, sendToClient_mockFile)
NetworkAddress serverAddress(TEST_HOST, TEST_PORT);
serverAddress.resolve();
-
+
// server
SocketMultiplexer serverSocketMultiplexer;
TCPSocketFactory* serverSocketFactory = new TCPSocketFactory(&m_events, &serverSocketMultiplexer);
- ClientListener listener(serverAddress, serverSocketFactory, &m_events, false);
+ ClientListener listener(serverAddress, serverSocketFactory, &m_events,
+ ConnectionSecurityLevel::PLAINTEXT);
NiceMock<MockScreen> serverScreen;
NiceMock<MockPrimaryClient> primaryClient;
NiceMock<MockConfig> serverConfig;
NiceMock<MockInputFilter> serverInputFilter;
-
+
m_events.adoptHandler(
m_events.forClientListener().connected(), &listener,
new TMethodEventJob<NetworkTests>(
@@ -186,7 +187,7 @@ TEST_F(NetworkTests, sendToClient_mockFile)
ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true));
ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter));
-
+
ServerArgs serverArgs;
serverArgs.m_enableDragDrop = true;
Server server(serverConfig, &primaryClient, &serverScreen, &m_events, serverArgs);
@@ -197,7 +198,7 @@ TEST_F(NetworkTests, sendToClient_mockFile)
NiceMock<MockScreen> clientScreen;
SocketMultiplexer clientSocketMultiplexer;
TCPSocketFactory* clientSocketFactory = new TCPSocketFactory(&m_events, &clientSocketMultiplexer);
-
+
ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape));
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos));
@@ -206,7 +207,7 @@ TEST_F(NetworkTests, sendToClient_mockFile)
clientArgs.m_enableDragDrop = true;
clientArgs.m_enableCrypto = false;
Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, clientArgs);
-
+
m_events.adoptHandler(
m_events.forFile().fileRecieveCompleted(), &client,
new TMethodEventJob<NetworkTests>(
@@ -230,7 +231,8 @@ TEST_F(NetworkTests, sendToServer_mockData)
// server
SocketMultiplexer serverSocketMultiplexer;
TCPSocketFactory* serverSocketFactory = new TCPSocketFactory(&m_events, &serverSocketMultiplexer);
- ClientListener listener(serverAddress, serverSocketFactory, &m_events, false);
+ ClientListener listener(serverAddress, serverSocketFactory, &m_events,
+ ConnectionSecurityLevel::PLAINTEXT);
NiceMock<MockScreen> serverScreen;
NiceMock<MockPrimaryClient> primaryClient;
NiceMock<MockConfig> serverConfig;
@@ -238,7 +240,7 @@ TEST_F(NetworkTests, sendToServer_mockData)
ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true));
ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter));
-
+
ServerArgs serverArgs;
serverArgs.m_enableDragDrop = true;
Server server(serverConfig, &primaryClient, &serverScreen, &m_events, serverArgs);
@@ -249,7 +251,7 @@ TEST_F(NetworkTests, sendToServer_mockData)
NiceMock<MockScreen> clientScreen;
SocketMultiplexer clientSocketMultiplexer;
TCPSocketFactory* clientSocketFactory = new TCPSocketFactory(&m_events, &clientSocketMultiplexer);
-
+
ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape));
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos));
@@ -257,7 +259,7 @@ TEST_F(NetworkTests, sendToServer_mockData)
clientArgs.m_enableDragDrop = true;
clientArgs.m_enableCrypto = false;
Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, clientArgs);
-
+
m_events.adoptHandler(
m_events.forClientListener().connected(), &listener,
new TMethodEventJob<NetworkTests>(
@@ -287,7 +289,8 @@ TEST_F(NetworkTests, sendToServer_mockFile)
// server
SocketMultiplexer serverSocketMultiplexer;
TCPSocketFactory* serverSocketFactory = new TCPSocketFactory(&m_events, &serverSocketMultiplexer);
- ClientListener listener(serverAddress, serverSocketFactory, &m_events, false);
+ ClientListener listener(serverAddress, serverSocketFactory, &m_events,
+ ConnectionSecurityLevel::PLAINTEXT);
NiceMock<MockScreen> serverScreen;
NiceMock<MockPrimaryClient> primaryClient;
NiceMock<MockConfig> serverConfig;
@@ -295,7 +298,7 @@ TEST_F(NetworkTests, sendToServer_mockFile)
ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true));
ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter));
-
+
ServerArgs serverArgs;
serverArgs.m_enableDragDrop = true;
Server server(serverConfig, &primaryClient, &serverScreen, &m_events, serverArgs);
@@ -306,7 +309,7 @@ TEST_F(NetworkTests, sendToServer_mockFile)
NiceMock<MockScreen> clientScreen;
SocketMultiplexer clientSocketMultiplexer;
TCPSocketFactory* clientSocketFactory = new TCPSocketFactory(&m_events, &clientSocketMultiplexer);
-
+
ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape));
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos));
@@ -334,7 +337,7 @@ TEST_F(NetworkTests, sendToServer_mockFile)
m_events.cleanupQuitTimeout();
}
-void
+void
NetworkTests::sendToClient_mockData_handleClientConnected(const Event&, void* vlistener)
{
ClientListener* listener = static_cast<ClientListener*>(vlistener);
@@ -352,7 +355,7 @@ NetworkTests::sendToClient_mockData_handleClientConnected(const Event&, void* vl
sendMockData(server);
}
-void
+void
NetworkTests::sendToClient_mockData_fileRecieveCompleted(const Event& event, void*)
{
Client* client = static_cast<Client*>(event.getTarget());
@@ -361,7 +364,7 @@ NetworkTests::sendToClient_mockData_fileRecieveCompleted(const Event& event, voi
m_events.raiseQuitEvent();
}
-void
+void
NetworkTests::sendToClient_mockFile_handleClientConnected(const Event&, void* vlistener)
{
ClientListener* listener = static_cast<ClientListener*>(vlistener);
@@ -379,7 +382,7 @@ NetworkTests::sendToClient_mockFile_handleClientConnected(const Event&, void* vl
server->sendFileToClient(kMockFilename);
}
-void
+void
NetworkTests::sendToClient_mockFile_fileRecieveCompleted(const Event& event, void*)
{
Client* client = static_cast<Client*>(event.getTarget());
@@ -388,14 +391,14 @@ NetworkTests::sendToClient_mockFile_fileRecieveCompleted(const Event& event, voi
m_events.raiseQuitEvent();
}
-void
+void
NetworkTests::sendToServer_mockData_handleClientConnected(const Event&, void* vclient)
{
Client* client = static_cast<Client*>(vclient);
sendMockData(client);
}
-void
+void
NetworkTests::sendToServer_mockData_fileRecieveCompleted(const Event& event, void*)
{
Server* server = static_cast<Server*>(event.getTarget());
@@ -404,14 +407,14 @@ NetworkTests::sendToServer_mockData_fileRecieveCompleted(const Event& event, voi
m_events.raiseQuitEvent();
}
-void
+void
NetworkTests::sendToServer_mockFile_handleClientConnected(const Event&, void* vclient)
{
Client* client = static_cast<Client*>(vclient);
client->sendFileToServer(kMockFilename);
}
-void
+void
NetworkTests::sendToServer_mockFile_fileRecieveCompleted(const Event& event, void*)
{
Server* server = static_cast<Server*>(event.getTarget());
@@ -420,13 +423,13 @@ NetworkTests::sendToServer_mockFile_fileRecieveCompleted(const Event& event, voi
m_events.raiseQuitEvent();
}
-void
+void
NetworkTests::sendMockData(void* eventTarget)
{
// send first message (file size)
String size = barrier::string::sizeTypeToString(kMockDataSize);
FileChunk* sizeMessage = FileChunk::start(size);
-
+
m_events.addEvent(Event(m_events.forFile().fileChunkSending(), eventTarget, sizeMessage));
// send chunk messages with incrementing chunk size
@@ -452,7 +455,7 @@ NetworkTests::sendMockData(void* eventTarget)
}
}
-
+
// send last message
FileChunk* transferFinished = FileChunk::end();
m_events.addEvent(Event(m_events.forFile().fileChunkSending(), eventTarget, transferFinished));
diff --git a/src/test/integtests/platform/MSWindowsClipboardTests.cpp b/src/test/integtests/platform/MSWindowsClipboardTests.cpp
index f9d09d1..edf5a97 100644
--- a/src/test/integtests/platform/MSWindowsClipboardTests.cpp
+++ b/src/test/integtests/platform/MSWindowsClipboardTests.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2011 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -36,7 +36,7 @@ protected:
}
private:
- void emptyClipboard()
+ void emptyClipboard()
{
MSWindowsClipboard clipboard(NULL);
clipboard.open(0);
diff --git a/src/test/integtests/platform/MSWindowsKeyStateTests.cpp b/src/test/integtests/platform/MSWindowsKeyStateTests.cpp
index 9373d14..6f6edf5 100644
--- a/src/test/integtests/platform/MSWindowsKeyStateTests.cpp
+++ b/src/test/integtests/platform/MSWindowsKeyStateTests.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2011 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -16,7 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#define TEST_ENV
+#define BARRIER_TEST_ENV
#include "test/mock/barrier/MockEventQueue.h"
#include "test/mock/barrier/MockKeyMap.h"
@@ -24,7 +24,6 @@
#include "platform/MSWindowsDesks.h"
#include "platform/MSWindowsScreen.h"
#include "platform/MSWindowsScreenSaver.h"
-#include "base/TMethodJob.h"
#include "test/global/gtest.h"
#include "test/global/gmock.h"
@@ -50,10 +49,7 @@ protected:
MSWindowsDesks* newDesks(IEventQueue* eventQueue)
{
- return new MSWindowsDesks(
- true, false, m_screensaver, eventQueue,
- new TMethodJob<MSWindowsKeyStateTests>(
- this, &MSWindowsKeyStateTests::updateKeysCB), false);
+ return new MSWindowsDesks(true, false, m_screensaver, eventQueue, [](){}, false);
}
void* getEventTarget() const
@@ -62,9 +58,7 @@ protected:
}
private:
- void updateKeysCB(void*) { }
IScreenSaver* m_screensaver;
- MSWindowsHook m_hook;
};
TEST_F(MSWindowsKeyStateTests, disable_eventQueueNotUsed)
@@ -73,7 +67,7 @@ TEST_F(MSWindowsKeyStateTests, disable_eventQueueNotUsed)
MSWindowsDesks* desks = newDesks(&eventQueue);
MockKeyMap keyMap;
MSWindowsKeyState keyState(desks, getEventTarget(), &eventQueue, keyMap);
-
+
EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(0);
keyState.disable();
diff --git a/src/test/integtests/platform/OSXClipboardTests.cpp b/src/test/integtests/platform/OSXClipboardTests.cpp
index 45b73bd..093c738 100644
--- a/src/test/integtests/platform/OSXClipboardTests.cpp
+++ b/src/test/integtests/platform/OSXClipboardTests.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2011 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -25,9 +25,9 @@ TEST(OSXClipboardTests, empty_openCalled_returnsTrue)
{
OSXClipboard clipboard;
clipboard.open(0);
-
+
bool actual = clipboard.empty();
-
+
EXPECT_EQ(true, actual);
}
@@ -36,9 +36,9 @@ TEST(OSXClipboardTests, empty_singleFormat_hasReturnsFalse)
OSXClipboard clipboard;
clipboard.open(0);
clipboard.add(OSXClipboard::kText, "barrier rocks!");
-
+
clipboard.empty();
-
+
bool actual = clipboard.has(OSXClipboard::kText);
EXPECT_EQ(false, actual);
}
@@ -47,9 +47,9 @@ TEST(OSXClipboardTests, add_newValue_valueWasStored)
{
OSXClipboard clipboard;
clipboard.open(0);
-
+
clipboard.add(IClipboard::kText, "barrier rocks!");
-
+
String actual = clipboard.get(IClipboard::kText);
EXPECT_EQ("barrier rocks!", actual);
}
@@ -58,10 +58,10 @@ TEST(OSXClipboardTests, add_replaceValue_valueWasReplaced)
{
OSXClipboard clipboard;
clipboard.open(0);
-
+
clipboard.add(IClipboard::kText, "barrier rocks!");
clipboard.add(IClipboard::kText, "maxivista sucks"); // haha, just kidding.
-
+
String actual = clipboard.get(IClipboard::kText);
EXPECT_EQ("maxivista sucks", actual);
}
@@ -69,18 +69,18 @@ TEST(OSXClipboardTests, add_replaceValue_valueWasReplaced)
TEST(OSXClipboardTests, open_timeIsZero_returnsTrue)
{
OSXClipboard clipboard;
-
+
bool actual = clipboard.open(0);
-
+
EXPECT_EQ(true, actual);
}
TEST(OSXClipboardTests, open_timeIsOne_returnsTrue)
{
OSXClipboard clipboard;
-
+
bool actual = clipboard.open(1);
-
+
EXPECT_EQ(true, actual);
}
@@ -88,9 +88,9 @@ TEST(OSXClipboardTests, close_isOpen_noErrors)
{
OSXClipboard clipboard;
clipboard.open(0);
-
+
clipboard.close();
-
+
// can't assert anything
}
@@ -98,9 +98,9 @@ TEST(OSXClipboardTests, getTime_openWithNoEmpty_returnsOne)
{
OSXClipboard clipboard;
clipboard.open(1);
-
+
OSXClipboard::Time actual = clipboard.getTime();
-
+
// this behavior is different to that of Clipboard which only
// returns the value passed into open(t) after empty() is called.
EXPECT_EQ((UInt32)1, actual);
@@ -111,9 +111,9 @@ TEST(OSXClipboardTests, getTime_openAndEmpty_returnsOne)
OSXClipboard clipboard;
clipboard.open(1);
clipboard.empty();
-
+
OSXClipboard::Time actual = clipboard.getTime();
-
+
EXPECT_EQ((UInt32)1, actual);
}
@@ -123,9 +123,9 @@ TEST(OSXClipboardTests, has_withFormatAdded_returnsTrue)
clipboard.open(0);
clipboard.empty();
clipboard.add(IClipboard::kText, "barrier rocks!");
-
+
bool actual = clipboard.has(IClipboard::kText);
-
+
EXPECT_EQ(true, actual);
}
@@ -134,9 +134,9 @@ TEST(OSXClipboardTests, has_withNoFormats_returnsFalse)
OSXClipboard clipboard;
clipboard.open(0);
clipboard.empty();
-
+
bool actual = clipboard.has(IClipboard::kText);
-
+
EXPECT_EQ(false, actual);
}
@@ -145,9 +145,9 @@ TEST(OSXClipboardTests, get_withNoFormats_returnsEmpty)
OSXClipboard clipboard;
clipboard.open(0);
clipboard.empty();
-
+
String actual = clipboard.get(IClipboard::kText);
-
+
EXPECT_EQ("", actual);
}
@@ -157,8 +157,8 @@ TEST(OSXClipboardTests, get_withFormatAdded_returnsExpected)
clipboard.open(0);
clipboard.empty();
clipboard.add(IClipboard::kText, "barrier rocks!");
-
+
String actual = clipboard.get(IClipboard::kText);
-
+
EXPECT_EQ("barrier rocks!", actual);
}
diff --git a/src/test/integtests/platform/OSXScreenTests.cpp b/src/test/integtests/platform/OSXScreenTests.cpp
index 96beb4d..390e22f 100644
--- a/src/test/integtests/platform/OSXScreenTests.cpp
+++ b/src/test/integtests/platform/OSXScreenTests.cpp
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/test/integtests/platform/XWindowsClipboardTests.cpp b/src/test/integtests/platform/XWindowsClipboardTests.cpp
index 652ee5e..52eacda 100644
--- a/src/test/integtests/platform/XWindowsClipboardTests.cpp
+++ b/src/test/integtests/platform/XWindowsClipboardTests.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2011 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -33,12 +33,12 @@ protected:
m_display = XOpenDisplay(NULL);
int screen = DefaultScreen(m_display);
Window root = XRootWindow(m_display, screen);
-
+
XSetWindowAttributes attr;
attr.do_not_propagate_mask = 0;
attr.override_redirect = True;
attr.cursor = Cursor();
-
+
m_window = XCreateWindow(
m_display, root, 0, 0, 1, 1, 0, 0,
InputOnly, CopyFromParent, 0, &attr);
@@ -68,9 +68,9 @@ protected:
TEST_F(CXWindowsClipboardTests, empty_openCalled_returnsTrue)
{
CXWindowsClipboard clipboard = createClipboard();
-
+
bool actual = clipboard.empty();
-
+
EXPECT_EQ(true, actual);
}
@@ -78,9 +78,9 @@ TEST_F(CXWindowsClipboardTests, empty_singleFormat_hasReturnsFalse)
{
CXWindowsClipboard clipboard = createClipboard();
clipboard.add(CXWindowsClipboard::kText, "barrier rocks!");
-
+
clipboard.empty();
-
+
bool actual = clipboard.has(CXWindowsClipboard::kText);
EXPECT_FALSE(actual);
}
@@ -88,9 +88,9 @@ TEST_F(CXWindowsClipboardTests, empty_singleFormat_hasReturnsFalse)
TEST_F(CXWindowsClipboardTests, add_newValue_valueWasStored)
{
CXWindowsClipboard clipboard = createClipboard();
-
+
clipboard.add(IClipboard::kText, "barrier rocks!");
-
+
String actual = clipboard.get(IClipboard::kText);
EXPECT_EQ("barrier rocks!", actual);
}
@@ -98,10 +98,10 @@ TEST_F(CXWindowsClipboardTests, add_newValue_valueWasStored)
TEST_F(CXWindowsClipboardTests, add_replaceValue_valueWasReplaced)
{
CXWindowsClipboard clipboard = createClipboard();
-
+
clipboard.add(IClipboard::kText, "barrier rocks!");
clipboard.add(IClipboard::kText, "maxivista sucks"); // haha, just kidding.
-
+
String actual = clipboard.get(IClipboard::kText);
EXPECT_EQ("maxivista sucks", actual);
}
@@ -109,10 +109,10 @@ TEST_F(CXWindowsClipboardTests, add_replaceValue_valueWasReplaced)
TEST_F(CXWindowsClipboardTests, close_isOpen_noErrors)
{
CXWindowsClipboard clipboard = createClipboard();
-
+
// clipboard opened in createClipboard()
clipboard.close();
-
+
// can't assert anything
}
@@ -120,27 +120,27 @@ TEST_F(CXWindowsClipboardTests, has_withFormatAdded_returnsTrue)
{
CXWindowsClipboard clipboard = createClipboard();
clipboard.add(IClipboard::kText, "barrier rocks!");
-
+
bool actual = clipboard.has(IClipboard::kText);
-
+
EXPECT_EQ(true, actual);
}
TEST_F(CXWindowsClipboardTests, has_withNoFormats_returnsFalse)
{
CXWindowsClipboard clipboard = createClipboard();
-
+
bool actual = clipboard.has(IClipboard::kText);
-
+
EXPECT_FALSE(actual);
}
TEST_F(CXWindowsClipboardTests, get_withNoFormats_returnsEmpty)
{
CXWindowsClipboard clipboard = createClipboard();
-
+
String actual = clipboard.get(IClipboard::kText);
-
+
EXPECT_EQ("", actual);
}
@@ -148,9 +148,9 @@ TEST_F(CXWindowsClipboardTests, get_withFormatAdded_returnsExpected)
{
CXWindowsClipboard clipboard = createClipboard();
clipboard.add(IClipboard::kText, "barrier rocks!");
-
+
String actual = clipboard.get(IClipboard::kText);
-
+
EXPECT_EQ("barrier rocks!", actual);
}
diff --git a/src/test/integtests/platform/XWindowsKeyStateTests.cpp b/src/test/integtests/platform/XWindowsKeyStateTests.cpp
index 9f6716d..28d090f 100644
--- a/src/test/integtests/platform/XWindowsKeyStateTests.cpp
+++ b/src/test/integtests/platform/XWindowsKeyStateTests.cpp
@@ -16,7 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#define TEST_ENV
+#define BARRIER_TEST_ENV
#include "test/mock/barrier/MockKeyMap.h"
#include "test/mock/barrier/MockEventQueue.h"
diff --git a/src/test/integtests/platform/XWindowsScreenSaverTests.cpp b/src/test/integtests/platform/XWindowsScreenSaverTests.cpp
index c6a2710..a3af21d 100644
--- a/src/test/integtests/platform/XWindowsScreenSaverTests.cpp
+++ b/src/test/integtests/platform/XWindowsScreenSaverTests.cpp
@@ -23,6 +23,7 @@
#include "platform/XWindowsScreenSaver.h"
#include "test/global/gtest.h"
+#include <cstdlib>
#include <X11/Xlib.h>
using ::testing::_;
@@ -30,7 +31,12 @@ using ::testing::_;
// TODO: not working on build machine for some reason
TEST(CXWindowsScreenSaverTests, activate_defaultScreen_todo)
{
- Display* display = XOpenDisplay(":0.0");
+ const char* displayName = std::getenv("DISPLAY");
+ if (displayName == NULL) {
+ displayName = ":0.0";
+ }
+
+ Display* display = XOpenDisplay(displayName);
Window window = DefaultRootWindow(display);
MockEventQueue eventQueue;
EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(1);
diff --git a/src/test/integtests/platform/XWindowsScreenTests.cpp b/src/test/integtests/platform/XWindowsScreenTests.cpp
index d8f75e1..53f113e 100644
--- a/src/test/integtests/platform/XWindowsScreenTests.cpp
+++ b/src/test/integtests/platform/XWindowsScreenTests.cpp
@@ -20,16 +20,22 @@
#include "platform/XWindowsScreen.h"
#include "test/global/gtest.h"
+#include <cstdlib>
using ::testing::_;
TEST(CXWindowsScreenTests, fakeMouseMove_nonPrimary_getCursorPosValuesCorrect)
{
+ const char* displayName = std::getenv("DISPLAY");
+ if (displayName == NULL) {
+ displayName = ":0.0";
+ }
+
MockEventQueue eventQueue;
EXPECT_CALL(eventQueue, adoptHandler(_, _, _)).Times(2);
EXPECT_CALL(eventQueue, adoptBuffer(_)).Times(2);
EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(2);
- XWindowsScreen screen(new XWindowsImpl(), ":0.0", false, false, 0, &eventQueue);
+ XWindowsScreen screen(new XWindowsImpl(), displayName, false, false, 0, &eventQueue);
screen.fakeMouseMove(10, 20);
diff --git a/src/test/mock/barrier/MockApp.h b/src/test/mock/barrier/MockApp.h
index 91745d3..fd4094d 100644
--- a/src/test/mock/barrier/MockApp.h
+++ b/src/test/mock/barrier/MockApp.h
@@ -17,7 +17,7 @@
#pragma once
-#define TEST_ENV
+#define BARRIER_TEST_ENV
#include "barrier/App.h"
diff --git a/src/test/mock/barrier/MockArgParser.h b/src/test/mock/barrier/MockArgParser.h
index b1dc07c..35d4ff9 100644
--- a/src/test/mock/barrier/MockArgParser.h
+++ b/src/test/mock/barrier/MockArgParser.h
@@ -17,7 +17,7 @@
#pragma once
-#define TEST_ENV
+#define BARRIER_TEST_ENV
#include "barrier/ArgParser.h"
diff --git a/src/test/mock/barrier/MockEventQueue.h b/src/test/mock/barrier/MockEventQueue.h
index 735b9fc..76175bb 100644
--- a/src/test/mock/barrier/MockEventQueue.h
+++ b/src/test/mock/barrier/MockEventQueue.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2011 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/test/mock/barrier/MockKeyState.h b/src/test/mock/barrier/MockKeyState.h
index 308e90a..d245ee6 100644
--- a/src/test/mock/barrier/MockKeyState.h
+++ b/src/test/mock/barrier/MockKeyState.h
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2011 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/test/mock/barrier/MockScreen.h b/src/test/mock/barrier/MockScreen.h
index 78c195a..3c05218 100644
--- a/src/test/mock/barrier/MockScreen.h
+++ b/src/test/mock/barrier/MockScreen.h
@@ -17,7 +17,7 @@
#pragma once
-#define TEST_ENV
+#define BARRIER_TEST_ENV
#include "barrier/Screen.h"
diff --git a/src/test/mock/ipc/MockIpcServer.h b/src/test/mock/ipc/MockIpcServer.h
index 4124b41..5b09b39 100644
--- a/src/test/mock/ipc/MockIpcServer.h
+++ b/src/test/mock/ipc/MockIpcServer.h
@@ -34,7 +34,7 @@ public:
MockIpcServer() :
m_sendCond(ARCH->newCondVar()),
m_sendMutex(ARCH->newMutex()) { }
-
+
~MockIpcServer() {
if (m_sendCond != NULL) {
ARCH->closeCondVar(m_sendCond);
diff --git a/src/test/mock/server/MockConfig.h b/src/test/mock/server/MockConfig.h
index 4161de0..c0b40dc 100644
--- a/src/test/mock/server/MockConfig.h
+++ b/src/test/mock/server/MockConfig.h
@@ -17,7 +17,7 @@
#pragma once
-#define TEST_ENV
+#define BARRIER_TEST_ENV
#include "server/Config.h"
diff --git a/src/test/mock/server/MockInputFilter.h b/src/test/mock/server/MockInputFilter.h
index edf6de1..09aeee2 100644
--- a/src/test/mock/server/MockInputFilter.h
+++ b/src/test/mock/server/MockInputFilter.h
@@ -17,7 +17,7 @@
#pragma once
-#define TEST_ENV
+#define BARRIER_TEST_ENV
#include "server/InputFilter.h"
diff --git a/src/test/mock/server/MockPrimaryClient.h b/src/test/mock/server/MockPrimaryClient.h
index 80f18a1..db76187 100644
--- a/src/test/mock/server/MockPrimaryClient.h
+++ b/src/test/mock/server/MockPrimaryClient.h
@@ -17,7 +17,7 @@
#pragma once
-#define TEST_ENV
+#define BARRIER_TEST_ENV
#include "server/PrimaryClient.h"
#include "base/String.h"
diff --git a/src/test/mock/server/MockServer.h b/src/test/mock/server/MockServer.h
index a45ee08..74ad1d0 100644
--- a/src/test/mock/server/MockServer.h
+++ b/src/test/mock/server/MockServer.h
@@ -17,7 +17,7 @@
#pragma once
-#define TEST_ENV
+#define BARRIER_TEST_ENV
#include "server/Server.h"
diff --git a/src/test/unittests/CMakeLists.txt b/src/test/unittests/CMakeLists.txt
index c46375c..8cf5e9a 100644
--- a/src/test/unittests/CMakeLists.txt
+++ b/src/test/unittests/CMakeLists.txt
@@ -1,11 +1,11 @@
# barrier -- mouse and keyboard sharing utility
# Copyright (C) 2012-2016 Symless Ltd.
# Copyright (C) 2009 Nick Bolton
-#
+#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
-#
+#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -50,8 +50,6 @@ list(APPEND headers ${platform_sources})
include_directories(
../../
- ../../../ext/gtest/include
- ../../../ext/gmock/include
../../../ext
)
@@ -67,4 +65,4 @@ endif()
add_executable(unittests ${sources})
target_link_libraries(unittests
- arch base client server common io net platform server synlib mt ipc gtest gmock ${libs} ${OPENSSL_LIBS})
+ arch base client server common io net platform server synlib mt ipc ${GTEST_LIBRARIES} ${GMOCK_LIBRARIES} ${libs} ${OPENSSL_LIBS})
diff --git a/src/test/unittests/Main.cpp b/src/test/unittests/Main.cpp
index 7f0d0fe..52ad252 100644
--- a/src/test/unittests/Main.cpp
+++ b/src/test/unittests/Main.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2011 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -35,12 +35,12 @@ main(int argc, char **argv)
Arch arch;
arch.init();
-
+
Log log;
log.setFilter(kDEBUG4);
testing::InitGoogleTest(&argc, argv);
-
+
// gtest seems to randomly finish with error codes (e.g. -1, -1073741819)
// even when no tests have failed. not sure what causes this, but it
// happens on all platforms and keeps leading to false positives.
diff --git a/src/test/unittests/barrier/ArgParserTests.cpp b/src/test/unittests/barrier/ArgParserTests.cpp
index e14877e..311162f 100644
--- a/src/test/unittests/barrier/ArgParserTests.cpp
+++ b/src/test/unittests/barrier/ArgParserTests.cpp
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2014-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/test/unittests/barrier/ClientArgsParsingTests.cpp b/src/test/unittests/barrier/ClientArgsParsingTests.cpp
index 5a1e7d0..7aaa5db 100644
--- a/src/test/unittests/barrier/ClientArgsParsingTests.cpp
+++ b/src/test/unittests/barrier/ClientArgsParsingTests.cpp
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2014-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/test/unittests/barrier/ClipboardChunkTests.cpp b/src/test/unittests/barrier/ClipboardChunkTests.cpp
index e0e37be..784dee8 100644
--- a/src/test/unittests/barrier/ClipboardChunkTests.cpp
+++ b/src/test/unittests/barrier/ClipboardChunkTests.cpp
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2015-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
diff --git a/src/test/unittests/barrier/ClipboardTests.cpp b/src/test/unittests/barrier/ClipboardTests.cpp
index f710751..c1afdfb 100644
--- a/src/test/unittests/barrier/ClipboardTests.cpp
+++ b/src/test/unittests/barrier/ClipboardTests.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2011 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -192,7 +192,7 @@ TEST(ClipboardTests, marshall_withTextAdded_lastSizeCharIs14)
EXPECT_EQ(14, (int)actual[11]);
}
-// TODO: there's some integer -> char encoding going on here. i find it
+// TODO: there's some integer -> char encoding going on here. i find it
// hard to believe that the clipboard is the only thing doing this. maybe
// we should refactor this stuff out of the clipboard.
TEST(ClipboardTests, marshall_withTextSize285_sizeCharsValid)
@@ -212,12 +212,12 @@ TEST(ClipboardTests, marshall_withTextSize285_sizeCharsValid)
String actual = clipboard.marshall();
- // 4 asserts here, but that's ok because we're really just asserting 1
+ // 4 asserts here, but that's ok because we're really just asserting 1
// thing. the 32-bit size value is split into 4 chars. if the size is 285
- // (29 more than the 8-bit max size), the last char "rolls over" to 29
- // (this is caused by a bit-wise & on 0xff and 8-bit truncation). each
- // char before the last stores a bit-shifted version of the number, each
- // 1 more power than the last, which is done by bit-shifting [0] by 24,
+ // (29 more than the 8-bit max size), the last char "rolls over" to 29
+ // (this is caused by a bit-wise & on 0xff and 8-bit truncation). each
+ // char before the last stores a bit-shifted version of the number, each
+ // 1 more power than the last, which is done by bit-shifting [0] by 24,
// [1] by 16, [2] by 8 ([3] is not bit-shifted).
EXPECT_EQ(0, actual[8]); // 285 >> 24 = 285 / (256^3) = 0
EXPECT_EQ(0, actual[9]); // 285 >> 16 = 285 / (256^2) = 0
diff --git a/src/test/unittests/barrier/GenericArgsParsingTests.cpp b/src/test/unittests/barrier/GenericArgsParsingTests.cpp
index f43070b..7f19918 100644
--- a/src/test/unittests/barrier/GenericArgsParsingTests.cpp
+++ b/src/test/unittests/barrier/GenericArgsParsingTests.cpp
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2014-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -50,7 +50,7 @@ TEST(GenericArgsParsingTests, parseGenericArgs_logLevelCmd_setLogLevel)
ArgParser argParser(NULL);
ArgsBase argsBase;
argParser.setArgsBase(argsBase);
-
+
argParser.parseGenericArgs(argc, kLogLevelCmd, i);
String logFilter(argsBase.m_logFilter);
@@ -68,7 +68,7 @@ TEST(GenericArgsParsingTests, parseGenericArgs_logFileCmd_saveLogFilename)
ArgParser argParser(NULL);
ArgsBase argsBase;
argParser.setArgsBase(argsBase);
-
+
argParser.parseGenericArgs(argc, kLogFileCmd, i);
String logFile(argsBase.m_logFile);
@@ -86,7 +86,7 @@ TEST(GenericArgsParsingTests, parseGenericArgs_logFileCmdWithSpace_saveLogFilena
ArgParser argParser(NULL);
ArgsBase argsBase;
argParser.setArgsBase(argsBase);
-
+
argParser.parseGenericArgs(argc, kLogFileCmdWithSpace, i);
String logFile(argsBase.m_logFile);
@@ -104,7 +104,7 @@ TEST(GenericArgsParsingTests, parseGenericArgs_noDeamonCmd_daemonFalse)
ArgParser argParser(NULL);
ArgsBase argsBase;
argParser.setArgsBase(argsBase);
-
+
argParser.parseGenericArgs(argc, kNoDeamonCmd, i);
EXPECT_FALSE(argsBase.m_daemon);
@@ -120,7 +120,7 @@ TEST(GenericArgsParsingTests, parseGenericArgs_deamonCmd_daemonTrue)
ArgParser argParser(NULL);
ArgsBase argsBase;
argParser.setArgsBase(argsBase);
-
+
argParser.parseGenericArgs(argc, kDeamonCmd, i);
EXPECT_EQ(true, argsBase.m_daemon);
@@ -136,7 +136,7 @@ TEST(GenericArgsParsingTests, parseGenericArgs_nameCmd_saveName)
ArgParser argParser(NULL);
ArgsBase argsBase;
argParser.setArgsBase(argsBase);
-
+
argParser.parseGenericArgs(argc, kNameCmd, i);
EXPECT_EQ("mock", argsBase.m_name);
@@ -152,7 +152,7 @@ TEST(GenericArgsParsingTests, parseGenericArgs_noRestartCmd_restartFalse)
ArgParser argParser(NULL);
ArgsBase argsBase;
argParser.setArgsBase(argsBase);
-
+
argParser.parseGenericArgs(argc, kNoRestartCmd, i);
EXPECT_FALSE(argsBase.m_restartable);
@@ -168,7 +168,7 @@ TEST(GenericArgsParsingTests, parseGenericArgs_restartCmd_restartTrue)
ArgParser argParser(NULL);
ArgsBase argsBase;
argParser.setArgsBase(argsBase);
-
+
argParser.parseGenericArgs(argc, kRestartCmd, i);
EXPECT_EQ(true, argsBase.m_restartable);
@@ -184,7 +184,7 @@ TEST(GenericArgsParsingTests, parseGenericArgs_backendCmd_backendTrue)
ArgParser argParser(NULL);
ArgsBase argsBase;
argParser.setArgsBase(argsBase);
-
+
argParser.parseGenericArgs(argc, kBackendCmd, i);
EXPECT_EQ(true, argsBase.m_backend);
@@ -200,7 +200,7 @@ TEST(GenericArgsParsingTests, parseGenericArgs_noHookCmd_noHookTrue)
ArgParser argParser(NULL);
ArgsBase argsBase;
argParser.setArgsBase(argsBase);
-
+
argParser.parseGenericArgs(argc, kNoHookCmd, i);
EXPECT_EQ(true, argsBase.m_noHooks);
@@ -219,7 +219,7 @@ TEST(GenericArgsParsingTests, parseGenericArgs_helpCmd_showHelp)
ArgsBase argsBase;
argParser.setArgsBase(argsBase);
ON_CALL(app, help()).WillByDefault(Invoke(showMockHelp));
-
+
argParser.parseGenericArgs(argc, kHelpCmd, i);
EXPECT_EQ(true, g_helpShowed);
@@ -239,7 +239,7 @@ TEST(GenericArgsParsingTests, parseGenericArgs_versionCmd_showVersion)
ArgsBase argsBase;
argParser.setArgsBase(argsBase);
ON_CALL(app, version()).WillByDefault(Invoke(showMockVersion));
-
+
argParser.parseGenericArgs(argc, kVersionCmd, i);
EXPECT_EQ(true, g_versionShowed);
@@ -255,7 +255,7 @@ TEST(GenericArgsParsingTests, parseGenericArgs_noTrayCmd_disableTrayTrue)
ArgParser argParser(NULL);
ArgsBase argsBase;
argParser.setArgsBase(argsBase);
-
+
argParser.parseGenericArgs(argc, kNoTrayCmd, i);
EXPECT_EQ(true, argsBase.m_disableTray);
@@ -271,7 +271,7 @@ TEST(GenericArgsParsingTests, parseGenericArgs_ipcCmd_enableIpcTrue)
ArgParser argParser(NULL);
ArgsBase argsBase;
argParser.setArgsBase(argsBase);
-
+
argParser.parseGenericArgs(argc, kIpcCmd, i);
EXPECT_EQ(true, argsBase.m_enableIpc);
@@ -288,7 +288,7 @@ TEST(GenericArgsParsingTests, parseGenericArgs_dragDropCmdOnNonLinux_enableDragD
ArgParser argParser(NULL);
ArgsBase argsBase;
argParser.setArgsBase(argsBase);
-
+
argParser.parseGenericArgs(argc, kDragDropCmd, i);
EXPECT_EQ(true, argsBase.m_enableDragDrop);
@@ -306,7 +306,7 @@ TEST(GenericArgsParsingTests, parseGenericArgs_dragDropCmdOnLinux_enableDragDrop
ArgParser argParser(NULL);
ArgsBase argsBase;
argParser.setArgsBase(argsBase);
-
+
argParser.parseGenericArgs(argc, kDragDropCmd, i);
EXPECT_FALSE(argsBase.m_enableDragDrop);
diff --git a/src/test/unittests/barrier/KeyMapTests.cpp b/src/test/unittests/barrier/KeyMapTests.cpp
index 5980633..20c1c55 100644
--- a/src/test/unittests/barrier/KeyMapTests.cpp
+++ b/src/test/unittests/barrier/KeyMapTests.cpp
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2016 Symless
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -15,6 +15,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#define BARRIER_TEST_ENV
+
#include "barrier/KeyMap.h"
#include "test/global/gtest.h"
@@ -28,7 +30,7 @@ using ::testing::ReturnRef;
using ::testing::SaveArg;
namespace barrier {
-
+
TEST(KeyMapTests, findBestKey_requiredDown_matchExactFirstItem)
{
KeyMap keyMap;
@@ -44,7 +46,7 @@ TEST(KeyMapTests, findBestKey_requiredDown_matchExactFirstItem)
EXPECT_EQ(0, keyMap.findBestKey(entryList, currentState, desiredState));
}
-
+
TEST(KeyMapTests, findBestKey_requiredAndExtraSensitiveDown_matchExactFirstItem)
{
KeyMap keyMap;
@@ -82,7 +84,7 @@ TEST(KeyMapTests, findBestKey_requiredAndExtraSensitiveDown_matchExactSecondItem
EXPECT_EQ(1, keyMap.findBestKey(entryList, currentState, desiredState));
}
-
+
TEST(KeyMapTests, findBestKey_extraSensitiveDown_matchExactSecondItem)
{
KeyMap keyMap;
@@ -101,7 +103,7 @@ TEST(KeyMapTests, findBestKey_extraSensitiveDown_matchExactSecondItem)
itemList2.push_back(item2);
entryList.push_back(itemList1);
entryList.push_back(itemList2);
-
+
EXPECT_EQ(1, keyMap.findBestKey(entryList, currentState, desiredState));
}
@@ -123,7 +125,7 @@ TEST(KeyMapTests, findBestKey_noRequiredDown_matchOneRequiredChangeItem)
itemList2.push_back(item2);
entryList.push_back(itemList1);
entryList.push_back(itemList2);
-
+
EXPECT_EQ(1, keyMap.findBestKey(entryList, currentState, desiredState));
}
@@ -148,7 +150,7 @@ TEST(KeyMapTests, findBestKey_onlyOneRequiredDown_matchTwoRequiredChangesItem)
EXPECT_EQ(1, keyMap.findBestKey(entryList, currentState, desiredState));
}
-
+
TEST(KeyMapTests, findBestKey_noRequiredDown_cannotMatch)
{
KeyMap keyMap;
@@ -161,31 +163,31 @@ TEST(KeyMapTests, findBestKey_noRequiredDown_cannotMatch)
KeyModifierMask desiredState = 0;
itemList.push_back(item);
entryList.push_back(itemList);
-
+
EXPECT_EQ(-1, keyMap.findBestKey(entryList, currentState, desiredState));
}
-
+
TEST(KeyMapTests, isCommand_shiftMask_returnFalse)
{
KeyMap keyMap;
KeyModifierMask mask= KeyModifierShift;
-
+
EXPECT_FALSE(keyMap.isCommand(mask));
}
-
+
TEST(KeyMapTests, isCommand_controlMask_returnTrue)
{
KeyMap keyMap;
KeyModifierMask mask= KeyModifierControl;
-
+
EXPECT_EQ(true, keyMap.isCommand(mask));
}
-
+
TEST(KeyMapTests, isCommand_alternateMask_returnTrue)
{
KeyMap keyMap;
KeyModifierMask mask= KeyModifierAlt;
-
+
EXPECT_EQ(true, keyMap.isCommand(mask));
}
@@ -193,15 +195,15 @@ TEST(KeyMapTests, isCommand_alternateGraphicMask_returnTrue)
{
KeyMap keyMap;
KeyModifierMask mask= KeyModifierAltGr;
-
+
EXPECT_EQ(true, keyMap.isCommand(mask));
}
-
+
TEST(KeyMapTests, isCommand_metaMask_returnTrue)
{
KeyMap keyMap;
KeyModifierMask mask= KeyModifierMeta;
-
+
EXPECT_EQ(true, keyMap.isCommand(mask));
}
@@ -209,8 +211,8 @@ TEST(KeyMapTests, isCommand_superMask_returnTrue)
{
KeyMap keyMap;
KeyModifierMask mask= KeyModifierSuper;
-
+
EXPECT_EQ(true, keyMap.isCommand(mask));
}
-
+
}
diff --git a/src/test/unittests/barrier/KeyStateTests.cpp b/src/test/unittests/barrier/KeyStateTests.cpp
index d4154d8..bc41933 100644
--- a/src/test/unittests/barrier/KeyStateTests.cpp
+++ b/src/test/unittests/barrier/KeyStateTests.cpp
@@ -2,11 +2,11 @@
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2011 Nick Bolton
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -100,7 +100,7 @@ TEST(KeyStateTests, sendKeyEvent_halfDuplex_addEventCalledTwice)
KeyStateImpl keyState(eventQueue, keyMap);
IKeyStateEvents keyStateEvents;
keyStateEvents.setEvents(&eventQueue);
-
+
ON_CALL(keyMap, isHalfDuplex(_, _)).WillByDefault(Return(true));
ON_CALL(eventQueue, forIKeyState()).WillByDefault(ReturnRef(keyStateEvents));
@@ -116,7 +116,7 @@ TEST(KeyStateTests, sendKeyEvent_keyRepeat_addEventCalledOnce)
KeyStateImpl keyState(eventQueue, keyMap);
IKeyStateEvents keyStateEvents;
keyStateEvents.setEvents(&eventQueue);
-
+
ON_CALL(eventQueue, forIKeyState()).WillByDefault(ReturnRef(keyStateEvents));
EXPECT_CALL(eventQueue, addEvent(_)).Times(1);
@@ -131,7 +131,7 @@ TEST(KeyStateTests, sendKeyEvent_keyDown_addEventCalledOnce)
KeyStateImpl keyState(eventQueue, keyMap);
IKeyStateEvents keyStateEvents;
keyStateEvents.setEvents(&eventQueue);
-
+
ON_CALL(eventQueue, forIKeyState()).WillByDefault(ReturnRef(keyStateEvents));
EXPECT_CALL(eventQueue, addEvent(_)).Times(1);
@@ -146,7 +146,7 @@ TEST(KeyStateTests, sendKeyEvent_keyUp_addEventCalledOnce)
KeyStateImpl keyState(eventQueue, keyMap);
IKeyStateEvents keyStateEvents;
keyStateEvents.setEvents(&eventQueue);
-
+
ON_CALL(eventQueue, forIKeyState()).WillByDefault(ReturnRef(keyStateEvents));
EXPECT_CALL(eventQueue, addEvent(_)).Times(1);
diff --git a/src/test/unittests/base/StringTests.cpp b/src/test/unittests/base/StringTests.cpp
index 39ad6e8..cc8e4fc 100644
--- a/src/test/unittests/base/StringTests.cpp
+++ b/src/test/unittests/base/StringTests.cpp
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2014-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -56,12 +56,38 @@ TEST(StringTests, sprintf_formatWithArgument_formatedString)
TEST(StringTests, toHex_plaintext_hexString)
{
- String subject = "foobar";
+ std::vector<std::uint8_t> subject{'f', 'o', 'o', 'b', 'a', 'r'};
int width = 2;
- string::toHex(subject, width);
+ EXPECT_EQ("666f6f626172", string::to_hex(subject, width));
+}
+
+TEST(StringTests, fromhex_plaintext_string)
+{
+ auto result = string::from_hex("666f6f626172");
+ std::string expected = "foobar";
+ EXPECT_EQ(result, std::vector<std::uint8_t>(expected.begin(), expected.end()));
+}
+
+TEST(StringTests, fromhex_plaintext_string_colons)
+{
+ auto result = string::from_hex("66:6f:6f:62:61:72");
+ std::string expected = "foobar";
+ EXPECT_EQ(result, std::vector<std::uint8_t>(expected.begin(), expected.end()));
+}
- EXPECT_EQ("666f6f626172", subject);
+TEST(StringTests, fromhex_binary_string)
+{
+ auto result = string::from_hex("01020304050600fff9");
+ auto expected = std::vector<std::uint8_t>{1, 2, 3, 4, 5, 6, 0, 0xff, 0xf9};
+ EXPECT_EQ(result, expected);
+}
+
+TEST(StringTests, fromhex_invalid_string)
+{
+ EXPECT_TRUE(string::from_hex("66:6").empty());
+ EXPECT_TRUE(string::from_hex("66:612").empty());
+ EXPECT_TRUE(string::from_hex("66:WW").empty());
}
TEST(StringTests, uppercase_lowercaseInput_uppercaseOutput)
diff --git a/src/test/unittests/ipc/IpcLogOutputterTests.cpp b/src/test/unittests/ipc/IpcLogOutputterTests.cpp
index bbfed9c..6db9ac9 100644
--- a/src/test/unittests/ipc/IpcLogOutputterTests.cpp
+++ b/src/test/unittests/ipc/IpcLogOutputterTests.cpp
@@ -1,11 +1,11 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2015-2016 Symless Ltd.
- *
+ *
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
- *
+ *
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -15,7 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#define TEST_ENV
+#define BARRIER_TEST_ENV
#include "test/mock/ipc/MockIpcServer.h"
@@ -50,7 +50,7 @@ TEST(IpcLogOutputterTests, write_threadingEnabled_bufferIsSent)
{
MockIpcServer mockServer;
mockServer.delegateToFake();
-
+
ON_CALL(mockServer, hasClients(_)).WillByDefault(Return(true));
EXPECT_CALL(mockServer, hasClients(_)).Times(AtLeast(3));
@@ -67,7 +67,7 @@ TEST(IpcLogOutputterTests, write_threadingEnabled_bufferIsSent)
TEST(IpcLogOutputterTests, write_overBufferMaxSize_firstLineTruncated)
{
MockIpcServer mockServer;
-
+
ON_CALL(mockServer, hasClients(_)).WillByDefault(Return(true));
EXPECT_CALL(mockServer, hasClients(_)).Times(1);
EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 2\nmock 3\n"), _)).Times(1);
@@ -85,7 +85,7 @@ TEST(IpcLogOutputterTests, write_overBufferMaxSize_firstLineTruncated)
TEST(IpcLogOutputterTests, write_underBufferMaxSize_allLinesAreSent)
{
MockIpcServer mockServer;
-
+
ON_CALL(mockServer, hasClients(_)).WillByDefault(Return(true));
EXPECT_CALL(mockServer, hasClients(_)).Times(1);
@@ -107,7 +107,7 @@ TEST(IpcLogOutputterTests, write_underBufferMaxSize_allLinesAreSent)
TEST(IpcLogOutputterTests, write_overBufferRateLimit_lastLineTruncated)
{
MockIpcServer mockServer;
-
+
ON_CALL(mockServer, hasClients(_)).WillByDefault(Return(true));
EXPECT_CALL(mockServer, hasClients(_)).Times(2);
@@ -123,7 +123,7 @@ TEST(IpcLogOutputterTests, write_overBufferRateLimit_lastLineTruncated)
outputter.write(kNOTE, "mock 3");
outputter.sendBuffer();
-
+
// after waiting the time limit send another to make sure
// we can log after the time limit passes.
// HACK: sleep causes the unit test to fail intermittently,
@@ -140,7 +140,7 @@ TEST(IpcLogOutputterTests, write_overBufferRateLimit_lastLineTruncated)
TEST(IpcLogOutputterTests, write_underBufferRateLimit_allLinesAreSent)
{
MockIpcServer mockServer;
-
+
ON_CALL(mockServer, hasClients(_)).WillByDefault(Return(true));
EXPECT_CALL(mockServer, hasClients(_)).Times(2);
@@ -154,7 +154,7 @@ TEST(IpcLogOutputterTests, write_underBufferRateLimit_allLinesAreSent)
outputter.write(kNOTE, "mock 1");
outputter.write(kNOTE, "mock 2");
outputter.sendBuffer();
-
+
// after waiting the time limit send another to make sure
// we can log after the time limit passes.
outputter.write(kNOTE, "mock 3");
diff --git a/src/test/unittests/net/FingerprintDatabaseTests.cpp b/src/test/unittests/net/FingerprintDatabaseTests.cpp
new file mode 100644
index 0000000..61bed0e
--- /dev/null
+++ b/src/test/unittests/net/FingerprintDatabaseTests.cpp
@@ -0,0 +1,95 @@
+/*
+ barrier -- mouse and keyboard sharing utility
+ Copyright (C) Barrier contributors
+
+ This package is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ found in the file LICENSE that should have accompanied this file.
+
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "net/FingerprintDatabase.h"
+#include "test/global/gtest.h"
+
+namespace barrier {
+
+TEST(FingerprintDatabase, parse_db_line)
+{
+ ASSERT_FALSE(FingerprintDatabase::parse_db_line("").valid());
+ ASSERT_FALSE(FingerprintDatabase::parse_db_line("abcd").valid());
+ ASSERT_FALSE(FingerprintDatabase::parse_db_line("v1:algo:something").valid());
+ ASSERT_FALSE(FingerprintDatabase::parse_db_line("v2:algo:something").valid());
+ ASSERT_FALSE(FingerprintDatabase::parse_db_line("v2:algo:01020304abc").valid());
+ ASSERT_FALSE(FingerprintDatabase::parse_db_line("v2:algo:01020304ZZ").valid());
+ ASSERT_EQ(FingerprintDatabase::parse_db_line("v2:algo:01020304ab"),
+ (FingerprintData{"algo", {1, 2, 3, 4, 0xab}}));
+}
+
+TEST(FingerprintDatabase, read)
+{
+ std::istringstream stream;
+ stream.str(R"(
+v2:algo1:01020304ab
+v2:algo2:03040506ab
+AB:CD:EF:00:01:02:03:04:05:06:07:08:09:10:11:12:13:14:15:16
+)");
+ FingerprintDatabase db;
+ db.read_stream(stream);
+
+ std::vector<FingerprintData> expected = {
+ { "algo1", { 1, 2, 3, 4, 0xab } },
+ { "algo2", { 3, 4, 5, 6, 0xab } },
+ { "sha1", { 0xab, 0xcd, 0xef, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 } },
+ };
+ ASSERT_EQ(db.fingerprints(), expected);
+}
+
+TEST(FingerprintDatabase, write)
+{
+ std::ostringstream stream;
+
+ FingerprintDatabase db;
+ db.add_trusted({ "algo1", { 1, 2, 3, 4, 0xab } });
+ db.add_trusted({ "algo2", { 3, 4, 5, 6, 0xab } });
+ db.write_stream(stream);
+
+ ASSERT_EQ(stream.str(), R"(v2:algo1:01020304ab
+v2:algo2:03040506ab
+)");
+}
+
+TEST(FingerprintDatabase, clear)
+{
+ FingerprintDatabase db;
+ db.add_trusted({ "algo1", { 1, 2, 3, 4, 0xab } });
+ db.clear();
+ ASSERT_TRUE(db.fingerprints().empty());
+}
+
+TEST(FingerprintDatabase, add_trusted_no_duplicates)
+{
+ FingerprintDatabase db;
+ db.add_trusted({ "algo1", { 1, 2, 3, 4, 0xab } });
+ db.add_trusted({ "algo2", { 3, 4, 5, 6, 0xab } });
+ db.add_trusted({ "algo1", { 1, 2, 3, 4, 0xab } });
+ ASSERT_EQ(db.fingerprints().size(), 2);
+}
+
+TEST(FingerprintDatabase, is_trusted)
+{
+ FingerprintDatabase db;
+ db.add_trusted({ "algo1", { 1, 2, 3, 4, 0xab } });
+ ASSERT_TRUE(db.is_trusted({ "algo1", { 1, 2, 3, 4, 0xab } }));
+ ASSERT_FALSE(db.is_trusted({ "algo2", { 1, 2, 3, 4, 0xab } }));
+ ASSERT_FALSE(db.is_trusted({ "algo1", { 1, 2, 3, 4, 0xac } }));
+}
+
+} // namespace barrier
diff --git a/src/test/unittests/net/SecureUtilsTests.cpp b/src/test/unittests/net/SecureUtilsTests.cpp
new file mode 100644
index 0000000..0cce693
--- /dev/null
+++ b/src/test/unittests/net/SecureUtilsTests.cpp
@@ -0,0 +1,73 @@
+/*
+ barrier -- mouse and keyboard sharing utility
+ Copyright (C) 2021 Barrier contributors
+
+ This package is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ found in the file LICENSE that should have accompanied this file.
+
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "net/SecureUtils.h"
+
+#include "test/global/gtest.h"
+#include "test/global/TestUtils.h"
+
+namespace barrier {
+
+TEST(SecureUtilsTest, FormatSslFingerprintHexWithSeparators)
+{
+ auto fingerprint = generate_pseudo_random_bytes(0, 32);
+ ASSERT_EQ(format_ssl_fingerprint(fingerprint, true),
+ "28:FD:0A:98:8A:0E:A1:6C:D7:E8:6C:A7:EE:58:41:71:"
+ "CA:B2:8E:49:25:94:90:25:26:05:8D:AF:63:ED:2E:30");
+}
+
+TEST(SecureUtilsTest, CreateFingerprintRandomArt)
+{
+ ASSERT_EQ(create_fingerprint_randomart(generate_pseudo_random_bytes(0, 32)),
+ "+-----------------+\n"
+ "|*X+. . |\n"
+ "|*oo + |\n"
+ "| + = |\n"
+ "| B . . |\n"
+ "|.+... o S |\n"
+ "|E+ ++. . |\n"
+ "|B*++.. . |\n"
+ "|+o*o o . |\n"
+ "|+o*Bo . |\n"
+ "+-----------------+");
+ ASSERT_EQ(create_fingerprint_randomart(generate_pseudo_random_bytes(1, 32)),
+ "+-----------------+\n"
+ "| .oo+ . .B=. |\n"
+ "| .o.+ . o o.= |\n"
+ "|o..+.. o . E * |\n"
+ "|oo..+ . * * |\n"
+ "|B o.....S. o . |\n"
+ "|+=o..... |\n"
+ "| + + . |\n"
+ "|o. .. |\n"
+ "|..o.. |\n"
+ "+-----------------+");
+ ASSERT_EQ(create_fingerprint_randomart(generate_pseudo_random_bytes(2, 32)),
+ "+-----------------+\n"
+ "| ... .o.o.|\n"
+ "| o .=.E|\n"
+ "| . + o ...+.|\n"
+ "| * o = o ... |\n"
+ "| * + S & . |\n"
+ "| = + % @ |\n"
+ "| . . = X o |\n"
+ "| . . O . |\n"
+ "| . + |\n"
+ "+-----------------+");
+}
+
+} // namespace barrier
diff --git a/src/test/unittests/platform/OSXKeyStateTests.cpp b/src/test/unittests/platform/OSXKeyStateTests.cpp
index dd9e80f..0e4ec83 100644
--- a/src/test/unittests/platform/OSXKeyStateTests.cpp
+++ b/src/test/unittests/platform/OSXKeyStateTests.cpp
@@ -30,27 +30,27 @@ TEST(OSXKeyStateTests, mapModifiersFromOSX_OSXMask_returnBarrierMask)
OSXKeyState keyState(&eventQueue, keyMap);
KeyModifierMask outMask = 0;
-
+
UInt32 shiftMask = 0 | kCGEventFlagMaskShift;
outMask = keyState.mapModifiersFromOSX(shiftMask);
EXPECT_EQ(KeyModifierShift, outMask);
-
+
UInt32 ctrlMask = 0 | kCGEventFlagMaskControl;
outMask = keyState.mapModifiersFromOSX(ctrlMask);
EXPECT_EQ(KeyModifierControl, outMask);
-
+
UInt32 altMask = 0 | kCGEventFlagMaskAlternate;
outMask = keyState.mapModifiersFromOSX(altMask);
EXPECT_EQ(KeyModifierAlt, outMask);
-
+
UInt32 cmdMask = 0 | kCGEventFlagMaskCommand;
outMask = keyState.mapModifiersFromOSX(cmdMask);
EXPECT_EQ(KeyModifierSuper, outMask);
-
+
UInt32 capsMask = 0 | kCGEventFlagMaskAlphaShift;
outMask = keyState.mapModifiersFromOSX(capsMask);
EXPECT_EQ(KeyModifierCapsLock, outMask);
-
+
UInt32 numMask = 0 | kCGEventFlagMaskNumericPad;
outMask = keyState.mapModifiersFromOSX(numMask);
EXPECT_EQ(KeyModifierNumLock, outMask);
diff --git a/towncrier.toml b/towncrier.toml
new file mode 100644
index 0000000..d8f0a61
--- /dev/null
+++ b/towncrier.toml
@@ -0,0 +1,39 @@
+[tool.towncrier]
+ package = ""
+ directory = "doc/newsfragments"
+ filename = "doc/release_notes/index.md"
+ template = "doc/release_notes/index.template.jinja"
+ title_format = "\nBarrier `{version}` ( `{project_date}` )\n================================\n"
+ start_string = "[comment]: <> (towncrier release notes start)"
+ [[tool.towncrier.section]]
+ path = ""
+
+ [[tool.towncrier.type]]
+ directory = "security"
+ name = "Security fixes"
+ showcontent = false
+
+ [[tool.towncrier.type]]
+ directory = "feature"
+ name = "Features"
+ showcontent = true
+
+ [[tool.towncrier.type]]
+ directory = "bugfix"
+ name = "Bug fixes"
+ showcontent = true
+
+ [[tool.towncrier.type]]
+ directory = "doc"
+ name = "Improved Documentation"
+ showcontent = true
+
+ [[tool.towncrier.type]]
+ directory = "removal"
+ name = "Deprecations and Removals"
+ showcontent = true
+
+ [[tool.towncrier.type]]
+ directory = "misc"
+ name = "Miscellaneous"
+ showcontent = false