1 //**************************************************************************
2 //**
3 //** ## ## ## ## ## #### #### ### ###
4 //** ## ## ## ## ## ## ## ## ## ## #### ####
5 //** ## ## ## ## ## ## ## ## ## ## ## ## ## ##
6 //** ## ## ######## ## ## ## ## ## ## ## ### ##
7 //** ### ## ## ### ## ## ## ## ## ##
8 //** # ## ## # #### #### ## ##
9 //**
10 //** $Id: language.cpp 4324 2010-07-09 19:19:37Z firebrand_kh $
11 //**
12 //** Copyright (C) 1999-2006 Jānis Legzdiņš
13 //**
14 //** This program is free software; you can redistribute it and/or
15 //** modify it under the terms of the GNU General Public License
16 //** as published by the Free Software Foundation; either version 2
17 //** of the License, or (at your option) any later version.
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 //**************************************************************************
25
26 // HEADER FILES ------------------------------------------------------------
27
28 #include "gamedefs.h"
29
30 // MACROS ------------------------------------------------------------------
31
32 // TYPES -------------------------------------------------------------------
33
34 struct VLanguage::VLangEntry
35 {
36 vint32 PassNum;
37 VStr Value;
38 };
39
40 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
41
42 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
43
44 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
45
46 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
47
48 // PUBLIC DATA DEFINITIONS -------------------------------------------------
49
50 VLanguage GLanguage;
51
52 // PRIVATE DATA DEFINITIONS ------------------------------------------------
53
54 // CODE --------------------------------------------------------------------
55
56 //==========================================================================
57 //
58 // VLanguage::VLanguage
59 //
60 //==========================================================================
61
VLanguage()62 VLanguage::VLanguage()
63 : Table(NULL)
64 {
65 }
66
67 //==========================================================================
68 //
69 // VLanguage::~VLanguage
70 //
71 //==========================================================================
72
~VLanguage()73 VLanguage::~VLanguage()
74 {
75 FreeData();
76 }
77
78 //==========================================================================
79 //
80 // VLanguage::FreeData
81 //
82 //==========================================================================
83
FreeData()84 void VLanguage::FreeData()
85 {
86 guard(VLanguage::FreeData);
87 if (Table)
88 {
89 delete Table;
90 Table = NULL;
91 }
92 unguard;
93 }
94
95 //==========================================================================
96 //
97 // VLanguage::FreeNonDehackedStrings
98 //
99 //==========================================================================
100
FreeNonDehackedStrings()101 void VLanguage::FreeNonDehackedStrings()
102 {
103 guard(VLanguage::FreeNonDehackedStrings);
104 for (TMap<VName, VLangEntry>::TIterator It(*Table); It; ++It)
105 if (It.GetValue().PassNum != 0)
106 It.RemoveCurrent();
107 unguard;
108 }
109
110 //==========================================================================
111 //
112 // VLanguage::LoadStrings
113 //
114 //==========================================================================
115
LoadStrings(const char * LangId)116 void VLanguage::LoadStrings(const char* LangId)
117 {
118 guard(VLanguage::LoadStrings);
119 if (!Table)
120 Table = new TMap<VName, VLangEntry>();
121
122 FreeNonDehackedStrings();
123
124 for (int Lump = W_IterateNS(-1, WADNS_Global); Lump >= 0;
125 Lump = W_IterateNS(Lump, WADNS_Global))
126 {
127 if (W_LumpName(Lump) == NAME_language)
128 {
129 int j = 1;
130 if (VStr::Cmp(LangId, "**"))
131 {
132 ParseLanguageScript(Lump, "*", true, j++);
133 ParseLanguageScript(Lump, LangId, true, j++);
134 ParseLanguageScript(Lump, LangId, false, j++);
135 }
136 ParseLanguageScript(Lump, "**", true, j++);
137 }
138 }
139 unguard;
140 }
141
142 //==========================================================================
143 //
144 // VLanguage::ParseLanguageScript
145 //
146 //==========================================================================
147
ParseLanguageScript(vint32 Lump,const char * InCode,bool ExactMatch,vint32 PassNum)148 void VLanguage::ParseLanguageScript(vint32 Lump, const char* InCode,
149 bool ExactMatch, vint32 PassNum)
150 {
151 guard(VLanguage::ParseLanguageScript);
152 char Code[4];
153 Code[0] = VStr::ToLower(InCode[0]);
154 Code[1] = VStr::ToLower(InCode[1]);
155 Code[2] = ExactMatch ? VStr::ToLower(InCode[2]) : 0;
156 Code[3] = 0;
157
158 VScriptParser* sc = new VScriptParser(*W_LumpName(Lump),
159 W_CreateLumpReaderNum(Lump));
160 sc->SetCMode(true);
161
162 bool GotLanguageCode = false;
163 bool Skip = false;
164 bool Finished = false;
165
166 while (!sc->AtEnd())
167 {
168 if (sc->Check("["))
169 {
170 // Language identifiers.
171 Skip = true;
172 while (!sc->Check("]"))
173 {
174 sc->ExpectString();
175 size_t Len = sc->String.Length();
176 char CurCode[4];
177 if (Len != 2 && Len != 3)
178 {
179 if (Len == 1 && sc->String[0] == '*')
180 {
181 CurCode[0] = '*';
182 CurCode[1] = 0;
183 CurCode[2] = 0;
184 }
185 else if (Len == 7 && !sc->String.ICmp("default"))
186 {
187 CurCode[0] = '*';
188 CurCode[1] = '*';
189 CurCode[2] = 0;
190 }
191 else
192 {
193 sc->Error(va("Language code must be 2 or 3 "
194 "characters long, %s is %d characters long",
195 *sc->String, Len));
196 // Shut up compiler
197 CurCode[0] = 0;
198 CurCode[1] = 0;
199 CurCode[2] = 0;
200 }
201 }
202 else
203 {
204 CurCode[0] = VStr::ToLower(sc->String[0]);
205 CurCode[1] = VStr::ToLower(sc->String[1]);
206 CurCode[2] = ExactMatch ? VStr::ToLower(sc->String[2]) : 0;
207 CurCode[3] = 0;
208 }
209 if (Code[0] == CurCode[0] && Code[1] == CurCode[1] &&
210 Code[2] == CurCode[2])
211 {
212 Skip = false;
213 }
214 GotLanguageCode = true;
215 }
216 }
217 else
218 {
219 if (!GotLanguageCode)
220 {
221 // Skip old binary LANGUAGE lumps.
222 if (!sc->IsText())
223 {
224 if (!Finished)
225 {
226 GCon->Logf("Skipping binary LANGUAGE lump");
227 }
228 Finished = true;
229 return;
230 }
231 sc->Error("Found a string without language specified");
232 }
233
234 // Parse string definitions.
235 if (Skip)
236 {
237 // We are skipping this language.
238 sc->ExpectString();
239 sc->Expect("=");
240 sc->ExpectString();
241 while (!sc->Check(";"))
242 {
243 sc->ExpectString();
244 }
245 continue;
246 }
247
248 sc->ExpectString();
249 VName Key = *sc->String.ToLower();
250 sc->Expect("=");
251 sc->ExpectString();
252 VStr Value = HandleEscapes(sc->String);
253 while (!sc->Check(";"))
254 {
255 sc->ExpectString();
256 Value += HandleEscapes(sc->String);
257 }
258
259 // Check for replacement.
260 VLangEntry* Found = Table->Find(Key);
261 if (!Found || Found->PassNum >= PassNum)
262 {
263 VLangEntry Entry;
264 Entry.Value = Value;
265 Entry.PassNum = PassNum;
266 Table->Set(Key, Entry);
267 }
268 }
269 }
270 delete sc;
271 sc = NULL;
272 unguard;
273 }
274
275 //==========================================================================
276 //
277 // VLanguage::HandleEscapes
278 //
279 //==========================================================================
280
HandleEscapes(VStr Src)281 VStr VLanguage::HandleEscapes(VStr Src)
282 {
283 guard(VLanguage::HandleEscapes);
284 VStr Ret;
285 for (size_t i = 0; i < Src.Length(); i++)
286 {
287 char c = Src[i];
288 if (c == '\\')
289 {
290 i++;
291 c = Src[i];
292 if (c == 'n')
293 c = '\n';
294 else if (c == 'r')
295 c = '\r';
296 else if (c == 't')
297 c = '\t';
298 else if (c == 'c')
299 c = -127;
300 else if (c == '\n')
301 continue;
302 }
303 Ret += c;
304 }
305 return Ret;
306 unguard;
307 }
308
309 //==========================================================================
310 //
311 // VLanguage::Find
312 //
313 //==========================================================================
314
Find(VName Key) const315 VStr VLanguage::Find(VName Key) const
316 {
317 guard(VLanguage::Find);
318 VLangEntry* Found = Table->Find(Key);
319 return Found ? Found->Value : VStr();
320 unguard;
321 }
322
323 //==========================================================================
324 //
325 // VLanguage::operator[]
326 //
327 //==========================================================================
328
operator [](VName Key) const329 VStr VLanguage::operator[](VName Key) const
330 {
331 guard(VLanguage::operator[]);
332 VLangEntry* Found = Table->Find(Key);
333 return Found ? Found->Value : VStr(Key);
334 unguard;
335 }
336
337 //==========================================================================
338 //
339 // VLanguage::GetStringId
340 //
341 //==========================================================================
342
GetStringId(const VStr & Str)343 VName VLanguage::GetStringId(const VStr& Str)
344 {
345 guard(VLanguage::GetStringId);
346 for (TMap<VName, VLangEntry>::TIterator It(*Table); It; ++It)
347 {
348 if (It.GetValue().Value == Str)
349 {
350 return It.GetKey();
351 }
352 }
353 return NAME_None;
354 unguard;
355 }
356
357 //==========================================================================
358 //
359 // VLanguage::ReplaceString
360 //
361 //==========================================================================
362
ReplaceString(VName Key,const VStr & Value)363 void VLanguage::ReplaceString(VName Key, const VStr& Value)
364 {
365 guard(VLanguage::ReplaceString);
366 VLangEntry Entry;
367 Entry.Value = Value;
368 Entry.PassNum = 0;
369 Table->Set(Key, Entry);
370 unguard;
371 }
372