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