00001 #include "Script.h"
00002 #ifdef WIN32
00003 #include <windows.h>
00004 #undef GetObject
00005 #endif
00006 #include <stdio.h>
00007 #include <string.h>
00008
00009 extern "C"
00010 {
00011 #include "lualib.h"
00012 }
00013
00014
00015 static int Script_LOG(lua_State* state)
00016 {
00017 Script script(state);
00018 Script::Object obj = script.GetObject(script.GetTop());
00019 #ifdef WIN32
00020 OutputDebugStringA(obj.GetString());
00021 OutputDebugStringA("\n");
00022 #else
00023 printf("%s\n", obj.GetString());
00024 #endif
00025 return 0;
00026 }
00027
00028
00029 static void FatalError()
00030 {
00031 throw -1;
00032 }
00033
00034 static const char* LuaScript_CopyTable =
00035 "function CopyTable(table) "
00036 "local newTable = {} "
00037 "for key, value in table do "
00038 "if type(value) == \"table\" then "
00039 "newTable[key] = CopyTable(value) "
00040 "else "
00041 "newTable[key] = value "
00042 "end "
00043 "end "
00044 "return newTable "
00045 "end";
00046
00047
00050 Script::Script(bool initStandardLibrary) :
00051 m_ownState(false)
00052 {
00053 m_state = lua_open(0);
00054 m_ownState = true;
00055 if (initStandardLibrary)
00056 lua_baselibopen(m_state);
00057
00058
00059 Register("LOG", Script_LOG);
00060 Register("_ERRORMESSAGE", Script_LOG);
00061 DoString(LuaScript_CopyTable);
00062
00063 }
00064
00065
00070 int Script::ConfigGetInteger(const char* section, const char* entry,
00071 int defaultValue)
00072 {
00073 return static_cast<int>(ConfigGetReal(section, entry, defaultValue));
00074 }
00075
00076
00081 float Script::ConfigGetReal(const char* section, const char* entry,
00082 double defaultValue)
00083 {
00084 AutoBlock block(*this);
00085
00086 Object obj = GetGlobal(section);
00087 if (obj.IsNil())
00088 return (float)defaultValue;
00089 obj = obj.GetByName(entry);
00090 if (obj.IsNumber())
00091 return obj.GetNumber();
00092 return (float)defaultValue;
00093 }
00094
00095
00100 const char* Script::ConfigGetString(const char* section, const char* entry,
00101 const char* defaultValue)
00102 {
00103 AutoBlock block(*this);
00104
00105 Object obj = GetGlobal(section);
00106 if (obj.IsNil())
00107 return defaultValue;
00108 obj = obj.GetByName(entry);
00109 if (obj.IsString())
00110 return obj.GetString();
00111 return defaultValue;
00112 }
00113
00114
00118 void Script::ConfigSetInteger(const char* section, const char* entry, int value)
00119 {
00120 AutoBlock block(*this);
00121
00122
00123
00124 Object sectionTable = GetGlobal(section);
00125
00126
00127 if (sectionTable.IsNil())
00128 {
00129 sectionTable = GetGlobals().CreateTable(section);
00130 }
00131
00132 sectionTable.SetNumber(entry, value);
00133 }
00134
00135
00139 void Script::ConfigSetReal(const char* section, const char* entry, double value)
00140 {
00141 AutoBlock block(*this);
00142
00143
00144
00145 Object sectionTable = GetGlobal(section);
00146
00147
00148 if (sectionTable.IsNil())
00149 {
00150 sectionTable = GetGlobals().CreateTable(section);
00151 }
00152
00153 sectionTable.SetNumber(entry, value);
00154 }
00155
00156
00160 void Script::ConfigSetString(const char* section, const char* entry, const char* value)
00161 {
00162 AutoBlock block(*this);
00163
00164
00165
00166 Object sectionTable = GetGlobal(section);
00167
00168
00169 if (sectionTable.IsNil())
00170 {
00171 sectionTable = GetGlobals().CreateTable(section);
00172 }
00173
00174 sectionTable.SetString(entry, value);
00175 }
00176
00177
00181 static void IndentFile(FILE* file, unsigned int indentLevel)
00182 {
00183
00184 char spaces[500];
00185 for (unsigned int i = 0; i < indentLevel; ++i)
00186 spaces[i] = ' ';
00187 spaces[i] = 0;
00188 fputs(spaces, file);
00189 }
00190
00191
00195 static void WriteObject(Script& script, FILE* file, const char* name,
00196 Script::Object value, unsigned int indentLevel)
00197 {
00198
00199 if (value.IsNil())
00200 return;
00201
00202
00203 if (value.IsUserData() || value.IsFunction())
00204 {
00205 return;
00206 }
00207
00208 using Script::Object;
00209
00210
00211 const unsigned int INDENT_SIZE = 4;
00212 const unsigned int indentSpaces = indentLevel * INDENT_SIZE;
00213 IndentFile(file, indentSpaces);
00214
00215
00216 if (name)
00217 fprintf(file, "%s = ", name);
00218
00219
00220 if (value.IsNumber())
00221 fprintf(file, "%.16g", value.GetNumber());
00222
00223
00224 else if (value.IsString())
00225 fprintf(file, "\"%s\"", value.GetString());
00226
00227
00228 else if (value.IsTable())
00229 {
00230
00231 fputs("\n", file);
00232 IndentFile(file, indentSpaces);
00233 fputs("{\n", file);
00234
00235
00236 Script::Object table = value;
00237
00238
00239
00240 int upperIndex = 1;
00241 bool wroteSemi = false;
00242 bool hasSequential = false;
00243
00244
00245 {
00246
00247 Script::AutoBlock block(script);
00248
00249
00250 Object value1 = table.GetByIndex(1);
00251 Object value2 = table.GetByIndex(2);
00252
00253
00254 if (!value1.IsNil() && !value2.IsNil())
00255 {
00256
00257 bool firstSequential = true;
00258 for (; ; ++upperIndex)
00259 {
00260
00261 Script::AutoBlock block(script);
00262
00263
00264 Object value = table.GetByIndex(upperIndex);
00265
00266
00267 if (value.IsNil())
00268 break;
00269
00270
00271 if (!firstSequential)
00272 fputs(",\n", file);
00273
00274
00275 WriteObject(script, file, NULL, value, indentLevel + 1);
00276
00277
00278 firstSequential = false;
00279 }
00280 }
00281 }
00282
00283
00284 if (upperIndex > 1)
00285 {
00286 hasSequential = true;
00287 }
00288
00289
00290 int i;
00291 script.PushNil();
00292 while ((i = script.Next(table.GetStackIndex())) != 0)
00293 {
00294 char keyName[255];
00295
00296
00297 Object key = script.GetObject(script.GetTop() - 1);
00298 Object value = script.GetObject(script.GetTop());
00299
00300
00301 if (key.IsNumber())
00302 {
00303
00304 if (hasSequential)
00305 {
00306
00307 float realNum = key.GetNumber();
00308 int intNum = (int)realNum;
00309 if (realNum == (float)intNum)
00310 {
00311
00312 if (intNum >= 1 && intNum < upperIndex)
00313 {
00314
00315
00316 script.Pop();
00317 continue;
00318 }
00319 }
00320 }
00321
00322
00323 sprintf(keyName, "[%.16g]", key.GetNumber());
00324 }
00325 else
00326 {
00327
00328 strcpy(keyName, key.GetString());
00329 }
00330
00331
00332
00333
00334 if (hasSequential && !value.IsNil() && !wroteSemi)
00335 {
00336
00337 fputs(", ;\n", file);
00338 wroteSemi = true;
00339 }
00340
00341
00342 WriteObject(script, file, keyName, value, indentLevel + 1);
00343
00344
00345 fputs(",\n", file);
00346
00347
00348 script.Pop();
00349 }
00350
00351
00352
00353 if (hasSequential && !wroteSemi)
00354 {
00355 fputs(",\n", file);
00356 }
00357
00358
00359 IndentFile(file, indentSpaces);
00360
00361
00362 if (indentLevel == 0)
00363 {
00364
00365 fputs("}\n\n", file);
00366 }
00367 else
00368 {
00369
00370
00371 fputs("}", file);
00372 }
00373 }
00374
00375
00376
00377 if (indentLevel == 0)
00378 {
00379 fputs("\n", file);
00380 }
00381 }
00382
00383
00387 void Script::SaveText(const char* filename)
00388 {
00389
00390 FILE* file = fopen(filename, "wt");
00391
00392
00393 AutoBlock block(*this);
00394
00395
00396 int i;
00397 Object table = GetGlobals();
00398 PushNil();
00399 while ((i = Next(table.GetStackIndex())) != 0)
00400 {
00401
00402 Object key = GetObject(GetTop() - 1);
00403 Object value = GetObject(GetTop());
00404
00405
00406 if (strcmp(key.GetString(), "_VERSION") != 0)
00407 {
00408 WriteObject(*this, file, key.GetString(), value, 0);
00409 }
00410
00411
00412 Pop();
00413 }
00414
00415
00416 fclose(file);
00417 }