blob: 958b54f28635f6e17259f23572a27ffbf1299267 [file] [log] [blame]
Yanbiao Lia8a7d272015-07-20 17:28:45 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright 2015, Regents of the University of California.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
6 * file except in compliance with the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software distributed under
11 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
12 * KIND, either express or implied. See the License for the specific language governing
13 * permissions and limitations under the License.
14 */
15
16#include "infoedit.hpp"
17#include <iostream>
18#include <boost/program_options/options_description.hpp>
19#include <boost/program_options/variables_map.hpp>
20#include <boost/program_options/parsers.hpp>
21
22namespace infoedit {
23
24void
25InfoEditor::load(const std::string& fileName)
26{
27 std::ifstream input(fileName);
28 if (!input.good() || !input.is_open()) {
29 throw Error("Failed to open configuration file for parsing");
30 }
31
32 try {
33 boost::property_tree::info_parser::read_info(input, m_info);
34 }
35 catch (boost::property_tree::info_parser::info_parser_error& error) {
36 std::stringstream msg;
37 msg << "Failed to parse configuration file";
38 msg << " " << error.message() << " line " << error.line();
39 throw Error(msg.str());
40 }
41
42 input.close();
43}
44
45InfoEditor&
46InfoEditor::modify(const std::string& section, const std::string& value)
47{
48 m_info.put(section.c_str(), value.c_str());
49 return *this;
50}
51
52InfoEditor&
53InfoEditor::remove(const std::string& section)
54{
55 std::size_t pos = section.find_last_of(".");
56 if (pos == std::string::npos) {
57 m_info.erase(section.c_str());
58 }
59 else {
60 boost::optional<boost::property_tree::ptree&> child =
61 m_info.get_child_optional(section.substr(0, pos));
62 if (child) {
63 child->erase(section.substr(pos + 1));
64 }
65 }
66
67 return *this;
68}
69
70InfoEditor&
71InfoEditor::insert(const std::string& section, std::istream& stream)
72{
73 boost::property_tree::ptree pt;
74 read_info(stream, pt);
75
76 m_info.add_child(section.c_str(), pt);
77
78 return *this;
79}
80
81void
82InfoEditor::save(const std::string& fileName)
83{
84 std::ofstream output(fileName);
85 write_info(output, m_info);
86 output.close();
87}
88
89int
90main(int argc, char** argv)
91{
92 std::string configFile;
93 std::string sectionPath;
94 std::string value;
95
96 namespace po = boost::program_options;
97 po::options_description description("Usage\n"
98 " infoedit [-f file] [-s|d|a|r path] [-v value]\n"
99 "Options");
100
101 description.add_options()
102 ("help,h", "print this help message")
103 ("file,f", po::value<std::string>(&configFile), "the file to edit")
104 ("section,s", po::value<std::string>(&sectionPath), "the section to modify")
105 ("value,v", po::value<std::string>(&value), "the value used to modify some section")
106 ("delete,d", po::value<std::string>(&sectionPath), "the sub tree to delete")
107 ("add,a", po::value<std::string>(&sectionPath), "adds a sub tree")
108 ("replace,r", po::value<std::string>(&sectionPath), "replace the sub tree")
109 ;
110
111 po::variables_map vm;
112 try {
113 po::store(po::command_line_parser(argc, argv).options(description).run(), vm);
114 po::notify(vm);
115 }
116 catch (const std::exception& e) {
117 std::cerr << "ERROR: " << e.what()
118 << "\n"
119 << description;
120 return 1;
121 }
122
123 if (vm.count("help") > 0) {
124 std::cout << description;
125 return 0;
126 }
127
128 if (vm.count("file") == 0) {
129 std::cerr << "ERROR: the file to edit should be specified"
130 << "\n"
131 << description;
132 return 1;
133 }
134
135 InfoEditor editor;
136 try {
137 editor.load(configFile);
138 }
139 catch (const std::exception& e) {
140 std::cerr << "ERROR: " << e.what() << std::endl;
141 return 1;
142 }
143
144 try {
145 if (vm.count("section") > 0) {
146 if (vm.count("value") == 0) {
147 std::cerr << "ERROR: value must be specified" << std::endl;
148 return 1;
149 }
150
151 editor.modify(sectionPath, value);
152 }
153
154 if (vm.count("delete") > 0) {
155 editor.remove(sectionPath);
156 }
157
158 if (vm.count("add") > 0) {
159 editor.insert(sectionPath, std::cin);
160 }
161
162 if (vm.count("replace") > 0) {
163 editor.remove(sectionPath).insert(sectionPath, std::cin);
164 }
165 }
166 catch (...) {
167 return 1;
168 }
169
170 try {
171 editor.save(configFile);
172 }
173 catch (...) {
174 return 1;
175 }
176
177 return 0;
178}
179
180} // namespace infoedit
181
182int
183main(int argc, char** argv)
184{
185 return infoedit::main(argc, argv);
186}