The Battle for Wesnoth  1.15.1+dev
persist_context.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2010 - 2018 by Jody Northup
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #include "filesystem.hpp"
16 #include "lexical_cast.hpp"
17 #include "log.hpp"
18 #include "persist_context.hpp"
19 #include "persist_manager.hpp"
21 #include "serialization/parser.hpp"
22 
23 config pack_scalar(const std::string &name, const t_string &val)
24 {
25  config cfg;
26  cfg[name] = val;
27  return cfg;
28 }
29 
30 static std::string get_persist_cfg_name(const std::string &name_space) {
31  return (filesystem::get_dir(filesystem::get_user_data_dir() + "/persist/") + name_space + ".cfg");
32 }
33 
35 {
36  std::string cfg_name = get_persist_cfg_name(namespace_.root_);
37  if (filesystem::file_exists(cfg_name) && !filesystem::is_directory(cfg_name)) {
39  if (!(file_stream->fail())) {
40  try {
41  read(cfg_,*file_stream);
42  } catch (const config::error &err) {
43  LOG_PERSIST << err.message << std::endl;
44  }
45  }
46  }
47 }
48 
50  : persist_context(name_space)
51 {
52  load();
53 }
54 
55 bool persist_file_context::clear_var(const std::string &global, bool immediate)
56 {
57  config bak;
58  config bactive;
59  if (immediate) {
60  bak = cfg_;
61  config *node = get_node(bak, namespace_);
62  if (node)
63  bactive = node->child_or_add("variables");
64  load();
65  }
66  config *active = get_node(cfg_, namespace_);
67  if (active == nullptr)
68  return false;
69 
70  bool ret = active->has_child("variables");
71  if (ret) {
72  config &cfg = active->child("variables");
73  bool exists = cfg.has_attribute(global);
74  if (!exists) {
75  if (cfg.has_child(global)) {
76  exists = true;
77  std::string::const_iterator index_start = std::find(global.begin(),global.end(),'[');
78  if (index_start != global.end())
79  {
80  const std::string::const_iterator index_end = std::find(global.begin(),global.end(),']');
81  const std::string index_str(index_start+1,index_end);
82  std::size_t index = static_cast<std::size_t>(lexical_cast_default<int>(index_str));
83  cfg.remove_child(global,index);
84  if (immediate) bactive.remove_child(global,index);
85  } else {
86  cfg.clear_children(global);
87  if (immediate) bactive.clear_children(global);
88  }
89  }
90  }
91  if (exists) {
92  cfg.remove_attribute(global);
93  if (immediate) bactive.remove_attribute(global);
94  if (cfg.empty()) {
95  active->clear_children("variables");
96  active->remove_attribute("variables");
97  name_space working = namespace_;
98  while ((active->empty()) && (!working.lineage_.empty())) {
99  name_space prev = working.prev();
100  active = get_node(cfg_, prev);
101  active->clear_children(working.node_);
102  if (active->has_child("variables") && active->child("variables").empty()) {
103  active->clear_children("variables");
104  active->remove_attribute("variables");
105  }
106  working = prev;
107  }
108  }
109 
110  if (!in_transaction_)
111  ret = save_context();
112  else if (immediate) {
113  ret = save_context();
114  cfg_ = bak;
115  active = get_node(cfg_, namespace_);
116  if (active != nullptr) {
117  active->clear_children("variables");
118  active->remove_attribute("variables");
119  if (!bactive.empty())
120  active->add_child("variables",bactive);
121  }
122  } else {
123  ret = true;
124  }
125  } else {
126  if (immediate) {
127  cfg_ = bak;
128  active = get_node(cfg_, namespace_);
129  if (active != nullptr) {
130  active->clear_children("variables");
131  active->remove_attribute("variables");
132  if (!bactive.empty())
133  active->add_child("variables", bactive);
134  }
135  }
136  ret = exists;
137  }
138  }
139 
140  // TODO: figure out when this is the case and adjust the next loop
141  // condition accordingly. -- shadowm
142  assert(active);
143 
144  while (active && active->empty() && !namespace_.lineage_.empty()) {
146  active = get_node(cfg_, prev);
147  if (active == nullptr) {
148  break;
149  }
151  if (active->has_child("variables") && active->child("variables").empty()) {
152  active->clear_children("variables");
153  active->remove_attribute("variables");
154  }
155  namespace_ = prev;
156  }
157  return ret;
158 }
159 
160 config persist_file_context::get_var(const std::string &global) const
161 {
162  config ret;
163  const config *active = get_node(cfg_, namespace_);
164  if (active && (active->has_child("variables"))) {
165  const config &cfg = active->child("variables");
166  std::size_t arrsize = cfg.child_count(global);
167  if (arrsize > 0) {
168  for (std::size_t i = 0; i < arrsize; i++)
169  ret.add_child(global,cfg.child(global,i));
170  } else {
171  ret = pack_scalar(global,cfg[global]);
172  }
173  } else {
174  ret = pack_scalar(global,"");
175  }
176  return ret;
177 }
179  bool success = false;
180 
181  std::string cfg_name = get_persist_cfg_name(namespace_.root_);
182  if (!cfg_name.empty()) {
183  if (cfg_.empty()) {
184  success = filesystem::delete_file(cfg_name);
185  } else {
187  if (!out->fail())
188  {
189  config_writer writer(*out,false);
190  try {
191  writer.write(cfg_);
192  success = true;
193  } catch(config::error &err) {
194  LOG_PERSIST << err.message << std::endl;
195  success = false;
196  }
197  }
198  }
199  }
200  return success;
201 }
202 bool persist_file_context::set_var(const std::string &global,const config &val, bool immediate)
203 {
204  config bak;
205  config bactive;
206  if (immediate) {
207  bak = cfg_;
208  bactive = get_node(bak, namespace_, true)->child_or_add("variables");
209  load();
210  }
211 
212  config *active = get_node(cfg_, namespace_, true);
213  config &cfg = active->child_or_add("variables");
214  if (val.has_attribute(global)) {
215  if (val[global].empty()) {
216  clear_var(global,immediate);
217  } else {
218  cfg[global] = val[global];
219  if (immediate) bactive[global] = val[global];
220  }
221  } else {
222  cfg.clear_children(global);
223  cfg.append(val);
224  if (immediate) {
225  bactive.clear_children(global);
226  bactive.append(val);
227  }
228  }
229 // dirty_ = true;
230  if (!in_transaction_)
231  return save_context();
232  else if (immediate) {
233  bool ret = save_context();
234  cfg_ = bak;
235  active = get_node(cfg_, namespace_, true);
236  active->clear_children("variables");
237  active->remove_attribute("variables");
238  active->add_child("variables",bactive);
239  return ret;
240  } else
241  return true;
242 }
243 
244 void persist_context::set_node(const std::string &name) {
245  std::string newspace = namespace_.root_;
246  if (!name.empty())
247  newspace += "." + name;
248  namespace_ = name_space(newspace);
249 }
250 
251 std::string persist_context::get_node() const
252 {
253  return namespace_.namespace_;
254 }
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:420
void write(const config &cfg)
void clear_children(T... keys)
Definition: config.hpp:509
void append(const config &cfg)
Append data from another config object to this one.
Definition: config.cpp:287
bool delete_file(const std::string &filename)
Definition: filesystem.cpp:901
New lexcical_cast header.
bool has_attribute(config_key_type key) const
Definition: config.cpp:213
bool has_child(config_key_type key) const
Determine whether a config has a child or not.
Definition: config.cpp:412
unsigned child_count(config_key_type key) const
Definition: config.cpp:390
static bool file_exists(const bfs::path &fpath)
Definition: filesystem.cpp:282
filesystem::scoped_istream istream_file(const std::string &fname, bool treat_failure_as_error)
Definition: filesystem.cpp:920
config & child_or_add(config_key_type key)
Definition: config.cpp:466
config pack_scalar(const std::string &name, const t_string &val)
void remove_attribute(config_key_type key)
Definition: config.cpp:235
static bfs::path get_dir(const bfs::path &dirpath)
Definition: filesystem.cpp:293
#define LOG_PERSIST
bool exists(const image::locator &i_locator)
returns true if the given image actually exists, without loading it.
Definition: picture.cpp:1070
static const char * name(const std::vector< SDL_Joystick *> &joysticks, const std::size_t index)
Definition: joystick.cpp:48
void read(config &cfg, std::istream &in, abstract_validator *validator)
Definition: parser.cpp:625
Class for writing a config out to a file in pieces.
std::string get_user_data_dir()
Definition: filesystem.cpp:775
bool set_var(const std::string &, const config &, bool immediate=false)
bool is_directory(const std::string &fname)
Returns true if the given file is a directory.
std::unique_ptr< std::istream > scoped_istream
Definition: filesystem.hpp:39
static std::string get_persist_cfg_name(const std::string &name_space)
std::unique_ptr< std::ostream > scoped_ostream
Definition: filesystem.hpp:40
persist_file_context(const std::string &name_space)
std::size_t i
Definition: function.cpp:933
logger & err()
Definition: log.cpp:78
Declarations for File-IO.
static int writer(lua_State *L, const void *b, size_t size, void *B)
Definition: lstrlib.cpp:182
std::size_t index(const std::string &str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:71
config & add_child(config_key_type key)
Definition: config.cpp:476
void set_node(const std::string &)
std::string get_node() const
config get_var(const std::string &) const
bool find(E event, F functor)
Tests whether an event handler is available.
map_location prev
Definition: astarsearch.cpp:65
Standard logging facilities (interface).
std::string message
Definition: exceptions.hpp:31
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:92
void remove_child(config_key_type key, unsigned index)
Definition: config.cpp:694
bool empty() const
Definition: config.cpp:884
bool clear_var(const std::string &, bool immediate=false)
filesystem::scoped_ostream ostream_file(const std::string &fname, bool create_directory)
Definition: filesystem.cpp:958