| 694 | } |
| 695 | |
| 696 | GameValue StrFormat(const GameState* state, GameValuePar oper1) |
| 697 | { |
| 698 | const GameArrayType& array = oper1; |
| 699 | if (array.Size() < 1 || array[0].GetType() != GameString) |
| 700 | { |
| 701 | return ""; |
| 702 | } |
| 703 | RString format = array[0]; |
| 704 | |
| 705 | int nParams = array.Size() - 1; |
| 706 | // The result is unbounded (params can be arbitrarily long), so accumulate into a |
| 707 | // growable buffer. A fixed stack buffer here overflows on long output and crashes. |
| 708 | std::string result; |
| 709 | const char* src = format; |
| 710 | |
| 711 | while (char c = *src) |
| 712 | { |
| 713 | if (c == '%') |
| 714 | { |
| 715 | src++; |
| 716 | int index = 0; |
| 717 | while (isdigit(static_cast<unsigned char>(*src))) |
| 718 | { |
| 719 | index = index * 10 + (*src - '0'); |
| 720 | src++; |
| 721 | } |
| 722 | if (index < 1 || index > nParams) |
| 723 | { |
| 724 | continue; |
| 725 | } |
| 726 | const GameValue& value = array[index]; |
| 727 | RString text = (value.GetType() == GameString) ? value.GetData()->GetString() : value.GetText(); |
| 728 | result.append(static_cast<const char*>(text), text.GetLength()); |
| 729 | } |
| 730 | else |
| 731 | { |
| 732 | result.push_back(c); |
| 733 | src++; |
| 734 | } |
| 735 | } |
| 736 | return RString(result.c_str()); |
| 737 | } |
| 738 | |
| 739 | GameValue StrLocalize(const GameState* state, GameValuePar oper1) |
| 740 | { |