StringTable, [[KEY]] Expansion

Programmers discuss here anything related to FreeOrion programming. Primarily for the developers to discuss.

Moderator: Committer

Post Reply
Message
Author
stride
Space Floater
Posts: 31
Joined: Sun Sep 28, 2008 3:05 pm
Location: Horten, Norway

StringTable, [[KEY]] Expansion

#1 Post by stride »

Added [[KEY]] Expansion in values on stringtable load. It works (c), but loop checks remains.

Code: Select all

Index: StringTable.cpp
===================================================================
--- StringTable.cpp	(revision 2680)
+++ StringTable.cpp	(working copy)
@@ -60,6 +60,8 @@
           (("'''" >> MULTI_LINE_VALUE >> "'''" >> _n) | SINGLE_LINE_VALUE >> _n));
     const sregex REFERENCE =
         "[[" >> *space >> (s1 = IDENTIFIER) >> +space >> (s2 = IDENTIFIER) >> *space >> "]]";
+    const sregex KEYEXPANSION =
+        "[[" >> *space >> (s1 = IDENTIFIER) >> *space >> "]]";
 
     smatch matches;
     if (regex_search(file_contents, matches, FILE_)) {
@@ -108,6 +110,24 @@
                 }
             }
         }
+		for (std::map<std::string, std::string>::iterator map_it = m_strings.begin(); map_it != m_strings.end(); ++map_it)
+        {
+            sregex_iterator it(map_it->second.begin(), map_it->second.end(), KEYEXPANSION);
+            sregex_iterator end;
+            std::size_t offset = 0;
+			for (; it != end; ) {
+                const smatch& match = *it;
+                std::map<std::string, std::string>::iterator map_lookup_it = m_strings.find(match[1]);
+                if (map_lookup_it != m_strings.end()) {
+                    std::string substitution = map_lookup_it->second;
+                    map_it->second.replace(match.position() + offset, match.length(), substitution);
+                    offset = match.position() + substitution.length();
+                    it = sregex_iterator(map_it->second.begin() + offset,
+                                         map_it->second.end(),
+                                         KEYEXPANSION);
+                }
+            }
+        }
     } else {
         Logger().errorStream() << "StringTable file \"" << m_filename << "\" is malformed";
     }

User avatar
Geoff the Medio
Programming, Design, Admin
Posts: 13603
Joined: Wed Oct 08, 2003 1:33 am
Location: Munich

Re: StringTable, [[KEY]] Expansion

#2 Post by Geoff the Medio »

What do you mean by "It works (c), but loop checks remains." ?

Does the order of strings matter? In particular, can a string refer to another string defined after it in the stringtable?

What happens if a string references another string which itself references another string? (Again, does order matter?)

Are circular references resolved somehow?

Does this definitely not interfere with tagged string references like [[tech TECH_NAME_STRINGTABLE_ENTRY]] that are replaced with in-UI links?

stride
Space Floater
Posts: 31
Joined: Sun Sep 28, 2008 3:05 pm
Location: Horten, Norway

Re: StringTable, [[KEY]] Expansion

#3 Post by stride »

Geoff the Medio wrote:What do you mean by "It works (c), but loop checks remains." ?

Does the order of strings matter? In particular, can a string refer to another string defined after it in the stringtable?

What happens if a string references another string which itself references another string? (Again, does order matter?)

Are circular references resolved somehow?

Does this definitely not interfere with tagged string references like [[tech TECH_NAME_STRINGTABLE_ENTRY]] that are replaced with in-UI links?
Code is executed after all keys is loaded, and "tagged string references" resolved. Regex looks for [[singleword]] in values and replaces with expanded value of that key (single word found). sregex_iterator is reinitialized after replacement, which means resultstring is reevaluated until resolved. Order does not matter, references to keys that contains references also works well.

This problem remains to be solved:
TEST1
Bla bla bla [[TEST2]]
TEST2
Bla bla blah [[TEST1]]

I've considered pushing the KEY being resolved onto some stack, check for roundtrips, and make a graceful exit. But... quite honestly my Boost lib skills aren't that adequate yet :)

stride
Space Floater
Posts: 31
Joined: Sun Sep 28, 2008 3:05 pm
Location: Horten, Norway

Re: StringTable, [[KEY]] Expansion

#4 Post by stride »

Ok... I read up on std::set, cyclic reference problem fixed:

Code: Select all

Index: StringTable.cpp
===================================================================
--- StringTable.cpp	(revision 2680)
+++ StringTable.cpp	(working copy)
@@ -60,6 +60,8 @@
           (("'''" >> MULTI_LINE_VALUE >> "'''" >> _n) | SINGLE_LINE_VALUE >> _n));
     const sregex REFERENCE =
         "[[" >> *space >> (s1 = IDENTIFIER) >> +space >> (s2 = IDENTIFIER) >> *space >> "]]";
+    const sregex KEYEXPANSION =
+        "[[" >> *space >> (s1 = IDENTIFIER) >> *space >> "]]";
 
     smatch matches;
     if (regex_search(file_contents, matches, FILE_)) {
@@ -108,6 +110,33 @@
                 }
             }
         }
+		for (std::map<std::string, std::string>::iterator map_it = m_strings.begin(); map_it != m_strings.end(); ++map_it)
+        {
+            sregex_iterator it(map_it->second.begin(), map_it->second.end(), KEYEXPANSION);
+            sregex_iterator end;
+            std::size_t offset = 0;
+			std::set<std::string> cyclic_reference_check;
+			bool cyclic_reference_error = false;
+			cyclic_reference_check.insert(map_it->first);
+			while(it != end && !cyclic_reference_error) {
+				const smatch& match = *it;
+				if (cyclic_reference_check.find(match[1]) == cyclic_reference_check.end()) {
+					cyclic_reference_check.insert(match[1]);
+					std::map<std::string, std::string>::iterator map_lookup_it = m_strings.find(match[1]);
+					if (map_lookup_it != m_strings.end()) {
+						std::string substitution = map_lookup_it->second;
+						map_it->second.replace(match.position() + offset, match.length(), substitution);
+						offset = match.position() + substitution.length();
+						it = sregex_iterator(map_it->second.begin() + offset,
+											 map_it->second.end(),
+											 KEYEXPANSION);
+					}
+				} else {
+					cyclic_reference_error = true;
+					Logger().errorStream() << "While parsing stringtable, expanding key " << match[1] << ": Cyclic referense found. File: '" << m_filename << "'.  Skipping expansion.";
+				}
+            }
+        }
     } else {
         Logger().errorStream() << "StringTable file \"" << m_filename << "\" is malformed";
     }

User avatar
Geoff the Medio
Programming, Design, Admin
Posts: 13603
Joined: Wed Oct 08, 2003 1:33 am
Location: Munich

Re: StringTable, [[KEY]] Expansion

#5 Post by Geoff the Medio »

Sounds good; I'll check it out when I have some time.

Before then, could you send me a private messge with your name for the credits? Standard format is

Real Name (Alias) - Contribution Type(s)

as can be seen on the credits that scroll when the button on the main splash screen is clicked.

tzlaine
Programming Lead Emeritus
Posts: 1092
Joined: Thu Jun 26, 2003 1:33 pm

Re: StringTable, [[KEY]] Expansion

#6 Post by tzlaine »

Nice work. I made one slight modification that allows recursive substitutions. Here's how I modified the English stringtable:

Code: Select all

#Button names####

INTRO_BTN_SINGLE_PLAYER
Single Player

INTRO_BTN_MULTI_PLAYER
Multi Player

INTRO_BTN_LOAD_GAME
Load Game

INTRO_BTN_OPTIONS
Options [[INTRO_BTN_SINGLE_PLAYER]]

INTRO_BTN_ABOUT
About [[INTRO_BTN_OPTIONS]]

INTRO_BTN_CREDITS
Credits [[INTRO_BTN_ABOUT]]

INTRO_BTN_EXIT
Exit
[code]

With your original patch, INTRO_BTN_ABOUT read "About Options [[INTRO_BTN_SINGLE_PLAYER]]".  I changed the new location of the sregex_iterator from just-after the substitution to right at it.  Now INTRO_BTN_ABOUT expands to "About Options Single Player".

Post Reply