Compare commits

...
Author SHA1 Message Date
anthropic-code-agent[bot]andashaduri 6193f2eb0e Fix AppImage CI: install libfuse2 for appimagetool
Co-authored-by: ashaduri <2302268+ashaduri@users.noreply.github.com>
2026-03-07 16:50:15 +00:00
anthropic-code-agent[bot]andashaduri 04849d1492 Fix AppImage build issues: version parsing, CMake expansion, and conditional desktop ID
Co-authored-by: ashaduri <2302268+ashaduri@users.noreply.github.com>
2026-03-06 19:16:32 +00:00
anthropic-code-agent[bot]andashaduri 8d95e6e90c Add AppImage support with rDNS format and portable paths
Co-authored-by: ashaduri <2302268+ashaduri@users.noreply.github.com>
2026-03-06 15:07:33 +00:00
anthropic-code-agent[bot] 73af50dc9d Initial plan 2026-03-06 15:01:03 +00:00
Alexander Shaduri 5343ba9dae Cleanups 2026-03-04 22:48:21 +01:00
Alexander Shaduri 3d1e962107 Agentic: Tweak instructions. 2026-03-04 22:37:05 +01:00
Alexander Shaduri c14d7a7791 Windows: Manually install nsis since it's no longer available by default in CI. 2026-03-04 22:33:57 +01:00
Alexander Shaduri 4f3745f8ec Add copilot helper files. 2026-03-04 22:06:57 +01:00
Alexander Shaduri dadfd60ed3 Fix gcc shadow warning. 2025-11-25 19:29:46 +01:00
copilot-swe-agent[bot] 6c8fea7309 Add new natural sort order tests. 2025-11-25 19:29:28 +01:00
copilot-swe-agent[bot] 9d9e3b1a4d Update .gitignore to exclude CodeQL build directory 2025-11-25 13:00:03 +01:00
copilot-swe-agent[bot]andashaduri 54425a306a Implement natural sort order for drive names
Co-authored-by: ashaduri <2302268+ashaduri@users.noreply.github.com>
2025-11-25 12:59:41 +01:00
Alexander Shaduri be601f514d Upgrade CodeQL actions to version 4
Updated CodeQL actions to version 4 in the workflow configuration.
2025-11-18 19:44:28 +01:00
Alexander Shaduri a7c7c8190c Update CodeQL SARIF upload action to v4 2025-11-18 19:43:57 +01:00
Alexander Shaduri 44948de7d0 Fixed typos and updated visible copyright years. 2025-06-11 09:43:36 +02:00
Alexander Shaduri e2efde2d1a Updated nlohmann json to version 3.12.0. 2025-05-16 17:48:32 +04:00
Alexander Shaduri 6630116ba1 Properly implemented persistence of manually added devices (#87). Added --forget-devices option to clear the list if any of the devices causes trouble. 2025-04-28 18:51:42 +04:00
Alexander Shaduri 1f7c2b6a92 Manually added devices can be persistent now. 2025-04-28 11:19:44 +00:00
Alexander Shaduri 10ad6b74eb Merge remote-tracking branch 'origin/main' 2025-04-25 12:22:38 +04:00
Alexander Shaduri f62de567df MSYS no longer supports 32-bit Windows, so disable it in CI. 2025-04-25 12:12:52 +04:00
Alexander Shaduri d96dc79943 Merge pull request #86 from checktext00/patch-1
Update 36535 to 65535 hours in selftest log tooltip.
2025-04-17 11:32:32 +04:00
Alexander Shaduri e35c301605 Update gsc_info_window.cpp
Looking at the smartmontools code, it should be 65535 I believe.
2025-04-17 11:31:13 +04:00
checktext00 7af8dba9f3 update 36535 to 65536 hours 2025-04-16 11:58:09 +00:00
Alexander Shaduri caa80a30d1 Merge pull request #83 from stanislav-brabec/main
Typo fix in Czech desktop translation.
2025-03-12 20:46:01 +04:00
Stanislav Brabec db4928e78f Typo fix in Czech desktop translation. 2025-03-12 16:43:39 +01:00
Alexander Shaduri af96fa2cda Merge pull request #82 from stanislav-brabec/main
Add desktop translations
2025-03-11 11:55:47 +04:00
Stanislav Brabec c08ef9070b Add desktop translations
Add desktop translations imported from the openSUSE
desktop-file-translations project.
https://l10n.opensuse.org/projects/desktop-file-translations/
2025-03-10 22:10:45 +01:00
Alexander Shaduri 6fe5b43bc1 Document Vista. 2025-03-02 19:13:32 +04:00
Alexander Shaduri b3056aedd0 Update download links for 2.0.2. 2025-02-24 16:50:08 +04:00
Alexander Shaduri b2912950c9 Fixed Windows CI packaging. 2025-02-24 16:08:36 +04:00
Alexander Shaduri af2e47308c Bumped version to 2.0.2. 2025-02-24 16:04:30 +04:00
Alexander Shaduri 37be3a413a Updated NEWS for 2.0.2 release. 2025-02-24 16:03:48 +04:00
Alexander Shaduri a7281b7b1e Document GCC 11 support. 2025-02-24 16:03:22 +04:00
Alexander Shaduri 23d06c4bc7 Cleanup. 2025-02-24 16:03:02 +04:00
Alexander Shaduri b5f522d8bc Fix OBS repository list. 2025-02-24 14:56:14 +04:00
Alexander Shaduri 283792715c Update CI to use GCC14. 2025-02-24 14:03:40 +04:00
Alexander Shaduri d7032eb351 Allow smartctl < 7.3 again, falling back to Text parser; this configuration is for compatibility only and not fully supported. 2025-02-24 13:52:04 +04:00
Alexander Shaduri 589c280bdc Support saving smartctl output to text (using old text format) instead of json (#76). 2025-02-15 13:22:47 +04:00
Alexander Shaduri 9f85d09736 Support standard (non-extended) self-test log in JSON ATA parser (#79). 2025-02-14 13:48:30 +04:00
Alexander Shaduri d45e5360cc Temperature: Fixed reporting unreasonably large values when raw value encodes min/max values as well (#78); support protocol-independent temperature reporting in JSON. 2025-02-14 13:28:43 +04:00
Alexander Shaduri 58d2a8b58f Windows: Use older librsvg in CI to support Windows 7 (#71). 2025-02-13 17:11:33 +04:00
Alexander Shaduri d51820476b Windows: Use older librsvg in CI to support Windows 7 (#71). 2025-02-13 16:35:55 +04:00
Alexander Shaduri bfce801cc5 Windows: Use older librsvg in CI to support Windows 7 (#71). 2025-02-13 16:30:36 +04:00
Alexander Shaduri 63f32e4d8b Windows: Use older librsvg in CI to support Windows 7 (#71). 2025-02-13 16:25:47 +04:00
Alexander Shaduri 0fc5d208bb Support Ubuntu 22.04 in CI. 2025-02-07 13:00:29 +04:00
Alexander Shaduri 8b3b500034 Support Ubuntu 22.04 in CI. 2025-02-07 11:51:13 +04:00
Alexander Shaduri a5fddf1bb2 Use {fmt} instead of <format> to support older compilers. 2025-02-07 11:44:50 +04:00
Alexander Shaduri f3dc0274c3 Added generic build instructions. 2025-02-07 10:41:04 +04:00
Alexander Shaduri 515bf11c3d Added self-test "lifetime hours" wrapping behavior to the column header tooltip. 2024-12-26 13:07:24 +04:00
Alexander Shaduri a254c17fcb Updated wikipedia links. 2024-12-10 18:26:40 +04:00
Alexander Shaduri 7e9959c455 Update wikipedia link. 2024-12-10 18:20:35 +04:00
Alexander Shaduri a57e543701 Windows: Avoid using non-integer font sizes. 2024-12-06 12:33:50 +04:00
Alexander Shaduri 43d4b86943 Add sha1sum of the source archive. 2024-11-26 15:44:54 +04:00
Alexander Shaduri 81cdd0db81 Reflect version 2.0.1. 2024-11-26 15:45:49 +04:00
Alexander Shaduri b76bb1002e Windows: Bundle missing dlls needed by CI GTK. 2024-11-26 14:59:00 +04:00
Alexander Shaduri dea940222e GitHub CI: Fixed invalid artifact names. 2024-11-26 14:57:21 +04:00
Alexander Shaduri 4a075cc187 Bumped version to 2.0.1. 2024-11-26 14:04:37 +04:00
Alexander Shaduri e17c10c965 Windows: Bundle glib schemas to avoid native file dialog crash. 2024-11-26 13:59:52 +04:00
Alexander Shaduri 8c96c02468 Add a note about DPI awareness limitations. 2024-11-26 13:43:45 +04:00
Alexander Shaduri 4260f94ce7 Minor style issue in documentation. 2024-11-21 16:17:50 +04:00
Alexander Shaduri 21f73e4eae Add a note about SCSI / SAS support. 2024-11-21 16:14:13 +04:00
Alexander Shaduri 743173df81 Merge remote-tracking branch 'origin/main' 2024-11-19 18:22:46 +04:00
Alexander Shaduri 17b6ea23b4 Clarify device support in documentation. 2024-11-19 18:21:34 +04:00
Alexander Shaduri 840398c073 Fix potential crash in attribute description database. 2024-11-19 12:58:45 +04:00
Alexander Shaduri 93384e4c37 Fix compiler warning. 2024-11-19 12:39:01 +04:00
Alexander Shaduri 566b11026e Fix "Show SMART capable only" checkbox not having effect. 2024-11-07 14:48:18 +04:00
Alexander Shaduri 8fd2986a92 Update SECURITY.md for 2.0.0. 2024-11-07 14:00:47 +04:00
Alexander Shaduri e7dd2cf434 Recommend a 64-bit installer on Windows due to more testing. 2024-11-07 13:57:27 +04:00
Alexander Shaduri cdfbf8795a Update the Downloads page for 2.0.0. 2024-11-07 13:51:46 +04:00
Alexander Shaduri d110ddad10 Update NEWS.txt and other files in preparation for 2.0.0. 2024-11-07 13:09:59 +04:00
Alexander Shaduri 36cecf3acc Bumped version to 2.0.0. 2024-11-06 14:55:23 +04:00
Alexander Shaduri 066eaec993 Windows: Use Adwaita theme by default, win32 theme has too many problems (with Classic theme and with fractional dpi scaling). 2024-11-06 14:11:08 +04:00
Alexander Shaduri 746ebf9b02 Windows: Re-enable dpi awareness and scale up the font in case of fractional scaling. 2024-11-06 13:57:59 +04:00
Alexander Shaduri 1deffe6a98 Don't require gettext - we don't need it yet. 2024-11-06 12:38:04 +04:00
Alexander Shaduri 7ac61f1cac Fix crash on startup in Windows. 2024-11-06 12:37:48 +04:00
Alexander Shaduri e386c86316 Merge remote-tracking branch 'origin/main' 2024-11-05 17:28:48 +04:00
Alexander Shaduri da84eb027f Disable LTO in mingw due to CI errors. 2024-11-05 17:28:25 +04:00
Alexander Shaduri 1d9f2a2744 Fix win32 toolchain files for release builds. 2024-11-05 16:52:26 +04:00
Alexander Shaduri c1d0f46366 Make sure NSIS installer works. 2024-11-05 15:33:33 +04:00
Alexander Shaduri 99bf00d27c Fixed running "Update smartctl database" on Windows; use argv on all platforms so it is more secure. 2024-11-05 14:53:19 +04:00
Alexander Shaduri 7fd43bba2c Info window: Don't use Gtk::Stock for icons. 2024-11-05 14:15:19 +04:00
Alexander Shaduri 48f14267e5 Hide too noisy clang-tidy warning. 2024-11-05 14:00:50 +04:00
Alexander Shaduri b785a4fbec Replace bundled icons with the ones from Oxygen project; bundle removable drive icon; update copyrights accordingly. 2024-11-05 14:00:33 +04:00
Alexander Shaduri 3aa5ddfc32 Test results are presented in a more obvious manner now. 2024-11-04 20:38:47 +04:00
Alexander Shaduri c2277edb56 Show smartctl database version in basic properties. 2024-11-04 17:07:20 +04:00
Alexander Shaduri d82ec219f6 Refactoring: Split out property description code for ATA Attribute and ATA Statistic into separate files.
Added descriptions and warnings to NVMe Attributes.
Storage Property: Rely less on reported name (not as useful with JSON parser), more on generic name.
2024-11-04 16:56:10 +04:00
Alexander Shaduri dc007c84ab Fix ATA testing with when JSON parser is used. 2024-11-04 13:11:19 +04:00
Alexander Shaduri ccd04b86d3 Page tweaks. 2024-10-31 19:09:43 +04:00
Alexander Shaduri 0531a37133 Update pages remote theme (the old one was deleted). 2024-10-31 19:02:11 +04:00
Alexander Shaduri 566cff8ded Update pages remote theme (the old one was deleted). 2024-10-31 18:57:24 +04:00
Alexander Shaduri 74c5e92d4b Do not remove NVMe devices namespaces if a device has more than one namespace. 2024-10-31 16:21:43 +04:00
Alexander Shaduri aaa374c8ed Fix self-test status execution returning error. 2024-10-31 16:21:15 +04:00
Alexander Shaduri 2a6902dbb5 Support self-tests on WD NVMe with smartctl < 7.5. 2024-10-31 16:05:07 +04:00
Alexander Shaduri 02206a8967 Minor code cleanups. 2024-10-31 15:56:23 +04:00
Alexander Shaduri af2a5a18b3 "Perform Tests" menu item is correctly disabled now if self-tests are not supported; if support is unknown, an appropriate message is shown after the Info window is displayed. 2024-10-31 15:47:42 +04:00
Alexander Shaduri 1d0e325813 JSON Basic Parser: Make sure the health property is in the health section (fixes GUI not displaying health after first scan). 2024-10-31 15:21:02 +04:00
Alexander Shaduri f4e22a5c96 Windows: Add a note about why hidpi is disabled. 2024-10-31 15:18:01 +04:00
Alexander Shaduri fb468f8594 Windows: Fixed auto-detection issues, minor refactoring of the detection code. 2024-10-31 14:26:20 +04:00
Alexander Shaduri 4ff0aaad9c Hide self-test tab if NVMe does not support self-tests. 2024-06-11 13:53:23 +04:00
Alexander Shaduri c0eb5e2087 Renamed bundled icon files. 2024-06-11 13:48:41 +04:00
Alexander Shaduri c795635469 Improve device type detection. 2024-06-11 13:47:11 +04:00
Alexander Shaduri e844b9949d Detection of NVMe self-test support. 2024-06-11 13:46:57 +04:00
Alexander Shaduri 5c807e1859 Fix missing include. 2024-06-11 13:29:35 +04:00
Alexander Shaduri b2edaf69c1 Fix data member naming convention. 2024-06-11 13:29:25 +04:00
Alexander Shaduri dfa6d043b3 Improve per-drive-type icon selection. 2024-06-11 13:16:24 +04:00
Alexander Shaduri 5e3f01f350 Fixed function naming convention. 2024-06-11 13:15:40 +04:00
Alexander Shaduri f9a098d67b Merge pull request #62 from skitt/package-name
Add the package name to the icons and ui paths
2024-06-11 12:22:18 +04:00
Stephen Kitt 3324e27dee Add the package name to the icons and ui paths
CMAKE_INSTALL_FULL_DATADIR gives the read-only
architecture-independent data root without the package name, so
BuildEnv::package_pkgdata_dir() only returns that ("/usr/share" or
equivalent). This adds the package name to the appropriate search
paths in app_init_and_loop().

Signed-off-by: Stephen Kitt <steve@sk2.org>
2024-06-05 16:01:47 +02:00
Alexander Shaduri 25f1c62d2c Support NVMe behind USB bridges. 2024-05-31 12:50:03 +04:00
Alexander Shaduri afd6ce0a1f Fix CI. 2024-05-29 13:36:00 +04:00
Alexander Shaduri fb62473b0b Fix CI. 2024-05-29 12:49:04 +04:00
Alexander Shaduri 9b1bc82353 Extract smartmontools before running cmake. 2024-05-29 12:23:51 +04:00
Alexander Shaduri d1f0b517e4 More debug messages. 2024-05-29 11:24:22 +04:00
Alexander Shaduri ec50159a15 Add listing of files for debugging. 2024-05-29 11:06:38 +04:00
Alexander Shaduri a7f513fd7c Fix CPack rules. 2024-05-28 14:07:20 +04:00
Alexander Shaduri 698024d47d Fix CPack rules. 2024-05-28 13:44:00 +04:00
Alexander Shaduri eb8d91470b Fix CPack rules. 2024-05-28 13:34:50 +04:00
Alexander Shaduri 780f22818e CPack improvements for Windows. 2024-05-28 11:59:49 +04:00
Alexander Shaduri fdcf9f7099 Fix security warning. 2024-05-28 11:25:59 +04:00
Alexander Shaduri ec0445ec54 Merge remote-tracking branch 'origin/main' 2024-05-28 11:21:13 +04:00
Alexander Shaduri 75f50cd5bb Update workflows with latest permissions. 2024-05-28 11:19:51 +04:00
Alexander Shaduri 4d1af3ce9c Merge pull request #61 from skitt/canonical-nlohmann-json
Use the canonical nlohmann json include path.
2024-05-28 10:53:52 +04:00
Stephen Kitt 7b6aa046f4 Use the canonical nlohmann json include path
As documented in https://github.com/nlohmann/json, the canonical
include path for json.hpp is nlohmann/json.hpp. Tihs updated the
vendored dependency to match, so that gsmartcontrol can more easily be
built using a system-installed copy of nlohmann json as well as the
vendored copy.

Signed-off-by: Stephen Kitt <steve@sk2.org>
2024-05-27 13:31:27 +02:00
Alexander Shaduri 844f6ed86f Add workflow for creating Windows Release packages. 2024-05-22 13:44:06 +04:00
Alexander Shaduri 7a8cbe202e Use llvm17 in FreeBSD. 2024-05-22 13:34:56 +04:00
Alexander Shaduri ec2a4648e1 Upgrade freebsd build to latest version of action. 2024-05-22 12:59:23 +04:00
Alexander Shaduri 186682b6d4 Updated NEWS.txt to include information about 1.1.4. 2024-05-22 12:01:55 +04:00
Alexander Shaduri db6811450e Remove local_glibmm.h workaround for broken libintl.h. 2024-05-22 11:51:41 +04:00
Alexander Shaduri 1c19b51fda Moved application GUI source files to gui subdirectory. 2024-05-22 11:46:02 +04:00
Alexander Shaduri 28cad446b7 Packaging fixes. 2024-05-21 20:33:04 +04:00
Alexander Shaduri 84867cc474 Create and use cmake toolchains for msys2. 2024-05-21 16:46:53 +04:00
Alexander Shaduri 13c644efdc List msys2 files for debugging. 2024-05-21 14:47:26 +04:00
Alexander Shaduri 5085c35269 List msys2 files for debugging. 2024-05-21 14:46:30 +04:00
Alexander Shaduri 7682f1285e Merge remote-tracking branch 'origin/main' 2024-05-20 17:41:41 +04:00
Alexander Shaduri 74a0cf012b Refactored so that executor options are given as a vector, not as a string; this improves reliability as the string does not have to be shell-parsed. 2024-05-20 17:41:29 +04:00
Alexander Shaduri d356e2e79f Add nvme as a type option in GUI. 2024-05-20 17:40:41 +04:00
Alexander Shaduri fe027b7fc7 Update windows packaging. 2024-05-17 17:09:22 +04:00
Alexander Shaduri 501134c2fd Use double-quoting of commands in Windows. 2024-05-17 16:56:44 +04:00
Alexander Shaduri debe2e63cb Github issue template tweaks. 2024-05-17 14:38:52 +04:00
Alexander Shaduri 4452ec50fb Updated OBS workflow repositories. 2024-05-17 14:38:21 +04:00
Alexander Shaduri f034f45b93 Packaging fixes. 2024-05-17 14:10:19 +04:00
Alexander Shaduri 5160486dcd Packaging fixes. 2024-05-17 14:04:24 +04:00
Alexander Shaduri 876c586620 Packaging fixes. 2024-05-17 13:59:47 +04:00
Alexander Shaduri 85ef6faf7d Packaging fixes. 2024-05-17 13:40:46 +04:00
Alexander Shaduri 6004a76884 Packaging fixes. 2024-05-17 13:39:54 +04:00
Alexander Shaduri 944829a6be Packaging fixes. 2024-05-17 13:34:29 +04:00
Alexander Shaduri 9b75a426c5 Packaging fixes. 2024-05-17 13:26:32 +04:00
Alexander Shaduri d6d63b7f88 Packaging fixes. 2024-05-17 13:14:01 +04:00
Alexander Shaduri d9adde161c Packaging fixes. 2024-05-17 13:12:03 +04:00
Alexander Shaduri 3d45bbe12a Packaging fixes. 2024-05-17 13:09:13 +04:00
Alexander Shaduri 90be761780 Updated packaging. 2024-05-17 12:49:47 +04:00
Alexander Shaduri 22c5cfdffd Updated packaging. 2024-05-17 12:46:06 +04:00
Alexander Shaduri 7834f61662 Updated packaging. 2024-05-17 12:43:04 +04:00
Alexander Shaduri cafb1ef28d Updated packaging. 2024-05-17 12:29:44 +04:00
Alexander Shaduri 4211374126 Updated documentation to indicate NVMe support. 2024-05-17 11:38:57 +04:00
Alexander Shaduri cfa50198ee Removed unused cmake file. 2024-05-17 11:37:35 +04:00
Alexander Shaduri f4c1cebfd0 Update cron script to use json. 2024-05-17 11:24:52 +04:00
Alexander Shaduri 7cef499e67 Use ubuntu-24.04 for Actions as ubuntu-latest does not have gcc13 as of now. 2024-05-16 17:04:37 +04:00
Alexander Shaduri e40da83827 Merge pull request #60 from ashaduri/stdregex
PCRE to std::regex port
2024-05-16 16:49:27 +04:00
Alexander Shaduri d916dc4a9d Removed mention of any pcre dependency. 2024-05-16 16:47:44 +04:00
Alexander Shaduri 791cc93f5f Fixed std::regex-based parsing. 2024-05-16 16:41:39 +04:00
Alexander Shaduri 1df72dc2e0 Initial port from pcre to std::regex (not working yet). 2024-05-16 16:27:18 +04:00
Alexander Shaduri cf3a9f6ae3 Partial port from pcre to std::regex. 2024-05-16 15:13:34 +04:00
Alexander Shaduri 946f4b4339 Fix test failure under Arm architecture. 2024-05-15 13:48:48 +04:00
Alexander Shaduri e88a0b5ca3 Limit the VM memory. 2024-05-15 13:42:50 +04:00
Alexander Shaduri 6d23e01a82 Fixed running tests under Arm. 2024-05-15 13:42:38 +04:00
Alexander Shaduri 0f8c6039ce Update GitHub actions. 2024-05-15 13:12:49 +04:00
Alexander Shaduri 2abae1c673 Update GitHub actions. 2024-05-15 13:07:05 +04:00
Alexander Shaduri 1e16d7b521 Update GitHub actions. 2024-05-15 12:26:40 +04:00
Alexander Shaduri 55dade8b51 Install clang. 2024-05-15 12:18:42 +04:00
Alexander Shaduri 2e53d3e4c9 Try AppleClang 16. 2024-05-15 12:09:52 +04:00
Alexander Shaduri 4a0ce23184 Compile with AppleClang 15. 2024-05-15 12:00:33 +04:00
Alexander Shaduri 02535eeeb2 Update GitHub actions. 2024-05-14 18:35:42 +04:00
Alexander Shaduri 6d49968a59 Fix make_format_args() calls. 2024-05-14 18:30:46 +04:00
Alexander Shaduri 84ae416c2c Removed AODC feature, it's been deprecated for a while. 2024-05-14 17:42:46 +04:00
Alexander Shaduri dd4fd4d187 Fixed loading text files as virtual devices (size parsing, ATA detection). 2024-05-14 17:26:51 +04:00
Alexander Shaduri ade001359b Implemented loading virtual drives from JSON. 2024-05-14 16:57:01 +04:00
Alexander Shaduri ac2d3d6b33 Implement proper SMART on/off switch support detection. 2024-05-14 15:55:12 +04:00
Alexander Shaduri 537ea258ca NVMe: Full support for self-testing. 2024-05-14 15:41:27 +04:00
Alexander Shaduri 32302c6a80 Info Window: Fixed refresh not working with treeviews. 2024-05-14 15:11:06 +04:00
Alexander Shaduri 5ba969c561 NVMe: Support self-test log and running self-tests (untested). 2024-05-14 14:27:24 +04:00
Alexander Shaduri 5a4e60f645 Format LBA in locale-aware way. 2024-05-14 14:26:37 +04:00
Alexander Shaduri 456feb645a NVMe: Show Error Log. 2024-05-14 11:50:27 +04:00
Alexander Shaduri 556a82e42b NVMe: Show attributes in Info window. 2024-05-13 18:11:06 +04:00
Alexander Shaduri 57f7b6d000 Make Info window display tabs only if properties with appropriate sections are available. 2024-05-13 17:17:24 +04:00
Alexander Shaduri 67a0b128f7 Display info properly for flash drives. 2024-05-13 16:49:07 +04:00
Alexander Shaduri f60f08327c Info Window: Adapt to ATA JSON parser. 2024-05-13 16:48:48 +04:00
Alexander Shaduri 72c01bebba NVMe: Parse error log. 2024-05-13 16:48:26 +04:00
Alexander Shaduri dede4695e9 ATA JSON parser is on par with Text parser now, feature-wise. 2024-05-13 16:48:01 +04:00
Alexander Shaduri 5efefd3576 Implemented NVMe self-test log parsing.
Refactoring AtaStorageProperty -> StorageProperty.
2024-05-07 19:36:40 +04:00
Alexander Shaduri 516eaa2086 Basic NVMe parser implemented. 2024-05-02 15:20:16 +04:00
Alexander Shaduri c3a6f0b624 Implemented detection of device type. 2024-05-02 14:38:31 +04:00
Alexander Shaduri 6594cddb65 Refactored drive data fetch and parsing, and drive types. 2024-05-02 13:47:20 +04:00
Alexander Shaduri bf2343015e Avoid unnecessary exceptions when reading config file. 2024-05-02 13:47:14 +04:00
Alexander Shaduri 228bcf5014 Fixed enum_helper.h errors. 2024-05-02 13:46:49 +04:00
Alexander Shaduri 589263e902 etc... -> etc. 2024-04-25 16:53:30 +04:00
Alexander Shaduri 02bdf755a3 Fixed crash on reload; tables still to be fixed. 2024-04-25 16:44:25 +04:00
Alexander Shaduri 61fe92e201 ATA JSON parser improvements. 2024-04-24 15:58:45 +04:00
Alexander Shaduri 1b7264793e ATA JSON parser improvements. 2024-04-24 15:51:01 +04:00
Alexander Shaduri 13fc56c24a Updated visible copyright years. 2024-04-23 17:18:08 +04:00
Alexander Shaduri 18a6628d0e Support parsing more of ATA output in JSON. 2024-04-23 17:03:52 +04:00
Alexander Shaduri 5746ab5ed9 GitHub actions: Fix conflicting artifact names. 2024-04-23 16:32:59 +04:00
Alexander Shaduri ac90991a27 GitHub actions: Support smartmontools 7.4 installer directory structure when extracting. 2024-04-23 14:11:31 +04:00
Alexander Shaduri 531d39d888 Smartmontools in Windows uses update-smart-drivedb.ps1 now, so use that. 2024-04-23 13:51:51 +04:00
Alexander Shaduri 68576e9a95 Use smartmontools 7.4 in CI. 2024-04-23 13:31:01 +04:00
Alexander Shaduri f7d9956665 Support parsing ATA Self-test Log in JSON.
UI fixes.
2024-04-23 12:55:23 +04:00
Alexander Shaduri aa0c2e520f Updated GitHub actions to use Node20 versions. 2024-04-22 22:19:14 +04:00
Alexander Shaduri 9ea48c7298 Fix win32 compilation. 2024-04-22 22:05:36 +04:00
Alexander Shaduri c065e55ca1 GH Actions: Use GCC 13, that is the minimum required now. 2024-04-22 18:08:34 +04:00
Alexander Shaduri 2c163503d9 GH Actions: Use GCC 12. 2024-04-22 17:48:34 +04:00
Alexander Shaduri 212b6bfe4f Fix compilation. 2024-04-22 17:22:14 +04:00
Alexander Shaduri ea6998dcad Support parsing ATA Directory Log in JSON. 2024-04-22 17:17:00 +04:00
Alexander Shaduri d6ec442945 Support parsing ATA Attributes in JSON. 2024-04-19 14:21:06 +04:00
Alexander Shaduri 6da27f7e86 Support parsing ATA Capabilities from JSON. 2024-04-19 11:47:48 +04:00
Alexander Shaduri 50d605b5b4 Updated .clang-tidy to ignore library headers. 2024-04-19 11:47:25 +04:00
Alexander Shaduri b147a3db3e Ported some more of string_algo.h to string_view. 2024-04-19 11:46:51 +04:00
Alexander Shaduri 6018f35598 Disable std::filesystem TR support, we require C++20 anyway. 2024-04-16 12:40:10 +04:00
Alexander Shaduri fccf448b3a Bundle and use tl::expected instead of std::expected to support C++20 compilers. 2024-04-16 12:39:22 +04:00
Alexander Shaduri 0cd846728c Fixed compiler warnings. 2024-04-15 17:15:00 +04:00
Alexander Shaduri 876e29973c Simplified AtaStorageProperty by mergin Section and SubSection. 2024-04-15 16:29:51 +04:00
Alexander Shaduri 351f5edaa9 Switched most of message-based error handling to std::expected.
Refactored enum class naming to use ThisCase.
Decorated most getters with [[nodiscard]].
2024-03-22 18:21:08 +04:00
Alexander Shaduri 6edcf19694 Implemented Basic Output JSON parser.
Switched all devices to JSON by default.
2024-03-20 23:11:50 +04:00
Alexander Shaduri 73463e5c23 Cleanup of output format / device type handling. 2024-03-20 20:57:16 +04:00
Alexander Shaduri 21267acb8c Separate out basic text parser from StorageDevice.
Store all properties in StoragePropertyRepository.
2024-03-20 20:29:19 +04:00
Alexander Shaduri 9889f8792f Initial work on JSON parser. 2024-03-19 16:16:36 +04:00
Alexander Shaduri ae5a327116 Initial work on JSON parser. 2024-03-15 17:33:24 +04:00
Alexander Shaduri 8b12bb45c3 Initial work on JSON parser. 2024-03-15 16:59:14 +04:00
Alexander Shaduri a32b9fb8a9 Initial work on JSON parser. 2024-03-14 16:06:16 +04:00
Alexander Shaduri eb44ed1bc5 Some code modernization. 2024-03-14 13:52:46 +04:00
Alexander Shaduri 5fe252934c Disabled false positive. 2024-03-11 15:25:38 +04:00
Alexander Shaduri 3c4a740759 Improved constness of local variables. 2024-03-11 15:25:14 +04:00
Alexander Shaduri 29555ed584 Ported away from deprecated u8path(). 2024-03-11 14:53:05 +04:00
Alexander Shaduri f454b9df2d Disabled noisy warnings. 2024-03-11 14:50:21 +04:00
Alexander Shaduri 6266ce3c6c Ported SmartctlParser to std::expected, added hz::ErrorContainer as a helper. 2024-03-11 14:50:08 +04:00
Alexander Shaduri d0cfd73fab Removed leaf, porting to std::expected. 2024-03-07 14:39:08 +04:00
Alexander Shaduri 985700c79d Moved to C++23, making the code compatible with it (u8string / u8path incompatibilities). 2024-03-07 14:38:44 +04:00
Alexander Shaduri e650fa4d8b Fixed a typo. 2024-02-29 18:28:35 +04:00
Alexander Shaduri 72b2173dfc Make sure to require Gtkmm. 2024-02-29 18:28:16 +04:00
Alexander Shaduri 7f688e0fa4 Initial work on JSON parser. 2023-03-06 19:18:48 +04:00
Alexander Shaduri c8f79c36b4 Minor cleanups. 2023-03-06 19:18:16 +04:00
Alexander Shaduri 396ea3daf3 Fixed some clang-tidy warnings. 2023-03-03 23:00:52 +04:00
Alexander Shaduri c4b2c1d760 Merge pull request #41 from ferdnyc/no-warn-printf
FindFilesystem: Eliminate Win32 warning
2023-01-16 13:32:31 +04:00
FeRD (Frank Dana) 0bf4ef711e FindFilesystem: Eliminate Win32 warning
Using `printf("%s")` with a `std::filesystem::path` on Win32 will
cause a compile warning, because `std::filesystem::path::value_type`
is technically `wchar_t`.

The warning is harmless, but by using iostream to print the value
on `std::cout` instead, the code compiles without warnings.
2023-01-15 12:54:17 -05:00
Alexander Shaduri affdd497ec Updated GitHub actions to use Node16 (try 2). 2023-01-09 18:18:29 +04:00
Alexander Shaduri 6b6bd2e369 GitHub action: Fix codeql. 2023-01-09 17:44:05 +04:00
Alexander Shaduri 466b4f9a0f GitHub action: Install pcre in msys2. 2023-01-09 17:43:02 +04:00
Alexander Shaduri e90aad5994 Updated GitHub actions to use Node16. 2023-01-09 17:41:21 +04:00
Alexander Shaduri 338c8a8eee Merge remote-tracking branch 'origin/main' 2023-01-09 17:28:04 +04:00
Alexander Shaduri a390c3daa6 Updated Catch2 to 2.13.10. 2023-01-09 17:27:52 +04:00
Alexander Shaduri 9e0dbe67e6 Ignore doxygen_doc in git. 2023-01-09 17:14:03 +04:00
Alexander Shaduri 6b02bf5df0 Update _config.yml 2022-09-14 12:38:20 +04:00
Alexander Shaduri 029f519005 Update SECURITY.md 2022-06-17 12:35:41 +04:00
Alexander Shaduri b6248459be Update issue templates 2022-06-17 12:34:08 +04:00
Alexander Shaduri 51e3b2a1f7 Update issue templates 2022-06-17 12:33:50 +04:00
Alexander Shaduri b2504e9477 Update issue templates 2022-06-17 12:32:35 +04:00
Alexander Shaduri ec6ddd1c5c Update SECURITY.md 2022-06-17 12:30:44 +04:00
Alexander Shaduri 60705fe93b Update issue templates 2022-06-17 12:29:37 +04:00
Alexander Shaduri cf407da41b Update issue templates 2022-06-17 12:27:01 +04:00
Alexander Shaduri 5435feb932 Windows: Make sure we consider non-fixed drives as well, when detecting "Drive letters" for a drive. 2022-05-20 13:04:26 +04:00
Alexander Shaduri 02e4f8e536 GitHub Actions: Use github.workspace instead of runner.workspace. 2022-03-15 14:12:30 +04:00
Alexander Shaduri db090f9164 Updated github pages: Document NSIS options. 2022-02-18 12:12:40 +04:00
Alexander Shaduri 70967beebf Implemented smartctl output format detection function, along with its test. 2022-02-16 17:33:05 +04:00
Alexander Shaduri 5b7c2f6dbb Added helper for testing leaf-created errors. 2022-02-16 17:32:20 +04:00
Alexander Shaduri 2d7a3a4dd9 Updated clang-tidy configuration to exclude noisy warnings. 2022-02-16 17:30:06 +04:00
Alexander Shaduri 01d699fc74 Make sure the third-party libraries are always included as "system". 2022-02-15 16:30:27 +04:00
Alexander Shaduri 6ed82f821f Added a Boost LEAF library copy. 2022-02-15 16:29:45 +04:00
Alexander Shaduri c59fa32efe Added a Boost LEAF library copy. 2022-02-15 16:22:41 +04:00
Alexander Shaduri dbdb0e4686 Fixed compilation. 2022-02-15 16:22:00 +04:00
Alexander Shaduri fc0df14992 Refactored smartctl output parser for better API, support for different formats. 2022-02-15 15:56:42 +04:00
Alexander Shaduri a5771f1af9 Updated OBS workflows. 2022-02-15 14:03:35 +04:00
Alexander Shaduri 4db097b0b0 Update cmake requirement to 3.14. 2022-02-15 14:03:24 +04:00
Alexander Shaduri 65e4c4f7ac Revert "Fixed test link errors on Debian 10."
This reverts commit 5009fbfbe4.
2022-02-15 14:01:51 +04:00
Alexander Shaduri d1df4b2fad Updated OBS workflows. 2022-02-15 13:44:01 +04:00
Alexander Shaduri 5009fbfbe4 Fixed test link errors on Debian 10. 2022-02-15 13:42:43 +04:00
Alexander Shaduri cbfcf2bb3c Updated OBS workflows. 2022-02-15 12:58:32 +04:00
Alexander Shaduri 63e16d0bac Updated OBS workflows. 2022-02-14 17:27:51 +04:00
Alexander Shaduri cd58c6ce90 Updated OBS workflows. 2022-02-14 15:29:41 +04:00
Alexander Shaduri 6787b3c1fe Updated OBS workflows. 2022-02-14 15:27:04 +04:00
Alexander Shaduri 980ff6f150 Updated OBS workflows. 2022-02-14 15:25:16 +04:00
Alexander Shaduri ef5f97ad88 Updated OBS workflows. 2022-02-14 15:20:21 +04:00
Alexander Shaduri 9ad97c8390 Added OBS workflow integration. 2022-02-14 14:33:12 +04:00
Alexander Shaduri 8256ea2115 Fixed CodeQL workflow. 2022-02-14 14:32:51 +04:00
Alexander Shaduri b6f97ba0a4 Updated github actions. 2022-02-14 13:46:42 +04:00
Alexander Shaduri 88a36c6f57 Changed internal property names to match smartctl's json paths. 2022-02-14 13:21:23 +04:00
Alexander Shaduri 8932460b8c Updated github pages. 2022-02-13 13:43:21 +04:00
Alexander Shaduri 7e570cea45 Refactored parse_byte_size out of SmartctlAtaTextParser. 2022-02-11 18:04:54 +04:00
Alexander Shaduri 1d781d3d54 Code cleanups. 2022-02-11 16:01:10 +04:00
Alexander Shaduri c1070e375f Added initial work for selecting smartctl parser type.
Refactored smartctl version parsing, added tests.
2022-02-11 16:00:21 +04:00
Alexander Shaduri 582d4ad5cd Converted hz string algorithms example into a test. 2022-02-11 14:08:57 +04:00
Alexander Shaduri 907c9ac423 Refactored example_string_num.cpp into a test.
Fixed underflow detection for unsigned types in hz::string_is_numeric().
2022-02-11 13:43:22 +04:00
Alexander Shaduri f9c805648a Converted hz unit formatting example into a test. 2022-02-10 17:17:06 +04:00
Alexander Shaduri 94e3e864bc Merge remote-tracking branch 'origin/main' into main 2022-02-10 16:45:45 +04:00
Alexander Shaduri 53acbd9594 libdebug: Removed C-style debug_print*() functions, ported everything to debug_out_*(). 2022-02-10 16:45:33 +04:00
Alexander Shaduri 085f066958 rconfig: A safer way to pass data to a C callback. 2022-02-10 16:44:08 +04:00
Alexander Shaduri 594f177160 Merge pull request #27 from skitt/lcall
Set LC_ALL to control the locale of other processes.
2022-02-10 12:18:23 +04:00
Stephen Kitt c53166f630 Set LC_ALL to control the locale
LANG specifies the default locale, LC_NUMERIC specifies the locale for
that particular category, but LC_ALL overrides all the locale
settings. Thus any user with LC_ALL set can still run into
locale-related problems.

Setting LC_ALL to C avoids any such issue.

See locale(7) for details.

Signed-off-by: Stephen Kitt <steve@sk2.org>
2022-02-10 08:26:34 +01:00
Alexander Shaduri 64f4a8077e Updated links to the new gsmartcontrol.shaduri.dev site. 2022-02-09 17:51:09 +04:00
Alexander Shaduri a4bfdcefa8 Updated github pages. 2022-02-09 17:33:20 +04:00
Alexander Shaduri e6b83c7473 Updated links to online documentation. 2022-02-08 19:21:45 +04:00
Alexander Shaduri 107292a328 Updated github pages. 2022-02-08 19:16:25 +04:00
Alexander Shaduri 9f31c845ee Updated github pages. 2022-02-08 18:39:26 +04:00
Alexander Shaduri 3acee26d05 Updated github pages. 2022-02-08 18:36:44 +04:00
Alexander Shaduri 1b260fd745 Updated github pages. 2022-02-08 18:35:32 +04:00
Alexander Shaduri 02dd6176d7 Updated github pages. 2022-02-08 18:32:33 +04:00
Alexander Shaduri d19c6acadd Updated github pages. 2022-02-08 18:26:53 +04:00
Alexander Shaduri 911ec96207 Updated github pages. 2022-02-08 18:10:21 +04:00
Alexander Shaduri 1cefc9d9ba Updated github pages. 2022-02-08 17:27:56 +04:00
Alexander Shaduri da1b73feee Updated github pages. 2022-02-08 17:22:10 +04:00
Alexander Shaduri 8ce7d781a4 Updated github pages. 2022-02-08 17:16:55 +04:00
Alexander Shaduri 3db5941757 Updated github pages. 2022-02-08 16:56:15 +04:00
Alexander Shaduri 8b925ae0c4 Updated github pages. 2022-02-08 15:31:34 +04:00
Alexander Shaduri ea7f65725e Updated github pages and README.md. 2022-02-08 15:28:13 +04:00
Alexander Shaduri 137736d6eb Updated github pages. 2022-02-08 13:05:27 +04:00
Alexander Shaduri d0136e6a71 Updated github pages. 2022-02-07 19:05:35 +04:00
Alexander Shaduri 9abb0ff3a9 Update README.md 2022-02-04 15:42:05 +04:00
Alexander Shaduri b706b114b3 Use ubuntu-latest in github action. 2022-02-04 14:33:41 +04:00
Alexander Shaduri 3085c037ba Bumped Debian package compatibility level to 9. 2022-02-04 14:29:43 +04:00
Alexander Shaduri c34ddd32a5 Split github tier2 builds into standard and flaky actions. 2022-02-04 14:29:26 +04:00
Alexander Shaduri 3c10a1e12a Fix syntax errors in cs.po. 2022-02-04 14:24:19 +04:00
Alexander Shaduri a154a813ad Use Catch2 v2 instead of v3 due to build errors with latest compilers. 2022-02-04 14:24:01 +04:00
Alexander Shaduri 3b5c7365a1 Windows: Embed exe manifest in the resource; don't handle the manifest in NSIS. 2022-02-04 12:02:44 +04:00
Alexander Shaduri 0f78b7e91c Windows: Set GTK_CSD=0 only if no GTK_CSD is set. 2022-02-04 12:02:04 +04:00
Alexander Shaduri cf93bf008f Updated Catch2 to git devel branch 2022-02-02. 2022-02-02 23:42:47 +04:00
Alexander Shaduri 2bbe7788f1 Ubuntu package: Fixed support for Ubuntu 21.10 on OBS. 2022-02-02 23:37:21 +04:00
Alexander Shaduri 025348bfe3 Remove trailing slash from homepage URL. 2022-02-02 23:14:15 +04:00
Alexander Shaduri 4cf809b579 Debian package: Fixed support for Debian Testing and Debian Unstable on OBS. 2022-02-02 23:13:53 +04:00
Alexander Shaduri 9e1d92a7bc Debian package: Build tests and examples, this should fix OBS build failures. 2022-02-02 23:09:20 +04:00
Alexander Shaduri ef94137edc Info Window: Make the text views with output texts use monospace font with the new GTK versions. 2022-02-01 13:46:43 +04:00
Alexander Shaduri 910f71ec9e Info Window: Align and monospace table cells where applicable to improve readability. 2022-02-01 13:31:18 +04:00
Alexander Shaduri f4973cdb4b Handle all tree view styling in per-table cell renderers; this fixes conflicts between renderer styles and markup. 2022-02-01 12:51:48 +04:00
Alexander Shaduri 4dcc8e23e7 List all gtkmm deprecation macros for future reference. 2022-02-01 12:45:41 +04:00
Alexander Shaduri 044193c7ed Command execution popup windows: Use "dialog" type of window instead of "notifications"; this should fix #17 (the popup is floating above all the other applications). 2022-01-31 15:29:14 +04:00
Alexander Shaduri 29b2bb6635 Merge remote-tracking branch 'origin/main' into main 2022-01-31 15:11:12 +04:00
Alexander Shaduri d9f0314655 Code cleanup - reduce std::wcslen usage. 2022-01-31 15:11:04 +04:00
Alexander Shaduri af6c230edc Update devskim-analysis.yml 2022-01-31 15:09:50 +04:00
Alexander Shaduri 01746ab16d Ported some win32_tools.h code to std::filesystem. 2022-01-31 14:38:31 +04:00
Alexander Shaduri 5865134b29 Code cleanup - reduce std::strlen usage. 2022-01-29 22:27:12 +04:00
Alexander Shaduri 39d033c50d Fixed Codacy note in shell script. 2022-01-29 21:48:35 +04:00
Alexander Shaduri f64b3bc82d Added license badge to README.md 2022-01-29 21:45:01 +04:00
Alexander Shaduri 3f2353cc57 Updated README.md for style. 2022-01-29 21:29:49 +04:00
Alexander Shaduri bc20a790da Merge remote-tracking branch 'origin/main' into main 2022-01-29 21:27:48 +04:00
Alexander Shaduri a238770418 Update style. 2022-01-29 21:25:47 +04:00
Alexander Shaduri 90eb339a05 Fixed Codacy warnings in shell scripts. 2022-01-29 21:12:36 +04:00
Alexander Shaduri fa16ff964e Merge remote-tracking branch 'origin/main' into main 2022-01-29 11:57:08 +04:00
Alexander Shaduri ebb864f234 Add nullptr check to on_cell_data_render(), just in case. 2022-01-29 11:56:54 +04:00
Alexander Shaduri 01a33b97a7 Merge pull request #25 from codacy-badger/codacy-badge
Add a Codacy badge to README.md
2022-01-27 23:07:22 +04:00
Alexander Shaduri 8b05464444 Delete msvc-analysis.yml 2022-01-27 23:04:16 +04:00
The Codacy Badger 977396e852 Add Codacy badge 2022-01-27 18:33:50 +00:00
Alexander Shaduri 84b6e84c49 Update devskim-analysis.yml 2022-01-27 22:19:55 +04:00
Alexander Shaduri 33b96b459e Update msvc-analysis.yml 2022-01-27 22:18:08 +04:00
Alexander Shaduri a095f9f6bd Delete scorecards-analysis.yml 2022-01-27 22:01:48 +04:00
Alexander Shaduri 828558bfcc Update devskim-analysis.yml 2022-01-27 21:57:52 +04:00
Alexander Shaduri e49b0cbf8c Update codeql-analysis.yml 2022-01-27 21:49:28 +04:00
Alexander Shaduri 39fc4b2997 Create CODE_OF_CONDUCT.md 2022-01-25 17:14:04 +04:00
Alexander Shaduri 5d2925fd94 Create SECURITY.md 2022-01-25 17:08:56 +04:00
Alexander Shaduri f6a2a1cab5 Create scorecards-analysis.yml 2022-01-25 17:05:30 +04:00
Alexander Shaduri 661bcfe56e Create msvc-analysis.yml 2022-01-25 17:04:03 +04:00
Alexander Shaduri 821da2ce29 Create devskim-analysis.yml 2022-01-25 17:03:11 +04:00
Alexander Shaduri 38ee3fabd9 Create codacy-analysis.yml 2022-01-25 17:02:01 +04:00
Alexander Shaduri ac54d29f66 Create codeql-analysis.yml 2022-01-25 17:00:46 +04:00
Alexander Shaduri b27b04ebf0 Fixed building under Windows. 2022-01-25 16:54:42 +04:00
Alexander Shaduri 055438e740 Place less code in #ifdef _WIN32 to make platform-specific compilation less error-prone. 2022-01-25 16:42:10 +04:00
Alexander Shaduri 5f11e9a7ce Fixed building under Windows. 2022-01-18 16:31:13 +04:00
Alexander Shaduri f128de2b30 Fixed building non-debug builds. 2022-01-18 15:53:48 +04:00
Alexander Shaduri 88e9e8c2f7 Implemented most build settings as constexpr functions and ported most of macro-based conditional compilation to if constexpr(); this significantly improves code quality and the chance of build success on different platforms and build configurations.
More code modernization.
2022-01-18 15:30:55 +04:00
Alexander Shaduri 235fba8a04 Convert relative smartctl-nc path to absolute before running it. 2022-01-15 15:24:11 +04:00
Alexander Shaduri 0183626c73 Change current path to gsmartcontrol directory before running smartctl - this should fix not being able to find "smartctl-nc" when CWD differs from gsmartcontrol installation directory, as it may happen when running gsmartcontrol from cmd. 2022-01-15 15:07:10 +04:00
Alexander Shaduri bcc36f260d Fixed finding data files in non-debug builds when running from build directory. 2022-01-15 15:01:39 +04:00
Alexander Shaduri ad796dad9e Automatically handle running from source/build directory and from package, using whereami library; this should fix not being able to run the application from non-standard build directories. 2022-01-15 14:35:06 +04:00
Alexander Shaduri 0ca482bc5d Include whereami library as a third-party dependency. 2022-01-15 14:33:12 +04:00
Alexander Shaduri c72b746d0a Escape all text wherever it may be interpreted as markup, even if not coming from external source. 2022-01-14 19:17:15 +04:00
Alexander Shaduri b4b6980a0c Fixed a GTK warning related to markup in Info window's attributes tab. 2022-01-14 18:53:16 +04:00
Alexander Shaduri 534dcd129e Code modernization and cleanups. 2022-01-14 15:06:07 +04:00
Alexander Shaduri 3e4cefb04f Fixed a crash when trying to render main window icons which have incomplete data; fixes #13 in main branch. 2022-01-12 18:04:42 +04:00
Alexander Shaduri dd392845a6 Fixed cmake build for the last commit. 2022-01-10 21:09:03 +04:00
Alexander Shaduri 7f2fb32735 Refactored InstanceManager (now WindowInstanceManager) to manage all window instances, keep them alive and have the ability to destroy them; this avoids any manual "delete" calls, and fixes a (newly introduced) crash on exit. 2022-01-10 19:13:11 +04:00
Alexander Shaduri f3247ec13b Merge remote-tracking branch 'origin/main' into main 2022-01-10 17:02:12 +04:00
Alexander Shaduri ad014517b9 Set LC_NUMERIC=C for smartctl process to avoid locale-dependent number formatting. 2022-01-10 17:01:56 +04:00
Alexander Shaduri e3de5aa3fe Merge pull request #21 from hjudt/fix-barely-readable-info-cell-texts
Device Information window: Fix barely readable table cell text on some systems
2021-12-21 18:03:12 +04:00
Harald Judt 6adac797d3 Fix barely readable info cell texts
By simply resetting values, the rendered cell text colors are barely
readable. Setting Pango::WEIGHT_NORMAL instead of resetting seems to fix this
nicely without any negative consequences.

Signed-off-by: Harald Judt <h.judt@gmx.at>
2021-12-21 14:25:06 +01:00
Alexander Shaduri 99c9d393c2 Merge pull request #15 from davoper/improvements
Add time to default filename in save dialog
2021-12-01 18:07:07 +04:00
dpc 17f54a8848 Add time (%H%M) to default filename in save dialog 2021-10-08 20:24:02 +02:00
Alexander Shaduri f9c5ad470c Merge pull request #11 from Translate-SW/patch-4
Update LINGUAS list
2021-08-11 18:32:23 +04:00
Alexander Shaduri da539e57a4 Merge pull request #12 from Translate-SW/patch-3
Czech translations for GSmartControl (cs.po)
2021-08-11 18:31:59 +04:00
CZ-Translator 37d86b2914 Update LINGUAS 2021-08-09 18:00:39 +02:00
CZ-Translator acc84385b5 Create cs.po 2021-08-09 17:59:07 +02:00
Alexander Shaduri 701ce81aab Merge pull request #5 from pinotree/legacy-pixmaps-location
Stop installing application icons to the legacy pixmaps location
2021-05-17 13:19:34 +04:00
Pino Toscano 71bcfe80e3 Stop installing app icon in pixmaps location
The /usr/share/pixmaps location is considered a legacy location for
application icons; since the application icons are already installed in
the global XDG hicolor theme, then simply stop installing the 48px one
in the legacy pixmaps location.
2021-05-16 17:57:52 +02:00
Pino Toscano b53bbe5a97 Drop the XPM version of the app icon
The application icon is already provided as PNG in different sizes, and
installed in the global XDG hicolor icon theme. Hence, the XPM version
of it can be dropped, as it is redundant.
2021-05-16 17:54:01 +02:00
Pino Toscano ccc9cd1a32 debian: drop old Debian menu file
Debian officially deprecated the old Debian menu system more than 5
years ago [1]. Hence, drop the old menu file, as not much of use
anymore.

[1] https://lists.debian.org/debian-devel-announce/2015/09/msg00000.html
2021-05-16 17:50:38 +02:00
Alexander Shaduri b78f8573b5 Implemented smartctl process environment changes without changing the main program's environment.
Removed ScopedEnv class - it's not thread-safe and very easy to misuse.
2021-04-21 16:48:46 +04:00
Alexander Shaduri 3b7576d95c Catch2: Treat catch2 headers as system. 2021-03-22 16:48:42 +04:00
Alexander Shaduri cdb9a4c603 Renamed SmartctlTextParser to SmartctlAtaTextParser. 2021-03-19 14:51:32 +04:00
Alexander Shaduri 9a2606d96f Disable compiler warnings when compiling third-party dependencies. 2021-03-19 14:50:08 +04:00
Alexander Shaduri b1ebc88a3c GitHub actions: Use msys2 shell when running tests in msys. 2021-03-19 14:49:18 +04:00
Alexander Shaduri a33d4109d1 Fix cross-compiling (test discovery doesn't work when cross-compiling). 2021-03-17 14:26:13 +04:00
Alexander Shaduri 15ab09063b Minor cleanups. 2021-03-17 14:25:30 +04:00
Alexander Shaduri 3f0b7c1681 Fixed catch2 compiling under mingw. 2021-03-17 14:24:52 +04:00
Alexander Shaduri b1150d8e86 Implemented app_pcre_get_options() tests. 2021-03-16 18:10:35 +04:00
Alexander Shaduri b84f3d9218 Register libdebug domains in test_all. 2021-03-16 18:10:19 +04:00
Alexander Shaduri 9db25f3907 Add Catch2 testing framework and integrate it into the build system and CI; moved json to subdirectory. 2021-03-16 17:57:01 +04:00
Alexander Shaduri 812bd2191e Fixed non-linux builds. 2021-03-16 16:27:06 +04:00
Alexander Shaduri 788a4760b8 Refactored storage property classes (better naming, documentation), removed app_gtkmm_features.h. 2021-03-16 16:06:28 +04:00
Alexander Shaduri d74da816a1 Refactored command executors (better naming, documentation). 2021-03-16 15:24:08 +04:00
Alexander Shaduri cfc11bef6e Refactored app_pcrecpp.h structure. 2021-03-15 19:00:50 +04:00
Alexander Shaduri bedd8f362b Refactored gtkmm utils and app builder to simply the code and document it better. 2021-03-15 17:55:22 +04:00
Alexander Shaduri 7855ce9dfb Fixed cmake warnings. 2021-03-15 16:40:25 +04:00
Alexander Shaduri 81d6656f13 Github actions: Add Linux binary package generation. 2021-03-12 18:36:59 +04:00
Alexander Shaduri 6fad220e7e Change version to 1.1.99. 2021-03-12 18:36:18 +04:00
Alexander Shaduri 2a0f32b2c7 Try to fix msys2 packaging. 2021-03-12 18:13:31 +04:00
Alexander Shaduri 212bdb80f8 Try to fix msys2 packaging. 2021-03-12 17:54:37 +04:00
Alexander Shaduri 6039667556 Try to fix msys2 packaging. 2021-03-12 16:25:00 +04:00
Alexander Shaduri 4960be8cd1 Try to fix msys2 packaging. 2021-03-12 16:03:16 +04:00
Alexander Shaduri 89b1a5a6bd Try to fix msys2 packaging. 2021-03-12 15:09:36 +04:00
Alexander Shaduri 173f379111 OBS Debian fixes. 2021-03-12 15:09:29 +04:00
Alexander Shaduri 14288cbd1a OBS Debian fixes. 2021-03-12 15:08:30 +04:00
Alexander Shaduri 4b72bd3824 Fixed compilation under Debian 10. 2021-03-12 10:58:31 +00:00
Alexander Shaduri 902e06b893 Try to fix msys2 packaging. 2021-03-12 14:48:19 +04:00
Alexander Shaduri ca9e83ce9b OBS fixes for Debian, SLE15. 2021-03-12 14:34:51 +04:00
Alexander Shaduri 58919f3dae Implement Windows zip and NSIS packaging in GitHub actions. 2021-03-12 14:34:25 +04:00
Alexander Shaduri b042e8ad19 Merge remote-tracking branch 'origin/main' into main 2021-03-12 14:33:13 +04:00
Alexander Shaduri b188fab4df Improved Windows packaging. 2021-03-12 14:09:10 +04:00
Alexander Shaduri 5f9801328f Merge remote-tracking branch 'origin/main' into main 2021-03-11 18:06:36 +04:00
Alexander Shaduri d7978e759d Support Windows zip and NSIS package generation in MSYS2. 2021-03-11 18:06:06 +04:00
Alexander Shaduri 2d83424510 Another fix for cmake 3.12. 2021-03-11 18:05:23 +04:00
Alexander Shaduri 78391d236b Support cmake 3.12. 2021-03-11 17:09:42 +04:00
Alexander Shaduri 7934433100 Make GitHub treat header files as C++. 2021-03-11 16:44:31 +04:00
Alexander Shaduri 692fb1c7ca Fixed "drive is testing" message on startup. 2021-03-10 14:28:22 +04:00
Alexander Shaduri a6fa512e46 Updated OBS rpm rules. 2021-03-10 14:14:35 +04:00
Alexander Shaduri 4809173feb Updated OBS rpm/debian rules. 2021-03-10 13:57:22 +04:00
Alexander Shaduri 2e49c6b7ed Support compilation under gcc 7. 2021-03-10 13:44:28 +04:00
Alexander Shaduri 72064d2324 Add naive deb package support (incomplete). 2021-03-10 13:31:22 +04:00
Alexander Shaduri ce309529c5 Update OBS rpm and deb builds (deb not really supported yet). 2021-03-10 13:13:19 +04:00
Alexander Shaduri cb1abab75f Support Finnish decimal separator (backported from Debian package). 2021-03-10 13:05:47 +04:00
Alexander Shaduri 9c97f463c9 Fixed a few typos (backported from debian package). 2021-03-10 13:05:21 +04:00
Alexander Shaduri c6d910ec21 GitHub actions: Moved macos to tier2 platform list. 2021-03-10 12:39:42 +04:00
Alexander Shaduri 9574a6df20 Fixed a warning from OBS. 2021-03-09 22:01:19 +04:00
Alexander Shaduri 39c57564a6 Fixed a warning in rpm SPEC file. 2021-03-09 22:00:42 +04:00
Alexander Shaduri c0686dd234 Fixed a typo in rpm spec file. 2021-03-09 21:33:15 +04:00
Alexander Shaduri 134633e7ac Updated RPM spec to support CentOS with EPEL. 2021-03-09 21:32:39 +04:00
Alexander Shaduri c1a1aca7ec GitHub actions: Add cpack test to Ubuntu build. 2021-03-09 21:12:18 +04:00
Alexander Shaduri 57f9605f70 Split github build actions into 2 tiers (tier 1 and 2 supported platforms); tier 1 platforms are build automatically, tier 2 are built on demand. 2021-03-09 21:11:54 +04:00
Alexander Shaduri 4a658d8f43 Require proper cmake version in spec file. 2021-03-09 21:10:43 +04:00
Alexander Shaduri e4e438b579 Fixed rpm spec file for opensuse. 2021-03-09 20:58:23 +04:00
Alexander Shaduri 3080aa7f87 Updated rpm spec file's build requirements. 2021-03-09 18:00:29 +04:00
Alexander Shaduri 3e19e3e5cb Updated rpm spec file to support cmake. 2021-03-09 17:57:46 +04:00
Alexander Shaduri 09e9e7d380 Fixed cmake install target, support cpack windows binary zip / NSIS, support package_source target; removed cpack RPM and DEB support. 2021-03-09 17:14:51 +04:00
Alexander Shaduri cbd45a27fb Removed autotools-related files from gitignore. 2021-03-09 17:12:08 +04:00
Alexander Shaduri b0b9c4169e Initial refactoring to support cpack-based packaging and OBS builds. 2021-03-09 15:17:25 +04:00
Alexander Shaduri 8d6b75057e GitHub action: Fix passing correct cmake flags in freebsd build. 2021-03-09 15:16:19 +04:00
Alexander Shaduri 1ddcbc224e Fixed compilation under FreeBSD and QNX. 2021-03-09 13:08:27 +04:00
Alexander Shaduri 8dd21e2b82 Re-enable freebsd in github workflow. 2021-03-09 12:18:28 +04:00
Alexander Shaduri 2de5360ac8 Updated github workflow. 2021-03-08 18:46:13 +04:00
Alexander Shaduri 28bc0fc826 Updated github workflow. 2021-03-08 18:36:14 +04:00
Alexander Shaduri 98b96cdeb2 Updated github workflow. 2021-03-08 18:06:30 +04:00
Alexander Shaduri 98798a3e57 Updated configure-dev script with cmake support. 2021-03-08 17:24:31 +04:00
Alexander Shaduri 4d04cd5089 Updated github workflow. 2021-03-08 17:16:59 +04:00
Alexander Shaduri 0b8c94bf6f Updated configure-dev script with cmake support. 2021-03-08 17:12:04 +04:00
Alexander Shaduri 2f900bf3a2 Updated github workflow. 2021-03-08 17:11:37 +04:00
Alexander Shaduri 71a34549ab Updated github workflow. 2021-03-08 17:00:35 +04:00
Alexander Shaduri a1c7855a63 Updated github workflow. 2021-03-08 16:53:16 +04:00
Alexander Shaduri d101a92750 Support old Glibmm only with libstdc++. 2021-03-08 16:51:42 +04:00
Alexander Shaduri fce77dc7d7 Fixed building under macosx. 2021-03-08 16:51:12 +04:00
Alexander Shaduri 14a7e26e09 Updated github workflow. 2021-03-08 16:38:37 +04:00
Alexander Shaduri 700ada0b5b Updated github workflow to include macos. 2021-03-08 16:06:16 +04:00
Alexander Shaduri 740b544615 Fixed syntax error in cmake.yml. 2021-03-08 15:58:14 +04:00
Alexander Shaduri ad64427126 Don't use $GITHUB_WORKSPACE in msys2 build. 2021-03-08 15:57:13 +04:00
Alexander Shaduri 4463726d51 Disabled freebsd build for now (it's broken), 2021-03-08 15:52:46 +04:00
Alexander Shaduri 95cb1abab8 Use matrix msystem for msys builds. 2021-03-08 14:55:04 +04:00
Alexander Shaduri 10af1ab1f2 Use msys shell for msys builds. 2021-03-08 14:45:51 +04:00
Alexander Shaduri 824827ff26 Added new experimental GitHub workflows for ubuntu, windows-msys2, freebsd. 2021-03-08 14:38:29 +04:00
Alexander Shaduri 60d9bf1922 Add separate toolchain with clang-tidy support. 2021-03-05 14:19:45 +04:00
Alexander Shaduri cb42040a8d Add .vs (VS with CMake support) to gitignore. 2021-03-05 14:19:26 +04:00
Alexander Shaduri d9d681db5e Refactored libdebug's bitset-related types. 2021-03-05 14:19:01 +04:00
Alexander Shaduri 1d5e8822e6 Fixed compilation under MSYS2. 2021-03-04 14:35:05 +04:00
Alexander Shaduri 53a3f73156 Modernized Windows code, fixed compiler warnings under mingw. 2021-03-03 19:40:02 +04:00
Alexander Shaduri 28dacf4d74 Fixed all remaining clang-tidy warnings. 2021-03-03 18:15:23 +04:00
Alexander Shaduri 2859666708 Make all examples use main_tools.h exception wrapper. 2021-03-03 18:15:05 +04:00
Alexander Shaduri f861918789 Fixed compilation error in hz/main_tools.h. 2021-03-03 17:40:46 +04:00
Alexander Shaduri 8e2cf08be1 Cleaned up libdebug for clang-tidy warnings. 2021-03-03 17:40:21 +04:00
Alexander Shaduri 4f6f0ce9f6 Minor cleanup. 2021-03-03 16:54:59 +04:00
Alexander Shaduri 3032bbc4e7 Added new hz/main_tools.h header to cmake. 2021-03-03 16:54:37 +04:00
Alexander Shaduri 6f1dd37818 Fixed a few clang-tidy warnings in hz. 2021-03-03 16:54:16 +04:00
Alexander Shaduri f8369fe436 Fixed a few clang-tidy warnings in libdebug. 2021-03-03 16:53:50 +04:00
Alexander Shaduri ff3b07a086 Fixed a few clang-tidy warnings in applib. 2021-03-03 16:53:22 +04:00
Alexander Shaduri e329946213 Ported some main() functions to new main_tools. 2021-03-03 16:43:04 +04:00
Alexander Shaduri 5572421eca New hz::main_tools component to handle exceptions in main(). 2021-03-03 16:42:26 +04:00
Alexander Shaduri ef0803cb4d Redirect github page to old sourceforge page for now. 2021-03-03 12:22:21 +04:00
Alexander Shaduri 60ba6078c2 Fixed some problems reported by clang-tidy. 2021-03-02 19:12:18 +04:00
Alexander Shaduri 8d66596995 New .clang-tidy configuration to catch code problems. 2021-03-02 19:11:56 +04:00
Alexander Shaduri 07b6a27dc0 Fixed libintl conflicts causing compilation errors in Windows. 2021-03-02 18:25:16 +04:00
Alexander Shaduri 6e93516a4b Fixed copying .ico file in Windows. 2021-03-02 18:24:19 +04:00
Alexander Shaduri 5ce4a3aeb8 Implement toolchain support for cross-compilation and development. 2021-03-02 18:23:49 +04:00
Alexander Shaduri 2e3d8e72b6 Fixed a memory leak in utf8-to-utf16 conversion and a gcc warning. 2021-03-02 18:22:46 +04:00
Alexander Shaduri 0be08399a0 Fixed Win32 compiler errors related to paths. 2021-03-02 18:21:55 +04:00
Alexander Shaduri 0cd5202e74 Hide binary symbols by default. 2021-03-02 18:20:13 +04:00
Alexander Shaduri 1479256575 Update "JSON for Modern C++" to version 3.9.1. 2021-03-02 18:19:42 +04:00
Alexander Shaduri 306fbd503b Write debian and rpm scripts to "data" directory, not build directory. 2021-03-02 18:19:12 +04:00
Alexander Shaduri a5aff22d34 Link Win32 manifest into the gsmartcontrol binary. 2021-03-02 16:44:50 +04:00
Alexander Shaduri 3a8d75fbf0 Link Win32 manifest into the gsmartcontrol binary. 2021-03-02 16:44:23 +04:00
Alexander Shaduri 1d0762e756 Disable format-security warnings in Clang. 2021-03-02 16:43:25 +04:00
Alexander Shaduri d017f425d0 Use "example_" prefix instead of "_example" suffix for example sources and binaries. 2021-03-02 16:42:24 +04:00
Alexander Shaduri 56dec521c5 Updated Doxyfile with latest doxygen template. 2021-03-01 23:19:14 +04:00
Alexander Shaduri fdce91471e Fixed clang warning. 2021-03-01 22:45:19 +04:00
Alexander Shaduri 2986bb4893 Ported hz::scoped_ptr to std::unique_ptr and removed it. 2021-03-01 22:43:22 +04:00
Alexander Shaduri 8f82cd5c8a Removed unnecessary line in github action. 2021-03-01 22:42:49 +04:00
Alexander Shaduri 11bbbe1155 Removed TODO file. 2021-03-01 18:12:23 +04:00
Alexander Shaduri 80cc4c9515 Disable glibmm throw(...) workaround with newer glibmm. 2021-03-01 16:47:02 +04:00
Alexander Shaduri c6f506781b Make flags size_t. 2021-03-01 16:26:51 +04:00
Alexander Shaduri be22e3b999 Re-enable checkout action. 2021-03-01 16:26:34 +04:00
Alexander Shaduri 8cc7fb1e17 Disable compiler warnings unless explicitly enabled, to avoid compilation failures on older systems without specific warning flags. 2021-03-01 16:21:42 +04:00
Alexander Shaduri 28c86de4c9 Fixed compiler warning in libdebug. 2021-03-01 16:20:54 +04:00
Alexander Shaduri dac585c01b Fixed building examples. 2021-03-01 16:20:40 +04:00
Alexander Shaduri 357207c6a8 Added gettext as debian package dependency. 2021-03-01 16:20:21 +04:00
Alexander Shaduri 4e1db889c0 Disable github checkout action, it's unnecessary. 2021-03-01 16:19:59 +04:00
Alexander Shaduri 8d4f4d26f7 Added Ubuntu dependencies. 2021-03-01 15:19:59 +04:00
Alexander Shaduri 6e4766149f Fixed github action matrix. 2021-03-01 15:08:22 +04:00
Alexander Shaduri d4bc3f01bf Added github action (Ubuntu). 2021-03-01 15:04:52 +04:00
Alexander Shaduri d5785606a0 Updated homepage URLs and some copyright notices. 2021-03-01 14:53:00 +04:00
Alexander Shaduri d760a3d0f2 Map gtk log levels to libdebug log levels. 2021-03-01 14:44:30 +04:00
Alexander Shaduri b013cbd65c Updated copyright notices in .glade files. 2021-03-01 14:04:46 +04:00
Alexander Shaduri 698500fd3e Refactored the build config header and macros; Added OS- and compiler-specific options and macros to cmake. 2021-03-01 14:04:35 +04:00
Alexander Shaduri f0dfeaf8c0 Updated / added copyright headers. 2021-02-26 14:36:27 +04:00
Alexander Shaduri fed79c7de0 Updated .in files to use cmake variables. 2021-02-26 14:01:09 +04:00
Alexander Shaduri 8eaef139e9 Merge remote-tracking branch 'origin/master' 2021-02-24 17:58:02 +04:00
Alexander Shaduri c6ebf9feb1 Initial version of complete port to cmake; removed all autotools files. 2021-02-24 17:57:51 +04:00
Alexander Shaduri 9ec1e52b5a Create CNAME 2021-02-23 20:37:50 +04:00
Alexander Shaduri d0db433bc8 Added sample github pages. 2021-02-23 20:33:46 +04:00
Alexander Shaduri b7be12c7aa Removed old IDE files. 2021-02-23 20:33:28 +04:00
Alexander Shaduri 7b1217100b Updated license files and some file license headers. 2021-02-23 20:33:17 +04:00
Alexander Shaduri b24e0ef6f2 Moved files out of doc directory and updated them. 2021-02-23 20:32:40 +04:00
Alexander Shaduri dc6bd27d22 Added .gitignore, removed SVN ignore files. 2021-02-23 20:29:29 +04:00
Alexander Shaduri 0f6ff2a4cb Moved files out of gsmartcontrol directory after import from SVN. 2021-02-23 20:24:01 +04:00
Alexander Shaduri 7075a4f4d5 More work on cmake support. 2021-02-23 11:54:56 +00:00
Alexander Shaduri f4ed97d5ea Fixed a crash when system locale is set to invalid locale. 2021-01-05 12:25:21 +00:00
Alexander Shaduri 6d3a097f20 Started marking texts as translatable.
Fixed a few minor bugs.
2019-07-23 10:45:17 +00:00
Alexander Shaduri 5265ebb939 Implemented gettext integration.
Marked all window texts for translation (library texts still to go).
Switched glade files to use gtk 3.20, added copyright information.
2018-02-05 17:52:41 +00:00
Alexander Shaduri 9e783a5afc Drive settings are now serialized to config as json objects.
Removed bin2ascii_encoder.
2018-02-02 20:21:35 +00:00
Alexander Shaduri 0feb3b4aaa Data files are no longer compiled-in, but loaded at runtime.
Moved licenses and other documentation to "docs".
Simplified some GtkBuilder code.
2018-02-01 22:26:31 +00:00
Alexander Shaduri 6c624de79c Ported all filesystem code to C++17 std::filesystem.
Removed hz/fs_*.
Added new hz/fs.h and hz/fs_ns.h files with some filesystem utility functions.
Removed hz/string_wcmatch.h, it's no longer needed.
Removed hz/i18n.h, it never worked.
2018-01-31 20:17:03 +00:00
Alexander Shaduri b48bd99f70 More C++17 modernization. 2018-01-27 21:09:14 +00:00
Alexander Shaduri cbd0d94d90 Removed some autoconf checks, they're detected using macros now.
Use config.h only for CONFIG_* macros; for everything else - define them on
the command-line, or detect using feature checks.
Removed hz_config.h - moved all of its checks to respective files.
More C++17 modernization.
Split GscInfoWindow::fill_ui_with_info() into tab-specific functions.
2018-01-27 20:44:55 +00:00
Alexander Shaduri ee3adb70d4 Info window: Fixed attribute values not being rendered properly.
Fixed examples.
2018-01-15 21:16:53 +00:00
Alexander Shaduri d8af6a9af1 Got rid of intrusive_ptr. 2018-01-15 20:11:55 +00:00
Alexander Shaduri e20b4326a8 switch on type -> static map. 2018-01-15 17:28:04 +00:00
Alexander Shaduri 77e0278f93 enum -> enum class where applicable. 2018-01-15 16:55:03 +00:00
Alexander Shaduri 32623afb9b Use std::variant in StorageProperty. 2018-01-15 15:00:46 +00:00
Alexander Shaduri e83abacffd Ported to std::chrono.
Fixed lots of build warnings.
2018-01-14 21:39:55 +00:00
Alexander Shaduri 52eb101aeb GSmartControl is GPL3 only now.
Updated copyrights to 2018.
2018-01-13 20:31:43 +00:00
Alexander Shaduri 59b3a8a8e4 Don't use picojson (it has problems), use Lohmann's JSON for Modern C++. 2018-01-13 20:09:04 +00:00
Alexander Shaduri f87003b192 Removed rmn.
Added picojson.
Ported rconfig to picojson.
Ported rconfig's "/runtime" to GscStartupSettings.
2018-01-12 21:16:36 +00:00
Alexander Shaduri 89fb954223 Removed errno_string. 2018-01-05 21:30:13 +00:00
Alexander Shaduri ecea03b271 Fixed string_num.
Renamed tests to examples.
2018-01-02 19:47:15 +00:00
Alexander Shaduri f127fb9afd Further porting to C++17 (string_num, ...). 2018-01-01 22:58:42 +00:00
Alexander Shaduri c77d23be7a Moar porting. 2018-01-01 00:29:24 +00:00
Alexander Shaduri 72343e1067 Futher porting to C++17. 2017-12-31 23:09:29 +00:00
Alexander Shaduri 0902345808 Removed all thread stuff. 2017-12-31 16:56:17 +00:00
Alexander Shaduri 2ae1a561d7 Further removal of old code and porting to C++17. 2017-12-30 22:52:39 +00:00
Alexander Shaduri d4c06f61d6 Ported from hz::any_type to std::any. 2017-12-30 21:35:28 +00:00
Alexander Shaduri 02cfa33907 First round of porting to C++17 and removing old code. 2017-12-30 20:27:07 +00:00
Alexander Shaduri 6e8628b1df Fixed gsmartcontrol-root not launching if no GDK_* variables are set.
Increased version to 1.1.3.
2017-11-12 09:55:27 +00:00
Alexander Shaduri 2b19afe66d Fixed not picking up GDK_DPI_SCALE=-1 by command-line. 2017-11-11 20:49:09 +00:00
Alexander Shaduri 7236841d64 Fixed compilation under gcc 4.7. 2017-11-11 19:10:11 +00:00
Alexander Shaduri 49fb65ce71 Updated NEWS file. 2017-11-11 18:52:51 +00:00
Alexander Shaduri ad87baee70 Windows: Show volume names beside drives letters in tooltips. 2017-11-11 18:19:57 +00:00
Alexander Shaduri 5e8fef98ec Fixed compilation with gtkmm < 3.10 and gcc 4.7. 2017-11-11 11:32:19 +00:00
Alexander Shaduri 83baafa615 Force C++11 mode since gtkmm3 requires it, but fails to enable it on Centos7. 2017-11-11 10:44:49 +00:00
Alexander Shaduri 9f39db9517 Tweak default window size. 2017-10-06 10:26:43 +00:00
Alexander Shaduri 19f2bcf286 Fixed a crash when icon theme doesn't contain a specified icon. 2017-10-05 20:14:23 +00:00
Alexander Shaduri 02e8876acc Bumped version to 1.1.2. 2017-10-05 19:55:56 +00:00
Alexander Shaduri 4f78e3dd90 Removed unused function. 2017-10-04 21:10:34 +00:00
Alexander Shaduri 6888d0862d Increased iconview icon size to 64.
Increased iconview icon widths to correspond to 2 icons per row for default window size; the text
will less likely get wrapped in this case.
Changed bundled icons to size 64.
Fixed iconview icon blurriness with GDK_SCALE=2.
Use XDG-style icon names, as per GTK >= 3.10; fallback to old names and bundled icons if needed.
Removed all mention of .glade files from comments; don't use non-standard gnome names anymore.
Don't show empty "()" for drive letters in Linux.
Show "not mounted" for drive letters when no drive letters are present.
Added new "--gdk-scale" and "--gdk-dpi-scale" parameters, since pkexec discards user environment;
pass $GDK_SCALE and $GDK_DPI_SCALE to these from gsmartcontrol-root.
2017-10-04 21:09:32 +00:00
Alexander Shaduri a95be84eac Fixed make dist. 2017-09-25 15:00:50 +00:00
Alexander Shaduri b76b5f2227 Removed Help window.
Moved most of the documentation to website.
The Help menu items now open the website pages.
2017-09-25 14:58:58 +00:00
Alexander Shaduri 7a12c0880f Don't package gtkrc in Windows (it's unused).
Added French translations to desktop file.
2017-09-23 17:14:45 +00:00
Alexander Shaduri 58b0b1fab2 Windows: Changed GTK+ theme changing to use gtkmm functions.
Added some special cases to SCT parser.
2017-09-23 16:06:09 +00:00
Alexander Shaduri 16b5c322d5 Bumped version to 1.1.1.
Windows: Default to Adwaita theme for Windows 7 and Windows Server, since
"Classic" theme is broken in GTK+3 with win32 theme.
Format Statistics entry values with commas for readability.
2017-09-15 12:26:45 +00:00
Alexander Shaduri 16d5b82ac8 Fixed compilation under C++98.
Fixed smartmontools URLs.
2017-09-07 13:51:26 +00:00
Alexander Shaduri be66a8749c Bumped version to 1.1.0.
Updated NEWS file.
Clarified a message for self-test log entry count.
2017-09-07 12:43:38 +00:00
Alexander Shaduri 5192a9d447 Implemented ability to copy rows from Attribute, Statistics and Self-Test Log
tables.
2017-09-06 20:11:39 +00:00
Alexander Shaduri b9160ec173 Improved parser so that all the "-x" test data is parsed. 2017-09-05 20:53:19 +00:00
Alexander Shaduri 675fad3fc1 Documented RAID support. 2017-09-05 17:27:31 +00:00
Alexander Shaduri f7c01d6c7b Implemented "Update Drive Database" item in main window menu. 2017-09-05 16:12:19 +00:00
Alexander Shaduri 5bc6318dcd Implemented parsing of "==> Warning" in Info section. 2017-09-05 15:45:21 +00:00
Alexander Shaduri 3d8b0c94df Allow loading multiple virtual drives from one Open dialog. 2017-09-05 15:14:02 +00:00
Alexander Shaduri 73fec7fa3f Rate individual error log entries for error severity. 2017-09-05 14:53:47 +00:00
Alexander Shaduri 22971e8567 Show scan time on virtual drive icons.
Show windows drive letters if "device name under icon" is enabled.
2017-09-04 18:52:41 +00:00
Alexander Shaduri 3df4cdae56 Implemented devstat warnings. 2017-09-04 18:12:27 +00:00
Alexander Shaduri 062096a0b4 Improve GtkNotebook appearances in Windows.
Don't show Info window tabs if only one tab is present.
2017-09-04 16:57:08 +00:00
Alexander Shaduri 978e7d41b7 Added filters to file chooser dialogs.
Add .txt when saving files if it's not present (fixes a Windows bug when the
default drive name is cleared by typing something else).
2017-09-04 14:38:10 +00:00
Alexander Shaduri 33028f81d9 Fixed a few parser issues.
SCT temperature overrides all others now.
2017-09-04 13:43:40 +00:00
Alexander Shaduri 4cb12c5e0c Show temperature (from sct, devstat, or attributes) in Temperature Log tab,
including warnings.
Don't warn if SCT is unsupported.
2017-09-01 19:21:15 +00:00
Alexander Shaduri b01acfeef3 Added entry descriptions to Statistics table. 2017-09-01 17:53:09 +00:00
Alexander Shaduri b7676aaba8 Added Page,Offset column to Statistics.
Enabled multiple selection in treeviews.
Renamed ERC tab to Error Recovery.
2017-09-01 14:20:34 +00:00
Alexander Shaduri e0a13c6867 Implemented parsing of devstat section.
Implemented Statistics tab.
Increased borders in some tabs.
Some code style changes.
2017-09-01 13:42:51 +00:00
Alexander Shaduri 9f5db6d034 Visual improvements in Error Log tab. 2017-08-31 20:50:41 +00:00
Alexander Shaduri 5c3bfe8db0 Fixed not detecting the number of errors in extended error log. 2017-08-31 20:44:00 +00:00
Alexander Shaduri 5926e43bc5 Refactored Info Window tabs (again).
Implemented support for Temperature Log, ERC, Physical, Directory tabs.
Added detection of a few "not supported" messages.
Added some more --get=all output lines.
Smartctl invocation now corresponds to -x, and -x output can be loaded as
a virtual drive (parsed fully except for devstat).
2017-08-31 20:03:04 +00:00
Alexander Shaduri f21f076386 Refactored Info window UI (added tabs for various logs).
Hid annoying gcc warning.
2017-08-29 19:06:46 +00:00
Alexander Shaduri da403b28c9 Require smartmontools version 5.43 at runtime. 2017-08-29 15:13:13 +00:00
Alexander Shaduri faba9270a0 Use --format=brief attribute format by default.
Removed "Updated" column from attributes; advanced users can look at flags to
get that information.
2017-08-29 13:41:38 +00:00
Alexander Shaduri 9ca87eb296 Use -l xerror,error and -l xselftest,selftest by default.
Implemented parsing of xerror, xselftest sections.
2017-08-29 13:26:25 +00:00
Alexander Shaduri b2b97f2c9a Added more info output detection (APM feature is...).
Enable -v by default on Windows (makes debugging easier).
2017-08-29 11:47:14 +00:00
Alexander Shaduri 8494880943 Fixes in spec file.
Fixes with polkit's pkexec invocation.
2017-08-28 12:29:54 +00:00
Alexander Shaduri 0f8f38f0e1 Fixed compilation. 2017-08-28 10:12:39 +00:00
Alexander Shaduri 8544163c46 Make sure we bundle the polkit file on make dist. 2017-08-28 09:59:42 +00:00
Alexander Shaduri fdcd190592 Added --get=all information to General section.
Made General section scrollable
Changed all smartctl invocation parameters to full versions (very old smartctl
versions didn't support these, but we can drop their support from now on).
2017-08-27 20:00:43 +00:00
Alexander Shaduri 40e08796d1 Use pkexec --disable-internal-agent for polkit.
Don't warn on Unknown property "Form Factor".
2017-08-27 19:07:52 +00:00
Alexander Shaduri 1e72729056 Implemented PolKit support.
Install gsmartcontrol binary to /usr/sbin.
Removed Fedora consolehelper support from spec file (in favor of PolKit).
2017-08-27 17:33:09 +00:00
Alexander Shaduri 731122e891 Bumped version number to 1.0.3. 2017-08-26 17:23:43 +00:00
Alexander Shaduri ebb3ab6017 Removed local copy of pcrecpp, always use system-installed one (it's not a
rarity anymore).
2017-08-26 17:23:14 +00:00
Alexander Shaduri 3d2fe7fd50 Windows: Show drive letters for each device. 2017-08-26 16:47:11 +00:00
Alexander Shaduri 9a70345f4a Format large numbers according to locale (usually with commas).
Save Open/Save paths across windows and program restarts.
2017-08-26 13:18:32 +00:00
Alexander Shaduri 897a4efa96 Save / load default window size and position (both for main window, size only
for info window).
2017-08-26 12:09:51 +00:00
Alexander Shaduri 6ab53c5436 Updated site URLs to https://gsmartcontrol.sourceforge.io/ . 2017-08-18 09:33:55 +00:00
Alexander Shaduri 6b5110e0b9 Updated NEWS file. 2017-07-21 10:08:04 +00:00
Alexander Shaduri 687c0bfe08 Fixed being able to turn on AODC even if unsupported. 2017-07-20 19:15:22 +00:00
Alexander Shaduri 48b069fef4 Added missing icon dialog-information under Windows.
Don't use gtk-stock icons (they're deprecated).
2017-07-19 14:41:12 +00:00
Alexander Shaduri ab48307235 Bump version to 1.0.2.
Bundle missing icons during make-win-dist so that the sorting
indicators are displayed properly.
2017-07-19 14:09:34 +00:00
Alexander Shaduri 93c43d8612 Make sure we capture the full output of smartctl under Windows. 2017-07-19 13:53:06 +00:00
Alexander Shaduri bf9889cb0c Fixed compilation under macOS.
Fixed compilation under Fedora Rawhide.
Don't use -mtune=generic for all targets.
Don't use common compiler options by default.
2017-06-19 14:29:12 +00:00
Alexander Shaduri 6e7d67aa61 Updated news file for 1.0.0. 2017-06-16 16:55:58 +00:00
Alexander Shaduri 16f60c678b Fixed build under older gtk3. 2017-06-16 10:49:59 +00:00
Alexander Shaduri 1b8f7bd886 About dialog: Fixed mailto: links not working under Windows. 2017-06-16 10:26:21 +00:00
Alexander Shaduri 31278654a0 Fixed Help menu items not scolling to right locations. 2017-06-16 10:01:45 +00:00
Alexander Shaduri 80e87d7868 Tweaked default window sizes. 2017-06-16 09:58:13 +00:00
Alexander Shaduri e21ccb9671 Fixed NSIS installer issues. 2017-06-15 21:09:27 +00:00
Alexander Shaduri e6cdcc9ee2 Fixed win64 zip packaging. 2017-06-15 20:07:23 +00:00
Alexander Shaduri 4a579b5141 Fixed "Use system-installed smartctl" not working with newer smartmontools. 2017-06-15 19:54:11 +00:00
Alexander Shaduri dc166364de Implemented native file chooser dialogs (Windows). 2017-06-15 19:37:09 +00:00
Alexander Shaduri 4564fd2948 Disable client-side window decorations under Windows. 2017-06-15 18:16:00 +00:00
Alexander Shaduri c591823c3e Disable dpi-aware for now; it has some artifacts (titlebar, checkboxes, font
size) under 250%.
Make main window a bit larger.
2017-06-15 12:34:38 +00:00
Alexander Shaduri 7a1904c1ef Get rid of "More", make its children direct parts of the GUI. 2017-06-14 21:53:16 +00:00
Alexander Shaduri 5c5466d6b2 Fixed "More" button to show horizontal layout.
Fixed win-dist target not picking up glib-2.0 schemas and Adwaita icons.
2017-06-14 21:30:05 +00:00
Alexander Shaduri 6aaf467950 Don't require library packages in spec - they are auto-computed by OBS. 2017-05-19 21:24:39 +00:00
Alexander Shaduri 428abcb3e7 Fixed syntax error in spec file. 2017-05-19 21:13:01 +00:00
Alexander Shaduri 9dea31e3d7 Don't generate tar.gz distribution files.
Compatibility with gtk3 <= 3.8.
Updated spec file to avoid errors on Fedora.
2017-05-19 21:10:39 +00:00
Alexander Shaduri 154b609576 Removed logo from About dialog (it wasn't working).
Changed back to Windows 2000 compatibility - apparently gtk3 in cross/mingw supports XP.
Updated svn ignore flags for new autotools-generated files.
Updated debian and spec files to reflect new gtk3 requirements.
Enabled dpiAware flag for Windows - gtk3 should support it properly.
Rewrote win32/win64 packaging to pick proper files (including gtk3).
Removed nogtk distribution generation code (it doesn't make sense without gtk installer).
Changed configure-dev to support msys- and cross-based mingw (win32 and win64).
2017-05-19 20:33:43 +00:00
Alexander Shaduri 7bfb502aa0 Added msys configuration to configure-dev. 2017-05-19 16:16:05 +00:00
Alexander Shaduri ded7d3bc86 Properly expand menubar. 2017-05-18 16:42:34 +00:00
Alexander Shaduri 526c1f6a69 Make sure menubar is expanded horizontally. 2017-05-18 16:35:03 +00:00
Alexander Shaduri 6fd501d553 Fixed launching URLs in About dialog under Windows. 2017-05-18 15:57:39 +00:00
Alexander Shaduri 11aa08354e Fixed an error in process_signa.h (win32). 2017-05-18 15:44:31 +00:00
Alexander Shaduri 0bfbebeb8b Avoid unhandled exception Gtk::IconThemeError. 2017-05-18 15:35:14 +00:00
Alexander Shaduri 413ba1c1a9 Fixed autogen warnings about AR. 2017-05-18 15:34:23 +00:00
Alexander Shaduri fdec3e8151 Fixed "empty iconview" text displaying.
Disabled no-deprecation flags to avoid future incompatibilities.
Info window: Renamed "Identity" tab to "General".
2017-05-17 18:28:49 +00:00
Alexander Shaduri 0012f831a8 Fixed a crash on exit. 2017-05-17 17:35:48 +00:00
Alexander Shaduri c8962a4e67 Fix Info Identity tab to look like the gtk2 version. 2017-05-17 17:10:57 +00:00
Alexander Shaduri 74d09cf879 Initial (incomplete) port to GTK 3.4. 2017-05-17 16:49:20 +00:00
Alexander Shaduri afdb516386 Updated copyright years. 2017-05-11 08:42:23 +00:00
Alexander Shaduri 9a1f28fe9a Fixed some win32 installer issues. 2017-05-10 21:26:56 +00:00
Alexander Shaduri b4583a7cc6 Bumped version to 0.9.0. 2017-05-10 20:08:20 +00:00
Alexander Shaduri 9918b13214 Updated drive descriptions to drivedb.h r4430, 2017-05-03.
Fixed selective self-test section parsing (if it's unsupported).
2017-05-10 20:06:44 +00:00
Alexander Shaduri 3f9d830294 Added appdata metainfo file. 2017-05-08 17:54:25 +00:00
Alexander Shaduri 7b2627b236 Clear the drives and show "please rescan" message after the preferences are
updated; this ensures that no old settings are used.
2017-05-08 17:16:27 +00:00
Alexander Shaduri c40d87b3ae Require gtk2 2.6.0 until we move to 2.24.0.
Win32 drive detection: stop scanning only after 3 not-found drives, so that
we detect drives after old removed drives.
2017-05-08 16:47:52 +00:00
Alexander Shaduri 99f707b6c6 Require gtk2 2.24.0, for future compatibility with gtk3. 2017-05-08 10:51:27 +00:00
Alexander Shaduri a561d5fef6 Changed the license field in spec file to conform to OBS requirements. 2016-06-04 16:14:12 +00:00
Alexander Shaduri 1d305e7626 Fixed time formatting with VS. 2015-07-01 12:10:23 +00:00
Alexander Shaduri 194fb51f75 Disable dpiAware flag in win32 manifest since it's not supported that well. 2014-05-29 18:00:49 +00:00
Alexander Shaduri e2dc39bff2 Don't show the info window if there's nothing to show. 2014-05-05 10:37:24 +00:00
Alexander Shaduri 836aa73430 Avoid scientific notation when displaying the drive size. 2014-05-05 10:16:38 +00:00
Alexander Shaduri 63f5b885a3 Fixed glib 2.32 warnings. 2014-05-05 09:36:10 +00:00
Alexander Shaduri c68d017475 Updated to latest libhz. 2014-05-05 09:20:18 +00:00
Alexander Shaduri bbe3bac923 Make sure we write some data from the Info window on Save Output if only basic
data is available.
Fixed a harmless "Number of written bytes doesn't match the data size" warning.
Added support for SSD-only and HDD-only vendor attributes.
Added the latest (r3897 / 2014-04-28) attributes from smartmontools.
Increased the Info window size a bit.
2014-05-05 08:59:13 +00:00
Alexander Shaduri 2293e357f4 Increased main window size a bit to avoid the iconview shift down each time an
icon is selected.
Added some scsi-output properties to full parser to avoid console warnings.
Devices having only basic info can be displayed now in the info window.
2014-04-30 10:38:48 +00:00
Alexander Shaduri 85dbceb14d Fixed a crash at scan time (bad parsing of empty smartctl output sections).
Updated program descriptions to include SSD.
2014-04-16 20:04:04 +00:00
Alexander Shaduri 45cba39be7 RAID volumes which report having SMART are now detected and explicitly set to
not having SMART.
2013-10-17 10:26:53 +00:00
Alexander Shaduri a0b235dd8a Increased timeouts when executing commands before the "Cancel" dialog is
shown; this helps with constant focus stealing from other windows when
smartctl is too slow (usually under Windows).
2013-02-25 20:27:18 +00:00
Alexander Shaduri 7e3db9ec30 Implemented detection for some new "not supported" smartctl messages. 2013-02-24 20:07:51 +00:00
Alexander Shaduri 6cc8770599 Implemented Linux support for Areca controllers with enclosures (untested).
Implemented Windows support for Areca controllers (thanks to Richard Kagerer);
untested so far.
2013-02-24 20:02:30 +00:00
Alexander Shaduri 462d465f3a Modified all glade files to use gtk 2.8 compatibility (not sure if it works).
Removed "tooltip_text" properties from all glade files, "tooltip" should be
enough.
Set the "activates_default" property on all relevant entries in glade files;
this will make the Enter key activate the default dialog action when these
entries are focused.
Added some clarifying text to Add Device dialog.
Clarified the per-drive parameters section (what it does) in Preferences.
Added a confirmation dialog in case the user doesn't set the Parameters field
in one of the Per-Drive Parameters entries.
Added a "Smartctl Options" section to README/Help.
Clarified the difference between smartctl.exe and smartctl-nc.exe in a
tooltip.
Improved some other tooltips.
2013-02-11 11:09:00 +00:00
Alexander Shaduri 6ac62cd0de Device detection is a lot more verbose now.
The read /proc files are now cached to avoid needless re-reading.
Some other minor changes.
2013-02-10 20:55:58 +00:00
Alexander Shaduri 1174b62b8f Bumped version number to 0.8.8. 2012-12-23 19:27:47 +00:00
Alexander Shaduri ef713900a0 Implemented support for HP controllers behind cciss and hpsa/hpahcisr drivers. 2012-12-23 19:25:20 +00:00
Alexander Shaduri c60f6815fa Fixed BDRW drive detection (it was detected as a HDD).
Added support for recent smartctl -i changes.
2012-09-28 08:52:10 +00:00
Alexander Shaduri 7ca709fcbb Fixed a comment. 2012-08-11 14:24:58 +00:00
Alexander Shaduri c3ce878376 Don't require libglademm in debian control file, it confuses newer Ubuntus. 2012-08-11 14:19:58 +00:00
Alexander Shaduri a06ac42eff Don't limit Fedora versions. 2012-08-11 13:30:55 +00:00
Alexander Shaduri 444eb6c211 Fixed spec file problems with Fedora.
Updated NEWS file.
2012-08-11 11:43:39 +00:00
Alexander Shaduri eb6cbe1ee0 Fixed make dist error. 2012-08-10 16:47:11 +00:00
Alexander Shaduri bcae9a2c37 Increased application version to 0.8.7.
Added Fedora consolehelper support to the spec file.
2012-08-10 16:33:29 +00:00
Alexander Shaduri d411b34dae Updated smartctl attributes from r3515 to r3587.
Added warnings for SSD lifetime attributes.
2012-08-10 15:49:28 +00:00
Alexander Shaduri a0fad4375a Added options to show device name and serial number under drive icons.
Added serial number to drive icon tooltip.
Fixed compiler error introduced in previous revision.
Removed some useless tooltips from UI.
2012-08-10 09:44:06 +00:00
Alexander Shaduri ffb02984fe Documented the rest of the code (rconfig, rmn, libdebug).
Fixed up the doxygen documentation, should be in usable state now.
2012-08-08 17:33:26 +00:00
Alexander Shaduri b400df2565 Completely documented hz, gsc and applib.
Fixed some compiler warnings.
Removed some unused files.
Added hz/initialized.h as part of hz.
2012-08-05 20:18:22 +00:00
Alexander Shaduri b06607cc37 Added a missing #include statement that caused build errors on SLES SP2.
Updated .spec and .desktop file to fix some warnings.
2012-04-28 15:17:44 +00:00
Alexander Shaduri 8881f42470 Fixed the detection of 3ware 9750 (twl) devices.
Implemented support for systems with several different 3ware controllers
(twa/twe/twl).
2012-03-12 20:06:33 +00:00
Alexander Shaduri 6558d31680 Support Areca RAID controller detection under Linux (untested).
Support 3ware 3w-sas-supported RAID controller detection under Linux (untested).
2012-03-03 18:03:15 +00:00
Alexander Shaduri 6e949677ec Don't open \\.\PhysicalDriveN needlessly if it was filtered out by --scan-open. 2012-02-26 19:19:34 +00:00
Alexander Shaduri 72f2d166b6 Updated the man page to reflect the new gsmartcontrol-root syntax.
The previous commit also contained the following changes:
The gsmartcontrol-root wrapper script now properly escapes the arguments
before passing them to gsmartcontrol.
gsmartcontrol-root has a new argument "--desktop=..." which replaces the old
positional argument; compatibility with the old invokation syntax has been
retained.
2012-02-19 15:09:26 +00:00
Alexander Shaduri 7b13cdf7b3 GSmartControl now prints an error message and a help text if an invalid
command-line options was specified.
2012-02-19 15:04:47 +00:00
Alexander Shaduri c7bdaad30a Fixed invalid parsing of tw_cli output which caused non-detection of drives
and controllers with controller or port numbers greater than 9 (3ware linux,
windows).
The same-brand controllers with identical SCSI host numbers are collapsed into
one controller now (the others are for LUNs and only pollute the drive list).
The drives are sorted during detection, not when adding them to the GUI.
The drive sorting algorithm has been slightly changed.
2012-02-19 13:10:05 +00:00
Alexander Shaduri fd9fce25fc Implemented support for Adaptec RAID 5805 controller and possibly other
Adaptec models as well.
2012-02-19 10:28:52 +00:00
Alexander Shaduri 5ba7add5b5 Fixed a few VS /analyze warnings in win32_tools.h. 2012-01-16 16:28:52 +00:00
Alexander Shaduri 68889d3804 Updated copyright headers for year 2012.
Updated the command line option descriptions in the man page and README.txt.
2012-01-11 17:26:34 +00:00
Alexander Shaduri 8ab18d433a The manifest now indicates that GSmartControl is dpi-aware (no more blurring
in high-dpi situations under Windows).
2012-01-09 16:52:29 +00:00
Alexander Shaduri 13d83949c4 Fix possibly invalid utf-8 data before showing it to the user (GscTextWindow,
GscExecutorLogWindow).
2011-12-15 16:58:06 +00:00
Alexander Shaduri daf98009d4 Added description for Multi_Zone_Error_Rate. 2011-12-15 15:57:58 +00:00
Alexander Shaduri 0cf5848772 Merged FreeBSD patches (fix in gsmartcontrol-root, /dev/ada* detection. 2011-11-19 18:08:58 +00:00
Alexander Shaduri 0ecc4bd8d3 Fixed compilation under Glib 2.31.x. 2011-11-02 16:00:39 +00:00
Alexander Shaduri 388a195794 Fixed compilation error.
Fixed parsing 'smartctl -v 194,raw8 -a' output (the attribute line).
2011-10-15 17:56:55 +00:00
Alexander Shaduri 0f89010225 Documented some more of hz. 2011-08-17 20:15:58 +00:00
Alexander Shaduri 42da49c5c1 Documented parts of hz library using doxygen tags. 2011-08-16 20:05:39 +00:00
Alexander Shaduri 0ffba26b1f Added (untested) Doxyfile.
Documented a few more hz files.
Added clang detection to the build system, use it when setting flags, etc...
Added some clang-specific flags to avoid excessive and unneeded warnings.
Fixed compilation under clang.
Fixed some clang-reported warnings.
2011-08-15 20:08:11 +00:00
Alexander Shaduri b19b094aaa Fixed a bug that issued SIGTERM to the child process instead of SIGKILL.
Documented applib completely.
Some minor member visibility adjustments.
2011-07-30 19:57:28 +00:00
Alexander Shaduri 5cc1e898b9 Use model name as well when detecting S/N duplicates. 2011-07-30 16:16:21 +00:00
Alexander Shaduri a4aa68a085 Very minor documentation changes.
NSIS: Don't strip update-smart-database.exe (it breaks if stripped) and
smartctl* (no reason to do it).
NSIS: Delete gtk installer on uninstall, sometimes it's not deleted during
installation.
2011-06-20 20:59:36 +00:00
Alexander Shaduri c954101bd9 Updated attribute database to smartmontools 5.41. 2011-06-11 17:27:28 +00:00
Alexander Shaduri d20aeb4121 Updated attribute DB.
Support older smartctl when filtering out 3ware sd* devices.
2011-06-07 17:08:57 +00:00
Alexander Shaduri 9440de5ca9 Updated some docs.
Proper filtering of /dev/sd* devices with older smartctl and 3ware.
Added missing file to Makefile.am.
2011-06-01 07:44:43 +00:00
Alexander Shaduri c2955b508c Fixed compilation under non-Linux/Windows platforms. 2011-05-28 12:49:56 +00:00
Alexander Shaduri fbf70814f0 Fixed make dist. 2011-05-28 12:22:54 +00:00
Alexander Shaduri a823790926 Updated NEWS file. 2011-05-28 12:18:05 +00:00
Alexander Shaduri 14838b82ae Updated readme. 2011-05-28 10:11:21 +00:00
Alexander Shaduri e11347c005 Support brief format of attributes, parse them to populate known columns. 2011-05-11 09:22:43 +00:00
Alexander Shaduri 98842f238e Windows: SUpport tw_cli/cx/px variant of smartctl device if --scan-open fails
and tw_cli is installed.
2011-05-01 14:41:58 +00:00
Alexander Shaduri 5ffc87ad9b Set tooltips wherever we have "No description available". 2011-05-01 13:03:36 +00:00
Alexander Shaduri fb5d139443 The detection now executes smartctl on the drives directly.
Don't execute smartctl --info if it was already executed during drive detection.
Made number of scanned ports configurable.
2011-05-01 12:16:26 +00:00
Alexander Shaduri 9d6ee05660 Add debian/ubuntu's su-to-root support to gsmartcontrol-root. 2011-04-30 18:41:36 +00:00
Alexander Shaduri 1ee97606aa Confirm operations (quit, rescan) when tests are running, don't just deny them. 2011-04-28 18:42:03 +00:00
Alexander Shaduri b6f721c167 Detect scsi number for 3ware and use that for tw_cli controller (Linux). 2011-04-20 12:23:54 +00:00
Alexander Shaduri ede4933819 Display device type argument along with device name everywhere. 2011-04-20 10:38:41 +00:00
Alexander Shaduri 70ce4a6d06 Fixed detecting usb flash drive names under winxp (smartctl would return a cli
parse error, which is incorrect).
Fixed parsing smartctl --scan-open output under windows.
2011-04-20 10:19:20 +00:00
Alexander Shaduri 213c26db3f Don't add sd* device if it's 3ware controller.
Properly add devices detected through 3ware scan (linux).
Limit smartctl sequential scans to 24 drives (it takes too long without it).
2011-04-19 17:59:44 +00:00
Alexander Shaduri 8ae3c42100 Added tooltips to both the labels and the entries in Add Device and Preferences
dialogs.
Changed the tooltips to avoid showing unsupported values for that OS.
Fixed usb drive re-detection with scsi (regression from previous commit).
Fixed invalid regexps in tw_cli output parsing (fixes 3ware in windows).
Added support for "Product" field of USB drives (used instead of Device in
newer smartctl).
2011-04-18 12:14:20 +00:00
Alexander Shaduri ff466a1d2d Add a note that we probably support Intel Matrix controllers as well. 2011-04-17 20:55:50 +00:00
Alexander Shaduri 5e46ed7cb6 Added support for devices detected by "smartctl --scan-open" under win32 (this
includes 3ware).
2011-04-17 20:36:54 +00:00
Alexander Shaduri c197ba76fa Support detecting drives behind 3ware controllers.
Add ExecutorFactory - now detectors can create their own gui or non-gui
executors, depending on who called them.
2011-04-17 18:47:43 +00:00
Alexander Shaduri fa2b10f3ce Show drive WWN and sector size. 2011-04-17 09:28:59 +00:00
Alexander Shaduri 7b523aa075 Updated to latest drivedb.h.
Made the type entry in Add Device window an editable combo, added sample types.
2011-04-16 20:38:39 +00:00
Alexander Shaduri 0ca9971460 Some more UI tweaks.
A new "Add Device" dialog - allows specifying type and additional smartctl
parameters.
Drive properties in preferences - allow specifying device type.
2011-04-16 19:25:06 +00:00
Alexander Shaduri b3f23abec0 Made the user interface more GNOME HIG-compliant. 2011-04-16 11:29:46 +00:00
Alexander Shaduri a2d735fee5 Added support for specifying -d option and extra parameters via command line
and preferences dialog. StorageDevice will use the specified type and
arguments when executing smartctl. This change effectively adds support for
multiple drives behind a single device name.
The preferences dialog can distinguish between various device types now (when
supplying smartctl arguments).
2011-04-04 20:02:41 +00:00
Alexander Shaduri fb801d8ebb Documented, reorganized StorageDevice source code.
Added "type argument" and "extra arguments" fields to StorageDevice.
2011-04-04 18:22:18 +00:00
Alexander Shaduri 9a92bfec45 Renamed "type" field (and all related stuff) of StorageDevice to detected_type. 2011-04-04 16:46:28 +00:00
Alexander Shaduri 6d50abb3cf Detect one more "smart unsupported" string in the latest version of smartctl
output.
Add a hint about "pd0" for Windows version in Preferences dialog.
2011-04-04 16:26:10 +00:00
Alexander Shaduri 778872363a New and improved attribute database (including SSD attributes).
Attributes are now matched according to smartctl names, and only then by ids.
Attribute notices are set by their generic names, not ids.
Improved displaying of attributes when they're unknown to us but known to
smartctl.
Set descriptions on all known capabilities.
Disabled tooltips on self-test log and error log entries (they always showed
"description unavailable" anyway).
2011-03-12 21:06:15 +00:00
Alexander Shaduri 6c404d57c9 Use -include only when using pch.
Document OptionalValue.
Use spaces when formatting date/time.
Capitalize some property names for consistency.
2011-03-09 11:26:52 +00:00
Alexander Shaduri 449b645278 Split storage detector to per-platform files. 2011-03-06 21:12:18 +00:00
Alexander Shaduri 02428a26c0 Show Error Log and Self-Test Log support.
Support attributes with undefined values like "---".
2011-03-06 20:31:39 +00:00
Alexander Shaduri 90bbc19923 Fixed inability to parse some error types in error log. 2011-03-06 19:04:13 +00:00
Alexander Shaduri 4f5690c89b Added ability to show smartctl output for devices whose info could not be
parsed fully.
2011-03-06 18:06:14 +00:00
Alexander Shaduri 4000fa1a2e Added the ability to configure default smartctl info save filename through
config file.
Use model-serial-date.txt for default save filename.
2011-03-06 17:15:56 +00:00
Alexander Shaduri ba7ffafa7f Updated copyrights to 2011.
Adjust Makefile.am for dist-files.
Added configure-dev script for easy developer-build configuration.
2011-03-06 10:43:38 +00:00
Alexander Shaduri 33b59d5723 Updated copyrights to 2010.
Reimplement locale stuff in hz (adding different controls for C and C++
locales), also take the recent locale-related changes in gtkmm into account.
Cleanups in snprintf-related code, portable_snprintf().
Added doxygen-style comments to some hz headers.
Better console redirection handling for win32.
Blacklisted linux device mapper devices (annoying in LVM setups).
Added beesu support and generally improved gsmartcontrol-root script (this is
needed for Fedora 14 which doesn't have any old supported su mechanisms).
Added "menu" dependency for deb packages.
Added kdev4 project.
2010-12-26 20:35:24 +00:00
Alexander Shaduri 28551a9666 Note: This revision was used to build 0.8.5-4 Windows package.
Set C++ locale as well, when setting C locale.
Improved windows installer.
2010-12-26 20:12:08 +00:00
Alexander Shaduri c5478d6a0e Note:This revision was used to build 0.8.5-3 Windows package.
Previous test result is cleared in GUI when running new tests now.
Windows: Vastly improved installer, supports built-in GTK+ now.
Windows: A proper method of privilege escalation is used for Vista/7.
Windows: GSmartControl works on Windows 7 now.
Updated copyright for files with Whatever License to use Unlicense.
2010-12-26 20:07:02 +00:00
620 changed files with 116210 additions and 53877 deletions
+109
View File
@@ -0,0 +1,109 @@
---
# Exceptions:
# bugprone-branch-clone is too noisy in parsing code.
# bugprone-easily-swappable-parameters is too noisy.
# cert-dcl50-cpp is triggered by hz::string_sprintf()'s C style.
# clang-analyzer-deadcode.DeadStores is too noisy.
# clang-analyzer-cplusplus.NewDeleteLeaks doesn't understand Gtkmm memory management.
# cppcoreguidelines-avoid-magic-numbers, readability-magic-numbers is triggered by attribute database.
# cppcoreguidelines-avoid-do-while is triggered in DBG macros.
# cppcoreguidelines-owning-memory doesn't support deleting Gtkmm objects.
# cppcoreguidelines-pro-type-cstyle-cast needed by GTK C casts.
# cppcoreguidelines-pro-type-reinterpret-cast is needed by WinAPI-facing functions
# cppcoreguidelines-pro-type-vararg is triggered by hz::string_sprintf().
# cppcoreguidelines-pro-bounds-array-to-pointer-decay is triggered by va_start in hz::string_sprintf().
# cppcoreguidelines-pro-bounds-pointer-arithmetic is useless (triggered by argv) until we have std::span.
# misc-include-cleaner does not really work.
# misc-no-recursion is too noisy.
# modernize-raw-string-literal is very noisy.
# modernize-use-trailing-return-type is contrary to our style.
# performance-enum-size is too noisy.
# readability-avoid-unconditional-preprocessor-if is triggered on platform-specific code
# readability-convert-member-functions-to-static is triggered for many callbacks.
# readability-function-cognitive-complexity needed by UI constructors.
# readability-isolate-declaration is noisy.
# readability-identifier-length is too noisy.
Checks: >
-abseil-*,
-altera-*,
-android-*,
-boost-*,
bugprone-*,
-bugprone-branch-clone,
-bugprone-easily-swappable-parameters,
cert-*,
-cert-dcl50-cpp,
clang-analyzer-*,
-clang-analyzer-deadcode.DeadStores,
-clang-analyzer-cplusplus.NewDeleteLeaks,
concurrency-*,
cppcoreguidelines-*,
-cppcoreguidelines-avoid-magic-numbers,
-cppcoreguidelines-avoid-do-while,
-cppcoreguidelines-owning-memory,
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
-cppcoreguidelines-pro-type-cstyle-cast,
-cppcoreguidelines-pro-type-reinterpret-cast,
-cppcoreguidelines-pro-type-vararg,
-cppcoreguidelines-pro-bounds-pointer-arithmetic,
-darwin-*,
-fuchsia-*,
google-*
hicpp-*,
-linuxkernel-*,
-llvm-*,
-llvmlibc-*,
misc-*,
-misc-include-cleaner,
-misc-no-recursion,
modernize-*,
-modernize-use-trailing-return-type,
-modernize-raw-string-literal,
-mpi-*,
-objc-*,
openmp-*,
performance-*,
-performance-enum-size,
portability-*,
readability-*,
-readability-avoid-unconditional-preprocessor-if,
-readability-convert-member-functions-to-static,
-readability-function-cognitive-complexity,
-readability-isolate-declaration,
-readability-magic-numbers,
-readability-identifier-length,
-zircon-*
WarningsAsErrors: ''
HeaderFilterRegex: ''
FormatStyle: none
CheckOptions:
- key: bugprone-exception-escape.CheckCapsOnly
value: '1'
- key: cppcoreguidelines-macro-usage.CheckCapsOnly
value: '1'
- key: cppcoreguidelines-owning-memory.LegacyResourceConsumers
value: '::free;::realloc;::freopen;::fclose;Gtk::manage'
- key: misc-assert-side-effect.AssertMacros
value: assert,DBG_ASSERT
- key: misc-assert-side-effect.CheckFunctionCalls
value: '0'
- key: misc-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic
value: '1'
- key: misc-include-cleaner.IgnoreHeaders
value: 'libdebug/*;local_glibmm.h;glib/*;gtk/*;gtkmm/*;glibmm/*'
- key: performance-unnecessary-value-param.AllowedTypes
value: 'RefPtr;Ptr$'
- key: readability-braces-around-statements.ShortStatementLines
value: '2'
- key: readability-implicit-bool-conversion.AllowPointerConditions
value: '1'
- key: readability-implicit-bool-cast.AllowConditionalPointerCasts
value: '1'
...
+3
View File
@@ -0,0 +1,3 @@
# Make sure github recognizes header files as C++, not C.
*.h linguist-language=C++
+28
View File
@@ -0,0 +1,28 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug, enhancement
assignees: ashaduri
---
**Version and Environment**
- GSmartControl version: [Are you using the latest released version or git?]
- OS: [e.g. openSUSE Linux 15.5]
**Describe the Bug**
[A clear and concise description of what the bug is].
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Screenshots**
[If applicable, add screenshots to help explain your problem].
**Additional Context**
[Add any other context about the problem here (GTK+ version, etc.)]
+24
View File
@@ -0,0 +1,24 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ashaduri
---
**Version and Environment**
- GSmartControl version: [Are you using the latest released version or git?]
- OS: [e.g. openSUSE Linux 15.5]
**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.
+15
View File
@@ -0,0 +1,15 @@
---
name: Other issue
about: Issues other than bugs and enhancements
title: ''
labels: ''
assignees: ashaduri
---
**Version and Environment**
- GSmartControl version: [Are you using the latest released version or git?]
- OS: [e.g. openSUSE Linux 15.5]
**Describe the Issue**
[A clear and concise description of what the issue is].
+124
View File
@@ -0,0 +1,124 @@
# GSmartControl – Copilot Instructions
GSmartControl is a C++20 GTK3/Gtkmm GUI for inspecting hard-drive and SSD health via SMART data
(wrapping `smartctl` from smartmontools). It supports Linux, Windows (MSYS2/MinGW), macOS, and BSDs.
## Build
```bash
mkdir build && cd build
# Standard Linux build (uses dev toolchain with warnings enabled)
cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_TOOLCHAIN_FILE=../toolchains/linux-dev.cmake
# Windows (MSYS2/MinGW64)
cmake .. -G "MSYS Makefiles" \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_TOOLCHAIN_FILE=../toolchains/win64-mingw-msys2.cmake
# Build on MSYS2/MinGW64 (from build dir)
cmake --build . --target all -j 18
```
The `configure-dev` script is a convenience wrapper: `./configure-dev -t <toolchain> -c <compiler> -b <build_type>`.
Key CMake options:
- `-DAPP_BUILD_TESTS=ON` – enable test targets
- `-DAPP_BUILD_EXAMPLES=ON` – enable example targets
- `-DAPP_COMPILER_ENABLE_WARNINGS=ON` – strict compiler warnings (set automatically by `linux-dev.cmake`)
## Tests
Tests use **Catch2** (vendored in `dependencies/catch2/`). They are only built when `-DAPP_BUILD_TESTS=ON` is passed.
```bash
# Build and run all tests
cmake .. -DAPP_BUILD_TESTS=ON
cmake --build .
ctest -C RelWithDebInfo --rerun-failed --output-on-failure
# Run a single test executable directly (from build dir)
./test_all "[smartctl_parser]" # Catch2 tag filter
./test_all "test name substring" # substring match
```
Test sources live in `src/applib/tests/` and `src/hz/tests/`; they are linked into `src/test_all/`.
## Linting
Clang-tidy config is at `.clang-tidy` in the repo root. Run it via CMake or directly:
```bash
clang-tidy src/applib/storage_device.cpp -- -std=c++20 $(pkg-config --cflags gtkmm-3.0)
```
## Architecture
The codebase is split into libraries and one GUI executable:
| Component | Location | Purpose |
|---|---|---|
| `applib` | `src/applib/` | Core logic: SMART parsing, device detection, command execution |
| `hz` | `src/hz/` | General-purpose C++ utilities (strings, filesystem, error types) |
| `rconfig` | `src/rconfig/` | Runtime config load/save with auto-save support |
| `libdebug` | `src/libdebug/` | Debug logging with named channels |
| `gui` | `src/gui/` | GTK/Gtkmm UI (windows, dialogs, Glade `.ui` files) |
### Parsing pipeline
`smartctl` output is parsed through a strategy pattern:
- JSON parsers (`smartctl_json_ata_parser`, `smartctl_json_nvme_parser`, `smartctl_json_basic_parser`) target smartctl ≥ 7.3.
- Text parsers (`smartctl_text_ata_parser`, `smartctl_text_basic_parser`) handle legacy output.
- Parsed results are stored as `StorageProperty` objects in a `StoragePropertyRepository` on `StorageDevice`.
### Device detection
`StorageDetector` is an abstract interface; platform implementations are:
- `storage_detector_linux.cpp` – scans `/dev/sd*`, `/dev/nvme*`, etc.
- `storage_detector_win32.cpp` – WMI/registry enumeration
- `storage_detector_other.cpp` – generic `/dev` scanning (BSD/macOS)
### Async execution
`AsyncCommandExecutor` wraps `CommandExecutor` (which shells out to `smartctl`) in a background thread.
Completion is signalled via **libsigc++** signals back to the GTK main loop. Never call GTK APIs from the worker thread;
queue them through signals or `Glib::signal_idle()`.
### Error handling
Use `hz::ExpectedValue<T, E>` (wrapping `tl::expected`) for recoverable errors instead of exceptions.
Enum-based error types (`StorageDeviceError`, `SmartctlParserError`) are preferred over string errors.
## Key Conventions
**Naming:**
- Classes: `PascalCase` (e.g., `StorageDevice`, `SmartctlParser`)
- Methods and members: `snake_case`; private/member fields have a trailing `_` (e.g., `device_list_`)
- GUI classes in `src/gui/` are prefixed `Gsc` (e.g., `GscMainWindow`)
- Filenames: `snake_case.cpp` / `snake_case.h`
**Headers:**
- Use `#ifndef FILENAME_H` / `#define FILENAME_H` guards (not `#pragma once`)
- Include order: standard library → third-party (GTK/Gtkmm) → project headers
- All project headers are included relative to `src/` (the include root)
**Modern C++20/23 patterns used throughout:**
- `std::optional<T>` for nullable values
- `hz::ExpectedValue<T, E>` for error-returning functions
- `std::string_view` for non-owning string parameters
- `fmt::format()` (vendored `fmt` library) for string formatting
- Smart pointers exclusively; no raw owning pointers
**Vendored dependencies** are in `dependencies/` and added via `add_subdirectory`.
Do not modify them; prefer upgrading the whole vendored copy.
**Translations:** UI strings are wrapped with `_()` (gettext). `.po` files live in `po/`.
Translations are not yet supported.
**Platform guards:** Use `#ifdef CONFIG_KERNEL_FAMILY_WINDOWS`,
`#ifdef CONFIG_KERNEL_LINUX`, etc.
## Agentic Development
Place all plans and temporary files in `agent_workspace/`. This directory is ignored by Git.
+128
View File
@@ -0,0 +1,128 @@
name: Build AppImage
on:
# Triggers the workflow on push or pull request events but only for the main branch
push:
branches: [ main ]
pull_request:
branches: [ main ]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
env:
BUILD_TYPE: RelWithDebInfo
jobs:
build-appimage:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Update Package Database
run: sudo apt-get update
- name: Install Dependencies
run: sudo apt-get install libgtkmm-3.0-dev gettext wget file libfuse2
- name: Download linuxdeploy
# Note: Using 'continuous' release for latest version. For reproducible builds,
# pin to a specific release tag and verify SHA256 checksum.
run: |
wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
chmod +x linuxdeploy-x86_64.AppImage
sudo mv linuxdeploy-x86_64.AppImage /usr/local/bin/linuxdeploy
- name: Download appimagetool
# Note: Using 'continuous' release for latest version. For reproducible builds,
# pin to a specific release tag and verify SHA256 checksum.
run: |
wget https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
chmod +x appimagetool-x86_64.AppImage
sudo mv appimagetool-x86_64.AppImage /usr/local/bin/appimagetool
- name: Create Build Directory
run: cmake -E make_directory build-appimage
- name: Configure CMake for AppImage
shell: bash
working-directory: ${{github.workspace}}/build-appimage
env:
CC: gcc-11
CXX: g++-11
run: >
cmake $GITHUB_WORKSPACE
-DCMAKE_BUILD_TYPE=$BUILD_TYPE
-DCMAKE_INSTALL_PREFIX=/usr
-DAPP_BUILD_APPIMAGE=ON
-DCMAKE_TOOLCHAIN_FILE="$GITHUB_WORKSPACE/toolchains/linux-dev.cmake"
- name: Build
shell: bash
working-directory: ${{github.workspace}}/build-appimage
run: cmake --build . --config $BUILD_TYPE -j$(nproc)
- name: Install to AppDir
shell: bash
working-directory: ${{github.workspace}}/build-appimage
run: DESTDIR=${{github.workspace}}/AppDir cmake --install .
- name: Setup AppDir structure
shell: bash
working-directory: ${{github.workspace}}
run: |
# Copy desktop file and icon to AppDir root
cp AppDir/usr/share/applications/dev.shaduri.gsmartcontrol.desktop AppDir/
cp AppDir/usr/share/icons/hicolor/256x256/apps/gsmartcontrol.png AppDir/
# Create AppRun script
cat > AppDir/AppRun << 'EOF'
#!/bin/bash
SELF=$(readlink -f "$0")
HERE=${SELF%/*}
export LD_LIBRARY_PATH="$HERE/usr/lib:${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
export PATH="$HERE/usr/bin:${PATH:+:$PATH}"
export GSETTINGS_SCHEMA_DIR="$HERE/usr/share/glib-2.0/schemas:${GSETTINGS_SCHEMA_DIR:+:$GSETTINGS_SCHEMA_DIR}"
export GDK_PIXBUF_MODULEDIR="$HERE/usr/lib/gdk-pixbuf-2.0/2.10.0/loaders"
export GDK_PIXBUF_MODULE_FILE="$HERE/usr/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache"
exec "$HERE/usr/bin/gsmartcontrol" "$@"
EOF
chmod +x AppDir/AppRun
- name: Bundle dependencies with linuxdeploy
shell: bash
working-directory: ${{github.workspace}}
run: |
linuxdeploy --appdir AppDir \
--executable AppDir/usr/bin/gsmartcontrol \
--desktop-file AppDir/dev.shaduri.gsmartcontrol.desktop \
--icon-file AppDir/gsmartcontrol.png
- name: Update GDK pixbuf cache
shell: bash
working-directory: ${{github.workspace}}
continue-on-error: true
run: |
if [ -d "AppDir/usr/lib/gdk-pixbuf-2.0" ]; then
gdk-pixbuf-query-loaders > AppDir/usr/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache || true
fi
- name: Get version
id: version
shell: bash
run: |
VERSION=$(sed -n 's/.*CMAKE_PROJECT_VERSION[[:space:]]*"\([^"]*\)".*/\1/p' version.txt)
echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
echo "Version: $VERSION"
- name: Create AppImage
shell: bash
working-directory: ${{github.workspace}}
run: |
ARCH=x86_64 appimagetool AppDir GSmartControl-${{ steps.version.outputs.VERSION }}-x86_64.AppImage
- name: Upload AppImage artifact
uses: actions/upload-artifact@v4
with:
name: GSmartControl AppImage
path: ${{github.workspace}}/GSmartControl-*-x86_64.AppImage
+249
View File
@@ -0,0 +1,249 @@
name: Build (Tier 1 platforms)
on:
# Triggers the workflow on push or pull request events but only for the main branch
push:
branches: [ main ]
pull_request:
branches: [ main ]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: RelWithDebInfo
SMARTMONTOOLS_INSTALLER: smartmontools-7.4-1.win32-setup.exe
SMARTMONTOOLS_URL: https://downloads.sourceforge.net/project/smartmontools/smartmontools/7.4/smartmontools-7.4-1.win32-setup.exe
jobs:
linux-ubuntu-24_04:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Update Package Database
run: sudo apt-get update
- name: Install Dependencies
run: sudo apt-get install libgtkmm-3.0-dev gettext
- name: Create Build Directory
run: cmake -E make_directory build
- name: Configure CMake
shell: bash
working-directory: ${{github.workspace}}/build
env:
CC: gcc-14
CXX: g++-14
run: >
cmake $GITHUB_WORKSPACE
-DCMAKE_BUILD_TYPE=$BUILD_TYPE
-DCMAKE_TOOLCHAIN_FILE="$GITHUB_WORKSPACE/toolchains/linux-dev.cmake"
- name: Build
shell: bash
working-directory: ${{github.workspace}}/build
run: cmake --build . --config $BUILD_TYPE
- name: Test
working-directory: ${{github.workspace}}/build
shell: bash
run: ctest -C $BUILD_TYPE --rerun-failed --output-on-failure
- name: Pack (cmake install and make binary package)
shell: bash
working-directory: ${{github.workspace}}/build
run: cpack -G TBZ2
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: Linux Packages
path: ${{github.workspace}}/build/gsmartcontrol-*-Linux*.*
linux-ubuntu-22_04:
# GCC 11
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Update Package Database
run: sudo apt-get update
- name: Install Dependencies
run: sudo apt-get install libgtkmm-3.0-dev gettext
- name: Create Build Directory
run: cmake -E make_directory build
- name: Configure CMake
shell: bash
working-directory: ${{github.workspace}}/build
env:
CC: gcc-11
CXX: g++-11
run: >
cmake $GITHUB_WORKSPACE
-DCMAKE_BUILD_TYPE=$BUILD_TYPE
-DCMAKE_TOOLCHAIN_FILE="$GITHUB_WORKSPACE/toolchains/linux-dev.cmake"
- name: Build
shell: bash
working-directory: ${{github.workspace}}/build
run: cmake --build . --config $BUILD_TYPE
- name: Test
working-directory: ${{github.workspace}}/build
shell: bash
run: ctest -C $BUILD_TYPE --rerun-failed --output-on-failure
- name: Pack (cmake install and make binary package)
shell: bash
working-directory: ${{github.workspace}}/build
run: cpack -G TBZ2
# - name: Upload artifacts
# uses: actions/upload-artifact@v4
# with:
# name: Linux Packages
# path: ${{github.workspace}}/build/gsmartcontrol-*-Linux*.*
windows-msys2:
runs-on: windows-latest
strategy:
matrix:
include: [
{ msystem: MINGW64, arch: x86_64, platform: win64, urlpath: mingw64 },
# MSYS2 no longer supports for 32-bit Windows.
# { msystem: MINGW32, arch: i686, platform: win32, urlpath: mingw32 }
]
steps:
- uses: actions/checkout@v4
- uses: msys2/setup-msys2@v2
# p7zip is needed to extract smartmontools
# fontconfig owns /etc/fonts
with:
msystem: ${{ matrix.msystem }}
update: true
install: >-
mingw-w64-${{ matrix.arch }}-gtkmm3
mingw-w64-${{ matrix.arch }}-pkg-config
mingw-w64-${{ matrix.arch }}-cmake
mingw-w64-${{ matrix.arch }}-gcc
mingw-w64-${{ matrix.arch }}-fontconfig
mingw-w64-${{ matrix.arch }}-nsis
make
p7zip
- name: Downgrade Packages to support Windows 7
# librsvg 2.59 requires Windows 8.1 or later (confirmed by dependency walker).
# We need to downgrade to 2.58.
# This contains gdk_pixbuf loader as well, and re-runs the loader cache update.
# https://repo.msys2.org/mingw/mingw32/mingw-w64-i686-librsvg-2.58.0-1-any.pkg.tar.zst
# https://repo.msys2.org/mingw/mingw64/mingw-w64-x86_64-librsvg-2.58.0-1-any.pkg.tar.zst
shell: msys2 {0}
working-directory: ${{github.workspace}}
run: |
wget https://repo.msys2.org/mingw/${{ matrix.urlpath }}/mingw-w64-${{ matrix.arch }}-librsvg-2.58.0-1-any.pkg.tar.zst
pacman -U --noconfirm mingw-w64-${{ matrix.arch }}-librsvg-2.58.0-1-any.pkg.tar.zst
- name: Download Package Requirements
shell: msys2 {0}
working-directory: ${{github.workspace}}
run: |
mkdir -p build/smartmontools
cd build/smartmontools
wget $SMARTMONTOOLS_URL
- name: Extract Package Requirements (64-bit)
if: ${{ matrix.msystem == 'MINGW64' }}
shell: msys2 {0}
working-directory: ${{github.workspace}}/build/smartmontools
run: >
7z -bb1 e $SMARTMONTOOLS_INSTALLER
bin/smartctl.exe
bin/smartctl-nc.exe
bin/update-smart-drivedb.ps1
bin/drivedb.h
- name: Extract Package Requirements (32-bit)
if: ${{ matrix.msystem == 'MINGW32' }}
shell: msys2 {0}
working-directory: ${{github.workspace}}/build/smartmontools
run: >
7z -bb1 e $SMARTMONTOOLS_INSTALLER
bin32/smartctl.exe
bin32/smartctl-nc.exe
bin/update-smart-drivedb.ps1
bin/drivedb.h
- name: List installed files
shell: msys2 {0}
run: |
ls -1R /mingw64
ls -1R /mingw32
- name: List Files in Workspace
shell: msys2 {0}
working-directory: ${{github.workspace}}
run: ls -1R .
- name: Configure CMake
shell: msys2 {0}
run: >
cmake -B build -S "$GITHUB_WORKSPACE"
-G "MSYS Makefiles"
-DCMAKE_BUILD_TYPE=$BUILD_TYPE
-DCMAKE_TOOLCHAIN_FILE="$GITHUB_WORKSPACE/toolchains/${{ matrix.platform }}-mingw-msys2.cmake"
- name: Build
shell: msys2 {0}
working-directory: ${{github.workspace}}/build
run: cmake --build . --config $BUILD_TYPE
- name: Test
working-directory: ${{github.workspace}}/build
shell: msys2 {0}
run: ctest -C $BUILD_TYPE --rerun-failed --output-on-failure
- name: Package ZIP
shell: msys2 {0}
working-directory: ${{github.workspace}}/build
run: cpack -G ZIP
- name: Package NSIS (64-bit)
if: ${{ matrix.msystem == 'MINGW64' }}
shell: msys2 {0}
working-directory: ${{github.workspace}}/build
run: cpack -G NSIS64
- name: Package NSIS (32-bit)
if: ${{ matrix.msystem == 'MINGW32' }}
shell: msys2 {0}
working-directory: ${{github.workspace}}/build
run: cpack -G NSIS
- name: Upload artifacts
if: ${{ matrix.msystem == 'MINGW64' }}
uses: actions/upload-artifact@v4
with:
name: Windows 64-Bit Packages
path: ${{github.workspace}}/build/gsmartcontrol-*-win*.*
- name: Upload artifacts
if: ${{ matrix.msystem == 'MINGW32' }}
uses: actions/upload-artifact@v4
with:
name: Windows 32-Bit Packages
path: ${{github.workspace}}/build/gsmartcontrol-*-win*.*
+46
View File
@@ -0,0 +1,46 @@
name: Build (Tier 2 platforms with flaky builds)
# FreeBSD build via vmactions/freebsd-vm is known to fail randomly,
# so we don't want it to be triggered on every commit.
# Manually triggered
on: [workflow_dispatch]
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: RelWithDebInfo
CXX: clang++-17
jobs:
freebsd:
runs-on: ubuntu-latest
# env:
# variables to pass to VM
# MYTOKEN : ${{ secrets.MYTOKEN }}
steps:
- uses: actions/checkout@v4
- name: Build and test in FreeBSD
id: test
uses: vmactions/freebsd-vm@v1
with:
envs: 'BUILD_TYPE CXX'
usesh: true
sync: rsync
# release: "14.0"
prepare: >
pkg install -y cmake pkgconf gtkmm30 gettext libiconv llvm17
run: >
mkdir build && cd build
cmake ..
-DCMAKE_BUILD_TYPE=$BUILD_TYPE
-DAPP_BUILD_EXAMPLES=ON
-DAPP_BUILD_TESTS=ON
-DAPP_COMPILER_ENABLE_WARNINGS=ON
cmake --build . --config $BUILD_TYPE
ctest -C $BUILD_TYPE --rerun-failed --output-on-failure
+75
View File
@@ -0,0 +1,75 @@
name: Build (Tier 2 platforms)
on:
# Triggers the workflow on push or pull request events but only for the main branch
push:
branches: [ main ]
pull_request:
branches: [ main ]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: RelWithDebInfo
jobs:
macos-homebrew:
runs-on: macos-latest
strategy:
matrix:
include: [
# We need AppleClang 16, but GitHub only has 14 for now.
# { compiler: apple-clang },
{ compiler: clang }
]
steps:
- uses: actions/checkout@v4
- name: Install Dependencies
run: brew install pkg-config gtkmm3 cmake
- name: Install Clang Compiler
if: ${{ matrix.compiler == 'clang' }}
run: brew install llvm@17
- name: Create Build Directory
run: cmake -E make_directory build
- name: Configure CMake (Apple Clang)
if: ${{ matrix.compiler == 'apple-clang' }}
shell: bash
working-directory: ${{github.workspace}}/build
run: >
cmake $GITHUB_WORKSPACE
-DCMAKE_BUILD_TYPE=$BUILD_TYPE
-DAPP_BUILD_EXAMPLES=ON
-DAPP_BUILD_TESTS=ON
-DAPP_COMPILER_ENABLE_WARNINGS=ON
- name: Configure CMake
if: ${{ matrix.compiler == 'clang' }}
shell: bash
working-directory: ${{github.workspace}}/build
run: >
cmake $GITHUB_WORKSPACE
-DCMAKE_BUILD_TYPE=$BUILD_TYPE
-DAPP_BUILD_EXAMPLES=ON
-DAPP_BUILD_TESTS=ON
-DAPP_COMPILER_ENABLE_WARNINGS=ON
-DCMAKE_CXX_COMPILER=$(brew --prefix llvm@17)/bin/clang++
- name: Build
shell: bash
working-directory: ${{github.workspace}}/build
run: cmake --build . --config $BUILD_TYPE
- name: Test
working-directory: ${{github.workspace}}/build
shell: bash
run: ctest -C $BUILD_TYPE --rerun-failed --output-on-failure
+61
View File
@@ -0,0 +1,61 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# This workflow checks out code, performs a Codacy security scan
# and integrates the results with the
# GitHub Advanced Security code scanning feature. For more information on
# the Codacy security scan action usage and parameters, see
# https://github.com/codacy/codacy-analysis-cli-action.
# For more information on Codacy Analysis CLI in general, see
# https://github.com/codacy/codacy-analysis-cli.
name: Codacy Security Scan
on:
push:
branches: [ main ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ main ]
schedule:
- cron: '27 22 * * 1'
permissions:
contents: read
jobs:
codacy-security-scan:
permissions:
contents: read # for actions/checkout to fetch code
security-events: write # for github/codeql-action/upload-sarif to upload SARIF results
actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status
name: Codacy Security Scan
runs-on: ubuntu-24.04
steps:
# Checkout the repository to the GitHub Actions runner
- name: Checkout code
uses: actions/checkout@v4
# Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis
- name: Run Codacy Analysis CLI
uses: codacy/codacy-analysis-cli-action@d840f886c4bd4edc059706d09c6a1586111c540b
with:
# Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository
# You can also omit the token and run the tools that support default configurations
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
verbose: true
output: results.sarif
format: sarif
# Adjust severity of non-security issues
gh-code-scanning-compat: true
# Force 0 exit code to allow SARIF file generation
# This will handover control about PR rejection to the GitHub side
max-allowed-issues: 2147483647
# Upload the SARIF file generated in the previous step
- name: Upload SARIF results file
uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: results.sarif
+85
View File
@@ -0,0 +1,85 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ main ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ main ]
schedule:
- cron: '24 10 * * 6'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-24.04
permissions:
# required for all workflows
security-events: write
# required to fetch internal or private CodeQL packs
#packages: read
# only required for workflows in private repositories
#actions: read
#contents: read
strategy:
fail-fast: false
matrix:
language: [ 'cpp' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://git.io/codeql-language-support
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Update Package Database
run: sudo apt-get update
- name: Install Dependencies
run: sudo apt-get install libgtkmm-3.0-dev gettext
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v4
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
env:
CC: gcc-13
CXX: g++-13
uses: github/codeql-action/autobuild@v4
# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4
+36
View File
@@ -0,0 +1,36 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
name: DevSkim
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
schedule:
- cron: '25 22 * * 0'
jobs:
lint:
name: DevSkim
runs-on: ubuntu-24.04
permissions:
actions: read
contents: read
security-events: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Run DevSkim scanner
uses: microsoft/DevSkim-Action@v1
with:
ignore-globs: dummy_to_avoid_action_error,**/.git/**,*.txt,**/dependencies/**,env_tools.h,app_gtkmm_tools.cpp
- name: Upload DevSkim scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: devskim-results.sarif
+140
View File
@@ -0,0 +1,140 @@
name: Windows Release
on:
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: Release
SMARTMONTOOLS_INSTALLER: smartmontools-7.4-1.win32-setup.exe
SMARTMONTOOLS_URL: https://downloads.sourceforge.net/project/smartmontools/smartmontools/7.4/smartmontools-7.4-1.win32-setup.exe
jobs:
windows-msys2:
runs-on: windows-latest
strategy:
matrix:
include: [
{ msystem: MINGW64, arch: x86_64, platform: win64, urlpath: mingw64 },
{ msystem: MINGW32, arch: i686, platform: win32, urlpath: mingw32 }
]
steps:
- uses: actions/checkout@v4
- uses: msys2/setup-msys2@v2
# p7zip is needed to extract smartmontools
# fontconfig owns /etc/fonts
with:
msystem: ${{ matrix.msystem }}
update: true
install: >-
mingw-w64-${{ matrix.arch }}-gtkmm3
mingw-w64-${{ matrix.arch }}-pkg-config
mingw-w64-${{ matrix.arch }}-cmake
mingw-w64-${{ matrix.arch }}-gcc
mingw-w64-${{ matrix.arch }}-fontconfig
make
p7zip
- name: Downgrade Packages to support Windows 7
# librsvg 2.59 requires Windows 8.1 or later (confirmed by dependency walker).
# We need to downgrade to 2.58.
# This contains gdk_pixbuf loader as well, and re-runs the loader cache update.
# https://repo.msys2.org/mingw/mingw32/mingw-w64-i686-librsvg-2.58.0-1-any.pkg.tar.zst
# https://repo.msys2.org/mingw/mingw64/mingw-w64-x86_64-librsvg-2.58.0-1-any.pkg.tar.zst
shell: msys2 {0}
working-directory: ${{github.workspace}}
run: |
wget https://repo.msys2.org/mingw/${{ matrix.urlpath }}/mingw-w64-${{ matrix.arch }}-librsvg-2.58.0-1-any.pkg.tar.zst
pacman -U --noconfirm mingw-w64-${{ matrix.arch }}-librsvg-2.58.0-1-any.pkg.tar.zst
- name: Download Package Requirements
shell: msys2 {0}
working-directory: ${{github.workspace}}
run: |
mkdir -p build/smartmontools
cd build/smartmontools
wget $SMARTMONTOOLS_URL
- name: Extract Package Requirements (64-bit)
if: ${{ matrix.msystem == 'MINGW64' }}
shell: msys2 {0}
working-directory: ${{github.workspace}}/build/smartmontools
run: >
7z -bb1 e $SMARTMONTOOLS_INSTALLER
bin/smartctl.exe
bin/smartctl-nc.exe
bin/update-smart-drivedb.ps1
bin/drivedb.h
- name: Extract Package Requirements (32-bit)
if: ${{ matrix.msystem == 'MINGW32' }}
shell: msys2 {0}
working-directory: ${{github.workspace}}/build/smartmontools
run: >
7z -bb1 e $SMARTMONTOOLS_INSTALLER
bin32/smartctl.exe
bin32/smartctl-nc.exe
bin/update-smart-drivedb.ps1
bin/drivedb.h
- name: List installed files
shell: msys2 {0}
run: |
ls -1R /mingw64
ls -1R /mingw32
- name: Configure CMake
shell: msys2 {0}
run: >
cmake -B build -S "$GITHUB_WORKSPACE"
-G "MSYS Makefiles"
-DCMAKE_BUILD_TYPE=$BUILD_TYPE
-DCMAKE_TOOLCHAIN_FILE="$GITHUB_WORKSPACE/toolchains/${{ matrix.platform }}-mingw-msys2.cmake"
- name: Build
shell: msys2 {0}
working-directory: ${{github.workspace}}/build
run: cmake --build . --config $BUILD_TYPE
- name: Test
working-directory: ${{github.workspace}}/build
shell: msys2 {0}
run: ctest -C $BUILD_TYPE --rerun-failed --output-on-failure
- name: Package ZIP
shell: msys2 {0}
working-directory: ${{github.workspace}}/build
run: cpack -G ZIP
- name: Package NSIS (64-bit)
if: ${{ matrix.msystem == 'MINGW64' }}
shell: msys2 {0}
working-directory: ${{github.workspace}}/build
run: cpack -G NSIS64
- name: Package NSIS (32-bit)
if: ${{ matrix.msystem == 'MINGW32' }}
shell: msys2 {0}
working-directory: ${{github.workspace}}/build
run: cpack -G NSIS
- name: Upload artifacts
if: ${{ matrix.msystem == 'MINGW64' }}
uses: actions/upload-artifact@v4
with:
name: Windows 64-Bit Packages
path: ${{github.workspace}}/build/gsmartcontrol-*-win*.*
- name: Upload artifacts
if: ${{ matrix.msystem == 'MINGW32' }}
uses: actions/upload-artifact@v4
with:
name: Windows 32-Bit Packages
path: ${{github.workspace}}/build/gsmartcontrol-*-win*.*
+46
View File
@@ -0,0 +1,46 @@
# Builds
/0*
/win32*
/win64*
/cmake-build-*
/build*
/_codeql_build_dir
# Non-project files
/TODO
# Doxygen generated
/doxygen_doc
# OS-generated files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
Icon?
ehthumbs.db
Thumbs.db
# IDE
/.vs
/*.pcs
/.idea
/CMakeLists.txt.user
# Agents
/.codebuddy
# Translations
/po/boldquot.sed
/po/en@boldquot.header
/po/en@quot.header
/po/insert-header.sin
/po/Makevars.template
/po/quot.sed
/po/remove-potcdate.sin
/po/Rules-quot
/po/gsmartcontrol.pot
/po/*.gmo
+206
View File
@@ -0,0 +1,206 @@
# This file describes OBS workflows:
# https://openbuildservice.org/help/manuals/obs-user-guide/cha.obs.scm_ci_workflow_integration.html
# Workflow for pull requests
#build_pull_request_workflow:
# steps:
# - branch_package:
# source_project: home:alex_sh:gsmartcontrol:github_ci:main
# source_package: gsmartcontrol
# target_project: home:alex_sh:gsmartcontrol:github_ci:main
#
# - configure_repositories:
# project: home:alex_sh:gsmartcontrol:github_ci:main
# repositories:
# - name: openSUSE_Tumbleweed
# paths:
# - target_project: openSUSE:Factory
# target_repository: snapshot
# architectures:
# - x86_64
# - i586
#
# - set_flags:
# flags:
# - type: publish
# status: disable
# project: home:alex_sh:gsmartcontrol:github_ci:main
#
# filters:
# event: pull_request
# branches:
# only:
# - main
# Workflow for pushes
# Note: This adds new repositories to the project if they do not exist.
build_main_workflow:
steps:
- configure_repositories:
project: home:alex_sh:gsmartcontrol:github_ci:main
repositories:
- name: openSUSE_Tumbleweed
paths:
- target_project: openSUSE:Factory
target_repository: snapshot
architectures:
- x86_64
- name: openSUSE_Slowroll
paths:
- target_project: openSUSE:Slowroll
target_repository: standard
architectures:
- x86_64
- name: openSUSE_Leap_15.6
paths:
- target_project: openSUSE:Leap:15.6
target_repository: standard
architectures:
- x86_64
- name: openSUSE_Leap_15.5
paths:
- target_project: devel:gcc
target_repository: openSUSE_Leap_15.5
- target_project: openSUSE:Leap:15.5
target_repository: standard
architectures:
- x86_64
- name: openSUSE_Factory_ARM
paths:
- target_project: openSUSE:Factory:ARM
target_repository: standard
architectures:
- aarch64
- armv7l
- name: SUSE_SLE-15-SP6
paths:
- target_project: devel:gcc
target_repository: SLE-15
- target_project: SUSE:SLE-15-SP6:GA
target_repository: standard
architectures:
- x86_64
- name: Ubuntu_24.04
paths:
- target_project: openSUSE:Tools
target_repository: xUbuntu_24.04
- target_project: Ubuntu:24.04
target_repository: universe
architectures:
- x86_64
- name: Ubuntu_23.10
paths:
- target_project: openSUSE:Tools
target_repository: xUbuntu_23.10
- target_project: Ubuntu:23.10
target_repository: universe
architectures:
- x86_64
- name: Ubuntu_22.04
paths:
- target_project: openSUSE:Tools
target_repository: xUbuntu_22.04
- target_project: Ubuntu:22.04
target_repository: universe
architectures:
- x86_64
- name: Fedora_Rawhide
paths:
- target_project: openSUSE:Tools
target_repository: Fedora_Rawhide
- target_project: Fedora:Rawhide
target_repository: standard
architectures:
- x86_64
- name: Fedora_41
paths:
- target_project: openSUSE:Tools
target_repository: Fedora_41
- target_project: Fedora:41
target_repository: standard
architectures:
- x86_64
- aarch64
- name: Fedora_40
paths:
- target_project: openSUSE:Tools
target_repository: Fedora_40
- target_project: Fedora:40
target_repository: standard
architectures:
- x86_64
- aarch64
- name: Fedora_39
paths:
- target_project: openSUSE:Tools
target_repository: Fedora_39
- target_project: Fedora:39
target_repository: standard
architectures:
- x86_64
- aarch64
- name: Debian_Unstable
paths:
- target_project: openSUSE:Tools
target_repository: Debian_Unstable
- target_project: Debian:Next
target_repository: standard
architectures:
- x86_64
- name: Debian_Testing
paths:
- target_project: openSUSE:Tools
target_repository: Debian_Testing
- target_project: Debian:Testing
target_repository: update
architectures:
- x86_64
- i586
# AppImage build (using Ubuntu 22.04 as base)
- name: AppImage
paths:
- target_project: openSUSE:Tools
target_repository: xUbuntu_22.04
- target_project: Ubuntu:22.04
target_repository: universe
architectures:
- x86_64
- set_flags:
flags:
- type: publish
status: enable
project: home:alex_sh:gsmartcontrol:github_ci:main
- type: debuginfo
status: enable
project: home:alex_sh:gsmartcontrol:github_ci:main
- rebuild_package:
project: home:alex_sh:gsmartcontrol:github_ci:main
package: gsmartcontrol
filters:
event: push
branches:
only:
- main
+82
View File
@@ -0,0 +1,82 @@
###############################################################################
# License: BSD Zero Clause License file
# Copyright:
# (C) 2021 - 2024 Alexander Shaduri <ashaduri@gmail.com>
###############################################################################
# 3.14 for proper object library support (wrt linking)
cmake_minimum_required(VERSION 3.14)
# Use new policy for option() to supress warnings.
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
include(${CMAKE_SOURCE_DIR}/version.txt)
project(gsmartcontrol
VERSION ${CMAKE_PROJECT_VERSION}
DESCRIPTION "Hard Disk Drive and SSD Health Inspection Tool"
HOMEPAGE_URL "https://gsmartcontrol.shaduri.dev"
LANGUAGES CXX
)
# Provide DATADIR, etc.
include(GNUInstallDirs)
message(STATUS "Using toolchain file: ${CMAKE_TOOLCHAIN_FILE}")
include(src/build_config/compiler_options.cmake)
# Disable RPATH manipulation, we don't have shared libraries
set(CMAKE_SKIP_BUILD_RPATH TRUE)
set(CMAKE_SKIP_INSTALL_RPATH TRUE)
# Write the binaries to project root (avoids conflicts with manifests, also it's more convenient this way)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
# User-controlled build options
option(APP_BUILD_EXAMPLES "Build examples" OFF)
option(APP_BUILD_TESTS "Build tests" OFF)
option(APP_BUILD_APPIMAGE "Build for AppImage (portable data file paths)" OFF)
# Install documentation
set(DOC_FILES
LICENSE.LGPL3.txt
LICENSE.txt
NEWS.txt
README.md
)
if (WIN32)
install(FILES ${DOC_FILES} DESTINATION doc/)
install(DIRECTORY docs DESTINATION doc/
PATTERN "*.yml" EXCLUDE
PATTERN "CNAME" EXCLUDE
)
else()
install(FILES ${DOC_FILES} TYPE DOC)
install(DIRECTORY docs TYPE DOC
PATTERN "*.yml" EXCLUDE
PATTERN "CNAME" EXCLUDE
)
endif()
# CTest support
include(CTest)
#include(${CMAKE_SOURCE_DIR}/dependencies/catch2/Catch2/extras/Catch.cmake)
include(${CMAKE_SOURCE_DIR}/dependencies/catch2/Catch2/contrib/Catch.cmake)
add_subdirectory(contrib)
add_subdirectory(data)
add_subdirectory(dependencies)
add_subdirectory(packaging)
add_subdirectory(src)
# Packaging support
include(packaging/cpack_options.cmake)
+128
View File
@@ -0,0 +1,128 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
ashaduri@gmail.com.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.
+2524
View File
File diff suppressed because it is too large Load Diff
+165
View File
@@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
+296
View File
@@ -0,0 +1,296 @@
Version 2.0.2, released on 2025-02-24
Support GCC 11 (and Ubuntu 22.04) by using and vendoring fmt library
(#77).
Support an option of saving smartctl output to text instead of JSON (#76).
Restored pre-2.0.0 runtime support for smartctl < 7.3 (based on Text
parser); this is an unsupported, old method without NVMe, provided
for compatibility only (#77).
Restored pre-2.0.0 support for standard (non-extended) self-test log found
in very old ATA drives; the new JSON parser did not support this
previously (#79).
Better support for temperature values in JSON parser; this fixes
unreasonably large temperature values (#78).
Add a tooltip explaining self-test "lifetime hours" wrapping behavior
(#73).
Windows: Fixed a crash on Windows 7 when opening drive information
by using Windows 7-compatible librsvg (#71).
Windows: Avoid using non-integer font sizes.
Version 2.0.1, released on 2024-11-26
Windows: Fixed a crash when opening a native file dialog (#67).
Version 2.0.0, released on 2024-11-07
New JSON-based parser for smartctl output (requires smartctl 7.3+) (#4).
Support for NVMe drives (self-tests require smartctl 7.4+) (#4).
New "Basic" JSON parser for SCSI, flash, and other non-ATA/NVMe drives.
PCRE library is no longer required (the code has been ported to
std::regex) (#40).
A lot of code has been refactored and modernized using C++17 and C++20
features, removing much of the custom library code.
The build process requires a C++20-compliant compiler now (GCC 13+,
Clang 17+, Apple Clang 15+).
CMake (3.14+) is now used as a build system instead of autotools.
GSmartControl is now licensed under GNU GPL 3 only.
Icons come from Oxygen project now (LGPL 3+) instead of Crystal project.
Documentation in md format comes with the source code ("docs" directory).
Support new versions and prereleases of smartctl (#46, #42).
Better detection of drive types thanks to the JSON parser.
Removed ATA AODC feature, it has been deprecated for a while now.
Information window: Some values are aligned and monospaced to improve
readability.
Fixed command execution popup dialog being on top of all windows (#17).
Other minor UI improvements and fixes.
Windows: Better support for HiDPI (including fractional scaling).
Windows: NSIS package is generated by CPack now.
Windows: Packages are built using GitHub CI now.
Version 1.1.4, released on 2022-02-04
Fixed a crash when trying to render main window icons which have
incomplete data; this fixes a rare crash when scanning devices (#13).
Fixed rendering compatibility issues with newer GTK3 versions.
Fixed build system conflict with C++20 version header (#14).
Fixed "Running command ..." dialog floating above windows of other
applications (#17).
Fixed a crash when system locale is set to invalid locale.
Support Finnish decimal separator (backported from the Debian package)
(#23).
Set LC_NUMERIC=C for smartctl process to avoid locale-dependent number
formatting (#23).
Fixed printing all GTK messages as warnings; the messages are sorted by
severity now.
Add current time to default filename in Save Output dialog.
Support macos stat command in file2csource.sh.
Fixed a few typos (backported from the Debian package).
Windows port now uses Adwaita theme due to issues with win32 theme.
Windows port is dpi-aware now.
Version 1.1.3, released on 2017-11-12
Fixed gsmartcontrol-root not launching if GDK_* variables are not set.
Version 1.1.2, released on 2017-11-11
Fixed gsmartcontrol-root not passing GDK_SCALE and GDK_DPI_SCALE variables
to gsmartcontrol when using PolKit.
Fixed blurriness of icons in the main window with GDK_SCALE=2.
Tweaked the main window interface.
Windows: Show volume labels beside drive letters in icon tooltips.
Version 1.1.1, released on 2017-09-25
Windows: Use Adwaita GTK+ theme for systems which support Classic Windows
theme, since the default win32 GTK+ theme is broken in it; this
includes Windows 7 and Windows Server.
Statistics entry values are formatted with commas for readability.
Moved help information to website.
Version 1.1.0, released on 2017-09-07
New Statistics, Temperature Log, Error Recovery, Physical and Directory
tabs.
General tab shows non-SMART device settings as well.
Attributes tab shows entries in "brief" format.
Error Log tab shows Extended error log by default (if supported).
Self-Test Log tab now shows Extended self-test log by default (if
supported).
GSmartControl now uses "-x" equivalent for retrieving data (as upposed to
"-a"); loading "-x" outputs as virtual drives is also supported.
Implemented ability to copy rows in CSV format from Attribute, Statistics
and Self-Test Log tables.
Implemented "Update Drive Database" functionality.
Windows: Drive letters are shown for each drive.
Scan time is shown under virtual drive icons.
Polkit is supported with gsmartcontrol-root script now.
Pcrecpp is no longer bundled, use system-installed one instead.
Smartmontools version 5.43 is required at runtime.
Other minor improvements and fixes.
Version 1.0.2, released on 2017-07-21
Fixed incomplete capturing of smartctl output under Windows.
Added missing icons under Windows.
Fixed being able to turn on AODC even if unsupported.
Version 1.0.1, released on 2017-06-19
Fixed compilation under macOS.
Fixed compilation under Fedora Rawhide.
Don't use -mtune=generic for all targets.
Version 1.0.0, released on 2017-06-16
Ported to GTK+ 3.
Tweaked the user interface a bit.
Dropped support for Windows XP, 2000 and 2003 (they are no longer
supported by GTK+).
Fixed detection of newer system-installed smartmontools under Windows.
Version 0.9.0, released on 2017-05-11
Implemented (untested) support for Linux-based Areca controllers with
enclosures.
Implemented (untested) support for Windows-based Areca controllers (thanks
to Richard Kagerer).
Implemented (untested) support for Linux-based HP controllers with cciss
and hpsa/hpahcisr drivers (thanks to Fabrice Bacchella).
Changes in Preferences no longer fail silently until rescan/restart.
Better drive detection under Windows after removable drives are detached.
Windows version is no longer marked as "dpi aware" since it's not
supported that well.
Drive attribute descriptions have been updated (including clarifications
for SSDs).
Added support for SSD-only and HDD-only vendor attributes.
Devices having only basic info can be displayed now in the info window.
Fixed BDRW drive detection (it was detected as a HDD).
Other minor improvements.
A number of issues have been fixed (including a crash).
Version 0.8.7, released on 2012-08-11
Implemented support for Adaptec RAID 5805 controller and possibly other
Adaptec models as well (Linux).
Implemented support for Areca RAID controller detection under Linux
(untested).
Implemented support for 3ware 3w-sas-supported (twl) RAID controller
detection under Linux (untested).
Implemented support for systems with several different 3ware controllers
(twa/twe/twl).
Fixed invalid parsing of tw_cli output which caused non-detection of
drives and controllers with controller or port numbers greater than 9
if tw_cli was found (3ware linux, windows).
The duplicate drives are no longer shown for some Intel matrix controllers
under Windows; Intel RAID controllers are fully supported under
Windows now.
Added options to show device name and serial number under drive icons.
Updated SMART attribute definitions and added warnings for SSD lifetime
attributes.
gsmartcontrol-root has a new argument "--desktop=..." which replaces the
old positional argument; compatibility with the old invocation syntax
has been retained.
Completely documented the source using doxygen tags.
Added support for Fedora's consolehelper.
Made GSmartControl DPI-aware under Windows.
Fixed compilation issues with clang and gcc 4.7, as well as glib 2.31.x
and newer.
Fixed minor issues in NSIS installer.
Fixed other minor bugs and made minor improvements.
Version 0.8.6, released on 2011-06-12
Support detecting drives behind 3ware controllers (Linux, Windows),
including tw_cli/cx/px mode in Windows. Having tw_cli is recommended
but not required.
Added support for specifying -d option and extra parameters via command
line, "Add Device" and "Preferences" dialogs. This change effectively
adds full support for multiple drives behind a single device name.
Beesu and su-to-root are supported by gsmartcontrol-root script now.
Completely revamped the attribute database and its handling, should be a
lot more usable and forward-compatible now; SSD attributes are also
included.
In-program help has been expanded considerably.
General improvements to user interface have been implemented (better GNOME
HIG compliance, better tooltips, dialogs, etc.).
Added ability to show smartctl output for devices whose info could not be
parsed fully.
Attributes in "brief" format are supported now.
The parser has been updated to reflect the recent changes in smartctl.
Quit and rescan operations are no longer denied without confirmation when
tests are running.
The Windows NSIS installer has been vastly improved.
Better support for Windows Vista and 7.
Changed copyright notices for files with Whatever License to use Unlicense.
Added other minor features and fixed quite a few bugs.
Version 0.8.5, released on 2009-09-05
GSmartControl now uses XDG config directory for per-user configuration on
UNIX and CSIDL_PROFILE directory on Windows. Existing configuration is
migrated automatically.
The names are shown correctly for unsupported devices even with the latest
smartctl snapshots now.
Smartctl SVN revision is shown (if available).
The progress bars update properly when parallel tests are run.
Windows: GSmartControl should be able to operate on any valid filesystem
path (not just locale-representable ones).
Windows: GSmartControl is now officially compilable on x86_64 via mingw64.
Fixed compilation under very old gtkmm/libglademm, and with gcc 4.4.
Fixed parsing of multiple error types in SMART error log.
Added minor features and fixed miscellaneous bugs.
Version 0.8.4, released on 2009-03-23
Linux Software RAID devices are blacklisted now. (backported from Debian).
Attributes tab is before the capabilities tab now.
A man page has been generously contributed by Giuseppe Iuculano
<giuseppe@iuculano.it>.
Smartctl version now includes the CVS snapshot date (if available).
Windows: Look for "smartctl-nc.exe" instead of "smartctl.exe" by default.
Windows: Use smartmontools-supplied smartctl-nc.exe by default (if found).
Other minor changes (mainly Debian backports).
Version 0.8.3, released on 2008-12-27
A random "Smartctl returned an empty output" error on Windows was fixed.
Thanks to Zurab Khetsuriani for testing.
Fixed a parser issue which prevented running self-tests in Windows.
The supplied icon (hopefully) shows correctly in Windows 2000 now.
This release adds an official support for Windows 2000 SP4.
Added scripts to allow GSmartControl to read smartctl data from
cron-generated files. This allows users to read somewhat recent
smartctl information without having to run GSmartControl as root.
Generously contributed by Alex Butcher <alex dot butcher 'at'
assursys.co.uk>.
Configure script correctly aborts instead of printing a warning if gtkmm
or libglademm (if needed) is not found.
Configure script now accepts --enable-windows-console,
--disable-abort-if-no-gtkmm, --disable-abort-if-no-glade-reader,
as well as Windows-supporting "auto" for --enable-nsis-wine and
--with-nsis.
Configure's --with-win32-env has been renamed to --with-windows-dlls.
The "About" dialog shows version information now.
Minor bugs were fixed.
Version 0.8.2, released on 2008-12-10
Fixed gsmartcontrol_root.sh script to support distributions with no
/usr/sbin in their users' paths (thanks to Erwan Velu).
Added desktop auto-detection to gsmartcontrol_root.sh script. This allows
us to use only one desktop file (thanks to Erwan Velu).
Added Debian package directory (named "debian.dist" for now to avoid
control file conflicts with Build Service).
Renamed gsmartcontrol_root.sh to gsmartcontrol-root, to make Debian happy.
Added make targets for Windows packages (zip and NSIS).
Fixed Windows-related issues (Vista is fully supported now).
Fixed minor bugs:
Smartctl parser is win32-locale-aware now.
No more unnecessary parsing.
No segfault on exit under Windows and Solaris.
A friendlier message is displayed if smartctl was not found.
No highlighted labels when switching tabs in Information window.
Version 0.8.1, released on 2008-11-11
Disabled Linux "by-id" drive detection - it's unreliable on some broken
systems.
Added some more attribute descriptions.
Our names for attributes override smartctls' now.
Added a proper "Add Device" dialog for Windows.
Added an icon and resource file for Windows.
Fixed minor bugs.
Version 0.8.0rc4, released on 2008-10-20
FreeBSD support (tested with DesktopBSD 1.6 (FreeBSD 6.3) / x86).
NetBSD support (tested with NetBSD 4.0.1 / x86).
OpenBSD support (tested with OpenBSD 4.3 / x86-64 / gcc-3.3.5).
Solaris/gcc support (tested with Solaris 10 / x86 / gcc-3.4.3 / blastwave).
Solaris/sunstudio support (tested with Solaris 10 / x86 / sunstudio12 /
sunfreeware).
Code to support Windows, Mac OS X, QNX.
Support of older pcre versions (at least 4.5, maybe older too).
Added gsmartcontrol_root.sh script to easily run gsmartcontrol as root.
Improved .desktop files.
License for tests and examples is legally more correct now.
Minor bugfixes.
Version 0.8.0rc3, released on 2008-10-08
Added support for udevless Linux distributions by providing a fallback
/proc/partitions-based drive detection method. The new method adds
support for Linux 2.4 and older systems. Thanks to Paul Marwick for
reporting and testing.
Fixed invalid error messages with directory-related operations.
Fixed invalid verbosity levels of console output of debug messages in
non-debug builds.
Improved rpm spec file - now supports building on OpenSUSE build
service with various distributions as targets.
Version 0.8.0rc2, released on 2008-10-05
Fixed compilation under gcc 4.3. Thanks to Peter Linnell for reporting.
Removed test data (there's a lot of it and it's unnecessary).
Version 0.8.0rc1, released on 2008-10-01
Initial public release.
+76
View File
@@ -0,0 +1,76 @@
# GSmartControl
***Hard disk drive and SSD health inspection tool***
[![Generic badge](https://img.shields.io/badge/Homepage-gsmartcontrol.shaduri.dev-brightgreen.svg)](https://gsmartcontrol.shaduri.dev)
[![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/ashaduri/gsmartcontrol?label=Version)](https://gsmartcontrol.shaduri.dev/downloads)
[![license: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
[![Platforms](https://img.shields.io/badge/Platforms-linux%20%7C%20windows%20%7C%20macos%20%7C%20*bsd-blue)](https://gsmartcontrol.shaduri.dev/software-requirements)
[![Packaging status](https://repology.org/badge/tiny-repos/gsmartcontrol.svg?header=Software%20distributions%20and%20repositories)](https://repology.org/project/gsmartcontrol/versions)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/528f4f7aaf0e446abf7e55d2affc7bec)](https://app.codacy.com/gh/ashaduri/gsmartcontrol?utm_source=github.com&utm_medium=referral&utm_content=ashaduri/gsmartcontrol&utm_campaign=Badge_Grade_Settings)
---
[GSmartControl](https://gsmartcontrol.shaduri.dev)
is a graphical user interface for smartctl (from [smartmontools](https://www.smartmontools.org/)
package), which is a tool for
querying and controlling [SMART](https://en.wikipedia.org/wiki/Self-Monitoring,_Analysis_and_Reporting_Technology)
(Self-Monitoring, Analysis, and Reporting
Technology) data on modern hard disk and solid-state drives. It allows you to
inspect the drive's SMART data to determine its health, as well as run various
tests on it.
## Downloads
The [Downloads](https://gsmartcontrol.shaduri.dev/downloads) page contains
all the available packages of GSmartControl.
## Features
- automatically reports and highlights any anomalies;
- allows enabling/disabling SMART;
- supports configuration of global and per-drive options for smartctl;
- performs SMART self-tests;
- displays drive identity information, capabilities, attributes, device statistics, etc.;
- can read in smartctl output from a saved file, interpreting it as a read-only virtual device;
- works on most smartctl-supported operating systems;
- has extensive help information.
### Supported Hardware
GSmartControl supports SATA, PATA, and NVMe drives, as well as drives
behind some USB bridges and RAID controllers.
Please see the
[Supported Hardware](https://gsmartcontrol.shaduri.dev/supported-hardware) page
for more information.
### Supported Platforms
GSmartControl supports all major desktop operating systems, including
Linux, Windows, macOS, FreeBSD, and other BSD-style operating systems.
Please see the
[Software Requirements](https://gsmartcontrol.shaduri.dev/software-requirements) page
for more information.
## Copyright and Licensing
GSmartControl is Copyright (C) 2008 - 2025 Alexander Shaduri [ashaduri@gmail.com](mailto:ashaduri@gmail.com) and contributors.
GSmartControl is licensed under the terms of
[GNU General Public License Version 3](https://www.gnu.org/licenses/gpl-3.0.en.html).
This program is free software: you can redistribute it and/or modify it under
the terms of version 3 of the GNU General Public License as published by the
Free Software Foundation.
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 Licenses for more details.
This product includes icons from Oxygen Icons copyright [KDE](https://kde.org)
and licensed under the [GNU LGPL version 3](https://www.gnu.org/licenses/lgpl-3.0.en.html) or later.
+16
View File
@@ -0,0 +1,16 @@
# Security Policy
## Supported Versions
The following versions are supported with security updates:
| Version | Supported |
|----------| ------------------ |
| git main | :white_check_mark: |
| 2.0.x | :white_check_mark: |
| < 2.0.0 | :x: |
## Reporting a Vulnerability
Please report security vulnerabilities privately to
Alexander Shaduri [ashaduri@gmail.com](mailto:ashaduri@gmail.com).
+1
View File
@@ -0,0 +1 @@
*
Executable
+160
View File
@@ -0,0 +1,160 @@
#!/bin/bash
###############################################################################
# License: BSD Zero Clause License file
# Copyright:
# (C) 2012 - 2021 Alexander Shaduri <ashaduri@gmail.com>
###############################################################################
# Configure a build directory for development
function print_usage() {
echo -e "Usage:"
echo -e " ${0} [-t <toolchain_name>] [-c <compiler>] [-b <build_type>]"
echo -e " [-s <source_dir>] [-g <generator>] [-o <cmake_options>]"
echo -e "\nDetails:"
echo -e "-t <toolchain_name> - toolchain_name can be e.g. \"win32-mingw64\"."
echo -e " A toolchain file \"toolchains/<toolchain_name>.cmake\" will be used."
echo -e "-c <compiler> - compiler is one of:"
echo -e " gcc, gcc-<version>, clang, intel."
echo -e " The gcc version is the suffix of gcc and g++ executables, e.g. \"4.8\" in"
echo -e " \"gcc-4.8\"."
echo -e " If unspecified, CC and CXX environment variables are used."
echo -e "-b <build_type> - build_type is one of:"
echo -e " Debug, Release, RelWithDebInfo, MinSizeRel, none. The default is Debug."
echo -e "-s <source_dir> - source_dir is \"..\" by default."
echo -e "-g <cmake_generator> - cmake uses \"Unix Makefiles\" by default."
echo -e "-o <cmake_options> - options to pass directly to cmake."
}
compiler=""
build_type="";
source_dir=".."
toolchain_name=""
generator=""
cmake_options=""
while getopts "t:c:b:s:g:o:h:" opt; do
case $opt in
t)
echo "Requested toolchain: $OPTARG"
toolchain_name="$OPTARG";
;;
c)
echo "Requested compiler: $OPTARG"
compiler="$OPTARG";
;;
b)
echo "Requested build type: $OPTARG"
build_type="$OPTARG";
;;
s)
echo "Requested source directory type: $OPTARG"
source_dir="$OPTARG";
;;
g)
echo "Requested generator: $OPTARG"
generator="$OPTARG";
;;
o)
echo "Requested cmake options: $OPTARG"
cmake_options="$OPTARG";
;;
h)
print_usage;
exit 1;
;;
\?)
echo "Invalid option: $opt";
print_usage;
exit 1;
;;
esac
done
if [ "$compiler" != "" ] && [ "$toolchain_name" != "" ]; then
echo "Error: Conflicting options -c and -t specified."
exit 1;
fi
cmake_flags="-Wdev";
if [ "$build_type" = "none" ]; then
build_type="";
fi
if [ "$build_type" != "" ]; then
cmake_flags="$cmake_flags -DCMAKE_BUILD_TYPE=$build_type";
fi
if [ "$generator" != "" ]; then
cmake_flags="$cmake_flags -G${generator}";
fi
status=1
# Toolchain mode
if [ "$toolchain_name" != "" ]; then
cmake_flags="$cmake_flags -DCMAKE_TOOLCHAIN_FILE='${source_dir}/data/cmake/toolchains/${toolchain_name}.cmake'"
echo "Running:"
echo "cmake $cmake_flags $source_dir";
cmake $cmake_flags $cmake_options $source_dir
status=$?
else # Compiler mode
c_compiler="";
cxx_compiler="";
# Detect gcc suffix like "-4.7"
if [ "${compiler:0:4}" = "gcc-" ]; then
suffix=${compiler:4};
c_compiler="gcc-${suffix}";
cxx_compiler="g++-${suffix}";
compiler="gcc";
fi
case $compiler in
gcc)
if [ "$c_compiler" = "" ]; then
c_compiler="gcc${machine_bits_switch}";
cxx_compiler="g++${machine_bits_switch}";
fi
;;
intel)
if [ $machine_bits_precise = "64" ]; then
c_compiler="icc64";
cxx_compiler="icpc64";
else
c_compiler="icc32";
cxx_compiler="icpc32";
fi
;;
clang)
c_compiler="clang${machine_bits_switch}";
cxx_compiler="clang++${machine_bits_switch}";
;;
"")
c_compiler="$CC"
cxx_compiler="$CXX"
;;
*)
echo "Unsupported compiler given; use CC and CXX instead."
exit 1;
;;
esac
echo "Running:"
echo "CC=\"$c_compiler\" CXX=\"$cxx_compiler\" cmake $cmake_flags $source_dir";
CC="$c_compiler" CXX="$cxx_compiler" cmake $cmake_flags $cmake_options $source_dir
status=$?
fi
exit $status
+10
View File
@@ -0,0 +1,10 @@
###############################################################################
# License: BSD Zero Clause License file
# Copyright:
# (C) 2021 Alexander Shaduri <ashaduri@gmail.com>
###############################################################################
if (NOT WIN32)
install(DIRECTORY "${CMAKE_SOURCE_DIR}/contrib" TYPE DOC
PATTERN "CMakeLists.txt" EXCLUDE)
endif()
@@ -1,10 +1,10 @@
#!/bin/bash
############################################################################
###############################################################################
# License: BSD Zero Clause License file
# Copyright:
# (C) 2008 - 2009 Alex Butcher <alex dot butcher 'at' assursys.co.uk>
# (C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
# License: See LICENSE_whatever.txt file
############################################################################
# (C) 2008 - 2024 Alex Butcher <alex dot butcher 'at' assursys.co.uk>
# (C) 2008 - 2024 Alexander Shaduri <ashaduri@gmail.com>
###############################################################################
device="$1";
@@ -13,10 +13,10 @@ if [ "$device" = "" ]; then
exit 1;
fi
dev_base="`basename \"$device\"`"
dev_base=$(basename "$device")
out_file=/var/run/smart-"$dev_base"
# Change the path to smartctl if necessary.
smartctl -a "$device" 2>&1 > "$out_file"
smartctl -x --json=o "$device" > "$out_file" 2>&1
chmod 644 "$out_file"
@@ -0,0 +1,9 @@
###############################################################################
# License: BSD Zero Clause License file
# Copyright:
# (C) 2008 - 2021 Alex Butcher <alex dot butcher 'at' assursys.co.uk>
# (C) 2008 - 2021 Alexander Shaduri <ashaduri@gmail.com>
###############################################################################
*/10 * * * * root /usr/local/bin/cron-smart.sh /dev/sda
*/10 * * * * root /usr/local/bin/cron-smart.sh /dev/sdb
@@ -1,10 +1,10 @@
#!/bin/bash
############################################################################
###############################################################################
# License: BSD Zero Clause License file
# Copyright:
# (C) 2008 - 2009 Alex Butcher <alex dot butcher 'at' assursys.co.uk>
# (C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
# License: See LICENSE_whatever.txt file
############################################################################
# (C) 2008 - 2022 Alex Butcher <alex dot butcher 'at' assursys.co.uk>
# (C) 2008 - 2022 Alexander Shaduri <ashaduri@gmail.com>
###############################################################################
if [ "$1" = "-V" ]; then
smartctl -V 2>&1
@@ -21,7 +21,7 @@ if [ "$device" = "" ]; then
exit 1;
fi
dev_base="`basename \"$device\"`"
dev_base=$(basename "$device")
out_file=/var/run/smart-"$dev_base"
cat "$out_file"
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 632 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

+81
View File
@@ -0,0 +1,81 @@
###############################################################################
# License: BSD Zero Clause License file
# Copyright:
# (C) 2021 Alexander Shaduri <ashaduri@gmail.com>
###############################################################################
# Generate files
if (APP_BUILD_APPIMAGE)
set(APPIMAGE_DESKTOP_ID "dev.shaduri.gsmartcontrol")
set(APPIMAGE_EXEC_LINE "Exec=\"${CMAKE_INSTALL_FULL_BINDIR}/gsmartcontrol\"")
configure_file("gsmartcontrol.appdata.in.xml" "gsmartcontrol.appdata.xml" ESCAPE_QUOTES @ONLY)
configure_file("gsmartcontrol.in.desktop" "dev.shaduri.gsmartcontrol.desktop" ESCAPE_QUOTES @ONLY)
else()
set(APPIMAGE_DESKTOP_ID "gsmartcontrol")
set(APPIMAGE_EXEC_LINE "Exec=\"${CMAKE_INSTALL_FULL_BINDIR}/gsmartcontrol-root\"")
configure_file("gsmartcontrol.appdata.in.xml" "gsmartcontrol.appdata.xml" ESCAPE_QUOTES @ONLY)
configure_file("gsmartcontrol.in.desktop" "gsmartcontrol.desktop" ESCAPE_QUOTES @ONLY)
endif()
configure_file("gsmartcontrol-root.in.sh" "gsmartcontrol-root.sh" ESCAPE_QUOTES @ONLY)
configure_file("org.gsmartcontrol.in.policy" "org.gsmartcontrol.policy" ESCAPE_QUOTES @ONLY)
# Install app icons
if (NOT WIN32)
foreach(dir 16 22 24 32 48 64 128 256)
install(FILES "${dir}/gsmartcontrol.png"
DESTINATION "${CMAKE_INSTALL_DATADIR}/icons/hicolor/${dir}x${dir}/apps/")
endforeach()
# Don't run update-icon-cache, cpack is mostly for packaging.
# install(CODE "execute_process (COMMAND gtk-update-icon-cache-3.0 -t -f \"@CMAKE_INSTALL_DATADIR@/icons/hicolor\")")
endif()
if (WIN32)
# .ico file
install(FILES gsmartcontrol.ico DESTINATION .)
endif()
set (DATA_ICONS
icons/drive-optical.png
icons/drive-harddisk.png
icons/drive-removable-media-usb.png
)
# Install internal icons
if (WIN32)
install(FILES ${DATA_ICONS} DESTINATION icons)
else()
install(FILES ${DATA_ICONS}
DESTINATION "${CMAKE_INSTALL_DATADIR}/gsmartcontrol/icons")
endif()
# Desktop file
if (NOT WIN32)
if (APP_BUILD_APPIMAGE)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/dev.shaduri.gsmartcontrol.desktop"
DESTINATION "${CMAKE_INSTALL_DATADIR}/applications/")
else()
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/gsmartcontrol.desktop"
DESTINATION "${CMAKE_INSTALL_DATADIR}/applications/")
endif()
# Appdata file
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/gsmartcontrol.appdata.xml"
DESTINATION "${CMAKE_INSTALL_DATADIR}/metainfo/")
# PolKit file
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/org.gsmartcontrol.policy"
DESTINATION "${CMAKE_INSTALL_DATADIR}/polkit-1/actions/")
# Man pages
install(FILES "man1/gsmartcontrol.1" DESTINATION "${CMAKE_INSTALL_MANDIR}/man1")
if (NOT APP_BUILD_APPIMAGE)
install(FILES "man1/gsmartcontrol.1" DESTINATION "${CMAKE_INSTALL_MANDIR}/man1" RENAME "gsmartcontrol-root.1")
endif()
# Scripts (this goes to bin, not sbin, as it doesn't require root privileges before running)
if (NOT APP_BUILD_APPIMAGE)
install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/gsmartcontrol-root.sh" TYPE BIN RENAME "gsmartcontrol-root")
endif()
endif()
+7
View File
@@ -0,0 +1,7 @@
#!/bin/bash
png_name="gsmartcontrol.png"
# needs imagemagick
convert 16/$png_name 22/$png_name 24/$png_name 32/$png_name \
48/$png_name 64/$png_name 128/$png_name 256/$png_name gsmartcontrol.ico
+33
View File
@@ -0,0 +1,33 @@
/******************************************************************************
License: GNU General Public License v3.0 only
Copyright:
(C) 2008 - 2021 Alexander Shaduri <ashaduri@gmail.com>
******************************************************************************/
// This file is for generating documentation only. Do NOT include it.
/// \file
/// \author Alexander Shaduri
/**
\mainpage GSmartControl Index
\section intro_section Introduction
This is GSmartControl internal documentation.
*/
// Group definitions and titles.
/**
\addtogroup applib Application-Specific Components
\addtogroup applib_examples Examples of Application-Specific Components
\addtogroup hz HZ Common System Components
\addtogroup hz_examples Examples for HZ Common System Components
\addtogroup libdebug LibDebug Flexible Debug Logging
\addtogroup libdebug_examples Examples for LibDebug Flexible Debug Logging
\addtogroup rconfig Resource Manager-Based Configuration
\addtogroup rconfig_examples Examples for Resource Manager-Based Configuration
\addtogroup gsc GSmartControl Application
*/
+168
View File
@@ -0,0 +1,168 @@
#!/bin/bash
###############################################################################
# License: Zlib
# Copyright:
# (C) 2008 - 2022 Alexander Shaduri <ashaduri@gmail.com>
###############################################################################
# Run gsmartcontrol with root, asking for root password first.
# export GSMARTCONTROL_SU to override a su command (e.g. "kdesu -c").
EXEC_BIN="@CMAKE_INSTALL_FULL_SBINDIR@/gsmartcontrol";
program_name="gsmartcontrol"
# Preserve quotes in arguments
final_args_quoted="";
for i in "$@";do
final_args_quoted="$final_args_quoted \"${i//\"/\\\"}\"";
done;
DESKTOP="auto";
# Compatibility with old syntax:
# gsmartcontrol-root [<desktop> [program_options]]
if [ "$1" == "auto" ] || [ "$1" == "kde" ] || [ "$1" == "gnome" ] || [ "$1" == "other" ]; then
DESKTOP="$1";
shift; # remove $1
else
# New syntax:
# gsmartcontrol-root [--desktop=<auto|kde|gnome|other>] [program_options]
for arg in "$@"; do
case $arg in
--desktop=*)
DESKTOP="${arg#*=}";
final_args_quoted="${final_args_quoted/\"$arg\"/}";
;;
*)
# unknown option
;;
esac
done
fi
if [ "$DESKTOP" != "auto" ] && [ "$DESKTOP" != "kde" ] && \
[ "$DESKTOP" != "gnome" ] && [ "$DESKTOP" != "other" ]; then
echo "Usage: $0 [--desktop=<auto|kde|gnome|other>] [<${program_name}_options>]";
exit 1;
fi
# Auto-detect current desktop if auto was specified.
if [ "$DESKTOP" = "auto" ]; then
# KDE_SESSION_UID is present on kde3 and kde4.
# Note that it may be empty (but still set)
if [ "${KDE_SESSION_UID+set}" = "set" ]; then
DESKTOP="kde";
# same with gnome
elif [ "${GNOME_DESKTOP_SESSION_ID+set}" = "set" ]; then
DESKTOP="gnome";
else
DESKTOP="other";
fi
fi
# echo $DESKTOP;
# They're basically the same, only the order is different.
# pkexec is for PolKit.
# sux requires xterm to ask for the password.
# xdg-su is basically like this script, except worse :)
# su-to-root is a debian/ubuntu official method (although gksu is available).
gnome_sus="pkexec su-to-root gnomesu gksu kdesu beesu xdg-su sux";
kde_sus="pkexec su-to-root kdesu gnomesu gksu beesu xdg-su sux";
other_sus="$gnome_sus";
candidates="";
found_su=""
if [ "$DESKTOP" = "gnome" ]; then
candidates="$gnome_sus";
elif [ "$DESKTOP" = "kde" ]; then
candidates="$kde_sus";
elif [ "$DESKTOP" = "other" ]; then
candidates="$other_sus";
fi
if [ "$GSMARTCONTROL_SU" = "" ]; then
for subin in $candidates; do
which "$subin" &>/dev/null
if [ $? -eq 0 ]; then
found_su="$subin";
break;
fi
done
if [ "$found_su" = "" ]; then
xmessage "Error launching ${program_name}: No suitable su mechanism found.
Try installing PolKit, kdesu, gnomesu, gksu, beesu or sux first.";
exit 1;
fi
fi
# gnomesu and gksu (but not kdesu, not sure about others) fail to adopt
# root's PATH. Since the user's PATH may not contain /usr/sbin (with smartctl)
# on some distributions (e.g. mandriva), add it manually. We also add
# /usr/local/sbin, since that's the default location of custom-compiled smartctl.
# Add these directories _before_ existing PATH, so that the user is not
# tricked into running it from some other path (we're running as root with
# the user's env after all).
# Add sbindir as well (freebsd seems to require it).
# Note that beesu won't show a GUI login box if /usr/sbin is before /usr/bin,
# so add it first as well.
EXTRA_PATHS="/usr/bin:/usr/sbin:/usr/local/sbin:@CMAKE_INSTALL_FULL_SBINDIR@";
export PATH="$EXTRA_PATHS:$PATH"
# echo $found_su;
# Examples:
# gnomesu -c 'gsmartcontrol --no-scan'
# kdesu -c 'gsmartcontrol --no-scan'
# beesu -P 'gsmartcontrol --no-scan'
# su-to-root -X -c 'gsmartcontrol --no-scan'
# xterm -e sux -c 'gsmartcontrol --no-scan' # sux asks for password in a terminal
full_cmd="";
if [ "$GSMARTCONTROL_SU" != "" ]; then
full_cmd="$GSMARTCONTROL_SU '$EXEC_BIN $final_args_quoted'";
elif [ "$found_su" = "pkexec" ]; then
if [ "$GDK_SCALE" != "" ]; then
final_args_quoted="$final_args_quoted --gdk-scale='$GDK_SCALE'"
fi
if [ "$GDK_DPI_SCALE" != "" ]; then
final_args_quoted="$final_args_quoted --gdk-dpi-scale='$GDK_DPI_SCALE'"
fi
full_cmd="pkexec --disable-internal-agent $EXEC_BIN $final_args_quoted";
elif [ "$found_su" = "sux" ]; then
full_cmd="xterm -e sux -c '$EXEC_BIN $final_args_quoted'";
elif [ "$found_su" = "gksu" ]; then
full_cmd="$found_su '$EXEC_BIN $final_args_quoted'";
elif [ "$found_su" = "beesu" ]; then
full_cmd="$found_su -P '$EXEC_BIN $final_args_quoted'";
elif [ "$found_su" = "su-to-root" ]; then
full_cmd="$found_su -X -c '$EXEC_BIN $final_args_quoted'";
else # gnomesu, kdesu, xdg-su
full_cmd="$found_su -c '$EXEC_BIN $final_args_quoted'";
fi
# echo $full_cmd
eval "$full_cmd"
+33
View File
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop">
<id>dev.shaduri.gsmartcontrol</id>
<metadata_license>CC0-1.0</metadata_license>
<project_license>GPL-3.0</project_license>
<name>GSmartControl</name>
<summary>Hard Disk and SSD Health Inspection</summary>
<description>
<p>
GSmartControl is a graphical user interface for smartctl, which is a tool for
querying and controlling SMART (Self-Monitoring, Analysis, and Reporting
Technology) data in hard disk and solid-state drives. It allows you to inspect
the drive's SMART data to determine its health, as well as run various tests
on it.
</p>
</description>
<launchable type="desktop-id">@APPIMAGE_DESKTOP_ID@.desktop</launchable>
<url type="homepage">https://gsmartcontrol.shaduri.dev</url>
<screenshots>
<screenshot type="default">
<caption>Main window</caption>
<image>https://gsmartcontrol.shaduri.dev/screenshots/main_ok.png</image>
</screenshot>
<screenshot>
<caption>Drive identity information</caption>
<image>https://gsmartcontrol.shaduri.dev/screenshots/info_identity.png</image>
</screenshot>
<screenshot>
<caption>Attribute list of a failing drive</caption>
<image>https://gsmartcontrol.shaduri.dev/screenshots/info_failing.png</image>
</screenshot>
</screenshots>
</component>
Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

+67
View File
@@ -0,0 +1,67 @@
###############################################################################
# License: BSD Zero Clause License file
# Copyright:
# (C) 2008 - 2021 Alexander Shaduri <ashaduri@gmail.com>
###############################################################################
[Desktop Entry]
# desktop file version
Version=1.0
Type=Application
Categories=System;Monitor;
Name=GSmartControl
Name[ca]=GSControlIntel
Name[cs]=GSmartControl
Name[es]=GSmartControl
Name[id]=GSmartControl
Name[it]=GSmartControl
Name[ja]=GSmartControl
Name[pt_BR]=GSmartControl
Name[ru]=GSmartControl
Name[sk]=GSmartControl
Name[sv]=GSmartControl
Name[zh_CN]=GSmartControl
# short description, usually shown in parentheses after Name
GenericName=Hard Disk and SSD Health Inspection
GenericName[ca]=Inspecció de salut del disc dur i de l'SSD
GenericName[cs]=Prohlídka zdraví pevných a SSD disků
GenericName[es]=Inspección de la salud de discos duros y SSD
GenericName[fr]=Inspecteur de santé de disque dur et de SSD
GenericName[id]=Pemeriksaan Kesehatan Cakram Keras dan SSD
GenericName[it]=Ispezione della salute del disco rigido e dell'SSD
GenericName[ja]=ハードディスクと SSD の健全状態の調査
GenericName[pt_BR]=Inspeção da integridade de disco rígido e SSD
GenericName[ru]=Проверка состояния жёстких и твердотельных дисков
GenericName[sk]=Zdravotná inšpekcia pevného disku a SSD
GenericName[zh_CN]=机械及固态硬盘健康检测
# tooltip
Comment=Monitor and control SMART data on hard disk and solid-state drives
Comment[ca]=Monitoreu i controleu les dades SMART dels discs durs i dels discs sòlids.
Comment[cs]=Sleduje a nastavuje SMART data na pevném disku a na polovodičových discích
Comment[es]=Monitorice y controle datos de SMART sobre discos duros y unidades de estado sólido
Comment[fr]=Surveille et contrôle les données SMART des disques durs et des SSD
Comment[id]=Pantau dan kendalikan data cerdas pada cakram keras dan SSD
Comment[it]=Monitora e controlla i dati SMART sui dischi rigidi e a stato solido
Comment[ja]=ハードディスクや SSD 内の SMART データの監視と制御
Comment[pt_BR]=Monitorar e controlar dados do SMART em discos rígidos e unidades de estado sólido
Comment[ru]=Мониторинг и контроль данных SMART на жёстких и твердотельных дисках
Comment[sk]=Monitorovanie a kontrola údajov SMART na pevných diskoch a diskoch SSD
Comment[zh_CN]=监测及控制机械硬盘和固态硬盘上的SMART数据
# If it's a name only, it looks for "name.[png|xpm]" file in
# $XDG_DATA_DIRS/icons.
# An absolute file path is also supported.
Icon=gsmartcontrol
# Run with root permissions. This should work with newer GNOME too.
# It _should_ work with kde, but it hangs on mine, so use plain kdesu.
#X-KDE-SubstituteUID=true
#X-KDE-RootOnly=true
# Run with root permissions.
# For AppImage builds, execute the binary directly (AppImage does not support embedded sudo scripts)
@APPIMAGE_EXEC_LINE@
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

@@ -1,16 +1,16 @@
.TH GSmartControl "1" "" "gsmartcontrol " "User Commands"
.SH NAME
GSmartControl \- Hard disk drive health inspection tool
GSmartControl \- Hard disk drive and SSD health inspection tool
.SH SYNOPSIS
\fBgsmartcontrol\fP [OPTIONS]
\fBgsmartcontrol\-root\fP [\fI<desktop>\fP [OPTIONS]]
\fBgsmartcontrol\-root\fP [--desktop=\fI<desktop>\fP] [OPTIONS]
.SH DESCRIPTION
\fBGSmartControl\fP is a graphical user interface for smartctl (from
smartmontools), which is a tool for querying and controlling SMART
(Self-Monitoring, Analysis, and Reporting Technology) data on modern hard disk
drives. It allows you to inspect the drive's SMART data to determine its
health, as well as run various tests on it.
and solid-state drives. It allows you to inspect the drive's SMART data to
determine its health, as well as run various tests on it.
.PP
This manual page documents briefly the \fBgsmartcontrol\fP and
\fBgsmartcontrol\-root\fP commands.
@@ -37,7 +37,7 @@ Show logging options
.SS "Application Options:"
.TP
\fB\-l\fP, \fB\-\-no\-locale\fP
Disable locale
Don't use system locale
.TP
\fB\-V\fP, \fB\-\-version\fP
Display version information
@@ -45,14 +45,21 @@ Display version information
\fB\-\-no\-scan\fP
Don't scan devices on startup
.TP
\fB\-\-no\-hide\-tabs\fP
Don't hide non\-identity tabs when SMART is disabled. Useful for debugging.
.TP
\fB\-\-add\-virtual\fP
Load smartctl data from file, creating a virtual drive
Load smartctl data from file, creating a virtual drive. You
can specify this option multiple times.
.TP
\fB\-\-add\-device\fP
Add this device to device list. Useful with \fB\-\-no\-scan\fP to list certain drives only.
Add this device to device list. The format of the device is
\fI<device>::<type>::<extra_args>\fP, where type and extra_args are optional.
This option is useful with \fB\-\-no\-scan\fP to list certain drives only. You
can specify this option multiple times. Example:\fR
.nf
\-\-add\-device /dev/sda \-\-add\-device /dev/twa0::3ware,2 \-\-add\-device '/dev/sdb::::-T permissive'
.fi
.TP
\fB\-\-forget\-devices\fP
Forget all previously manually added devices
.TP
\fB\-\-display\fP=\fIDISPLAY\fP
X display to use
@@ -67,8 +74,8 @@ Disable logging; same as \fB\-\-verbosity\-level\fP 0
Set verbosity level [0\-5]
.PP
.SH COPYRIGHT
Copyright \(co 2008 \- 2009 Alexander Shaduri <ashaduri \'at\' gmail.com>
Copyright \(co 2008 \- 2021 Alexander Shaduri <ashaduri@gmail.com>
.PP
.SH AUTHOR
This manual page was originally written by Giuseppe Iuculano
<giuseppe@iuculano.it>, for the Debian project.
<giuseppe@iuculano.it> for the Debian project.
+26
View File
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE policyconfig PUBLIC
"-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
"http://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd">
<!--
License: BSD Zero Clause License file
Copyright:
(C) 2008 - 2021 GSmartControl developers
-->
<policyconfig>
<action id="org.gsmartcontrol">
<message>Authentication is required to run GSmartControl</message>
<icon_name>gsmartcontrol</icon_name>
<defaults>
<allow_any>auth_admin</allow_any>
<allow_inactive>auth_admin</allow_inactive>
<allow_active>auth_admin</allow_active>
</defaults>
<annotate key="org.freedesktop.policykit.exec.path">@CMAKE_INSTALL_FULL_SBINDIR@/gsmartcontrol</annotate>
<annotate key="org.freedesktop.policykit.exec.allow_gui">true</annotate>
</action>
</policyconfig>
+74
View File
@@ -0,0 +1,74 @@
###############################################################################
# License: BSD Zero Clause License file
# Copyright:
# (C) 2021 - 2024 Alexander Shaduri <ashaduri@gmail.com>
###############################################################################
# Disable all warnings
if (${CMAKE_CXX_COMPILER_ID} STREQUAL Clang
OR ${CMAKE_CXX_COMPILER_ID} STREQUAL GNU
OR ${CMAKE_CXX_COMPILER_ID} STREQUAL AppleClang)
add_compile_options(-w)
elseif (${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC)
add_compile_options(/w)
endif()
find_package(PkgConfig REQUIRED) # pkg_check_modules()
# Gtkmm.
# Don't make it REQUIRED, we may want to build only the parsers
pkg_check_modules(Gtkmm REQUIRED IMPORTED_TARGET GLOBAL "gtkmm-3.0>=3.0")
add_library(app_gtkmm_interface INTERFACE)
target_link_libraries(app_gtkmm_interface
INTERFACE
PkgConfig::Gtkmm
)
target_compile_definitions(app_gtkmm_interface
INTERFACE
ENABLE_GLIB=1
ENABLE_GLIBMM=1
# For porting to GTK4
# GTK_DISABLE_DEPRECATED=1
# GDK_DISABLE_DEPRECATED=1
# GTKMM_DISABLE_DEPRECATED=1
# GDKMM_DISABLE_DEPRECATED=1
# GLIBMM_DISABLE_DEPRECATED=1
# GIOMM_DISABLE_DEPRECATED=1
)
# Support pre-C++17 glibmm with throw(...) exception specifications
pkg_check_modules(Glibmm "glibmm-2.4")
if ("${Glibmm_VERSION}" VERSION_LESS "2.50.1")
target_compile_definitions(app_gtkmm_interface INTERFACE "APP_GLIBMM_USES_THROW")
message(STATUS "Enabling old glibmm throw(...) workaround")
endif()
# Gettext libintl
find_package(Intl REQUIRED)
add_library(app_gettext_interface INTERFACE)
if (Intl_INCLUDE_DIRS)
target_include_directories(app_gettext_interface
SYSTEM INTERFACE
${Intl_INCLUDE_DIRS}
)
endif()
if (Intl_LIBRARIES)
target_link_libraries(app_gettext_interface
INTERFACE
${Intl_LIBRARIES}
)
endif()
# Gettext binaries and macros.
# See https://cmake.org/cmake/help/v3.15/module/FindGettext.html
# find_package(Gettext REQUIRED)
add_subdirectory(catch2)
add_subdirectory(fmt)
add_subdirectory(nlohmann_json)
add_subdirectory(whereami)
add_subdirectory(tl_expected)
+22
View File
@@ -0,0 +1,22 @@
###############################################################################
# License: BSD Zero Clause License file
# Copyright:
# (C) 2021 Alexander Shaduri <ashaduri@gmail.com>
###############################################################################
#add_subdirectory(Catch2)
add_library(Catch2 INTERFACE)
# Relative sources are allowed only since cmake 3.13.
target_sources(Catch2 INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}/Catch2/single_include/catch2/catch.hpp
)
target_include_directories(Catch2
SYSTEM INTERFACE
"${CMAKE_SOURCE_DIR}/dependencies/catch2/Catch2/single_include"
)
+25
View File
@@ -0,0 +1,25 @@
---
AccessModifierOffset: '-4'
AlignEscapedNewlines: Left
AllowAllConstructorInitializersOnNextLine: 'true'
BinPackArguments: 'false'
BinPackParameters: 'false'
BreakConstructorInitializers: AfterColon
ConstructorInitializerAllOnOneLineOrOnePerLine: 'true'
DerivePointerAlignment: 'false'
FixNamespaceComments: 'true'
IncludeBlocks: Regroup
IndentCaseLabels: 'false'
IndentPPDirectives: AfterHash
IndentWidth: '4'
Language: Cpp
NamespaceIndentation: All
PointerAlignment: Left
SpaceBeforeCtorInitializerColon: 'false'
SpaceInEmptyParentheses: 'false'
SpacesInParentheses: 'true'
Standard: Cpp11
TabWidth: '4'
UseTab: Never
...
+22
View File
@@ -0,0 +1,22 @@
# This sets the default behaviour, overriding core.autocrlf
* text=auto
# All source files should have unix line-endings in the repository,
# but convert to native line-endings on checkout
*.cpp text
*.h text
*.hpp text
# Windows specific files should retain windows line-endings
*.sln text eol=crlf
# Keep executable scripts with LFs so they can be run after being
# checked out on Windows
*.py text eol=lf
# Keep the single include header with LFs to make sure it is uploaded,
# hashed etc with LF
single_include/**/*.hpp eol=lf
# Also keep the LICENCE file with LFs for the same reason
LICENCE.txt eol=lf
+31
View File
@@ -0,0 +1,31 @@
*.build
*.pbxuser
*.mode1v3
*.ncb
*.suo
Debug
Release
*.user
*.xcuserstate
.DS_Store
xcuserdata
CatchSelfTest.xcscheme
Breakpoints.xcbkptlist
projects/VS2010/TestCatch/_UpgradeReport_Files/
projects/VS2010/TestCatch/TestCatch/TestCatch.vcxproj.filters
projects/VisualStudio/TestCatch/UpgradeLog.XML
projects/CMake/.idea
projects/CMake/cmake-build-debug
UpgradeLog.XML
Resources/DWARF
projects/Generated
*.pyc
DerivedData
*.xccheckout
Build
.idea
.vs
cmake-build-*
benchmark-dir
.conan/test_package/build
bazel-*
+37
View File
@@ -0,0 +1,37 @@
<a id="top"></a>
![catch logo](artwork/catch2-logo-small.png)
[![Github Releases](https://img.shields.io/github/release/catchorg/catch2.svg)](https://github.com/catchorg/catch2/releases)
[![Build Status](https://travis-ci.org/catchorg/Catch2.svg?branch=v2.x)](https://travis-ci.org/catchorg/Catch2)
[![Build status](https://ci.appveyor.com/api/projects/status/github/catchorg/Catch2?svg=true)](https://ci.appveyor.com/project/catchorg/catch2)
[![codecov](https://codecov.io/gh/catchorg/Catch2/branch/v2.x/graph/badge.svg)](https://codecov.io/gh/catchorg/Catch2)
[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/6JUH8Eybx4CtvkJS)
[![Join the chat in Discord: https://discord.gg/4CWS9zD](https://img.shields.io/badge/Discord-Chat!-brightgreen.svg)](https://discord.gg/4CWS9zD)
<a href="https://github.com/catchorg/Catch2/releases/download/v2.13.10/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
## Catch2 is released!
If you've been using an earlier version of Catch, please see the
Breaking Changes section of [the release notes](https://github.com/catchorg/Catch2/releases/tag/v2.0.1)
before moving to Catch2. You might also like to read [this blog post](https://levelofindirection.com/blog/catch2-released.html) for more details.
## What's the Catch?
Catch2 is a multi-paradigm test framework for C++. which also supports
Objective-C (and maybe C).
It is primarily distributed as a single header file, although certain
extensions may require additional headers.
## How to use it
This documentation comprises these three parts:
* [Why do we need yet another C++ Test Framework?](docs/why-catch.md#top)
* [Tutorial](docs/tutorial.md#top) - getting started
* [Reference section](docs/Readme.md#top) - all the details
## More
* Issues and bugs can be raised on the [Issue tracker on GitHub](https://github.com/catchorg/Catch2/issues)
* For discussion or questions please use [the dedicated Google Groups forum](https://groups.google.com/forum/?fromgroups#!forum/catch-forum) or our [Discord](https://discord.gg/4CWS9zD)
* See [who else is using Catch2](docs/opensource-users.md#top)
+206
View File
@@ -0,0 +1,206 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
#[=======================================================================[.rst:
Catch
-----
This module defines a function to help use the Catch test framework.
The :command:`catch_discover_tests` discovers tests by asking the compiled test
executable to enumerate its tests. This does not require CMake to be re-run
when tests change. However, it may not work in a cross-compiling environment,
and setting test properties is less convenient.
This command is intended to replace use of :command:`add_test` to register
tests, and will create a separate CTest test for each Catch test case. Note
that this is in some cases less efficient, as common set-up and tear-down logic
cannot be shared by multiple test cases executing in the same instance.
However, it provides more fine-grained pass/fail information to CTest, which is
usually considered as more beneficial. By default, the CTest test name is the
same as the Catch name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``.
.. command:: catch_discover_tests
Automatically add tests with CTest by querying the compiled test executable
for available tests::
catch_discover_tests(target
[TEST_SPEC arg1...]
[EXTRA_ARGS arg1...]
[WORKING_DIRECTORY dir]
[TEST_PREFIX prefix]
[TEST_SUFFIX suffix]
[PROPERTIES name1 value1...]
[TEST_LIST var]
[REPORTER reporter]
[OUTPUT_DIR dir]
[OUTPUT_PREFIX prefix}
[OUTPUT_SUFFIX suffix]
)
``catch_discover_tests`` sets up a post-build command on the test executable
that generates the list of tests by parsing the output from running the test
with the ``--list-test-names-only`` argument. This ensures that the full
list of tests is obtained. Since test discovery occurs at build time, it is
not necessary to re-run CMake when the list of tests changes.
However, it requires that :prop_tgt:`CROSSCOMPILING_EMULATOR` is properly set
in order to function in a cross-compiling environment.
Additionally, setting properties on tests is somewhat less convenient, since
the tests are not available at CMake time. Additional test properties may be
assigned to the set of tests as a whole using the ``PROPERTIES`` option. If
more fine-grained test control is needed, custom content may be provided
through an external CTest script using the :prop_dir:`TEST_INCLUDE_FILES`
directory property. The set of discovered tests is made accessible to such a
script via the ``<target>_TESTS`` variable.
The options are:
``target``
Specifies the Catch executable, which must be a known CMake executable
target. CMake will substitute the location of the built executable when
running the test.
``TEST_SPEC arg1...``
Specifies test cases, wildcarded test cases, tags and tag expressions to
pass to the Catch executable with the ``--list-test-names-only`` argument.
``EXTRA_ARGS arg1...``
Any extra arguments to pass on the command line to each test case.
``WORKING_DIRECTORY dir``
Specifies the directory in which to run the discovered test cases. If this
option is not provided, the current binary directory is used.
``TEST_PREFIX prefix``
Specifies a ``prefix`` to be prepended to the name of each discovered test
case. This can be useful when the same test executable is being used in
multiple calls to ``catch_discover_tests()`` but with different
``TEST_SPEC`` or ``EXTRA_ARGS``.
``TEST_SUFFIX suffix``
Similar to ``TEST_PREFIX`` except the ``suffix`` is appended to the name of
every discovered test case. Both ``TEST_PREFIX`` and ``TEST_SUFFIX`` may
be specified.
``PROPERTIES name1 value1...``
Specifies additional properties to be set on all tests discovered by this
invocation of ``catch_discover_tests``.
``TEST_LIST var``
Make the list of tests available in the variable ``var``, rather than the
default ``<target>_TESTS``. This can be useful when the same test
executable is being used in multiple calls to ``catch_discover_tests()``.
Note that this variable is only available in CTest.
``REPORTER reporter``
Use the specified reporter when running the test case. The reporter will
be passed to the Catch executable as ``--reporter reporter``.
``OUTPUT_DIR dir``
If specified, the parameter is passed along as
``--out dir/<test_name>`` to Catch executable. The actual file name is the
same as the test name. This should be used instead of
``EXTRA_ARGS --out foo`` to avoid race conditions writing the result output
when using parallel test execution.
``OUTPUT_PREFIX prefix``
May be used in conjunction with ``OUTPUT_DIR``.
If specified, ``prefix`` is added to each output file name, like so
``--out dir/prefix<test_name>``.
``OUTPUT_SUFFIX suffix``
May be used in conjunction with ``OUTPUT_DIR``.
If specified, ``suffix`` is added to each output file name, like so
``--out dir/<test_name>suffix``. This can be used to add a file extension to
the output e.g. ".xml".
#]=======================================================================]
#------------------------------------------------------------------------------
function(catch_discover_tests TARGET)
cmake_parse_arguments(
""
""
"TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST;REPORTER;OUTPUT_DIR;OUTPUT_PREFIX;OUTPUT_SUFFIX"
"TEST_SPEC;EXTRA_ARGS;PROPERTIES"
${ARGN}
)
if(NOT _WORKING_DIRECTORY)
set(_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
endif()
if(NOT _TEST_LIST)
set(_TEST_LIST ${TARGET}_TESTS)
endif()
## Generate a unique name based on the extra arguments
string(SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS} ${_REPORTER} ${_OUTPUT_DIR} ${_OUTPUT_PREFIX} ${_OUTPUT_SUFFIX}")
string(SUBSTRING ${args_hash} 0 7 args_hash)
# Define rule to generate test list for aforementioned test executable
set(ctest_include_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_include-${args_hash}.cmake")
set(ctest_tests_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_tests-${args_hash}.cmake")
get_property(crosscompiling_emulator
TARGET ${TARGET}
PROPERTY CROSSCOMPILING_EMULATOR
)
add_custom_command(
TARGET ${TARGET} POST_BUILD
BYPRODUCTS "${ctest_tests_file}"
COMMAND "${CMAKE_COMMAND}"
-D "TEST_TARGET=${TARGET}"
-D "TEST_EXECUTABLE=$<TARGET_FILE:${TARGET}>"
-D "TEST_EXECUTOR=${crosscompiling_emulator}"
-D "TEST_WORKING_DIR=${_WORKING_DIRECTORY}"
-D "TEST_SPEC=${_TEST_SPEC}"
-D "TEST_EXTRA_ARGS=${_EXTRA_ARGS}"
-D "TEST_PROPERTIES=${_PROPERTIES}"
-D "TEST_PREFIX=${_TEST_PREFIX}"
-D "TEST_SUFFIX=${_TEST_SUFFIX}"
-D "TEST_LIST=${_TEST_LIST}"
-D "TEST_REPORTER=${_REPORTER}"
-D "TEST_OUTPUT_DIR=${_OUTPUT_DIR}"
-D "TEST_OUTPUT_PREFIX=${_OUTPUT_PREFIX}"
-D "TEST_OUTPUT_SUFFIX=${_OUTPUT_SUFFIX}"
-D "CTEST_FILE=${ctest_tests_file}"
-P "${_CATCH_DISCOVER_TESTS_SCRIPT}"
VERBATIM
)
file(WRITE "${ctest_include_file}"
"if(EXISTS \"${ctest_tests_file}\")\n"
" include(\"${ctest_tests_file}\")\n"
"else()\n"
" add_test(${TARGET}_NOT_BUILT-${args_hash} ${TARGET}_NOT_BUILT-${args_hash})\n"
"endif()\n"
)
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.10.0")
# Add discovered tests to directory TEST_INCLUDE_FILES
set_property(DIRECTORY
APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file}"
)
else()
# Add discovered tests as directory TEST_INCLUDE_FILE if possible
get_property(test_include_file_set DIRECTORY PROPERTY TEST_INCLUDE_FILE SET)
if (NOT ${test_include_file_set})
set_property(DIRECTORY
PROPERTY TEST_INCLUDE_FILE "${ctest_include_file}"
)
else()
message(FATAL_ERROR
"Cannot set more than one TEST_INCLUDE_FILE"
)
endif()
endif()
endfunction()
###############################################################################
set(_CATCH_DISCOVER_TESTS_SCRIPT
${CMAKE_CURRENT_LIST_DIR}/CatchAddTests.cmake
CACHE INTERNAL "Catch2 full path to CatchAddTests.cmake helper file"
)
+135
View File
@@ -0,0 +1,135 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
set(prefix "${TEST_PREFIX}")
set(suffix "${TEST_SUFFIX}")
set(spec ${TEST_SPEC})
set(extra_args ${TEST_EXTRA_ARGS})
set(properties ${TEST_PROPERTIES})
set(reporter ${TEST_REPORTER})
set(output_dir ${TEST_OUTPUT_DIR})
set(output_prefix ${TEST_OUTPUT_PREFIX})
set(output_suffix ${TEST_OUTPUT_SUFFIX})
set(script)
set(suite)
set(tests)
function(add_command NAME)
set(_args "")
# use ARGV* instead of ARGN, because ARGN splits arrays into multiple arguments
math(EXPR _last_arg ${ARGC}-1)
foreach(_n RANGE 1 ${_last_arg})
set(_arg "${ARGV${_n}}")
if(_arg MATCHES "[^-./:a-zA-Z0-9_]")
set(_args "${_args} [==[${_arg}]==]") # form a bracket_argument
else()
set(_args "${_args} ${_arg}")
endif()
endforeach()
set(script "${script}${NAME}(${_args})\n" PARENT_SCOPE)
endfunction()
# Run test executable to get list of available tests
if(NOT EXISTS "${TEST_EXECUTABLE}")
message(FATAL_ERROR
"Specified test executable '${TEST_EXECUTABLE}' does not exist"
)
endif()
execute_process(
COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-test-names-only
OUTPUT_VARIABLE output
RESULT_VARIABLE result
WORKING_DIRECTORY "${TEST_WORKING_DIR}"
)
# Catch --list-test-names-only reports the number of tests, so 0 is... surprising
if(${result} EQUAL 0)
message(WARNING
"Test executable '${TEST_EXECUTABLE}' contains no tests!\n"
)
elseif(${result} LESS 0)
message(FATAL_ERROR
"Error running test executable '${TEST_EXECUTABLE}':\n"
" Result: ${result}\n"
" Output: ${output}\n"
)
endif()
string(REPLACE "\n" ";" output "${output}")
# Run test executable to get list of available reporters
execute_process(
COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-reporters
OUTPUT_VARIABLE reporters_output
RESULT_VARIABLE reporters_result
WORKING_DIRECTORY "${TEST_WORKING_DIR}"
)
if(${reporters_result} EQUAL 0)
message(WARNING
"Test executable '${TEST_EXECUTABLE}' contains no reporters!\n"
)
elseif(${reporters_result} LESS 0)
message(FATAL_ERROR
"Error running test executable '${TEST_EXECUTABLE}':\n"
" Result: ${reporters_result}\n"
" Output: ${reporters_output}\n"
)
endif()
string(FIND "${reporters_output}" "${reporter}" reporter_is_valid)
if(reporter AND ${reporter_is_valid} EQUAL -1)
message(FATAL_ERROR
"\"${reporter}\" is not a valid reporter!\n"
)
endif()
# Prepare reporter
if(reporter)
set(reporter_arg "--reporter ${reporter}")
endif()
# Prepare output dir
if(output_dir AND NOT IS_ABSOLUTE ${output_dir})
set(output_dir "${TEST_WORKING_DIR}/${output_dir}")
if(NOT EXISTS ${output_dir})
file(MAKE_DIRECTORY ${output_dir})
endif()
endif()
# Parse output
foreach(line ${output})
set(test ${line})
# Escape characters in test case names that would be parsed by Catch2
set(test_name ${test})
foreach(char , [ ])
string(REPLACE ${char} "\\${char}" test_name ${test_name})
endforeach(char)
# ...add output dir
if(output_dir)
string(REGEX REPLACE "[^A-Za-z0-9_]" "_" test_name_clean ${test_name})
set(output_dir_arg "--out ${output_dir}/${output_prefix}${test_name_clean}${output_suffix}")
endif()
# ...and add to script
add_command(add_test
"${prefix}${test}${suffix}"
${TEST_EXECUTOR}
"${TEST_EXECUTABLE}"
"${test_name}"
${extra_args}
"${reporter_arg}"
"${output_dir_arg}"
)
add_command(set_tests_properties
"${prefix}${test}${suffix}"
PROPERTIES
WORKING_DIRECTORY "${TEST_WORKING_DIR}"
${properties}
)
list(APPEND tests "${prefix}${test}${suffix}")
endforeach()
# Create a list of all discovered tests, which users may use to e.g. set
# properties on the tests
add_command(set ${TEST_LIST} ${tests})
# Write CTest script
file(WRITE "${CTEST_FILE}" "${script}")
@@ -0,0 +1,252 @@
#==================================================================================================#
# supported macros #
# - TEST_CASE, #
# - TEMPLATE_TEST_CASE #
# - SCENARIO, #
# - TEST_CASE_METHOD, #
# - CATCH_TEST_CASE, #
# - CATCH_TEMPLATE_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
# https://regex101.com/r/JygOND/1
string(REGEX MATCHALL "[ \t]*(CATCH_)?(TEMPLATE_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([ \t\n]*\"[^\"]*\"[ \t\n]*(,[ \t\n]*\"[^\"]*\")?(,[ \t\n]*[^\,\)]*)*\\)[ \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()
# check CMP0110 policy for new add_test() behavior
if(POLICY CMP0110)
cmake_policy(GET CMP0110 _cmp0110_value) # new add_test() behavior
else()
# just to be thorough explicitly set the variable
set(_cmp0110_value)
endif()
foreach(TestName ${Tests})
# Strip newlines
string(REGEX REPLACE "\\\\\n|\n" "" TestName "${TestName}")
# Get test type and fixture if applicable
string(REGEX MATCH "(CATCH_)?(TEMPLATE_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^,^\"]*" TestTypeAndFixture "${TestName}")
string(REGEX MATCH "(CATCH_)?(TEMPLATE_)?(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 necessary,
# only with CMake 3.18.0 the escaped double quotes confuse the call. This change is reverted in 3.18.1
# And properly introduced in 3.19 with the CMP0110 policy
if(_cmp0110_value STREQUAL "NEW" OR ${CMAKE_VERSION} VERSION_EQUAL "3.18")
ParseAndAddCatchTests_PrintDebugMessage("CMP0110 set to NEW, no need for add_test(\"\") workaround")
else()
ParseAndAddCatchTests_PrintDebugMessage("CMP0110 set to OLD adding \"\" for add_test() workaround")
set(CTestName "\"${CTestName}\"")
endif()
# Handle template test cases
if("${TestTypeAndFixture}" MATCHES ".*TEMPLATE_.*")
set(Name "${Name} - *")
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)
message(DEPRECATION "ParseAndAddCatchTest: function deprecated because of possibility of missed test cases. Consider using 'catch_discover_tests' from 'Catch.cmake'")
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()
File diff suppressed because it is too large Load Diff
+2
View File
@@ -0,0 +1,2 @@
Catch2 v2.13.10.
https://github.com/catchorg/Catch2
+32
View File
@@ -0,0 +1,32 @@
###############################################################################
# License: BSD Zero Clause License file
# Copyright:
# (C) 2025 Alexander Shaduri <ashaduri@gmail.com>
###############################################################################
add_library(fmt STATIC)
# Relative sources are allowed only since cmake 3.13.
target_sources(fmt PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/fmt/src/format.cc
${CMAKE_CURRENT_SOURCE_DIR}/fmt/include/fmt/args.h
${CMAKE_CURRENT_SOURCE_DIR}/fmt/include/fmt/base.h
${CMAKE_CURRENT_SOURCE_DIR}/fmt/include/fmt/chrono.h
${CMAKE_CURRENT_SOURCE_DIR}/fmt/include/fmt/color.h
${CMAKE_CURRENT_SOURCE_DIR}/fmt/include/fmt/compile.h
${CMAKE_CURRENT_SOURCE_DIR}/fmt/include/fmt/core.h
${CMAKE_CURRENT_SOURCE_DIR}/fmt/include/fmt/format.h
${CMAKE_CURRENT_SOURCE_DIR}/fmt/include/fmt/format-inl.h
${CMAKE_CURRENT_SOURCE_DIR}/fmt/include/fmt/os.h
${CMAKE_CURRENT_SOURCE_DIR}/fmt/include/fmt/ostream.h
${CMAKE_CURRENT_SOURCE_DIR}/fmt/include/fmt/printf.h
${CMAKE_CURRENT_SOURCE_DIR}/fmt/include/fmt/ranges.h
${CMAKE_CURRENT_SOURCE_DIR}/fmt/include/fmt/std.h
${CMAKE_CURRENT_SOURCE_DIR}/fmt/include/fmt/xchar.h
)
target_include_directories(fmt
SYSTEM PUBLIC
"fmt/include"
)
+27
View File
@@ -0,0 +1,27 @@
Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
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.
--- Optional exception to the license ---
As an exception, if, as a result of your compiling your source code, portions
of this Software are embedded into a machine-executable object form of such
source code, you may redistribute such embedded portions in such object form
without including the above copyright and permission notices.
+485
View File
@@ -0,0 +1,485 @@
<img src="https://user-images.githubusercontent.com/576385/156254208-f5b743a9-88cf-439d-b0c0-923d53e8d551.png" alt="{fmt}" width="25%"/>
[![image](https://github.com/fmtlib/fmt/workflows/linux/badge.svg)](https://github.com/fmtlib/fmt/actions?query=workflow%3Alinux)
[![image](https://github.com/fmtlib/fmt/workflows/macos/badge.svg)](https://github.com/fmtlib/fmt/actions?query=workflow%3Amacos)
[![image](https://github.com/fmtlib/fmt/workflows/windows/badge.svg)](https://github.com/fmtlib/fmt/actions?query=workflow%3Awindows)
[![fmt is continuously fuzzed at oss-fuzz](https://oss-fuzz-build-logs.storage.googleapis.com/badges/fmt.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?\%0Acolspec=ID%20Type%20Component%20Status%20Proj%20Reported%20Owner%20\%0ASummary&q=proj%3Dfmt&can=1)
[![Ask questions at StackOverflow with the tag fmt](https://img.shields.io/badge/stackoverflow-fmt-blue.svg)](https://stackoverflow.com/questions/tagged/fmt)
[![image](https://api.securityscorecards.dev/projects/github.com/fmtlib/fmt/badge)](https://securityscorecards.dev/viewer/?uri=github.com/fmtlib/fmt)
**{fmt}** is an open-source formatting library providing a fast and safe
alternative to C stdio and C++ iostreams.
If you like this project, please consider donating to one of the funds
that help victims of the war in Ukraine: <https://www.stopputin.net/>.
[Documentation](https://fmt.dev)
[Cheat Sheets](https://hackingcpp.com/cpp/libs/fmt.html)
Q&A: ask questions on [StackOverflow with the tag
fmt](https://stackoverflow.com/questions/tagged/fmt).
Try {fmt} in [Compiler Explorer](https://godbolt.org/z/8Mx1EW73v).
# Features
- Simple [format API](https://fmt.dev/latest/api/) with positional
arguments for localization
- Implementation of [C++20
std::format](https://en.cppreference.com/w/cpp/utility/format) and
[C++23 std::print](https://en.cppreference.com/w/cpp/io/print)
- [Format string syntax](https://fmt.dev/latest/syntax/) similar
to Python\'s
[format](https://docs.python.org/3/library/stdtypes.html#str.format)
- Fast IEEE 754 floating-point formatter with correct rounding,
shortness and round-trip guarantees using the
[Dragonbox](https://github.com/jk-jeon/dragonbox) algorithm
- Portable Unicode support
- Safe [printf
implementation](https://fmt.dev/latest/api/#printf-formatting)
including the POSIX extension for positional arguments
- Extensibility: [support for user-defined
types](https://fmt.dev/latest/api/#formatting-user-defined-types)
- High performance: faster than common standard library
implementations of `(s)printf`, iostreams, `to_string` and
`to_chars`, see [Speed tests](#speed-tests) and [Converting a
hundred million integers to strings per
second](http://www.zverovich.net/2020/06/13/fast-int-to-string-revisited.html)
- Small code size both in terms of source code with the minimum
configuration consisting of just three files, `core.h`, `format.h`
and `format-inl.h`, and compiled code; see [Compile time and code
bloat](#compile-time-and-code-bloat)
- Reliability: the library has an extensive set of
[tests](https://github.com/fmtlib/fmt/tree/master/test) and is
[continuously fuzzed](https://bugs.chromium.org/p/oss-fuzz/issues/list?colspec=ID%20Type%20Component%20Status%20Proj%20Reported%20Owner%20Summary&q=proj%3Dfmt&can=1)
- Safety: the library is fully type-safe, errors in format strings can
be reported at compile time, automatic memory management prevents
buffer overflow errors
- Ease of use: small self-contained code base, no external
dependencies, permissive MIT
[license](https://github.com/fmtlib/fmt/blob/master/LICENSE)
- [Portability](https://fmt.dev/latest/#portability) with
consistent output across platforms and support for older compilers
- Clean warning-free codebase even on high warning levels such as
`-Wall -Wextra -pedantic`
- Locale independence by default
- Optional header-only configuration enabled with the
`FMT_HEADER_ONLY` macro
See the [documentation](https://fmt.dev) for more details.
# Examples
**Print to stdout** ([run](https://godbolt.org/z/Tevcjh))
``` c++
#include <fmt/core.h>
int main() {
fmt::print("Hello, world!\n");
}
```
**Format a string** ([run](https://godbolt.org/z/oK8h33))
``` c++
std::string s = fmt::format("The answer is {}.", 42);
// s == "The answer is 42."
```
**Format a string using positional arguments**
([run](https://godbolt.org/z/Yn7Txe))
``` c++
std::string s = fmt::format("I'd rather be {1} than {0}.", "right", "happy");
// s == "I'd rather be happy than right."
```
**Print dates and times** ([run](https://godbolt.org/z/c31ExdY3W))
``` c++
#include <fmt/chrono.h>
int main() {
auto now = std::chrono::system_clock::now();
fmt::print("Date and time: {}\n", now);
fmt::print("Time: {:%H:%M}\n", now);
}
```
Output:
Date and time: 2023-12-26 19:10:31.557195597
Time: 19:10
**Print a container** ([run](https://godbolt.org/z/MxM1YqjE7))
``` c++
#include <vector>
#include <fmt/ranges.h>
int main() {
std::vector<int> v = {1, 2, 3};
fmt::print("{}\n", v);
}
```
Output:
[1, 2, 3]
**Check a format string at compile time**
``` c++
std::string s = fmt::format("{:d}", "I am not a number");
```
This gives a compile-time error in C++20 because `d` is an invalid
format specifier for a string.
**Write a file from a single thread**
``` c++
#include <fmt/os.h>
int main() {
auto out = fmt::output_file("guide.txt");
out.print("Don't {}", "Panic");
}
```
This can be [5 to 9 times faster than
fprintf](http://www.zverovich.net/2020/08/04/optimal-file-buffer-size.html).
**Print with colors and text styles**
``` c++
#include <fmt/color.h>
int main() {
fmt::print(fg(fmt::color::crimson) | fmt::emphasis::bold,
"Hello, {}!\n", "world");
fmt::print(fg(fmt::color::floral_white) | bg(fmt::color::slate_gray) |
fmt::emphasis::underline, "Olá, {}!\n", "Mundo");
fmt::print(fg(fmt::color::steel_blue) | fmt::emphasis::italic,
"你好{}!\n", "世界");
}
```
Output on a modern terminal with Unicode support:
![image](https://github.com/fmtlib/fmt/assets/%0A576385/2a93c904-d6fa-4aa6-b453-2618e1c327d7)
# Benchmarks
## Speed tests
| Library | Method | Run Time, s |
|-------------------|---------------|-------------|
| libc | printf | 0.91 |
| libc++ | std::ostream | 2.49 |
| {fmt} 9.1 | fmt::print | 0.74 |
| Boost Format 1.80 | boost::format | 6.26 |
| Folly Format | folly::format | 1.87 |
{fmt} is the fastest of the benchmarked methods, \~20% faster than
`printf`.
The above results were generated by building `tinyformat_test.cpp` on
macOS 12.6.1 with `clang++ -O3 -DNDEBUG -DSPEED_TEST -DHAVE_FORMAT`, and
taking the best of three runs. In the test, the format string
`"%0.10f:%04d:%+g:%s:%p:%c:%%\n"` or equivalent is filled 2,000,000
times with output sent to `/dev/null`; for further details refer to the
[source](https://github.com/fmtlib/format-benchmark/blob/master/src/tinyformat-test.cc).
{fmt} is up to 20-30x faster than `std::ostringstream` and `sprintf` on
IEEE754 `float` and `double` formatting
([dtoa-benchmark](https://github.com/fmtlib/dtoa-benchmark)) and faster
than [double-conversion](https://github.com/google/double-conversion)
and [ryu](https://github.com/ulfjack/ryu):
[![image](https://user-images.githubusercontent.com/576385/95684665-11719600-0ba8-11eb-8e5b-972ff4e49428.png)](https://fmt.dev/unknown_mac64_clang12.0.html)
## Compile time and code bloat
The script [bloat-test.py][test] from [format-benchmark][bench] tests compile
time and code bloat for nontrivial projects. It generates 100 translation units
and uses `printf()` or its alternative five times in each to simulate a
medium-sized project. The resulting executable size and compile time (Apple
clang version 15.0.0 (clang-1500.1.0.2.5), macOS Sonoma, best of three) is shown
in the following tables.
[test]: https://github.com/fmtlib/format-benchmark/blob/master/bloat-test.py
[bench]: https://github.com/fmtlib/format-benchmark
**Optimized build (-O3)**
| Method | Compile Time, s | Executable size, KiB | Stripped size, KiB |
|---------------|-----------------|----------------------|--------------------|
| printf | 1.6 | 54 | 50 |
| IOStreams | 25.9 | 98 | 84 |
| fmt 83652df | 4.8 | 54 | 50 |
| tinyformat | 29.1 | 161 | 136 |
| Boost Format | 55.0 | 530 | 317 |
{fmt} is fast to compile and is comparable to `printf` in terms of per-call
binary size (within a rounding error on this system).
**Non-optimized build**
| Method | Compile Time, s | Executable size, KiB | Stripped size, KiB |
|---------------|-----------------|----------------------|--------------------|
| printf | 1.4 | 54 | 50 |
| IOStreams | 23.4 | 92 | 68 |
| {fmt} 83652df | 4.4 | 89 | 85 |
| tinyformat | 24.5 | 204 | 161 |
| Boost Format | 36.4 | 831 | 462 |
`libc`, `lib(std)c++`, and `libfmt` are all linked as shared libraries
to compare formatting function overhead only. Boost Format is a
header-only library so it doesn\'t provide any linkage options.
## Running the tests
Please refer to [Building the
library](https://fmt.dev/latest/get-started/#building-from-source) for
instructions on how to build the library and run the unit tests.
Benchmarks reside in a separate repository,
[format-benchmarks](https://github.com/fmtlib/format-benchmark), so to
run the benchmarks you first need to clone this repository and generate
Makefiles with CMake:
$ git clone --recursive https://github.com/fmtlib/format-benchmark.git
$ cd format-benchmark
$ cmake .
Then you can run the speed test:
$ make speed-test
or the bloat test:
$ make bloat-test
# Migrating code
[clang-tidy](https://clang.llvm.org/extra/clang-tidy/) v18 provides the
[modernize-use-std-print](https://clang.llvm.org/extra/clang-tidy/checks/modernize/use-std-print.html)
check that is capable of converting occurrences of `printf` and
`fprintf` to `fmt::print` if configured to do so. (By default it
converts to `std::print`.)
# Notable projects using this library
- [0 A.D.](https://play0ad.com/): a free, open-source, cross-platform
real-time strategy game
- [AMPL/MP](https://github.com/ampl/mp): an open-source library for
mathematical programming
- [Apple's FoundationDB](https://github.com/apple/foundationdb): an open-source,
distributed, transactional key-value store
- [Aseprite](https://github.com/aseprite/aseprite): animated sprite
editor & pixel art tool
- [AvioBook](https://www.aviobook.aero/en): a comprehensive aircraft
operations suite
- [Blizzard Battle.net](https://battle.net/): an online gaming
platform
- [Celestia](https://celestia.space/): real-time 3D visualization of
space
- [Ceph](https://ceph.com/): a scalable distributed storage system
- [ccache](https://ccache.dev/): a compiler cache
- [ClickHouse](https://github.com/ClickHouse/ClickHouse): an
analytical database management system
- [ContextVision](https://www.contextvision.com/): medical imaging software
- [Contour](https://github.com/contour-terminal/contour/): a modern
terminal emulator
- [CUAUV](https://cuauv.org/): Cornell University\'s autonomous
underwater vehicle
- [Drake](https://drake.mit.edu/): a planning, control, and analysis
toolbox for nonlinear dynamical systems (MIT)
- [Envoy](https://github.com/envoyproxy/envoy): C++ L7 proxy and
communication bus (Lyft)
- [FiveM](https://fivem.net/): a modification framework for GTA V
- [fmtlog](https://github.com/MengRao/fmtlog): a performant
fmtlib-style logging library with latency in nanoseconds
- [Folly](https://github.com/facebook/folly): Facebook open-source
library
- [GemRB](https://gemrb.org/): a portable open-source implementation
of Bioware's Infinity Engine
- [Grand Mountain
Adventure](https://store.steampowered.com/app/1247360/Grand_Mountain_Adventure/):
a beautiful open-world ski & snowboarding game
- [HarpyWar/pvpgn](https://github.com/pvpgn/pvpgn-server): Player vs
Player Gaming Network with tweaks
- [KBEngine](https://github.com/kbengine/kbengine): an open-source
MMOG server engine
- [Keypirinha](https://keypirinha.com/): a semantic launcher for
Windows
- [Kodi](https://kodi.tv/) (formerly xbmc): home theater software
- [Knuth](https://kth.cash/): high-performance Bitcoin full-node
- [libunicode](https://github.com/contour-terminal/libunicode/): a
modern C++17 Unicode library
- [MariaDB](https://mariadb.org/): relational database management
system
- [Microsoft Verona](https://github.com/microsoft/verona): research
programming language for concurrent ownership
- [MongoDB](https://mongodb.com/): distributed document database
- [MongoDB Smasher](https://github.com/duckie/mongo_smasher): a small
tool to generate randomized datasets
- [OpenSpace](https://openspaceproject.com/): an open-source
astrovisualization framework
- [PenUltima Online (POL)](https://www.polserver.com/): an MMO server,
compatible with most Ultima Online clients
- [PyTorch](https://github.com/pytorch/pytorch): an open-source
machine learning library
- [quasardb](https://www.quasardb.net/): a distributed,
high-performance, associative database
- [Quill](https://github.com/odygrd/quill): asynchronous low-latency
logging library
- [QKW](https://github.com/ravijanjam/qkw): generalizing aliasing to
simplify navigation, and execute complex multi-line terminal
command sequences
- [redis-cerberus](https://github.com/HunanTV/redis-cerberus): a Redis
cluster proxy
- [redpanda](https://vectorized.io/redpanda): a 10x faster Kafka®
replacement for mission-critical systems written in C++
- [rpclib](http://rpclib.net/): a modern C++ msgpack-RPC server and
client library
- [Salesforce Analytics
Cloud](https://www.salesforce.com/analytics-cloud/overview/):
business intelligence software
- [Scylla](https://www.scylladb.com/): a Cassandra-compatible NoSQL
data store that can handle 1 million transactions per second on a
single server
- [Seastar](http://www.seastar-project.org/): an advanced, open-source
C++ framework for high-performance server applications on modern
hardware
- [spdlog](https://github.com/gabime/spdlog): super fast C++ logging
library
- [Stellar](https://www.stellar.org/): financial platform
- [Touch Surgery](https://www.touchsurgery.com/): surgery simulator
- [TrinityCore](https://github.com/TrinityCore/TrinityCore):
open-source MMORPG framework
- [🐙 userver framework](https://userver.tech/): open-source
asynchronous framework with a rich set of abstractions and database
drivers
- [Windows Terminal](https://github.com/microsoft/terminal): the new
Windows terminal
[More\...](https://github.com/search?q=fmtlib&type=Code)
If you are aware of other projects using this library, please let me
know by [email](mailto:victor.zverovich@gmail.com) or by submitting an
[issue](https://github.com/fmtlib/fmt/issues).
# Motivation
So why yet another formatting library?
There are plenty of methods for doing this task, from standard ones like
the printf family of function and iostreams to Boost Format and
FastFormat libraries. The reason for creating a new library is that
every existing solution that I found either had serious issues or
didn\'t provide all the features I needed.
## printf
The good thing about `printf` is that it is pretty fast and readily
available being a part of the C standard library. The main drawback is
that it doesn\'t support user-defined types. `printf` also has safety
issues although they are somewhat mitigated with [\_\_attribute\_\_
((format (printf,
\...))](https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html) in
GCC. There is a POSIX extension that adds positional arguments required
for
[i18n](https://en.wikipedia.org/wiki/Internationalization_and_localization)
to `printf` but it is not a part of C99 and may not be available on some
platforms.
## iostreams
The main issue with iostreams is best illustrated with an example:
``` c++
std::cout << std::setprecision(2) << std::fixed << 1.23456 << "\n";
```
which is a lot of typing compared to printf:
``` c++
printf("%.2f\n", 1.23456);
```
Matthew Wilson, the author of FastFormat, called this \"chevron hell\".
iostreams don\'t support positional arguments by design.
The good part is that iostreams support user-defined types and are safe
although error handling is awkward.
## Boost Format
This is a very powerful library that supports both `printf`-like format
strings and positional arguments. Its main drawback is performance.
According to various benchmarks, it is much slower than other methods
considered here. Boost Format also has excessive build times and severe
code bloat issues (see [Benchmarks](#benchmarks)).
## FastFormat
This is an interesting library that is fast, safe and has positional
arguments. However, it has significant limitations, citing its author:
> Three features that have no hope of being accommodated within the
> current design are:
>
> - Leading zeros (or any other non-space padding)
> - Octal/hexadecimal encoding
> - Runtime width/alignment specification
It is also quite big and has a heavy dependency, on STLSoft, which might be
too restrictive for use in some projects.
## Boost Spirit.Karma
This is not a formatting library but I decided to include it here for
completeness. As iostreams, it suffers from the problem of mixing
verbatim text with arguments. The library is pretty fast, but slower on
integer formatting than `fmt::format_to` with format string compilation
on Karma\'s own benchmark, see [Converting a hundred million integers to
strings per
second](http://www.zverovich.net/2020/06/13/fast-int-to-string-revisited.html).
# License
{fmt} is distributed under the MIT
[license](https://github.com/fmtlib/fmt/blob/master/LICENSE).
# Documentation License
The [Format String Syntax](https://fmt.dev/latest/syntax/) section
in the documentation is based on the one from Python [string module
documentation](https://docs.python.org/3/library/string.html#module-string).
For this reason, the documentation is distributed under the Python
Software Foundation license available in
[doc/python-license.txt](https://raw.github.com/fmtlib/fmt/master/doc/python-license.txt).
It only applies if you distribute the documentation of {fmt}.
# Maintainers
The {fmt} library is maintained by Victor Zverovich
([vitaut](https://github.com/vitaut)) with contributions from many other
people. See
[Contributors](https://github.com/fmtlib/fmt/graphs/contributors) and
[Releases](https://github.com/fmtlib/fmt/releases) for some of the
names. Let us know if your contribution is not listed or mentioned
incorrectly and we\'ll make it right.
# Security Policy
To report a security issue, please disclose it at [security
advisory](https://github.com/fmtlib/fmt/security/advisories/new).
This project is maintained by a team of volunteers on a
reasonable-effort basis. As such, please give us at least *90* days to
work on a fix before public exposure.
+220
View File
@@ -0,0 +1,220 @@
// Formatting library for C++ - dynamic argument lists
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_ARGS_H_
#define FMT_ARGS_H_
#ifndef FMT_MODULE
# include <functional> // std::reference_wrapper
# include <memory> // std::unique_ptr
# include <vector>
#endif
#include "format.h" // std_string_view
FMT_BEGIN_NAMESPACE
namespace detail {
template <typename T> struct is_reference_wrapper : std::false_type {};
template <typename T>
struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {};
template <typename T> auto unwrap(const T& v) -> const T& { return v; }
template <typename T>
auto unwrap(const std::reference_wrapper<T>& v) -> const T& {
return static_cast<const T&>(v);
}
// node is defined outside dynamic_arg_list to workaround a C2504 bug in MSVC
// 2022 (v17.10.0).
//
// Workaround for clang's -Wweak-vtables. Unlike for regular classes, for
// templates it doesn't complain about inability to deduce single translation
// unit for placing vtable. So node is made a fake template.
template <typename = void> struct node {
virtual ~node() = default;
std::unique_ptr<node<>> next;
};
class dynamic_arg_list {
template <typename T> struct typed_node : node<> {
T value;
template <typename Arg>
FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {}
template <typename Char>
FMT_CONSTEXPR typed_node(const basic_string_view<Char>& arg)
: value(arg.data(), arg.size()) {}
};
std::unique_ptr<node<>> head_;
public:
template <typename T, typename Arg> auto push(const Arg& arg) -> const T& {
auto new_node = std::unique_ptr<typed_node<T>>(new typed_node<T>(arg));
auto& value = new_node->value;
new_node->next = std::move(head_);
head_ = std::move(new_node);
return value;
}
};
} // namespace detail
/**
* A dynamic list of formatting arguments with storage.
*
* It can be implicitly converted into `fmt::basic_format_args` for passing
* into type-erased formatting functions such as `fmt::vformat`.
*/
template <typename Context> class dynamic_format_arg_store {
private:
using char_type = typename Context::char_type;
template <typename T> struct need_copy {
static constexpr detail::type mapped_type =
detail::mapped_type_constant<T, char_type>::value;
enum {
value = !(detail::is_reference_wrapper<T>::value ||
std::is_same<T, basic_string_view<char_type>>::value ||
std::is_same<T, detail::std_string_view<char_type>>::value ||
(mapped_type != detail::type::cstring_type &&
mapped_type != detail::type::string_type &&
mapped_type != detail::type::custom_type))
};
};
template <typename T>
using stored_t = conditional_t<
std::is_convertible<T, std::basic_string<char_type>>::value &&
!detail::is_reference_wrapper<T>::value,
std::basic_string<char_type>, T>;
// Storage of basic_format_arg must be contiguous.
std::vector<basic_format_arg<Context>> data_;
std::vector<detail::named_arg_info<char_type>> named_info_;
// Storage of arguments not fitting into basic_format_arg must grow
// without relocation because items in data_ refer to it.
detail::dynamic_arg_list dynamic_args_;
friend class basic_format_args<Context>;
auto data() const -> const basic_format_arg<Context>* {
return named_info_.empty() ? data_.data() : data_.data() + 1;
}
template <typename T> void emplace_arg(const T& arg) {
data_.emplace_back(arg);
}
template <typename T>
void emplace_arg(const detail::named_arg<char_type, T>& arg) {
if (named_info_.empty())
data_.insert(data_.begin(), basic_format_arg<Context>(nullptr, 0));
data_.emplace_back(detail::unwrap(arg.value));
auto pop_one = [](std::vector<basic_format_arg<Context>>* data) {
data->pop_back();
};
std::unique_ptr<std::vector<basic_format_arg<Context>>, decltype(pop_one)>
guard{&data_, pop_one};
named_info_.push_back({arg.name, static_cast<int>(data_.size() - 2u)});
data_[0] = {named_info_.data(), named_info_.size()};
guard.release();
}
public:
constexpr dynamic_format_arg_store() = default;
operator basic_format_args<Context>() const {
return basic_format_args<Context>(data(), static_cast<int>(data_.size()),
!named_info_.empty());
}
/**
* Adds an argument into the dynamic store for later passing to a formatting
* function.
*
* Note that custom types and string types (but not string views) are copied
* into the store dynamically allocating memory if necessary.
*
* **Example**:
*
* fmt::dynamic_format_arg_store<fmt::format_context> store;
* store.push_back(42);
* store.push_back("abc");
* store.push_back(1.5f);
* std::string result = fmt::vformat("{} and {} and {}", store);
*/
template <typename T> void push_back(const T& arg) {
if (detail::const_check(need_copy<T>::value))
emplace_arg(dynamic_args_.push<stored_t<T>>(arg));
else
emplace_arg(detail::unwrap(arg));
}
/**
* Adds a reference to the argument into the dynamic store for later passing
* to a formatting function.
*
* **Example**:
*
* fmt::dynamic_format_arg_store<fmt::format_context> store;
* char band[] = "Rolling Stones";
* store.push_back(std::cref(band));
* band[9] = 'c'; // Changing str affects the output.
* std::string result = fmt::vformat("{}", store);
* // result == "Rolling Scones"
*/
template <typename T> void push_back(std::reference_wrapper<T> arg) {
static_assert(
need_copy<T>::value,
"objects of built-in types and string views are always copied");
emplace_arg(arg.get());
}
/**
* Adds named argument into the dynamic store for later passing to a
* formatting function. `std::reference_wrapper` is supported to avoid
* copying of the argument. The name is always copied into the store.
*/
template <typename T>
void push_back(const detail::named_arg<char_type, T>& arg) {
const char_type* arg_name =
dynamic_args_.push<std::basic_string<char_type>>(arg.name).c_str();
if (detail::const_check(need_copy<T>::value)) {
emplace_arg(
fmt::arg(arg_name, dynamic_args_.push<stored_t<T>>(arg.value)));
} else {
emplace_arg(fmt::arg(arg_name, arg.value));
}
}
/// Erase all elements from the store.
void clear() {
data_.clear();
named_info_.clear();
dynamic_args_ = {};
}
/// Reserves space to store at least `new_cap` arguments including
/// `new_cap_named` named arguments.
void reserve(size_t new_cap, size_t new_cap_named) {
FMT_ASSERT(new_cap >= new_cap_named,
"set of arguments includes set of named arguments");
data_.reserve(new_cap);
named_info_.reserve(new_cap_named);
}
/// Returns the number of elements in the store.
size_t size() const noexcept { return data_.size(); }
};
FMT_END_NAMESPACE
#endif // FMT_ARGS_H_
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+610
View File
@@ -0,0 +1,610 @@
// Formatting library for C++ - color support
//
// Copyright (c) 2018 - present, Victor Zverovich and fmt contributors
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_COLOR_H_
#define FMT_COLOR_H_
#include "format.h"
FMT_BEGIN_NAMESPACE
FMT_BEGIN_EXPORT
enum class color : uint32_t {
alice_blue = 0xF0F8FF, // rgb(240,248,255)
antique_white = 0xFAEBD7, // rgb(250,235,215)
aqua = 0x00FFFF, // rgb(0,255,255)
aquamarine = 0x7FFFD4, // rgb(127,255,212)
azure = 0xF0FFFF, // rgb(240,255,255)
beige = 0xF5F5DC, // rgb(245,245,220)
bisque = 0xFFE4C4, // rgb(255,228,196)
black = 0x000000, // rgb(0,0,0)
blanched_almond = 0xFFEBCD, // rgb(255,235,205)
blue = 0x0000FF, // rgb(0,0,255)
blue_violet = 0x8A2BE2, // rgb(138,43,226)
brown = 0xA52A2A, // rgb(165,42,42)
burly_wood = 0xDEB887, // rgb(222,184,135)
cadet_blue = 0x5F9EA0, // rgb(95,158,160)
chartreuse = 0x7FFF00, // rgb(127,255,0)
chocolate = 0xD2691E, // rgb(210,105,30)
coral = 0xFF7F50, // rgb(255,127,80)
cornflower_blue = 0x6495ED, // rgb(100,149,237)
cornsilk = 0xFFF8DC, // rgb(255,248,220)
crimson = 0xDC143C, // rgb(220,20,60)
cyan = 0x00FFFF, // rgb(0,255,255)
dark_blue = 0x00008B, // rgb(0,0,139)
dark_cyan = 0x008B8B, // rgb(0,139,139)
dark_golden_rod = 0xB8860B, // rgb(184,134,11)
dark_gray = 0xA9A9A9, // rgb(169,169,169)
dark_green = 0x006400, // rgb(0,100,0)
dark_khaki = 0xBDB76B, // rgb(189,183,107)
dark_magenta = 0x8B008B, // rgb(139,0,139)
dark_olive_green = 0x556B2F, // rgb(85,107,47)
dark_orange = 0xFF8C00, // rgb(255,140,0)
dark_orchid = 0x9932CC, // rgb(153,50,204)
dark_red = 0x8B0000, // rgb(139,0,0)
dark_salmon = 0xE9967A, // rgb(233,150,122)
dark_sea_green = 0x8FBC8F, // rgb(143,188,143)
dark_slate_blue = 0x483D8B, // rgb(72,61,139)
dark_slate_gray = 0x2F4F4F, // rgb(47,79,79)
dark_turquoise = 0x00CED1, // rgb(0,206,209)
dark_violet = 0x9400D3, // rgb(148,0,211)
deep_pink = 0xFF1493, // rgb(255,20,147)
deep_sky_blue = 0x00BFFF, // rgb(0,191,255)
dim_gray = 0x696969, // rgb(105,105,105)
dodger_blue = 0x1E90FF, // rgb(30,144,255)
fire_brick = 0xB22222, // rgb(178,34,34)
floral_white = 0xFFFAF0, // rgb(255,250,240)
forest_green = 0x228B22, // rgb(34,139,34)
fuchsia = 0xFF00FF, // rgb(255,0,255)
gainsboro = 0xDCDCDC, // rgb(220,220,220)
ghost_white = 0xF8F8FF, // rgb(248,248,255)
gold = 0xFFD700, // rgb(255,215,0)
golden_rod = 0xDAA520, // rgb(218,165,32)
gray = 0x808080, // rgb(128,128,128)
green = 0x008000, // rgb(0,128,0)
green_yellow = 0xADFF2F, // rgb(173,255,47)
honey_dew = 0xF0FFF0, // rgb(240,255,240)
hot_pink = 0xFF69B4, // rgb(255,105,180)
indian_red = 0xCD5C5C, // rgb(205,92,92)
indigo = 0x4B0082, // rgb(75,0,130)
ivory = 0xFFFFF0, // rgb(255,255,240)
khaki = 0xF0E68C, // rgb(240,230,140)
lavender = 0xE6E6FA, // rgb(230,230,250)
lavender_blush = 0xFFF0F5, // rgb(255,240,245)
lawn_green = 0x7CFC00, // rgb(124,252,0)
lemon_chiffon = 0xFFFACD, // rgb(255,250,205)
light_blue = 0xADD8E6, // rgb(173,216,230)
light_coral = 0xF08080, // rgb(240,128,128)
light_cyan = 0xE0FFFF, // rgb(224,255,255)
light_golden_rod_yellow = 0xFAFAD2, // rgb(250,250,210)
light_gray = 0xD3D3D3, // rgb(211,211,211)
light_green = 0x90EE90, // rgb(144,238,144)
light_pink = 0xFFB6C1, // rgb(255,182,193)
light_salmon = 0xFFA07A, // rgb(255,160,122)
light_sea_green = 0x20B2AA, // rgb(32,178,170)
light_sky_blue = 0x87CEFA, // rgb(135,206,250)
light_slate_gray = 0x778899, // rgb(119,136,153)
light_steel_blue = 0xB0C4DE, // rgb(176,196,222)
light_yellow = 0xFFFFE0, // rgb(255,255,224)
lime = 0x00FF00, // rgb(0,255,0)
lime_green = 0x32CD32, // rgb(50,205,50)
linen = 0xFAF0E6, // rgb(250,240,230)
magenta = 0xFF00FF, // rgb(255,0,255)
maroon = 0x800000, // rgb(128,0,0)
medium_aquamarine = 0x66CDAA, // rgb(102,205,170)
medium_blue = 0x0000CD, // rgb(0,0,205)
medium_orchid = 0xBA55D3, // rgb(186,85,211)
medium_purple = 0x9370DB, // rgb(147,112,219)
medium_sea_green = 0x3CB371, // rgb(60,179,113)
medium_slate_blue = 0x7B68EE, // rgb(123,104,238)
medium_spring_green = 0x00FA9A, // rgb(0,250,154)
medium_turquoise = 0x48D1CC, // rgb(72,209,204)
medium_violet_red = 0xC71585, // rgb(199,21,133)
midnight_blue = 0x191970, // rgb(25,25,112)
mint_cream = 0xF5FFFA, // rgb(245,255,250)
misty_rose = 0xFFE4E1, // rgb(255,228,225)
moccasin = 0xFFE4B5, // rgb(255,228,181)
navajo_white = 0xFFDEAD, // rgb(255,222,173)
navy = 0x000080, // rgb(0,0,128)
old_lace = 0xFDF5E6, // rgb(253,245,230)
olive = 0x808000, // rgb(128,128,0)
olive_drab = 0x6B8E23, // rgb(107,142,35)
orange = 0xFFA500, // rgb(255,165,0)
orange_red = 0xFF4500, // rgb(255,69,0)
orchid = 0xDA70D6, // rgb(218,112,214)
pale_golden_rod = 0xEEE8AA, // rgb(238,232,170)
pale_green = 0x98FB98, // rgb(152,251,152)
pale_turquoise = 0xAFEEEE, // rgb(175,238,238)
pale_violet_red = 0xDB7093, // rgb(219,112,147)
papaya_whip = 0xFFEFD5, // rgb(255,239,213)
peach_puff = 0xFFDAB9, // rgb(255,218,185)
peru = 0xCD853F, // rgb(205,133,63)
pink = 0xFFC0CB, // rgb(255,192,203)
plum = 0xDDA0DD, // rgb(221,160,221)
powder_blue = 0xB0E0E6, // rgb(176,224,230)
purple = 0x800080, // rgb(128,0,128)
rebecca_purple = 0x663399, // rgb(102,51,153)
red = 0xFF0000, // rgb(255,0,0)
rosy_brown = 0xBC8F8F, // rgb(188,143,143)
royal_blue = 0x4169E1, // rgb(65,105,225)
saddle_brown = 0x8B4513, // rgb(139,69,19)
salmon = 0xFA8072, // rgb(250,128,114)
sandy_brown = 0xF4A460, // rgb(244,164,96)
sea_green = 0x2E8B57, // rgb(46,139,87)
sea_shell = 0xFFF5EE, // rgb(255,245,238)
sienna = 0xA0522D, // rgb(160,82,45)
silver = 0xC0C0C0, // rgb(192,192,192)
sky_blue = 0x87CEEB, // rgb(135,206,235)
slate_blue = 0x6A5ACD, // rgb(106,90,205)
slate_gray = 0x708090, // rgb(112,128,144)
snow = 0xFFFAFA, // rgb(255,250,250)
spring_green = 0x00FF7F, // rgb(0,255,127)
steel_blue = 0x4682B4, // rgb(70,130,180)
tan = 0xD2B48C, // rgb(210,180,140)
teal = 0x008080, // rgb(0,128,128)
thistle = 0xD8BFD8, // rgb(216,191,216)
tomato = 0xFF6347, // rgb(255,99,71)
turquoise = 0x40E0D0, // rgb(64,224,208)
violet = 0xEE82EE, // rgb(238,130,238)
wheat = 0xF5DEB3, // rgb(245,222,179)
white = 0xFFFFFF, // rgb(255,255,255)
white_smoke = 0xF5F5F5, // rgb(245,245,245)
yellow = 0xFFFF00, // rgb(255,255,0)
yellow_green = 0x9ACD32 // rgb(154,205,50)
}; // enum class color
enum class terminal_color : uint8_t {
black = 30,
red,
green,
yellow,
blue,
magenta,
cyan,
white,
bright_black = 90,
bright_red,
bright_green,
bright_yellow,
bright_blue,
bright_magenta,
bright_cyan,
bright_white
};
enum class emphasis : uint8_t {
bold = 1,
faint = 1 << 1,
italic = 1 << 2,
underline = 1 << 3,
blink = 1 << 4,
reverse = 1 << 5,
conceal = 1 << 6,
strikethrough = 1 << 7,
};
// rgb is a struct for red, green and blue colors.
// Using the name "rgb" makes some editors show the color in a tooltip.
struct rgb {
FMT_CONSTEXPR rgb() : r(0), g(0), b(0) {}
FMT_CONSTEXPR rgb(uint8_t r_, uint8_t g_, uint8_t b_) : r(r_), g(g_), b(b_) {}
FMT_CONSTEXPR rgb(uint32_t hex)
: r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b(hex & 0xFF) {}
FMT_CONSTEXPR rgb(color hex)
: r((uint32_t(hex) >> 16) & 0xFF),
g((uint32_t(hex) >> 8) & 0xFF),
b(uint32_t(hex) & 0xFF) {}
uint8_t r;
uint8_t g;
uint8_t b;
};
namespace detail {
// color is a struct of either a rgb color or a terminal color.
struct color_type {
FMT_CONSTEXPR color_type() noexcept : is_rgb(), value{} {}
FMT_CONSTEXPR color_type(color rgb_color) noexcept : is_rgb(true), value{} {
value.rgb_color = static_cast<uint32_t>(rgb_color);
}
FMT_CONSTEXPR color_type(rgb rgb_color) noexcept : is_rgb(true), value{} {
value.rgb_color = (static_cast<uint32_t>(rgb_color.r) << 16) |
(static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b;
}
FMT_CONSTEXPR color_type(terminal_color term_color) noexcept
: is_rgb(), value{} {
value.term_color = static_cast<uint8_t>(term_color);
}
bool is_rgb;
union color_union {
uint8_t term_color;
uint32_t rgb_color;
} value;
};
} // namespace detail
/// A text style consisting of foreground and background colors and emphasis.
class text_style {
public:
FMT_CONSTEXPR text_style(emphasis em = emphasis()) noexcept
: set_foreground_color(), set_background_color(), ems(em) {}
FMT_CONSTEXPR auto operator|=(const text_style& rhs) -> text_style& {
if (!set_foreground_color) {
set_foreground_color = rhs.set_foreground_color;
foreground_color = rhs.foreground_color;
} else if (rhs.set_foreground_color) {
if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb)
report_error("can't OR a terminal color");
foreground_color.value.rgb_color |= rhs.foreground_color.value.rgb_color;
}
if (!set_background_color) {
set_background_color = rhs.set_background_color;
background_color = rhs.background_color;
} else if (rhs.set_background_color) {
if (!background_color.is_rgb || !rhs.background_color.is_rgb)
report_error("can't OR a terminal color");
background_color.value.rgb_color |= rhs.background_color.value.rgb_color;
}
ems = static_cast<emphasis>(static_cast<uint8_t>(ems) |
static_cast<uint8_t>(rhs.ems));
return *this;
}
friend FMT_CONSTEXPR auto operator|(text_style lhs, const text_style& rhs)
-> text_style {
return lhs |= rhs;
}
FMT_CONSTEXPR auto has_foreground() const noexcept -> bool {
return set_foreground_color;
}
FMT_CONSTEXPR auto has_background() const noexcept -> bool {
return set_background_color;
}
FMT_CONSTEXPR auto has_emphasis() const noexcept -> bool {
return static_cast<uint8_t>(ems) != 0;
}
FMT_CONSTEXPR auto get_foreground() const noexcept -> detail::color_type {
FMT_ASSERT(has_foreground(), "no foreground specified for this style");
return foreground_color;
}
FMT_CONSTEXPR auto get_background() const noexcept -> detail::color_type {
FMT_ASSERT(has_background(), "no background specified for this style");
return background_color;
}
FMT_CONSTEXPR auto get_emphasis() const noexcept -> emphasis {
FMT_ASSERT(has_emphasis(), "no emphasis specified for this style");
return ems;
}
private:
FMT_CONSTEXPR text_style(bool is_foreground,
detail::color_type text_color) noexcept
: set_foreground_color(), set_background_color(), ems() {
if (is_foreground) {
foreground_color = text_color;
set_foreground_color = true;
} else {
background_color = text_color;
set_background_color = true;
}
}
friend FMT_CONSTEXPR auto fg(detail::color_type foreground) noexcept
-> text_style;
friend FMT_CONSTEXPR auto bg(detail::color_type background) noexcept
-> text_style;
detail::color_type foreground_color;
detail::color_type background_color;
bool set_foreground_color;
bool set_background_color;
emphasis ems;
};
/// Creates a text style from the foreground (text) color.
FMT_CONSTEXPR inline auto fg(detail::color_type foreground) noexcept
-> text_style {
return text_style(true, foreground);
}
/// Creates a text style from the background color.
FMT_CONSTEXPR inline auto bg(detail::color_type background) noexcept
-> text_style {
return text_style(false, background);
}
FMT_CONSTEXPR inline auto operator|(emphasis lhs, emphasis rhs) noexcept
-> text_style {
return text_style(lhs) | rhs;
}
namespace detail {
template <typename Char> struct ansi_color_escape {
FMT_CONSTEXPR ansi_color_escape(color_type text_color,
const char* esc) noexcept {
// If we have a terminal color, we need to output another escape code
// sequence.
if (!text_color.is_rgb) {
bool is_background = esc == string_view("\x1b[48;2;");
uint32_t value = text_color.value.term_color;
// Background ASCII codes are the same as the foreground ones but with
// 10 more.
if (is_background) value += 10u;
size_t index = 0;
buffer[index++] = static_cast<Char>('\x1b');
buffer[index++] = static_cast<Char>('[');
if (value >= 100u) {
buffer[index++] = static_cast<Char>('1');
value %= 100u;
}
buffer[index++] = static_cast<Char>('0' + value / 10u);
buffer[index++] = static_cast<Char>('0' + value % 10u);
buffer[index++] = static_cast<Char>('m');
buffer[index++] = static_cast<Char>('\0');
return;
}
for (int i = 0; i < 7; i++) {
buffer[i] = static_cast<Char>(esc[i]);
}
rgb color(text_color.value.rgb_color);
to_esc(color.r, buffer + 7, ';');
to_esc(color.g, buffer + 11, ';');
to_esc(color.b, buffer + 15, 'm');
buffer[19] = static_cast<Char>(0);
}
FMT_CONSTEXPR ansi_color_escape(emphasis em) noexcept {
uint8_t em_codes[num_emphases] = {};
if (has_emphasis(em, emphasis::bold)) em_codes[0] = 1;
if (has_emphasis(em, emphasis::faint)) em_codes[1] = 2;
if (has_emphasis(em, emphasis::italic)) em_codes[2] = 3;
if (has_emphasis(em, emphasis::underline)) em_codes[3] = 4;
if (has_emphasis(em, emphasis::blink)) em_codes[4] = 5;
if (has_emphasis(em, emphasis::reverse)) em_codes[5] = 7;
if (has_emphasis(em, emphasis::conceal)) em_codes[6] = 8;
if (has_emphasis(em, emphasis::strikethrough)) em_codes[7] = 9;
size_t index = 0;
for (size_t i = 0; i < num_emphases; ++i) {
if (!em_codes[i]) continue;
buffer[index++] = static_cast<Char>('\x1b');
buffer[index++] = static_cast<Char>('[');
buffer[index++] = static_cast<Char>('0' + em_codes[i]);
buffer[index++] = static_cast<Char>('m');
}
buffer[index++] = static_cast<Char>(0);
}
FMT_CONSTEXPR operator const Char*() const noexcept { return buffer; }
FMT_CONSTEXPR auto begin() const noexcept -> const Char* { return buffer; }
FMT_CONSTEXPR20 auto end() const noexcept -> const Char* {
return buffer + basic_string_view<Char>(buffer).size();
}
private:
static constexpr size_t num_emphases = 8;
Char buffer[7u + 3u * num_emphases + 1u];
static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out,
char delimiter) noexcept {
out[0] = static_cast<Char>('0' + c / 100);
out[1] = static_cast<Char>('0' + c / 10 % 10);
out[2] = static_cast<Char>('0' + c % 10);
out[3] = static_cast<Char>(delimiter);
}
static FMT_CONSTEXPR auto has_emphasis(emphasis em, emphasis mask) noexcept
-> bool {
return static_cast<uint8_t>(em) & static_cast<uint8_t>(mask);
}
};
template <typename Char>
FMT_CONSTEXPR auto make_foreground_color(color_type foreground) noexcept
-> ansi_color_escape<Char> {
return ansi_color_escape<Char>(foreground, "\x1b[38;2;");
}
template <typename Char>
FMT_CONSTEXPR auto make_background_color(color_type background) noexcept
-> ansi_color_escape<Char> {
return ansi_color_escape<Char>(background, "\x1b[48;2;");
}
template <typename Char>
FMT_CONSTEXPR auto make_emphasis(emphasis em) noexcept
-> ansi_color_escape<Char> {
return ansi_color_escape<Char>(em);
}
template <typename Char> inline void reset_color(buffer<Char>& buffer) {
auto reset_color = string_view("\x1b[0m");
buffer.append(reset_color.begin(), reset_color.end());
}
template <typename T> struct styled_arg : view {
const T& value;
text_style style;
styled_arg(const T& v, text_style s) : value(v), style(s) {}
};
template <typename Char>
void vformat_to(buffer<Char>& buf, const text_style& ts,
basic_string_view<Char> fmt,
basic_format_args<buffered_context<Char>> args) {
bool has_style = false;
if (ts.has_emphasis()) {
has_style = true;
auto emphasis = make_emphasis<Char>(ts.get_emphasis());
buf.append(emphasis.begin(), emphasis.end());
}
if (ts.has_foreground()) {
has_style = true;
auto foreground = make_foreground_color<Char>(ts.get_foreground());
buf.append(foreground.begin(), foreground.end());
}
if (ts.has_background()) {
has_style = true;
auto background = make_background_color<Char>(ts.get_background());
buf.append(background.begin(), background.end());
}
vformat_to(buf, fmt, args);
if (has_style) reset_color<Char>(buf);
}
} // namespace detail
inline void vprint(FILE* f, const text_style& ts, string_view fmt,
format_args args) {
auto buf = memory_buffer();
detail::vformat_to(buf, ts, fmt, args);
print(f, FMT_STRING("{}"), string_view(buf.begin(), buf.size()));
}
/**
* Formats a string and prints it to the specified file stream using ANSI
* escape sequences to specify text formatting.
*
* **Example**:
*
* fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
* "Elapsed time: {0:.2f} seconds", 1.23);
*/
template <typename... T>
void print(FILE* f, const text_style& ts, format_string<T...> fmt,
T&&... args) {
vprint(f, ts, fmt.str, vargs<T...>{{args...}});
}
/**
* Formats a string and prints it to stdout using ANSI escape sequences to
* specify text formatting.
*
* **Example**:
*
* fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
* "Elapsed time: {0:.2f} seconds", 1.23);
*/
template <typename... T>
void print(const text_style& ts, format_string<T...> fmt, T&&... args) {
return print(stdout, ts, fmt, std::forward<T>(args)...);
}
inline auto vformat(const text_style& ts, string_view fmt, format_args args)
-> std::string {
auto buf = memory_buffer();
detail::vformat_to(buf, ts, fmt, args);
return fmt::to_string(buf);
}
/**
* Formats arguments and returns the result as a string using ANSI escape
* sequences to specify text formatting.
*
* **Example**:
*
* ```
* #include <fmt/color.h>
* std::string message = fmt::format(fmt::emphasis::bold | fg(fmt::color::red),
* "The answer is {}", 42);
* ```
*/
template <typename... T>
inline auto format(const text_style& ts, format_string<T...> fmt, T&&... args)
-> std::string {
return fmt::vformat(ts, fmt.str, vargs<T...>{{args...}});
}
/// Formats a string with the given text_style and writes the output to `out`.
template <typename OutputIt,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
auto vformat_to(OutputIt out, const text_style& ts, string_view fmt,
format_args args) -> OutputIt {
auto&& buf = detail::get_buffer<char>(out);
detail::vformat_to(buf, ts, fmt, args);
return detail::get_iterator(buf, out);
}
/**
* Formats arguments with the given text style, writes the result to the output
* iterator `out` and returns the iterator past the end of the output range.
*
* **Example**:
*
* std::vector<char> out;
* fmt::format_to(std::back_inserter(out),
* fmt::emphasis::bold | fg(fmt::color::red), "{}", 42);
*/
template <typename OutputIt, typename... T,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
inline auto format_to(OutputIt out, const text_style& ts,
format_string<T...> fmt, T&&... args) -> OutputIt {
return vformat_to(out, ts, fmt.str, vargs<T...>{{args...}});
}
template <typename T, typename Char>
struct formatter<detail::styled_arg<T>, Char> : formatter<T, Char> {
template <typename FormatContext>
auto format(const detail::styled_arg<T>& arg, FormatContext& ctx) const
-> decltype(ctx.out()) {
const auto& ts = arg.style;
auto out = ctx.out();
bool has_style = false;
if (ts.has_emphasis()) {
has_style = true;
auto emphasis = detail::make_emphasis<Char>(ts.get_emphasis());
out = detail::copy<Char>(emphasis.begin(), emphasis.end(), out);
}
if (ts.has_foreground()) {
has_style = true;
auto foreground =
detail::make_foreground_color<Char>(ts.get_foreground());
out = detail::copy<Char>(foreground.begin(), foreground.end(), out);
}
if (ts.has_background()) {
has_style = true;
auto background =
detail::make_background_color<Char>(ts.get_background());
out = detail::copy<Char>(background.begin(), background.end(), out);
}
out = formatter<T, Char>::format(arg.value, ctx);
if (has_style) {
auto reset_color = string_view("\x1b[0m");
out = detail::copy<Char>(reset_color.begin(), reset_color.end(), out);
}
return out;
}
};
/**
* Returns an argument that will be formatted using ANSI escape sequences,
* to be used in a formatting function.
*
* **Example**:
*
* fmt::print("Elapsed time: {0:.2f} seconds",
* fmt::styled(1.23, fmt::fg(fmt::color::green) |
* fmt::bg(fmt::color::blue)));
*/
template <typename T>
FMT_CONSTEXPR auto styled(const T& value, text_style ts)
-> detail::styled_arg<remove_cvref_t<T>> {
return detail::styled_arg<remove_cvref_t<T>>{value, ts};
}
FMT_END_EXPORT
FMT_END_NAMESPACE
#endif // FMT_COLOR_H_
+551
View File
@@ -0,0 +1,551 @@
// Formatting library for C++ - experimental format string compilation
//
// Copyright (c) 2012 - present, Victor Zverovich and fmt contributors
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_COMPILE_H_
#define FMT_COMPILE_H_
#ifndef FMT_MODULE
# include <iterator> // std::back_inserter
#endif
#include "format.h"
FMT_BEGIN_NAMESPACE
// A compile-time string which is compiled into fast formatting code.
FMT_EXPORT class compiled_string {};
namespace detail {
template <typename S>
struct is_compiled_string : std::is_base_of<compiled_string, S> {};
/**
* Converts a string literal `s` into a format string that will be parsed at
* compile time and converted into efficient formatting code. Requires C++17
* `constexpr if` compiler support.
*
* **Example**:
*
* // Converts 42 into std::string using the most efficient method and no
* // runtime format string processing.
* std::string s = fmt::format(FMT_COMPILE("{}"), 42);
*/
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
# define FMT_COMPILE(s) FMT_STRING_IMPL(s, fmt::compiled_string)
#else
# define FMT_COMPILE(s) FMT_STRING(s)
#endif
#if FMT_USE_NONTYPE_TEMPLATE_ARGS
template <typename Char, size_t N, fmt::detail::fixed_string<Char, N> Str>
struct udl_compiled_string : compiled_string {
using char_type = Char;
constexpr explicit operator basic_string_view<char_type>() const {
return {Str.data, N - 1};
}
};
#endif
template <typename T, typename... Tail>
auto first(const T& value, const Tail&...) -> const T& {
return value;
}
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
template <typename... Args> struct type_list {};
// Returns a reference to the argument at index N from [first, rest...].
template <int N, typename T, typename... Args>
constexpr const auto& get([[maybe_unused]] const T& first,
[[maybe_unused]] const Args&... rest) {
static_assert(N < 1 + sizeof...(Args), "index is out of bounds");
if constexpr (N == 0)
return first;
else
return detail::get<N - 1>(rest...);
}
# if FMT_USE_NONTYPE_TEMPLATE_ARGS
template <int N, typename T, typename... Args, typename Char>
constexpr auto get_arg_index_by_name(basic_string_view<Char> name) -> int {
if constexpr (is_static_named_arg<T>()) {
if (name == T::name) return N;
}
if constexpr (sizeof...(Args) > 0)
return get_arg_index_by_name<N + 1, Args...>(name);
(void)name; // Workaround an MSVC bug about "unused" parameter.
return -1;
}
# endif
template <typename... Args, typename Char>
FMT_CONSTEXPR auto get_arg_index_by_name(basic_string_view<Char> name) -> int {
# if FMT_USE_NONTYPE_TEMPLATE_ARGS
if constexpr (sizeof...(Args) > 0)
return get_arg_index_by_name<0, Args...>(name);
# endif
(void)name;
return -1;
}
template <typename Char, typename... Args>
constexpr int get_arg_index_by_name(basic_string_view<Char> name,
type_list<Args...>) {
return get_arg_index_by_name<Args...>(name);
}
template <int N, typename> struct get_type_impl;
template <int N, typename... Args> struct get_type_impl<N, type_list<Args...>> {
using type =
remove_cvref_t<decltype(detail::get<N>(std::declval<Args>()...))>;
};
template <int N, typename T>
using get_type = typename get_type_impl<N, T>::type;
template <typename T> struct is_compiled_format : std::false_type {};
template <typename Char> struct text {
basic_string_view<Char> data;
using char_type = Char;
template <typename OutputIt, typename... Args>
constexpr OutputIt format(OutputIt out, const Args&...) const {
return write<Char>(out, data);
}
};
template <typename Char>
struct is_compiled_format<text<Char>> : std::true_type {};
template <typename Char>
constexpr text<Char> make_text(basic_string_view<Char> s, size_t pos,
size_t size) {
return {{&s[pos], size}};
}
template <typename Char> struct code_unit {
Char value;
using char_type = Char;
template <typename OutputIt, typename... Args>
constexpr OutputIt format(OutputIt out, const Args&...) const {
*out++ = value;
return out;
}
};
// This ensures that the argument type is convertible to `const T&`.
template <typename T, int N, typename... Args>
constexpr const T& get_arg_checked(const Args&... args) {
const auto& arg = detail::get<N>(args...);
if constexpr (detail::is_named_arg<remove_cvref_t<decltype(arg)>>()) {
return arg.value;
} else {
return arg;
}
}
template <typename Char>
struct is_compiled_format<code_unit<Char>> : std::true_type {};
// A replacement field that refers to argument N.
template <typename Char, typename T, int N> struct field {
using char_type = Char;
template <typename OutputIt, typename... Args>
constexpr OutputIt format(OutputIt out, const Args&... args) const {
const T& arg = get_arg_checked<T, N>(args...);
if constexpr (std::is_convertible<T, basic_string_view<Char>>::value) {
auto s = basic_string_view<Char>(arg);
return copy<Char>(s.begin(), s.end(), out);
} else {
return write<Char>(out, arg);
}
}
};
template <typename Char, typename T, int N>
struct is_compiled_format<field<Char, T, N>> : std::true_type {};
// A replacement field that refers to argument with name.
template <typename Char> struct runtime_named_field {
using char_type = Char;
basic_string_view<Char> name;
template <typename OutputIt, typename T>
constexpr static bool try_format_argument(
OutputIt& out,
// [[maybe_unused]] due to unused-but-set-parameter warning in GCC 7,8,9
[[maybe_unused]] basic_string_view<Char> arg_name, const T& arg) {
if constexpr (is_named_arg<typename std::remove_cv<T>::type>::value) {
if (arg_name == arg.name) {
out = write<Char>(out, arg.value);
return true;
}
}
return false;
}
template <typename OutputIt, typename... Args>
constexpr OutputIt format(OutputIt out, const Args&... args) const {
bool found = (try_format_argument(out, name, args) || ...);
if (!found) {
FMT_THROW(format_error("argument with specified name is not found"));
}
return out;
}
};
template <typename Char>
struct is_compiled_format<runtime_named_field<Char>> : std::true_type {};
// A replacement field that refers to argument N and has format specifiers.
template <typename Char, typename T, int N> struct spec_field {
using char_type = Char;
formatter<T, Char> fmt;
template <typename OutputIt, typename... Args>
constexpr FMT_INLINE OutputIt format(OutputIt out,
const Args&... args) const {
const auto& vargs =
fmt::make_format_args<basic_format_context<OutputIt, Char>>(args...);
basic_format_context<OutputIt, Char> ctx(out, vargs);
return fmt.format(get_arg_checked<T, N>(args...), ctx);
}
};
template <typename Char, typename T, int N>
struct is_compiled_format<spec_field<Char, T, N>> : std::true_type {};
template <typename L, typename R> struct concat {
L lhs;
R rhs;
using char_type = typename L::char_type;
template <typename OutputIt, typename... Args>
constexpr OutputIt format(OutputIt out, const Args&... args) const {
out = lhs.format(out, args...);
return rhs.format(out, args...);
}
};
template <typename L, typename R>
struct is_compiled_format<concat<L, R>> : std::true_type {};
template <typename L, typename R>
constexpr concat<L, R> make_concat(L lhs, R rhs) {
return {lhs, rhs};
}
struct unknown_format {};
template <typename Char>
constexpr size_t parse_text(basic_string_view<Char> str, size_t pos) {
for (size_t size = str.size(); pos != size; ++pos) {
if (str[pos] == '{' || str[pos] == '}') break;
}
return pos;
}
template <typename Args, size_t POS, int ID, typename S>
constexpr auto compile_format_string(S fmt);
template <typename Args, size_t POS, int ID, typename T, typename S>
constexpr auto parse_tail(T head, S fmt) {
if constexpr (POS != basic_string_view<typename S::char_type>(fmt).size()) {
constexpr auto tail = compile_format_string<Args, POS, ID>(fmt);
if constexpr (std::is_same<remove_cvref_t<decltype(tail)>,
unknown_format>())
return tail;
else
return make_concat(head, tail);
} else {
return head;
}
}
template <typename T, typename Char> struct parse_specs_result {
formatter<T, Char> fmt;
size_t end;
int next_arg_id;
};
enum { manual_indexing_id = -1 };
template <typename T, typename Char>
constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str,
size_t pos, int next_arg_id) {
str.remove_prefix(pos);
auto ctx =
compile_parse_context<Char>(str, max_value<int>(), nullptr, next_arg_id);
auto f = formatter<T, Char>();
auto end = f.parse(ctx);
return {f, pos + fmt::detail::to_unsigned(end - str.data()),
next_arg_id == 0 ? manual_indexing_id : ctx.next_arg_id()};
}
template <typename Char> struct arg_id_handler {
arg_id_kind kind;
arg_ref<Char> arg_id;
constexpr int on_auto() {
FMT_ASSERT(false, "handler cannot be used with automatic indexing");
return 0;
}
constexpr int on_index(int id) {
kind = arg_id_kind::index;
arg_id = arg_ref<Char>(id);
return 0;
}
constexpr int on_name(basic_string_view<Char> id) {
kind = arg_id_kind::name;
arg_id = arg_ref<Char>(id);
return 0;
}
};
template <typename Char> struct parse_arg_id_result {
arg_id_kind kind;
arg_ref<Char> arg_id;
const Char* arg_id_end;
};
template <int ID, typename Char>
constexpr auto parse_arg_id(const Char* begin, const Char* end) {
auto handler = arg_id_handler<Char>{arg_id_kind::none, arg_ref<Char>{}};
auto arg_id_end = parse_arg_id(begin, end, handler);
return parse_arg_id_result<Char>{handler.kind, handler.arg_id, arg_id_end};
}
template <typename T, typename Enable = void> struct field_type {
using type = remove_cvref_t<T>;
};
template <typename T>
struct field_type<T, enable_if_t<detail::is_named_arg<T>::value>> {
using type = remove_cvref_t<decltype(T::value)>;
};
template <typename T, typename Args, size_t END_POS, int ARG_INDEX, int NEXT_ID,
typename S>
constexpr auto parse_replacement_field_then_tail(S fmt) {
using char_type = typename S::char_type;
constexpr auto str = basic_string_view<char_type>(fmt);
constexpr char_type c = END_POS != str.size() ? str[END_POS] : char_type();
if constexpr (c == '}') {
return parse_tail<Args, END_POS + 1, NEXT_ID>(
field<char_type, typename field_type<T>::type, ARG_INDEX>(), fmt);
} else if constexpr (c != ':') {
FMT_THROW(format_error("expected ':'"));
} else {
constexpr auto result = parse_specs<typename field_type<T>::type>(
str, END_POS + 1, NEXT_ID == manual_indexing_id ? 0 : NEXT_ID);
if constexpr (result.end >= str.size() || str[result.end] != '}') {
FMT_THROW(format_error("expected '}'"));
return 0;
} else {
return parse_tail<Args, result.end + 1, result.next_arg_id>(
spec_field<char_type, typename field_type<T>::type, ARG_INDEX>{
result.fmt},
fmt);
}
}
}
// Compiles a non-empty format string and returns the compiled representation
// or unknown_format() on unrecognized input.
template <typename Args, size_t POS, int ID, typename S>
constexpr auto compile_format_string(S fmt) {
using char_type = typename S::char_type;
constexpr auto str = basic_string_view<char_type>(fmt);
if constexpr (str[POS] == '{') {
if constexpr (POS + 1 == str.size())
FMT_THROW(format_error("unmatched '{' in format string"));
if constexpr (str[POS + 1] == '{') {
return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), fmt);
} else if constexpr (str[POS + 1] == '}' || str[POS + 1] == ':') {
static_assert(ID != manual_indexing_id,
"cannot switch from manual to automatic argument indexing");
constexpr auto next_id =
ID != manual_indexing_id ? ID + 1 : manual_indexing_id;
return parse_replacement_field_then_tail<get_type<ID, Args>, Args,
POS + 1, ID, next_id>(fmt);
} else {
constexpr auto arg_id_result =
parse_arg_id<ID>(str.data() + POS + 1, str.data() + str.size());
constexpr auto arg_id_end_pos = arg_id_result.arg_id_end - str.data();
constexpr char_type c =
arg_id_end_pos != str.size() ? str[arg_id_end_pos] : char_type();
static_assert(c == '}' || c == ':', "missing '}' in format string");
if constexpr (arg_id_result.kind == arg_id_kind::index) {
static_assert(
ID == manual_indexing_id || ID == 0,
"cannot switch from automatic to manual argument indexing");
constexpr auto arg_index = arg_id_result.arg_id.index;
return parse_replacement_field_then_tail<get_type<arg_index, Args>,
Args, arg_id_end_pos,
arg_index, manual_indexing_id>(
fmt);
} else if constexpr (arg_id_result.kind == arg_id_kind::name) {
constexpr auto arg_index =
get_arg_index_by_name(arg_id_result.arg_id.name, Args{});
if constexpr (arg_index >= 0) {
constexpr auto next_id =
ID != manual_indexing_id ? ID + 1 : manual_indexing_id;
return parse_replacement_field_then_tail<
decltype(get_type<arg_index, Args>::value), Args, arg_id_end_pos,
arg_index, next_id>(fmt);
} else if constexpr (c == '}') {
return parse_tail<Args, arg_id_end_pos + 1, ID>(
runtime_named_field<char_type>{arg_id_result.arg_id.name}, fmt);
} else if constexpr (c == ':') {
return unknown_format(); // no type info for specs parsing
}
}
}
} else if constexpr (str[POS] == '}') {
if constexpr (POS + 1 == str.size())
FMT_THROW(format_error("unmatched '}' in format string"));
return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), fmt);
} else {
constexpr auto end = parse_text(str, POS + 1);
if constexpr (end - POS > 1) {
return parse_tail<Args, end, ID>(make_text(str, POS, end - POS), fmt);
} else {
return parse_tail<Args, end, ID>(code_unit<char_type>{str[POS]}, fmt);
}
}
}
template <typename... Args, typename S,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
constexpr auto compile(S fmt) {
constexpr auto str = basic_string_view<typename S::char_type>(fmt);
if constexpr (str.size() == 0) {
return detail::make_text(str, 0, 0);
} else {
constexpr auto result =
detail::compile_format_string<detail::type_list<Args...>, 0, 0>(fmt);
return result;
}
}
#endif // defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
} // namespace detail
FMT_BEGIN_EXPORT
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
template <typename CompiledFormat, typename... Args,
typename Char = typename CompiledFormat::char_type,
FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)>
FMT_INLINE std::basic_string<Char> format(const CompiledFormat& cf,
const Args&... args) {
auto s = std::basic_string<Char>();
cf.format(std::back_inserter(s), args...);
return s;
}
template <typename OutputIt, typename CompiledFormat, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)>
constexpr FMT_INLINE OutputIt format_to(OutputIt out, const CompiledFormat& cf,
const Args&... args) {
return cf.format(out, args...);
}
template <typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
FMT_INLINE std::basic_string<typename S::char_type> format(const S&,
Args&&... args) {
if constexpr (std::is_same<typename S::char_type, char>::value) {
constexpr auto str = basic_string_view<typename S::char_type>(S());
if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}') {
const auto& first = detail::first(args...);
if constexpr (detail::is_named_arg<
remove_cvref_t<decltype(first)>>::value) {
return fmt::to_string(first.value);
} else {
return fmt::to_string(first);
}
}
}
constexpr auto compiled = detail::compile<Args...>(S());
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
detail::unknown_format>()) {
return fmt::format(
static_cast<basic_string_view<typename S::char_type>>(S()),
std::forward<Args>(args)...);
} else {
return fmt::format(compiled, std::forward<Args>(args)...);
}
}
template <typename OutputIt, typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, Args&&... args) {
constexpr auto compiled = detail::compile<Args...>(S());
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
detail::unknown_format>()) {
return fmt::format_to(
out, static_cast<basic_string_view<typename S::char_type>>(S()),
std::forward<Args>(args)...);
} else {
return fmt::format_to(out, compiled, std::forward<Args>(args)...);
}
}
#endif
template <typename OutputIt, typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
auto format_to_n(OutputIt out, size_t n, const S& fmt, Args&&... args)
-> format_to_n_result<OutputIt> {
using traits = detail::fixed_buffer_traits;
auto buf = detail::iterator_buffer<OutputIt, char, traits>(out, n);
fmt::format_to(std::back_inserter(buf), fmt, std::forward<Args>(args)...);
return {buf.out(), buf.count()};
}
template <typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
FMT_CONSTEXPR20 auto formatted_size(const S& fmt, const Args&... args)
-> size_t {
auto buf = detail::counting_buffer<>();
fmt::format_to(appender(buf), fmt, args...);
return buf.count();
}
template <typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
void print(std::FILE* f, const S& fmt, const Args&... args) {
auto buf = memory_buffer();
fmt::format_to(appender(buf), fmt, args...);
detail::print(f, {buf.data(), buf.size()});
}
template <typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
void print(const S& fmt, const Args&... args) {
print(stdout, fmt, args...);
}
#if FMT_USE_NONTYPE_TEMPLATE_ARGS
inline namespace literals {
template <detail::fixed_string Str> constexpr auto operator""_cf() {
using char_t = remove_cvref_t<decltype(Str.data[0])>;
return detail::udl_compiled_string<char_t, sizeof(Str.data) / sizeof(char_t),
Str>();
}
} // namespace literals
#endif
FMT_END_EXPORT
FMT_END_NAMESPACE
#endif // FMT_COMPILE_H_
+5
View File
@@ -0,0 +1,5 @@
// This file is only provided for compatibility and may be removed in future
// versions. Use fmt/base.h if you don't need fmt::format and fmt/format.h
// otherwise.
#include "format.h"
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+427
View File
@@ -0,0 +1,427 @@
// Formatting library for C++ - optional OS-specific functionality
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_OS_H_
#define FMT_OS_H_
#include "format.h"
#ifndef FMT_MODULE
# include <cerrno>
# include <cstddef>
# include <cstdio>
# include <system_error> // std::system_error
# if FMT_HAS_INCLUDE(<xlocale.h>)
# include <xlocale.h> // LC_NUMERIC_MASK on macOS
# endif
#endif // FMT_MODULE
#ifndef FMT_USE_FCNTL
// UWP doesn't provide _pipe.
# if FMT_HAS_INCLUDE("winapifamily.h")
# include <winapifamily.h>
# endif
# if (FMT_HAS_INCLUDE(<fcntl.h>) || defined(__APPLE__) || \
defined(__linux__)) && \
(!defined(WINAPI_FAMILY) || \
(WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))
# include <fcntl.h> // for O_RDONLY
# define FMT_USE_FCNTL 1
# else
# define FMT_USE_FCNTL 0
# endif
#endif
#ifndef FMT_POSIX
# if defined(_WIN32) && !defined(__MINGW32__)
// Fix warnings about deprecated symbols.
# define FMT_POSIX(call) _##call
# else
# define FMT_POSIX(call) call
# endif
#endif
// Calls to system functions are wrapped in FMT_SYSTEM for testability.
#ifdef FMT_SYSTEM
# define FMT_HAS_SYSTEM
# define FMT_POSIX_CALL(call) FMT_SYSTEM(call)
#else
# define FMT_SYSTEM(call) ::call
# ifdef _WIN32
// Fix warnings about deprecated symbols.
# define FMT_POSIX_CALL(call) ::_##call
# else
# define FMT_POSIX_CALL(call) ::call
# endif
#endif
// Retries the expression while it evaluates to error_result and errno
// equals to EINTR.
#ifndef _WIN32
# define FMT_RETRY_VAL(result, expression, error_result) \
do { \
(result) = (expression); \
} while ((result) == (error_result) && errno == EINTR)
#else
# define FMT_RETRY_VAL(result, expression, error_result) result = (expression)
#endif
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
FMT_BEGIN_NAMESPACE
FMT_BEGIN_EXPORT
/**
* A reference to a null-terminated string. It can be constructed from a C
* string or `std::string`.
*
* You can use one of the following type aliases for common character types:
*
* +---------------+-----------------------------+
* | Type | Definition |
* +===============+=============================+
* | cstring_view | basic_cstring_view<char> |
* +---------------+-----------------------------+
* | wcstring_view | basic_cstring_view<wchar_t> |
* +---------------+-----------------------------+
*
* This class is most useful as a parameter type for functions that wrap C APIs.
*/
template <typename Char> class basic_cstring_view {
private:
const Char* data_;
public:
/// Constructs a string reference object from a C string.
basic_cstring_view(const Char* s) : data_(s) {}
/// Constructs a string reference from an `std::string` object.
basic_cstring_view(const std::basic_string<Char>& s) : data_(s.c_str()) {}
/// Returns the pointer to a C string.
auto c_str() const -> const Char* { return data_; }
};
using cstring_view = basic_cstring_view<char>;
using wcstring_view = basic_cstring_view<wchar_t>;
#ifdef _WIN32
FMT_API const std::error_category& system_category() noexcept;
namespace detail {
FMT_API void format_windows_error(buffer<char>& out, int error_code,
const char* message) noexcept;
}
FMT_API std::system_error vwindows_error(int error_code, string_view fmt,
format_args args);
/**
* Constructs a `std::system_error` object with the description of the form
*
* <message>: <system-message>
*
* where `<message>` is the formatted message and `<system-message>` is the
* system message corresponding to the error code.
* `error_code` is a Windows error code as given by `GetLastError`.
* If `error_code` is not a valid error code such as -1, the system message
* will look like "error -1".
*
* **Example**:
*
* // This throws a system_error with the description
* // cannot open file 'madeup': The system cannot find the file
* specified.
* // or similar (system message may vary).
* const char *filename = "madeup";
* LPOFSTRUCT of = LPOFSTRUCT();
* HFILE file = OpenFile(filename, &of, OF_READ);
* if (file == HFILE_ERROR) {
* throw fmt::windows_error(GetLastError(),
* "cannot open file '{}'", filename);
* }
*/
template <typename... T>
auto windows_error(int error_code, string_view message, const T&... args)
-> std::system_error {
return vwindows_error(error_code, message, vargs<T...>{{args...}});
}
// Reports a Windows error without throwing an exception.
// Can be used to report errors from destructors.
FMT_API void report_windows_error(int error_code, const char* message) noexcept;
#else
inline auto system_category() noexcept -> const std::error_category& {
return std::system_category();
}
#endif // _WIN32
// std::system is not available on some platforms such as iOS (#2248).
#ifdef __OSX__
template <typename S, typename... Args, typename Char = char_t<S>>
void say(const S& fmt, Args&&... args) {
std::system(format("say \"{}\"", format(fmt, args...)).c_str());
}
#endif
// A buffered file.
class buffered_file {
private:
FILE* file_;
friend class file;
inline explicit buffered_file(FILE* f) : file_(f) {}
public:
buffered_file(const buffered_file&) = delete;
void operator=(const buffered_file&) = delete;
// Constructs a buffered_file object which doesn't represent any file.
inline buffered_file() noexcept : file_(nullptr) {}
// Destroys the object closing the file it represents if any.
FMT_API ~buffered_file() noexcept;
public:
inline buffered_file(buffered_file&& other) noexcept : file_(other.file_) {
other.file_ = nullptr;
}
inline auto operator=(buffered_file&& other) -> buffered_file& {
close();
file_ = other.file_;
other.file_ = nullptr;
return *this;
}
// Opens a file.
FMT_API buffered_file(cstring_view filename, cstring_view mode);
// Closes the file.
FMT_API void close();
// Returns the pointer to a FILE object representing this file.
inline auto get() const noexcept -> FILE* { return file_; }
FMT_API auto descriptor() const -> int;
template <typename... T>
inline void print(string_view fmt, const T&... args) {
fmt::vargs<T...> vargs = {{args...}};
detail::is_locking<T...>() ? fmt::vprint_buffered(file_, fmt, vargs)
: fmt::vprint(file_, fmt, vargs);
}
};
#if FMT_USE_FCNTL
// A file. Closed file is represented by a file object with descriptor -1.
// Methods that are not declared with noexcept may throw
// fmt::system_error in case of failure. Note that some errors such as
// closing the file multiple times will cause a crash on Windows rather
// than an exception. You can get standard behavior by overriding the
// invalid parameter handler with _set_invalid_parameter_handler.
class FMT_API file {
private:
int fd_; // File descriptor.
// Constructs a file object with a given descriptor.
explicit file(int fd) : fd_(fd) {}
friend struct pipe;
public:
// Possible values for the oflag argument to the constructor.
enum {
RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
RDWR = FMT_POSIX(O_RDWR), // Open for reading and writing.
CREATE = FMT_POSIX(O_CREAT), // Create if the file doesn't exist.
APPEND = FMT_POSIX(O_APPEND), // Open in append mode.
TRUNC = FMT_POSIX(O_TRUNC) // Truncate the content of the file.
};
// Constructs a file object which doesn't represent any file.
inline file() noexcept : fd_(-1) {}
// Opens a file and constructs a file object representing this file.
file(cstring_view path, int oflag);
public:
file(const file&) = delete;
void operator=(const file&) = delete;
inline file(file&& other) noexcept : fd_(other.fd_) { other.fd_ = -1; }
// Move assignment is not noexcept because close may throw.
inline auto operator=(file&& other) -> file& {
close();
fd_ = other.fd_;
other.fd_ = -1;
return *this;
}
// Destroys the object closing the file it represents if any.
~file() noexcept;
// Returns the file descriptor.
inline auto descriptor() const noexcept -> int { return fd_; }
// Closes the file.
void close();
// Returns the file size. The size has signed type for consistency with
// stat::st_size.
auto size() const -> long long;
// Attempts to read count bytes from the file into the specified buffer.
auto read(void* buffer, size_t count) -> size_t;
// Attempts to write count bytes from the specified buffer to the file.
auto write(const void* buffer, size_t count) -> size_t;
// Duplicates a file descriptor with the dup function and returns
// the duplicate as a file object.
static auto dup(int fd) -> file;
// Makes fd be the copy of this file descriptor, closing fd first if
// necessary.
void dup2(int fd);
// Makes fd be the copy of this file descriptor, closing fd first if
// necessary.
void dup2(int fd, std::error_code& ec) noexcept;
// Creates a buffered_file object associated with this file and detaches
// this file object from the file.
auto fdopen(const char* mode) -> buffered_file;
# if defined(_WIN32) && !defined(__MINGW32__)
// Opens a file and constructs a file object representing this file by
// wcstring_view filename. Windows only.
static file open_windows_file(wcstring_view path, int oflag);
# endif
};
struct FMT_API pipe {
file read_end;
file write_end;
// Creates a pipe setting up read_end and write_end file objects for reading
// and writing respectively.
pipe();
};
// Returns the memory page size.
auto getpagesize() -> long;
namespace detail {
struct buffer_size {
constexpr buffer_size() = default;
size_t value = 0;
FMT_CONSTEXPR auto operator=(size_t val) const -> buffer_size {
auto bs = buffer_size();
bs.value = val;
return bs;
}
};
struct ostream_params {
int oflag = file::WRONLY | file::CREATE | file::TRUNC;
size_t buffer_size = BUFSIZ > 32768 ? BUFSIZ : 32768;
constexpr ostream_params() {}
template <typename... T>
ostream_params(T... params, int new_oflag) : ostream_params(params...) {
oflag = new_oflag;
}
template <typename... T>
ostream_params(T... params, detail::buffer_size bs)
: ostream_params(params...) {
this->buffer_size = bs.value;
}
// Intel has a bug that results in failure to deduce a constructor
// for empty parameter packs.
# if defined(__INTEL_COMPILER) && __INTEL_COMPILER < 2000
ostream_params(int new_oflag) : oflag(new_oflag) {}
ostream_params(detail::buffer_size bs) : buffer_size(bs.value) {}
# endif
};
} // namespace detail
FMT_INLINE_VARIABLE constexpr auto buffer_size = detail::buffer_size();
/// A fast buffered output stream for writing from a single thread. Writing from
/// multiple threads without external synchronization may result in a data race.
class FMT_API ostream : private detail::buffer<char> {
private:
file file_;
ostream(cstring_view path, const detail::ostream_params& params);
static void grow(buffer<char>& buf, size_t);
public:
ostream(ostream&& other) noexcept;
~ostream();
operator writer() {
detail::buffer<char>& buf = *this;
return buf;
}
inline void flush() {
if (size() == 0) return;
file_.write(data(), size() * sizeof(data()[0]));
clear();
}
template <typename... T>
friend auto output_file(cstring_view path, T... params) -> ostream;
inline void close() {
flush();
file_.close();
}
/// Formats `args` according to specifications in `fmt` and writes the
/// output to the file.
template <typename... T> void print(format_string<T...> fmt, T&&... args) {
vformat_to(appender(*this), fmt.str, vargs<T...>{{args...}});
}
};
/**
* Opens a file for writing. Supported parameters passed in `params`:
*
* - `<integer>`: Flags passed to [open](
* https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html)
* (`file::WRONLY | file::CREATE | file::TRUNC` by default)
* - `buffer_size=<integer>`: Output buffer size
*
* **Example**:
*
* auto out = fmt::output_file("guide.txt");
* out.print("Don't {}", "Panic");
*/
template <typename... T>
inline auto output_file(cstring_view path, T... params) -> ostream {
return {path, detail::ostream_params(params...)};
}
#endif // FMT_USE_FCNTL
FMT_END_EXPORT
FMT_END_NAMESPACE
#endif // FMT_OS_H_
+166
View File
@@ -0,0 +1,166 @@
// Formatting library for C++ - std::ostream support
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_OSTREAM_H_
#define FMT_OSTREAM_H_
#ifndef FMT_MODULE
# include <fstream> // std::filebuf
#endif
#ifdef _WIN32
# ifdef __GLIBCXX__
# include <ext/stdio_filebuf.h>
# include <ext/stdio_sync_filebuf.h>
# endif
# include <io.h>
#endif
#include "chrono.h" // formatbuf
#ifdef _MSVC_STL_UPDATE
# define FMT_MSVC_STL_UPDATE _MSVC_STL_UPDATE
#elif defined(_MSC_VER) && _MSC_VER < 1912 // VS 15.5
# define FMT_MSVC_STL_UPDATE _MSVC_LANG
#else
# define FMT_MSVC_STL_UPDATE 0
#endif
FMT_BEGIN_NAMESPACE
namespace detail {
// Generate a unique explicit instantion in every translation unit using a tag
// type in an anonymous namespace.
namespace {
struct file_access_tag {};
} // namespace
template <typename Tag, typename BufType, FILE* BufType::*FileMemberPtr>
class file_access {
friend auto get_file(BufType& obj) -> FILE* { return obj.*FileMemberPtr; }
};
#if FMT_MSVC_STL_UPDATE
template class file_access<file_access_tag, std::filebuf,
&std::filebuf::_Myfile>;
auto get_file(std::filebuf&) -> FILE*;
#endif
// Write the content of buf to os.
// It is a separate function rather than a part of vprint to simplify testing.
template <typename Char>
void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) {
const Char* buf_data = buf.data();
using unsigned_streamsize = make_unsigned_t<std::streamsize>;
unsigned_streamsize size = buf.size();
unsigned_streamsize max_size = to_unsigned(max_value<std::streamsize>());
do {
unsigned_streamsize n = size <= max_size ? size : max_size;
os.write(buf_data, static_cast<std::streamsize>(n));
buf_data += n;
size -= n;
} while (size != 0);
}
template <typename T> struct streamed_view {
const T& value;
};
} // namespace detail
// Formats an object of type T that has an overloaded ostream operator<<.
template <typename Char>
struct basic_ostream_formatter : formatter<basic_string_view<Char>, Char> {
void set_debug_format() = delete;
template <typename T, typename Context>
auto format(const T& value, Context& ctx) const -> decltype(ctx.out()) {
auto buffer = basic_memory_buffer<Char>();
auto&& formatbuf = detail::formatbuf<std::basic_streambuf<Char>>(buffer);
auto&& output = std::basic_ostream<Char>(&formatbuf);
output.imbue(std::locale::classic()); // The default is always unlocalized.
output << value;
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
return formatter<basic_string_view<Char>, Char>::format(
{buffer.data(), buffer.size()}, ctx);
}
};
using ostream_formatter = basic_ostream_formatter<char>;
template <typename T, typename Char>
struct formatter<detail::streamed_view<T>, Char>
: basic_ostream_formatter<Char> {
template <typename Context>
auto format(detail::streamed_view<T> view, Context& ctx) const
-> decltype(ctx.out()) {
return basic_ostream_formatter<Char>::format(view.value, ctx);
}
};
/**
* Returns a view that formats `value` via an ostream `operator<<`.
*
* **Example**:
*
* fmt::print("Current thread id: {}\n",
* fmt::streamed(std::this_thread::get_id()));
*/
template <typename T>
constexpr auto streamed(const T& value) -> detail::streamed_view<T> {
return {value};
}
inline void vprint(std::ostream& os, string_view fmt, format_args args) {
auto buffer = memory_buffer();
detail::vformat_to(buffer, fmt, args);
FILE* f = nullptr;
#if FMT_MSVC_STL_UPDATE && FMT_USE_RTTI
if (auto* buf = dynamic_cast<std::filebuf*>(os.rdbuf()))
f = detail::get_file(*buf);
#elif defined(_WIN32) && defined(__GLIBCXX__) && FMT_USE_RTTI
auto* rdbuf = os.rdbuf();
if (auto* sfbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf<char>*>(rdbuf))
f = sfbuf->file();
else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf<char>*>(rdbuf))
f = fbuf->file();
#endif
#ifdef _WIN32
if (f) {
int fd = _fileno(f);
if (_isatty(fd)) {
os.flush();
if (detail::write_console(fd, {buffer.data(), buffer.size()})) return;
}
}
#endif
detail::ignore_unused(f);
detail::write_buffer(os, buffer);
}
/**
* Prints formatted data to the stream `os`.
*
* **Example**:
*
* fmt::print(cerr, "Don't {}!", "panic");
*/
FMT_EXPORT template <typename... T>
void print(std::ostream& os, format_string<T...> fmt, T&&... args) {
fmt::vargs<T...> vargs = {{args...}};
if (detail::const_check(detail::use_utf8)) return vprint(os, fmt.str, vargs);
auto buffer = memory_buffer();
detail::vformat_to(buffer, fmt.str, vargs);
detail::write_buffer(os, buffer);
}
FMT_EXPORT template <typename... T>
void println(std::ostream& os, format_string<T...> fmt, T&&... args) {
fmt::print(os, "{}\n", fmt::format(fmt, std::forward<T>(args)...));
}
FMT_END_NAMESPACE
#endif // FMT_OSTREAM_H_
+633
View File
@@ -0,0 +1,633 @@
// Formatting library for C++ - legacy printf implementation
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_PRINTF_H_
#define FMT_PRINTF_H_
#ifndef FMT_MODULE
# include <algorithm> // std::max
# include <limits> // std::numeric_limits
#endif
#include "format.h"
FMT_BEGIN_NAMESPACE
FMT_BEGIN_EXPORT
template <typename T> struct printf_formatter {
printf_formatter() = delete;
};
template <typename Char> class basic_printf_context {
private:
basic_appender<Char> out_;
basic_format_args<basic_printf_context> args_;
static_assert(std::is_same<Char, char>::value ||
std::is_same<Char, wchar_t>::value,
"Unsupported code unit type.");
public:
using char_type = Char;
using parse_context_type = parse_context<Char>;
template <typename T> using formatter_type = printf_formatter<T>;
enum { builtin_types = 1 };
/// Constructs a `printf_context` object. References to the arguments are
/// stored in the context object so make sure they have appropriate lifetimes.
basic_printf_context(basic_appender<Char> out,
basic_format_args<basic_printf_context> args)
: out_(out), args_(args) {}
auto out() -> basic_appender<Char> { return out_; }
void advance_to(basic_appender<Char>) {}
auto locale() -> detail::locale_ref { return {}; }
auto arg(int id) const -> basic_format_arg<basic_printf_context> {
return args_.get(id);
}
};
namespace detail {
// Return the result via the out param to workaround gcc bug 77539.
template <bool IS_CONSTEXPR, typename T, typename Ptr = const T*>
FMT_CONSTEXPR auto find(Ptr first, Ptr last, T value, Ptr& out) -> bool {
for (out = first; out != last; ++out) {
if (*out == value) return true;
}
return false;
}
template <>
inline auto find<false, char>(const char* first, const char* last, char value,
const char*& out) -> bool {
out =
static_cast<const char*>(memchr(first, value, to_unsigned(last - first)));
return out != nullptr;
}
// Checks if a value fits in int - used to avoid warnings about comparing
// signed and unsigned integers.
template <bool IsSigned> struct int_checker {
template <typename T> static auto fits_in_int(T value) -> bool {
unsigned max = to_unsigned(max_value<int>());
return value <= max;
}
inline static auto fits_in_int(bool) -> bool { return true; }
};
template <> struct int_checker<true> {
template <typename T> static auto fits_in_int(T value) -> bool {
return value >= (std::numeric_limits<int>::min)() &&
value <= max_value<int>();
}
inline static auto fits_in_int(int) -> bool { return true; }
};
struct printf_precision_handler {
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
auto operator()(T value) -> int {
if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
report_error("number is too big");
return (std::max)(static_cast<int>(value), 0);
}
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
auto operator()(T) -> int {
report_error("precision is not integer");
return 0;
}
};
// An argument visitor that returns true iff arg is a zero integer.
struct is_zero_int {
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
auto operator()(T value) -> bool {
return value == 0;
}
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
auto operator()(T) -> bool {
return false;
}
};
template <typename T> struct make_unsigned_or_bool : std::make_unsigned<T> {};
template <> struct make_unsigned_or_bool<bool> {
using type = bool;
};
template <typename T, typename Context> class arg_converter {
private:
using char_type = typename Context::char_type;
basic_format_arg<Context>& arg_;
char_type type_;
public:
arg_converter(basic_format_arg<Context>& arg, char_type type)
: arg_(arg), type_(type) {}
void operator()(bool value) {
if (type_ != 's') operator()<bool>(value);
}
template <typename U, FMT_ENABLE_IF(std::is_integral<U>::value)>
void operator()(U value) {
bool is_signed = type_ == 'd' || type_ == 'i';
using target_type = conditional_t<std::is_same<T, void>::value, U, T>;
if (const_check(sizeof(target_type) <= sizeof(int))) {
// Extra casts are used to silence warnings.
using unsigned_type = typename make_unsigned_or_bool<target_type>::type;
if (is_signed)
arg_ = static_cast<int>(static_cast<target_type>(value));
else
arg_ = static_cast<unsigned>(static_cast<unsigned_type>(value));
} else {
// glibc's printf doesn't sign extend arguments of smaller types:
// std::printf("%lld", -42); // prints "4294967254"
// but we don't have to do the same because it's a UB.
if (is_signed)
arg_ = static_cast<long long>(value);
else
arg_ = static_cast<typename make_unsigned_or_bool<U>::type>(value);
}
}
template <typename U, FMT_ENABLE_IF(!std::is_integral<U>::value)>
void operator()(U) {} // No conversion needed for non-integral types.
};
// Converts an integer argument to T for printf, if T is an integral type.
// If T is void, the argument is converted to corresponding signed or unsigned
// type depending on the type specifier: 'd' and 'i' - signed, other -
// unsigned).
template <typename T, typename Context, typename Char>
void convert_arg(basic_format_arg<Context>& arg, Char type) {
arg.visit(arg_converter<T, Context>(arg, type));
}
// Converts an integer argument to char for printf.
template <typename Context> class char_converter {
private:
basic_format_arg<Context>& arg_;
public:
explicit char_converter(basic_format_arg<Context>& arg) : arg_(arg) {}
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
void operator()(T value) {
arg_ = static_cast<typename Context::char_type>(value);
}
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
void operator()(T) {} // No conversion needed for non-integral types.
};
// An argument visitor that return a pointer to a C string if argument is a
// string or null otherwise.
template <typename Char> struct get_cstring {
template <typename T> auto operator()(T) -> const Char* { return nullptr; }
auto operator()(const Char* s) -> const Char* { return s; }
};
// Checks if an argument is a valid printf width specifier and sets
// left alignment if it is negative.
class printf_width_handler {
private:
format_specs& specs_;
public:
inline explicit printf_width_handler(format_specs& specs) : specs_(specs) {}
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
auto operator()(T value) -> unsigned {
auto width = static_cast<uint32_or_64_or_128_t<T>>(value);
if (detail::is_negative(value)) {
specs_.set_align(align::left);
width = 0 - width;
}
unsigned int_max = to_unsigned(max_value<int>());
if (width > int_max) report_error("number is too big");
return static_cast<unsigned>(width);
}
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
auto operator()(T) -> unsigned {
report_error("width is not integer");
return 0;
}
};
// Workaround for a bug with the XL compiler when initializing
// printf_arg_formatter's base class.
template <typename Char>
auto make_arg_formatter(basic_appender<Char> iter, format_specs& s)
-> arg_formatter<Char> {
return {iter, s, locale_ref()};
}
// The `printf` argument formatter.
template <typename Char>
class printf_arg_formatter : public arg_formatter<Char> {
private:
using base = arg_formatter<Char>;
using context_type = basic_printf_context<Char>;
context_type& context_;
void write_null_pointer(bool is_string = false) {
auto s = this->specs;
s.set_type(presentation_type::none);
write_bytes<Char>(this->out, is_string ? "(null)" : "(nil)", s);
}
template <typename T> void write(T value) {
detail::write<Char>(this->out, value, this->specs, this->locale);
}
public:
printf_arg_formatter(basic_appender<Char> iter, format_specs& s,
context_type& ctx)
: base(make_arg_formatter(iter, s)), context_(ctx) {}
void operator()(monostate value) { write(value); }
template <typename T, FMT_ENABLE_IF(detail::is_integral<T>::value)>
void operator()(T value) {
// MSVC2013 fails to compile separate overloads for bool and Char so use
// std::is_same instead.
if (!std::is_same<T, Char>::value) {
write(value);
return;
}
format_specs s = this->specs;
if (s.type() != presentation_type::none &&
s.type() != presentation_type::chr) {
return (*this)(static_cast<int>(value));
}
s.set_sign(sign::none);
s.clear_alt();
s.set_fill(' '); // Ignore '0' flag for char types.
// align::numeric needs to be overwritten here since the '0' flag is
// ignored for non-numeric types
if (s.align() == align::none || s.align() == align::numeric)
s.set_align(align::right);
detail::write<Char>(this->out, static_cast<Char>(value), s);
}
template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
void operator()(T value) {
write(value);
}
void operator()(const char* value) {
if (value)
write(value);
else
write_null_pointer(this->specs.type() != presentation_type::pointer);
}
void operator()(const wchar_t* value) {
if (value)
write(value);
else
write_null_pointer(this->specs.type() != presentation_type::pointer);
}
void operator()(basic_string_view<Char> value) { write(value); }
void operator()(const void* value) {
if (value)
write(value);
else
write_null_pointer();
}
void operator()(typename basic_format_arg<context_type>::handle handle) {
auto parse_ctx = parse_context<Char>({});
handle.format(parse_ctx, context_);
}
};
template <typename Char>
void parse_flags(format_specs& specs, const Char*& it, const Char* end) {
for (; it != end; ++it) {
switch (*it) {
case '-': specs.set_align(align::left); break;
case '+': specs.set_sign(sign::plus); break;
case '0': specs.set_fill('0'); break;
case ' ':
if (specs.sign() != sign::plus) specs.set_sign(sign::space);
break;
case '#': specs.set_alt(); break;
default: return;
}
}
}
template <typename Char, typename GetArg>
auto parse_header(const Char*& it, const Char* end, format_specs& specs,
GetArg get_arg) -> int {
int arg_index = -1;
Char c = *it;
if (c >= '0' && c <= '9') {
// Parse an argument index (if followed by '$') or a width possibly
// preceded with '0' flag(s).
int value = parse_nonnegative_int(it, end, -1);
if (it != end && *it == '$') { // value is an argument index
++it;
arg_index = value != -1 ? value : max_value<int>();
} else {
if (c == '0') specs.set_fill('0');
if (value != 0) {
// Nonzero value means that we parsed width and don't need to
// parse it or flags again, so return now.
if (value == -1) report_error("number is too big");
specs.width = value;
return arg_index;
}
}
}
parse_flags(specs, it, end);
// Parse width.
if (it != end) {
if (*it >= '0' && *it <= '9') {
specs.width = parse_nonnegative_int(it, end, -1);
if (specs.width == -1) report_error("number is too big");
} else if (*it == '*') {
++it;
specs.width = static_cast<int>(
get_arg(-1).visit(detail::printf_width_handler(specs)));
}
}
return arg_index;
}
inline auto parse_printf_presentation_type(char c, type t, bool& upper)
-> presentation_type {
using pt = presentation_type;
constexpr auto integral_set = sint_set | uint_set | bool_set | char_set;
switch (c) {
case 'd': return in(t, integral_set) ? pt::dec : pt::none;
case 'o': return in(t, integral_set) ? pt::oct : pt::none;
case 'X': upper = true; FMT_FALLTHROUGH;
case 'x': return in(t, integral_set) ? pt::hex : pt::none;
case 'E': upper = true; FMT_FALLTHROUGH;
case 'e': return in(t, float_set) ? pt::exp : pt::none;
case 'F': upper = true; FMT_FALLTHROUGH;
case 'f': return in(t, float_set) ? pt::fixed : pt::none;
case 'G': upper = true; FMT_FALLTHROUGH;
case 'g': return in(t, float_set) ? pt::general : pt::none;
case 'A': upper = true; FMT_FALLTHROUGH;
case 'a': return in(t, float_set) ? pt::hexfloat : pt::none;
case 'c': return in(t, integral_set) ? pt::chr : pt::none;
case 's': return in(t, string_set | cstring_set) ? pt::string : pt::none;
case 'p': return in(t, pointer_set | cstring_set) ? pt::pointer : pt::none;
default: return pt::none;
}
}
template <typename Char, typename Context>
void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
basic_format_args<Context> args) {
using iterator = basic_appender<Char>;
auto out = iterator(buf);
auto context = basic_printf_context<Char>(out, args);
auto parse_ctx = parse_context<Char>(format);
// Returns the argument with specified index or, if arg_index is -1, the next
// argument.
auto get_arg = [&](int arg_index) {
if (arg_index < 0)
arg_index = parse_ctx.next_arg_id();
else
parse_ctx.check_arg_id(--arg_index);
return detail::get_arg(context, arg_index);
};
const Char* start = parse_ctx.begin();
const Char* end = parse_ctx.end();
auto it = start;
while (it != end) {
if (!find<false, Char>(it, end, '%', it)) {
it = end; // find leaves it == nullptr if it doesn't find '%'.
break;
}
Char c = *it++;
if (it != end && *it == c) {
write(out, basic_string_view<Char>(start, to_unsigned(it - start)));
start = ++it;
continue;
}
write(out, basic_string_view<Char>(start, to_unsigned(it - 1 - start)));
auto specs = format_specs();
specs.set_align(align::right);
// Parse argument index, flags and width.
int arg_index = parse_header(it, end, specs, get_arg);
if (arg_index == 0) report_error("argument not found");
// Parse precision.
if (it != end && *it == '.') {
++it;
c = it != end ? *it : 0;
if ('0' <= c && c <= '9') {
specs.precision = parse_nonnegative_int(it, end, 0);
} else if (c == '*') {
++it;
specs.precision =
static_cast<int>(get_arg(-1).visit(printf_precision_handler()));
} else {
specs.precision = 0;
}
}
auto arg = get_arg(arg_index);
// For d, i, o, u, x, and X conversion specifiers, if a precision is
// specified, the '0' flag is ignored
if (specs.precision >= 0 && is_integral_type(arg.type())) {
// Ignore '0' for non-numeric types or if '-' present.
specs.set_fill(' ');
}
if (specs.precision >= 0 && arg.type() == type::cstring_type) {
auto str = arg.visit(get_cstring<Char>());
auto str_end = str + specs.precision;
auto nul = std::find(str, str_end, Char());
auto sv = basic_string_view<Char>(
str, to_unsigned(nul != str_end ? nul - str : specs.precision));
arg = sv;
}
if (specs.alt() && arg.visit(is_zero_int())) specs.clear_alt();
if (specs.fill_unit<Char>() == '0') {
if (is_arithmetic_type(arg.type()) && specs.align() != align::left) {
specs.set_align(align::numeric);
} else {
// Ignore '0' flag for non-numeric types or if '-' flag is also present.
specs.set_fill(' ');
}
}
// Parse length and convert the argument to the required type.
c = it != end ? *it++ : 0;
Char t = it != end ? *it : 0;
switch (c) {
case 'h':
if (t == 'h') {
++it;
t = it != end ? *it : 0;
convert_arg<signed char>(arg, t);
} else {
convert_arg<short>(arg, t);
}
break;
case 'l':
if (t == 'l') {
++it;
t = it != end ? *it : 0;
convert_arg<long long>(arg, t);
} else {
convert_arg<long>(arg, t);
}
break;
case 'j': convert_arg<intmax_t>(arg, t); break;
case 'z': convert_arg<size_t>(arg, t); break;
case 't': convert_arg<std::ptrdiff_t>(arg, t); break;
case 'L':
// printf produces garbage when 'L' is omitted for long double, no
// need to do the same.
break;
default: --it; convert_arg<void>(arg, c);
}
// Parse type.
if (it == end) report_error("invalid format string");
char type = static_cast<char>(*it++);
if (is_integral_type(arg.type())) {
// Normalize type.
switch (type) {
case 'i':
case 'u': type = 'd'; break;
case 'c':
arg.visit(char_converter<basic_printf_context<Char>>(arg));
break;
}
}
bool upper = false;
specs.set_type(parse_printf_presentation_type(type, arg.type(), upper));
if (specs.type() == presentation_type::none)
report_error("invalid format specifier");
if (upper) specs.set_upper();
start = it;
// Format argument.
arg.visit(printf_arg_formatter<Char>(out, specs, context));
}
write(out, basic_string_view<Char>(start, to_unsigned(it - start)));
}
} // namespace detail
using printf_context = basic_printf_context<char>;
using wprintf_context = basic_printf_context<wchar_t>;
using printf_args = basic_format_args<printf_context>;
using wprintf_args = basic_format_args<wprintf_context>;
/// Constructs an `format_arg_store` object that contains references to
/// arguments and can be implicitly converted to `printf_args`.
template <typename Char = char, typename... T>
inline auto make_printf_args(T&... args)
-> decltype(fmt::make_format_args<basic_printf_context<Char>>(args...)) {
return fmt::make_format_args<basic_printf_context<Char>>(args...);
}
template <typename Char> struct vprintf_args {
using type = basic_format_args<basic_printf_context<Char>>;
};
template <typename Char>
inline auto vsprintf(basic_string_view<Char> fmt,
typename vprintf_args<Char>::type args)
-> std::basic_string<Char> {
auto buf = basic_memory_buffer<Char>();
detail::vprintf(buf, fmt, args);
return {buf.data(), buf.size()};
}
/**
* Formats `args` according to specifications in `fmt` and returns the result
* as as string.
*
* **Example**:
*
* std::string message = fmt::sprintf("The answer is %d", 42);
*/
template <typename S, typename... T, typename Char = detail::char_t<S>>
inline auto sprintf(const S& fmt, const T&... args) -> std::basic_string<Char> {
return vsprintf(detail::to_string_view(fmt),
fmt::make_format_args<basic_printf_context<Char>>(args...));
}
template <typename Char>
inline auto vfprintf(std::FILE* f, basic_string_view<Char> fmt,
typename vprintf_args<Char>::type args) -> int {
auto buf = basic_memory_buffer<Char>();
detail::vprintf(buf, fmt, args);
size_t size = buf.size();
return std::fwrite(buf.data(), sizeof(Char), size, f) < size
? -1
: static_cast<int>(size);
}
/**
* Formats `args` according to specifications in `fmt` and writes the output
* to `f`.
*
* **Example**:
*
* fmt::fprintf(stderr, "Don't %s!", "panic");
*/
template <typename S, typename... T, typename Char = detail::char_t<S>>
inline auto fprintf(std::FILE* f, const S& fmt, const T&... args) -> int {
return vfprintf(f, detail::to_string_view(fmt),
make_printf_args<Char>(args...));
}
template <typename Char>
FMT_DEPRECATED inline auto vprintf(basic_string_view<Char> fmt,
typename vprintf_args<Char>::type args)
-> int {
return vfprintf(stdout, fmt, args);
}
/**
* Formats `args` according to specifications in `fmt` and writes the output
* to `stdout`.
*
* **Example**:
*
* fmt::printf("Elapsed time: %.2f seconds", 1.23);
*/
template <typename... T>
inline auto printf(string_view fmt, const T&... args) -> int {
return vfprintf(stdout, fmt, make_printf_args(args...));
}
template <typename... T>
FMT_DEPRECATED inline auto printf(basic_string_view<wchar_t> fmt,
const T&... args) -> int {
return vfprintf(stdout, fmt, make_printf_args<wchar_t>(args...));
}
FMT_END_EXPORT
FMT_END_NAMESPACE
#endif // FMT_PRINTF_H_
+850
View File
@@ -0,0 +1,850 @@
// Formatting library for C++ - range and tuple support
//
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_RANGES_H_
#define FMT_RANGES_H_
#ifndef FMT_MODULE
# include <initializer_list>
# include <iterator>
# include <string>
# include <tuple>
# include <type_traits>
# include <utility>
#endif
#include "format.h"
FMT_BEGIN_NAMESPACE
FMT_EXPORT
enum class range_format { disabled, map, set, sequence, string, debug_string };
namespace detail {
template <typename T> class is_map {
template <typename U> static auto check(U*) -> typename U::mapped_type;
template <typename> static void check(...);
public:
static constexpr const bool value =
!std::is_void<decltype(check<T>(nullptr))>::value;
};
template <typename T> class is_set {
template <typename U> static auto check(U*) -> typename U::key_type;
template <typename> static void check(...);
public:
static constexpr const bool value =
!std::is_void<decltype(check<T>(nullptr))>::value && !is_map<T>::value;
};
// C array overload
template <typename T, std::size_t N>
auto range_begin(const T (&arr)[N]) -> const T* {
return arr;
}
template <typename T, std::size_t N>
auto range_end(const T (&arr)[N]) -> const T* {
return arr + N;
}
template <typename T, typename Enable = void>
struct has_member_fn_begin_end_t : std::false_type {};
template <typename T>
struct has_member_fn_begin_end_t<T, void_t<decltype(*std::declval<T>().begin()),
decltype(std::declval<T>().end())>>
: std::true_type {};
// Member function overloads.
template <typename T>
auto range_begin(T&& rng) -> decltype(static_cast<T&&>(rng).begin()) {
return static_cast<T&&>(rng).begin();
}
template <typename T>
auto range_end(T&& rng) -> decltype(static_cast<T&&>(rng).end()) {
return static_cast<T&&>(rng).end();
}
// ADL overloads. Only participate in overload resolution if member functions
// are not found.
template <typename T>
auto range_begin(T&& rng)
-> enable_if_t<!has_member_fn_begin_end_t<T&&>::value,
decltype(begin(static_cast<T&&>(rng)))> {
return begin(static_cast<T&&>(rng));
}
template <typename T>
auto range_end(T&& rng) -> enable_if_t<!has_member_fn_begin_end_t<T&&>::value,
decltype(end(static_cast<T&&>(rng)))> {
return end(static_cast<T&&>(rng));
}
template <typename T, typename Enable = void>
struct has_const_begin_end : std::false_type {};
template <typename T, typename Enable = void>
struct has_mutable_begin_end : std::false_type {};
template <typename T>
struct has_const_begin_end<
T, void_t<decltype(*detail::range_begin(
std::declval<const remove_cvref_t<T>&>())),
decltype(detail::range_end(
std::declval<const remove_cvref_t<T>&>()))>>
: std::true_type {};
template <typename T>
struct has_mutable_begin_end<
T, void_t<decltype(*detail::range_begin(std::declval<T&>())),
decltype(detail::range_end(std::declval<T&>())),
// the extra int here is because older versions of MSVC don't
// SFINAE properly unless there are distinct types
int>> : std::true_type {};
template <typename T, typename _ = void> struct is_range_ : std::false_type {};
template <typename T>
struct is_range_<T, void>
: std::integral_constant<bool, (has_const_begin_end<T>::value ||
has_mutable_begin_end<T>::value)> {};
// tuple_size and tuple_element check.
template <typename T> class is_tuple_like_ {
template <typename U, typename V = typename std::remove_cv<U>::type>
static auto check(U* p) -> decltype(std::tuple_size<V>::value, 0);
template <typename> static void check(...);
public:
static constexpr const bool value =
!std::is_void<decltype(check<T>(nullptr))>::value;
};
// Check for integer_sequence
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VERSION >= 1900
template <typename T, T... N>
using integer_sequence = std::integer_sequence<T, N...>;
template <size_t... N> using index_sequence = std::index_sequence<N...>;
template <size_t N> using make_index_sequence = std::make_index_sequence<N>;
#else
template <typename T, T... N> struct integer_sequence {
using value_type = T;
static FMT_CONSTEXPR auto size() -> size_t { return sizeof...(N); }
};
template <size_t... N> using index_sequence = integer_sequence<size_t, N...>;
template <typename T, size_t N, T... Ns>
struct make_integer_sequence : make_integer_sequence<T, N - 1, N - 1, Ns...> {};
template <typename T, T... Ns>
struct make_integer_sequence<T, 0, Ns...> : integer_sequence<T, Ns...> {};
template <size_t N>
using make_index_sequence = make_integer_sequence<size_t, N>;
#endif
template <typename T>
using tuple_index_sequence = make_index_sequence<std::tuple_size<T>::value>;
template <typename T, typename C, bool = is_tuple_like_<T>::value>
class is_tuple_formattable_ {
public:
static constexpr const bool value = false;
};
template <typename T, typename C> class is_tuple_formattable_<T, C, true> {
template <size_t... Is>
static auto all_true(index_sequence<Is...>,
integer_sequence<bool, (Is >= 0)...>) -> std::true_type;
static auto all_true(...) -> std::false_type;
template <size_t... Is>
static auto check(index_sequence<Is...>) -> decltype(all_true(
index_sequence<Is...>{},
integer_sequence<bool,
(is_formattable<typename std::tuple_element<Is, T>::type,
C>::value)...>{}));
public:
static constexpr const bool value =
decltype(check(tuple_index_sequence<T>{}))::value;
};
template <typename Tuple, typename F, size_t... Is>
FMT_CONSTEXPR void for_each(index_sequence<Is...>, Tuple&& t, F&& f) {
using std::get;
// Using a free function get<Is>(Tuple) now.
const int unused[] = {0, ((void)f(get<Is>(t)), 0)...};
ignore_unused(unused);
}
template <typename Tuple, typename F>
FMT_CONSTEXPR void for_each(Tuple&& t, F&& f) {
for_each(tuple_index_sequence<remove_cvref_t<Tuple>>(),
std::forward<Tuple>(t), std::forward<F>(f));
}
template <typename Tuple1, typename Tuple2, typename F, size_t... Is>
void for_each2(index_sequence<Is...>, Tuple1&& t1, Tuple2&& t2, F&& f) {
using std::get;
const int unused[] = {0, ((void)f(get<Is>(t1), get<Is>(t2)), 0)...};
ignore_unused(unused);
}
template <typename Tuple1, typename Tuple2, typename F>
void for_each2(Tuple1&& t1, Tuple2&& t2, F&& f) {
for_each2(tuple_index_sequence<remove_cvref_t<Tuple1>>(),
std::forward<Tuple1>(t1), std::forward<Tuple2>(t2),
std::forward<F>(f));
}
namespace tuple {
// Workaround a bug in MSVC 2019 (v140).
template <typename Char, typename... T>
using result_t = std::tuple<formatter<remove_cvref_t<T>, Char>...>;
using std::get;
template <typename Tuple, typename Char, std::size_t... Is>
auto get_formatters(index_sequence<Is...>)
-> result_t<Char, decltype(get<Is>(std::declval<Tuple>()))...>;
} // namespace tuple
#if FMT_MSC_VERSION && FMT_MSC_VERSION < 1920
// Older MSVC doesn't get the reference type correctly for arrays.
template <typename R> struct range_reference_type_impl {
using type = decltype(*detail::range_begin(std::declval<R&>()));
};
template <typename T, std::size_t N> struct range_reference_type_impl<T[N]> {
using type = T&;
};
template <typename T>
using range_reference_type = typename range_reference_type_impl<T>::type;
#else
template <typename Range>
using range_reference_type =
decltype(*detail::range_begin(std::declval<Range&>()));
#endif
// We don't use the Range's value_type for anything, but we do need the Range's
// reference type, with cv-ref stripped.
template <typename Range>
using uncvref_type = remove_cvref_t<range_reference_type<Range>>;
template <typename Formatter>
FMT_CONSTEXPR auto maybe_set_debug_format(Formatter& f, bool set)
-> decltype(f.set_debug_format(set)) {
f.set_debug_format(set);
}
template <typename Formatter>
FMT_CONSTEXPR void maybe_set_debug_format(Formatter&, ...) {}
template <typename T>
struct range_format_kind_
: std::integral_constant<range_format,
std::is_same<uncvref_type<T>, T>::value
? range_format::disabled
: is_map<T>::value ? range_format::map
: is_set<T>::value ? range_format::set
: range_format::sequence> {};
template <range_format K>
using range_format_constant = std::integral_constant<range_format, K>;
// These are not generic lambdas for compatibility with C++11.
template <typename Char> struct parse_empty_specs {
template <typename Formatter> FMT_CONSTEXPR void operator()(Formatter& f) {
f.parse(ctx);
detail::maybe_set_debug_format(f, true);
}
parse_context<Char>& ctx;
};
template <typename FormatContext> struct format_tuple_element {
using char_type = typename FormatContext::char_type;
template <typename T>
void operator()(const formatter<T, char_type>& f, const T& v) {
if (i > 0) ctx.advance_to(detail::copy<char_type>(separator, ctx.out()));
ctx.advance_to(f.format(v, ctx));
++i;
}
int i;
FormatContext& ctx;
basic_string_view<char_type> separator;
};
} // namespace detail
template <typename T> struct is_tuple_like {
static constexpr const bool value =
detail::is_tuple_like_<T>::value && !detail::is_range_<T>::value;
};
template <typename T, typename C> struct is_tuple_formattable {
static constexpr const bool value =
detail::is_tuple_formattable_<T, C>::value;
};
template <typename Tuple, typename Char>
struct formatter<Tuple, Char,
enable_if_t<fmt::is_tuple_like<Tuple>::value &&
fmt::is_tuple_formattable<Tuple, Char>::value>> {
private:
decltype(detail::tuple::get_formatters<Tuple, Char>(
detail::tuple_index_sequence<Tuple>())) formatters_;
basic_string_view<Char> separator_ = detail::string_literal<Char, ',', ' '>{};
basic_string_view<Char> opening_bracket_ =
detail::string_literal<Char, '('>{};
basic_string_view<Char> closing_bracket_ =
detail::string_literal<Char, ')'>{};
public:
FMT_CONSTEXPR formatter() {}
FMT_CONSTEXPR void set_separator(basic_string_view<Char> sep) {
separator_ = sep;
}
FMT_CONSTEXPR void set_brackets(basic_string_view<Char> open,
basic_string_view<Char> close) {
opening_bracket_ = open;
closing_bracket_ = close;
}
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
auto it = ctx.begin();
auto end = ctx.end();
if (it != end && detail::to_ascii(*it) == 'n') {
++it;
set_brackets({}, {});
set_separator({});
}
if (it != end && *it != '}') report_error("invalid format specifier");
ctx.advance_to(it);
detail::for_each(formatters_, detail::parse_empty_specs<Char>{ctx});
return it;
}
template <typename FormatContext>
auto format(const Tuple& value, FormatContext& ctx) const
-> decltype(ctx.out()) {
ctx.advance_to(detail::copy<Char>(opening_bracket_, ctx.out()));
detail::for_each2(
formatters_, value,
detail::format_tuple_element<FormatContext>{0, ctx, separator_});
return detail::copy<Char>(closing_bracket_, ctx.out());
}
};
template <typename T, typename Char> struct is_range {
static constexpr const bool value =
detail::is_range_<T>::value && !detail::has_to_string_view<T>::value;
};
namespace detail {
template <typename Char, typename Element>
using range_formatter_type = formatter<remove_cvref_t<Element>, Char>;
template <typename R>
using maybe_const_range =
conditional_t<has_const_begin_end<R>::value, const R, R>;
template <typename R, typename Char>
struct is_formattable_delayed
: is_formattable<uncvref_type<maybe_const_range<R>>, Char> {};
} // namespace detail
template <typename...> struct conjunction : std::true_type {};
template <typename P> struct conjunction<P> : P {};
template <typename P1, typename... Pn>
struct conjunction<P1, Pn...>
: conditional_t<bool(P1::value), conjunction<Pn...>, P1> {};
template <typename T, typename Char, typename Enable = void>
struct range_formatter;
template <typename T, typename Char>
struct range_formatter<
T, Char,
enable_if_t<conjunction<std::is_same<T, remove_cvref_t<T>>,
is_formattable<T, Char>>::value>> {
private:
detail::range_formatter_type<Char, T> underlying_;
basic_string_view<Char> separator_ = detail::string_literal<Char, ',', ' '>{};
basic_string_view<Char> opening_bracket_ =
detail::string_literal<Char, '['>{};
basic_string_view<Char> closing_bracket_ =
detail::string_literal<Char, ']'>{};
bool is_debug = false;
template <typename Output, typename It, typename Sentinel, typename U = T,
FMT_ENABLE_IF(std::is_same<U, Char>::value)>
auto write_debug_string(Output& out, It it, Sentinel end) const -> Output {
auto buf = basic_memory_buffer<Char>();
for (; it != end; ++it) buf.push_back(*it);
auto specs = format_specs();
specs.set_type(presentation_type::debug);
return detail::write<Char>(
out, basic_string_view<Char>(buf.data(), buf.size()), specs);
}
template <typename Output, typename It, typename Sentinel, typename U = T,
FMT_ENABLE_IF(!std::is_same<U, Char>::value)>
auto write_debug_string(Output& out, It, Sentinel) const -> Output {
return out;
}
public:
FMT_CONSTEXPR range_formatter() {}
FMT_CONSTEXPR auto underlying() -> detail::range_formatter_type<Char, T>& {
return underlying_;
}
FMT_CONSTEXPR void set_separator(basic_string_view<Char> sep) {
separator_ = sep;
}
FMT_CONSTEXPR void set_brackets(basic_string_view<Char> open,
basic_string_view<Char> close) {
opening_bracket_ = open;
closing_bracket_ = close;
}
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
auto it = ctx.begin();
auto end = ctx.end();
detail::maybe_set_debug_format(underlying_, true);
if (it == end) return underlying_.parse(ctx);
switch (detail::to_ascii(*it)) {
case 'n':
set_brackets({}, {});
++it;
break;
case '?':
is_debug = true;
set_brackets({}, {});
++it;
if (it == end || *it != 's') report_error("invalid format specifier");
FMT_FALLTHROUGH;
case 's':
if (!std::is_same<T, Char>::value)
report_error("invalid format specifier");
if (!is_debug) {
set_brackets(detail::string_literal<Char, '"'>{},
detail::string_literal<Char, '"'>{});
set_separator({});
detail::maybe_set_debug_format(underlying_, false);
}
++it;
return it;
}
if (it != end && *it != '}') {
if (*it != ':') report_error("invalid format specifier");
detail::maybe_set_debug_format(underlying_, false);
++it;
}
ctx.advance_to(it);
return underlying_.parse(ctx);
}
template <typename R, typename FormatContext>
auto format(R&& range, FormatContext& ctx) const -> decltype(ctx.out()) {
auto out = ctx.out();
auto it = detail::range_begin(range);
auto end = detail::range_end(range);
if (is_debug) return write_debug_string(out, std::move(it), end);
out = detail::copy<Char>(opening_bracket_, out);
int i = 0;
for (; it != end; ++it) {
if (i > 0) out = detail::copy<Char>(separator_, out);
ctx.advance_to(out);
auto&& item = *it; // Need an lvalue
out = underlying_.format(item, ctx);
++i;
}
out = detail::copy<Char>(closing_bracket_, out);
return out;
}
};
FMT_EXPORT
template <typename T, typename Char, typename Enable = void>
struct range_format_kind
: conditional_t<
is_range<T, Char>::value, detail::range_format_kind_<T>,
std::integral_constant<range_format, range_format::disabled>> {};
template <typename R, typename Char>
struct formatter<
R, Char,
enable_if_t<conjunction<
bool_constant<
range_format_kind<R, Char>::value != range_format::disabled &&
range_format_kind<R, Char>::value != range_format::map &&
range_format_kind<R, Char>::value != range_format::string &&
range_format_kind<R, Char>::value != range_format::debug_string>,
detail::is_formattable_delayed<R, Char>>::value>> {
private:
using range_type = detail::maybe_const_range<R>;
range_formatter<detail::uncvref_type<range_type>, Char> range_formatter_;
public:
using nonlocking = void;
FMT_CONSTEXPR formatter() {
if (detail::const_check(range_format_kind<R, Char>::value !=
range_format::set))
return;
range_formatter_.set_brackets(detail::string_literal<Char, '{'>{},
detail::string_literal<Char, '}'>{});
}
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
return range_formatter_.parse(ctx);
}
template <typename FormatContext>
auto format(range_type& range, FormatContext& ctx) const
-> decltype(ctx.out()) {
return range_formatter_.format(range, ctx);
}
};
// A map formatter.
template <typename R, typename Char>
struct formatter<
R, Char,
enable_if_t<conjunction<
bool_constant<range_format_kind<R, Char>::value == range_format::map>,
detail::is_formattable_delayed<R, Char>>::value>> {
private:
using map_type = detail::maybe_const_range<R>;
using element_type = detail::uncvref_type<map_type>;
decltype(detail::tuple::get_formatters<element_type, Char>(
detail::tuple_index_sequence<element_type>())) formatters_;
bool no_delimiters_ = false;
public:
FMT_CONSTEXPR formatter() {}
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
auto it = ctx.begin();
auto end = ctx.end();
if (it != end) {
if (detail::to_ascii(*it) == 'n') {
no_delimiters_ = true;
++it;
}
if (it != end && *it != '}') {
if (*it != ':') report_error("invalid format specifier");
++it;
}
ctx.advance_to(it);
}
detail::for_each(formatters_, detail::parse_empty_specs<Char>{ctx});
return it;
}
template <typename FormatContext>
auto format(map_type& map, FormatContext& ctx) const -> decltype(ctx.out()) {
auto out = ctx.out();
basic_string_view<Char> open = detail::string_literal<Char, '{'>{};
if (!no_delimiters_) out = detail::copy<Char>(open, out);
int i = 0;
basic_string_view<Char> sep = detail::string_literal<Char, ',', ' '>{};
for (auto&& value : map) {
if (i > 0) out = detail::copy<Char>(sep, out);
ctx.advance_to(out);
detail::for_each2(formatters_, value,
detail::format_tuple_element<FormatContext>{
0, ctx, detail::string_literal<Char, ':', ' '>{}});
++i;
}
basic_string_view<Char> close = detail::string_literal<Char, '}'>{};
if (!no_delimiters_) out = detail::copy<Char>(close, out);
return out;
}
};
// A (debug_)string formatter.
template <typename R, typename Char>
struct formatter<
R, Char,
enable_if_t<range_format_kind<R, Char>::value == range_format::string ||
range_format_kind<R, Char>::value ==
range_format::debug_string>> {
private:
using range_type = detail::maybe_const_range<R>;
using string_type =
conditional_t<std::is_constructible<
detail::std_string_view<Char>,
decltype(detail::range_begin(std::declval<R>())),
decltype(detail::range_end(std::declval<R>()))>::value,
detail::std_string_view<Char>, std::basic_string<Char>>;
formatter<string_type, Char> underlying_;
public:
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
return underlying_.parse(ctx);
}
template <typename FormatContext>
auto format(range_type& range, FormatContext& ctx) const
-> decltype(ctx.out()) {
auto out = ctx.out();
if (detail::const_check(range_format_kind<R, Char>::value ==
range_format::debug_string))
*out++ = '"';
out = underlying_.format(
string_type{detail::range_begin(range), detail::range_end(range)}, ctx);
if (detail::const_check(range_format_kind<R, Char>::value ==
range_format::debug_string))
*out++ = '"';
return out;
}
};
template <typename It, typename Sentinel, typename Char = char>
struct join_view : detail::view {
It begin;
Sentinel end;
basic_string_view<Char> sep;
join_view(It b, Sentinel e, basic_string_view<Char> s)
: begin(std::move(b)), end(e), sep(s) {}
};
template <typename It, typename Sentinel, typename Char>
struct formatter<join_view<It, Sentinel, Char>, Char> {
private:
using value_type =
#ifdef __cpp_lib_ranges
std::iter_value_t<It>;
#else
typename std::iterator_traits<It>::value_type;
#endif
formatter<remove_cvref_t<value_type>, Char> value_formatter_;
using view = conditional_t<std::is_copy_constructible<It>::value,
const join_view<It, Sentinel, Char>,
join_view<It, Sentinel, Char>>;
public:
using nonlocking = void;
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
return value_formatter_.parse(ctx);
}
template <typename FormatContext>
auto format(view& value, FormatContext& ctx) const -> decltype(ctx.out()) {
using iter =
conditional_t<std::is_copy_constructible<view>::value, It, It&>;
iter it = value.begin;
auto out = ctx.out();
if (it == value.end) return out;
out = value_formatter_.format(*it, ctx);
++it;
while (it != value.end) {
out = detail::copy<Char>(value.sep.begin(), value.sep.end(), out);
ctx.advance_to(out);
out = value_formatter_.format(*it, ctx);
++it;
}
return out;
}
};
template <typename Char, typename Tuple> struct tuple_join_view : detail::view {
const Tuple& tuple;
basic_string_view<Char> sep;
tuple_join_view(const Tuple& t, basic_string_view<Char> s)
: tuple(t), sep{s} {}
};
// Define FMT_TUPLE_JOIN_SPECIFIERS to enable experimental format specifiers
// support in tuple_join. It is disabled by default because of issues with
// the dynamic width and precision.
#ifndef FMT_TUPLE_JOIN_SPECIFIERS
# define FMT_TUPLE_JOIN_SPECIFIERS 0
#endif
template <typename Char, typename Tuple>
struct formatter<tuple_join_view<Char, Tuple>, Char,
enable_if_t<is_tuple_like<Tuple>::value>> {
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
return do_parse(ctx, std::tuple_size<Tuple>());
}
template <typename FormatContext>
auto format(const tuple_join_view<Char, Tuple>& value,
FormatContext& ctx) const -> typename FormatContext::iterator {
return do_format(value, ctx, std::tuple_size<Tuple>());
}
private:
decltype(detail::tuple::get_formatters<Tuple, Char>(
detail::tuple_index_sequence<Tuple>())) formatters_;
FMT_CONSTEXPR auto do_parse(parse_context<Char>& ctx,
std::integral_constant<size_t, 0>)
-> const Char* {
return ctx.begin();
}
template <size_t N>
FMT_CONSTEXPR auto do_parse(parse_context<Char>& ctx,
std::integral_constant<size_t, N>)
-> const Char* {
auto end = ctx.begin();
#if FMT_TUPLE_JOIN_SPECIFIERS
end = std::get<std::tuple_size<Tuple>::value - N>(formatters_).parse(ctx);
if (N > 1) {
auto end1 = do_parse(ctx, std::integral_constant<size_t, N - 1>());
if (end != end1)
report_error("incompatible format specs for tuple elements");
}
#endif
return end;
}
template <typename FormatContext>
auto do_format(const tuple_join_view<Char, Tuple>&, FormatContext& ctx,
std::integral_constant<size_t, 0>) const ->
typename FormatContext::iterator {
return ctx.out();
}
template <typename FormatContext, size_t N>
auto do_format(const tuple_join_view<Char, Tuple>& value, FormatContext& ctx,
std::integral_constant<size_t, N>) const ->
typename FormatContext::iterator {
using std::get;
auto out =
std::get<std::tuple_size<Tuple>::value - N>(formatters_)
.format(get<std::tuple_size<Tuple>::value - N>(value.tuple), ctx);
if (N <= 1) return out;
out = detail::copy<Char>(value.sep, out);
ctx.advance_to(out);
return do_format(value, ctx, std::integral_constant<size_t, N - 1>());
}
};
namespace detail {
// Check if T has an interface like a container adaptor (e.g. std::stack,
// std::queue, std::priority_queue).
template <typename T> class is_container_adaptor_like {
template <typename U> static auto check(U* p) -> typename U::container_type;
template <typename> static void check(...);
public:
static constexpr const bool value =
!std::is_void<decltype(check<T>(nullptr))>::value;
};
template <typename Container> struct all {
const Container& c;
auto begin() const -> typename Container::const_iterator { return c.begin(); }
auto end() const -> typename Container::const_iterator { return c.end(); }
};
} // namespace detail
template <typename T, typename Char>
struct formatter<
T, Char,
enable_if_t<conjunction<detail::is_container_adaptor_like<T>,
bool_constant<range_format_kind<T, Char>::value ==
range_format::disabled>>::value>>
: formatter<detail::all<typename T::container_type>, Char> {
using all = detail::all<typename T::container_type>;
template <typename FormatContext>
auto format(const T& t, FormatContext& ctx) const -> decltype(ctx.out()) {
struct getter : T {
static auto get(const T& t) -> all {
return {t.*(&getter::c)}; // Access c through the derived class.
}
};
return formatter<all>::format(getter::get(t), ctx);
}
};
FMT_BEGIN_EXPORT
/// Returns a view that formats the iterator range `[begin, end)` with elements
/// separated by `sep`.
template <typename It, typename Sentinel>
auto join(It begin, Sentinel end, string_view sep) -> join_view<It, Sentinel> {
return {std::move(begin), end, sep};
}
/**
* Returns a view that formats `range` with elements separated by `sep`.
*
* **Example**:
*
* auto v = std::vector<int>{1, 2, 3};
* fmt::print("{}", fmt::join(v, ", "));
* // Output: 1, 2, 3
*
* `fmt::join` applies passed format specifiers to the range elements:
*
* fmt::print("{:02}", fmt::join(v, ", "));
* // Output: 01, 02, 03
*/
template <typename Range, FMT_ENABLE_IF(!is_tuple_like<Range>::value)>
auto join(Range&& r, string_view sep)
-> join_view<decltype(detail::range_begin(r)),
decltype(detail::range_end(r))> {
return {detail::range_begin(r), detail::range_end(r), sep};
}
/**
* Returns an object that formats `std::tuple` with elements separated by `sep`.
*
* **Example**:
*
* auto t = std::tuple<int, char>{1, 'a'};
* fmt::print("{}", fmt::join(t, ", "));
* // Output: 1, a
*/
template <typename Tuple, FMT_ENABLE_IF(is_tuple_like<Tuple>::value)>
FMT_CONSTEXPR auto join(const Tuple& tuple, string_view sep)
-> tuple_join_view<char, Tuple> {
return {tuple, sep};
}
/**
* Returns an object that formats `std::initializer_list` with elements
* separated by `sep`.
*
* **Example**:
*
* fmt::print("{}", fmt::join({1, 2, 3}, ", "));
* // Output: "1, 2, 3"
*/
template <typename T>
auto join(std::initializer_list<T> list, string_view sep)
-> join_view<const T*, const T*> {
return join(std::begin(list), std::end(list), sep);
}
FMT_END_EXPORT
FMT_END_NAMESPACE
#endif // FMT_RANGES_H_
+726
View File
@@ -0,0 +1,726 @@
// Formatting library for C++ - formatters for standard library types
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_STD_H_
#define FMT_STD_H_
#include "format.h"
#include "ostream.h"
#ifndef FMT_MODULE
# include <atomic>
# include <bitset>
# include <complex>
# include <cstdlib>
# include <exception>
# include <functional>
# include <memory>
# include <thread>
# include <type_traits>
# include <typeinfo>
# include <utility>
# include <vector>
// Check FMT_CPLUSPLUS to suppress a bogus warning in MSVC.
# if FMT_CPLUSPLUS >= 201703L
# if FMT_HAS_INCLUDE(<filesystem>) && \
(!defined(FMT_CPP_LIB_FILESYSTEM) || FMT_CPP_LIB_FILESYSTEM != 0)
# include <filesystem>
# endif
# if FMT_HAS_INCLUDE(<variant>)
# include <variant>
# endif
# if FMT_HAS_INCLUDE(<optional>)
# include <optional>
# endif
# endif
// Use > instead of >= in the version check because <source_location> may be
// available after C++17 but before C++20 is marked as implemented.
# if FMT_CPLUSPLUS > 201703L && FMT_HAS_INCLUDE(<source_location>)
# include <source_location>
# endif
# if FMT_CPLUSPLUS > 202002L && FMT_HAS_INCLUDE(<expected>)
# include <expected>
# endif
#endif // FMT_MODULE
#if FMT_HAS_INCLUDE(<version>)
# include <version>
#endif
// GCC 4 does not support FMT_HAS_INCLUDE.
#if FMT_HAS_INCLUDE(<cxxabi.h>) || defined(__GLIBCXX__)
# include <cxxabi.h>
// Android NDK with gabi++ library on some architectures does not implement
// abi::__cxa_demangle().
# ifndef __GABIXX_CXXABI_H__
# define FMT_HAS_ABI_CXA_DEMANGLE
# endif
#endif
// For older Xcode versions, __cpp_lib_xxx flags are inaccurately defined.
#ifndef FMT_CPP_LIB_FILESYSTEM
# ifdef __cpp_lib_filesystem
# define FMT_CPP_LIB_FILESYSTEM __cpp_lib_filesystem
# else
# define FMT_CPP_LIB_FILESYSTEM 0
# endif
#endif
#ifndef FMT_CPP_LIB_VARIANT
# ifdef __cpp_lib_variant
# define FMT_CPP_LIB_VARIANT __cpp_lib_variant
# else
# define FMT_CPP_LIB_VARIANT 0
# endif
#endif
#if FMT_CPP_LIB_FILESYSTEM
FMT_BEGIN_NAMESPACE
namespace detail {
template <typename Char, typename PathChar>
auto get_path_string(const std::filesystem::path& p,
const std::basic_string<PathChar>& native) {
if constexpr (std::is_same_v<Char, char> && std::is_same_v<PathChar, wchar_t>)
return to_utf8<wchar_t>(native, to_utf8_error_policy::replace);
else
return p.string<Char>();
}
template <typename Char, typename PathChar>
void write_escaped_path(basic_memory_buffer<Char>& quoted,
const std::filesystem::path& p,
const std::basic_string<PathChar>& native) {
if constexpr (std::is_same_v<Char, char> &&
std::is_same_v<PathChar, wchar_t>) {
auto buf = basic_memory_buffer<wchar_t>();
write_escaped_string<wchar_t>(std::back_inserter(buf), native);
bool valid = to_utf8<wchar_t>::convert(quoted, {buf.data(), buf.size()});
FMT_ASSERT(valid, "invalid utf16");
} else if constexpr (std::is_same_v<Char, PathChar>) {
write_escaped_string<std::filesystem::path::value_type>(
std::back_inserter(quoted), native);
} else {
write_escaped_string<Char>(std::back_inserter(quoted), p.string<Char>());
}
}
} // namespace detail
FMT_EXPORT
template <typename Char> struct formatter<std::filesystem::path, Char> {
private:
format_specs specs_;
detail::arg_ref<Char> width_ref_;
bool debug_ = false;
char path_type_ = 0;
public:
FMT_CONSTEXPR void set_debug_format(bool set = true) { debug_ = set; }
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) {
auto it = ctx.begin(), end = ctx.end();
if (it == end) return it;
it = detail::parse_align(it, end, specs_);
if (it == end) return it;
Char c = *it;
if ((c >= '0' && c <= '9') || c == '{')
it = detail::parse_width(it, end, specs_, width_ref_, ctx);
if (it != end && *it == '?') {
debug_ = true;
++it;
}
if (it != end && (*it == 'g')) path_type_ = detail::to_ascii(*it++);
return it;
}
template <typename FormatContext>
auto format(const std::filesystem::path& p, FormatContext& ctx) const {
auto specs = specs_;
auto path_string =
!path_type_ ? p.native()
: p.generic_string<std::filesystem::path::value_type>();
detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_,
ctx);
if (!debug_) {
auto s = detail::get_path_string<Char>(p, path_string);
return detail::write(ctx.out(), basic_string_view<Char>(s), specs);
}
auto quoted = basic_memory_buffer<Char>();
detail::write_escaped_path(quoted, p, path_string);
return detail::write(ctx.out(),
basic_string_view<Char>(quoted.data(), quoted.size()),
specs);
}
};
class path : public std::filesystem::path {
public:
auto display_string() const -> std::string {
const std::filesystem::path& base = *this;
return fmt::format(FMT_STRING("{}"), base);
}
auto system_string() const -> std::string { return string(); }
auto generic_display_string() const -> std::string {
const std::filesystem::path& base = *this;
return fmt::format(FMT_STRING("{:g}"), base);
}
auto generic_system_string() const -> std::string { return generic_string(); }
};
FMT_END_NAMESPACE
#endif // FMT_CPP_LIB_FILESYSTEM
FMT_BEGIN_NAMESPACE
FMT_EXPORT
template <std::size_t N, typename Char>
struct formatter<std::bitset<N>, Char>
: nested_formatter<basic_string_view<Char>, Char> {
private:
// Functor because C++11 doesn't support generic lambdas.
struct writer {
const std::bitset<N>& bs;
template <typename OutputIt>
FMT_CONSTEXPR auto operator()(OutputIt out) -> OutputIt {
for (auto pos = N; pos > 0; --pos) {
out = detail::write<Char>(out, bs[pos - 1] ? Char('1') : Char('0'));
}
return out;
}
};
public:
template <typename FormatContext>
auto format(const std::bitset<N>& bs, FormatContext& ctx) const
-> decltype(ctx.out()) {
return this->write_padded(ctx, writer{bs});
}
};
FMT_EXPORT
template <typename Char>
struct formatter<std::thread::id, Char> : basic_ostream_formatter<Char> {};
FMT_END_NAMESPACE
#ifdef __cpp_lib_optional
FMT_BEGIN_NAMESPACE
FMT_EXPORT
template <typename T, typename Char>
struct formatter<std::optional<T>, Char,
std::enable_if_t<is_formattable<T, Char>::value>> {
private:
formatter<T, Char> underlying_;
static constexpr basic_string_view<Char> optional =
detail::string_literal<Char, 'o', 'p', 't', 'i', 'o', 'n', 'a', 'l',
'('>{};
static constexpr basic_string_view<Char> none =
detail::string_literal<Char, 'n', 'o', 'n', 'e'>{};
template <class U>
FMT_CONSTEXPR static auto maybe_set_debug_format(U& u, bool set)
-> decltype(u.set_debug_format(set)) {
u.set_debug_format(set);
}
template <class U>
FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {}
public:
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) {
maybe_set_debug_format(underlying_, true);
return underlying_.parse(ctx);
}
template <typename FormatContext>
auto format(const std::optional<T>& opt, FormatContext& ctx) const
-> decltype(ctx.out()) {
if (!opt) return detail::write<Char>(ctx.out(), none);
auto out = ctx.out();
out = detail::write<Char>(out, optional);
ctx.advance_to(out);
out = underlying_.format(*opt, ctx);
return detail::write(out, ')');
}
};
FMT_END_NAMESPACE
#endif // __cpp_lib_optional
#if defined(__cpp_lib_expected) || FMT_CPP_LIB_VARIANT
FMT_BEGIN_NAMESPACE
namespace detail {
template <typename Char, typename OutputIt, typename T>
auto write_escaped_alternative(OutputIt out, const T& v) -> OutputIt {
if constexpr (has_to_string_view<T>::value)
return write_escaped_string<Char>(out, detail::to_string_view(v));
if constexpr (std::is_same_v<T, Char>) return write_escaped_char(out, v);
return write<Char>(out, v);
}
} // namespace detail
FMT_END_NAMESPACE
#endif
#ifdef __cpp_lib_expected
FMT_BEGIN_NAMESPACE
FMT_EXPORT
template <typename T, typename E, typename Char>
struct formatter<std::expected<T, E>, Char,
std::enable_if_t<(std::is_void<T>::value ||
is_formattable<T, Char>::value) &&
is_formattable<E, Char>::value>> {
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
return ctx.begin();
}
template <typename FormatContext>
auto format(const std::expected<T, E>& value, FormatContext& ctx) const
-> decltype(ctx.out()) {
auto out = ctx.out();
if (value.has_value()) {
out = detail::write<Char>(out, "expected(");
if constexpr (!std::is_void<T>::value)
out = detail::write_escaped_alternative<Char>(out, *value);
} else {
out = detail::write<Char>(out, "unexpected(");
out = detail::write_escaped_alternative<Char>(out, value.error());
}
*out++ = ')';
return out;
}
};
FMT_END_NAMESPACE
#endif // __cpp_lib_expected
#ifdef __cpp_lib_source_location
FMT_BEGIN_NAMESPACE
FMT_EXPORT
template <> struct formatter<std::source_location> {
FMT_CONSTEXPR auto parse(parse_context<>& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const std::source_location& loc, FormatContext& ctx) const
-> decltype(ctx.out()) {
auto out = ctx.out();
out = detail::write(out, loc.file_name());
out = detail::write(out, ':');
out = detail::write<char>(out, loc.line());
out = detail::write(out, ':');
out = detail::write<char>(out, loc.column());
out = detail::write(out, ": ");
out = detail::write(out, loc.function_name());
return out;
}
};
FMT_END_NAMESPACE
#endif
#if FMT_CPP_LIB_VARIANT
FMT_BEGIN_NAMESPACE
namespace detail {
template <typename T>
using variant_index_sequence =
std::make_index_sequence<std::variant_size<T>::value>;
template <typename> struct is_variant_like_ : std::false_type {};
template <typename... Types>
struct is_variant_like_<std::variant<Types...>> : std::true_type {};
// formattable element check.
template <typename T, typename C> class is_variant_formattable_ {
template <std::size_t... Is>
static std::conjunction<
is_formattable<std::variant_alternative_t<Is, T>, C>...>
check(std::index_sequence<Is...>);
public:
static constexpr const bool value =
decltype(check(variant_index_sequence<T>{}))::value;
};
} // namespace detail
template <typename T> struct is_variant_like {
static constexpr const bool value = detail::is_variant_like_<T>::value;
};
template <typename T, typename C> struct is_variant_formattable {
static constexpr const bool value =
detail::is_variant_formattable_<T, C>::value;
};
FMT_EXPORT
template <typename Char> struct formatter<std::monostate, Char> {
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
return ctx.begin();
}
template <typename FormatContext>
auto format(const std::monostate&, FormatContext& ctx) const
-> decltype(ctx.out()) {
return detail::write<Char>(ctx.out(), "monostate");
}
};
FMT_EXPORT
template <typename Variant, typename Char>
struct formatter<
Variant, Char,
std::enable_if_t<std::conjunction_v<
is_variant_like<Variant>, is_variant_formattable<Variant, Char>>>> {
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
return ctx.begin();
}
template <typename FormatContext>
auto format(const Variant& value, FormatContext& ctx) const
-> decltype(ctx.out()) {
auto out = ctx.out();
out = detail::write<Char>(out, "variant(");
FMT_TRY {
std::visit(
[&](const auto& v) {
out = detail::write_escaped_alternative<Char>(out, v);
},
value);
}
FMT_CATCH(const std::bad_variant_access&) {
detail::write<Char>(out, "valueless by exception");
}
*out++ = ')';
return out;
}
};
FMT_END_NAMESPACE
#endif // FMT_CPP_LIB_VARIANT
FMT_BEGIN_NAMESPACE
FMT_EXPORT
template <> struct formatter<std::error_code> {
private:
format_specs specs_;
detail::arg_ref<char> width_ref_;
public:
FMT_CONSTEXPR auto parse(parse_context<>& ctx) -> const char* {
auto it = ctx.begin(), end = ctx.end();
if (it == end) return it;
it = detail::parse_align(it, end, specs_);
if (it == end) return it;
char c = *it;
if ((c >= '0' && c <= '9') || c == '{')
it = detail::parse_width(it, end, specs_, width_ref_, ctx);
return it;
}
template <typename FormatContext>
FMT_CONSTEXPR20 auto format(const std::error_code& ec,
FormatContext& ctx) const -> decltype(ctx.out()) {
auto specs = specs_;
detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_,
ctx);
memory_buffer buf;
buf.append(string_view(ec.category().name()));
buf.push_back(':');
detail::write<char>(appender(buf), ec.value());
return detail::write<char>(ctx.out(), string_view(buf.data(), buf.size()),
specs);
}
};
#if FMT_USE_RTTI
namespace detail {
template <typename Char, typename OutputIt>
auto write_demangled_name(OutputIt out, const std::type_info& ti) -> OutputIt {
# ifdef FMT_HAS_ABI_CXA_DEMANGLE
int status = 0;
std::size_t size = 0;
std::unique_ptr<char, void (*)(void*)> demangled_name_ptr(
abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &std::free);
string_view demangled_name_view;
if (demangled_name_ptr) {
demangled_name_view = demangled_name_ptr.get();
// Normalization of stdlib inline namespace names.
// libc++ inline namespaces.
// std::__1::* -> std::*
// std::__1::__fs::* -> std::*
// libstdc++ inline namespaces.
// std::__cxx11::* -> std::*
// std::filesystem::__cxx11::* -> std::filesystem::*
if (demangled_name_view.starts_with("std::")) {
char* begin = demangled_name_ptr.get();
char* to = begin + 5; // std::
for (char *from = to, *end = begin + demangled_name_view.size();
from < end;) {
// This is safe, because demangled_name is NUL-terminated.
if (from[0] == '_' && from[1] == '_') {
char* next = from + 1;
while (next < end && *next != ':') next++;
if (next[0] == ':' && next[1] == ':') {
from = next + 2;
continue;
}
}
*to++ = *from++;
}
demangled_name_view = {begin, detail::to_unsigned(to - begin)};
}
} else {
demangled_name_view = string_view(ti.name());
}
return detail::write_bytes<Char>(out, demangled_name_view);
# elif FMT_MSC_VERSION
const string_view demangled_name(ti.name());
for (std::size_t i = 0; i < demangled_name.size(); ++i) {
auto sub = demangled_name;
sub.remove_prefix(i);
if (sub.starts_with("enum ")) {
i += 4;
continue;
}
if (sub.starts_with("class ") || sub.starts_with("union ")) {
i += 5;
continue;
}
if (sub.starts_with("struct ")) {
i += 6;
continue;
}
if (*sub.begin() != ' ') *out++ = *sub.begin();
}
return out;
# else
return detail::write_bytes<Char>(out, string_view(ti.name()));
# endif
}
} // namespace detail
FMT_EXPORT
template <typename Char>
struct formatter<std::type_info, Char // DEPRECATED! Mixing code unit types.
> {
public:
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
return ctx.begin();
}
template <typename Context>
auto format(const std::type_info& ti, Context& ctx) const
-> decltype(ctx.out()) {
return detail::write_demangled_name<Char>(ctx.out(), ti);
}
};
#endif
FMT_EXPORT
template <typename T, typename Char>
struct formatter<
T, Char, // DEPRECATED! Mixing code unit types.
typename std::enable_if<std::is_base_of<std::exception, T>::value>::type> {
private:
bool with_typename_ = false;
public:
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
auto it = ctx.begin();
auto end = ctx.end();
if (it == end || *it == '}') return it;
if (*it == 't') {
++it;
with_typename_ = FMT_USE_RTTI != 0;
}
return it;
}
template <typename Context>
auto format(const std::exception& ex, Context& ctx) const
-> decltype(ctx.out()) {
auto out = ctx.out();
#if FMT_USE_RTTI
if (with_typename_) {
out = detail::write_demangled_name<Char>(out, typeid(ex));
*out++ = ':';
*out++ = ' ';
}
#endif
return detail::write_bytes<Char>(out, string_view(ex.what()));
}
};
namespace detail {
template <typename T, typename Enable = void>
struct has_flip : std::false_type {};
template <typename T>
struct has_flip<T, void_t<decltype(std::declval<T>().flip())>>
: std::true_type {};
template <typename T> struct is_bit_reference_like {
static constexpr const bool value =
std::is_convertible<T, bool>::value &&
std::is_nothrow_assignable<T, bool>::value && has_flip<T>::value;
};
#ifdef _LIBCPP_VERSION
// Workaround for libc++ incompatibility with C++ standard.
// According to the Standard, `bitset::operator[] const` returns bool.
template <typename C>
struct is_bit_reference_like<std::__bit_const_reference<C>> {
static constexpr const bool value = true;
};
#endif
} // namespace detail
// We can't use std::vector<bool, Allocator>::reference and
// std::bitset<N>::reference because the compiler can't deduce Allocator and N
// in partial specialization.
FMT_EXPORT
template <typename BitRef, typename Char>
struct formatter<BitRef, Char,
enable_if_t<detail::is_bit_reference_like<BitRef>::value>>
: formatter<bool, Char> {
template <typename FormatContext>
FMT_CONSTEXPR auto format(const BitRef& v, FormatContext& ctx) const
-> decltype(ctx.out()) {
return formatter<bool, Char>::format(v, ctx);
}
};
template <typename T, typename Deleter>
auto ptr(const std::unique_ptr<T, Deleter>& p) -> const void* {
return p.get();
}
template <typename T> auto ptr(const std::shared_ptr<T>& p) -> const void* {
return p.get();
}
FMT_EXPORT
template <typename T, typename Char>
struct formatter<std::atomic<T>, Char,
enable_if_t<is_formattable<T, Char>::value>>
: formatter<T, Char> {
template <typename FormatContext>
auto format(const std::atomic<T>& v, FormatContext& ctx) const
-> decltype(ctx.out()) {
return formatter<T, Char>::format(v.load(), ctx);
}
};
#ifdef __cpp_lib_atomic_flag_test
FMT_EXPORT
template <typename Char>
struct formatter<std::atomic_flag, Char> : formatter<bool, Char> {
template <typename FormatContext>
auto format(const std::atomic_flag& v, FormatContext& ctx) const
-> decltype(ctx.out()) {
return formatter<bool, Char>::format(v.test(), ctx);
}
};
#endif // __cpp_lib_atomic_flag_test
FMT_EXPORT
template <typename T, typename Char> struct formatter<std::complex<T>, Char> {
private:
detail::dynamic_format_specs<Char> specs_;
template <typename FormatContext, typename OutputIt>
FMT_CONSTEXPR auto do_format(const std::complex<T>& c,
detail::dynamic_format_specs<Char>& specs,
FormatContext& ctx, OutputIt out) const
-> OutputIt {
if (c.real() != 0) {
*out++ = Char('(');
out = detail::write<Char>(out, c.real(), specs, ctx.locale());
specs.set_sign(sign::plus);
out = detail::write<Char>(out, c.imag(), specs, ctx.locale());
if (!detail::isfinite(c.imag())) *out++ = Char(' ');
*out++ = Char('i');
*out++ = Char(')');
return out;
}
out = detail::write<Char>(out, c.imag(), specs, ctx.locale());
if (!detail::isfinite(c.imag())) *out++ = Char(' ');
*out++ = Char('i');
return out;
}
public:
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
if (ctx.begin() == ctx.end() || *ctx.begin() == '}') return ctx.begin();
return parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx,
detail::type_constant<T, Char>::value);
}
template <typename FormatContext>
auto format(const std::complex<T>& c, FormatContext& ctx) const
-> decltype(ctx.out()) {
auto specs = specs_;
if (specs.dynamic()) {
detail::handle_dynamic_spec(specs.dynamic_width(), specs.width,
specs.width_ref, ctx);
detail::handle_dynamic_spec(specs.dynamic_precision(), specs.precision,
specs.precision_ref, ctx);
}
if (specs.width == 0) return do_format(c, specs, ctx, ctx.out());
auto buf = basic_memory_buffer<Char>();
auto outer_specs = format_specs();
outer_specs.width = specs.width;
outer_specs.copy_fill_from(specs);
outer_specs.set_align(specs.align());
specs.width = 0;
specs.set_fill({});
specs.set_align(align::none);
do_format(c, specs, ctx, basic_appender<Char>(buf));
return detail::write<Char>(ctx.out(),
basic_string_view<Char>(buf.data(), buf.size()),
outer_specs);
}
};
FMT_EXPORT
template <typename T, typename Char>
struct formatter<std::reference_wrapper<T>, Char,
enable_if_t<is_formattable<remove_cvref_t<T>, Char>::value>>
: formatter<remove_cvref_t<T>, Char> {
template <typename FormatContext>
auto format(std::reference_wrapper<T> ref, FormatContext& ctx) const
-> decltype(ctx.out()) {
return formatter<remove_cvref_t<T>, Char>::format(ref.get(), ctx);
}
};
FMT_END_NAMESPACE
#endif // FMT_STD_H_
+373
View File
@@ -0,0 +1,373 @@
// Formatting library for C++ - optional wchar_t and exotic character support
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_XCHAR_H_
#define FMT_XCHAR_H_
#include "color.h"
#include "format.h"
#include "ostream.h"
#include "ranges.h"
#ifndef FMT_MODULE
# include <cwchar>
# if FMT_USE_LOCALE
# include <locale>
# endif
#endif
FMT_BEGIN_NAMESPACE
namespace detail {
template <typename T>
using is_exotic_char = bool_constant<!std::is_same<T, char>::value>;
template <typename S, typename = void> struct format_string_char {};
template <typename S>
struct format_string_char<
S, void_t<decltype(sizeof(detail::to_string_view(std::declval<S>())))>> {
using type = char_t<S>;
};
template <typename S>
struct format_string_char<
S, enable_if_t<std::is_base_of<detail::compile_string, S>::value>> {
using type = typename S::char_type;
};
template <typename S>
using format_string_char_t = typename format_string_char<S>::type;
inline auto write_loc(basic_appender<wchar_t> out, loc_value value,
const format_specs& specs, locale_ref loc) -> bool {
#if FMT_USE_LOCALE
auto& numpunct =
std::use_facet<std::numpunct<wchar_t>>(loc.get<std::locale>());
auto separator = std::wstring();
auto grouping = numpunct.grouping();
if (!grouping.empty()) separator = std::wstring(1, numpunct.thousands_sep());
return value.visit(loc_writer<wchar_t>{out, specs, separator, grouping, {}});
#endif
return false;
}
} // namespace detail
FMT_BEGIN_EXPORT
using wstring_view = basic_string_view<wchar_t>;
using wformat_parse_context = parse_context<wchar_t>;
using wformat_context = buffered_context<wchar_t>;
using wformat_args = basic_format_args<wformat_context>;
using wmemory_buffer = basic_memory_buffer<wchar_t>;
template <typename Char, typename... T> struct basic_fstring {
private:
basic_string_view<Char> str_;
static constexpr int num_static_named_args =
detail::count_static_named_args<T...>();
using checker = detail::format_string_checker<
Char, static_cast<int>(sizeof...(T)), num_static_named_args,
num_static_named_args != detail::count_named_args<T...>()>;
using arg_pack = detail::arg_pack<T...>;
public:
using t = basic_fstring;
template <typename S,
FMT_ENABLE_IF(
std::is_convertible<const S&, basic_string_view<Char>>::value)>
FMT_CONSTEVAL FMT_ALWAYS_INLINE basic_fstring(const S& s) : str_(s) {
if (FMT_USE_CONSTEVAL)
detail::parse_format_string<Char>(s, checker(s, arg_pack()));
}
template <typename S,
FMT_ENABLE_IF(std::is_base_of<detail::compile_string, S>::value&&
std::is_same<typename S::char_type, Char>::value)>
FMT_ALWAYS_INLINE basic_fstring(const S&) : str_(S()) {
FMT_CONSTEXPR auto sv = basic_string_view<Char>(S());
FMT_CONSTEXPR int ignore =
(parse_format_string(sv, checker(sv, arg_pack())), 0);
detail::ignore_unused(ignore);
}
basic_fstring(runtime_format_string<Char> fmt) : str_(fmt.str) {}
operator basic_string_view<Char>() const { return str_; }
auto get() const -> basic_string_view<Char> { return str_; }
};
template <typename Char, typename... T>
using basic_format_string = basic_fstring<Char, T...>;
template <typename... T>
using wformat_string = typename basic_format_string<wchar_t, T...>::t;
inline auto runtime(wstring_view s) -> runtime_format_string<wchar_t> {
return {{s}};
}
template <> struct is_char<wchar_t> : std::true_type {};
template <> struct is_char<char16_t> : std::true_type {};
template <> struct is_char<char32_t> : std::true_type {};
#ifdef __cpp_char8_t
template <> struct is_char<char8_t> : bool_constant<detail::is_utf8_enabled> {};
#endif
template <typename... T>
constexpr auto make_wformat_args(T&... args)
-> decltype(fmt::make_format_args<wformat_context>(args...)) {
return fmt::make_format_args<wformat_context>(args...);
}
#if !FMT_USE_NONTYPE_TEMPLATE_ARGS
inline namespace literals {
inline auto operator""_a(const wchar_t* s, size_t) -> detail::udl_arg<wchar_t> {
return {s};
}
} // namespace literals
#endif
template <typename It, typename Sentinel>
auto join(It begin, Sentinel end, wstring_view sep)
-> join_view<It, Sentinel, wchar_t> {
return {begin, end, sep};
}
template <typename Range, FMT_ENABLE_IF(!is_tuple_like<Range>::value)>
auto join(Range&& range, wstring_view sep)
-> join_view<decltype(std::begin(range)), decltype(std::end(range)),
wchar_t> {
return join(std::begin(range), std::end(range), sep);
}
template <typename T>
auto join(std::initializer_list<T> list, wstring_view sep)
-> join_view<const T*, const T*, wchar_t> {
return join(std::begin(list), std::end(list), sep);
}
template <typename Tuple, FMT_ENABLE_IF(is_tuple_like<Tuple>::value)>
auto join(const Tuple& tuple, basic_string_view<wchar_t> sep)
-> tuple_join_view<wchar_t, Tuple> {
return {tuple, sep};
}
template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
auto vformat(basic_string_view<Char> fmt,
typename detail::vformat_args<Char>::type args)
-> std::basic_string<Char> {
auto buf = basic_memory_buffer<Char>();
detail::vformat_to(buf, fmt, args);
return {buf.data(), buf.size()};
}
template <typename... T>
auto format(wformat_string<T...> fmt, T&&... args) -> std::wstring {
return vformat(fmt::wstring_view(fmt), fmt::make_wformat_args(args...));
}
template <typename OutputIt, typename... T>
auto format_to(OutputIt out, wformat_string<T...> fmt, T&&... args)
-> OutputIt {
return vformat_to(out, fmt::wstring_view(fmt),
fmt::make_wformat_args(args...));
}
// Pass char_t as a default template parameter instead of using
// std::basic_string<char_t<S>> to reduce the symbol size.
template <typename S, typename... T,
typename Char = detail::format_string_char_t<S>,
FMT_ENABLE_IF(!std::is_same<Char, char>::value &&
!std::is_same<Char, wchar_t>::value)>
auto format(const S& fmt, T&&... args) -> std::basic_string<Char> {
return vformat(detail::to_string_view(fmt),
fmt::make_format_args<buffered_context<Char>>(args...));
}
template <typename Locale, typename S,
typename Char = detail::format_string_char_t<S>,
FMT_ENABLE_IF(detail::is_locale<Locale>::value&&
detail::is_exotic_char<Char>::value)>
inline auto vformat(const Locale& loc, const S& fmt,
typename detail::vformat_args<Char>::type args)
-> std::basic_string<Char> {
auto buf = basic_memory_buffer<Char>();
detail::vformat_to(buf, detail::to_string_view(fmt), args,
detail::locale_ref(loc));
return {buf.data(), buf.size()};
}
template <typename Locale, typename S, typename... T,
typename Char = detail::format_string_char_t<S>,
FMT_ENABLE_IF(detail::is_locale<Locale>::value&&
detail::is_exotic_char<Char>::value)>
inline auto format(const Locale& loc, const S& fmt, T&&... args)
-> std::basic_string<Char> {
return vformat(loc, detail::to_string_view(fmt),
fmt::make_format_args<buffered_context<Char>>(args...));
}
template <typename OutputIt, typename S,
typename Char = detail::format_string_char_t<S>,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
detail::is_exotic_char<Char>::value)>
auto vformat_to(OutputIt out, const S& fmt,
typename detail::vformat_args<Char>::type args) -> OutputIt {
auto&& buf = detail::get_buffer<Char>(out);
detail::vformat_to(buf, detail::to_string_view(fmt), args);
return detail::get_iterator(buf, out);
}
template <typename OutputIt, typename S, typename... T,
typename Char = detail::format_string_char_t<S>,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value &&
!std::is_same<Char, char>::value &&
!std::is_same<Char, wchar_t>::value)>
inline auto format_to(OutputIt out, const S& fmt, T&&... args) -> OutputIt {
return vformat_to(out, detail::to_string_view(fmt),
fmt::make_format_args<buffered_context<Char>>(args...));
}
template <typename Locale, typename S, typename OutputIt, typename... Args,
typename Char = detail::format_string_char_t<S>,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
detail::is_locale<Locale>::value&&
detail::is_exotic_char<Char>::value)>
inline auto vformat_to(OutputIt out, const Locale& loc, const S& fmt,
typename detail::vformat_args<Char>::type args)
-> OutputIt {
auto&& buf = detail::get_buffer<Char>(out);
vformat_to(buf, detail::to_string_view(fmt), args, detail::locale_ref(loc));
return detail::get_iterator(buf, out);
}
template <typename Locale, typename OutputIt, typename S, typename... T,
typename Char = detail::format_string_char_t<S>,
bool enable = detail::is_output_iterator<OutputIt, Char>::value &&
detail::is_locale<Locale>::value &&
detail::is_exotic_char<Char>::value>
inline auto format_to(OutputIt out, const Locale& loc, const S& fmt,
T&&... args) ->
typename std::enable_if<enable, OutputIt>::type {
return vformat_to(out, loc, detail::to_string_view(fmt),
fmt::make_format_args<buffered_context<Char>>(args...));
}
template <typename OutputIt, typename Char, typename... Args,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
detail::is_exotic_char<Char>::value)>
inline auto vformat_to_n(OutputIt out, size_t n, basic_string_view<Char> fmt,
typename detail::vformat_args<Char>::type args)
-> format_to_n_result<OutputIt> {
using traits = detail::fixed_buffer_traits;
auto buf = detail::iterator_buffer<OutputIt, Char, traits>(out, n);
detail::vformat_to(buf, fmt, args);
return {buf.out(), buf.count()};
}
template <typename OutputIt, typename S, typename... T,
typename Char = detail::format_string_char_t<S>,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
detail::is_exotic_char<Char>::value)>
inline auto format_to_n(OutputIt out, size_t n, const S& fmt, T&&... args)
-> format_to_n_result<OutputIt> {
return vformat_to_n(out, n, fmt::basic_string_view<Char>(fmt),
fmt::make_format_args<buffered_context<Char>>(args...));
}
template <typename S, typename... T,
typename Char = detail::format_string_char_t<S>,
FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)>
inline auto formatted_size(const S& fmt, T&&... args) -> size_t {
auto buf = detail::counting_buffer<Char>();
detail::vformat_to(buf, detail::to_string_view(fmt),
fmt::make_format_args<buffered_context<Char>>(args...));
return buf.count();
}
inline void vprint(std::FILE* f, wstring_view fmt, wformat_args args) {
auto buf = wmemory_buffer();
detail::vformat_to(buf, fmt, args);
buf.push_back(L'\0');
if (std::fputws(buf.data(), f) == -1)
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
}
inline void vprint(wstring_view fmt, wformat_args args) {
vprint(stdout, fmt, args);
}
template <typename... T>
void print(std::FILE* f, wformat_string<T...> fmt, T&&... args) {
return vprint(f, wstring_view(fmt), fmt::make_wformat_args(args...));
}
template <typename... T> void print(wformat_string<T...> fmt, T&&... args) {
return vprint(wstring_view(fmt), fmt::make_wformat_args(args...));
}
template <typename... T>
void println(std::FILE* f, wformat_string<T...> fmt, T&&... args) {
return print(f, L"{}\n", fmt::format(fmt, std::forward<T>(args)...));
}
template <typename... T> void println(wformat_string<T...> fmt, T&&... args) {
return print(L"{}\n", fmt::format(fmt, std::forward<T>(args)...));
}
inline auto vformat(const text_style& ts, wstring_view fmt, wformat_args args)
-> std::wstring {
auto buf = wmemory_buffer();
detail::vformat_to(buf, ts, fmt, args);
return {buf.data(), buf.size()};
}
template <typename... T>
inline auto format(const text_style& ts, wformat_string<T...> fmt, T&&... args)
-> std::wstring {
return fmt::vformat(ts, fmt, fmt::make_wformat_args(args...));
}
template <typename... T>
FMT_DEPRECATED void print(std::FILE* f, const text_style& ts,
wformat_string<T...> fmt, const T&... args) {
vprint(f, ts, fmt, fmt::make_wformat_args(args...));
}
template <typename... T>
FMT_DEPRECATED void print(const text_style& ts, wformat_string<T...> fmt,
const T&... args) {
return print(stdout, ts, fmt, args...);
}
inline void vprint(std::wostream& os, wstring_view fmt, wformat_args args) {
auto buffer = basic_memory_buffer<wchar_t>();
detail::vformat_to(buffer, fmt, args);
detail::write_buffer(os, buffer);
}
template <typename... T>
void print(std::wostream& os, wformat_string<T...> fmt, T&&... args) {
vprint(os, fmt, fmt::make_format_args<buffered_context<wchar_t>>(args...));
}
template <typename... T>
void println(std::wostream& os, wformat_string<T...> fmt, T&&... args) {
print(os, L"{}\n", fmt::format(fmt, std::forward<T>(args)...));
}
/// Converts `value` to `std::wstring` using the default format for type `T`.
template <typename T> inline auto to_wstring(const T& value) -> std::wstring {
return format(FMT_STRING(L"{}"), value);
}
FMT_END_EXPORT
FMT_END_NAMESPACE
#endif // FMT_XCHAR_H_
+46
View File
@@ -0,0 +1,46 @@
// Formatting library for C++
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include "fmt/format-inl.h"
FMT_BEGIN_NAMESPACE
namespace detail {
template FMT_API auto dragonbox::to_decimal(float x) noexcept
-> dragonbox::decimal_fp<float>;
template FMT_API auto dragonbox::to_decimal(double x) noexcept
-> dragonbox::decimal_fp<double>;
#if FMT_USE_LOCALE
// DEPRECATED! locale_ref in the detail namespace
template FMT_API locale_ref::locale_ref(const std::locale& loc);
template FMT_API auto locale_ref::get<std::locale>() const -> std::locale;
#endif
// Explicit instantiations for char.
template FMT_API auto thousands_sep_impl(locale_ref)
-> thousands_sep_result<char>;
template FMT_API auto decimal_point_impl(locale_ref) -> char;
// DEPRECATED!
template FMT_API void buffer<char>::append(const char*, const char*);
// DEPRECATED!
template FMT_API void vformat_to(buffer<char>&, string_view,
typename vformat_args<>::type, locale_ref);
// Explicit instantiations for wchar_t.
template FMT_API auto thousands_sep_impl(locale_ref)
-> thousands_sep_result<wchar_t>;
template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t;
template FMT_API void buffer<wchar_t>::append(const wchar_t*, const wchar_t*);
} // namespace detail
FMT_END_NAMESPACE
+5
View File
@@ -0,0 +1,5 @@
{fmt}
11.1.3
https://github.com/fmtlib/fmt
only required files are present.
+18
View File
@@ -0,0 +1,18 @@
###############################################################################
# License: BSD Zero Clause License file
# Copyright:
# (C) 2021 Alexander Shaduri <ashaduri@gmail.com>
###############################################################################
add_library(nlohmann_json INTERFACE)
# Relative sources are allowed only since cmake 3.13.
target_sources(nlohmann_json INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}/nlohmann/json.hpp
)
target_include_directories(nlohmann_json
SYSTEM INTERFACE
"${CMAKE_SOURCE_DIR}/dependencies/nlohmann_json"
)
File diff suppressed because it is too large Load Diff
+3
View File
@@ -0,0 +1,3 @@
JSON for Modern C++
version 3.12.0
https://github.com/nlohmann/json
+20
View File
@@ -0,0 +1,20 @@
###############################################################################
# License: BSD Zero Clause License file
# Copyright:
# (C) 2024 Alexander Shaduri <ashaduri@gmail.com>
###############################################################################
add_library(tl_expected INTERFACE)
# Relative sources are allowed only since cmake 3.13.
target_sources(tl_expected INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}/expected/include/tl/expected.hpp
)
target_include_directories(tl_expected
SYSTEM INTERFACE
"${CMAKE_SOURCE_DIR}/dependencies/tl_expected/expected/include"
)
+10
View File
@@ -0,0 +1,10 @@
os:
- Visual Studio 2015
- Visual Studio 2017
- Visual Studio 2019
- Visual Studio 2022
build_script:
- cmake -Bbuild -S.
- cmake --build build
- cmake --build build --target RUN_TESTS
+1
View File
@@ -0,0 +1 @@
BasedOnStyle: LLVM
@@ -0,0 +1,131 @@
name: CMake
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
jobs:
build:
runs-on: ubuntu-20.04
strategy:
matrix:
std: [11, 14]
cxx: [g++-4.8, g++-4.9, g++-5, g++-6, g++-7, g++-8, g++-9, g++-10, clang++-3.5, clang++-3.6, clang++-3.7, clang++-3.8, clang++-3.9, clang++-4.0, clang++-5.0, clang++-6.0, clang++-7, clang++-8, clang++-9, clang++-10, clang++-11]
exclude:
- cxx: g++-4.8
std: 14
- cxx: g++4.9
std: 14
include:
- cxx: g++-4.8
install: sudo apt install g++-4.8
- cxx: g++-4.9
install: sudo apt install g++-4.9
- cxx: g++-5
install: sudo apt install g++-5
- cxx: g++-6
install: sudo apt install g++-6
- cxx: g++-7
install: sudo apt install g++-7
- cxx: g++-8
std: 11
install: sudo apt install g++-8
- cxx: g++-8
std: 14
install: sudo apt install g++-8
- cxx: g++-8
std: 17
install: sudo apt install g++-8
- cxx: g++-9
std: 14
- cxx: g++-9
std: 17
- cxx: g++-10
std: 14
- cxx: g++-10
std: 17
- cxx: g++-11
std: 14
install: sudo apt install g++-11
- cxx: g++-11
std: 17
install: sudo apt install g++-11
- cxx: g++-11
std: 20
install: sudo apt install g++-11
- cxx: clang++-3.5
install: sudo apt install clang-3.5
- cxx: clang++-3.6
install: sudo apt install clang-3.6
- cxx: clang++-3.7
install: sudo apt install clang-3.7
- cxx: clang++-3.8
install: sudo apt install clang-3.8
- cxx: clang++-3.9
install: sudo apt install clang-3.9
- cxx: clang++-4.0
install: sudo apt install clang-4.0
- cxx: clang++-5.0
install: sudo apt install clang-5.0
- cxx: clang++-6.0
install: sudo apt install clang-6.0
- cxx: clang++-7
install: sudo apt install clang-7
- cxx: clang++-8
install: sudo apt install clang-8
- cxx: clang++-9
install: sudo apt install clang-9
- cxx: clang++-10
install: sudo apt install clang-10
- cxx: clang++-11
install: sudo apt install clang-11
- cxx: clang++-6.0
std: 17
install: sudo apt install clang-6.0
- cxx: clang++-7
std: 17
install: sudo apt install clang-7
- cxx: clang++-8
std: 17
install: sudo apt install clang-8
- cxx: clang++-9
std: 17
install: sudo apt install clang-9
- cxx: clang++-10
std: 17
install: sudo apt install clang-10
- cxx: clang++-11
std: 17
install: sudo apt install clang-11
steps:
- uses: actions/checkout@v3
- name: Setup Toolchain
run: |
sudo apt-add-repository 'deb http://azure.archive.ubuntu.com/ubuntu/ xenial main'
sudo apt-add-repository 'deb http://azure.archive.ubuntu.com/ubuntu/ xenial universe'
sudo apt-add-repository 'deb http://azure.archive.ubuntu.com/ubuntu/ bionic main'
sudo apt-add-repository 'deb http://azure.archive.ubuntu.com/ubuntu/ bionic universe'
${{matrix.install}}
- name: Configure CMake
env:
CXX: ${{matrix.cxx}}
run: cmake -B ${{github.workspace}}/build -DCMAKE_CXX_STANDARD=${{matrix.std}}
- name: Build
run: cmake --build ${{github.workspace}}/build
- name: Test
working-directory: ${{github.workspace}}/build
run: cmake --build ${{github.workspace}}/build --target test
@@ -0,0 +1,3 @@
\#*
.\#*
/build/
+268
View File
@@ -0,0 +1,268 @@
language: cpp
dist: xenial
matrix:
include:
- compiler: gcc
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-5
env: COMPILER=g++-5 CXXSTD=11
- compiler: gcc
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-6
env: COMPILER=g++-6 CXXSTD=11
- compiler: gcc
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-7
env: COMPILER=g++-7 CXXSTD=11
- compiler: gcc
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-8
env: COMPILER=g++-8 CXXSTD=11
- compiler: gcc
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.9
env: COMPILER=g++-4.9 CXXSTD=11
- compiler: gcc
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.8
env: COMPILER=g++-4.8 CXXSTD=11
- compiler: clang
addons:
apt:
sources:
- llvm-toolchain-precise-3.5
- ubuntu-toolchain-r-test
packages:
- clang++-3.5
- libc++-dev
env: COMPILER=clang++-3.5 CXXSTD=11
- compiler: clang
addons:
apt:
sources:
- llvm-toolchain-precise-3.6
- ubuntu-toolchain-r-test
packages:
- clang++-3.6
- libc++-dev
env: COMPILER=clang++-3.6 CXXSTD=11
- compiler: clang
addons:
apt:
sources:
- llvm-toolchain-precise-3.7
- ubuntu-toolchain-r-test
packages:
- clang++-3.7
- libc++-dev
env: COMPILER=clang++-3.7 CXXSTD=11
- compiler: clang
addons:
apt:
sources:
- sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-3.8 main"
key_url: "http://apt.llvm.org/llvm-snapshot.gpg.key"
- ubuntu-toolchain-r-test
packages:
- clang++-3.8
- libc++-dev
env: COMPILER=clang++-3.8 CXXSTD=11
- compiler: clang
addons:
apt:
sources:
- sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-3.9 main"
key_url: "http://apt.llvm.org/llvm-snapshot.gpg.key"
- ubuntu-toolchain-r-test
packages:
- clang++-3.9
- libc++-dev
env: COMPILER=clang++-3.9 CXXSTD=11
- compiler: clang
addons:
apt:
sources:
- llvm-toolchain-xenial-4.0
- ubuntu-toolchain-r-test
packages:
- clang++-4.0
- libc++-dev
env: COMPILER=clang++-4.0 CXXSTD=11
- compiler: clang
addons:
apt:
sources:
- llvm-toolchain-xenial-5.0
- ubuntu-toolchain-r-test
packages:
- clang++-5.0
- libc++-dev
env: COMPILER=clang++-5.0 CXXSTD=11
- compiler: clang
addons:
apt:
sources:
- llvm-toolchain-xenial-6.0
- ubuntu-toolchain-r-test
packages:
- clang++-6.0
- libc++-dev
env: COMPILER=clang++-6.0 CXXSTD=11
- compiler: gcc
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-5
env: COMPILER=g++-5 CXXSTD=14
- compiler: gcc
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-6
env: COMPILER=g++-6 CXXSTD=14
- compiler: gcc
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-7
env: COMPILER=g++-7 CXXSTD=14
- compiler: gcc
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-8
env: COMPILER=g++-8 CXXSTD=14
- compiler: clang
addons:
apt:
sources:
- llvm-toolchain-precise-3.5
- ubuntu-toolchain-r-test
packages:
- clang++-3.5
- libc++-dev
env: COMPILER=clang++-3.5 CXXSTD=14
- compiler: clang
addons:
apt:
sources:
- llvm-toolchain-precise-3.6
- ubuntu-toolchain-r-test
packages:
- clang++-3.6
- libc++-dev
env: COMPILER=clang++-3.6 CXXSTD=14
- compiler: clang
addons:
apt:
sources:
- llvm-toolchain-precise-3.7
- ubuntu-toolchain-r-test
packages:
- clang++-3.7
- libc++-dev
env: COMPILER=clang++-3.7 CXXSTD=14
- compiler: clang
addons:
apt:
sources:
- sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-3.8 main"
key_url: "http://apt.llvm.org/llvm-snapshot.gpg.key"
- ubuntu-toolchain-r-test
packages:
- clang++-3.8
- libc++-dev
env: COMPILER=clang++-3.8 CXXSTD=14
- compiler: clang
addons:
apt:
sources:
- sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-3.9 main"
key_url: "http://apt.llvm.org/llvm-snapshot.gpg.key"
- ubuntu-toolchain-r-test
packages:
- clang++-3.9
- libc++-dev
env: COMPILER=clang++-3.9 CXXSTD=14
- compiler: clang
addons:
apt:
sources:
- llvm-toolchain-xenial-4.0
- ubuntu-toolchain-r-test
packages:
- clang++-4.0
- libc++-dev
env: COMPILER=clang++-4.0 CXXSTD=14
- compiler: clang
addons:
apt:
sources:
- llvm-toolchain-xenial-5.0
- ubuntu-toolchain-r-test
packages:
- clang++-5.0
- libc++-dev
env: COMPILER=clang++-5.0 CXXSTD=14
- compiler: clang
addons:
apt:
sources:
- llvm-toolchain-xenial-6.0
- ubuntu-toolchain-r-test
packages:
- clang++-6.0
- libc++-dev
env: COMPILER=clang++-6.0 CXXSTD=14
before_install:
- sudo apt update
- sudo apt install -y apt-transport-https ca-certificates gnupg software-properties-common
- curl -L https://apt.kitware.com/keys/kitware-archive-latest.asc | sudo apt-key add -
- sudo apt-add-repository 'deb https://apt.kitware.com/ubuntu/ xenial main'
- sudo apt update
install:
- if [ "$CXX" = "clang++" ]; then export CXX="$COMPILER -stdlib=libc++"; fi
- if [ "$CXX" = "g++" ]; then export CXX="$COMPILER"; fi
- sudo apt install -y cmake
script:
- /usr/bin/cmake -B build -S . "-DCMAKE_CXX_STANDARD=$CXXSTD"
- /usr/bin/cmake --build build
- /usr/bin/cmake --build build --target test
+117
View File
@@ -0,0 +1,117 @@
cmake_minimum_required(VERSION 3.14)
project(tl-expected
HOMEPAGE_URL https://tl.tartanllama.xyz
DESCRIPTION "C++11/14/17 std::expected with functional-style extensions"
VERSION 1.0.0
LANGUAGES CXX)
include(CMakePackageConfigHelpers)
include(CMakeDependentOption)
include(GNUInstallDirs)
include(FetchContent)
include(CTest)
if (NOT DEFINED CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 14)
endif()
option(EXPECTED_BUILD_PACKAGE "Build package files as well" ON)
cmake_dependent_option(EXPECTED_BUILD_TESTS
"Enable tl::expected tests" ON
"BUILD_TESTING" OFF)
cmake_dependent_option(EXPECTED_BUILD_PACKAGE_DEB
"Create a DEB" ON
"EXPECTED_BUILD_PACKAGE" OFF)
add_library(expected INTERFACE)
target_include_directories(expected
INTERFACE
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
if (NOT CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
add_library(tl::expected ALIAS expected)
endif()
# Installation help
configure_package_config_file(
"${PROJECT_SOURCE_DIR}/cmake/${PROJECT_NAME}-config.cmake.in"
"${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config.cmake"
INSTALL_DESTINATION "share/cmake/${PROJECT_NAME}")
write_basic_package_version_file(
"${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake"
COMPATIBILITY SameMajorVersion
ARCH_INDEPENDENT)
install(TARGETS expected
EXPORT ${PROJECT_NAME}-targets
INCLUDES DESTINATION "${CMAKE_INSTALL_DATADIR}")
install(EXPORT ${PROJECT_NAME}-targets
DESTINATION "${CMAKE_INSTALL_DATADIR}/cmake/${PROJECT_NAME}"
NAMESPACE tl::
FILE "${PROJECT_NAME}-targets.cmake")
install(FILES
"${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake"
"${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config.cmake"
DESTINATION "${CMAKE_INSTALL_DATADIR}/cmake/${PROJECT_NAME}")
install(DIRECTORY "include/" TYPE INCLUDE)
if(EXPECTED_BUILD_TESTS)
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
set(CATCH_INSTALL_HELPERS OFF)
set(CATCH_BUILD_TESTING OFF)
set(CATCH_INSTALL_DOCS OFF)
FetchContent_Declare(Catch2 URL
https://github.com/catchorg/Catch2/archive/v2.13.10.zip)
FetchContent_MakeAvailable(Catch2)
file(GLOB test-sources CONFIGURE_DEPENDS tests/*.cpp)
list(FILTER test-sources EXCLUDE REGEX "tests/test.cpp")
add_executable(${PROJECT_NAME}-tests "${test-sources}")
target_compile_options(${PROJECT_NAME}-tests PRIVATE
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall -Wextra>)
target_link_libraries(${PROJECT_NAME}-tests
PRIVATE
Catch2::Catch2
expected)
add_test(NAME tl::expected::tests COMMAND ${PROJECT_NAME}-tests)
endif()
if (NOT EXPECTED_BUILD_PACKAGE)
return()
endif()
list(APPEND source-generators TBZ2 TGZ TXZ ZIP)
if (CMAKE_HOST_WIN32)
list(APPEND binary-generators "WIX")
endif()
if (EXPECTED_BUILD_PACKAGE_DEB)
list(APPEND binary-generators "DEB")
endif()
if (EXPECTED_BUILD_RPM)
list(APPEND binary-generators "RPM")
endif()
set(CPACK_SOURCE_GENERATOR ${source-generators})
set(CPACK_GENERATOR ${binary-generators})
set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION}")
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Sy Brand")
list(APPEND CPACK_SOURCE_IGNORE_FILES /.git/ /build/ .gitignore .DS_Store)
include(CPack)
+121
View File
@@ -0,0 +1,121 @@
Creative Commons Legal Code
CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.
+76
View File
@@ -0,0 +1,76 @@
# expected
Single header implementation of `std::expected` with functional-style extensions.
[![Documentation SmartStatus](https://readthedocs.org/projects/tl-docs/badge/?version=latest)](https://tl.tartanllama.xyz/en/latest/?badge=latest)
Clang + GCC: [![Linux Build SmartStatus](https://github.com/TartanLlama/expected/actions/workflows/cmake.yml/badge.svg)](https://github.com/TartanLlama/expected/actions/workflows/cmake.yml)
MSVC: [![Windows Build SmartStatus](https://ci.appveyor.com/api/projects/status/k5x00xa11y3s5wsg?svg=true)](https://ci.appveyor.com/project/TartanLlama/expected)
Available on [Vcpkg](https://github.com/microsoft/vcpkg/tree/master/ports/tl-expected) and [Conan](https://github.com/yipdw/conan-tl-expected).
[`std::expected`](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0323r3.pdf) is proposed as the preferred way to represent object which will either have an expected value, or an unexpected value giving information about why something failed. Unfortunately, chaining together many computations which may fail can be verbose, as error-checking code will be mixed in with the actual programming logic. This implementation provides a number of utilities to make coding with `expected` cleaner.
For example, instead of writing this code:
```cpp
std::expected<image,fail_reason> get_cute_cat (const image& img) {
auto cropped = crop_to_cat(img);
if (!cropped) {
return cropped;
}
auto with_tie = add_bow_tie(*cropped);
if (!with_tie) {
return with_tie;
}
auto with_sparkles = make_eyes_sparkle(*with_tie);
if (!with_sparkles) {
return with_sparkles;
}
return add_rainbow(make_smaller(*with_sparkles));
}
```
You can do this:
```cpp
tl::expected<image,fail_reason> get_cute_cat (const image& img) {
return crop_to_cat(img)
.and_then(add_bow_tie)
.and_then(make_eyes_sparkle)
.map(make_smaller)
.map(add_rainbow);
}
```
The interface is the same as `std::expected` as proposed in [p0323r3](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0323r3.pdf), but the following member functions are also defined. Explicit types are for clarity.
- `map`: carries out some operation on the stored object if there is one.
* `tl::expected<std::size_t,std::error_code> s = exp_string.map(&std::string::size);`
- `map_error`: carries out some operation on the unexpected object if there is one.
* `my_error_code translate_error (std::error_code);`
* `tl::expected<int,my_error_code> s = exp_int.map_error(translate_error);`
- `and_then`: like `map`, but for operations which return a `tl::expected`.
* `tl::expected<ast, fail_reason> parse (const std::string& s);`
* `tl::expected<ast, fail_reason> exp_ast = exp_string.and_then(parse);`
- `or_else`: calls some function if there is no value stored.
* `exp.or_else([] { throw std::runtime_error{"oh no"}; });`
p0323r3 specifies calling `.error()` on an expected value, or using the `*` or `->` operators on an unexpected value, to be undefined behaviour. In this implementation it causes an assertion failure. The implementation of assertions can be overridden by defining the macro `TL_ASSERT(boolean_condition)` before #including <tl/expected.hpp>; by default, `assert(boolean_condition)` from the `<cassert>` header is used. Note that correct code would not rely on these assertions.
### Compiler support
Tested on:
- Linux
* clang++ 3.5, 3.6, 3.7, 3.8, 3.9, 4, 5, 6, 7, 8, 9, 10, 11
* g++ 4.8, 4.9, 5.5, 6.4, 7.5, 8, 9, 10
- Windows
* MSVC 2015, 2017, 2019, 2022
----------
[![CC0](http://i.creativecommons.org/p/zero/1.0/88x31.png)]("http://creativecommons.org/publicdomain/zero/1.0/")
To the extent possible under law, [Sy Brand](https://twitter.com/TartanLlama) has waived all copyright and related or neighboring rights to the `expected` library. This work is published from: United Kingdom.
@@ -0,0 +1,3 @@
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/tl-expected-targets.cmake")
File diff suppressed because it is too large Load Diff
+18
View File
@@ -0,0 +1,18 @@
#include <catch2/catch.hpp>
#include <stdexcept>
#define TL_ASSERT(cond) if (!(cond)) { throw std::runtime_error(std::string("assertion failure")); }
#include <tl/expected.hpp>
TEST_CASE("Assertions", "[assertions]") {
tl::expected<int,int> o1 = 42;
REQUIRE_THROWS_WITH(o1.error(), "assertion failure");
tl::expected<int,int> o2 {tl::unexpect, 0};
REQUIRE_THROWS_WITH(*o2, "assertion failure");
struct foo { int bar; };
tl::expected<struct foo,int> o3 {tl::unexpect, 0};
REQUIRE_THROWS_WITH(o3->bar, "assertion failure");
}
+75
View File
@@ -0,0 +1,75 @@
#include <catch2/catch.hpp>
#include <tl/expected.hpp>
TEST_CASE("Simple assignment", "[assignment.simple]") {
tl::expected<int, int> e1 = 42;
tl::expected<int, int> e2 = 17;
tl::expected<int, int> e3 = 21;
tl::expected<int, int> e4 = tl::make_unexpected(42);
tl::expected<int, int> e5 = tl::make_unexpected(17);
tl::expected<int, int> e6 = tl::make_unexpected(21);
e1 = e2;
REQUIRE(e1);
REQUIRE(*e1 == 17);
REQUIRE(e2);
REQUIRE(*e2 == 17);
e1 = std::move(e2);
REQUIRE(e1);
REQUIRE(*e1 == 17);
REQUIRE(e2);
REQUIRE(*e2 == 17);
e1 = 42;
REQUIRE(e1);
REQUIRE(*e1 == 42);
auto unex = tl::make_unexpected(12);
e1 = unex;
REQUIRE(!e1);
REQUIRE(e1.error() == 12);
e1 = tl::make_unexpected(42);
REQUIRE(!e1);
REQUIRE(e1.error() == 42);
e1 = e3;
REQUIRE(e1);
REQUIRE(*e1 == 21);
e4 = e5;
REQUIRE(!e4);
REQUIRE(e4.error() == 17);
e4 = std::move(e6);
REQUIRE(!e4);
REQUIRE(e4.error() == 21);
e4 = e1;
REQUIRE(e4);
REQUIRE(*e4 == 21);
}
TEST_CASE("Assignment deletion", "[assignment.deletion]") {
struct has_all {
has_all() = default;
has_all(const has_all &) = default;
has_all(has_all &&) noexcept = default;
has_all &operator=(const has_all &) = default;
};
tl::expected<has_all, has_all> e1 = {};
tl::expected<has_all, has_all> e2 = {};
e1 = e2;
struct except_move {
except_move() = default;
except_move(const except_move &) = default;
except_move(except_move &&) noexcept(false){};
except_move &operator=(const except_move &) = default;
};
tl::expected<except_move, except_move> e3 = {};
tl::expected<except_move, except_move> e4 = {};
// e3 = e4; should not compile
}
+191
View File
@@ -0,0 +1,191 @@
#include <catch2/catch.hpp>
#include <tl/expected.hpp>
#include <string>
// Old versions of GCC don't have the correct trait names. Could fix them up if needs be.
#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
!defined(__clang__))
// nothing for now
#else
TEST_CASE("Triviality", "[bases.triviality]") {
REQUIRE(std::is_trivially_copy_constructible<tl::expected<int,int>>::value);
REQUIRE(std::is_trivially_copy_assignable<tl::expected<int,int>>::value);
REQUIRE(std::is_trivially_move_constructible<tl::expected<int,int>>::value);
REQUIRE(std::is_trivially_move_assignable<tl::expected<int,int>>::value);
REQUIRE(std::is_trivially_destructible<tl::expected<int,int>>::value);
REQUIRE(std::is_trivially_copy_constructible<tl::expected<void,int>>::value);
REQUIRE(std::is_trivially_move_constructible<tl::expected<void,int>>::value);
REQUIRE(std::is_trivially_destructible<tl::expected<void,int>>::value);
{
struct T {
T(const T&) = default;
T(T&&) = default;
T& operator=(const T&) = default;
T& operator=(T&&) = default;
~T() = default;
};
REQUIRE(std::is_trivially_copy_constructible<tl::expected<T,int>>::value);
REQUIRE(std::is_trivially_copy_assignable<tl::expected<T,int>>::value);
REQUIRE(std::is_trivially_move_constructible<tl::expected<T,int>>::value);
REQUIRE(std::is_trivially_move_assignable<tl::expected<T,int>>::value);
REQUIRE(std::is_trivially_destructible<tl::expected<T,int>>::value);
}
{
struct T {
T(const T&){}
T(T&&) {}
T& operator=(const T&) { return *this; }
T& operator=(T&&) { return *this; }
~T(){}
};
REQUIRE(!std::is_trivially_copy_constructible<tl::expected<T,int>>::value);
REQUIRE(!std::is_trivially_copy_assignable<tl::expected<T,int>>::value);
REQUIRE(!std::is_trivially_move_constructible<tl::expected<T,int>>::value);
REQUIRE(!std::is_trivially_move_assignable<tl::expected<T,int>>::value);
REQUIRE(!std::is_trivially_destructible<tl::expected<T,int>>::value);
}
}
TEST_CASE("Deletion", "[bases.deletion]") {
REQUIRE(std::is_copy_constructible<tl::expected<int,int>>::value);
REQUIRE(std::is_copy_assignable<tl::expected<int,int>>::value);
REQUIRE(std::is_move_constructible<tl::expected<int,int>>::value);
REQUIRE(std::is_move_assignable<tl::expected<int,int>>::value);
REQUIRE(std::is_destructible<tl::expected<int,int>>::value);
{
struct T {
T()=default;
};
REQUIRE(std::is_default_constructible<tl::expected<T,int>>::value);
}
{
struct T {
T(int){}
};
REQUIRE(!std::is_default_constructible<tl::expected<T,int>>::value);
}
{
struct T {
T(const T&) = default;
T(T&&) = default;
T& operator=(const T&) = default;
T& operator=(T&&) = default;
~T() = default;
};
REQUIRE(std::is_copy_constructible<tl::expected<T,int>>::value);
REQUIRE(std::is_copy_assignable<tl::expected<T,int>>::value);
REQUIRE(std::is_move_constructible<tl::expected<T,int>>::value);
REQUIRE(std::is_move_assignable<tl::expected<T,int>>::value);
REQUIRE(std::is_destructible<tl::expected<T,int>>::value);
}
{
struct T {
T(const T&)=delete;
T(T&&)=delete;
T& operator=(const T&)=delete;
T& operator=(T&&)=delete;
};
REQUIRE(!std::is_copy_constructible<tl::expected<T,int>>::value);
REQUIRE(!std::is_copy_assignable<tl::expected<T,int>>::value);
REQUIRE(!std::is_move_constructible<tl::expected<T,int>>::value);
REQUIRE(!std::is_move_assignable<tl::expected<T,int>>::value);
}
{
struct T {
T(const T&)=delete;
T(T&&)=default;
T& operator=(const T&)=delete;
T& operator=(T&&)=default;
};
REQUIRE(!std::is_copy_constructible<tl::expected<T,int>>::value);
REQUIRE(!std::is_copy_assignable<tl::expected<T,int>>::value);
REQUIRE(std::is_move_constructible<tl::expected<T,int>>::value);
REQUIRE(std::is_move_assignable<tl::expected<T,int>>::value);
}
{
struct T {
T(const T&)=default;
T(T&&)=delete;
T& operator=(const T&)=default;
T& operator=(T&&)=delete;
};
REQUIRE(std::is_copy_constructible<tl::expected<T,int>>::value);
REQUIRE(std::is_copy_assignable<tl::expected<T,int>>::value);
}
{
tl::expected<int, int> e;
REQUIRE(std::is_default_constructible<decltype(e)>::value);
REQUIRE(std::is_copy_constructible<decltype(e)>::value);
REQUIRE(std::is_move_constructible<decltype(e)>::value);
REQUIRE(std::is_copy_assignable<decltype(e)>::value);
REQUIRE(std::is_move_assignable<decltype(e)>::value);
REQUIRE(TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value);
REQUIRE(TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value);
# if !defined(TL_EXPECTED_GCC49)
REQUIRE(std::is_trivially_move_constructible<decltype(e)>::value);
REQUIRE(std::is_trivially_move_assignable<decltype(e)>::value);
# endif
}
{
tl::expected<int, std::string> e;
REQUIRE(std::is_default_constructible<decltype(e)>::value);
REQUIRE(std::is_copy_constructible<decltype(e)>::value);
REQUIRE(std::is_move_constructible<decltype(e)>::value);
REQUIRE(std::is_copy_assignable<decltype(e)>::value);
REQUIRE(std::is_move_assignable<decltype(e)>::value);
REQUIRE(!TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value);
REQUIRE(!TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value);
# if !defined(TL_EXPECTED_GCC49)
REQUIRE(!std::is_trivially_move_constructible<decltype(e)>::value);
REQUIRE(!std::is_trivially_move_assignable<decltype(e)>::value);
# endif
}
{
tl::expected<std::string, int> e;
REQUIRE(std::is_default_constructible<decltype(e)>::value);
REQUIRE(std::is_copy_constructible<decltype(e)>::value);
REQUIRE(std::is_move_constructible<decltype(e)>::value);
REQUIRE(std::is_copy_assignable<decltype(e)>::value);
REQUIRE(std::is_move_assignable<decltype(e)>::value);
REQUIRE(!TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value);
REQUIRE(!TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value);
# if !defined(TL_EXPECTED_GCC49)
REQUIRE(!std::is_trivially_move_constructible<decltype(e)>::value);
REQUIRE(!std::is_trivially_move_assignable<decltype(e)>::value);
# endif
}
{
tl::expected<std::string, std::string> e;
REQUIRE(std::is_default_constructible<decltype(e)>::value);
REQUIRE(std::is_copy_constructible<decltype(e)>::value);
REQUIRE(std::is_move_constructible<decltype(e)>::value);
REQUIRE(std::is_copy_assignable<decltype(e)>::value);
REQUIRE(std::is_move_assignable<decltype(e)>::value);
REQUIRE(!TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value);
REQUIRE(!TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value);
# if !defined(TL_EXPECTED_GCC49)
REQUIRE(!std::is_trivially_move_constructible<decltype(e)>::value);
REQUIRE(!std::is_trivially_move_assignable<decltype(e)>::value);
# endif
}
}
#endif
+6
View File
@@ -0,0 +1,6 @@
#include <catch2/catch.hpp>
#include <tl/expected.hpp>
TEST_CASE("Constexpr", "[constexpr]") {
//TODO
}

Some files were not shown because too many files have changed in this diff Show More