1 // _________ __ __
2 // / _____// |_____________ _/ |______ ____ __ __ ______
3 // \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
4 // / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
5 // /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
6 // \/ \/ \//_____/ \/
7 // ______________________ ______________________
8 // T H E W A R B E G I N S
9 // Stratagus - A free fantasy real time strategy game engine
10 //
11 /**@name util.cpp - General utilites. */
12 //
13 // (c) Copyright 1998-2019 by Lutz Sammer, Jimmy Salmon and Andrettin
14 //
15 // This program is free software; you can redistribute it and/or modify
16 // it under the terms of the GNU General Public License as published by
17 // the Free Software Foundation; only version 2 of the License.
18 //
19 // This program is distributed in the hope that it will be useful,
20 // but WITHOUT ANY WARRANTY; without even the implied warranty of
21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 // GNU General Public License for more details.
23 //
24 // You should have received a copy of the GNU General Public License
25 // along with this program; if not, write to the Free Software
26 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 // 02111-1307, USA.
28 //
29
30 #include "stratagus.h"
31
32 #include "util.h"
33
34 //Wyrmgus start
35 #include "network.h"
36 //Wyrmgus end
37
38 #include <boost/tokenizer.hpp>
39
40 #include <ctype.h>
41 #include <cctype>
42 #include <errno.h>
43 #include <map>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <stdarg.h>
47 //Wyrmgus start
48 #include <time.h>
49 //Wyrmgus end
50
51 #ifdef WIN32
52 #include <windows.h>
53 #endif
54
55 #ifdef USE_STACKTRACE
56 #include <stdexcept>
57 #include <stacktrace/call_stack.hpp>
58 #include <stacktrace/stack_exception.hpp>
59 #endif
60
61 #ifdef USE_X11
62 #include <X11/Xlib.h>
63 #include <X11/Xatom.h>
64 #endif
65
66 /*----------------------------------------------------------------------------
67 -- Random
68 ----------------------------------------------------------------------------*/
69
70 unsigned SyncRandSeed; /// sync random seed value.
71
72 /**
73 ** Inititalize sync rand seed.
74 */
InitSyncRand()75 void InitSyncRand()
76 {
77 if (!IsNetworkGame()) { //if isn't a network game, make the seed vary according to the date and time
78 time_t time_curr;
79 time(&time_curr);
80 SyncRandSeed = static_cast<unsigned>(time_curr);
81 } else {
82 SyncRandSeed = 0x87654321;
83 }
84 }
85
86 /**
87 ** Synchronized random number.
88 **
89 ** @note This random value must be same on all machines in network game.
90 ** Very simple random generations, enough for us.
91 */
SyncRand()92 int SyncRand()
93 {
94 int val;
95
96 val = SyncRandSeed >> 16;
97
98 SyncRandSeed = SyncRandSeed * (0x12345678 * 4 + 1) + 1;
99
100 return val;
101 }
102
103 /**
104 ** Synchronized random number.
105 **
106 ** @param max Max value of random number to return
107 */
SyncRand(int max)108 int SyncRand(int max)
109 {
110 return SyncRand() % max;
111 }
112
113
114
MyRand()115 int MyRand()
116 {
117 return rand();
118 }
119
120 /*----------------------------------------------------------------------------
121 -- Math
122 ----------------------------------------------------------------------------*/
123
124 /**
125 ** Compute a square root using ints
126 **
127 ** Uses John Halleck's method, see
128 ** http://www.cc.utah.edu/~nahaj/factoring/isqrt.legalize.c.html
129 **
130 ** @param num Calculate the square root of this number
131 **
132 ** @return The integer square root.
133 */
isqrt(long num)134 long isqrt(long num)
135 {
136 long squaredbit;
137 long remainder;
138 long root;
139
140 if (num < 1) {
141 return 0;
142 }
143
144 //
145 // Load the binary constant 01 00 00 ... 00, where the number
146 // of zero bits to the right of the single one bit
147 // is even, and the one bit is as far left as is consistent
148 // with that condition.)
149 //
150 // This portable load replaces the loop that used to be
151 // here, and was donated by legalize@xmission.com
152 //
153 squaredbit = (long)((((unsigned long)~0L) >> 1) & ~(((unsigned long)~0L) >> 2));
154
155 // Form bits of the answer.
156 remainder = num;
157 root = 0;
158 while (squaredbit > 0) {
159 if (remainder >= (squaredbit | root)) {
160 remainder -= (squaredbit | root);
161 root >>= 1;
162 root |= squaredbit;
163 } else {
164 root >>= 1;
165 }
166 squaredbit >>= 2;
167 }
168
169 return root;
170 }
171
172
173 /*----------------------------------------------------------------------------
174 -- Strings
175 ----------------------------------------------------------------------------*/
176
177 #ifndef HAVE_STRCPYS
strcpy_s(char * dst,size_t dstsize,const char * src)178 errno_t strcpy_s(char *dst, size_t dstsize, const char *src)
179 {
180 if (dst == nullptr || src == nullptr) {
181 return EINVAL;
182 }
183 if (strlen(src) >= dstsize) {
184 return ERANGE;
185 }
186 strcpy(dst, src);
187 return 0;
188 }
189 #endif
190
191 #ifndef HAVE_STRNLEN
strnlen(const char * str,size_t strsize)192 size_t strnlen(const char *str, size_t strsize)
193 {
194 size_t len = 0;
195 while (len < strsize) {
196 if (*str == '\0') {
197 break;
198 }
199 ++str;
200 ++len;
201 }
202 return len;
203 }
204 #endif
205
206 #ifndef HAVE_STRNCPYS
strncpy_s(char * dst,size_t dstsize,const char * src,size_t count)207 errno_t strncpy_s(char *dst, size_t dstsize, const char *src, size_t count)
208 {
209 if (dst == nullptr || src == nullptr || dstsize == 0) {
210 return EINVAL;
211 }
212
213 size_t mincount;
214 if (count == _TRUNCATE) {
215 mincount = strnlen(src, dstsize);
216 } else {
217 mincount = strnlen(src, count);
218 }
219 if (mincount >= dstsize) {
220 if (count != _TRUNCATE) {
221 dst[0] = '\0';
222 return EINVAL;
223 } else {
224 mincount = dstsize - 1;
225 }
226 }
227 for (size_t i = 0; i < mincount; ++i) {
228 *dst++ = *src++;
229 }
230 *dst = '\0';
231 return 0;
232 }
233 #endif
234
235 #ifndef HAVE_STRCATS
strcat_s(char * dst,size_t dstsize,const char * src)236 errno_t strcat_s(char *dst, size_t dstsize, const char *src)
237 {
238 if (dst == nullptr || src == nullptr) {
239 return EINVAL;
240 }
241 char *enddst = dst;
242 size_t count = dstsize;
243 while (count > 0 && *enddst != '\0') {
244 ++enddst;
245 count--;
246 }
247 if (count == 0) {
248 return EINVAL;
249 }
250 if (strlen(src) >= count) {
251 return ERANGE;
252 }
253 strcpy(enddst, src);
254 return 0;
255 }
256 #endif
257
258 #if !defined(HAVE_STRCASESTR)
259 /**
260 ** Case insensitive version of strstr
261 **
262 ** @param a String to search in
263 ** @param b Substring to search for
264 **
265 ** @return Pointer to first occurrence of b or null if not found.
266 */
strcasestr(const char * a,const char * b)267 char *strcasestr(const char *a, const char *b)
268 {
269 int x;
270
271 if (!a || !*a || !b || !*b || strlen(a) < strlen(b)) {
272 return nullptr;
273 }
274
275 x = 0;
276 while (*a) {
277 if (a[x] && (tolower(a[x]) == tolower(b[x]))) {
278 ++x;
279 } else if (b[x]) {
280 ++a;
281 x = 0;
282 } else {
283 return (char *)a;
284 }
285 }
286
287 return nullptr;
288 }
289 #endif // !HAVE_STRCASESTR
290
SplitString(const std::string & str,const char * separators)291 std::vector<std::string> SplitString(const std::string &str, const char *separators)
292 {
293 std::vector<std::string> output;
294
295 boost::char_separator<char> separator(separators);
296
297 boost::tokenizer<boost::char_separator<char>> tokens(str, separator);
298
299 for (boost::tokenizer<boost::char_separator<char>>::iterator iterator = tokens.begin(); iterator != tokens.end(); ++iterator) {
300 output.push_back(*iterator);
301 }
302
303 return output;
304 }
305
StringToBool(const std::string & str)306 bool StringToBool(const std::string &str)
307 {
308 return str == "true" || str == "1";
309 }
310
IsStringNumber(const std::string & str)311 bool IsStringNumber(const std::string &str)
312 {
313 for (size_t i = 0; i < str.length(); ++i) {
314 if (!std::isdigit(str[i]) && (i != 0 || str[i] != '-')) {
315 return false;
316 }
317 }
318
319 return true;
320 }
321
IsStringBool(const std::string & str)322 bool IsStringBool(const std::string &str)
323 {
324 return str == "true" || str == "false";
325 }
326
327 static std::map<unsigned, std::string> RomanConversionTable = {{1000, "M"}, {900, "CM"}, {500, "D"}, {400, "CD"}, {100, "C"}, {90, "XC"}, {50, "L"}, {40, "XL"}, {10, "X"}, {9, "IX"}, {5, "V"}, {4, "IV"}, {1, "I"}};
328
NumberToRomanNumeral(unsigned number)329 std::string NumberToRomanNumeral(unsigned number)
330 {
331 std::string numeral;
332
333 for (std::map<unsigned, std::string>::const_reverse_iterator iterator = RomanConversionTable.rbegin(); iterator != RomanConversionTable.rend(); ++iterator) {
334 while (number >= iterator->first) {
335 numeral += iterator->second;
336 number -= iterator->first;
337 }
338 }
339
340 return numeral;
341 }
342
343 /**
344 ** @brief Format a number using commas
345 **
346 ** @param number Number to be formatted
347 **
348 ** @return The formatted number as a string
349 */
FormatNumber(const int number)350 std::string FormatNumber(const int number)
351 {
352 std::string str;
353 const char sep = ',';
354 int n = abs(number);
355
356 int loop = 0;
357 while (n > 0 || loop == 0) {
358 if (loop > 0 && loop % 3 == 0) {
359 str.insert(0, 1, sep);
360 }
361 const char c = n % 10 + 48;
362 str.insert(0, 1, c);
363 n /= 10;
364 loop++;
365 }
366
367 if (number < 0) {
368 str.insert(0, 1, '-');
369 }
370
371 return str;
372 }
373
SnakeCaseToPascalCase(const std::string & str)374 std::string SnakeCaseToPascalCase(const std::string &str)
375 {
376 if (str.empty()) {
377 return str;
378 }
379
380 std::string result(str);
381
382 result[0] = toupper(result[0]);
383
384 size_t pos = 0;
385 while ((pos = result.find('_', pos)) != std::string::npos) {
386 result.replace(pos, 1, "");
387 if (pos < result.length()) {
388 result[pos] = toupper(result[pos]);
389 }
390 }
391
392 return result;
393 }
394
395 /*----------------------------------------------------------------------------
396 -- Getopt
397 ----------------------------------------------------------------------------*/
398
399 #ifndef HAVE_GETOPT
400
401 /**
402 ** Standard implementation of getopt(3).
403 **
404 ** One extension: If the first character of the optionsstring is a ':'
405 ** the error return for 'argument required' is a ':' not a '?'.
406 ** This makes it easier to differentiate between an 'illegal option' and
407 ** an 'argument required' error.
408 */
409
410 #include <string.h>
411
412 int opterr = 1;
413 int optind = 1;
414 int optopt;
415 char *optarg;
416
getopt_err(const char * argv0,const char * str,char opt)417 static void getopt_err(const char *argv0, const char *str, char opt)
418 {
419 if (opterr) {
420 const char *x;
421
422 while ((x = strchr(argv0, '/'))) {
423 argv0 = x + 1;
424 }
425
426 fprintf(stderr, "%s%s%c\n", argv0, str, opt);
427 }
428 }
429
getopt(int argc,char * const * argv,const char * opts)430 int getopt(int argc, char *const *argv, const char *opts)
431 {
432 static int sp = 1;
433 register int c;
434 register const char *cp;
435
436 optarg = nullptr;
437
438 if (sp == 1) {
439 if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0') {
440 return EOF;
441 } else if (!strcmp(argv[optind], "--")) {
442 optind++;
443 return EOF;
444 }
445 }
446 optopt = c = argv[optind][sp];
447 if (c == ':' || (cp = strchr(opts, c)) == nullptr) {
448 getopt_err(argv[0], ": illegal option -", (char)c);
449 cp = "xx"; /* make the next if false */
450 c = '?';
451 }
452 if (*++cp == ':') {
453 if (argv[optind][++sp] != '\0') {
454 optarg = &argv[optind++][sp];
455 } else if (++optind < argc) {
456 optarg = argv[optind++];
457 } else {
458 getopt_err(argv[0], ": option requires an argument -", (char)c);
459 c = (*opts == ':') ? ':' : '?';
460 }
461 sp = 1;
462 } else if (argv[optind][++sp] == '\0') {
463 optind++;
464 sp = 1;
465 }
466 return c;
467 }
468
469 #endif
470
471
472 /*----------------------------------------------------------------------------
473 -- Clipboard
474 ----------------------------------------------------------------------------*/
475
476 /**
477 ** Paste text from the clipboard
478 */
GetClipboard(std::string & str)479 int GetClipboard(std::string &str)
480 {
481 #if defined(USE_WIN32) || defined(USE_X11)
482 int i;
483 unsigned char *clipboard;
484 #ifdef USE_WIN32
485 HGLOBAL handle;
486 #elif defined(USE_X11)
487 Display *display;
488 Window window;
489 Atom rettype;
490 unsigned long nitem;
491 unsigned long dummy;
492 int retform;
493 XEvent event;
494 #endif
495
496 #ifdef USE_WIN32
497 if (!IsClipboardFormatAvailable(CF_TEXT) || !OpenClipboard(nullptr)) {
498 return -1;
499 }
500 handle = GetClipboardData(CF_TEXT);
501 if (!handle) {
502 CloseClipboard();
503 return -1;
504 }
505 clipboard = (unsigned char *)GlobalLock(handle);
506 if (!clipboard) {
507 CloseClipboard();
508 return -1;
509 }
510 #elif defined(USE_X11)
511 if (!(display = XOpenDisplay(nullptr))) {
512 return -1;
513 }
514
515 // Creates a non maped temporary X window to hold the selection
516 if (!(window = XCreateSimpleWindow(display,
517 DefaultRootWindow(display), 0, 0, 1, 1, 0, 0, 0))) {
518 XCloseDisplay(display);
519 return -1;
520 }
521
522 XConvertSelection(display, XA_PRIMARY, XA_STRING, XA_STRING,
523 window, CurrentTime);
524
525 XNextEvent(display, &event);
526
527 if (event.type != SelectionNotify || event.xselection.property != XA_STRING) {
528 return -1;
529 }
530
531 XGetWindowProperty(display, window, XA_STRING, 0, 1024, False,
532 XA_STRING, &rettype, &retform, &nitem, &dummy, &clipboard);
533
534 XDestroyWindow(display, window);
535 XCloseDisplay(display);
536
537 if (rettype != XA_STRING || retform != 8) {
538 if (clipboard != nullptr) {
539 XFree(clipboard);
540 }
541 clipboard = nullptr;
542 }
543
544 if (clipboard == nullptr) {
545 return -1;
546 }
547 #endif
548 // Only allow ascii characters
549 for (i = 0; clipboard[i] != '\0'; ++i) {
550 if (clipboard[i] < 32 || clipboard[i] > 126) {
551 return -1;
552 }
553 }
554 str = (char *)clipboard;
555 #ifdef USE_WIN32
556 GlobalUnlock(handle);
557 CloseClipboard();
558 #elif defined(USE_X11)
559 if (clipboard != nullptr) {
560 XFree(clipboard);
561 }
562 #endif
563 return 0;
564 #else
565 return -1;
566 #endif
567 }
568
569
570 /*----------------------------------------------------------------------------
571 -- UTF8
572 ----------------------------------------------------------------------------*/
573
UTF8GetPrev(const std::string & text,int curpos)574 int UTF8GetPrev(const std::string &text, int curpos)
575 {
576 --curpos;
577 if (curpos < 0) {
578 return curpos;
579 }
580 while (curpos >= 0) {
581 if ((text[curpos] & 0xC0) != 0x80) {
582 return curpos;
583 }
584 --curpos;
585 }
586 if (curpos < 0) {
587 fprintf(stderr, "Invalid UTF8.\n");
588 }
589 return 0;
590 }
591
UTF8GetNext(const std::string & text,int curpos)592 int UTF8GetNext(const std::string &text, int curpos)
593 {
594 if (curpos == (int)text.size()) {
595 return curpos + 1;
596 }
597 char c = text[curpos];
598 if (!(c & 0x80)) {
599 return curpos + 1;
600 }
601 if ((c & 0xE0) == 0xC0) {
602 return curpos + 2;
603 }
604 if ((c & 0xF0) == 0xE0) {
605 return curpos + 3;
606 }
607 fprintf(stderr, "Invalid UTF8.\n");
608 return text.size();
609 }
610
611
612 /*----------------------------------------------------------------------------
613 -- others
614 ----------------------------------------------------------------------------*/
615
PrintLocation(const char * file,int line,const char * funcName)616 void PrintLocation(const char *file, int line, const char *funcName)
617 {
618 fprintf(stdout, "%s:%d: %s: ", file, line, funcName);
619 }
620
AbortAt(const char * file,int line,const char * funcName,const char * conditionStr)621 void AbortAt(const char *file, int line, const char *funcName, const char *conditionStr)
622 {
623 char buf[1024];
624 snprintf(buf, 1024, "Assertion failed at %s:%d: %s: %s\n", file, line, funcName, conditionStr);
625 #ifdef USE_STACKTRACE
626 throw stacktrace::stack_runtime_error((const char*)buf);
627 #else
628 fprintf(stderr, "%s\n", buf);
629 #endif
630 fflush(stdout);
631 fflush(stderr);
632 abort();
633 }
634
PrintOnStdOut(const char * format,...)635 void PrintOnStdOut(const char *format, ...)
636 {
637 va_list valist;
638 va_start(valist, format);
639 vprintf(format, valist);
640 va_end(valist);
641 fflush(stdout);
642 }
643
644 //Wyrmgus start
645 #include "character.h" //for personal name generation
646 #include "iocompat.h" //for getting a file's last modified date
647 #include "iolib.h" //for getting a file's last modified date
648 #include "player.h" //for personal name generation
649 #include "unit/unittype.h" //for personal name generation
650 #include "upgrade/upgrade.h" //for personal name generation
651
FindAndReplaceString(const std::string & text,const std::string & find,const std::string & replace)652 std::string FindAndReplaceString(const std::string &text, const std::string &find, const std::string &replace)
653 {
654 std::string result(text);
655
656 size_t pos = 0;
657 while ((pos = result.find(find, pos)) != std::string::npos) {
658 result.replace(pos, find.length(), replace);
659 pos += replace.length();
660 }
661
662 return result;
663 }
664
FindAndReplaceStringEnding(const std::string & text,const std::string & find,const std::string & replace)665 std::string FindAndReplaceStringEnding(const std::string &text, const std::string &find, const std::string &replace)
666 {
667 std::string result(text);
668
669 size_t pos = text.find(find, text.length() - find.length());
670 if (pos != std::string::npos) {
671 result.replace(pos, find.length(), replace);
672 }
673
674 return result;
675 }
676
FindAndReplaceStringBeginning(const std::string & text,const std::string & find,const std::string & replace)677 std::string FindAndReplaceStringBeginning(const std::string &text, const std::string &find, const std::string &replace)
678 {
679 std::string result(text);
680
681 size_t pos = text.find(find, 0);
682 if (pos != std::string::npos && pos == 0) {
683 result.replace(pos, find.length(), replace);
684 }
685
686 return result;
687 }
688
GetFileLastModified(const std::string & file_name)689 int GetFileLastModified(const std::string &file_name)
690 {
691 std::string library_file_name = LibraryFileName(file_name.c_str());
692
693 struct stat tmp;
694
695 stat(library_file_name.c_str(), &tmp);
696
697 int date = tmp.st_mtime;
698
699 return date;
700 }
701
TransliterateText(const std::string & text)702 std::string TransliterateText(const std::string &text) //convert special characters into ones more legible for English-speakers
703 {
704 std::string result(text);
705
706 result = FindAndReplaceString(result, "Ā́", "A");
707 result = FindAndReplaceString(result, "ā́", "a");
708 result = FindAndReplaceString(result, "Ā", "A");
709 result = FindAndReplaceString(result, "ā", "a");
710 result = FindAndReplaceString(result, "Ấ", "A");
711 result = FindAndReplaceString(result, "ấ", "a");
712 result = FindAndReplaceString(result, "Ȧ́", "A");
713 result = FindAndReplaceString(result, "ȧ́", "a");
714 result = FindAndReplaceString(result, "Á", "A");
715 result = FindAndReplaceString(result, "á", "a");
716 result = FindAndReplaceString(result, "À", "A");
717 result = FindAndReplaceString(result, "à", "a");
718 result = FindAndReplaceString(result, "Ã", "A");
719 result = FindAndReplaceString(result, "ã", "a");
720 result = FindAndReplaceString(result, "Ä", "A");
721 result = FindAndReplaceString(result, "ä", "a");
722 result = FindAndReplaceString(result, "Ā", "A");
723 result = FindAndReplaceString(result, "ā", "a");
724 result = FindAndReplaceString(result, "Â", "A");
725 result = FindAndReplaceString(result, "â", "a");
726 result = FindAndReplaceString(result, "Ą", "A");
727 result = FindAndReplaceString(result, "ą", "a");
728 result = FindAndReplaceString(result, "ᶏ", "a");
729 result = FindAndReplaceString(result, "Å", "A");
730 result = FindAndReplaceString(result, "å", "a");
731 result = FindAndReplaceString(result, "Ă", "A");
732 result = FindAndReplaceString(result, "ă", "a");
733 result = FindAndReplaceString(result, "Æ̂", "Ae");
734 result = FindAndReplaceString(result, "æ̂", "ae");
735 result = FindAndReplaceString(result, "Æ", "Ae");
736 result = FindAndReplaceString(result, "æ", "ae");
737 result = FindAndReplaceString(result, "Ǣ", "Ae");
738 result = FindAndReplaceString(result, "ǣ", "ae");
739 result = FindAndReplaceString(result, "Ǽ", "Ae");
740 result = FindAndReplaceString(result, "ǽ", "ae");
741 result = FindAndReplaceString(result, "Ƀ", "B");
742 result = FindAndReplaceString(result, "ƀ", "b");
743 result = FindAndReplaceString(result, "Č", "C");
744 result = FindAndReplaceString(result, "č", "c");
745 result = FindAndReplaceString(result, "Ð", "D");
746 result = FindAndReplaceString(result, "ð", "d");
747 result = FindAndReplaceString(result, "Ḍ", "D");
748 result = FindAndReplaceString(result, "ḍ", "d");
749 result = FindAndReplaceString(result, "Đ", "D");
750 result = FindAndReplaceString(result, "đ", "d");
751 result = FindAndReplaceString(result, "ẟ", "d"); //not the same character as "δ"
752 result = FindAndReplaceString(result, "Ę̄", "E");
753 result = FindAndReplaceString(result, "ę̄", "e");
754 result = FindAndReplaceString(result, "Ḗ", "E");
755 result = FindAndReplaceString(result, "ḗ", "e");
756 result = FindAndReplaceString(result, "Ė́", "E");
757 result = FindAndReplaceString(result, "ė́", "e");
758 result = FindAndReplaceString(result, "Ë̃", "E");
759 result = FindAndReplaceString(result, "ë̃", "e");
760 result = FindAndReplaceString(result, "Ë̂", "E");
761 result = FindAndReplaceString(result, "ë̂", "e");
762 result = FindAndReplaceString(result, "É", "E");
763 result = FindAndReplaceString(result, "é", "e");
764 result = FindAndReplaceString(result, "È", "E");
765 result = FindAndReplaceString(result, "è", "e");
766 result = FindAndReplaceString(result, "Ē", "E");
767 result = FindAndReplaceString(result, "ē", "e");
768 result = FindAndReplaceString(result, "Ê", "E");
769 result = FindAndReplaceString(result, "ê", "e");
770 result = FindAndReplaceString(result, "Ě", "E");
771 result = FindAndReplaceString(result, "ě", "e");
772 result = FindAndReplaceString(result, "Ė", "E");
773 result = FindAndReplaceString(result, "ė", "e");
774 result = FindAndReplaceString(result, "Ë", "E");
775 result = FindAndReplaceString(result, "ë", "e");
776 result = FindAndReplaceString(result, "Ę", "E");
777 result = FindAndReplaceString(result, "ę", "e");
778 result = FindAndReplaceString(result, "Ĕ", "E");
779 result = FindAndReplaceString(result, "ĕ", "e");
780 result = FindAndReplaceString(result, "Ə", "E");
781 result = FindAndReplaceString(result, "ə", "e");
782 result = FindAndReplaceString(result, "Ǝ", "E");
783 result = FindAndReplaceString(result, "ǝ", "e");
784 result = FindAndReplaceString(result, "ϵ", "e");
785 result = FindAndReplaceString(result, "Ĝ", "G");
786 result = FindAndReplaceString(result, "ĝ", "g");
787 result = FindAndReplaceString(result, "Ī̆", "I");
788 result = FindAndReplaceString(result, "ī̆", "i");
789 result = FindAndReplaceString(result, "Î́", "I");
790 result = FindAndReplaceString(result, "î́", "i");
791 result = FindAndReplaceString(result, "Ī́", "I");
792 result = FindAndReplaceString(result, "ī́", "i");
793 result = FindAndReplaceString(result, "Ī", "I");
794 result = FindAndReplaceString(result, "ī", "i");
795 result = FindAndReplaceString(result, "I̊", "I");
796 result = FindAndReplaceString(result, "i̊", "i");
797 result = FindAndReplaceString(result, "Í", "I");
798 result = FindAndReplaceString(result, "í", "i");
799 result = FindAndReplaceString(result, "Ì", "I");
800 result = FindAndReplaceString(result, "ì", "i");
801 result = FindAndReplaceString(result, "Ī", "I");
802 result = FindAndReplaceString(result, "ī", "i");
803 result = FindAndReplaceString(result, "Î", "I");
804 result = FindAndReplaceString(result, "î", "i");
805 result = FindAndReplaceString(result, "Ĭ", "I");
806 result = FindAndReplaceString(result, "ĭ", "i");
807 result = FindAndReplaceString(result, "Ĩ", "I");
808 result = FindAndReplaceString(result, "ĩ", "i");
809 result = FindAndReplaceString(result, "Ḱ", "K");
810 result = FindAndReplaceString(result, "ḱ", "k");
811 result = FindAndReplaceString(result, "L̥", "L");
812 result = FindAndReplaceString(result, "l̥", "l");
813 result = FindAndReplaceString(result, "Ɫ", "L");
814 result = FindAndReplaceString(result, "ɫ", "l");
815 result = FindAndReplaceString(result, "Ň", "N");
816 result = FindAndReplaceString(result, "ň", "n");
817 result = FindAndReplaceString(result, "Ṇ", "N");
818 result = FindAndReplaceString(result, "ṇ", "n");
819 result = FindAndReplaceString(result, "Ṅ", "N");
820 result = FindAndReplaceString(result, "ṅ", "n");
821 result = FindAndReplaceString(result, "Ṓ", "O");
822 result = FindAndReplaceString(result, "ṓ", "o");
823 result = FindAndReplaceString(result, "Ŏ", "O");
824 result = FindAndReplaceString(result, "ŏ", "o");
825 result = FindAndReplaceString(result, "Ø", "Ö"); //Source: Henry Adams Bellows (transl.), "The Poetic Edda", p. xxviii.
826 result = FindAndReplaceString(result, "ø", "ö"); //Source: Henry Adams Bellows (transl.), "The Poetic Edda", p. xxviii.
827 result = FindAndReplaceString(result, "Ǫ", "O"); //Source: Henry Adams Bellows (transl.), "The Poetic Edda", p. xxviii.
828 result = FindAndReplaceString(result, "ǫ", "o"); //Source: Henry Adams Bellows (transl.), "The Poetic Edda", p. xxviii.
829 result = FindAndReplaceString(result, "Ö", "O");
830 result = FindAndReplaceString(result, "ö", "o");
831 result = FindAndReplaceString(result, "Ó", "O");
832 result = FindAndReplaceString(result, "ó", "o");
833 result = FindAndReplaceString(result, "Ò", "O");
834 result = FindAndReplaceString(result, "ò", "o");
835 result = FindAndReplaceString(result, "Ō", "O");
836 result = FindAndReplaceString(result, "ō", "o");
837 result = FindAndReplaceString(result, "Ô", "O");
838 result = FindAndReplaceString(result, "ô", "o");
839 result = FindAndReplaceString(result, "Ǒ", "O");
840 result = FindAndReplaceString(result, "ǒ", "o");
841 result = FindAndReplaceString(result, "Œ", "Oe");
842 result = FindAndReplaceString(result, "œ", "oe");
843 result = FindAndReplaceString(result, "Ṛ́", "R");
844 result = FindAndReplaceString(result, "ṛ́", "r");
845 result = FindAndReplaceString(result, "Ŗ́", "R");
846 result = FindAndReplaceString(result, "ŗ́", "r");
847 result = FindAndReplaceString(result, "R̄", "R");
848 result = FindAndReplaceString(result, "r̄", "r");
849 result = FindAndReplaceString(result, "Ř", "R");
850 result = FindAndReplaceString(result, "ř", "r");
851 result = FindAndReplaceString(result, "Ṛ", "R");
852 result = FindAndReplaceString(result, "ṛ", "r");
853 result = FindAndReplaceString(result, "Ŕ", "R");
854 result = FindAndReplaceString(result, "ŕ", "r");
855 result = FindAndReplaceString(result, "Ṙ", "R");
856 result = FindAndReplaceString(result, "ṙ", "r");
857 result = FindAndReplaceString(result, "Š", "S");
858 result = FindAndReplaceString(result, "š", "s");
859 result = FindAndReplaceString(result, "Ș", "S");
860 result = FindAndReplaceString(result, "ș", "s");
861 result = FindAndReplaceString(result, "Ś", "S");
862 result = FindAndReplaceString(result, "ś", "s");
863 result = FindAndReplaceString(result, "ß", "ss"); //Source: Henry Adams Bellows (transl.), "The Poetic Edda", p. xxviii.
864 result = FindAndReplaceString(result, "Ṭ", "T");
865 result = FindAndReplaceString(result, "ṭ", "t");
866 result = FindAndReplaceString(result, "Ț", "T");
867 result = FindAndReplaceString(result, "ț", "t");
868 result = FindAndReplaceString(result, "ÞÞ", "Þ"); //replace double thorns with a single one
869 result = FindAndReplaceString(result, "þþ", "þ"); //replace double thorns with a single one
870 result = FindAndReplaceString(result, "Þ", "Th"); //Source: Henry Adams Bellows (transl.), "The Poetic Edda", p. xxviii.
871 result = FindAndReplaceString(result, "þ", "th"); //Source: Henry Adams Bellows (transl.), "The Poetic Edda", p. xxviii.
872 result = FindAndReplaceString(result, "Ū́", "U");
873 result = FindAndReplaceString(result, "ū́", "u");
874 result = FindAndReplaceString(result, "Ů̃", "U");
875 result = FindAndReplaceString(result, "ů̃", "u");
876 result = FindAndReplaceString(result, "Ü", "U");
877 result = FindAndReplaceString(result, "ü", "u");
878 result = FindAndReplaceString(result, "Ú", "U");
879 result = FindAndReplaceString(result, "ú", "u");
880 result = FindAndReplaceString(result, "Ù", "U");
881 result = FindAndReplaceString(result, "ù", "u");
882 result = FindAndReplaceString(result, "Ū", "U");
883 result = FindAndReplaceString(result, "ū", "u");
884 result = FindAndReplaceString(result, "Û", "U");
885 result = FindAndReplaceString(result, "û", "u");
886 result = FindAndReplaceString(result, "Ŭ", "U");
887 result = FindAndReplaceString(result, "ŭ", "u");
888 result = FindAndReplaceString(result, "Ů", "U");
889 result = FindAndReplaceString(result, "ů", "u");
890 result = FindAndReplaceString(result, "Ũ", "U");
891 result = FindAndReplaceString(result, "ũ", "u");
892 result = FindAndReplaceString(result, "Ṷ", "U");
893 result = FindAndReplaceString(result, "ṷ", "u");
894 result = FindAndReplaceString(result, "ʷ", "w");
895 result = FindAndReplaceString(result, "Ȳ", "Y");
896 result = FindAndReplaceString(result, "ȳ", "y");
897 result = FindAndReplaceString(result, "Ŷ", "Y");
898 result = FindAndReplaceString(result, "ŷ", "y");
899 result = FindAndReplaceString(result, "Ỹ", "Y");
900 result = FindAndReplaceString(result, "ỹ", "y");
901 result = FindAndReplaceString(result, "Ý", "Y");
902 result = FindAndReplaceString(result, "ý", "y");
903 result = FindAndReplaceString(result, "Ž", "Z");
904 result = FindAndReplaceString(result, "ž", "z");
905 result = FindAndReplaceString(result, "Z̨", "Z");
906 result = FindAndReplaceString(result, "z̨", "z");
907 result = FindAndReplaceString(result, "Ż", "Z");
908 result = FindAndReplaceString(result, "ż", "z");
909
910 result = FindAndReplaceString(result, "ʔ", "'"); // glottal stop
911
912 //replace endings in -r after consonants (which happens in the nominative for Old Norse); Source: Henry Adams Bellows (transl.), "The Poetic Edda", p. xxviii.
913 result = FindAndReplaceStringEnding(result, "dr", "d");
914 result = FindAndReplaceString(result, "dr ", "d ");
915 result = FindAndReplaceStringEnding(result, "fr", "f");
916 result = FindAndReplaceString(result, "fr ", "f ");
917 result = FindAndReplaceStringEnding(result, "gr", "g");
918 result = FindAndReplaceString(result, "gr ", "g ");
919 result = FindAndReplaceStringEnding(result, "kr", "k");
920 result = FindAndReplaceString(result, "kr ", "k ");
921 result = FindAndReplaceStringEnding(result, "mr", "m");
922 result = FindAndReplaceString(result, "mr ", "m ");
923 result = FindAndReplaceStringEnding(result, "nr", "n");
924 result = FindAndReplaceString(result, "nr ", "n ");
925 result = FindAndReplaceStringEnding(result, "pr", "p");
926 result = FindAndReplaceString(result, "pr ", "p ");
927 result = FindAndReplaceStringEnding(result, "rr", "r");
928 result = FindAndReplaceString(result, "rr ", "r ");
929 result = FindAndReplaceStringEnding(result, "tr", "t");
930 result = FindAndReplaceString(result, "tr ", "t ");
931
932 //Greek characters
933 result = FindAndReplaceString(result, "Ἄ", "A");
934 result = FindAndReplaceString(result, "ἄ", "a");
935 result = FindAndReplaceString(result, "Ά", "A");
936 result = FindAndReplaceString(result, "ά", "a");
937 result = FindAndReplaceString(result, "Ἀ", "A");
938 result = FindAndReplaceString(result, "ἀ", "a");
939 result = FindAndReplaceString(result, "Α", "A");
940 result = FindAndReplaceString(result, "α", "a");
941 result = FindAndReplaceString(result, "Β", "B");
942 result = FindAndReplaceString(result, "β", "b");
943 result = FindAndReplaceString(result, "Χ", "Ch");
944 result = FindAndReplaceString(result, "χ", "ch");
945 result = FindAndReplaceString(result, "Δ", "D");
946 result = FindAndReplaceString(result, "δ", "d");
947 result = FindAndReplaceString(result, "Ἑ", "E");
948 result = FindAndReplaceString(result, "ἑ", "e");
949 result = FindAndReplaceString(result, "Ἔ", "E");
950 result = FindAndReplaceString(result, "ἔ", "e");
951 result = FindAndReplaceString(result, "Έ", "E");
952 result = FindAndReplaceString(result, "έ", "e");
953 result = FindAndReplaceString(result, "Ε", "E");
954 result = FindAndReplaceString(result, "ε", "e");
955 result = FindAndReplaceString(result, "Η", "E");
956 result = FindAndReplaceString(result, "η", "e");
957 result = FindAndReplaceString(result, "Γ", "G");
958 result = FindAndReplaceString(result, "γ", "g");
959 result = FindAndReplaceString(result, "Ῑ́", "I");
960 result = FindAndReplaceString(result, "ῑ́", "i");
961 result = FindAndReplaceString(result, "Ί", "I");
962 result = FindAndReplaceString(result, "ί", "i");
963 result = FindAndReplaceString(result, "ῖ", "i");
964 result = FindAndReplaceString(result, "Ι", "I");
965 result = FindAndReplaceString(result, "ι", "i");
966 result = FindAndReplaceString(result, "Ή", "I");
967 result = FindAndReplaceString(result, "ή", "i");
968 result = FindAndReplaceString(result, "Κ", "K");
969 result = FindAndReplaceString(result, "κ", "k");
970 result = FindAndReplaceString(result, "Λ", "L");
971 result = FindAndReplaceString(result, "λ", "l");
972 result = FindAndReplaceString(result, "Μ", "M");
973 result = FindAndReplaceString(result, "μ", "m");
974 result = FindAndReplaceString(result, "Ν", "N");
975 result = FindAndReplaceString(result, "ν", "n");
976 result = FindAndReplaceString(result, "Ὄ", "O");
977 result = FindAndReplaceString(result, "ὄ", "o");
978 result = FindAndReplaceString(result, "Ὅ", "O");
979 result = FindAndReplaceString(result, "ὅ", "o");
980 result = FindAndReplaceString(result, "Ό", "O");
981 result = FindAndReplaceString(result, "ό", "o");
982 result = FindAndReplaceString(result, "Ὀ", "O");
983 result = FindAndReplaceString(result, "ὀ", "o");
984 result = FindAndReplaceString(result, "Ὁ", "O");
985 result = FindAndReplaceString(result, "ὁ", "o");
986 result = FindAndReplaceString(result, "Ο", "O");
987 result = FindAndReplaceString(result, "ο", "o");
988 result = FindAndReplaceString(result, "Ώ", "O");
989 result = FindAndReplaceString(result, "ώ", "o");
990 result = FindAndReplaceString(result, "Ω", "O");
991 result = FindAndReplaceString(result, "ω", "o");
992 result = FindAndReplaceString(result, "Π", "P");
993 result = FindAndReplaceString(result, "π", "p");
994 result = FindAndReplaceString(result, "Φ", "Ph");
995 result = FindAndReplaceString(result, "φ", "ph");
996 result = FindAndReplaceString(result, "Ψ", "Ps");
997 result = FindAndReplaceString(result, "ψ", "ps");
998 result = FindAndReplaceString(result, "Ρ", "R");
999 result = FindAndReplaceString(result, "ρ", "r");
1000 result = FindAndReplaceString(result, "Σ", "S");
1001 result = FindAndReplaceString(result, "σ", "s");
1002 result = FindAndReplaceString(result, "ς", "s");
1003 result = FindAndReplaceString(result, "Τ", "T");
1004 result = FindAndReplaceString(result, "τ", "t");
1005 result = FindAndReplaceString(result, "Θ", "Th");
1006 result = FindAndReplaceString(result, "θ", "th");
1007 result = FindAndReplaceString(result, "Ξ", "X");
1008 result = FindAndReplaceString(result, "ξ", "x");
1009 result = FindAndReplaceString(result, "Ύ", "Y");
1010 result = FindAndReplaceString(result, "ύ", "y");
1011 result = FindAndReplaceString(result, "Ὑ", "Y");
1012 result = FindAndReplaceString(result, "ὑ", "y");
1013 result = FindAndReplaceString(result, "Υ", "Y");
1014 result = FindAndReplaceString(result, "υ", "y");
1015 result = FindAndReplaceString(result, "Ζ", "Z");
1016 result = FindAndReplaceString(result, "ζ", "z");
1017
1018 //remove large clusters of the same letters
1019 result = FindAndReplaceString(result, "nnn", "nn");
1020
1021 return result;
1022 }
1023
CapitalizeString(const std::string & text)1024 std::string CapitalizeString(const std::string &text)
1025 {
1026 if (text.empty()) {
1027 return text;
1028 }
1029
1030 std::string result(text);
1031
1032 result[0] = toupper(result[0]);
1033
1034 // replace special characters which may not have been uppered with the previous method
1035 result = FindAndReplaceStringBeginning(result, "ā", "Ā");
1036 result = FindAndReplaceStringBeginning(result, "â", "Â");
1037 result = FindAndReplaceStringBeginning(result, "æ", "Æ");
1038 result = FindAndReplaceStringBeginning(result, "ǣ", "Ǣ");
1039 result = FindAndReplaceStringBeginning(result, "ǽ", "Ǽ");
1040 result = FindAndReplaceStringBeginning(result, "ð", "Ð");
1041 result = FindAndReplaceStringBeginning(result, "ḍ", "Ḍ");
1042 result = FindAndReplaceStringBeginning(result, "ē", "Ē");
1043 result = FindAndReplaceStringBeginning(result, "ê", "Ê");
1044 result = FindAndReplaceStringBeginning(result, "ě", "Ě");
1045 result = FindAndReplaceStringBeginning(result, "ī", "Ī");
1046 result = FindAndReplaceStringBeginning(result, "î", "Î");
1047 result = FindAndReplaceStringBeginning(result, "ĭ", "Ĭ");
1048 result = FindAndReplaceStringBeginning(result, "ī̆", "Ī̆");
1049 result = FindAndReplaceStringBeginning(result, "ō", "Ō");
1050 result = FindAndReplaceStringBeginning(result, "ô", "Ô");
1051 result = FindAndReplaceStringBeginning(result, "ø", "Ø");
1052 result = FindAndReplaceStringBeginning(result, "ǫ", "Ǫ");
1053 result = FindAndReplaceStringBeginning(result, "ș", "Ș");
1054 result = FindAndReplaceStringBeginning(result, "ț", "Ț");
1055 result = FindAndReplaceStringBeginning(result, "þ", "Þ");
1056 result = FindAndReplaceStringBeginning(result, "ū", "Ū");
1057 result = FindAndReplaceStringBeginning(result, "û", "Û");
1058 result = FindAndReplaceStringBeginning(result, "ŭ", "Ŭ");
1059 result = FindAndReplaceStringBeginning(result, "ȳ", "Ȳ");
1060 result = FindAndReplaceStringBeginning(result, "ž", "Ž");
1061
1062 //Greek characters
1063 result = FindAndReplaceStringBeginning(result, "α", "Α");
1064 result = FindAndReplaceStringBeginning(result, "χ", "Χ");
1065 result = FindAndReplaceStringBeginning(result, "έ", "Έ");
1066 result = FindAndReplaceStringBeginning(result, "ι", "Ι");
1067 result = FindAndReplaceStringBeginning(result, "μ", "Μ");
1068 result = FindAndReplaceStringBeginning(result, "ν", "Ν");
1069 result = FindAndReplaceStringBeginning(result, "ο", "Ο");
1070 result = FindAndReplaceStringBeginning(result, "ό", "Ό");
1071 result = FindAndReplaceStringBeginning(result, "σ", "Σ");
1072 result = FindAndReplaceStringBeginning(result, "θ", "Θ");
1073 result = FindAndReplaceStringBeginning(result, "ύ", "Ύ");
1074
1075 return result;
1076 }
1077
DecapitalizeString(const std::string & text)1078 std::string DecapitalizeString(const std::string &text)
1079 {
1080 if (text.empty()) {
1081 return text;
1082 }
1083
1084 std::string result(text);
1085
1086 result[0] = tolower(result[0]);
1087
1088 // replace special characters which may not have been lowered with the previous method
1089 result = FindAndReplaceStringBeginning(result, "Ā", "ā");
1090 result = FindAndReplaceStringBeginning(result, "Â", "â");
1091 result = FindAndReplaceStringBeginning(result, "Æ", "æ");
1092 result = FindAndReplaceStringBeginning(result, "Ǣ", "ǣ");
1093 result = FindAndReplaceStringBeginning(result, "Ǽ", "ǽ");
1094 result = FindAndReplaceStringBeginning(result, "Ç", "ç");
1095 result = FindAndReplaceStringBeginning(result, "Ð", "ð");
1096 result = FindAndReplaceStringBeginning(result, "Ḍ", "ḍ");
1097 result = FindAndReplaceStringBeginning(result, "Ē", "ē");
1098 result = FindAndReplaceStringBeginning(result, "Ê", "ê");
1099 result = FindAndReplaceStringBeginning(result, "Ě", "ě");
1100 result = FindAndReplaceStringBeginning(result, "Ī", "ī");
1101 result = FindAndReplaceStringBeginning(result, "Î", "î");
1102 result = FindAndReplaceStringBeginning(result, "Ĭ", "ĭ");
1103 result = FindAndReplaceStringBeginning(result, "Ī̆", "ī̆");
1104 result = FindAndReplaceStringBeginning(result, "Ō", "ō");
1105 result = FindAndReplaceStringBeginning(result, "Ô", "ô");
1106 result = FindAndReplaceStringBeginning(result, "Ø", "ø");
1107 result = FindAndReplaceStringBeginning(result, "Ǫ", "ǫ");
1108 result = FindAndReplaceStringBeginning(result, "Þ", "þ");
1109 result = FindAndReplaceStringBeginning(result, "Ū", "ū");
1110 result = FindAndReplaceStringBeginning(result, "Û", "û");
1111 result = FindAndReplaceStringBeginning(result, "Ŭ", "ŭ");
1112 result = FindAndReplaceStringBeginning(result, "Ȳ", "ȳ");
1113 result = FindAndReplaceStringBeginning(result, "Ž", "ž");
1114
1115 //Greek characters
1116 result = FindAndReplaceStringBeginning(result, "Α", "α");
1117 result = FindAndReplaceStringBeginning(result, "Χ", "χ");
1118 result = FindAndReplaceStringBeginning(result, "Έ", "έ");
1119 result = FindAndReplaceStringBeginning(result, "Ι", "ι");
1120 result = FindAndReplaceStringBeginning(result, "Μ", "μ");
1121 result = FindAndReplaceStringBeginning(result, "Ν", "ν");
1122 result = FindAndReplaceStringBeginning(result, "Ο", "ο");
1123 result = FindAndReplaceStringBeginning(result, "Ό", "ό");
1124 result = FindAndReplaceStringBeginning(result, "Σ", "σ");
1125 result = FindAndReplaceStringBeginning(result, "Θ", "θ");
1126 result = FindAndReplaceStringBeginning(result, "Ύ", "ύ");
1127
1128 return result;
1129 }
1130
FullyCapitalizeString(const std::string & text)1131 std::string FullyCapitalizeString(const std::string &text)
1132 {
1133 std::string result(text);
1134
1135 result = CapitalizeString(result);
1136
1137 size_t pos = 0;
1138 while ((pos = result.find(" ", pos)) != std::string::npos) {
1139 std::string replace = CapitalizeString(result.substr(pos + 1, 1));
1140 result.replace(pos + 1, 1, replace);
1141 pos += replace.length();
1142 }
1143
1144 return result;
1145 }
1146
FullyDecapitalizeString(const std::string & text)1147 std::string FullyDecapitalizeString(const std::string &text)
1148 {
1149 std::string result(text);
1150
1151 result = DecapitalizeString(result);
1152
1153 size_t pos = 0;
1154 while ((pos = result.find(" ", pos)) != std::string::npos) {
1155 std::string replace = DecapitalizeString(result.substr(pos + 1, 1));
1156 result.replace(pos + 1, 1, replace);
1157 pos += replace.length();
1158 }
1159
1160 return result;
1161 }
1162
GetPluralForm(const std::string & name)1163 std::string GetPluralForm(const std::string &name)
1164 {
1165 if (name == "Einherjar" || name == "Wose") {
1166 return name; // no difference
1167 }
1168
1169 std::string result(name);
1170
1171 if (result != "Monkey") {
1172 result = FindAndReplaceStringEnding(result, "y", "ie");
1173 }
1174
1175 if (result.substr(result.size() - 2, 2) == "os" || result.substr(result.size() - 2, 2) == "us" || result.substr(result.size() - 1, 1) == "x") {
1176 result += "es";
1177 }
1178
1179 if (result.substr(result.size() - 1, 1) != "s") {
1180 result += "s";
1181 }
1182
1183 result = FindAndReplaceString(result, "Barracks", "Barrackses");
1184 result = FindAndReplaceString(result, "Dwarfs", "Dwarves");
1185 result = FindAndReplaceString(result, "Elfs", "Elves");
1186 result = FindAndReplaceString(result, "Ostrichs", "Ostriches");
1187 result = FindAndReplaceString(result, "Thiefs", "Thieves");
1188 result = FindAndReplaceString(result, "Wolfs", "Wolves");
1189 if (result != "Humans") {
1190 result = FindAndReplaceStringEnding(result, "mans", "men");
1191 }
1192
1193 return result;
1194 }
1195
IdentToName(const std::string & text)1196 std::string IdentToName(const std::string &text)
1197 {
1198 std::string result(text);
1199
1200 result = FindAndReplaceString(result, "-", " ");
1201 result = FullyCapitalizeString(result);
1202
1203 return result;
1204 }
1205
NameToIdent(const std::string & text)1206 std::string NameToIdent(const std::string &text)
1207 {
1208 std::string result(text);
1209
1210 result = FullyDecapitalizeString(result);
1211 result = FindAndReplaceString(result, " ", "-");
1212 result = FindAndReplaceString(result, "'", "");
1213
1214 return result;
1215 }
1216
SeparateCapitalizedStringElements(const std::string & text)1217 std::string SeparateCapitalizedStringElements(const std::string &text)
1218 {
1219 std::string result(text);
1220
1221 for (size_t pos = 1; pos < result.length(); ++pos) {
1222 if (isupper(result[pos])) {
1223 result.replace(pos, 1, " " + result.substr(pos, 1));
1224 pos += 1;
1225 }
1226 }
1227 return result;
1228 }
1229
GeneratePersonalName(const std::string & unit_type_ident)1230 std::string GeneratePersonalName(const std::string &unit_type_ident)
1231 {
1232 int unit_type_id = UnitTypeIdByIdent(unit_type_ident);
1233 return UnitTypes[unit_type_id]->GeneratePersonalName(nullptr, UnitTypes[unit_type_id]->DefaultStat.Variables[GENDER_INDEX].Value);
1234 }
1235 //Wyrmgus end
1236