00001
00002
00003
00004
00005
00006
00007
00009
00010 #ifdef WIN32
00011 #include <windows.h>
00012 #undef GetObject
00013 #endif WIN32
00014 #pragma warning(disable: 4786)
00015 #include <list>
00016 #include <string>
00017 #include <algorithm>
00018 #include <stdio.h>
00019 #include <string.h>
00020 #include "LuaStateFunctions.h"
00021 #pragma warning(disable: 4786)
00022
00023
00024 extern "C"
00025 {
00026 #include "lualib.h"
00027 }
00028
00029 static int LS_LOG(LuaState state)
00030 {
00031 LuaObject obj(state, 1);
00032 #ifdef WIN32
00033 OutputDebugStringA(obj.GetString());
00034 OutputDebugStringA("\n");
00035 #else
00036 printf("%s\n", obj.GetString());
00037 #endif
00038 return 0;
00039 }
00040
00041
00044 static int LS_WriteLuaObject(LuaState state)
00045 {
00046 FILE* stdioFile = (FILE *)LuaObject(state, 1).GetUserData();
00047 LuaObject nameObj(state, 2);
00048 LuaObject valueObj(state, 3);
00049 LuaObject indentLevelObj(state, 4);
00050 LuaObject writeAllObj(state, 5);
00051 LuaObject alphabeticalObj(state, 6);
00052 LuaObject maxIndentLevelObj(state, 7);
00053 bool writeAll = !writeAllObj.IsNil() && writeAllObj.GetInteger() != 0;
00054 bool alphabetical = !alphabeticalObj.IsNil() && alphabeticalObj.GetInteger() != 0;
00055 int maxIndentLevel = maxIndentLevelObj.IsNumber() ? maxIndentLevelObj.GetInteger() : 0xFFFFFFFF;
00056
00057 LuaStateOutFile file;
00058 file.Assign(stdioFile);
00059 state.WriteLuaObject(file, nameObj.GetString(), valueObj, indentLevelObj.GetInteger(), writeAll, alphabetical, false, maxIndentLevel);
00060
00061 return 0;
00062 }
00063
00064
00067 static int LS_WriteLuaFile(LuaState state)
00068 {
00069 LPCSTR fileName = state.ToString(1);
00070 FILE* file = fopen(fileName, "wt");
00071 if (!file)
00072 {
00073 state.PushBool(false);
00074 return 1;
00075 }
00076 LuaObject nameObj(state, 2);
00077 LuaObject valueObj(state, 3);
00078 LuaObject indentLevelObj(state, 4);
00079 LuaObject writeAllObj(state, 5);
00080 LuaObject alphabeticalObj(state, 6);
00081 LuaObject maxIndentLevelObj(state, 7);
00082 bool writeAll = !writeAllObj.IsNil() && writeAllObj.GetInteger() != 0;
00083 bool alphabetical = !alphabeticalObj.IsNil() && alphabeticalObj.GetInteger() != 0;
00084 int maxIndentLevel = maxIndentLevelObj.IsNumber() ? maxIndentLevelObj.GetInteger() : 0xFFFFFFFF;
00085
00086 LuaStateOutFile stdFile;
00087 stdFile.Assign(file);
00088 state.WriteLuaObject(stdFile, nameObj.GetString(), valueObj,
00089 indentLevelObj.GetInteger(), writeAll, alphabetical, false, maxIndentLevel);
00090 fclose(file);
00091
00092 state.PushBool(true);
00093 return 1;
00094 }
00095
00096
00099 static int LS_WriteLuaGlobalsFile(LuaState state)
00100 {
00101 LPCSTR fileName = state.ToString(1);
00102 LuaObject writeAllObj(state, 2);
00103 LuaObject alphabeticalObj(state, 3);
00104 LuaObject maxIndentLevelObj(state, 4);
00105 bool writeAll = !writeAllObj.IsNil() && writeAllObj.GetInteger() != 0;
00106 bool alphabetical = !alphabeticalObj.IsNil() && alphabeticalObj.GetInteger() != 0;
00107 int maxIndentLevel = maxIndentLevelObj.IsNumber() ? maxIndentLevelObj.GetInteger() : 0xFFFFFFFF;
00108
00109 state.WriteLuaGlobalsFile(fileName, writeAll, alphabetical, false, maxIndentLevel);
00110
00111 state.PushBool(true);
00112 return 1;
00113 }
00114
00115
00118 static void FatalError()
00119 {
00120 throw -1;
00121 }
00122
00123
00126 static void LSLock(void* data)
00127 {
00128 CRITICAL_SECTION* cs = (CRITICAL_SECTION*)data;
00129 ::EnterCriticalSection(cs);
00130 }
00131
00132
00135 static void LSUnlock(void* data)
00136 {
00137 CRITICAL_SECTION* cs = (CRITICAL_SECTION*)data;
00138 ::LeaveCriticalSection(cs);
00139 }
00140
00141
00144 LuaStateOwner::LuaStateOwner(bool initStandardLibrary, DWORD stackSize, bool multithreaded)
00145 {
00146 m_state = lua_open(stackSize);
00147
00148 if (multithreaded)
00149 {
00150
00151 CRITICAL_SECTION* cs = new CRITICAL_SECTION;
00152 ::InitializeCriticalSection(cs);
00153 lua_setlockfunctions(m_state, LSLock, LSUnlock, cs);
00154 }
00155
00156 Init(initStandardLibrary, stackSize);
00157 }
00158
00159
00162 LuaStateOwner::LuaStateOwner(LuaState& script, bool initStandardLibrary, DWORD stackSize)
00163 {
00164 m_state = lua_newthread(script, stackSize);
00165 Init(initStandardLibrary, stackSize);
00166 }
00167
00168
00169 extern "C" int lua_dumplibopen (lua_State *L);
00170
00173 void LuaStateOwner::Init(bool initStandardLibrary, DWORD stackSize)
00174 {
00175
00176 if (initStandardLibrary)
00177 {
00178 lua_baselibopen(m_state);
00179 lua_iolibopen(m_state);
00180 lua_strlibopen(m_state);
00181 lua_mathlibopen(m_state);
00182 lua_dblibopen(m_state);
00183 lua_dumplibopen(m_state);
00184
00185 ScriptFunctionsRegister(m_state);
00186
00187 Register("WriteLuaObject", LS_WriteLuaObject);
00188 Register("WriteLuaFile", LS_WriteLuaFile);
00189 Register("WriteLuaGlobalsFile", LS_WriteLuaGlobalsFile);
00190 }
00191
00192 Register("LOG", LS_LOG);
00193 Register("_ALERT", LS_LOG);
00194
00195 lua_setfatalerrorfunction(m_state, FatalError);
00196 }
00197
00198
00203 int LuaState::ConfigGetInteger(const char* section, const char* entry,
00204 int defaultValue)
00205 {
00206 return static_cast<int>(ConfigGetReal(section, entry, defaultValue));
00207 }
00208
00209
00214 float LuaState::ConfigGetReal(const char* section, const char* entry,
00215 double defaultValue)
00216 {
00217 LuaAutoBlock block(*this);
00218
00219 LuaObject obj = GetGlobal(section);
00220 if (obj.IsNil())
00221 return (float)defaultValue;
00222 obj = obj.GetByName(entry);
00223 if (obj.IsNumber())
00224 return obj.GetNumber();
00225 return (float)defaultValue;
00226 }
00227
00228
00233 const char* LuaState::ConfigGetString(const char* section, const char* entry,
00234 const char* defaultValue)
00235 {
00236 LuaAutoBlock block(*this);
00237
00238 LuaObject obj = GetGlobal(section);
00239 if (obj.IsNil())
00240 return defaultValue;
00241 obj = obj.GetByName(entry);
00242 if (obj.IsString())
00243 return obj.GetString();
00244 return defaultValue;
00245 }
00246
00247
00251 void LuaState::ConfigSetInteger(const char* section, const char* entry, int value)
00252 {
00253 LuaAutoBlock block(*this);
00254
00255
00256
00257 LuaObject sectionTable = GetGlobal(section);
00258
00259
00260 if (sectionTable.IsNil())
00261 {
00262 sectionTable = GetGlobals().CreateTable(section);
00263 }
00264
00265 sectionTable.SetNumber(entry, value);
00266 }
00267
00268
00272 void LuaState::ConfigSetReal(const char* section, const char* entry, double value)
00273 {
00274 LuaAutoBlock block(*this);
00275
00276
00277
00278 LuaObject sectionTable = GetGlobal(section);
00279
00280
00281 if (sectionTable.IsNil())
00282 {
00283 sectionTable = GetGlobals().CreateTable(section);
00284 }
00285
00286 sectionTable.SetNumber(entry, value);
00287 }
00288
00289
00293 void LuaState::ConfigSetString(const char* section, const char* entry, const char* value)
00294 {
00295 LuaAutoBlock block(*this);
00296
00297
00298
00299 LuaObject sectionTable = GetGlobal(section);
00300
00301
00302 if (sectionTable.IsNil())
00303 {
00304 sectionTable = GetGlobals().CreateTable(section);
00305 }
00306
00307 sectionTable.SetString(entry, value);
00308 }
00309
00310
00314 static void IndentFile(LuaStateOutFile& file, unsigned int indentLevel)
00315 {
00316
00317 char spaces[500];
00318 for (unsigned int i = 0; i < indentLevel; ++i)
00319 spaces[i] = '\t';
00320 spaces[i] = 0;
00321 file.Print(spaces);
00322 }
00323
00324 bool LuaState::WriteLuaObject(FILE* stdioFile, const char* name, LuaObject value,
00325 int indentLevel, bool writeAll, bool alphabetical,
00326 bool writeTablePointers, unsigned int maxIndentLevel)
00327 {
00328 LuaStateOutFile file;
00329 file.Assign(stdioFile);
00330 WriteLuaObject(file, name, value, indentLevel, writeAll, alphabetical,
00331 writeTablePointers, maxIndentLevel);
00332 return false;
00333 }
00334
00335
00336 static void luaI_addquotedbinary (LuaStateOutFile& file, lua_State *L, const char* s, int l)
00337 {
00338 file.Print("%c", l_c('"'));
00339 while (l--)
00340 {
00341 switch (*s)
00342 {
00343 case l_c('"'): case l_c('\\'):
00344 file.Print("\\%c", *s);
00345 break;
00346 case l_c('\a'): file.Print("\\a"); break;
00347 case l_c('\b'): file.Print("\\b"); break;
00348 case l_c('\f'): file.Print("\\f"); break;
00349 case l_c('\n'): file.Print("\\n"); break;
00350 case l_c('\r'): file.Print("\\r"); break;
00351 case l_c('\t'): file.Print("\\t"); break;
00352 case l_c('\v'): file.Print("\\v"); break;
00353 default:
00354 if (isprint((BYTE)*s))
00355 file.Print("%c", *s);
00356 else
00357 {
00358 file.Print("\\%03d", (BYTE)*s);
00359 }
00360 }
00361 s++;
00362 }
00363 file.Print("%c", l_c('"'));
00364 }
00365
00366
00367 static void luaI_addquotedwidebinary (LuaStateOutFile& file, lua_State *L, const wchar_t* s, int l)
00368 {
00369 file.Print("L\"");
00370 while (l--)
00371 {
00372 switch (*s)
00373 {
00374 case l_uc('"'):
00375 case l_uc('\\'):
00376 file.Print("\\%c", *s);
00377 break;
00378 case l_uc('\a'): file.Print("\\a"); break;
00379 case l_uc('\b'): file.Print("\\b"); break;
00380 case l_uc('\f'): file.Print("\\f"); break;
00381 case l_uc('\n'): file.Print("\\n"); break;
00382 case l_uc('\r'): file.Print("\\r"); break;
00383 case l_uc('\t'): file.Print("\\t"); break;
00384 case l_uc('\v'): file.Print("\\v"); break;
00385 default:
00386 if (*s < 256 && isprint((BYTE)*s))
00387 {
00388 file.Print("%c", *s);
00389 }
00390 else
00391 {
00392 file.Print("\\x%04x", (DWORD)*s);
00393 }
00394 }
00395 s++;
00396 }
00397 file.Print("\"");
00398 }
00399
00400
00404 bool LuaState::WriteLuaObject(LuaStateOutFile& file, const char* name, LuaObject value,
00405 int indentLevel, bool writeAll, bool alphabetical,
00406 bool writeTablePointers, unsigned int maxIndentLevel)
00407 {
00408 LuaState script = value;
00409
00410
00411 if (value.IsNil())
00412 return false;
00413
00414
00415 if (value.IsUserData() || value.IsFunction() || value.IsCFunction())
00416 {
00417 if (writeAll && name)
00418 {
00419 if (value.IsUserData())
00420 file.Print("-- %s = '!!!USERDATA!!!'\n", name);
00421 else if (value.IsFunction())
00422 {
00423 lua_Debug ar;
00424 PushValue(value);
00425 lua_getinfo(m_state, ">S", &ar);
00426
00427 file.Print("-- %s = '!!!FUNCTION!!! %s %d'\n", name, ar.source, ar.linedefined);
00428 }
00429 else
00430 file.Print("-- %s = '!!!CFUNCTION!!!'\n", name);
00431 return true;
00432 }
00433 return false;
00434 }
00435
00436
00437 const unsigned int INDENT_SIZE = 1;
00438 const unsigned int indentSpaces = (indentLevel == -1 ? 0 : indentLevel) * INDENT_SIZE;
00439 IndentFile(file, indentSpaces);
00440
00441
00442 if (name)
00443 file.Print("%s = ", name);
00444
00445
00446 if (value.IsNumber())
00447 file.Print("%.16g", value.GetNumber());
00448
00449
00450 else if (value.IsString())
00451 {
00452 luaI_addquotedbinary(file, m_state, value.GetString(), value.StrLen());
00453 }
00454
00455
00456 else if (value.IsUString())
00457 {
00458 luaI_addquotedwidebinary(file, m_state, value.GetUString(), value.StrLen());
00459 }
00460
00461
00462 else if (value.IsTable())
00463 {
00464
00465 if (indentLevel != -1)
00466 {
00467 if (indentLevel < maxIndentLevel)
00468 {
00469 file.Print("\n");
00470 IndentFile(file, indentSpaces);
00471 }
00472 if (writeTablePointers)
00473 file.Print("{ --%8x\n", lua_topointer(m_state, value));
00474 else
00475 file.Print("{");
00476 if (indentLevel < maxIndentLevel)
00477 {
00478 file.Print("\n");
00479 }
00480 }
00481
00482
00483 LuaObject table = value;
00484
00485
00486
00487 int upperIndex = 1;
00488 bool wroteSemi = false;
00489 bool hasSequential = false;
00490
00491
00492 {
00493
00494 LuaAutoBlock block(*this);
00495
00496
00497 LuaObject value1 = table.GetByIndex(1);
00498 LuaObject value2 = table.GetByIndex(2);
00499
00500
00501 if (!value1.IsNil() && !value2.IsNil())
00502 {
00503
00504 bool firstSequential = true;
00505 for (; ; ++upperIndex)
00506 {
00507
00508 LuaAutoBlock block(*this);
00509
00510
00511 LuaObject value = table.GetByIndex(upperIndex);
00512
00513
00514 if (value.IsNil())
00515 break;
00516
00517
00518 if (!firstSequential && indentLevel != -1)
00519 {
00520 file.Print(",");
00521 if (indentLevel < maxIndentLevel)
00522 {
00523 file.Print("\n");
00524 }
00525 }
00526
00527
00528 WriteLuaObject(file, NULL, value, indentLevel + 1, writeAll, alphabetical, writeTablePointers, maxIndentLevel);
00529
00530
00531 firstSequential = false;
00532 }
00533 }
00534 }
00535
00536
00537 if (upperIndex > 1)
00538 {
00539 hasSequential = true;
00540 }
00541
00542 if (alphabetical)
00543 {
00544 std::list<std::string> keyNames;
00545
00546
00547 int i;
00548 PushNil();
00549 while ((i = Next(table)) != 0)
00550 {
00551 char keyName[255];
00552
00553
00554 LuaObject key(this, GetTop() - 1);
00555
00556
00557 if (key.IsNumber())
00558 {
00559
00560 if (hasSequential)
00561 {
00562
00563 float realNum = key.GetNumber();
00564 int intNum = (int)realNum;
00565 if (realNum == (float)intNum)
00566 {
00567
00568 if (intNum >= 1 && intNum < upperIndex)
00569 {
00570
00571
00572 Pop();
00573 continue;
00574 }
00575 }
00576 }
00577
00578
00579 sprintf(keyName, "[%.16g]", key.GetNumber());
00580 }
00581 else
00582 {
00583
00584 const char* ptr = key.GetString();
00585 bool isAlphaNumeric = true;
00586 while (*ptr)
00587 {
00588 if (!isalnum(*ptr) && *ptr != '_')
00589 {
00590 isAlphaNumeric = false;
00591 break;
00592 }
00593 ptr++;
00594 }
00595 if (isAlphaNumeric)
00596 strcpy(keyName, key.GetString());
00597 else
00598 sprintf(keyName, "[\"%s\"]", key.GetString());
00599 }
00600
00601 keyNames.push_back(keyName);
00602
00603
00604 Pop();
00605 }
00606
00607 keyNames.sort();
00608
00609 if (keyNames.size() > 0)
00610 {
00611
00612
00613
00614 if (hasSequential && indentLevel != -1)
00615 {
00616
00617 file.Print(", ;");
00618 if (indentLevel < maxIndentLevel)
00619 {
00620 file.Print("\n");
00621 }
00622 wroteSemi = true;
00623 }
00624 }
00625
00626 for(std::list<std::string>::iterator it = keyNames.begin(); it != keyNames.end(); ++it)
00627 {
00628 LuaAutoBlock autoBlock(*this);
00629 const std::string& keyFullName = (*it);
00630
00631 LuaObject value = table;
00632 if (keyFullName[0] == '[')
00633 {
00634 if (keyFullName[1] == '"')
00635 {
00636 std::string keyName = keyFullName.substr(2, keyFullName.size() - 4);
00637 value = table.GetByName(keyName.c_str());
00638 }
00639 else
00640 {
00641 std::string keyName = keyFullName.substr(1, keyFullName.size() - 2);
00642 int number = atoi(keyName.c_str());
00643 value = table.GetByIndex(number);
00644 }
00645 }
00646 else
00647 {
00648 value = table.GetByName(keyFullName.c_str());
00649 }
00650
00651
00652 bool ret = WriteLuaObject(file, keyFullName.c_str(), value, indentLevel + 1, writeAll, alphabetical, writeTablePointers, maxIndentLevel);
00653
00654
00655 if (indentLevel != -1 && ret)
00656 {
00657 file.Print(",");
00658 if (indentLevel < maxIndentLevel)
00659 {
00660 file.Print("\n");
00661 }
00662 }
00663 }
00664 }
00665 else
00666 {
00667
00668 int i;
00669 PushNil();
00670 while ((i = Next(table)) != 0)
00671 {
00672 char keyName[255];
00673
00674
00675 LuaObject key(this, GetTop() - 1);
00676 LuaObject value(this, GetTop());
00677
00678
00679 if (key.IsNumber())
00680 {
00681
00682 if (hasSequential)
00683 {
00684
00685 float realNum = key.GetNumber();
00686 int intNum = (int)realNum;
00687 if (realNum == (float)intNum)
00688 {
00689
00690 if (intNum >= 1 && intNum < upperIndex)
00691 {
00692
00693
00694 Pop();
00695 continue;
00696 }
00697 }
00698 }
00699
00700
00701 sprintf(keyName, "[%.16g]", key.GetNumber());
00702 }
00703 else
00704 {
00705
00706 const char* ptr = key.GetString();
00707 bool isAlphaNumeric = true;
00708 while (*ptr)
00709 {
00710 if (!isalnum(*ptr) && *ptr != '_')
00711 {
00712 isAlphaNumeric = false;
00713 break;
00714 }
00715 ptr++;
00716 }
00717 if (isAlphaNumeric)
00718 strcpy(keyName, key.GetString());
00719 else
00720 sprintf(keyName, "[\"%s\"]", key.GetString());
00721 }
00722
00723
00724
00725
00726 if (hasSequential && !value.IsNil() && !wroteSemi)
00727 {
00728
00729 if (indentLevel != -1)
00730 {
00731 file.Print(", ;");
00732 if (indentLevel < maxIndentLevel)
00733 {
00734 file.Print("\n");
00735 }
00736 }
00737 wroteSemi = true;
00738 }
00739
00740
00741 bool ret = WriteLuaObject(file, keyName, value, indentLevel + 1, writeAll, alphabetical, writeTablePointers, maxIndentLevel);
00742
00743
00744 if (ret && indentLevel != -1)
00745 {
00746 file.Print(",");
00747 if (indentLevel < maxIndentLevel)
00748 {
00749 file.Print("\n");
00750 }
00751 }
00752
00753
00754 Pop();
00755 }
00756 }
00757
00758
00759
00760 if (hasSequential && !wroteSemi && indentLevel != -1)
00761 {
00762 file.Print(",");
00763 if (indentLevel < maxIndentLevel)
00764 {
00765 file.Print("\n");
00766 }
00767 }
00768
00769
00770 IndentFile(file, indentSpaces);
00771
00772
00773 if (indentLevel == 0)
00774 {
00775
00776 file.Print("}");
00777 if (indentLevel < maxIndentLevel)
00778 {
00779 file.Print("\n\n", file);
00780 }
00781 }
00782 else if (indentLevel > 0)
00783 {
00784
00785
00786 file.Print("}");
00787 }
00788 }
00789
00790
00791
00792 if (indentLevel == 0)
00793 {
00794 if (indentLevel < maxIndentLevel)
00795 {
00796 file.Print("\n");
00797 }
00798 }
00799
00800 return true;
00801 }
00802
00803
00807 void LuaState::WriteLuaGlobalsFile(const char* filename, bool writeAll,
00808 bool alphabetical, bool writeTablePointers,
00809 unsigned int maxIndentLevel)
00810 {
00811
00812 LuaAutoBlock block(*this);
00813
00814 WriteLuaFile(filename, NULL, GetGlobals(), -1, writeAll, alphabetical,
00815 writeTablePointers, maxIndentLevel);
00816 }
00817
00818
00822 void LuaState::WriteLuaFile(const char* filename, const char* name, LuaObject value,
00823 int indentLevel, bool writeAll, bool alphabetical,
00824 bool writeTablePointers, unsigned int maxIndentLevel)
00825 {
00826
00827 LuaStateOutFile file;
00828 file.Open(filename);
00829
00830
00831 LuaAutoBlock block(*this);
00832
00833
00834 WriteLuaObject(file, name, value, indentLevel, writeAll, alphabetical,
00835 writeTablePointers, maxIndentLevel);
00836 }
00837
00838