// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chromeos/system/name_value_pairs_parser.h" #include "base/command_line.h" #include "base/file_util.h" #include "base/files/file_path.h" #include "base/logging.h" #include "base/process_util.h" #include "base/stl_util.h" #include "base/strings/string_tokenizer.h" #include "base/strings/string_util.h" namespace chromeos { // NOLINT namespace system { namespace { const char kQuoteChars[] = "\""; const char kTrimChars[] = "\" "; bool GetToolOutput(int argc, const char* argv[], std::string& output) { DCHECK_GE(argc, 1); if (!file_util::PathExists(base::FilePath(argv[0]))) { LOG(WARNING) << "Tool for statistics not found: " << argv[0]; return false; } std::vector args; for (int argn = 0; argn < argc; ++argn) args.push_back(argv[argn]); if (!base::GetAppOutput(args, &output)) { LOG(WARNING) << "Error executing " << argv[0]; return false; } return true; } } // namespace NameValuePairsParser::NameValuePairsParser(NameValueMap* map) : map_(map) { } void NameValuePairsParser::AddNameValuePair(const std::string& key, const std::string& value) { if (!ContainsKey(*map_, key)) { (*map_)[key] = value; VLOG(1) << "name: " << key << ", value: " << value; } else { LOG(WARNING) << "Key " << key << " already has value " << (*map_)[key] << ", ignoring new value: " << value; } } bool NameValuePairsParser::ParseNameValuePairs(const std::string& in_string, const std::string& eq, const std::string& delim) { return ParseNameValuePairsWithComments(in_string, eq, delim, ""); } bool NameValuePairsParser::ParseNameValuePairsWithComments( const std::string& in_string, const std::string& eq, const std::string& delim, const std::string& comment_delim) { bool all_valid = true; // Set up the pair tokenizer. base::StringTokenizer pair_toks(in_string, delim); pair_toks.set_quote_chars(kQuoteChars); // Process token pairs. while (pair_toks.GetNext()) { std::string pair(pair_toks.token()); // Anything before the first |eq| is the key, anything after is the value. // |eq| must exist. size_t eq_pos = pair.find(eq); if (eq_pos != std::string::npos) { // First |comment_delim| after |eq_pos| starts the comment. // A value of |std::string::npos| means that the value spans to the end // of |pair|. size_t value_size = std::string::npos; if (!comment_delim.empty()) { size_t comment_pos = pair.find(comment_delim, eq_pos + 1); if (comment_pos != std::string::npos) value_size = comment_pos - eq_pos - 1; } std::string key; std::string value; TrimString(pair.substr(0, eq_pos), kTrimChars, &key); TrimString(pair.substr(eq_pos + 1, value_size), kTrimChars, &value); if (!key.empty()) { AddNameValuePair(key, value); continue; } } LOG(WARNING) << "Invalid token pair: " << pair << ". Ignoring."; all_valid = false; } return all_valid; } bool NameValuePairsParser::GetSingleValueFromTool(int argc, const char* argv[], const std::string& key) { std::string output_string; if (!GetToolOutput(argc, argv, output_string)) return false; TrimWhitespaceASCII(output_string, TRIM_ALL, &output_string); AddNameValuePair(key, output_string); return true; } bool NameValuePairsParser::GetNameValuePairsFromFile( const base::FilePath& file_path, const std::string& eq, const std::string& delim) { std::string contents; if (file_util::ReadFileToString(file_path, &contents)) { return ParseNameValuePairs(contents, eq, delim); } else { LOG(WARNING) << "Unable to read statistics file: " << file_path.value(); return false; } } bool NameValuePairsParser::ParseNameValuePairsFromTool( int argc, const char* argv[], const std::string& eq, const std::string& delim, const std::string& comment_delim) { std::string output_string; if (!GetToolOutput(argc, argv, output_string)) return false; return ParseNameValuePairsWithComments( output_string, eq, delim, comment_delim); } } // namespace system } // namespace chromeos