1 /* 2 Copyright (C) 2011 - 2018 by Sytyi Nick <nsytyi@gmail.com> 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 /** 16 * @file 17 * This file contains objects "tag" and "key", which are used to store 18 * information about tags and keys while annotation parsing. 19 */ 20 21 #pragma once 22 23 #include <algorithm> 24 #include <iostream> 25 #include <map> 26 #include <sstream> 27 #include <string> 28 29 class config; 30 31 namespace schema_validation 32 { 33 /** 34 * class_key is used to save the information about one key. 35 * Key has next info: name, type, default value or key is mandatory. 36 */ 37 class class_key 38 { 39 public: class_key()40 class_key() 41 : name_("") 42 , type_("") 43 , default_("\"\"") 44 , mandatory_(false) 45 { 46 } 47 class_key(const std::string & name,const std::string & type,const std::string & def="\\"\\"")48 class_key(const std::string& name, const std::string& type, const std::string& def = "\"\"") 49 : name_(name) 50 , type_(type) 51 , default_(def) 52 , mandatory_(def.empty()) 53 { 54 } 55 56 class_key(const config&); 57 get_name() const58 const std::string& get_name() const 59 { 60 return name_; 61 } 62 get_type() const63 const std::string& get_type() const 64 { 65 return type_; 66 } 67 get_default() const68 const std::string& get_default() const 69 { 70 return default_; 71 } 72 is_mandatory() const73 bool is_mandatory() const 74 { 75 return mandatory_; 76 } 77 set_name(const std::string & name)78 void set_name(const std::string& name) 79 { 80 name_ = name; 81 } 82 set_type(const std::string & type)83 void set_type(const std::string& type) 84 { 85 type_ = type; 86 } 87 set_default(const std::string & def)88 void set_default(const std::string& def) 89 { 90 default_ = def; 91 if(def.empty()) { 92 mandatory_ = true; 93 } 94 } 95 set_mandatory(bool mandatory)96 void set_mandatory(bool mandatory) 97 { 98 mandatory_ = mandatory; 99 } 100 101 /** is used to print key info 102 * the format is next 103 * [key] 104 * name="name" 105 * type="type" 106 * default="default" 107 * mandatory="true/false" 108 * [/key] 109 */ 110 void print(std::ostream& os, int level) const; 111 112 /** Compares keys by name. Used in std::sort, i.e. */ operator <(const class_key & k) const113 bool operator<(const class_key& k) const 114 { 115 return (get_name() < k.get_name()); 116 } 117 118 private: 119 /** Name of key. */ 120 std::string name_; 121 122 /** Type of key. */ 123 std::string type_; 124 125 /** Default value. */ 126 std::string default_; 127 128 /** Shows, if key is a mandatory key. */ 129 bool mandatory_; 130 }; 131 132 /** 133 * Stores information about tag. 134 * Each tags is an element of great tag tree. This tree is close to filesystem: 135 * you can use links and special include directory global/ 136 * Normally root is not mentioned in path. 137 * Each tag has name, minimum and maximum occasions number, 138 * and lists of subtags, keys and links. 139 */ 140 class class_tag 141 { 142 public: 143 using tag_map = std::map<std::string, class_tag>; 144 using key_map = std::map<std::string, class_key>; 145 using link_map = std::map<std::string, std::string>; 146 class_tag()147 class_tag() 148 : name_("") 149 , min_(0) 150 , max_(0) 151 , super_("") 152 , tags_() 153 , keys_() 154 , links_() 155 { 156 } 157 class_tag(const std::string & name,int min,int max,const std::string & super="")158 class_tag(const std::string& name, int min, int max, const std::string& super = "") 159 : name_(name) 160 , min_(min) 161 , max_(max) 162 , super_(super) 163 , tags_() 164 , keys_() 165 , links_() 166 { 167 } 168 169 class_tag(const config&); 170 ~class_tag()171 ~class_tag() 172 { 173 } 174 175 /** Prints information about tag to outputstream, recursively 176 * is used to print tag info 177 * the format is next 178 * [tag] 179 * subtags 180 * keys 181 * name="name" 182 * min="min" 183 * max="max" 184 * [/tag] 185 */ 186 void print(std::ostream& os); 187 get_name() const188 const std::string& get_name() const 189 { 190 return name_; 191 } 192 get_min() const193 int get_min() const 194 { 195 return min_; 196 } 197 get_max() const198 int get_max() const 199 { 200 return max_; 201 } 202 get_super() const203 const std::string& get_super() const 204 { 205 return super_; 206 } 207 is_extension() const208 bool is_extension() const 209 { 210 return !super_.empty(); 211 } 212 set_name(const std::string & name)213 void set_name(const std::string& name) 214 { 215 name_ = name; 216 } 217 set_min(int o)218 void set_min(int o) 219 { 220 min_ = o; 221 } 222 set_max(int o)223 void set_max(int o) 224 { 225 max_ = o; 226 } 227 set_min(const std::string & s)228 void set_min(const std::string& s) 229 { 230 std::istringstream i(s); 231 if(!(i >> min_)) { 232 min_ = 0; 233 } 234 } 235 set_max(const std::string & s)236 void set_max(const std::string& s) 237 { 238 std::istringstream i(s); 239 if(!(i >> max_)) { 240 max_ = 0; 241 } 242 } 243 set_super(const std::string & s)244 void set_super(const std::string& s) 245 { 246 super_ = s; 247 } 248 add_key(const class_key & new_key)249 void add_key(const class_key& new_key) 250 { 251 keys_.emplace(new_key.get_name(), new_key); 252 } 253 add_tag(const class_tag & new_tag)254 void add_tag(const class_tag& new_tag) 255 { 256 tags_.emplace(new_tag.name_, new_tag); 257 } 258 259 void add_link(const std::string& link); 260 261 /** 262 * Tags are usually organized in tree. 263 * This function helps to add a tag to his exact place in tree 264 * @param path - path in subtree to exact place of tag 265 * @param tag - tag to add 266 * @param root - root of schema tree - use to support of adding to link. 267 * Path is getting shotter and shoter with each call. 268 * Path should look like tag1/tag2/parent/ Slash at end is mandatory. 269 */ 270 void add_tag(const std::string& path, const class_tag& tag, class_tag& root); 271 operator <(const class_tag & t) const272 bool operator<(const class_tag& t) const 273 { 274 return name_ < t.name_; 275 } 276 operator ==(const class_tag & other) const277 bool operator==(const class_tag& other) const 278 { 279 return name_ == other.name_; 280 } 281 282 /** Returns pointer to child key. */ 283 const class_key* find_key(const std::string& name) const; 284 285 /** Returns pointer to child link. */ 286 const std::string* find_link(const std::string& name) const; 287 288 /** 289 * Returns pointer to tag using full path to it. 290 * Also work with links 291 */ 292 const class_tag* find_tag(const std::string& fullpath, const class_tag& root) const; 293 294 /** Calls the expansion on each child. */ 295 void expand_all(class_tag& root); 296 tags() const297 const tag_map& tags() const 298 { 299 return tags_; 300 } 301 keys() const302 const key_map& keys() const 303 { 304 return keys_; 305 } 306 links() const307 const link_map& links() const 308 { 309 return links_; 310 } 311 remove_key_by_name(const std::string & name)312 void remove_key_by_name(const std::string& name) 313 { 314 keys_.erase(name); 315 } 316 317 /** Removes all keys with this type. Works recursively */ 318 void remove_keys_by_type(const std::string& type); 319 320 #ifdef _MSC_VER 321 // MSVC throws an error if this method is private. 322 // so, define it as public to prevent that. The error is: 323 // error C2248: 'schema_validation::class_tag::find_tag' : cannot 324 // access private member declared in class 'schema_validation::class_tag' 325 326 class_tag* find_tag(const std::string& fullpath, class_tag& root); 327 #endif 328 329 // class_tag & operator= (const class_tag&); 330 331 private: 332 /** name of tag. */ 333 std::string name_; 334 335 /** number of minimum occasions. */ 336 int min_; 337 338 /** number of maximum occasions. */ 339 int max_; 340 341 /** 342 * name of tag to extend "super-tag" 343 * Extension is smth like inheritance and is used in case 344 * when you need to use another tag with all his 345 * keys, children, etc. But you also want to allow extra subtags of that tags, 346 * so just linking that tag wouldn't help at all. 347 */ 348 std::string super_; 349 350 /** children tags*/ 351 tag_map tags_; 352 353 /** keys*/ 354 key_map keys_; 355 356 /** links to possible children. */ 357 link_map links_; 358 359 /** 360 * the same as class_tag::print(std::ostream&) 361 * but indents different levels with step space. 362 * @param os stream to print 363 * @param level current level of indentation 364 * @param step step to next indent 365 */ 366 void printl(std::ostream& os, int level, int step = 4); 367 368 #ifndef _MSC_VER 369 // this is complementary with the above #ifdef for the MSVC error 370 class_tag* find_tag(const std::string& fullpath, class_tag& root); 371 #endif 372 add_tags(const tag_map & list)373 void add_tags(const tag_map& list) 374 { 375 tags_.insert(list.begin(), list.end()); 376 } 377 add_keys(const key_map & list)378 void add_keys(const key_map& list) 379 { 380 keys_.insert(list.begin(), list.end()); 381 } 382 add_links(const link_map & list)383 void add_links(const link_map& list) 384 { 385 links_.insert(list.begin(), list.end()); 386 } 387 388 /** Copies tags, keys and links of tag to this. */ 389 void append_super(const class_tag& tag, const std::string& super); 390 391 /** Expands all "super" copying their data to this. */ 392 void expand(class_tag& root); 393 }; 394 } 395