The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
persist_context.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2010 - 2016 by Jody Northup
3  Part of the Battle for Wesnoth Project http://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 "global.hpp"
16 
17 #include "filesystem.hpp"
18 #include "log.hpp"
19 #include "persist_context.hpp"
20 #include "persist_manager.hpp"
22 #include "serialization/parser.hpp"
23 #include "util.hpp"
24 
26 {
27  config cfg;
28  cfg[name] = val;
29  return cfg;
30 }
31 
32 static std::string get_persist_cfg_name(const std::string &name_space) {
33  return (filesystem::get_dir(filesystem::get_user_data_dir() + "/persist/") + name_space + ".cfg");
34 }
35 
37 {
39  if (filesystem::file_exists(cfg_name) && !filesystem::is_directory(cfg_name)) {
41  if (!(file_stream->fail())) {
42  try {
43  read(cfg_,*file_stream);
44  } catch (config::error &err) {
45  LOG_PERSIST << err.message << std::endl;
46  }
47  }
48  }
49 }
50 
52  : persist_context(name_space)
53 {
54  load();
55 }
56 
57 bool persist_file_context::clear_var(const std::string &global, bool immediate)
58 {
59  config bak;
60  config bactive;
61  if (immediate) {
62  bak = cfg_;
63  config *node = get_node(bak, namespace_);
64  if (node)
65  bactive = node->child_or_add("variables");
66  load();
67  }
68  config *active = get_node(cfg_, namespace_);
69  if (active == nullptr)
70  return false;
71 
72  bool ret = active->has_child("variables");
73  if (ret) {
74  config &cfg = active->child("variables");
75  bool exists = cfg.has_attribute(global);
76  if (!exists) {
77  if (cfg.has_child(global)) {
78  exists = true;
79  std::string::const_iterator index_start = std::find(global.begin(),global.end(),'[');
80  if (index_start != global.end())
81  {
82  const std::string::const_iterator index_end = std::find(global.begin(),global.end(),']');
83  const std::string index_str(index_start+1,index_end);
84  size_t index = static_cast<size_t>(lexical_cast_default<int>(index_str));
85  cfg.remove_child(global,index);
86  if (immediate) bactive.remove_child(global,index);
87  } else {
88  cfg.clear_children(global);
89  if (immediate) bactive.clear_children(global);
90  }
91  }
92  }
93  if (exists) {
94  cfg.remove_attribute(global);
95  if (immediate) bactive.remove_attribute(global);
96  if (cfg.empty()) {
97  active->clear_children("variables");
98  active->remove_attribute("variables");
99  name_space working = namespace_;
100  while ((active->empty()) && (!working.lineage_.empty())) {
101  name_space prev = working.prev();
102  active = get_node(cfg_, prev);
103  active->clear_children(working.node_);
104  if (active->has_child("variables") && active->child("variables").empty()) {
105  active->clear_children("variables");
106  active->remove_attribute("variables");
107  }
108  working = prev;
109  }
110  }
111 
112  if (!in_transaction_)
113  ret = save_context();
114  else if (immediate) {
115  ret = save_context();
116  cfg_ = bak;
117  active = get_node(cfg_, namespace_);
118  if (active != nullptr) {
119  active->clear_children("variables");
120  active->remove_attribute("variables");
121  if (!bactive.empty())
122  active->add_child("variables",bactive);
123  }
124  } else {
125  ret = true;
126  }
127  } else {
128  if (immediate) {
129  cfg_ = bak;
130  config *active = get_node(cfg_, namespace_);
131  if (active != nullptr) {
132  active->clear_children("variables");
133  active->remove_attribute("variables");
134  if (!bactive.empty())
135  active->add_child("variables",bactive);
136  }
137  }
138  ret = exists;
139  }
140  }
141 
142  // TODO: figure out when this is the case and adjust the next loop
143  // condition accordingly. -- shadowm
144  assert(active);
145 
146  while (active && active->empty() && !namespace_.lineage_.empty()) {
148  active = get_node(cfg_, prev);
149  if (active == nullptr) {
150  break;
151  }
153  if (active->has_child("variables") && active->child("variables").empty()) {
154  active->clear_children("variables");
155  active->remove_attribute("variables");
156  }
157  namespace_ = prev;
158  }
159  return ret;
160 }
161 
163 {
164  config ret;
165  const config *active = get_node(cfg_, namespace_);
166  if (active && (active->has_child("variables"))) {
167  const config &cfg = active->child("variables");
168  size_t arrsize = cfg.child_count(global);
169  if (arrsize > 0) {
170  for (size_t i = 0; i < arrsize; i++)
171  ret.add_child(global,cfg.child(global,i));
172  } else {
173  ret = pack_scalar(global,cfg[global]);
174  }
175  } else {
176  ret = pack_scalar(global,"");
177  }
178  return ret;
179 }
181  bool success = false;
182 
184  if (!cfg_name.empty()) {
185  if (cfg_.empty()) {
186  success = filesystem::delete_file(cfg_name);
187  } else {
189  if (!out->fail())
190  {
191  config_writer writer(*out,false);
192  try {
193  writer.write(cfg_);
194  success = true;
195  } catch(config::error &err) {
196  LOG_PERSIST << err.message << std::endl;
197  success = false;
198  }
199  }
200  }
201  }
202  return success;
203 }
204 bool persist_file_context::set_var(const std::string &global,const config &val, bool immediate)
205 {
206  config bak;
207  config bactive;
208  if (immediate) {
209  bak = cfg_;
210  bactive = get_node(bak, namespace_, true)->child_or_add("variables");
211  load();
212  }
213 
214  config *active = get_node(cfg_, namespace_, true);
215  config &cfg = active->child_or_add("variables");
216  if (val.has_attribute(global)) {
217  if (val[global].empty()) {
218  clear_var(global,immediate);
219  } else {
220  cfg[global] = val[global];
221  if (immediate) bactive[global] = val[global];
222  }
223  } else {
224  cfg.clear_children(global);
225  cfg.append(val);
226  if (immediate) {
227  bactive.clear_children(global);
228  bactive.append(val);
229  }
230  }
231 // dirty_ = true;
232  if (!in_transaction_)
233  return save_context();
234  else if (immediate) {
235  bool ret = save_context();
236  cfg_ = bak;
237  active = get_node(cfg_, namespace_, true);
238  active->clear_children("variables");
239  active->remove_attribute("variables");
240  active->add_child("variables",bactive);
241  return ret;
242  } else
243  return true;
244 }
245 
247  std::string newspace = namespace_.root_;
248  if (!name.empty())
249  newspace += "." + name;
250  namespace_ = name_space(newspace);
251 }
252 
254 {
255  return namespace_.namespace_;
256 }
257 
void remove_attribute(const std::string &key)
Definition: config.cpp:534
void write(const config &cfg)
void append(const config &cfg)
Append data from another config object to this one.
Definition: config.cpp:566
bool delete_file(const std::string &filename)
config & child_or_add(const std::string &key)
Returns a reference to the first child with the given key.
Definition: config.cpp:734
GLuint const GLfloat * val
Definition: glew.h:2614
config pack_scalar(const std::string &name, const t_string &val)
void clear_children(const std::string &key)
Definition: config.cpp:820
bool empty() const
Definition: config.cpp:1105
#define LOG_PERSIST
bool exists(const image::locator &i_locator)
returns true if the given image actually exists, without loading it.
Definition: image.cpp:1187
bool has_child(const std::string &key) const
Determine whether a config has a child or not.
Definition: config.cpp:651
Class for writing a config out to a file in pieces.
std::string get_user_data_dir()
bool set_var(const std::string &, const config &, bool immediate=false)
std::istream * istream_file(const std::string &fname, bool treat_failure_as_error=true)
void remove_child(const std::string &key, unsigned index)
Definition: config.cpp:899
std::ostream * ostream_file(std::string const &fname, bool create_directory=true)
bool is_directory(const std::string &fname)
Returns true if the given file is a directory.
config & add_child(const std::string &key)
Definition: config.cpp:743
static std::string get_persist_cfg_name(const std::string &name_space)
Templates and utility-routines for strings and numbers.
std::string get_dir(const std::string &dir)
std::string get_node() const
persist_file_context(const std::string &name_space)
logger & err()
Definition: log.cpp:79
GLuint index
Definition: glew.h:1782
size_t i
Definition: function.cpp:1057
Declarations for File-IO.
void read(config &cfg, std::istream &in, abstract_validator *validator)
Definition: parser.cpp:400
static int writer(lua_State *L, const void *b, size_t size, void *B)
Definition: lstrlib.cpp:166
unsigned child_count(const std::string &key) const
Definition: config.cpp:635
GLuint const GLchar * name
Definition: glew.h:1782
void set_node(const std::string &)
bool has_attribute(const std::string &key) const
Definition: config.cpp:514
bool find(E event, F functor)
Tests whether an event handler is available.
map_location prev
Definition: astarsearch.cpp:67
config & child(const std::string &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:658
Standard logging facilities (interface).
std::string message
Definition: exceptions.hpp:29
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
config get_var(const std::string &) const
bool file_exists(const std::string &name)
Returns true if a file or directory with such name already exists.
GLsizei const GLcharARB ** string
Definition: glew.h:4503
bool clear_var(const std::string &, bool immediate=false)