Scid  4.6.5
misc.h
Go to the documentation of this file.
1 
2 //////////////////////////////////////////////////////////////////////
3 //
4 // FILE: misc.h
5 // Miscellaneous routines (File I/O, etc)
6 //
7 // Part of: Scid (Shane's Chess Information Database)
8 // Version: 3.5
9 //
10 // Notice: Copyright (c) 2001-2003 Shane Hudson. All rights reserved.
11 // Copyright (C) 2015 Fulvio Benini
12 //
13 // Author: Shane Hudson (sgh@users.sourceforge.net)
14 //
15 //////////////////////////////////////////////////////////////////////
16 
17 
18 #ifndef SCID_MISC_H
19 #define SCID_MISC_H
20 
21 #include "common.h"
22 #include <string>
23 #include <cstring>
24 #include <stdio.h>
25 #include <ctype.h> // For isspace(), etc
26 #include <cstdlib>
27 #include <vector>
28 
29 /**
30  * class StrRange - parse a string interpreting its content as 1 or 2 integers
31  * separated by whitespace.
32  * The integers represent the min and max value of a range.
33  * If only one integer is provided it will represent both the min and max value.
34  *
35  * inRange() : Return true if @val is >= min and <= max
36  */
37 class StrRange {
38 protected:
39  long min_;
40  long max_;
41 
42 protected:
44  : min_(0), max_(0) {}
45 
46 public:
47  explicit StrRange(const char* range) {
48  char* next;
49  min_ = std::strtol(range, &next, 10);
50  char* end;
51  max_ = std::strtol(next, &end, 10);
52  if (next == end) max_ = min_;
53  if (min_ > max_) std::swap(min_, max_);
54  }
55 
56  bool inRange(long val) const {
57  if (val < min_ || val > max_) return false;
58  return true;
59  }
60 };
61 
62 
63 /**
64  * class VectorBig - store data into chunks to avoid (or minimize) reallocations
65  * @CHUNKSHIFT: is the base-2 logarithm of the number of T entries per chunk.
66  * Total size of a chunk: (2^CHUNKSHIFT)*sizeof(T)
67  * resize() : Used to avoid reallocations.
68  * Very efficient because it allocates space only for chunk pointers
69  * i.e with @count==16777214 and @CHUNKSHIFT==16 will use 256 pointers
70  */
71 template <class T, size_t CHUNKSHIFT>
72 class VectorBig {
73  std::vector<T*> index_;
74  size_t size_;
75 
76 public:
77  VectorBig() : size_(0) {}
78  VectorBig(const VectorBig&);
79  VectorBig& operator=(const VectorBig&);
80  ~VectorBig() { resize(0); }
81 
82  const T& operator[] (size_t idx) const {
83  const size_t low_mask = ((1 << CHUNKSHIFT) - 1);
84  return index_[idx >> CHUNKSHIFT][idx & low_mask];
85  }
86  T& operator[] (size_t idx) {
87  const size_t low_mask = ((1 << CHUNKSHIFT) - 1);
88  return index_[idx >> CHUNKSHIFT][idx & low_mask];
89  }
90 
91  size_t size() const {
92  return size_;
93  }
94 
95  void reserve(size_t count) {
96  index_.reserve(1 + (count >> CHUNKSHIFT));
97  }
98 
99  void resize(size_t count) {
100  size_ = count;
101  size_t index_NewSize = (count > 0) ? 1 + (count >> CHUNKSHIFT) : 0;
102 
103  while (index_.size() > index_NewSize) {
104  delete [] index_.back();
105  index_.pop_back();
106  }
107  while (index_.size() < index_NewSize) {
108  index_.push_back(new T[1 << CHUNKSHIFT]);
109  }
110  }
111  void resize(size_t count, const T& defaulVal) {
112  size_t i = size_;
113  resize(count);
114  while (i < count) (*this)[i++] = defaulVal;
115  }
116 
117  void push_back(const T& e) {
118  resize(size_ + 1, e);
119  }
120 };
121 
122 
123 
124 class Progress {
125 public:
126  struct Impl {
127  virtual ~Impl() {}
128  virtual bool report(size_t done, size_t total, const char* msg) = 0;
129  };
130 
131  Progress(Impl* f = NULL) : f_(f) {}
132  Progress(const Progress&);
133  Progress& operator=(const Progress&);
134  ~Progress() { delete f_; }
135 
136  bool report(size_t done, size_t total) const {
137  return operator()(done, total);
138  }
139  bool operator()(size_t done, size_t total, const char* msg = NULL) const {
140  if (f_) return f_->report(done, total, msg);
141  return true;
142  }
143 
144 private:
145  Impl* f_;
146 };
147 
148 
149 #if CPP11_SUPPORT
150 using std::to_string;
151 #else
152 #include <sstream>
153 inline std::string to_string(int val) {
154  std::ostringstream res;
155  res << std::dec << val;
156  return res.str();
157 }
158 #endif
159 
160 
161 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
162 // strGetFilterOp:
163 // Converts a string value to a filter operation value.
165 
166 inline filterOpT strGetFilterOp (const char * str)
167 {
168  switch (*str) {
169  // AND:
170  case 'A': case 'a': case '0': return FILTEROP_AND;
171  // OR:
172  case 'O': case 'o': case '1': return FILTEROP_OR;
173  // RESET:
174  case 'R': case 'r': case '2': return FILTEROP_RESET;
175  }
176  // Default is RESET.
177  return FILTEROP_RESET;
178 }
179 
180 // ECO string routines
181 //
182 void eco_ToString (ecoT ecoCode, char * ecoStr, bool extensions = true);
183 inline void eco_ToBasicString (ecoT ecoCode, char * ecoStr) {
184  eco_ToString (ecoCode, ecoStr, false);
185 }
186 inline void eco_ToExtendedString (ecoT ecoCode, char * ecoStr) {
187  eco_ToString (ecoCode, ecoStr, true);
188 }
189 ecoT eco_FromString (const char * ecoStr);
190 ecoT eco_LastSubCode (ecoT ecoCode);
191 ecoT eco_BasicCode (ecoT ecoCode);
192 ecoT eco_Reduce(ecoT eco);
193 
194 // String routines. Some are identical to ANSI standard functions, but
195 // I have included them:
196 // (a) to keep nice consistent naming conventions, e.g. strCopy.
197 // (b) so stats can easily be kept by modifying the functions.
198 // (c) so some can be made inline for speed if necessary.
199 
200 inline uint32_t strStartHash(const char* str) {
201  ASSERT(str != 0);
202  const unsigned char* s = reinterpret_cast<const unsigned char*>(str);
203 
204  uint32_t tmp = static_cast<unsigned char>(tolower(*s));
205  uint32_t result = tmp << 24;
206  if (*s == '\0') return result;
207  tmp = static_cast<unsigned char>(tolower(*++s));
208  result += tmp << 16;
209  if (*s == '\0') return result;
210  tmp = static_cast<unsigned char>(tolower(*++s));
211  result += tmp << 8;
212  if (*s == '\0') return result;
213  result += static_cast<unsigned char>(tolower(*++s));
214  return result;
215 }
216 
217 char * strDuplicate (const char * str);
218 
219 void strCopyExclude (char * target, const char * original,
220  const char * excludeChars);
221 char * strAppend (char * target, const char * extra);
222 uint strPad (char * target, const char * orig, int length, char pad);
223 const char * strFirstChar (const char * target, char matchChar);
224 const char * strLastChar (const char * target, char matchChar);
225 void strStrip (char * str, char ch);
226 
227 static const char WHITESPACE[6] = " \t\r\n";
228 const char * strTrimLeft (const char * target, const char * trimChars);
229 inline const char * strTrimLeft (const char * target) {
230  return strTrimLeft (target, WHITESPACE);
231 }
232 uint strTrimRight (char * target, const char * trimChars);
233 inline uint strTrimRight (char * target) {
234  return strTrimRight (target, WHITESPACE);
235 }
236 uint strTrimSuffix (char * target, char suffixChar);
237 void strTrimDate (char * str);
238 void strTrimMarkCodes (char * str);
239 void strTrimMarkup (char * str);
240 void strTrimSurname (char * str, uint initials);
241 inline void strTrimSurname (char * str) { strTrimSurname (str, 0); }
242 const char * strFirstWord (const char * str);
243 const char * strNextWord (const char * str);
244 
245 // strPlural:
246 // Returns the empty string if its parameter is 1, or "s" otherwise.
247 inline const char *
249  return (x == 1 ? "" : "s");
250 }
251 
252 bool strIsAllWhitespace (const char * str);
253 bool strIsUnknownName (const char * str);
254 
255 // strIsSurnameOnly: returns true if a string appears to only
256 // contain a surname.
257 bool strIsSurnameOnly (const char * name);
258 
259 bool strGetBoolean (const char * str);
260 
261 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
262 // strGetInteger():
263 // Extracts a signed base-10 value from a string.
264 // Defaults to zero (as strtol does) for non-numeric strings.
265 inline int
266 strGetInteger(const char * str)
267 {
268  return std::strtol(str, NULL, 10);
269 }
270 
271 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
272 // strGetUnsigned():
273 // Extracts an unsigned base-10 value from a string.
274 // Defaults to zero (as strtoul does) for non-numeric strings.
275 //
276 inline uint32_t strGetUnsigned(const char* str) {
277  ASSERT(str != NULL);
278  return static_cast<uint32_t>(std::strtoul(str, NULL, 10));
279 }
280 
281 inline int strCaseCompare(const char* str1, const char* str2) {
282  ASSERT(str1 != NULL && str2 != NULL);
283  const unsigned char* s1 = reinterpret_cast<const unsigned char*>(str1);
284  const unsigned char* s2 = reinterpret_cast<const unsigned char*>(str2);
285  int c1, c2;
286  do {
287  c1 = tolower(*s1++);
288  c2 = tolower(*s2++);
289  if (c1 == '\0')
290  break;
291  } while (c1 == c2);
292 
293  return c1 - c2;
294 }
295 
296 inline int strCompareRound(const char* str1, const char* str2) {
297  ASSERT(str1 != NULL && str2 != NULL);
298  uint32_t a = strGetUnsigned(str1);
299  uint32_t b = strGetUnsigned(str2);
300  if (a == b)
301  return strCaseCompare(str1, str2);
302  return (a < b) ? -1 : 1;
303 }
304 
305 inline bool strEqual(const char* str1, const char* str2) {
306  ASSERT(str1 != NULL && str2 != NULL);
307  return (std::strcmp(str1, str2) == 0);
308 }
309 
310 void strGetIntegers (const char * str, int * results, uint nResults);
311 void strGetUnsigneds (const char * str, uint * results, uint nResults);
312 resultT strGetResult (const char * str);
313 
314 typedef uint flagT;
315 const flagT FLAG_EMPTY = 0;
316 const flagT FLAG_YES = 1;
317 const flagT FLAG_NO = 2;
318 const flagT FLAG_BOTH = 3;
319 inline bool flag_Yes (flagT t) { return (t & FLAG_YES); }
320 inline bool flag_No (flagT t) { return (t & FLAG_NO); }
321 flagT strGetFlag (const char * str);
322 
323 squareT strGetSquare (const char * str);
324 
325 inline uint
326 strTrimFileSuffix (char * target) { return strTrimSuffix (target, '.'); }
327 
328 inline const char *
329 strFileSuffix (const char * target) { return strLastChar (target, '.'); }
330 
331 
332 
333 int strUniqueExactMatch (const char * keyStr, const char ** strTable,
334  bool exact);
335 
336 inline int strUniqueMatch (const char * keyStr, const char ** strTable) {
337  return strUniqueExactMatch (keyStr, strTable, false);
338 }
339 inline int strExactMatch (const char * keyStr, const char ** strTable) {
340  return strUniqueExactMatch (keyStr, strTable, true);
341 }
342 
343 inline bool
344 strContainsChar (const char * str, char ch)
345 {
346  while (*str) {
347  if (*str == ch) { return true; }
348  str++;
349  }
350  return false;
351 }
352 
353 // WARNING: Avoid this function!
354 // Considering that the sign of a char is implementation-defined [3.9.1], the
355 // int conversion ("[4.7.3] If the destination type is signed, the value is
356 // unchanged if it can be represented in the destination type") can yield
357 // different results on different architectures or compilers.
358 // A better alternative is the standard function strcmp() that returns the
359 // difference between the values of the first pair of characters (both
360 // interpreted as unsigned char) that differ in the strings being compared.
361 inline int strCompare(const char* s1, const char* s2)
362 {
363  ASSERT (s1 != NULL && s2 != NULL);
364  while (1) {
365  if (*s1 != *s2) {
366  return ((int) *s1) - ((int) *s2);
367  }
368  if (*s1 == 0)
369  break;
370  s1++; s2++;
371  }
372  return 0;
373 }
374 
375 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
376 // strCopy(): same as strcpy().
377 //
378 inline void
379 strCopy (char * target, const char * original)
380 {
381  ASSERT (target != NULL && original != NULL);
382  while (*original != 0) {
383  *target = *original;
384  target++;
385  original++;
386  }
387  *target = 0;
388 }
389 
390 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
391 // strPrefix():
392 // Returns the length of the common prefix of two strings.
393 //
394 inline uint
395 strPrefix (const char * s1, const char * s2)
396 {
397  ASSERT (s1 != NULL && s2 != NULL);
398  uint count = 0;
399  while (*s1 == *s2) {
400  if (*s1 == 0) { // seen end of string, strings are identical
401  return count;
402  }
403  count++; s1++; s2++;
404  }
405  return count;
406 }
407 
408 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
409 // strIsPrefix():
410 // Returns true if the prefix string is a prefix of longStr.
411 inline bool
412 strIsPrefix (const char * prefix, const char * longStr)
413 {
414  while (*prefix) {
415  if (*longStr == 0) { return false; }
416  if (*prefix != *longStr) { return false; }
417  prefix++;
418  longStr++;
419  }
420  return true;
421 }
422 
423 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
424 // strIsCasePrefix():
425 // Returns true if the prefix string is a case-insensitive
426 // prefix of longStr.
427 inline bool
428 strIsCasePrefix (const char * prefix, const char * longStr)
429 {
430  typedef unsigned char U;
431  while (*prefix) {
432  if (*longStr == 0) { return false; }
433  if (tolower(U(*prefix)) != tolower(U(*longStr))) { return false; }
434  prefix++;
435  longStr++;
436  }
437  return true;
438 }
439 
440 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
441 // strIsAlphaPrefix():
442 // Returns true if the prefix string is a prefix of longStr.
443 // Unlike strIsPrexix(), this version is case-insensitive and
444 // spaces are ignored.
445 // Example: strIsAlphaPrefix ("smith,j", "Smith, John") == true.
446 inline bool
447 strIsAlphaPrefix (const char * prefix, const char * longStr)
448 {
449  typedef unsigned char U;
450  while (*prefix) {
451  while (*prefix == ' ') { prefix++; }
452  while (*longStr == ' ') { longStr++; }
453  if (*longStr == 0) { return false; }
454  if (tolower(U(*prefix)) != tolower(U(*longStr))) { return false; }
455  prefix++;
456  longStr++;
457  }
458  return true;
459 }
460 
461 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
462 // strContains():
463 // Returns true if longStr contains an occurrence of keyStr,
464 // case-sensitive and NOT ignoring any characters such as spaces.
465 inline bool
466 strContains (const char * longStr, const char * keyStr)
467 {
468  while (*longStr) {
469  if (strIsPrefix (keyStr, longStr)) { return true; }
470  longStr++;
471  }
472  return false;
473 }
474 
475 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
476 // strAlphaContains():
477 // Returns true if longStr contains an occurrence of keyStr,
478 // case-insensitive and ignoring spaces.
479 // Example: strAlphaContains ("Smith, John", "th,j") == true.
480 //
481 inline bool
482 strAlphaContains (const char * longStr, const char * keyStr)
483 {
484  while (*longStr) {
485  if (strIsAlphaPrefix (keyStr, longStr)) { return true; }
486  longStr++;
487  }
488  return false;
489 }
490 
491 inline uint
492 strLength (const char * str)
493 {
494  ASSERT(str != NULL);
495  uint len = 0;
496  while (*str != 0) { len++; str++; }
497  return len;
498 }
499 
500 
501 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
502 // strTrimRight():
503 // Trims the provided string in-place, removing the
504 // end characters that match the trimChars.
505 // Returns the number of characters trimmed.
506 // E.g., strTrimRight("abcyzyz", "yz") would leave the string
507 // as "abc" and return 4.
508 inline uint strTrimRight (char* target, const char* trimChars)
509 {
510  int oldSz = strlen(target);
511  int sz = oldSz;
512  while (--sz >= 0) {
513  if (std::strchr(trimChars, target[sz]) == 0) break;
514  }
515  if (++sz == oldSz) return 0;
516  target[sz] = 0;
517  return oldSz - sz;
518 }
519 
520 
521 //////////////////////////////////////////////////////////////////////
522 // FILE I/O Routines.
523 // TODO: remove this functions
524 
525 uint fileSize (const char * name, const char * suffix);
526 uint rawFileSize (const char * name);
527 uint gzipFileSize (const char * name);
528 
529 #endif // #ifdef SCID_MISC_H
530 
531 //////////////////////////////////////////////////////////////////////
532 // EOF: misc.h
533 //////////////////////////////////////////////////////////////////////
534 
resizew psize
Definition: board.tcl:647
byte resultT
Definition: common.h:183
bool report(size_t done, size_t total) const
Definition: misc.h:136
uint strLength(const char *str)
Definition: misc.h:492
int strExactMatch(const char *keyStr, const char **strTable)
Definition: misc.h:339
void resize(size_t count)
Definition: misc.h:99
Progress(Impl *f=NULL)
Definition: misc.h:131
uint32_t strStartHash(const char *str)
Definition: misc.h:200
bool strEqual(const char *str1, const char *str2)
Definition: misc.h:305
bool strIsPrefix(const char *prefix, const char *longStr)
Definition: misc.h:412
flagT strGetFlag(const char *str)
Definition: misc.cpp:666
uint strPad(char *target, const char *orig, int length, char pad)
Definition: misc.cpp:268
long min_
Definition: misc.h:39
int strUniqueExactMatch(const char *keyStr, const char **strTable, bool exact)
Definition: misc.cpp:718
#define ASSERT(f)
Definition: common.h:67
void resize(size_t count, const T &defaulVal)
Definition: misc.h:111
bool inRange(long val) const
Definition: misc.h:56
Definition: misc.h:124
names
Definition: tablebase.tcl:260
std::string to_string(int val)
Definition: misc.h:153
int strUniqueMatch(const char *keyStr, const char **strTable)
Definition: misc.h:336
class StrRange - parse a string interpreting its content as 1 or 2 integers separated by whitespace...
Definition: misc.h:37
char * strAppend(char *target, const char *extra)
Definition: misc.cpp:222
ecoT eco_FromString(const char *ecoStr)
Definition: misc.cpp:69
StrRange(const char *range)
Definition: misc.h:47
uint strPrefix(const char *s1, const char *s2)
Definition: misc.h:395
int strCompareRound(const char *str1, const char *str2)
Definition: misc.h:296
const char * strFileSuffix(const char *target)
Definition: misc.h:329
void push_back(const T &e)
Definition: misc.h:117
const flagT FLAG_BOTH
Definition: misc.h:318
const char * strFirstChar(const char *target, char matchChar)
Definition: misc.cpp:297
void strGetIntegers(const char *str, int *results, uint nResults)
Definition: misc.cpp:618
bool strIsAllWhitespace(const char *str)
Definition: misc.cpp:528
const char * strNextWord(const char *str)
Definition: misc.cpp:516
uint flagT
Definition: misc.h:314
bool flag_Yes(flagT t)
Definition: misc.h:319
void strGetUnsigneds(const char *str, uint *results, uint nResults)
Definition: misc.cpp:632
const flagT FLAG_NO
Definition: misc.h:317
ecoT eco_Reduce(ecoT eco)
ecoReduce() - maps eco to a smaller set : the eco value to convert (must be != 0) ...
Definition: misc.cpp:163
uint gzipFileSize(const char *name)
Definition: misc.cpp:796
~Progress()
Definition: misc.h:134
const char * strLastChar(const char *target, char matchChar)
Definition: misc.cpp:314
uint fileSize(const char *name, const char *suffix)
Definition: misc.cpp:764
filterOpT strGetFilterOp(const char *str)
Definition: misc.h:166
uint strTrimFileSuffix(char *target)
Definition: misc.h:326
uint rawFileSize(const char *name)
Definition: misc.cpp:781
uint strTrimRight(char *target, const char *trimChars)
Definition: misc.h:508
bool strIsCasePrefix(const char *prefix, const char *longStr)
Definition: misc.h:428
uint32_t uint
Definition: common.h:99
void reserve(size_t count)
Definition: misc.h:95
const char * strFirstWord(const char *str)
Definition: misc.cpp:503
void strTrimSurname(char *str, uint initials)
Definition: misc.cpp:472
void strStrip(char *str, char ch)
Definition: misc.cpp:329
VectorBig()
Definition: misc.h:77
filterOpT
Definition: misc.h:164
bool strAlphaContains(const char *longStr, const char *keyStr)
Definition: misc.h:482
ecoT eco_LastSubCode(ecoT ecoCode)
Definition: misc.cpp:176
void strTrimMarkup(char *str)
Definition: misc.cpp:448
int strGetInteger(const char *str)
Definition: misc.h:266
bool strContainsChar(const char *str, char ch)
Definition: misc.h:344
bool strGetBoolean(const char *str)
Definition: misc.cpp:579
bool strIsUnknownName(const char *str)
Definition: misc.cpp:544
ushort ecoT
Definition: common.h:161
char * strDuplicate(const char *str)
Definition: misc.cpp:239
virtual ~Impl()
Definition: misc.h:127
int strCaseCompare(const char *str1, const char *str2)
Definition: misc.h:281
void strCopyExclude(char *target, const char *original, const char *excludeChars)
Definition: misc.cpp:196
void eco_ToExtendedString(ecoT ecoCode, char *ecoStr)
Definition: misc.h:186
uint32_t strGetUnsigned(const char *str)
Definition: misc.h:276
StrRange()
Definition: misc.h:43
size_t size() const
Definition: misc.h:91
void strTrimDate(char *str)
Definition: misc.cpp:389
class VectorBig - store data into chunks to avoid (or minimize) reallocations : is the base-2 logarit...
Definition: misc.h:72
bool flag_No(flagT t)
Definition: misc.h:320
bool strContains(const char *longStr, const char *keyStr)
Definition: misc.h:466
void strCopy(char *target, const char *original)
Definition: misc.h:379
const flagT FLAG_EMPTY
Definition: misc.h:315
const flagT FLAG_YES
Definition: misc.h:316
bool operator()(size_t done, size_t total, const char *msg=NULL) const
Definition: misc.h:139
resultsreportType fmt
Definition: optable.tcl:642
resultT strGetResult(const char *str)
Definition: misc.cpp:645
const char * strPlural(uint x)
Definition: misc.h:248
squareT strGetSquare(const char *str)
Definition: misc.cpp:693
void strTrimMarkCodes(char *str)
Definition: misc.cpp:404
uint strTrimSuffix(char *target, char suffixChar)
Definition: misc.cpp:365
long max_
Definition: misc.h:40
void eco_ToBasicString(ecoT ecoCode, char *ecoStr)
Definition: misc.h:183
int strCompare(const char *s1, const char *s2)
Definition: misc.h:361
ecoT eco_BasicCode(ecoT ecoCode)
Definition: misc.cpp:143
const char * strTrimLeft(const char *target, const char *trimChars)
Definition: misc.cpp:347
bool strIsAlphaPrefix(const char *prefix, const char *longStr)
Definition: misc.h:447
byte squareT
Definition: common.h:113
bool strIsSurnameOnly(const char *name)
Definition: misc.cpp:556
~VectorBig()
Definition: misc.h:80
void eco_ToString(ecoT ecoCode, char *ecoStr, bool extensions=true)
Definition: misc.cpp:111