Strings under I4 are perhaps one of the most complicated things to
understand.  

The main string classes are 

i4_const_str                    (strings which cannot be changed or freed)
i4_str : public i4_const_str    (strings which can be changed and freed)

i4_string_manager_class : public i4_init_class


The primary goal of the string classes is to assist translations of
products.  To enforce translation of all user visible strings, all
strings must be created by a i4_string_manager_class which loads them
from a resource file (while can be easily translated).  A resource
file is a simple text file formatted as follows :

internal external

where is internal is the internal name referred to by the program.  The
external name is the one the user sees and is might be translated.
The string manager also supports arrays of strings as follows :

internal { external1 external2 external3 external4 }

optionally you can insert a = between the external and the external as
follows :

internal = external

this assist parsing match up should you miss a word by accident.


An i4_string_manager_class can load up strings from a file via
load(i4_open_file_function_type opener, char *filename); 
(see files.txt for details about opener)

Or it can load them up from a memory buffer (i.e. a resource file
loaded into some memory location) with

i4_bool load_buffer(i4_open_file_function_type opener,
                    void *internal_buffer, char *error_prefix);


Substitutions are allowed in resource files.

internal1 = external1
internal2 = ${external1}_external2

Once strings have been loaded into a string_manager, then you can
fetch them with either get or get_array.  

i4_string_manager_class.get("internal2") returns
i4_const_str("external1_external2")

There is a global string manager defined for convince.
i4_string_man.  Also the global function i4gets(char *) will
fetch an external string from it using an internal name.

font->put_string(screen, 10, 10, i4gets("name"), context);

Internal symbol names are stored in a binary tree and a search
is performed every time you call i4gets().

The difference between i4_const_str and i4_str is that i4_const_str's
are compacted into a small heap (head to toe) and cannot be freed or
modified.  An i4_str resides in the main heap (allocated with
i4_malloc). i4_str's can be deleted or modified.  An i4_str can be
passed to routines needing i4_const_str because it is derived from it.
i4_str's are usually constructed from i4_const_strs by insertion,
concatenation, etc.  This ensures that all i4_str will built from
parts that are translated, thus being translated themselves.

Strings use iterators to access individual characters.  An iterator
can be thought of as a pointer.  Incrementing moves to the next
character, decrementing goes back one character.  i4_const_str.begin()
returns an iterator referencing the first character in the string,
while i4_const_str.end() returns an iterator referencing the last+1
character in a string.  So you iterator through all the characters in
a string if you want to.  This allows for addition of wide characters
or kanji-escaped code characters without changes to the rest of the
application.  (Neither are currently supported though).


