src/tools/tLocale.cpp

Go to the documentation of this file.
00001 /*
00002 
00003 *************************************************************************
00004 
00005 ArmageTron -- Just another Tron Lightcycle Game in 3D.
00006 Copyright (C) 2000  Manuel Moos (manuel@moosnet.de)
00007 
00008 **************************************************************************
00009 
00010 This program is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU General Public License
00012 as published by the Free Software Foundation; either version 2
00013 of the License, or (at your option) any later version.
00014 
00015 This program is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00023   
00024 ***************************************************************************
00025 
00026 */
00027 
00028 #include "tMemManager.h"
00029 #include "tLocale.h"
00030 #include "tConsole.h"
00031 #include "tDirectories.h"
00032 #include "tSafePTR.h"
00033 
00034 #include <fstream>
00035 #include <string>
00036 #include <map>
00037 
00038 class tLocaleSubItem; // identifies a single string in a single language
00039 
00040 static tArray<tString> st_TemplateParameters;
00041 
00042 static tString s_gameName("Armagetron"); // the official name of this game
00043 
00044 class tLocaleItem: public tReferencable< tLocaleItem >    // idendifies a string in all languages
00045 {
00046     friend class tLocaleSubItem;
00047 
00048     tString identifier;     // the cross-language identifier of this string
00049     tLocaleSubItem *items;  // the versions of various languages
00050     bool istemplate;        // does it contain \i-directives?
00051 
00052 public:
00053     // static void Check();    // display warnings for all strings not defined in
00054     // the favorite language
00055 
00056     //  operator tString() const; // return the version of this string in the favorite language
00057     operator const char *() const;
00058 
00059     tLocaleItem(const char *identifier); // constructor taking the string identifier
00060     ~tLocaleItem();
00061 
00062     static void Load(const char *file, bool complete = true );  // load the language definitions from a file
00063 
00064     static void Clear();           // clear all locale data on program exit
00065 
00066     static tLocaleItem& Find(const char *identifier); // find identifier
00067 };
00068 
00069 
00070 static const tLanguage* st_firstLanguage  = NULL;
00071 static const tLanguage* st_secondLanguage = NULL;
00072 
00073 static tLanguage*      st_languageAnchor = NULL;
00074 
00075 typedef std::map< std::string, tJUST_CONTROLLED_PTR< tLocaleItem > > tLocaleItemMap;
00076 
00077 // static tLocaleItem*    st_localeAnchor   = NULL;
00078 
00079 static tLanguage *currentLanguage = NULL;
00080 
00081 
00082 class tLocaleSubItem: public tListItem<tLocaleSubItem>
00083 {
00084 public:
00085     const tLanguage *language;  // the language this string is in
00086     tString translation;        // the string itself
00087 
00088     tLocaleSubItem(tLocaleItem *item) // adds this SubItem to item
00089             : tListItem<tLocaleSubItem>(item->items){}
00090 };
00091 
00092 
00093 
00094 tLanguage::tLanguage(const tString& n)
00095         :tListItem<tLanguage>(st_languageAnchor),
00096         name(n)
00097 {
00098 }
00099 
00100 
00101 tLanguage* tLanguage::FirstLanguage()
00102 {
00103     return st_languageAnchor;
00104 }
00105 
00106 void tLanguage::SetFirstLanguage()  const
00107 {
00108     st_firstLanguage = this;
00109     Load();
00110 }
00111 
00112 void tLanguage::SetSecondLanguage() const
00113 {
00114     st_secondLanguage = this;
00115     Load();
00116 }
00117 
00118 void tLanguage::Load() const
00119 {
00120     if (file.Len() > 1)
00121     {
00122         tLocaleItem::Load( file );
00123         file.Clear();
00124     }
00125 }
00126 
00127 void tLanguage::LoadLater( char const * file ) const
00128 {
00129     // store name for later loading
00130     this->file = file;
00131 }
00132 
00133 tLanguage* tLanguage::Find(tString const & name )
00134 {
00135     tLanguage *ret = FindSloppy( name );
00136 
00137     if (ret)
00138         return ret;
00139 
00140     return tNEW(tLanguage(name));
00141 }
00142 
00143 tLanguage* tLanguage::FindStrict(tString const & name )
00144 {
00145     tLanguage *ret = FindSloppy( name );
00146 
00147     if (ret)
00148         return ret;
00149 
00150     tERR_ERROR_INT("Language " << name << " not found.");
00151     return NULL;
00152 }
00153 
00154 tLanguage* tLanguage::FindSloppy(tString const & name )
00155 {
00156     tLanguage *ret = st_languageAnchor;
00157     while (ret)
00158     {
00159         if (ret->name == name)
00160             return ret;
00161         ret = ret->Next();
00162     }
00163 
00164     return NULL;
00165 }
00166 
00167 
00168 /*
00169 void tLocaleItem::Check()
00170 {
00171     tLocaleItem *run = st_localeAnchor;
00172     while (run)
00173     {
00174         tLocaleSubItem *r = run->items;
00175         bool ok = false;
00176         while (r)
00177         {
00178             if (r->language == currentLanguage)
00179                 ok = true;
00180             r = r->Next();
00181         }
00182 
00183         if (!ok)
00184         {
00185             //                  con << "Identifier " << run->identifier << " not translated.\n";
00186             con << run->identifier << "\n";
00187         }
00188         run = run->Next();
00189     }
00190 }
00191 */
00192 
00193 tLocaleItem::operator const char *() const// return the version of this string in the favorite language
00194 {
00195     static tLanguage * english = tLanguage::FindStrict( tString("British English") );
00196 
00197     tString *first = NULL, *second = NULL, *third = NULL, *fourth = NULL;
00198     const tString *ret = NULL;
00199 
00200     tLocaleSubItem *run = items;
00201     while (run)
00202     {
00203         if (st_firstLanguage && run->language == st_firstLanguage)
00204             first = &run->translation;
00205 
00206         if (st_secondLanguage && run->language == st_secondLanguage)
00207             second = &run->translation;
00208 
00209         if (run->language == english)
00210             third = &run->translation;
00211 
00212         fourth = &run->translation;
00213         run = run->Next();
00214     }
00215 
00216     if (first)
00217         ret = first;
00218     else if (second)
00219         ret = second;
00220     else
00221     {
00222         if (third)
00223             ret = third;
00224         else
00225         {
00226             // load english and try again
00227             static bool loadEnglish = true;
00228             if ( loadEnglish )
00229             {
00230                 loadEnglish = false;
00231                 english->Load();
00232                 return *this;
00233             }
00234         }
00235 
00236         if (!ret && fourth)
00237             ret = fourth;
00238         if (!ret)
00239             ret = &identifier;
00240     }
00241 
00242     if (!istemplate)
00243         return *ret;   // no template replacements need to be made
00244     else
00245     {
00246         const tString& temp = *ret;
00247         static tString        replaced;
00248         replaced.Clear();
00249         for(int i = 0; i < temp.Len(); i++)
00250         {
00251             char c = temp(i);
00252             if (c != '\\')
00253                 replaced += c;
00254             else if (i < temp.Len() - 1)
00255             {
00256                 c = temp(i+1);
00257                 if (c == 'g')
00258                     replaced << s_gameName;
00259                 else
00260                 {
00261                     int index = c-'0';
00262                     if (index > 0 && index < 10)
00263                         replaced << st_TemplateParameters[index];
00264                     else if (temp(i+1) == '\\')
00265                         replaced << '\n';
00266                 }
00267                 i++;
00268             }
00269         }
00270 
00271         return replaced;
00272     }
00273 }
00274 
00275 
00276 tLocaleItem::tLocaleItem(const char *id) // constructor taking the string identifier
00277 //:tListItem<tLocaleItem>(st_localeAnchor),
00278         :identifier(id), items(NULL), istemplate(false)
00279 {
00280 }
00281 
00282 tLocaleItem::~tLocaleItem()
00283 {
00284     while (items)
00285         delete (items);
00286 }
00287 
00288 
00289 void tLocaleItem::Clear()
00290 {
00291     //while (st_localeAnchor)
00292     //    delete (st_localeAnchor);
00293 
00294     while (st_languageAnchor)
00295         delete (st_languageAnchor);
00296 }
00297 
00298 
00299 tLocaleItem& tLocaleItem::Find(const char *nn)
00300 {
00301     /*
00302     tLocaleItem *ret = st_localeAnchor;
00303      tString n(nn);
00304 
00305     while (ret)
00306     {
00307         if (ret->identifier == n)
00308             return *ret;
00309         ret = ret->Next();
00310     }
00311 
00312 
00313     return *tNEW(tLocaleItem(n));
00314     */
00315     static tLocaleItemMap    st_localeMap;
00316 
00317     tJUST_CONTROLLED_PTR< tLocaleItem > & ret = st_localeMap[ nn ];
00318 
00319     if ( !ret )
00320         ret = tNEW(tLocaleItem(nn));
00321 
00322     return *ret;
00323 }
00324 
00325 static const tString LANGUAGE("language");
00326 static const tString INCLUDE("include");
00327 // static const tString CHECK("check");
00328 
00329 void tLocaleItem::Load(const char *file, bool complete)  // load the language definitions from a file
00330 {
00331     // bool check = false;
00332     {
00333         tString f;
00334 
00335         f <<  "language/" << file;
00336 
00337         std::ifstream s;
00338         if ( tDirectories::Data().Open( s, f ) )
00339         {
00340             while (!s.eof() && s.good())
00341             {
00342                 tString id;
00343                 s >> id;
00344 
00345                 if (id.Len() <= 1 )
00346                 {
00347                     continue;
00348                 }
00349 
00350                 if(id[0] == '#')
00351                 {
00352                     tString dummy;
00353                     dummy.ReadLine(s);
00354                     continue;
00355                 }
00356 
00357                 if (LANGUAGE == id)
00358                 {
00359                     tString lang;
00360                     lang.ReadLine(s);
00361                     currentLanguage = tLanguage::Find(lang);
00362 
00363                     // delayed loading
00364                     if (!complete)
00365                     {
00366                         currentLanguage->LoadLater(file);
00367                         return;
00368                     }
00369                     continue;
00370                 }
00371 
00372                 if (INCLUDE == id)
00373                 {
00374                     tString inc;
00375                     inc.ReadLine(s);
00376                     Load(inc, complete);
00377                     continue;
00378                 }
00379 
00380                 /*
00381                 if (CHECK == id)
00382                 {
00383                     check = true;
00384                     tString dummy;
00385                     dummy.ReadLine(s);
00386                     continue;
00387                 }
00388                 */
00389 
00390                 // id is a true string identifier.
00391                 tLocaleItem &li = Find(id);
00392                 tLocaleSubItem *r = li.items;
00393                 bool done = false;
00394                 while (r && !done)
00395                 {
00396                     if (r->language == currentLanguage)
00397                     {
00398                         // r->translation.ReadLine(s);
00399                         done = true;
00400                         continue;
00401                     }
00402                     r = r->Next();
00403                 }
00404 
00405                 if (!done)
00406                     r = tNEW(tLocaleSubItem)(&li);
00407                 else
00408                 {
00409                     // st_Breakpoint();
00410                     // con << "Locale item " << id << " defined twice in language "
00411                     // << currentLanguage->Name() << ".\n";
00412                 }
00413 
00414                 tString pre;
00415                 pre.ReadLine(s);
00416                 r->translation.Clear();
00417 
00418                 for (size_t i=0; i< pre.Size(); i++)
00419                 {
00420                     char c = pre(i);
00421                     if (c != '\\')
00422                         r->translation += c;
00423                     else if (i < pre.Size())
00424                         switch (pre(i+1))
00425                         {
00426                         case 'n':
00427                             r->translation += '\n';
00428                             i++;
00429                             break;
00430 
00431                         case '1':
00432                         case '2':
00433                         case '3':
00434                         case '4':
00435                         case '5':
00436                         case '6':
00437                         case '7':
00438                         case '8':
00439                         case '9':
00440                         case 'g':
00441                             r->translation += '\\';
00442                             li.istemplate = true;
00443                             break;
00444 
00445                             /*
00446                                          case '\\':
00447                                          r->translation << "\\\\";
00448                                          i++;
00449                             */
00450 
00451                         default:
00452                             r->translation += '\\';
00453                             break;
00454                         }
00455                 }
00456 
00457                 r->language = currentLanguage;
00458                 //      r->translation.ReadLine(s);
00459 
00460 
00461             }
00462         }
00463     }
00464 
00465     /*
00466     if (check)
00467         Check();
00468     */
00469 }
00470 
00471 class tOutputItemLocale: public tOutputItemBase
00472 {
00473     const tLocaleItem *element;
00474 public:
00475     tOutputItemLocale(tOutput& o, const tLocaleItem& e);
00476     virtual void Print(tString& target) const;
00477     virtual void Clone(tOutput& o)      const;
00478 };
00479 
00480 class tOutputItemSpace: public tOutputItemBase
00481 {
00482 public:
00483     tOutputItemSpace(tOutput& o);
00484     virtual void Print(tString& target) const;
00485     virtual void Clone(tOutput& o)      const;
00486 };
00487 
00488 
00489 class tOutputItemTemplate: public tOutputItemBase
00490 {
00491     int       num;
00492     tString   parameter;
00493 public:
00494     tOutputItemTemplate(tOutput& o, int n, const char *p);
00495     virtual void Print(tString& target) const;
00496     virtual void Clone(tOutput& o)      const;
00497 };
00498 
00499 
00500 tOutput::tOutput(): anchor(0){}
00501 tOutput::~tOutput()
00502 {
00503     while (anchor)
00504         delete anchor;
00505 }
00506 
00507 void tOutput::Clear()
00508 {
00509     while (anchor)
00510         delete anchor;
00511 }
00512 
00513 
00514 static void getstring(tString &target, tOutputItemBase *item)
00515 {
00516     if (!item)
00517         return;
00518     getstring(target, item->Next());
00519     item->Print(target);
00520 }
00521 
00522 /*
00523 tOutput::operator tString() const
00524 {
00525 #ifdef DEBUG
00526 #ifndef WIN32
00527         static bool recursion = false;
00528         if (recursion)
00529     {
00530                 tERR_ERROR_INT("Locale Recursion!");
00531     }
00532         recursion = true;
00533 #endif
00534 #endif
00535 
00536         static tString x;
00537         x.Clear();
00538         getstring(x, anchor);
00539 
00540 #ifdef DEBUG
00541 #ifndef WIN32
00542         recursion = false;
00543 #endif
00544 #endif
00545 
00546         return x;
00547 }
00548 */
00549 
00550 tOutput::operator const char *() const
00551 {
00552 #ifdef DEBUG
00553 #ifndef WIN32
00554     static bool recursion = false;
00555     if (recursion)
00556     {
00557         tERR_ERROR_INT("Locale Recursion!");
00558     }
00559     recursion = true;
00560 #endif
00561 #endif
00562 
00563     // get a relatively safe buffer to write to
00564     static const int maxstrings = 5;
00565     static int current = 0;
00566     static tString buffers[maxstrings];
00567     tString & x = buffers[current];
00568     current = ( current + 1 ) % maxstrings;
00569 
00570     x.Clear();
00571     getstring(x, anchor);
00572 
00573 #ifdef DEBUG
00574 #ifndef WIN32
00575     recursion = false;
00576 #endif
00577 #endif
00578 
00579     return x;
00580 }
00581 
00582 
00583 void tOutput::AddLiteral(const char *x)
00584 {
00585     tNEW(tOutputItem<tString>)(*this, tString(x));
00586 }
00587 
00588 void tOutput::AddSpace()
00589 {
00590     tNEW(tOutputItemSpace)(*this);
00591 }
00592 
00593 void tOutput::AddLocale(const char *x)
00594 {
00595     tNEW(tOutputItemLocale)(*this, tLocale::Find(x));
00596 }
00597 
00598 
00599 tOutput & tOutput::SetTemplateParameter(int num, const char *parameter)
00600 {
00601     tNEW(tOutputItemTemplate)(*this, num, parameter);
00602     return *this;
00603 }
00604 
00605 tOutput &  tOutput::SetTemplateParameter(int num, int parameter)
00606 {
00607     tString p;
00608     p << parameter;
00609     tNEW(tOutputItemTemplate)(*this, num, p);
00610 
00611     return *this;
00612 }
00613 
00614 tOutput & tOutput::SetTemplateParameter(int num, float parameter)
00615 {
00616     tString p;
00617     p << parameter;
00618     tNEW(tOutputItemTemplate)(*this, num, p);
00619 
00620     return *this;
00621 }
00622 
00623 
00624 tOutput::tOutput(const std::string & x)
00625         :anchor(NULL)
00626 {
00627     tNEW(tOutputItem<tString>)(*this, x);
00628 }
00629 
00630 tOutput::tOutput(const tString& x)
00631         :anchor(NULL)
00632 {
00633     tNEW(tOutputItem<tString>)(*this, x);
00634 }
00635 
00636 tOutput::tOutput(const char * x)
00637         :anchor(NULL)
00638 {
00639     *this << x;
00640 }
00641 
00642 
00643 tOutput::tOutput(const tLocaleItem &locale)
00644         :anchor(NULL)
00645 {
00646     tNEW(tOutputItemLocale)(*this, locale);
00647 }
00648 
00649 
00650 static void copyrec(tOutput &targ, tOutputItemBase *it)
00651 {
00652     if (!it)
00653         return;
00654 
00655     copyrec(targ, it->Next());
00656     it->Clone(targ);
00657 }
00658 
00659 tOutput::tOutput(const tOutput &o)
00660         :anchor(NULL)
00661 {
00662     copyrec(*this, o.anchor);
00663 }
00664 
00665 tOutput& tOutput::operator=(const tOutput &o)
00666 {
00667     Clear();
00668 
00669     copyrec(*this, o.anchor);
00670 
00671     return *this;
00672 }
00673 
00674 void tOutput::Append(const tOutput &o)
00675 {
00676     copyrec(*this, o.anchor);
00677 }
00678 
00679 
00680 tOutputItemBase::tOutputItemBase(tOutput& o): tListItem<tOutputItemBase>(o.anchor){}
00681 
00682 tOutputItemBase::~tOutputItemBase(){}
00683 
00684 
00685 
00686 tOutputItemLocale::tOutputItemLocale(tOutput& o, const tLocaleItem& e)
00687         :tOutputItemBase(o),
00688         element(&e)
00689 {
00690 }
00691 
00692 void tOutputItemLocale::Print(tString& target) const
00693 {
00694     target << *element;
00695 }
00696 
00697 void tOutputItemLocale::Clone(tOutput& o)      const
00698 {
00699     tNEW(tOutputItemLocale)(o, *element);
00700 }
00701 
00702 
00703 tOutputItemSpace::tOutputItemSpace(tOutput& o)
00704         :tOutputItemBase(o)
00705 {}
00706 
00707 void tOutputItemSpace::Print(tString& target) const
00708 {
00709     target << ' ';
00710 }
00711 
00712 void tOutputItemSpace::Clone(tOutput& o)      const
00713 {
00714     tNEW(tOutputItemSpace)(o);
00715 }
00716 
00717 
00718 tOutputItemTemplate::tOutputItemTemplate(tOutput& o, int n, const char *p)
00719         :tOutputItemBase(o), num(n), parameter(p)
00720 {}
00721 
00722 void tOutputItemTemplate::Print(tString& target) const
00723 {
00724     st_TemplateParameters[num] = parameter;
00725 }
00726 
00727 void tOutputItemTemplate::Clone(tOutput& o)      const
00728 {
00729     tNEW(tOutputItemTemplate)(o, num, parameter);
00730 }
00731 
00732 
00733 tOutput& operator << (tOutput &o, char *locale)
00734 {
00735     return operator<<(o, static_cast<const char *>(locale));
00736 }
00737 
00738 // and a special implementation for the locales and strings:
00739 tOutput& operator << (tOutput &o, const char *locale){
00740     int len = strlen(locale);
00741     if (len == 0)
00742         return o;
00743     if (len == 1 && locale[0] == ' ')
00744         tNEW(tOutputItemSpace)(o);
00745     else if (locale[0] == '$')
00746         tNEW(tOutputItemLocale)(o, tLocale::Find(locale+1));
00747     else
00748         tNEW(tOutputItem<tString>)(o, tString(locale));
00749 
00750     return o;
00751 }
00752 
00753 // output operators
00754 std::ostream& operator<< (std::ostream& s, const tOutput& o)
00755 {
00756     return s << tString(o);
00757 }
00758 
00759 /*
00760 std::stringstream& operator<< (std::stringstream& s, const tOutput& o)
00761 {
00762         static_cast<std::ostream&>(s) << static_cast<const char *>(o);
00763         return s;
00764 }
00765 */
00766 
00767 tString& operator<< (tString& s, const tOutput& o)
00768 {
00769     s << tString(o);
00770     return s;
00771 }
00772 
00773 
00774 
00775 // interface class for locale items
00776 const tLocaleItem& tLocale::Find(const char* id)
00777 {
00778     return tLocaleItem::Find(id);
00779 }
00780 
00781 void               tLocale::Load(const char* filename)
00782 {
00783     tLocaleItem::Load(filename, false);
00784 
00785     // determine the name of the game
00786     s_gameName.Clear();
00787     s_gameName << tOutput("$game_name");
00788 }
00789 
00790 void               tLocale::Clear()
00791 {
00792     tLocaleItem::Clear();
00793 }
00794 
00795 /*
00796 std::stringstream& operator<<(std::stringstream& s, const tLocaleItem &t)
00797 {
00798         static_cast<std::ostream&>(s) << static_cast<const char*>(t);
00799         return s;
00800 }
00801 */
00802 
00803 std::ostream& operator<<(std::ostream& s, const tLocaleItem &t)
00804 {
00805     return s << static_cast<const char*>(t);
00806 }
00807 
00808 tString& operator<< (tString& s, const tLocaleItem& o)
00809 {
00810     s << static_cast<const char *>(o);
00811     return s;
00812 }

Generated on Sat Mar 15 22:56:00 2008 for Armagetron Advanced by  doxygen 1.5.4