The Battle for Wesnoth  1.15.0-dev
translation.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2006 - 2018 by Mark de Wever <koraq@xs4all.nl>
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  * Routines for terrain-conversion.
18  */
19 
20 #define GETTEXT_DOMAIN "wesnoth-lib"
21 
22 #include "gettext.hpp"
23 #include "lexical_cast.hpp"
24 #include "log.hpp"
25 #include "terrain/translation.hpp"
27 #include "wml_exception.hpp"
28 
29 
30 #define ERR_G LOG_STREAM(err, lg::general())
31 #define WRN_G LOG_STREAM(warn, lg::general())
32 
33 namespace t_translation {
34 
35  int max_map_size() {
36  return 1000; //TODO make this overridable by the user without having to rebuild
37  }
38 
39 /***************************************************************************************/
40 // forward declaration of internal functions
41 
42  // The low level convertors,
43  // These function are the ones which know about the internal format.
44  // All other functions are unaware of the internal format.
45 
46  /**
47  * Get the mask for a single layer.
48  *
49  * @param terrain 1 layer of a terrain, might have a wildcard.
50  *
51  * @return Mask for that layer.
52  */
53  static ter_layer get_layer_mask_(ter_layer terrain); //inlined
54 
55  /**
56  * Gets a mask for a terrain, this mask is used for wildcard matching.
57  *
58  * @param terrain The terrain which might have a wildcard.
59  *
60  * @return The mask for this terrain.
61  */
62  static terrain_code get_mask_(const terrain_code& terrain);
63 
64  static ter_layer string_to_layer_(const char* begin, const char* end);
65 
66  /**
67  * Converts a string to a layer.
68  *
69  * @param str The terrain string to convert, but needs to be
70  * sanitized so no spaces and only the terrain to convert.
71  *
72  * @return The converted layer.
73  */
74  static ter_layer string_to_layer_(const std::string& str)
75  {
76  return string_to_layer_(str.c_str(), str.c_str() + str.size());
77  }
78 
79  /**
80  * Converts a terrain string to a number.
81  * @param str The terrain string with an optional number.
82  * @param start_position Returns the start_position, the caller should
83  * set it on -1 and it's only changed it there is
84  * a starting position found.
85  * @param filler If the terrain has only 1 layer then the filler
86  * will be used as the second layer.
87  *
88  * @return The terrain code found in the string if no
89  * valid terrain is found VOID will be returned.
90  */
91  static terrain_code string_to_number_(utils::string_view, std::string& start_position, const ter_layer filler);
93 
94  /**
95  * Converts a terrain number to a string
96  *
97  * @param terrain The terrain number to convert.
98  * @param start_position The starting position, if smaller than 0
99  * it's ignored else it's written.
100  *
101  * @return The converted string, if no starting
102  * position given it's padded to 4 chars else
103  * padded to 7 chars.
104  */
105  static std::string number_to_string_(terrain_code terrain, const std::string& start_position = "");
106 
107  /**
108  * Converts a terrain string to a number for the builder.
109  * The translation rules differ from the normal conversion rules
110  *
111  * @param str The terrain string.
112  *
113  * @return Number for the builder map.
114  */
115  static terrain_code string_to_builder_number_(std::string str);
116 
117 /***************************************************************************************/
118 
120 
123 
132 
138 
144 
145 const ter_match ALL_OFF_MAP("_off^_usr,*^_fme");
146 const ter_match ALL_FORESTS("F*,*^F*");
147 const ter_match ALL_HILLS("!,*^V*,!,H*");
148 const ter_match ALL_MOUNTAINS("!,*^V*,!,M*"); //excluding impassable mountains
149 const ter_match ALL_SWAMPS("!,*^V*,*^B*,!,S*"); //excluding swamp villages and bridges
150 
151 /***************************************************************************************/
152 
153 terrain_code::terrain_code(const std::string& b, ter_layer o) :
154  base(string_to_layer_(b)), overlay(o)
155 {}
156 
157 terrain_code::terrain_code(const std::string& b, const std::string& o) :
158  base(string_to_layer_(b)), overlay(string_to_layer_(o))
159 {}
160 
162  terrain(),
163  mask(),
164  masked_terrain(),
165  has_wildcard(false),
166  is_empty(true)
167 {}
168 
170  terrain(t_translation::read_list(str, filler)),
171  mask(),
172  masked_terrain(),
174  is_empty(terrain.empty())
175 
176 {
177  mask.resize(terrain.size());
178  masked_terrain.resize(terrain.size());
179 
180  for(std::size_t i = 0; i < terrain.size(); i++) {
181  mask[i] = t_translation::get_mask_(terrain[i]);
182  masked_terrain[i] = mask[i] & terrain[i];
183  }
184 }
185 
187  terrain(ter_list(1, tcode)),
188  mask(),
189  masked_terrain(),
191  is_empty(terrain.empty())
192 {
193  mask.resize(terrain.size());
194  masked_terrain.resize(terrain.size());
195 
196  for(std::size_t i = 0; i < terrain.size(); i++) {
197  mask[i] = t_translation::get_mask_(terrain[i]);
198  masked_terrain[i] = mask[i] & terrain[i];
199  }
200 }
201 
203 {
204  return string_to_number_(str, filler);
205 }
206 
207 std::string write_terrain_code(const terrain_code& tcode)
208 {
209  return number_to_string_(tcode);
210 }
211 
213 {
214  // Handle an empty string
215  ter_list result;
216 
217  if(str.empty()) {
218  return result;
219  }
220 
221  std::size_t offset = 0;
222  while(offset < str.length()) {
223 
224  // Get a terrain chunk
225  const std::string separators = ",";
226  const size_t pos_separator = str.find_first_of(separators, offset);
227  utils::string_view terrain = str.substr(offset, pos_separator - offset);
228 
229  // Process the chunk
230  const terrain_code tile = string_to_number_(terrain, filler);
231 
232  // Add the resulting terrain number
233  result.push_back(tile);
234 
235  // Evaluate the separator
236  if(pos_separator == utils::string_view::npos) {
237  offset = str.length();
238  } else {
239  offset = pos_separator + 1;
240  }
241  }
242 
243  return result;
244 }
245 
246 std::string write_list(const ter_list& list)
247 {
248  std::stringstream result;
249 
250  ter_list::const_iterator itor = list.begin();
251  for( ; itor != list.end(); ++itor) {
252  if(itor == list.begin()) {
253  result << number_to_string_(*itor);
254  } else {
255  result << ", " << number_to_string_(*itor);
256  }
257  }
258 
259  return result.str();
260 }
261 
262 static std::pair<int, int> get_map_size(const char* begin, const char* end)
263 {
264  int w = 1;
265  int h = 0;
266  for (const char* it = begin; it != end;) {
267  int cur_w = 1;
268  ++h;
269 
270 
271  for (;it != end && (*it != '\n' && *it != '\r'); ++it) {
272  if (*it == ',') {
273  ++cur_w;
274  }
275  }
276  w = std::max(w, cur_w);
277 
278  while (it != end && (*it == '\n' || *it == '\r')) {
279  ++it;
280  }
281 
282  }
283  return{ w, h };
284 }
285 
287 {
288  std::size_t offset = 0;
289  int x = 0, y = 0, width = 0;
290 
291  // Skip the leading newlines
292  while(!str.empty() && utils::isnewline(str.front())) {
293  str.remove_prefix(1);
294  }
295 
296  // Did we get an empty map?
297  if(str.length() <= 1) {
298  return ter_map();
299  }
300 
301  auto map_size = get_map_size(&str[0], &str[0] + str.size());
302  ter_map result(map_size.first, map_size.second);
303 
304  while(offset < str.length()) {
305 
306  // Get a terrain chunk
307  const std::string separators = ",\n\r";
308  const std::size_t pos_separator = str.find_first_of(separators, offset);
309  utils::string_view terrain = str.substr(offset, pos_separator - offset);
310 
311  // Process the chunk
312  std::string starting_position;
313  // The gamemap never has a wildcard
314  const terrain_code tile = string_to_number_(terrain, starting_position, NO_LAYER);
315 
316  // Add to the resulting starting position
317  if(!starting_position.empty()) {
318  if (starting_positions.left.find(starting_position) != starting_positions.left.end()) {
319  WRN_G << "Starting position " << starting_position << " is redefined." << std::endl;
320  }
321  starting_positions.insert(starting_positions::value_type(starting_position, coordinate(x - border_offset.x, y - border_offset.y)));
322  }
323 
324  if(result.w <= x || result.h <= y) {
325  throw error("Map not a rectangle.");
326  }
327 
328  // Add the resulting terrain number
329  result.get(x, y) = tile;
330 
331  // Evaluate the separator
332  if(pos_separator == std::string::npos || utils::isnewline(str[pos_separator])) {
333  // the first line we set the with the other lines we check the width
334  if(y == 0) {
335  // x contains the offset in the map
336  width = x + 1;
337  } else {
338  if((x + 1) != width ) {
339  ERR_G << "Map not a rectangle error occurred at line offset " << y << " position offset " << x << std::endl;
340  throw error("Map not a rectangle.");
341  }
342  if (y > max_map_size()) {
343  ERR_G << "Map size exceeds limit (y > " << max_map_size() << ")" << std::endl;
344  throw error("Map height limit exceeded.");
345  }
346  }
347 
348  // Prepare next iteration
349  ++y;
350  x = 0;
351 
352  // Avoid in infinite loop if the last line ends without an EOL
353  if(pos_separator == std::string::npos) {
354  offset = str.length();
355 
356  } else {
357 
358  offset = pos_separator + 1;
359  // Skip the following newlines
360  while(offset < str.length() && utils::isnewline(str[offset])) {
361  ++offset;
362  }
363  }
364 
365  } else {
366  ++x;
367  offset = pos_separator + 1;
368  if (x > max_map_size()) {
369  ERR_G << "Map size exceeds limit (x > " << max_map_size() << ")" << std::endl;
370  throw error("Map width limit exceeded.");
371  }
372  }
373 
374  }
375 
376  if(x != 0 && (x + 1) != width) {
377  ERR_G << "Map not a rectangle error occurred at the end" << std::endl;
378  throw error("Map not a rectangle.");
379  }
380 
381  return result;
382 }
383 
384 std::string write_game_map(const ter_map& map, const starting_positions& starting_positions, coordinate border_offset)
385 {
386  std::stringstream str;
387 
388  for(int y = 0; y < map.h; ++y) {
389  for(int x = 0; x < map.w; ++x) {
390 
391  // If the current location is a starting position,
392  // it needs to be added to the terrain.
393  // After it's found it can't be found again,
394  // so the location is removed from the map.
395  auto itor = starting_positions.right.find(coordinate(x - border_offset.x, y - border_offset.y));
396  std::string starting_position;
397  if (itor != starting_positions.right.end()) {
398  starting_position = itor->second;
399  }
400  // Add the separator
401  if(x != 0) {
402  str << ", ";
403  }
404  str << number_to_string_(map[x][y], starting_position);
405  }
406 
407  if (y < map.h -1)
408  str << "\n";
409  }
410 
411  return str.str();
412 }
413 
414 bool terrain_matches(const terrain_code& src, const terrain_code& dest)
415 {
416  return terrain_matches(src, ter_list(1, dest));
417 }
418 
419 bool terrain_matches(const terrain_code& src, const ter_list& dest)
420 {
421  // NOTE we impose some code duplication.
422  // It could have been rewritten to get a match structure
423  // and then call the version with the match structure.
424  // IMO that's some extra overhead to this function
425  // which is not required. Hence the two versions
426  if(dest.empty()) {
427  return false;
428  }
429 
430 #if 0
431  std::cerr << std::hex << "src = " << src.base << "^" << src.overlay << "\t"
432  << src_mask.base << "^" << src_mask.overlay << "\t"
433  << masked_src.base << "^" << masked_src.overlay << "\t"
434  << src_has_wildcard << "\n";
435 #endif
436 
437  bool result = true;
438  ter_list::const_iterator itor = dest.begin();
439 
440  // Try to match the terrains if matched jump out of the loop.
441  for(; itor != dest.end(); ++itor) {
442 
443  // Match wildcard
444  if(*itor == STAR) {
445  return result;
446  }
447 
448  // Match inverse symbol
449  if(*itor == NOT) {
450  result = !result;
451  continue;
452  }
453 
454  // Full match
455  if(src == *itor) {
456  return result;
457  }
458 
459  // Does the destination wildcard match
460  const terrain_code dest_mask = get_mask_(*itor);
461  const terrain_code masked_dest = (*itor & dest_mask);
462  const bool dest_has_wildcard = has_wildcard(*itor);
463 #if 0
464  std::cerr << std::hex << "dest= "
465  << itor->base << "^" << itor->overlay << "\t"
466  << dest_mask.base << "^" << dest_mask.overlay << "\t"
467  << masked_dest.base << "^" << masked_dest.overlay << "\t"
468  << dest_has_wildcard << "\n";
469 #endif
470  if(dest_has_wildcard &&
471  (src.base & dest_mask.base) == masked_dest.base &&
472  (src.overlay & dest_mask.overlay) == masked_dest.overlay) {
473  return result;
474  }
475 
476 /* Test code */ /*
477  if(src_has_wildcard && dest_has_wildcard && (
478  (
479  get_layer_mask_(itor->base) != NO_LAYER &&
480  get_layer_mask_(src.overlay) != NO_LAYER &&
481  (src.base & dest_mask.base) == masked_dest.base &&
482  (itor->overlay & src_mask.overlay) == masked_src.overlay
483  ) || (
484  get_layer_mask_(itor->overlay) != NO_LAYER &&
485  get_layer_mask_(src.base) != NO_LAYER &&
486  (src.overlay & dest_mask.overlay) == masked_dest.overlay &&
487  (itor->base & src_mask.base) == masked_src.base
488  ))) {
489 
490  return result;
491  }
492 */
493  }
494 
495  // No match, return the inverse of the result
496  return !result;
497 }
498 
499 // This routine is used for the terrain building,
500 // so it's one of the delays while loading a map.
501 // This routine is optimized a bit at the loss of readability.
502 bool terrain_matches(const terrain_code& src, const ter_match& dest)
503 {
504  if(dest.is_empty) {
505  return false;
506  }
507 
508  bool result = true;
509 
510  // Try to match the terrains if matched jump out of the loop.
511  // We loop on the dest.terrain since the iterator is faster than operator[].
512  // The i holds the value for operator[].
513  // Since dest.mask and dest.masked_terrain need to be in sync,
514  // they are less often looked up, so no iterator for them.
515  std::size_t i = 0;
516  ter_list::const_iterator end = dest.terrain.end();
517  for(ter_list::const_iterator terrain_itor = dest.terrain.begin();
518  terrain_itor != end;
519  ++i, ++terrain_itor) {
520 
521  // Match wildcard
522  if(*terrain_itor == STAR) {
523  return result;
524  }
525 
526  // Match inverse symbol
527  if(*terrain_itor == NOT) {
528  result = !result;
529  continue;
530  }
531 
532  // Full match
533  if(*terrain_itor == src) {
534  return result;
535  }
536 
537  // Does the destination wildcard match
538  if(dest.has_wildcard &&
539  (src.base & dest.mask[i].base) == dest.masked_terrain[i].base &&
540  (src.overlay & dest.mask[i].overlay) == dest.masked_terrain[i].overlay) {
541  return result;
542  }
543 
544 /* Test code */ /*
545  if(src_has_wildcard && has_wildcard(*terrain_itor) && (
546  (
547  get_layer_mask_(terrain_itor->base) != NO_LAYER &&
548  get_layer_mask_(src.overlay) != NO_LAYER &&
549  (src.base & dest.mask[i].base) == dest.masked_terrain[i].base &&
550  (terrain_itor->overlay & src_mask.overlay) == masked_src.overlay
551  ) || (
552  get_layer_mask_(terrain_itor->overlay) != NO_LAYER &&
553  get_layer_mask_(src.base) != NO_LAYER &&
554  (src.overlay & dest.mask[i].overlay) == dest.masked_terrain[i].overlay &&
555  (terrain_itor->base & src_mask.base) == masked_src.base
556  ))) {
557 
558  return result;
559  }
560 */
561  }
562 
563  // No match, return the inverse of the result
564  return !result;
565 }
566 
567 bool has_wildcard(const terrain_code& tcode)
568 {
569  if(tcode.overlay == NO_LAYER) {
570  return get_layer_mask_(tcode.base) != NO_LAYER;
571  } else {
572  return get_layer_mask_(tcode.base) != NO_LAYER || get_layer_mask_(tcode.overlay) != NO_LAYER;
573  }
574 }
575 
576 bool has_wildcard(const ter_list& list)
577 {
578  if(list.empty()) {
579  return false;
580  }
581 
582  // Test all items for a wildcard
583  ter_list::const_iterator itor = list.begin();
584  for(; itor != list.end(); ++itor) {
585  if(has_wildcard(*itor)) {
586  return true;
587  }
588  }
589 
590  // No wildcard found
591  return false;
592 }
593 
594 ter_map read_builder_map(const std::string& str)
595 {
596  boost::multi_array<int, sizeof(ter_map)> a;
597 
598  std::size_t offset = 0;
599  // Skip the leading newlines
600  while(offset < str.length() && utils::isnewline(str[offset])) {
601  ++offset;
602  }
603  // Did we get an empty map?
604  if((offset + 1) >= str.length()) {
605  return ter_map();
606  }
607 
608  auto map_size = get_map_size(&str[offset], str.c_str() + str.size());
609  ter_map result(map_size.second, map_size.first, terrain_code(t_translation::TB_DOT, ter_layer()));
610 
611  int x = 0, y = 0;
612  while(offset < str.length()) {
613 
614  // Get a terrain chunk
615  const std::string separators = ",\n\r";
616  const std::size_t pos_separator = str.find_first_of(separators, offset);
617  std::string terrain = "";
618  // Make sure we didn't hit an empty chunk
619  // which is allowed
620  if(pos_separator != offset) {
621  terrain = str.substr(offset, pos_separator - offset);
622  }
623 
624  // Process the chunk
625  const terrain_code tile = string_to_builder_number_(terrain);
626 
627  // Make space for the new item
628  if (result.h <= x || result.w <= y) {
629  throw error("Map not a rectangle.");
630  }
631 
632  // Add the resulting terrain number,
633  result.get(y, x) = tile;
634 
635  // evaluate the separator
636  if(pos_separator == std::string::npos) {
637  // Probably not required to change the value,
638  // but be sure the case should be handled at least.
639  // I'm not sure how it is defined in the standard,
640  // but here it's defined at max u32 which with +1 gives 0
641  // and make a nice infinite loop.
642  offset = str.length();
643  } else if(utils::isnewline(str[pos_separator])) {
644  // Prepare next iteration
645  ++y;
646  x = 0;
647 
648  offset = pos_separator + 1;
649  // Skip the following newlines
650  while(offset < str.length() && utils::isnewline(str[offset])) {
651  ++offset;
652  }
653 
654  } else {
655  ++x;
656  offset = pos_separator + 1;
657  }
658 
659  }
660 
661  return result;
662 }
663 
664 /***************************************************************************************/
665 // Internal
666 
668 {
669  // Test for the star 0x2A in every position
670  // and return the appropriate mask
671 /*
672  * This is what the code intents to do, but in order to gain some more
673  * speed it's changed to the code below, which does the same but faster.
674  * This routine is used often in the builder and the speedup is noticeable. */
675  if((terrain & 0xFF000000) == 0x2A000000) return 0x00000000;
676  if((terrain & 0x00FF0000) == 0x002A0000) return 0xFF000000;
677  if((terrain & 0x0000FF00) == 0x00002A00) return 0xFFFF0000;
678  if((terrain & 0x000000FF) == 0x0000002A) return 0xFFFFFF00;
679 
680 /*
681  uint8_t *ptr = (uint8_t *) &terrain;
682 
683  if(ptr[3] == 0x2A) return 0x00000000;
684  if(ptr[2] == 0x2A) return 0xFF000000;
685  if(ptr[1] == 0x2A) return 0xFFFF0000;
686  if(ptr[0] == 0x2A) return 0xFFFFFF00;
687 */
688  // no star found return the default
689  return 0xFFFFFFFF;
690 }
691 
692 static terrain_code get_mask_(const terrain_code& terrain)
693 {
694  if(terrain.overlay == NO_LAYER) {
695  return terrain_code(get_layer_mask_(terrain.base), 0xFFFFFFFF);
696  } else {
697  return terrain_code(get_layer_mask_(terrain.base), get_layer_mask_(terrain.overlay));
698  }
699 }
700 
701 static ter_layer string_to_layer_(const char* begin, const char* end)
702 {
703  std::size_t size = end - begin;
704  if (begin == end) {
705  return NO_LAYER;
706  }
707  ter_layer result = 0;
708 
709  // Validate the string
710  VALIDATE(size <= 4, _("A terrain with a string with more "
711  "than 4 characters has been found, the affected terrain is :") + std::string(begin, end));
712 
713  // The conversion to int puts the first char
714  // in the highest part of the number.
715  // This will make the wildcard matching
716  // later on a bit easier.
717  for(std::size_t i = 0; i < 4; ++i) {
718  const unsigned char c = (i < size) ? begin[i] : 0;
719 
720  // Clearing the lower area is a nop on i == 0
721  // so no need for if statement
722  result <<= 8;
723 
724  // Add the result
725  result += c;
726  }
727 
728  return result;
729 }
730 
732  std::string dummy;
733  return string_to_number_(str, dummy, filler);
734 }
735 
736 static terrain_code string_to_number_(utils::string_view str, std::string& start_position, const ter_layer filler)
737 {
738  const char* c_str = &str[0];
739  terrain_code result;
740 
741  // Strip the spaces around us
742  const std::string& whitespace = " \t";
743  std::size_t begin = str.find_first_not_of(whitespace);
744  std::size_t end = str.find_last_not_of(whitespace) + 1;
745  if(begin == std::string::npos) {
746  return result;
747  }
748 
749  // Split if we have 1 space inside
750  std::size_t offset = str.find(' ', begin);
751  if(offset < end) {
752  start_position = std::string(str.substr(begin, offset - begin));
753  begin = offset + 1;
754  }
755 
756  offset = str.find('^', 0);
757  if(offset != std::string::npos) {
758  result = terrain_code { string_to_layer_(c_str + begin, c_str + offset), string_to_layer_(c_str + offset + 1, c_str + end) };
759  } else {
760  result = terrain_code { string_to_layer_(c_str + begin, c_str + end), filler };
761 
762  // Ugly hack
763  if(filler == WILDCARD && (result.base == NOT.base ||
764  result.base == STAR.base)) {
765 
766  result.overlay = NO_LAYER;
767  }
768  }
769 
770  return result;
771 }
772 
773 static std::string number_to_string_(terrain_code terrain, const std::string& start_position)
774 {
775  std::string result = "";
776 
777  // Insert the start position
778  if(!start_position.empty()) {
779  result = start_position + " ";
780  }
781 
782  /*
783  * The initialization of tcode is done to make gcc-4.7 happy. Otherwise it
784  * some uninitialized fields might be used. Its analysis are wrong, but
785  * Initialize to keep it happy.
786  */
787  unsigned char tcode[9] {0};
788  // Insert the terrain tcode
789  tcode[0] = ((terrain.base & 0xFF000000) >> 24);
790  tcode[1] = ((terrain.base & 0x00FF0000) >> 16);
791  tcode[2] = ((terrain.base & 0x0000FF00) >> 8);
792  tcode[3] = (terrain.base & 0x000000FF);
793 
794  if(terrain.overlay != NO_LAYER) {
795  tcode[4] = '^'; //the layer separator
796  tcode[5] = ((terrain.overlay & 0xFF000000) >> 24);
797  tcode[6] = ((terrain.overlay & 0x00FF0000) >> 16);
798  tcode[7] = ((terrain.overlay & 0x0000FF00) >> 8);
799  tcode[8] = (terrain.overlay & 0x000000FF);
800  } else {
801  // If no second layer, the second layer won't be written,
802  // so no need to initialize that part of the array
803  tcode[4] = 0;
804  }
805 
806  for(int i = 0; i < 9; ++i) {
807  if(tcode[i] != 0 && tcode[i] != 0xFF) {
808  result += tcode[i];
809  }
810  if(i == 4 && tcode[i] == 0) {
811  // no layer, stop
812  break;
813  }
814  }
815 
816  return result;
817 }
818 
820 {
821  // Strip the spaces around us
822  const std::string& whitespace = " \t";
823  str.erase(0, str.find_first_not_of(whitespace));
824  if(! str.empty()) {
825  str.erase(str.find_last_not_of(whitespace) + 1);
826  }
827 
828  // Empty string is allowed here, so handle it
829  if(str.empty()) {
830  return terrain_code();
831  }
832 
833  const int number = lexical_cast_default(str, -1);
834  if(number == -1) {
835  // At this point we have a single char
836  // which should be interpreted by the
837  // map builder, so return this number
838  return terrain_code(str[0] << 24, 0);
839  } else {
840  return terrain_code(0, number);
841  }
842 }
843 
844 } // end namespace t_translation
845 
846 #if 0
847 // small helper rule to test the matching rules
848 // building rule
849 // make terrain_translation.o && g++ terrain_translation.o libwesnoth-core.a -lSDL -o terrain_translation
850 int main(int argc, char** argv)
851 {
852  if(argc > 1) {
853 
854  if(std::string(argv[1]) == "match" && argc == 4) {
856 
857  t_translation::ter_list dest = t_translation::read_list(std::string(argv[3]));
858 
859  if(t_translation::terrain_matches(src, dest)) {
860  std::cout << "Match\n" ;
861  } else {
862  std::cout << "No match\n";
863  }
864  }
865  }
866 }
867 
868 #endif
#define ERR_G
Definition: translation.cpp:30
const terrain_code CAVE
BOOST_CXX14_CONSTEXPR size_type find(basic_string_view s, size_type pos=0) const BOOST_NOEXCEPT
BOOST_CXX14_CONSTEXPR size_type find_last_not_of(basic_string_view s, size_type pos=npos) const BOOST_NOEXCEPT
const terrain_code FOREST
int dummy
Definition: lstrlib.cpp:1125
static ter_layer string_to_layer_(const char *begin, const char *end)
boost::bimaps::bimap< boost::bimaps::set_of< std::string >, boost::bimaps::multiset_of< coordinate > > starting_positions
const terrain_code DWARVEN_KEEP
Add a special kind of assert to validate whether the input from WML doesn&#39;t contain any problems that...
bool terrain_matches(const terrain_code &src, const terrain_code &dest)
Tests whether a specific terrain matches an expression, for matching rules see above.
static l_noret error(LoadState *S, const char *why)
Definition: lundump.cpp:39
New lexcical_cast header.
#define a
ter_map read_game_map(utils::string_view str, starting_positions &starting_positions, coordinate border_offset)
Reads a gamemap string into a 2D vector.
BOOST_CXX14_CONSTEXPR void remove_prefix(size_type n)
To lexical_cast_default(From value, To fallback=To())
Lexical cast converts one type to another with a fallback.
uint32_t ter_layer
Definition: translation.hpp:39
BOOST_CXX14_CONSTEXPR basic_string_view substr(size_type pos, size_type n=npos) const
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
Definition: translation.hpp:50
const ter_layer NO_LAYER
Definition: translation.hpp:41
#define h
BOOST_CONSTEXPR size_type length() const BOOST_NOEXCEPT
const terrain_code HUMAN_KEEP
const terrain_code HILL
const ter_match ALL_MOUNTAINS("!,*^V*,!,M*")
const terrain_code VOID_TERRAIN
#define b
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:89
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:86
int max_map_size()
Return the maximum allowed map size (in either dimension), the maximum map area is, therefore, this value squared.
Definition: translation.cpp:35
const terrain_code MOUNTAIN
#define VALIDATE(cond, message)
The macro to use for the validation of WML.
const terrain_code FOGGED
const terrain_code STAR
const terrain_code DWARVEN_CASTLE
BOOST_CXX14_CONSTEXPR size_type find_first_not_of(basic_string_view s, size_type pos=0) const BOOST_NOEXCEPT
terrain_code read_terrain_code(utils::string_view str, const ter_layer filler)
Reads a single terrain from a string.
const terrain_code MINUS
const terrain_code PLUS
BOOST_CONSTEXPR bool empty() const BOOST_NOEXCEPT
const terrain_code NOT
#define WRN_G
Definition: translation.cpp:31
const ter_layer TB_DOT
static const ::config * terrain
The terrain used to create the cache.
Definition: minimap.cpp:130
const ter_match ALL_HILLS("!,*^V*,!,H*")
const terrain_code OFF_MAP_USER
static terrain_code string_to_builder_number_(std::string str)
Converts a terrain string to a number for the builder.
std::string write_terrain_code(const terrain_code &tcode)
Writes a single terrain code to a string.
const terrain_code HUMAN_CASTLE
BOOST_CONSTEXPR size_type size() const BOOST_NOEXCEPT
Encapsulates the map of the game.
Definition: location.hpp:42
static ter_layer get_layer_mask_(ter_layer terrain)
Get the mask for a single layer.
const terrain_code BASE
std::size_t i
Definition: function.cpp:933
const ter_match ALL_SWAMPS("!,*^V*,*^B*,!,S*")
int main()
ter_map read_builder_map(const std::string &str)
Reads a builder map.
static std::string number_to_string_(terrain_code terrain, const std::string &start_position="")
Converts a terrain number to a string.
std::string write_list(const ter_list &list)
Writes a list of terrains to a string, only writes the new format.
int w
static BOOST_CONSTEXPR_OR_CONST size_type npos
Definition: string_view.hpp:84
static std::pair< int, int > get_map_size(const char *begin, const char *end)
const terrain_code CAVE_WALL
bool has_wildcard(const terrain_code &tcode)
Tests whether a terrain code contains a wildcard.
bool isnewline(const char c)
std::string write_game_map(const ter_map &map, const starting_positions &starting_positions, coordinate border_offset)
Write a gamemap in to a vector string.
const terrain_code DEEP_WATER
const ter_match ALL_OFF_MAP
BOOST_CONSTEXPR const_reference front() const
const terrain_code UNDERGROUND_VILLAGE
ter_list read_list(utils::string_view str, const ter_layer filler)
Reads a list of terrains from a string, when reading the.
Standard logging facilities (interface).
std::vector< terrain_code > ter_list
Definition: translation.hpp:78
const ter_layer WILDCARD
Definition: translation.hpp:40
static terrain_code get_mask_(const terrain_code &terrain)
Gets a mask for a terrain, this mask is used for wildcard matching.
const terrain_code SHALLOW_WATER
BOOST_CXX14_CONSTEXPR size_type find_first_of(basic_string_view s, size_type pos=0) const BOOST_NOEXCEPT
map_location coordinate
Contains an x and y coordinate used for starting positions in maps.
mock_char c
This structure can be used for matching terrain strings.
const terrain_code GRASS_LAND
static terrain_code string_to_number_(utils::string_view, std::string &start_position, const ter_layer filler)
Converts a terrain string to a number.
const ter_match ALL_FORESTS