mirror of
https://github.com/ashaduri/gsmartcontrol.git
synced 2026-09-27 06:15:45 +00:00
Initial work on JSON parser.
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
# 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.
|
||||
@@ -63,6 +64,7 @@ Checks: >
|
||||
-objc-*,
|
||||
openmp-*,
|
||||
performance-*,
|
||||
-performance-enum-size,
|
||||
portability-*,
|
||||
readability-*,
|
||||
-readability-avoid-unconditional-preprocessor-if,
|
||||
|
||||
@@ -34,6 +34,8 @@ target_sources(applib PRIVATE
|
||||
smartctl_parser.h
|
||||
smartctl_json_ata_parser.cpp
|
||||
smartctl_json_ata_parser.h
|
||||
smartctl_json_basic_parser.cpp
|
||||
smartctl_json_basic_parser.h
|
||||
smartctl_json_parser_helpers.h
|
||||
smartctl_executor.cpp
|
||||
smartctl_executor_gui.h
|
||||
@@ -41,6 +43,8 @@ target_sources(applib PRIVATE
|
||||
smartctl_parser_types.h
|
||||
smartctl_text_ata_parser.cpp
|
||||
smartctl_text_ata_parser.h
|
||||
smartctl_text_basic_parser.cpp
|
||||
smartctl_text_basic_parser.h
|
||||
smartctl_text_parser_helper.cpp
|
||||
smartctl_text_parser_helper.h
|
||||
smartctl_version_parser.cpp
|
||||
|
||||
@@ -42,8 +42,8 @@ int main(int argc, char* argv[])
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
SmartctlAtaTextParser parser;
|
||||
if (const auto parse_status = parser.parse_full(contents); !parse_status.has_value()) {
|
||||
SmartctlTextAtaParser parser;
|
||||
if (const auto parse_status = parser.parse(contents); !parse_status.has_value()) {
|
||||
debug_out_error("app", "Cannot parse file contents: " << parse_status.error().message() << "\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
@@ -243,10 +243,10 @@ std::string SelfTest::update(const std::shared_ptr<CommandExecutor>& smartctl_ex
|
||||
return error_msg;
|
||||
|
||||
const AtaStorageAttribute::DiskType disk_type = drive_->get_is_hdd() ? AtaStorageAttribute::DiskType::Hdd : AtaStorageAttribute::DiskType::Ssd;
|
||||
auto parser = SmartctlParser::create(SmartctlParserType::Text);
|
||||
auto parser = SmartctlParser::create(SmartctlParserType::TextAta);
|
||||
DBG_ASSERT_RETURN(parser, "Cannot create parser");
|
||||
|
||||
auto parse_status = parser->parse_full(output);
|
||||
auto parse_status = parser->parse(output);
|
||||
if (!parse_status) {
|
||||
return Glib::ustring::compose(_("Cannot parse smartctl output: %1"), parse_status.error().message());
|
||||
}
|
||||
|
||||
@@ -80,20 +80,18 @@ _custom/smart_enabled
|
||||
|
||||
|
||||
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlAtaJsonParser::parse_full(const std::string& json_data_full)
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlJsonAtaParser::parse(std::string_view smartctl_output)
|
||||
{
|
||||
using namespace SmartctlJsonParserHelpers;
|
||||
|
||||
this->set_data_full(json_data_full);
|
||||
|
||||
if (hz::string_trim_copy(json_data_full).empty()) {
|
||||
if (hz::string_trim_copy(smartctl_output).empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Empty string passed as an argument. Returning.\n");
|
||||
return hz::Unexpected(SmartctlParserError::EmptyInput, "Smartctl data is empty.");
|
||||
}
|
||||
|
||||
nlohmann::json json_root_node;
|
||||
try {
|
||||
json_root_node = nlohmann::json::parse(json_data_full);
|
||||
json_root_node = nlohmann::json::parse(smartctl_output);
|
||||
} catch (const nlohmann::json::parse_error& e) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Error parsing smartctl output as JSON: " << e.what() << "\n");
|
||||
return hz::Unexpected(SmartctlParserError::SyntaxError, std::string("Invalid JSON data: ") + e.what());
|
||||
@@ -112,7 +110,7 @@ hz::ExpectedVoid<SmartctlParserError> SmartctlAtaJsonParser::parse_full(const st
|
||||
|
||||
|
||||
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlAtaJsonParser::parse_version(const nlohmann::json& json_root_node)
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlJsonAtaParser::parse_version(const nlohmann::json& json_root_node)
|
||||
{
|
||||
using namespace SmartctlJsonParserHelpers;
|
||||
|
||||
@@ -155,7 +153,7 @@ hz::ExpectedVoid<SmartctlParserError> SmartctlAtaJsonParser::parse_version(const
|
||||
p.section = AtaStorageProperty::Section::info; // add to info section
|
||||
add_property(p);
|
||||
}
|
||||
if (!SmartctlVersionParser::check_parsed_version(SmartctlParserType::Json, smartctl_version)) {
|
||||
if (!SmartctlVersionParser::check_parsed_version(SmartctlParserType::JsonAta, smartctl_version)) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Incompatible smartctl version. Returning.\n");
|
||||
return hz::Unexpected(SmartctlParserError::IncompatibleVersion, "Incompatible smartctl version.");
|
||||
}
|
||||
@@ -165,7 +163,7 @@ hz::ExpectedVoid<SmartctlParserError> SmartctlAtaJsonParser::parse_version(const
|
||||
|
||||
|
||||
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlAtaJsonParser::parse_section_info(const nlohmann::json& json_root_node)
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlJsonAtaParser::parse_section_info(const nlohmann::json& json_root_node)
|
||||
{
|
||||
using namespace SmartctlJsonParserHelpers;
|
||||
|
||||
@@ -285,7 +283,7 @@ hz::ExpectedVoid<SmartctlParserError> SmartctlAtaJsonParser::parse_section_info(
|
||||
|
||||
|
||||
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlAtaJsonParser::parse_section_health(const nlohmann::json& json_root_node)
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlJsonAtaParser::parse_section_health(const nlohmann::json& json_root_node)
|
||||
{
|
||||
using namespace SmartctlJsonParserHelpers;
|
||||
|
||||
|
||||
@@ -20,14 +20,14 @@ Copyright:
|
||||
|
||||
|
||||
/// Smartctl (S)ATA JSON output parser
|
||||
class SmartctlAtaJsonParser : public SmartctlParser {
|
||||
class SmartctlJsonAtaParser : public SmartctlParser {
|
||||
public:
|
||||
|
||||
// Defaulted, used by make_unique.
|
||||
SmartctlAtaJsonParser() = default;
|
||||
SmartctlJsonAtaParser() = default;
|
||||
|
||||
// Overridden
|
||||
hz::ExpectedVoid<SmartctlParserError> parse_full(const std::string& json_data_full) override;
|
||||
hz::ExpectedVoid<SmartctlParserError> parse(std::string_view smartctl_output) override;
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/******************************************************************************
|
||||
License: GNU General Public License v3.0 only
|
||||
Copyright:
|
||||
(C) 2024 Alexander Shaduri <ashaduri@gmail.com>
|
||||
******************************************************************************/
|
||||
/// \file
|
||||
/// \author Alexander Shaduri
|
||||
/// \ingroup applib
|
||||
/// \weakgroup applib
|
||||
/// @{
|
||||
|
||||
// #include "local_glibmm.h"
|
||||
//#include <clocale> // localeconv
|
||||
//#include <cstdint>
|
||||
//#include <utility>
|
||||
|
||||
// #include "hz/locale_tools.h" // ScopedCLocale, locale_c_get().
|
||||
//#include "hz/string_algo.h" // string_*
|
||||
//#include "hz/string_num.h" // string_is_numeric, number_to_string
|
||||
//#include "hz/debug.h" // debug_*
|
||||
|
||||
//#include "app_pcrecpp.h"
|
||||
//#include "smartctl_text_ata_parser.h"
|
||||
//#include "ata_storage_property_descr.h"
|
||||
// #include "warning_colors.h"
|
||||
//#include "smartctl_version_parser.h"
|
||||
#include "smartctl_json_basic_parser.h"
|
||||
|
||||
|
||||
|
||||
|
||||
// Parse full "smartctl -x" output
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlJsonBasicParser::parse(std::string_view smartctl_output)
|
||||
{
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// @}
|
||||
@@ -0,0 +1,41 @@
|
||||
/******************************************************************************
|
||||
License: GNU General Public License v3.0 only
|
||||
Copyright:
|
||||
(C) 2024 Alexander Shaduri <ashaduri@gmail.com>
|
||||
******************************************************************************/
|
||||
/// \file
|
||||
/// \author Alexander Shaduri
|
||||
/// \ingroup applib
|
||||
/// \weakgroup applib
|
||||
/// @{
|
||||
|
||||
#ifndef SMARTCTL_JSON_BASIC_PARSER_H
|
||||
#define SMARTCTL_JSON_BASIC_PARSER_H
|
||||
|
||||
//#include <string>
|
||||
//#include <vector>
|
||||
|
||||
#include "smartctl_parser.h"
|
||||
|
||||
|
||||
|
||||
/// Parse info output, regardless of device type
|
||||
class SmartctlJsonBasicParser : public SmartctlParser {
|
||||
public:
|
||||
|
||||
// Defaulted, used by make_unique.
|
||||
SmartctlJsonBasicParser() = default;
|
||||
|
||||
// Overridden
|
||||
hz::ExpectedVoid<SmartctlParserError> parse(std::string_view smartctl_output) override;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/// @}
|
||||
@@ -15,36 +15,45 @@ Copyright:
|
||||
#include "smartctl_parser.h"
|
||||
#include "smartctl_text_ata_parser.h"
|
||||
#include "smartctl_json_ata_parser.h"
|
||||
#include "ata_storage_property_descr.h"
|
||||
#include "warning_colors.h"
|
||||
#include "smartctl_json_basic_parser.h"
|
||||
#include "smartctl_text_basic_parser.h"
|
||||
//#include "ata_storage_property_descr.h"
|
||||
|
||||
|
||||
|
||||
std::unique_ptr<SmartctlParser> SmartctlParser::create(SmartctlParserType type)
|
||||
{
|
||||
switch(type) {
|
||||
case SmartctlParserType::Json:
|
||||
return std::make_unique<SmartctlAtaJsonParser>();
|
||||
case SmartctlParserType::Text:
|
||||
return std::make_unique<SmartctlAtaTextParser>();
|
||||
case SmartctlParserType::JsonBasic:
|
||||
return std::make_unique<SmartctlJsonBasicParser>();
|
||||
break;
|
||||
case SmartctlParserType::JsonAta:
|
||||
return std::make_unique<SmartctlJsonAtaParser>();
|
||||
break;
|
||||
case SmartctlParserType::TextBasic:
|
||||
return std::make_unique<SmartctlTextBasicParser>();
|
||||
break;
|
||||
case SmartctlParserType::TextAta:
|
||||
return std::make_unique<SmartctlTextAtaParser>();
|
||||
break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
hz::ExpectedValue<SmartctlParserType, SmartctlParserError> SmartctlParser::detect_output_type(const std::string& output)
|
||||
hz::ExpectedValue<SmartctlParserFormat, SmartctlParserError> SmartctlParser::detect_output_format(std::string_view smartctl_output)
|
||||
{
|
||||
// Look for the first non-whitespace symbol
|
||||
auto first_symbol = std::find_if(output.begin(), output.end(), [&](char c) {
|
||||
const auto* first_symbol = std::find_if(smartctl_output.begin(), smartctl_output.end(), [&](char c) {
|
||||
return !std::isspace(c, std::locale::classic());
|
||||
});
|
||||
if (first_symbol != output.end()) {
|
||||
if (first_symbol != smartctl_output.end()) {
|
||||
if (*first_symbol == '{') {
|
||||
return SmartctlParserType::Json;
|
||||
return SmartctlParserFormat::Json;
|
||||
}
|
||||
if (output.rfind("smartctl", static_cast<std::size_t>(first_symbol - output.begin())) == 0) {
|
||||
return SmartctlParserType::Text;
|
||||
if (smartctl_output.rfind("smartctl", static_cast<std::size_t>(first_symbol - smartctl_output.begin())) == 0) {
|
||||
return SmartctlParserFormat::Text;
|
||||
}
|
||||
return hz::Unexpected(SmartctlParserError::UnsupportedFormat, "Unsupported format while trying to detect smartctl output format.");
|
||||
}
|
||||
@@ -53,13 +62,6 @@ hz::ExpectedValue<SmartctlParserType, SmartctlParserError> SmartctlParser::detec
|
||||
|
||||
|
||||
|
||||
std::string SmartctlParser::get_data_full() const
|
||||
{
|
||||
return data_full_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const std::vector<AtaStorageProperty>& SmartctlParser::get_properties() const
|
||||
{
|
||||
return properties_;
|
||||
@@ -76,13 +78,6 @@ void SmartctlParser::add_property(AtaStorageProperty p)
|
||||
|
||||
|
||||
|
||||
void SmartctlParser::set_data_full(const std::string& s)
|
||||
{
|
||||
data_full_ = s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// @}
|
||||
|
||||
@@ -12,7 +12,7 @@ Copyright:
|
||||
#ifndef SMARTCTL_PARSER_H
|
||||
#define SMARTCTL_PARSER_H
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
@@ -71,16 +71,13 @@ class SmartctlParser {
|
||||
|
||||
/// Parse full "smartctl -x" output.
|
||||
/// Note: Once parsed, this function cannot be called again.
|
||||
virtual hz::ExpectedVoid<SmartctlParserError> parse_full(const std::string& full) = 0;
|
||||
virtual hz::ExpectedVoid<SmartctlParserError> parse(std::string_view smartctl_output) = 0;
|
||||
|
||||
|
||||
/// Detect smartctl output type (text, json).
|
||||
[[nodiscard]] static hz::ExpectedValue<SmartctlParserType, SmartctlParserError> detect_output_type(const std::string& output);
|
||||
[[nodiscard]] static hz::ExpectedValue<SmartctlParserFormat, SmartctlParserError> detect_output_format(std::string_view smartctl_output);
|
||||
|
||||
|
||||
/// Get "full" data, as passed to parse_full().
|
||||
[[nodiscard]] std::string get_data_full() const;
|
||||
|
||||
/// Get parse result properties
|
||||
[[nodiscard]] const std::vector<AtaStorageProperty>& get_properties() const;
|
||||
|
||||
@@ -90,14 +87,10 @@ class SmartctlParser {
|
||||
/// Add a property into property list, look up and set its description
|
||||
void add_property(AtaStorageProperty p);
|
||||
|
||||
/// Set "full" data ("smartctl -x" output), json or text.
|
||||
void set_data_full(const std::string& s);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
std::vector<AtaStorageProperty> properties_; ///< Parsed data properties
|
||||
std::string data_full_; ///< full data, filled by parse_full()
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -19,8 +19,10 @@ Copyright:
|
||||
|
||||
|
||||
enum class SmartctlParserType {
|
||||
Json,
|
||||
Text,
|
||||
JsonBasic, ///< Info only
|
||||
JsonAta,
|
||||
TextBasic, ///< Info only
|
||||
TextAta,
|
||||
};
|
||||
|
||||
|
||||
@@ -32,13 +34,15 @@ struct SmartctlParserTypeExt
|
||||
SmartctlParserTypeExt,
|
||||
Glib::ustring>
|
||||
{
|
||||
static constexpr inline SmartctlParserType default_value = SmartctlParserType::Json;
|
||||
static constexpr inline SmartctlParserType default_value = SmartctlParserType::JsonAta;
|
||||
|
||||
static std::unordered_map<EnumType, std::pair<std::string, Glib::ustring>> build_enum_map()
|
||||
{
|
||||
return {
|
||||
{SmartctlParserType::Json, {"json", _("JSON")}},
|
||||
{SmartctlParserType::Text, {"text", _("Text")}},
|
||||
{SmartctlParserType::JsonBasic, {"json_basic", _("JSON Basic")}},
|
||||
{SmartctlParserType::JsonAta, {"json_ata", _("JSON ATA")}},
|
||||
{SmartctlParserType::TextBasic, {"text_basic", _("Text Basic")}},
|
||||
{SmartctlParserType::TextAta, {"text_ata", _("Text ATA")}},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -46,6 +50,12 @@ struct SmartctlParserTypeExt
|
||||
|
||||
|
||||
|
||||
enum class SmartctlParserFormat {
|
||||
Json,
|
||||
Text,
|
||||
};
|
||||
|
||||
|
||||
|
||||
enum class SmartctlParserSettingType {
|
||||
Auto,
|
||||
|
||||
@@ -69,15 +69,12 @@ namespace {
|
||||
|
||||
|
||||
// Parse full "smartctl -x" output
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlAtaTextParser::parse_full(const std::string& full)
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlTextAtaParser::parse(std::string_view smartctl_output)
|
||||
{
|
||||
this->set_data_full(full);
|
||||
|
||||
|
||||
// -------------------- Fix the output, so it doesn't interfere with proper parsing
|
||||
|
||||
// perform any2unix
|
||||
std::string s = hz::string_trim_copy(hz::string_any_to_unix_copy(full));
|
||||
std::string s = hz::string_trim_copy(hz::string_any_to_unix_copy(smartctl_output));
|
||||
|
||||
if (s.empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Empty string passed as an argument. Returning.\n");
|
||||
@@ -204,7 +201,7 @@ hz::ExpectedVoid<SmartctlParserError> SmartctlAtaTextParser::parse_full(const st
|
||||
// version info
|
||||
|
||||
std::string version, version_full;
|
||||
if (!SmartctlVersionParser::parse_version(s, version, version_full)) {
|
||||
if (!SmartctlVersionParser::parse_version_text(s, version, version_full)) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Cannot extract version information. Returning.\n");
|
||||
return hz::Unexpected(SmartctlParserError::NoVersion, "Cannot extract smartctl version information.");
|
||||
}
|
||||
@@ -226,7 +223,7 @@ hz::ExpectedVoid<SmartctlParserError> SmartctlAtaTextParser::parse_full(const st
|
||||
add_property(p);
|
||||
}
|
||||
|
||||
if (!SmartctlVersionParser::check_parsed_version(SmartctlParserType::Text, version)) {
|
||||
if (!SmartctlVersionParser::check_parsed_version(SmartctlParserType::TextAta, version)) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Incompatible smartctl version. Returning.\n");
|
||||
return hz::Unexpected(SmartctlParserError::IncompatibleVersion, "Incompatible smartctl version.");
|
||||
}
|
||||
@@ -269,7 +266,7 @@ hz::ExpectedVoid<SmartctlParserError> SmartctlAtaTextParser::parse_full(const st
|
||||
|
||||
|
||||
// Parse the section part (with "=== .... ===" header) - info or data sections.
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlAtaTextParser::parse_section(const std::string& header, const std::string& body)
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlTextAtaParser::parse_section(const std::string& header, const std::string& body)
|
||||
{
|
||||
if (app_pcre_match("/START OF INFORMATION SECTION/mi", header)) {
|
||||
return parse_section_info(body);
|
||||
@@ -311,7 +308,7 @@ hz::ExpectedVoid<SmartctlParserError> SmartctlAtaTextParser::parse_section(const
|
||||
// ------------------------------------------------ INFO SECTION
|
||||
|
||||
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlAtaTextParser::parse_section_info(const std::string& body)
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlTextAtaParser::parse_section_info(const std::string& body)
|
||||
{
|
||||
this->set_data_section_info(body);
|
||||
|
||||
@@ -423,7 +420,7 @@ http://knowledge.seagate.com/articles/en_US/FAQ/213891en
|
||||
|
||||
|
||||
// Parse a component (one line) of the info section
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlAtaTextParser::parse_section_info_property(AtaStorageProperty& p)
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlTextAtaParser::parse_section_info_property(AtaStorageProperty& p)
|
||||
{
|
||||
// ---- Info
|
||||
if (p.section != AtaStorageProperty::Section::info) {
|
||||
@@ -613,7 +610,7 @@ hz::ExpectedVoid<SmartctlParserError> SmartctlAtaTextParser::parse_section_info_
|
||||
|
||||
|
||||
// Parse the Data section (without "===" header)
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlAtaTextParser::parse_section_data(const std::string& body)
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlTextAtaParser::parse_section_data(const std::string& body)
|
||||
{
|
||||
this->set_data_section_data(body);
|
||||
|
||||
@@ -764,7 +761,7 @@ hz::ExpectedVoid<SmartctlParserError> SmartctlAtaTextParser::parse_section_data(
|
||||
|
||||
// -------------------- Health
|
||||
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlAtaTextParser::parse_section_data_subsection_health(const std::string& sub)
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlTextAtaParser::parse_section_data_subsection_health(const std::string& sub)
|
||||
{
|
||||
// Health section data (--info and --get=all):
|
||||
/*
|
||||
@@ -807,7 +804,7 @@ Device is: In smartctl database [for details use: -P show]
|
||||
|
||||
// -------------------- Capabilities
|
||||
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlAtaTextParser::parse_section_data_subsection_capabilities(const std::string& sub_initial)
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlTextAtaParser::parse_section_data_subsection_capabilities(const std::string& sub_initial)
|
||||
{
|
||||
// Capabilities section data:
|
||||
/*
|
||||
@@ -987,7 +984,7 @@ SCT capabilities: (0x003d) SCT Status supported.
|
||||
|
||||
|
||||
// Check the capabilities for internal properties we can use.
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlAtaTextParser::parse_section_data_internal_capabilities(AtaStorageProperty& cap_prop)
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlTextAtaParser::parse_section_data_internal_capabilities(AtaStorageProperty& cap_prop)
|
||||
{
|
||||
// Some special capabilities we're interested in.
|
||||
|
||||
@@ -1244,7 +1241,7 @@ hz::ExpectedVoid<SmartctlParserError> SmartctlAtaTextParser::parse_section_data_
|
||||
|
||||
// -------------------- Attributes
|
||||
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlAtaTextParser::parse_section_data_subsection_attributes(const std::string& sub)
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlTextAtaParser::parse_section_data_subsection_attributes(const std::string& sub)
|
||||
{
|
||||
AtaStorageProperty pt; // template for easy copying
|
||||
pt.section = AtaStorageProperty::Section::data;
|
||||
@@ -1465,7 +1462,7 @@ ID# ATTRIBUTE_NAME FLAGS VALUE WORST THRESH FAIL RAW_VALUE
|
||||
|
||||
|
||||
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlAtaTextParser::parse_section_data_subsection_directory_log(const std::string& sub)
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlTextAtaParser::parse_section_data_subsection_directory_log(const std::string& sub)
|
||||
{
|
||||
AtaStorageProperty pt; // template for easy copying
|
||||
pt.section = AtaStorageProperty::Section::data;
|
||||
@@ -1517,7 +1514,7 @@ Address Access R/W Size Description
|
||||
|
||||
|
||||
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlAtaTextParser::parse_section_data_subsection_error_log(const std::string& sub)
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlTextAtaParser::parse_section_data_subsection_error_log(const std::string& sub)
|
||||
{
|
||||
AtaStorageProperty pt; // template for easy copying
|
||||
pt.section = AtaStorageProperty::Section::data;
|
||||
@@ -1714,7 +1711,7 @@ Error 1 [0] occurred at disk power-on lifetime: 1 hours (0 days + 1 hours)
|
||||
|
||||
// -------------------- Selftest Log
|
||||
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlAtaTextParser::parse_section_data_subsection_selftest_log(const std::string& sub)
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlTextAtaParser::parse_section_data_subsection_selftest_log(const std::string& sub)
|
||||
{
|
||||
AtaStorageProperty pt; // template for easy copying
|
||||
pt.section = AtaStorageProperty::Section::data;
|
||||
@@ -1893,7 +1890,7 @@ Num Test_Description Status Remaining LifeTime(hours) LBA
|
||||
|
||||
// -------------------- Selective Selftest Log
|
||||
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlAtaTextParser::parse_section_data_subsection_selective_selftest_log(const std::string& sub)
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlTextAtaParser::parse_section_data_subsection_selective_selftest_log(const std::string& sub)
|
||||
{
|
||||
AtaStorageProperty pt; // template for easy copying
|
||||
pt.section = AtaStorageProperty::Section::data;
|
||||
@@ -1950,7 +1947,7 @@ If Selective self-test is pending on power-up, resume after 0 minute delay.
|
||||
|
||||
|
||||
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlAtaTextParser::parse_section_data_subsection_scttemp_log(const std::string& sub)
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlTextAtaParser::parse_section_data_subsection_scttemp_log(const std::string& sub)
|
||||
{
|
||||
AtaStorageProperty pt; // template for easy copying
|
||||
pt.section = AtaStorageProperty::Section::data;
|
||||
@@ -2040,7 +2037,7 @@ Index Estimated Time Temperature Celsius
|
||||
|
||||
|
||||
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlAtaTextParser::parse_section_data_subsection_scterc_log(const std::string& sub)
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlTextAtaParser::parse_section_data_subsection_scterc_log(const std::string& sub)
|
||||
{
|
||||
AtaStorageProperty pt; // template for easy copying
|
||||
pt.section = AtaStorageProperty::Section::data;
|
||||
@@ -2089,7 +2086,7 @@ SCT Error Recovery Control:
|
||||
|
||||
|
||||
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlAtaTextParser::parse_section_data_subsection_devstat(const std::string& sub)
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlTextAtaParser::parse_section_data_subsection_devstat(const std::string& sub)
|
||||
{
|
||||
AtaStorageProperty pt; // template for easy copying
|
||||
pt.section = AtaStorageProperty::Section::data;
|
||||
@@ -2260,7 +2257,7 @@ Page Offset Size Value Description
|
||||
|
||||
|
||||
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlAtaTextParser::parse_section_data_subsection_sataphy(const std::string& sub)
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlTextAtaParser::parse_section_data_subsection_sataphy(const std::string& sub)
|
||||
{
|
||||
AtaStorageProperty pt; // template for easy copying
|
||||
pt.section = AtaStorageProperty::Section::data;
|
||||
@@ -2318,14 +2315,14 @@ ID Size Value Description
|
||||
|
||||
|
||||
|
||||
void SmartctlAtaTextParser::set_data_section_info(std::string s)
|
||||
void SmartctlTextAtaParser::set_data_section_info(std::string s)
|
||||
{
|
||||
data_section_info_ = std::move(s);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SmartctlAtaTextParser::set_data_section_data(std::string s)
|
||||
void SmartctlTextAtaParser::set_data_section_data(std::string s)
|
||||
{
|
||||
data_section_data_ = std::move(s);
|
||||
}
|
||||
|
||||
@@ -20,16 +20,16 @@ Copyright:
|
||||
|
||||
|
||||
/// Smartctl (S)ATA text output parser.
|
||||
/// Note: ALL parse_* functions (except parse_full() and parse_version())
|
||||
/// Note: ALL parse_* functions (except parse())
|
||||
/// expect data in unix-newline format!
|
||||
class SmartctlAtaTextParser : public SmartctlParser {
|
||||
class SmartctlTextAtaParser : public SmartctlParser {
|
||||
public:
|
||||
|
||||
// Defaulted, used by make_unique.
|
||||
SmartctlAtaTextParser() = default;
|
||||
SmartctlTextAtaParser() = default;
|
||||
|
||||
// Overridden
|
||||
hz::ExpectedVoid<SmartctlParserError> parse_full(const std::string& full) override;
|
||||
hz::ExpectedVoid<SmartctlParserError> parse(std::string_view smartctl_output) override;
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/******************************************************************************
|
||||
License: GNU General Public License v3.0 only
|
||||
Copyright:
|
||||
(C) 2008 - 2024 Alexander Shaduri <ashaduri@gmail.com>
|
||||
******************************************************************************/
|
||||
/// \file
|
||||
/// \author Alexander Shaduri
|
||||
/// \ingroup applib
|
||||
/// \weakgroup applib
|
||||
/// @{
|
||||
|
||||
// #include "local_glibmm.h"
|
||||
//#include <clocale> // localeconv
|
||||
//#include <cstdint>
|
||||
//#include <utility>
|
||||
|
||||
// #include "hz/locale_tools.h" // ScopedCLocale, locale_c_get().
|
||||
//#include "hz/string_algo.h" // string_*
|
||||
//#include "hz/string_num.h" // string_is_numeric, number_to_string
|
||||
//#include "hz/debug.h" // debug_*
|
||||
|
||||
#include "app_pcrecpp.h"
|
||||
//#include "smartctl_text_ata_parser.h"
|
||||
//#include "ata_storage_property_descr.h"
|
||||
// #include "warning_colors.h"
|
||||
//#include "smartctl_version_parser.h"
|
||||
#include "smartctl_text_basic_parser.h"
|
||||
|
||||
|
||||
|
||||
|
||||
hz::ExpectedVoid<SmartctlParserError> SmartctlTextBasicParser::parse(std::string_view smartctl_output)
|
||||
{
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// @}
|
||||
@@ -0,0 +1,41 @@
|
||||
/******************************************************************************
|
||||
License: GNU General Public License v3.0 only
|
||||
Copyright:
|
||||
(C) 2008 - 2024 Alexander Shaduri <ashaduri@gmail.com>
|
||||
******************************************************************************/
|
||||
/// \file
|
||||
/// \author Alexander Shaduri
|
||||
/// \ingroup applib
|
||||
/// \weakgroup applib
|
||||
/// @{
|
||||
|
||||
#ifndef SMARTCTL_TEXT_BASIC_PARSER_H
|
||||
#define SMARTCTL_TEXT_BASIC_PARSER_H
|
||||
|
||||
//#include <string>
|
||||
//#include <vector>
|
||||
|
||||
#include "smartctl_parser.h"
|
||||
|
||||
|
||||
|
||||
/// Parse info output, regardless of device type
|
||||
class SmartctlTextBasicParser : public SmartctlParser {
|
||||
public:
|
||||
|
||||
// Defaulted, used by make_unique.
|
||||
SmartctlTextBasicParser() = default;
|
||||
|
||||
// Overridden
|
||||
hz::ExpectedVoid<SmartctlParserError> parse(std::string_view smartctl_output) override;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/// @}
|
||||
@@ -21,7 +21,7 @@ Copyright:
|
||||
|
||||
|
||||
|
||||
bool SmartctlVersionParser::parse_version(const std::string& s, std::string& version_only, std::string& version_full)
|
||||
bool SmartctlVersionParser::parse_version_text(const std::string& s, std::string& version_only, std::string& version_full)
|
||||
{
|
||||
// e.g.
|
||||
// "smartctl version 5.37"
|
||||
@@ -57,9 +57,11 @@ bool SmartctlVersionParser::check_parsed_version(SmartctlParserType parser_type,
|
||||
{
|
||||
if (auto numeric_version = get_numeric_version(version_only); numeric_version.has_value()) {
|
||||
switch(parser_type) {
|
||||
case SmartctlParserType::Json:
|
||||
case SmartctlParserType::JsonBasic:
|
||||
case SmartctlParserType::JsonAta:
|
||||
return numeric_version.value() >= minimum_req_json_version;
|
||||
case SmartctlParserType::Text:
|
||||
case SmartctlParserType::TextBasic:
|
||||
case SmartctlParserType::TextAta:
|
||||
return numeric_version.value() >= minimum_req_text_version;
|
||||
}
|
||||
}
|
||||
@@ -70,11 +72,10 @@ bool SmartctlVersionParser::check_parsed_version(SmartctlParserType parser_type,
|
||||
|
||||
std::optional<SmartctlParserType> SmartctlVersionParser::detect_supported_parser_type(const std::string& version_only)
|
||||
{
|
||||
if (check_parsed_version(SmartctlParserType::Json, version_only)) {
|
||||
return SmartctlParserType::Json;
|
||||
}
|
||||
if (check_parsed_version(SmartctlParserType::Text, version_only)) {
|
||||
return SmartctlParserType::Text;
|
||||
for (auto type : SmartctlParserTypeExt::getAllValues()) {
|
||||
if (check_parsed_version(type, version_only)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@@ -28,15 +28,15 @@ class SmartctlVersionParser {
|
||||
|
||||
/// Supply any text (not JSON) output of smartctl here, the smartctl version will be retrieved.
|
||||
/// The text does not have to be in Unix newline format.
|
||||
/// \param command_output "smartctl -V" command output.
|
||||
/// \param s "smartctl -V" command output.
|
||||
/// \param[out] version_only A string similar to "7.2"
|
||||
/// \param[out] version_full A string similar to "smartctl 7.2 2020-12-30 r5155"
|
||||
/// \return false if the version could not be parsed.
|
||||
static bool parse_version(const std::string& command_output, std::string& version_only, std::string& version_full);
|
||||
static bool parse_version_text(const std::string& s, std::string& version_only, std::string& version_full);
|
||||
|
||||
|
||||
/// Get numeric version as a double from a parsed version.
|
||||
/// \param version_only A string similar to "7.2", as parsed by parse_version().
|
||||
/// \param version_only A string similar to "7.2", as parsed by parse_version_text().
|
||||
/// \return Numeric version as a double, e.g. 7.2. std::nullopt if the version could not be parsed.
|
||||
static std::optional<double> get_numeric_version(const std::string& version_only);
|
||||
|
||||
|
||||
@@ -146,7 +146,7 @@ std::string StorageDevice::parse_basic_data(bool do_set_properties, bool emit_si
|
||||
}
|
||||
|
||||
std::string version, version_full;
|
||||
if (!SmartctlVersionParser::parse_version(this->info_output_, version, version_full)) // is this smartctl data at all?
|
||||
if (!SmartctlVersionParser::parse_version_text(this->info_output_, version, version_full)) // is this smartctl data at all?
|
||||
return _("Cannot get smartctl version information.");
|
||||
|
||||
// Detect type. note: we can't distinguish between sata and scsi (on linux, for -d ata switch).
|
||||
@@ -174,10 +174,10 @@ std::string StorageDevice::parse_basic_data(bool do_set_properties, bool emit_si
|
||||
smart_enabled_ = false;
|
||||
|
||||
} else {
|
||||
// Note: We don't use SmartctlAtaTextParser here, because this information
|
||||
// Note: We don't use SmartctlTextAtaParser here, because this information
|
||||
// may be in some other format. If this information is valid, only then it's
|
||||
// passed to SmartctlAtaTextParser.
|
||||
// Compared to SmartctlAtaTextParser, this one is much looser.
|
||||
// passed to SmartctlTextAtaParser.
|
||||
// Compared to SmartctlTextAtaParser, this one is much looser.
|
||||
|
||||
// Don't put complete messages here - they change across smartctl versions.
|
||||
if (app_pcre_match("/^SMART support is:[ \\t]*Unavailable/mi", info_output_) // cdroms output this
|
||||
@@ -241,10 +241,10 @@ std::string StorageDevice::parse_basic_data(bool do_set_properties, bool emit_si
|
||||
disk_type = hdd_.value() ? AtaStorageAttribute::DiskType::Hdd : AtaStorageAttribute::DiskType::Ssd;
|
||||
}
|
||||
|
||||
auto parser = SmartctlParser::create(SmartctlParserType::Text);
|
||||
auto parser = SmartctlParser::create(SmartctlParserType::TextAta);
|
||||
DBG_ASSERT_RETURN(parser, "Cannot create parser");
|
||||
|
||||
if (parser->parse_full(this->info_output_)) { // try to parse it
|
||||
if (parser->parse(this->info_output_)) { // try to parse it
|
||||
this->set_properties(StoragePropertyProcessor::process_properties(parser->get_properties(), disk_type)); // copy to our drive, overwriting old data
|
||||
}
|
||||
}
|
||||
@@ -317,24 +317,30 @@ std::string StorageDevice::parse_data()
|
||||
disk_type = hdd_.value() ? AtaStorageAttribute::DiskType::Hdd : AtaStorageAttribute::DiskType::Ssd;
|
||||
}
|
||||
|
||||
auto parser_type = SmartctlParser::detect_output_type(this->full_output_);
|
||||
auto parser_format = SmartctlParser::detect_output_format(this->full_output_);
|
||||
|
||||
if (!parser_type.has_value()) {
|
||||
return parser_type.error().message();
|
||||
if (!parser_format.has_value()) {
|
||||
return parser_format.error().message();
|
||||
}
|
||||
|
||||
auto parser = SmartctlParser::create(parser_type.value());
|
||||
// TODO Choose format according to device type
|
||||
SmartctlParserType parser_type = SmartctlParserType::TextAta;
|
||||
if (parser_format == SmartctlParserFormat::Json) {
|
||||
parser_type = SmartctlParserType::JsonAta;
|
||||
}
|
||||
|
||||
auto parser = SmartctlParser::create(parser_type);
|
||||
DBG_ASSERT_RETURN(parser, "Cannot create parser");
|
||||
|
||||
// Try to parse it (parse only, set the properties after basic parsing).
|
||||
const auto parse_status = parser->parse_full(this->full_output_);
|
||||
const auto parse_status = parser->parse(this->full_output_);
|
||||
if (parse_status.has_value()) {
|
||||
|
||||
// refresh basic info too
|
||||
this->info_output_ = parser->get_data_full(); // put data including version information
|
||||
this->info_output_ = this->full_output_; // put data including version information
|
||||
|
||||
// note: this will clear the non-basic properties!
|
||||
// this will parse some info that is already parsed by SmartctlAtaTextParser::parse_full(),
|
||||
// this will parse some info that is already parsed by SmartctlAtaTextParser::parse(),
|
||||
// but this one sets the StorageDevice class members, not properties.
|
||||
this->parse_basic_data(false, false); // don't emit signal, we're not complete yet.
|
||||
|
||||
|
||||
@@ -21,21 +21,21 @@ Copyright:
|
||||
|
||||
TEST_CASE("SmartctlFormatDetection", "[app][parser]")
|
||||
{
|
||||
REQUIRE(SmartctlParser::detect_output_type({}).error().data() == SmartctlParserError::EmptyInput);
|
||||
REQUIRE(SmartctlParser::detect_output_format({}).error().data() == SmartctlParserError::EmptyInput);
|
||||
|
||||
REQUIRE(SmartctlParser::detect_output_type("smart").error().data() == SmartctlParserError::UnsupportedFormat);
|
||||
REQUIRE(SmartctlParser::detect_output_format("smart").error().data() == SmartctlParserError::UnsupportedFormat);
|
||||
|
||||
REQUIRE(SmartctlParser::detect_output_type("{ }").value() == SmartctlParserType::Json);
|
||||
REQUIRE(SmartctlParser::detect_output_format("{ }").value() == SmartctlParserFormat::Json);
|
||||
|
||||
REQUIRE(SmartctlParser::detect_output_type(" \n { } ").value() == SmartctlParserType::Json);
|
||||
REQUIRE(SmartctlParser::detect_output_format(" \n { } ").value() == SmartctlParserFormat::Json);
|
||||
|
||||
REQUIRE(SmartctlParser::detect_output_type("smartctl").value() == SmartctlParserType::Text);
|
||||
REQUIRE(SmartctlParser::detect_output_format("smartctl").value() == SmartctlParserFormat::Text);
|
||||
|
||||
REQUIRE(SmartctlParser::detect_output_type(
|
||||
REQUIRE(SmartctlParser::detect_output_format(
|
||||
R"(smartctl 7.2 2020-12-30 r5155 [x86_64-linux-5.3.18-lp152.66-default] (SUSE RPM)
|
||||
Copyright (C) 2002-20, Bruce Allen, Christian Franke, www.smartmontools.org
|
||||
|
||||
)").value() == SmartctlParserType::Text);
|
||||
)").value() == SmartctlParserFormat::Text);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -24,31 +24,31 @@ TEST_CASE("SmartctlVersionParser", "[app][parser]")
|
||||
std::string version_only, version_full;
|
||||
|
||||
SECTION("Parse with version keyword") {
|
||||
SmartctlVersionParser::parse_version("smartctl version 5.37", version_only, version_full);
|
||||
SmartctlVersionParser::parse_version_text("smartctl version 5.37", version_only, version_full);
|
||||
REQUIRE(version_only == "5.37");
|
||||
REQUIRE(version_full == "5.37");
|
||||
}
|
||||
|
||||
SECTION("Parse without version keyword") {
|
||||
SmartctlVersionParser::parse_version("smartctl 5.39", version_only, version_full);
|
||||
SmartctlVersionParser::parse_version_text("smartctl 5.39", version_only, version_full);
|
||||
REQUIRE(version_only == "5.39");
|
||||
REQUIRE(version_full == "5.39");
|
||||
}
|
||||
|
||||
SECTION("Parse with date (CVS)") {
|
||||
SmartctlVersionParser::parse_version("smartctl 5.39 2009-06-03 20:10", version_only, version_full);
|
||||
SmartctlVersionParser::parse_version_text("smartctl 5.39 2009-06-03 20:10", version_only, version_full);
|
||||
REQUIRE(version_only == "5.39");
|
||||
REQUIRE(version_full == "5.39 2009-06-03 20:10");
|
||||
}
|
||||
|
||||
SECTION("Parse with date (SVN)") {
|
||||
SmartctlVersionParser::parse_version("smartctl 5.39 2009-08-08 r2873", version_only, version_full);
|
||||
SmartctlVersionParser::parse_version_text("smartctl 5.39 2009-08-08 r2873", version_only, version_full);
|
||||
REQUIRE(version_only == "5.39");
|
||||
REQUIRE(version_full == "5.39 2009-08-08 r2873");
|
||||
}
|
||||
|
||||
SECTION("Parse old 5.0") {
|
||||
SmartctlVersionParser::parse_version("smartctl version 5.0-49", version_only, version_full);
|
||||
SmartctlVersionParser::parse_version_text("smartctl version 5.0-49", version_only, version_full);
|
||||
REQUIRE(version_only == "5.0-49");
|
||||
REQUIRE(version_full == "5.0-49");
|
||||
}
|
||||
@@ -70,7 +70,7 @@ smartmontools build host: x86_64-suse-linux-gnu
|
||||
smartmontools build with: C++14, GCC 7.5.0
|
||||
smartmontools configure arguments: '--host=x86_64-suse-linux-gnu' '--build=x86_64-suse-linux-gnu' '--program-prefix=' '--prefix=/usr' '--exec-prefix=/usr' '--bindir=/usr/bin' '--sbindir=/usr/sbin' '--sysconfdir=/etc' '--datadir=/usr/share' '--includedir=/usr/include' '--libdir=/usr/lib64' '--libexecdir=/usr/lib' '--localstatedir=/var' '--sharedstatedir=/var/lib' '--mandir=/usr/share/man' '--infodir=/usr/share/info' '--disable-dependency-tracking' '--docdir=/usr/share/doc/packages/smartmontools' '--with-selinux' '--with-libsystemd' '--with-systemdsystemunitdir=/usr/lib/systemd/system' '--with-savestates' '--with-attributelog' '--with-nvme-devicescan' 'build_alias=x86_64-suse-linux-gnu' 'host_alias=x86_64-suse-linux-gnu' 'CXXFLAGS=-O2 -g -m64 -fmessage-length=0 -D_FORTIFY_SOURCE=2 -fstack-protector -funwind-tables -fasynchronous-unwind-tables -fPIE ' 'LDFLAGS=-pie' 'CFLAGS=-O2 -g -m64 -fmessage-length=0 -D_FORTIFY_SOURCE=2 -fstack-protector -funwind-tables -fasynchronous-unwind-tables -fPIE' 'PKG_CONFIG_PATH=:/usr/lib64/pkgconfig:/usr/share/pkgconfig'
|
||||
)";
|
||||
SmartctlVersionParser::parse_version(output, version_only, version_full);
|
||||
SmartctlVersionParser::parse_version_text(output, version_only, version_full);
|
||||
REQUIRE(version_only == "7.2");
|
||||
REQUIRE(version_full == "7.2 2020-12-30 r5155");
|
||||
}
|
||||
@@ -93,7 +93,7 @@ smartmontools build with: C++11, GCC 7.5.0
|
||||
smartmontools configure arguments: [no arguments given]
|
||||
|
||||
)";
|
||||
SmartctlVersionParser::parse_version(output, version_only, version_full);
|
||||
SmartctlVersionParser::parse_version_text(output, version_only, version_full);
|
||||
REQUIRE(version_only == "7.3");
|
||||
REQUIRE(version_full == "7.3");
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ GscMainWindow::GscMainWindow(BaseObjectType* gtkcobj, Glib::RefPtr<Gtk::Builder>
|
||||
}
|
||||
|
||||
std::string version, version_full;
|
||||
if (!SmartctlVersionParser::parse_version(output, version, version_full)) {
|
||||
if (!SmartctlVersionParser::parse_version_text(output, version, version_full)) {
|
||||
error_msg = _("Smartctl returned invalid output.");
|
||||
break;
|
||||
}
|
||||
|
||||
+11
-11
@@ -236,7 +236,7 @@ inline bool string_trim(std::string& s, const std::string& trim_chars = " \t\r\n
|
||||
|
||||
/// Trim a string s from both sides (not modifying s), returning the changed string.
|
||||
/// Trimming removes all trim_chars that occur on either side of the string s.
|
||||
inline std::string string_trim_copy(const std::string& s, const std::string& trim_chars = " \t\r\n")
|
||||
inline std::string string_trim_copy(std::string_view s, const std::string& trim_chars = " \t\r\n")
|
||||
{
|
||||
std::string ret(s);
|
||||
string_trim(ret, trim_chars);
|
||||
@@ -268,7 +268,7 @@ inline bool string_trim_left(std::string& s, const std::string& trim_chars = " \
|
||||
|
||||
/// Trim a string s from the left (not modifying s), returning the changed string.
|
||||
/// Trimming removes all trim_chars that occur on the left side of the string s.
|
||||
inline std::string string_trim_left_copy(const std::string& s, const std::string& trim_chars = " \t\r\n")
|
||||
inline std::string string_trim_left_copy(std::string_view s, const std::string& trim_chars = " \t\r\n")
|
||||
{
|
||||
std::string ret(s);
|
||||
string_trim_left(ret, trim_chars);
|
||||
@@ -297,7 +297,7 @@ inline bool string_trim_right(std::string& s, const std::string& trim_chars = "
|
||||
|
||||
/// Trim a string s from the right (not modifying s), returning the changed string.
|
||||
/// Trimming removes all trim_chars that occur on the right side of the string s.
|
||||
inline std::string string_trim_right_copy(const std::string& s, const std::string& trim_chars = " \t\r\n")
|
||||
inline std::string string_trim_right_copy(std::string_view s, const std::string& trim_chars = " \t\r\n")
|
||||
{
|
||||
std::string ret(s);
|
||||
string_trim_right(ret, trim_chars);
|
||||
@@ -756,7 +756,7 @@ std::string string_replace_array_copy(const std::string& s,
|
||||
|
||||
|
||||
/// Check whether a string begins with another string
|
||||
inline bool string_begins_with(const std::string& str, const std::string& substr)
|
||||
inline bool string_begins_with(std::string_view str, const std::string& substr)
|
||||
{
|
||||
if (str.length() >= substr.length()) {
|
||||
return (str.compare(0, substr.length(), substr) == 0);
|
||||
@@ -767,7 +767,7 @@ inline bool string_begins_with(const std::string& str, const std::string& substr
|
||||
|
||||
|
||||
/// Check whether a string begins with a character
|
||||
inline bool string_begins_with(const std::string& str, char ch)
|
||||
inline bool string_begins_with(std::string_view str, char ch)
|
||||
{
|
||||
return !str.empty() && str[0] == ch;
|
||||
}
|
||||
@@ -775,7 +775,7 @@ inline bool string_begins_with(const std::string& str, char ch)
|
||||
|
||||
|
||||
/// Check whether a string ends with another string
|
||||
inline bool string_ends_with(const std::string& str, const std::string& substr)
|
||||
inline bool string_ends_with(std::string_view str, const std::string& substr)
|
||||
{
|
||||
if (str.length() >= substr.length()) {
|
||||
return (str.compare(str.length() - substr.length(), substr.length(), substr) == 0);
|
||||
@@ -786,7 +786,7 @@ inline bool string_ends_with(const std::string& str, const std::string& substr)
|
||||
|
||||
|
||||
/// Check whether a string ends with a character
|
||||
inline bool string_ends_with(const std::string& str, char ch)
|
||||
inline bool string_ends_with(std::string_view str, char ch)
|
||||
{
|
||||
return !str.empty() && str[str.size() - 1] == ch;
|
||||
}
|
||||
@@ -810,7 +810,7 @@ inline bool string_any_to_unix(std::string& s)
|
||||
|
||||
/// Auto-detect and convert mac/dos/unix newline formats in s to unix format.
|
||||
/// Returns the result string.
|
||||
inline std::string string_any_to_unix_copy(const std::string& s)
|
||||
inline std::string string_any_to_unix_copy(std::string_view s)
|
||||
{
|
||||
std::string ret(s);
|
||||
string_any_to_unix(ret);
|
||||
@@ -831,7 +831,7 @@ inline bool string_any_to_dos(std::string& s)
|
||||
|
||||
/// Auto-detect and convert mac/dos/unix newline formats in s to dos format.
|
||||
/// Returns the result string.
|
||||
inline std::string string_any_to_dos_copy(const std::string& s)
|
||||
inline std::string string_any_to_dos_copy(std::string_view s)
|
||||
{
|
||||
std::string ret(s);
|
||||
string_any_to_dos(ret);
|
||||
@@ -853,7 +853,7 @@ inline std::string::size_type string_to_lower(std::string& s)
|
||||
|
||||
|
||||
/// Convert s to lowercase, not modifying s, returning the changed string.
|
||||
inline std::string string_to_lower_copy(const std::string& s)
|
||||
inline std::string string_to_lower_copy(std::string_view s)
|
||||
{
|
||||
std::string ret(s);
|
||||
string_to_lower(ret);
|
||||
@@ -875,7 +875,7 @@ inline std::string::size_type string_to_upper(std::string& s)
|
||||
|
||||
|
||||
/// Convert s to uppercase, not modifying s, returning the changed string.
|
||||
inline std::string string_to_upper_copy(const std::string& s)
|
||||
inline std::string string_to_upper_copy(std::string_view s)
|
||||
{
|
||||
std::string ret(s);
|
||||
string_to_upper(ret);
|
||||
|
||||
Reference in New Issue
Block a user