hbpreprocessor.cpp 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231
  1. /**
  2. * @file hbpreprocessor.cpp
  3. * @brief HBPreprocessor class implementation
  4. *
  5. * HBPreprocessor is a simple sources pre-processor with support for #include,
  6. * #define (plain defines, no macros)/#undef/#if/#ifdef/#ifndef/#elif/#else/
  7. * #endif/#warning/#error directives (it also got special #pragma's).
  8. * It is of course not as complete as boost::wave, but it is about 20 times
  9. * smaller (when comparing stripped binaries).
  10. * It can be used to preprocess Lua or LSL source files, for example.
  11. *
  12. * $LicenseInfo:firstyear=2019&license=viewergpl$
  13. *
  14. * Copyright (c) 2019, Henri Beauchamp.
  15. *
  16. * Second Life Viewer Source Code
  17. * The source code in this file ("Source Code") is provided by Linden Lab
  18. * to you under the terms of the GNU General Public License, version 2.0
  19. * ("GPL"), unless you have obtained a separate licensing agreement
  20. * ("Other License"), formally executed by you and Linden Lab. Terms of
  21. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  22. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  23. *
  24. * There are special exceptions to the terms and conditions of the GPL as
  25. * it is applied to this Source Code. View the full text of the exception
  26. * in the file doc/FLOSS-exception.txt in this software distribution, or
  27. * online at
  28. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  29. *
  30. * By copying, modifying or distributing this software, you acknowledge
  31. * that you have read and understood your obligations described above,
  32. * and agree to abide by those obligations.
  33. *
  34. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  35. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  36. * COMPLETENESS OR PERFORMANCE.
  37. * $/LicenseInfo$
  38. */
  39. #include "llviewerprecompiledheaders.h"
  40. #include <stdlib.h> // For atof() and atoi()
  41. #include "lua.hpp"
  42. #include "hbpreprocessor.h"
  43. #include "lldir.h"
  44. #include "lltimer.h"
  45. #include "llagent.h"
  46. #include "llappviewer.h" // For gSecondLife, gViewerVersion*
  47. #include "llviewercontrol.h"
  48. // Helper functions
  49. std::string get_one_line(const std::string& buffer, size_t& pos)
  50. {
  51. std::string line;
  52. char c;
  53. size_t len = buffer.length();
  54. while (pos < len)
  55. {
  56. c = buffer[pos++];
  57. line += c;
  58. if (c == '\n')
  59. {
  60. break;
  61. }
  62. }
  63. return line;
  64. }
  65. // Skips all spaces/tabs in 'line' and changes 'pos' to point on the first
  66. // non-spacing character.
  67. static void skip_spacing(const std::string& line, size_t& pos)
  68. {
  69. size_t len = line.length();
  70. while (pos < len)
  71. {
  72. char c = line[pos];
  73. if (c != ' ' && c != '\t')
  74. {
  75. break;
  76. }
  77. ++pos;
  78. }
  79. }
  80. // Attempts to find a preprocessor directive in 'line': valid directives shall
  81. // be prefixed with a '#' that must be the first non-spacing character in
  82. // 'line', the '#' itself may be followed with spacing characters before the
  83. // directive name. When the directive accepts arguments, they must be separated
  84. // from its name with spacing characters.
  85. // This function returns false when it cannot find a directive-like statement
  86. // in 'line'. When a potential directive is found, it returns true with the
  87. // directive name in 'directive' and its argument in 'argument' (empty string
  88. // when no argument is found).
  89. static bool is_directive(const std::string& line, std::string& directive,
  90. std::string& argument, bool directive_only = false)
  91. {
  92. // Skip all spaces/tabs till the start of a word.
  93. size_t i = 0;
  94. skip_spacing(line, i);
  95. size_t len = line.length();
  96. if (i >= len || line[i] != '#')
  97. {
  98. return false;
  99. }
  100. ++i; // Skip the '#'...
  101. skip_spacing(line, i); // ... and any spacing till the start of a word.
  102. // Get the directive name, which must be separated with spacing from its
  103. // arguments, when present.
  104. directive.clear();
  105. while (i < len)
  106. {
  107. char c = line[i++];
  108. if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
  109. {
  110. break;
  111. }
  112. directive += c;
  113. }
  114. if (directive_only)
  115. {
  116. return true;
  117. }
  118. // Skip arguments spacing, possibly
  119. skip_spacing(line, i);
  120. // If any argument is present, get it
  121. argument.clear();
  122. if (i + 1 < len)
  123. {
  124. argument = line.substr(i);
  125. // Strip trailing spacing or end of line characters
  126. len = argument.length();
  127. // Note: size_t is most often an unsigned int, so we cannot use i here.
  128. S32 j = len;
  129. while (--j >= 0)
  130. {
  131. char c = argument[j];
  132. if (c != ' ' && c != '\t' && c != '\r' && c != '\n')
  133. {
  134. break;
  135. }
  136. }
  137. if (j < 0)
  138. {
  139. argument.clear();
  140. }
  141. else if ((size_t)j + 1 < len)
  142. {
  143. argument.erase(j + 1);
  144. }
  145. }
  146. return true;
  147. }
  148. // Attempts to get a define name and the expression/value following it in
  149. // 'line', i.e. something in the form "DEFINE_NAME expression or value".
  150. // Note that macros (e.g. "MACRO_NAME(x, y, z)") are not accepted as valid
  151. // defines.
  152. static std::string get_define_and_value(const std::string& line,
  153. std::string& value)
  154. {
  155. size_t len = line.length();
  156. // Get the define name
  157. std::string define;
  158. size_t i = 0;
  159. while (i < len)
  160. {
  161. char c = line[i++];
  162. if (c != '_' && !LLStringOps::isAlnum(c))
  163. {
  164. break;
  165. }
  166. define += c;
  167. }
  168. // Skip all spaces/tabs
  169. skip_spacing(line, i);
  170. if (i < len)
  171. {
  172. value = line.substr(i);
  173. }
  174. else
  175. {
  176. value.clear();
  177. }
  178. return define;
  179. }
  180. // HBPreprocessor class proper
  181. HBPreprocessor::HBPreprocessor(const std::string& file_name,
  182. HBPPIncludeCB callback, void* userdata)
  183. : mFilename(file_name),
  184. mCurrentLine(0),
  185. mRootIncludeLine(0),
  186. mSavedPos(0),
  187. mIncludeCallback(callback),
  188. mMessageCallback(NULL),
  189. mCallbackUserData(userdata)
  190. {
  191. if (!mIncludeCallback)
  192. {
  193. llerrs << "A non-NULL #include callback must be passed !" << llendl;
  194. }
  195. // Do not allow to define defined()...
  196. mForbiddenTokens.emplace("defined");
  197. // These are special, read-only defines:
  198. mForbiddenTokens.emplace("__DATE__");
  199. mForbiddenTokens.emplace("__TIME__");
  200. mForbiddenTokens.emplace("__FILE__");
  201. mForbiddenTokens.emplace("__LINE__");
  202. mForbiddenTokens.emplace("__AGENT_ID__");
  203. mForbiddenTokens.emplace("__AGENT_NAME__");
  204. mForbiddenTokens.emplace("__VIEWER_NAME__");
  205. mForbiddenTokens.emplace("__VIEWER_VERSION__");
  206. mForbiddenTokens.emplace("__VIEWER_VERNUM__");
  207. mLuaState = luaL_newstate();
  208. if (!mLuaState)
  209. {
  210. llwarns << "Failure to allocate a new Lua state !" << llendl;
  211. llassert(false);
  212. }
  213. }
  214. HBPreprocessor::~HBPreprocessor()
  215. {
  216. if (mLuaState)
  217. {
  218. lua_settop(mLuaState, 0);
  219. lua_close(mLuaState);
  220. }
  221. }
  222. bool HBPreprocessor::isValidToken(const std::string& token)
  223. {
  224. if (token.empty() || mForbiddenTokens.count(token))
  225. {
  226. return false;
  227. }
  228. for (size_t i = 0, len = token.length(); i < len; ++i)
  229. {
  230. char c = token[i];
  231. if (i > 0 && LLStringOps::isDigit(c))
  232. {
  233. continue;
  234. }
  235. if (c != '_' && !LLStringOps::isAlpha(c))
  236. {
  237. return false;
  238. }
  239. }
  240. return true;
  241. }
  242. bool HBPreprocessor::isExpressionTrue(std::string expression)
  243. {
  244. LL_DEBUGS("Preprocessor") << "Evaluating expression: " << expression
  245. << LL_ENDL;
  246. if (!mLuaState)
  247. {
  248. return atof(expression.c_str()) != 0.f;
  249. }
  250. lua_settop(mLuaState, 0); // Empty the stack
  251. // Translate C operators into Lua ones
  252. LLStringUtil::replaceString(expression, "!=", "~=");
  253. LLStringUtil::replaceString(expression, "||", " or ");
  254. LLStringUtil::replaceString(expression, "&&", " and ");
  255. LLStringUtil::replaceString(expression, "!", " not ");
  256. LLStringUtil::replaceString(expression, "^", "~");
  257. LL_DEBUGS("Preprocessor") << "Lua translated expression: " << expression
  258. << LL_ENDL;
  259. // Use the expression and assign it to a Lua global variable.
  260. expression = "V_EVAL_PP_EXPRESSION=" + expression;
  261. if (luaL_loadstring(mLuaState, expression.c_str()) != LUA_OK)
  262. {
  263. LL_DEBUGS("Preprocessor") << "Lua error loading expression: "
  264. << lua_tostring(mLuaState, -1) << LL_ENDL;
  265. return false;
  266. }
  267. if (lua_pcall(mLuaState, 0, LUA_MULTRET, 0) != LUA_OK)
  268. {
  269. LL_DEBUGS("Preprocessor") << "Lua error evaluationg expression: "
  270. << lua_tostring(mLuaState, -1) << LL_ENDL;
  271. return false;
  272. }
  273. // Put the variable contents on the Lua stack
  274. lua_getglobal(mLuaState, "V_EVAL_PP_EXPRESSION");
  275. bool success;
  276. // WARNING: under Lua 0 is true, not false, thus why we *must* check the
  277. // type of the value resulting from the expression evaluation and take
  278. // appropriate decisions.
  279. int type = lua_type(mLuaState, -1);
  280. switch (type)
  281. {
  282. case LUA_TNIL:
  283. success = false;
  284. break;
  285. case LUA_TBOOLEAN:
  286. success = lua_toboolean(mLuaState, -1);
  287. break;
  288. case LUA_TNUMBER:
  289. success = lua_tonumber(mLuaState, -1) != 0.f;
  290. break;
  291. case LUA_TSTRING:
  292. // Note: what if the string is "0.0", for example ?... Should we
  293. // check for this ?
  294. success = strlen(lua_tostring(mLuaState, -1)) != 0;
  295. break;
  296. default:
  297. // Tables, etc... Let's consider "something" is "true"
  298. success = true;
  299. }
  300. LL_DEBUGS("Preprocessor") << "Expression is "
  301. << (success ? "true" : "false") << LL_ENDL;
  302. return success;
  303. }
  304. //static
  305. bool HBPreprocessor::evaluate(std::string& expression, lua_State* statep)
  306. {
  307. if (expression.empty())
  308. {
  309. return true; // Nothing to do !
  310. }
  311. bool allocated_lua_state = false;
  312. if (!statep)
  313. {
  314. statep = luaL_newstate();
  315. allocated_lua_state = true;
  316. }
  317. if (!statep)
  318. {
  319. // This should never happen, unless all memory is exhausted...
  320. return false;
  321. }
  322. // Make sure the math module is loaded...
  323. luaL_requiref(statep, LUA_MATHLIBNAME, luaopen_math, 1);
  324. lua_settop(statep, 0);
  325. // Remove tabs and trim spaces.
  326. LLStringUtil::replaceString(expression, "\t", " ");
  327. LLStringUtil::trim(expression);
  328. LL_DEBUGS("Preprocessor") << "Evaluating math expression: " << expression
  329. << LL_ENDL;
  330. // Translate C-style math function with Lua ones.
  331. // We need to avoid replacing 'acos() with 'math.a.math.cos()' and other
  332. // such weirdness, and since I am lazy and do not want to write a proper
  333. // math functions parser for such cases, let's do a two steps brute-force
  334. // replacement for such math functions...
  335. LLStringUtil::replaceString(expression, "acos(", "MATH.ACOS(");
  336. LLStringUtil::replaceString(expression, "cos(", "math.cos(");
  337. LLStringUtil::replaceString(expression, "MATH.ACOS(", "math.acos(");
  338. LLStringUtil::replaceString(expression, "asin(", "MATH.ASIN(");
  339. LLStringUtil::replaceString(expression, "sin(", "math.sin(");
  340. LLStringUtil::replaceString(expression, "MATH.ASIN(", "math.asin(");
  341. LLStringUtil::replaceString(expression, "atan(", "MATH.ATAN(");
  342. LLStringUtil::replaceString(expression, "tan(", "math.tan(");
  343. LLStringUtil::replaceString(expression, "MATH.ATAN(", "math.atan(");
  344. LLStringUtil::replaceString(expression, "fabs(", "MATH.ABS(");
  345. LLStringUtil::replaceString(expression, "abs(", "MATH.ABS(");
  346. LLStringUtil::replaceString(expression, "MATH.ABS(", "math.abs(");
  347. LLStringUtil::replaceString(expression, "fmod(", "MATH.FMOD(");
  348. LLStringUtil::replaceString(expression, "mod(", "MATH.FMOD(");
  349. LLStringUtil::replaceString(expression, "MATH.FMOD(", "math.fmod(");
  350. // Deal with the unambiguous function names, now...
  351. LLStringUtil::replaceString(expression, "max(", "math.max(");
  352. LLStringUtil::replaceString(expression, "min(", "math.min(");
  353. LLStringUtil::replaceString(expression, "ceil(", "math.ceil(");
  354. LLStringUtil::replaceString(expression, "floor(", "math.floor(");
  355. LLStringUtil::replaceString(expression, "int(", "math.tointeger(");
  356. LLStringUtil::replaceString(expression, "deg(", "math.deg(");
  357. LLStringUtil::replaceString(expression, "rad(", "math.rad(");
  358. LLStringUtil::replaceString(expression, "sqrt(", "math.sqrt(");
  359. LLStringUtil::replaceString(expression, "exp(", "math.exp(");
  360. LLStringUtil::replaceString(expression, "log(", "math.log(");
  361. LLStringUtil::replaceString(expression, "rand(", "math.random(");
  362. // Also accept PI...
  363. LLStringUtil::replaceString(expression, "PI", "math.pi");
  364. LL_DEBUGS("Preprocessor") << "Lua translated expression: " << expression
  365. << LL_ENDL;
  366. // Use the expression and assign it to a Lua global variable.
  367. expression = "V_EVAL_PP_EXPRESSION=" + expression;
  368. bool success = true;
  369. if (luaL_loadstring(statep, expression.c_str()) != LUA_OK)
  370. {
  371. LL_DEBUGS("Preprocessor") << "Lua error loading expression: "
  372. << expression << LL_ENDL;
  373. success = false;
  374. }
  375. else if (lua_pcall(statep, 0, LUA_MULTRET, 0) != LUA_OK)
  376. {
  377. LL_DEBUGS("Preprocessor") << "Lua error evaluationg expression: "
  378. << expression << LL_ENDL;
  379. success = false;
  380. }
  381. else
  382. {
  383. // Put the variable contents on the Lua stack and retreive it as a
  384. // string.
  385. lua_getglobal(statep, "V_EVAL_PP_EXPRESSION");
  386. expression = lua_tostring(statep, -1);
  387. LL_DEBUGS("Preprocessor") << "Result: " << expression << LL_ENDL;
  388. // Let's report math errors as a failure.
  389. success = expression != "nan" && expression != "-nan";
  390. }
  391. // Empty the stack (in case the user would have added Lua functions
  392. // returning several values on the stack, such as math.modf()).
  393. lua_settop(statep, 0);
  394. if (allocated_lua_state)
  395. {
  396. lua_close(statep);
  397. }
  398. return success;
  399. }
  400. std::string HBPreprocessor::replaceEvalInExpr(std::string expr,
  401. bool replace_tokens)
  402. {
  403. if (expr.empty())
  404. {
  405. return "";
  406. }
  407. LL_DEBUGS("Preprocessor") << "Raw expression: " << expr << LL_ENDL;
  408. std::string result;
  409. size_t i;
  410. while ((i = expr.find("eval(")) != std::string::npos)
  411. {
  412. // Search for the matching closing parenthesis.
  413. size_t j = std::string::npos;
  414. U32 n = 1; // Number of opening parenthesis found so far.
  415. for (size_t k = i + 5, l = expr.size(); k < l; ++k)
  416. {
  417. if (expr[k] == ')')
  418. {
  419. if (--n == 0)
  420. {
  421. j = k;
  422. break;
  423. }
  424. }
  425. else if (expr[k] == '(')
  426. {
  427. ++n;
  428. }
  429. }
  430. if (j == std::string::npos)
  431. {
  432. parsingError("No matching closing parenthesis for eval()");
  433. return "";
  434. }
  435. result = expr.substr(i + 5, j - i - 5);
  436. if (replace_tokens)
  437. {
  438. // Replace any #defined tokens inside the eval() expression with
  439. // their value.
  440. result = replaceDefinesInLine(result);
  441. }
  442. if (!evaluate(result, mLuaState))
  443. {
  444. parsingError("Error while evaluating the math expression in eval()");
  445. return "";
  446. }
  447. expr = expr.substr(0, i) + result + expr.substr(j + 1);
  448. }
  449. LL_DEBUGS("Preprocessor") << "Processed expression: " << expr << LL_ENDL;
  450. return expr;
  451. }
  452. std::string HBPreprocessor::getDefine(const std::string& name) const
  453. {
  454. if (name == "__FILE__")
  455. {
  456. return mFilenames.empty() ? "" : mFilenames.top();
  457. }
  458. else if (name == "__LINE__")
  459. {
  460. return llformat("%d", mCurrentLine);
  461. }
  462. else if (!name.empty())
  463. {
  464. defines_map_t::const_iterator it = mDefines.find(name);
  465. if (it != mDefines.end())
  466. {
  467. return it->second;
  468. }
  469. }
  470. return name;
  471. }
  472. std::string HBPreprocessor::replaceDefinedInExpr(std::string expr)
  473. {
  474. if (expr.empty())
  475. {
  476. // It is OK to return "0" (and not an Lua "false"), because even though
  477. // 0 == true under Lua, we retrieve this value as a number, not as a
  478. // boolean, and we do properly consider a 0 number as "false".
  479. // Note that this will work as well for atof() when Lua is not used.
  480. return "0";
  481. }
  482. LL_DEBUGS("Preprocessor") << "Raw expression: " << expr << LL_ENDL;
  483. std::string token;
  484. size_t i;
  485. while ((i = expr.find("defined(")) != std::string::npos)
  486. {
  487. size_t j = expr.find(')', i);
  488. if (j == std::string::npos)
  489. {
  490. parsingError("No matching closing parenthesis for defined()");
  491. return "";
  492. }
  493. token = expr.substr(i + 8, j - i - 8);
  494. LLStringUtil::replaceString(token, "\t", " ");
  495. LLStringUtil::trim(token);
  496. token = mDefines.count(token) ? "true" : "false";
  497. expr = expr.substr(0, i) + token + expr.substr(j + 1);
  498. }
  499. LL_DEBUGS("Preprocessor") << "Processed expression: " << expr << LL_ENDL;
  500. return expr;
  501. }
  502. std::string HBPreprocessor::replaceDefinesInLine(const std::string& line)
  503. {
  504. if (line.empty() || line == "\n" || line == "\r\n")
  505. {
  506. return line;
  507. }
  508. LL_DEBUGS("Preprocessor") << "Unprocessed line: "
  509. << line.substr(0, line.find_first_of("\n\r"))
  510. << LL_ENDL;
  511. std::string result, word, value;
  512. size_t len = line.length();
  513. size_t pos = 0;
  514. bool in_quotes = false;
  515. bool in_double_quotes = false;
  516. bool escaped = false;
  517. bool valid_word_char;
  518. while (pos < len)
  519. {
  520. char c = line[pos++];
  521. valid_word_char = LLStringUtil::isPartOfWord(c);
  522. if (!valid_word_char)
  523. {
  524. if (!word.empty())
  525. {
  526. result += getDefine(word);
  527. word.clear();
  528. }
  529. result += c;
  530. }
  531. if (c == '\\') // Invalid char, so already added to result
  532. {
  533. escaped = !escaped;
  534. continue;
  535. }
  536. if (escaped)
  537. {
  538. if (valid_word_char) // Valid char, so not yet added to result
  539. {
  540. result += c;
  541. }
  542. escaped = false;
  543. continue;
  544. }
  545. if (c == '\'') // Invalid char, so already added to result
  546. {
  547. in_quotes = !in_quotes && !in_double_quotes;
  548. continue;
  549. }
  550. if (c == '"') // Invalid char, so already added to result
  551. {
  552. in_double_quotes = !in_double_quotes && !in_quotes;
  553. continue;
  554. }
  555. if (valid_word_char)
  556. {
  557. if (!in_quotes && !in_double_quotes)
  558. {
  559. word += c;
  560. }
  561. else
  562. {
  563. result += c;
  564. }
  565. }
  566. }
  567. if (!word.empty())
  568. {
  569. result += getDefine(word);
  570. }
  571. LL_DEBUGS("Preprocessor") << "Preprocessed line: "
  572. << result.substr(0, result.find_first_of("\n\r"))
  573. << LL_ENDL;
  574. return result;
  575. }
  576. void HBPreprocessor::parsingError(const std::string& message, bool is_warning)
  577. {
  578. std::string msg =
  579. llformat("File: %s - Line: %d - ",
  580. mFilenames.empty() ? "?" : mFilenames.top().c_str(),
  581. mCurrentLine) + message;
  582. if (!is_warning)
  583. {
  584. mErrorMessage = msg;
  585. }
  586. llwarns << msg << llendl;
  587. if (mMessageCallback)
  588. {
  589. mMessageCallback(msg, is_warning, mCallbackUserData);
  590. }
  591. }
  592. bool HBPreprocessor::skipToElseOrEndif(const std::string& buffer, size_t& pos)
  593. {
  594. S32 level = 0; // Number of nested #if* directives
  595. size_t len = buffer.length();
  596. std::string line, directive, argument;
  597. while (pos < len)
  598. {
  599. size_t old_pos = pos; // Keep old position for #elif
  600. line = get_one_line(buffer, pos);
  601. if (line.empty()) // This should never happen...
  602. {
  603. parsingError("Internal error in get_one_line(): empty line returned");
  604. return false;
  605. }
  606. ++mCurrentLine;
  607. if (!is_directive(line, directive, argument))
  608. {
  609. continue;
  610. }
  611. // Check for #include boundary
  612. if (directive == "endinclude")
  613. {
  614. LL_DEBUGS("Preprocessor") << "Found #endinclude " << argument
  615. << LL_ENDL;
  616. parsingError("Matching #endif not found.");
  617. return false;
  618. }
  619. if (level == 0) // Ignore all deeper levels
  620. {
  621. if (directive == "else" || directive == "elif")
  622. {
  623. LL_DEBUGS("Preprocessor") << "Found a #" << directive
  624. << " " << argument << LL_ENDL;
  625. // Only take them into account when the matching #if failed
  626. if (mIfClauses.empty()) // This should never happen...
  627. {
  628. parsingError("Internal error: #if clauses stack empty.");
  629. return false;
  630. }
  631. if (!mIfClauses.top())
  632. {
  633. // We found the matching #else or #elif and must execute
  634. // (what follows) it.
  635. if (directive == "elif")
  636. {
  637. // We must evaluate the #elif, so restore its position
  638. pos = old_pos;
  639. --mCurrentLine;
  640. }
  641. return true;
  642. }
  643. }
  644. else if (directive == "endif")
  645. {
  646. LL_DEBUGS("Preprocessor") << "Found a #endif" << LL_ENDL;
  647. if (mIfClauses.empty()) // This should never happen...
  648. {
  649. parsingError("Internal error: #if clauses stack empty.");
  650. return false;
  651. }
  652. mIfClauses.pop();
  653. return true;
  654. }
  655. }
  656. if (directive.find("if") == 0)
  657. {
  658. LL_DEBUGS("Preprocessor") << "Found a new #" << directive
  659. << ", incrementing level." << LL_ENDL;
  660. ++level;
  661. }
  662. else if (directive == "endif")
  663. {
  664. LL_DEBUGS("Preprocessor") << "Found an #endif, decrementing level."
  665. << LL_ENDL;
  666. --level;
  667. if (level < 0)
  668. {
  669. parsingError("Found #endif without matching #if");
  670. return false;
  671. }
  672. }
  673. }
  674. parsingError("Matching #endif not found.");
  675. return false;
  676. }
  677. void HBPreprocessor::clear()
  678. {
  679. // Reset our member variables
  680. mPreprocessed.clear();
  681. mLineMapping.clear();
  682. mIncludeBuffer.clear();
  683. mIncludes.clear();
  684. mDefaultIncludePath.clear();
  685. mErrorMessage.clear();
  686. while (!mIfClauses.empty())
  687. {
  688. mIfClauses.pop();
  689. }
  690. while (!mFilenames.empty())
  691. {
  692. mFilenames.pop();
  693. }
  694. mCurrentLine = mRootIncludeLine = mSavedPos = 0;
  695. }
  696. // Note that __FILE__ and __LINE__ are "dynamic" (they change during the
  697. // preprocessing of the sources) and not set by setDefaultDefines(), but
  698. // instead replaced explicitely in replaceDefinesInLine().
  699. void HBPreprocessor::setDefaultDefines()
  700. {
  701. std::string format, temp;
  702. mDefines.clear();
  703. // Get the local time
  704. struct tm* internal_time;
  705. time_t local_time = computer_time();
  706. internal_time = local_time_to_tm(local_time);
  707. // Format the date, following the user's preferences
  708. format = "\"" + gSavedSettings.getString("ShortDateFormat") + "\"";
  709. timeStructToFormattedString(internal_time, format, temp);
  710. mDefines["__DATE__"] = temp;
  711. // Format the time, following the user's preferences
  712. format = "\"" + gSavedSettings.getString("LongTimeFormat") + "\"";
  713. timeStructToFormattedString(internal_time, format, temp);
  714. mDefines["__TIME__"] = temp;
  715. mDefines["__AGENT_ID__"] = "\"" + gAgentID.asString() + "\"";
  716. gAgent.getName(temp);
  717. mDefines["__AGENT_NAME__"] = "\"" + temp + "\"";
  718. mDefines["__VIEWER_NAME__"] = "\"" + gSecondLife + "\"";
  719. mDefines["__VIEWER_VERSION__"] = "\"" + gViewerVersionString + "\"";
  720. mDefines["__VIEWER_VERNUM__"] = llformat("%lu", gViewerVersionNumber);
  721. }
  722. S32 HBPreprocessor::preprocess(const std::string& sources)
  723. {
  724. clear();
  725. // Set current filename and line number:
  726. mFilenames.emplace("\"" + mFilename + "\"");
  727. // Set the default defines
  728. setDefaultDefines();
  729. // Initialise the sources buffer and position
  730. mSourcesBuffer = sources;
  731. return resume();
  732. }
  733. S32 HBPreprocessor::resume()
  734. {
  735. // Preprocessing is always enabled on resume (since, even if paused, it was
  736. // the result of an #include interpretation, and it was therefore enabled
  737. // when it happened).
  738. bool enabled = true;
  739. std::string line, directive, argument;
  740. size_t pos = mSavedPos;
  741. size_t len = mSourcesBuffer.length();
  742. while (pos < len)
  743. {
  744. mSavedPos = pos; // Preserve in case of PAUSED event
  745. ++mCurrentLine;
  746. line = get_one_line(mSourcesBuffer, pos);
  747. if (line.empty()) // This should never happen...
  748. {
  749. parsingError("Internal error in get_one_line(): empty line returned");
  750. return FAILURE;
  751. }
  752. if (mCurrentLine == 1 && line.find("#!") == 0)
  753. {
  754. // This is a shebang line, just ignore it and continue
  755. continue;
  756. }
  757. // If it is not a pre-processor directive, just store the line in the
  758. // processed buffer and continue with next line.
  759. if (!is_directive(line, directive, argument))
  760. {
  761. if (enabled)
  762. {
  763. // Proceed to replace all #defined tokens with their value in
  764. // that line
  765. line = replaceDefinesInLine(line);
  766. }
  767. mPreprocessed += line;
  768. if (mFilenames.size() == 1)
  769. {
  770. // We are processing the original sources: map this newly
  771. // inserted preprocessed line with the line in the said
  772. // sources.
  773. mLineMapping.push_back(mCurrentLine);
  774. }
  775. else
  776. {
  777. // We are processing an #include: map this newly inserted
  778. // preprocessed line with the line of the root #include
  779. // directive in the original (unprocessed) sources.
  780. mLineMapping.push_back(mRootIncludeLine);
  781. }
  782. continue;
  783. }
  784. if (directive == "endinclude")
  785. {
  786. LL_DEBUGS("Preprocessor") << "Found #endinclude " << argument
  787. << LL_ENDL;
  788. mCurrentLine = atoi(argument.c_str());
  789. if (!enabled)
  790. {
  791. parsingError("Missing directive '#pragma preprocessor-on' at end of file");
  792. return FAILURE;
  793. }
  794. else if (mFilenames.size() < 2)
  795. {
  796. parsingError("Unexpected directive #endinclude " + argument);
  797. return FAILURE;
  798. }
  799. else if (mCurrentLine <= 0)
  800. {
  801. parsingError("Invalid directive #endinclude " + argument);
  802. return FAILURE;
  803. }
  804. mFilenames.pop();
  805. continue;
  806. }
  807. if (directive == "pragma")
  808. {
  809. LL_DEBUGS("Preprocessor") << "Found #pragma " << argument
  810. << LL_ENDL;
  811. if (argument.find("preprocessor-on") == 0)
  812. {
  813. LL_DEBUGS("Preprocessor") << "Preprocessing enabled"
  814. << LL_ENDL;
  815. enabled = true;
  816. }
  817. else if (enabled && argument.find("preprocessor-off") == 0)
  818. {
  819. LL_DEBUGS("Preprocessor") << "Preprocessing disabled"
  820. << LL_ENDL;
  821. enabled = false;
  822. }
  823. else if (enabled && argument.length() > 14 &&
  824. argument.find("include-from: ") == 0)
  825. {
  826. mDefaultIncludePath = argument.substr(14);
  827. LL_DEBUGS("Preprocessor") << "Default include path set to: "
  828. << mDefaultIncludePath << LL_ENDL;
  829. }
  830. continue;
  831. }
  832. // If preprocessing is disabled, simply consider the directive is
  833. // a normal line
  834. if (!enabled)
  835. {
  836. mPreprocessed += line;
  837. if (mFilenames.size() == 1)
  838. {
  839. // We are processing the original sources: map this newly
  840. // inserted preprocessed line with the line in the said
  841. // sources.
  842. mLineMapping.push_back(mCurrentLine);
  843. }
  844. else
  845. {
  846. // We are processing an #include: map this newly inserted
  847. // preprocessed line with the line of the root #include
  848. // directive in the original (unprocessed) sources.
  849. mLineMapping.push_back(mRootIncludeLine);
  850. }
  851. continue;
  852. }
  853. if (directive == "include")
  854. {
  855. LL_DEBUGS("Preprocessor") << "Found: #include " << argument
  856. << LL_ENDL;
  857. // Check for the presence of quotes or angle brackets
  858. size_t i = argument.length() - 1;
  859. if (i < 2 ||
  860. (argument[0] != '"' && argument[0] != '<') ||
  861. (argument[i] != '"' && argument[i] != '>'))
  862. {
  863. parsingError("Invalid #include name provided: " + argument);
  864. return FAILURE;
  865. }
  866. // Strip off the quotes or angle brackets
  867. argument = argument.substr(1, i - 1);
  868. // Only actually include the file if it was not already included
  869. // (this avoids infinite loops).
  870. if (!mIncludes.count(argument))
  871. {
  872. // Let our caller deal with the include file retrieval and
  873. // recover the text it contains.
  874. mIncludeBuffer.clear();
  875. line = argument; // 'line' will be modified with full path
  876. S32 result = mIncludeCallback(line, mDefaultIncludePath,
  877. mIncludeBuffer,
  878. mCallbackUserData);
  879. if (result == FAILURE)
  880. {
  881. parsingError("Failure to #include: " + argument);
  882. return FAILURE;
  883. }
  884. else if (result == PAUSED)
  885. {
  886. LL_DEBUGS("Preprocessor") << "Pausing until asset is available for #include: "
  887. << argument << LL_ENDL;
  888. --mCurrentLine; // We will retry the #include on resume()
  889. return PAUSED;
  890. }
  891. // Remember that this file has been successfully included
  892. mIncludes.emplace(argument);
  893. // If we are not already processing an include, remember the
  894. // line of this root #include directive, for sources lines
  895. // mapping.
  896. if (mFilenames.size() == 1)
  897. {
  898. mRootIncludeLine = mCurrentLine;
  899. }
  900. // Make sure there is a trailing line feed
  901. if (mIncludeBuffer[mIncludeBuffer.length() - 1] != '\n')
  902. {
  903. mIncludeBuffer += '\n';
  904. }
  905. // Add a special boundary directive at the end of the included
  906. // file block to allow tracking the filename and line number.
  907. mIncludeBuffer += llformat("#endinclude %d\n", mCurrentLine);
  908. // Push the name of the included file on the stack and set
  909. // the current line to 0, since this is what we are going to
  910. // process at the next loop.
  911. mFilenames.emplace("\"" + line + "\"");
  912. mCurrentLine = 0;
  913. // Replace our buffer with the included file followed with
  914. // whatever is left to process in the original buffer.
  915. mSourcesBuffer = mIncludeBuffer + mSourcesBuffer.substr(pos);
  916. // Continue processing from the start of our new buffer
  917. len = mSourcesBuffer.length();
  918. pos = 0;
  919. }
  920. else
  921. {
  922. LL_DEBUGS("Preprocessor") << "Skipping inclusion of already #included file: "
  923. << argument << LL_ENDL;
  924. }
  925. }
  926. else if (directive == "define")
  927. {
  928. argument = get_define_and_value(argument, line);
  929. // Replace any eval() tokens with their result in the line
  930. line = replaceEvalInExpr(line, true);
  931. LL_DEBUGS("Preprocessor") << "Found: #define " << argument << " "
  932. << line << LL_ENDL;
  933. if (!isValidToken(argument))
  934. {
  935. parsingError("Cannot define '" + argument +
  936. "': invalid token.");
  937. return FAILURE;
  938. }
  939. if (mDefines.count(argument))
  940. {
  941. parsingError("Cannot redefine '" + argument +
  942. "' which is already defined.");
  943. return FAILURE;
  944. }
  945. mDefines[argument] = line;
  946. }
  947. else if (directive == "undef")
  948. {
  949. LL_DEBUGS("Preprocessor") << "Found: #undef " << argument
  950. << LL_ENDL;
  951. if (!isValidToken(argument))
  952. {
  953. parsingError("Cannot undefine '" + argument +
  954. "': invalid token.");
  955. return FAILURE;
  956. }
  957. defines_map_t::iterator it = mDefines.find(argument);
  958. if (it != mDefines.end())
  959. {
  960. mDefines.erase(it);
  961. }
  962. }
  963. else if (directive == "ifdef")
  964. {
  965. LL_DEBUGS("Preprocessor") << "Found: #ifdef " << argument
  966. << LL_ENDL;
  967. if (mDefines.count(argument))
  968. {
  969. mIfClauses.push(true);
  970. }
  971. else
  972. {
  973. mIfClauses.push(false);
  974. // Condition not met, skip lines till we find a #elif, #else or
  975. // #endif (and resume the flow one line past them)
  976. LL_DEBUGS("Preprocessor") << "Condition not met." << LL_ENDL;
  977. if (!skipToElseOrEndif(mSourcesBuffer, pos))
  978. {
  979. return FAILURE;
  980. }
  981. }
  982. }
  983. else if (directive == "ifndef")
  984. {
  985. LL_DEBUGS("Preprocessor") << "Found: #ifndef " << argument
  986. << LL_ENDL;
  987. if (mDefines.count(argument))
  988. {
  989. mIfClauses.push(false);
  990. // Condition not met, skip lines till we find a #elif, #else or
  991. // #endif (and resume the flow one line past them)
  992. LL_DEBUGS("Preprocessor") << "Condition not met." << LL_ENDL;
  993. if (!skipToElseOrEndif(mSourcesBuffer, pos))
  994. {
  995. return FAILURE;
  996. }
  997. }
  998. else
  999. {
  1000. mIfClauses.push(true);
  1001. }
  1002. }
  1003. else if (directive == "if" || directive == "elif")
  1004. {
  1005. LL_DEBUGS("Preprocessor") << "Found: #" << directive << " "
  1006. << argument << LL_ENDL;
  1007. // Proceed to replace all #defined tokens with their value in the
  1008. // expression
  1009. argument = replaceDefinedInExpr(argument);
  1010. argument = replaceDefinesInLine(argument);
  1011. // Replace any eval() tokens with their result in the expression
  1012. argument = replaceEvalInExpr(argument);
  1013. bool met = !argument.empty() && isExpressionTrue(argument);
  1014. if (directive == "elif")
  1015. {
  1016. if (mIfClauses.empty())
  1017. {
  1018. parsingError("#elif without matching #if");
  1019. return FAILURE;
  1020. }
  1021. mIfClauses.pop();
  1022. }
  1023. mIfClauses.push(met);
  1024. if (!met)
  1025. {
  1026. // Condition not met, skip lines till we find a #elif, #else or
  1027. // #endif (and resume the flow one line past them)
  1028. LL_DEBUGS("Preprocessor") << "Condition not met." << LL_ENDL;
  1029. if (!skipToElseOrEndif(mSourcesBuffer, pos))
  1030. {
  1031. return FAILURE;
  1032. }
  1033. }
  1034. }
  1035. else if (directive == "else")
  1036. {
  1037. LL_DEBUGS("Preprocessor") << "Found: #else" << LL_ENDL;
  1038. if (mIfClauses.empty())
  1039. {
  1040. parsingError("#else without matching #if");
  1041. return false;
  1042. }
  1043. if (!skipToElseOrEndif(mSourcesBuffer, pos))
  1044. {
  1045. return FAILURE;
  1046. }
  1047. }
  1048. else if (directive == "endif")
  1049. {
  1050. LL_DEBUGS("Preprocessor") << "Found: #endif" << LL_ENDL;
  1051. if (mIfClauses.empty())
  1052. {
  1053. parsingError("#endif without matching #if");
  1054. return FAILURE;
  1055. }
  1056. mIfClauses.pop();
  1057. }
  1058. else if (directive == "warning")
  1059. {
  1060. LL_DEBUGS("Preprocessor") << "Found: #warning " << argument
  1061. << LL_ENDL;
  1062. parsingError("#warning: " + argument, true);
  1063. }
  1064. else if (directive == "error")
  1065. {
  1066. LL_DEBUGS("Preprocessor") << "Found: #error " << argument
  1067. << LL_ENDL;
  1068. parsingError("#error: " + argument);
  1069. return FAILURE;
  1070. }
  1071. else
  1072. {
  1073. parsingError("Unknown pre-processor directive: " + directive);
  1074. return FAILURE;
  1075. }
  1076. }
  1077. if (!mIfClauses.empty())
  1078. {
  1079. parsingError("Missing #endif");
  1080. return FAILURE;
  1081. }
  1082. LL_DEBUGS("Preprocessor") << "Preprocessed sources:\n" << mPreprocessed
  1083. << LL_ENDL;
  1084. return SUCCESS;
  1085. }
  1086. //static
  1087. bool HBPreprocessor::needsPreprocessing(const std::string& sources)
  1088. {
  1089. size_t pos = 0;
  1090. size_t len = sources.length();
  1091. std::string line, directive, argument;
  1092. while (pos < len)
  1093. {
  1094. line = get_one_line(sources, pos);
  1095. if (is_directive(line, directive, argument, true))
  1096. {
  1097. // Test for known directives, most likely ones first, ignoring
  1098. // #elif, #else and #endif, since there must be an #if* appearing
  1099. // before them anyway...
  1100. if (directive == "include" || directive == "define" ||
  1101. directive == "ifdef" || directive == "ifndef" ||
  1102. directive == "if" || directive == "undef" ||
  1103. directive == "warning" || directive == "error" ||
  1104. directive == "pragma")
  1105. {
  1106. return true;
  1107. }
  1108. }
  1109. // Check for special defines (that do not need a #define and that could
  1110. // therefore appear in a sources file without any preprocessor
  1111. // directive).
  1112. if (line.find("__") != std::string::npos)
  1113. {
  1114. if (line.find("__DATE__") != std::string::npos ||
  1115. line.find("__TIME__") != std::string::npos ||
  1116. line.find("__FILE__") != std::string::npos ||
  1117. line.find("__LINE__") != std::string::npos ||
  1118. line.find("__AGENT_ID__") != std::string::npos ||
  1119. line.find("__AGENT_NAME__") != std::string::npos ||
  1120. line.find("__VIEWER_") != std::string::npos)
  1121. {
  1122. return true;
  1123. }
  1124. }
  1125. }
  1126. return false;
  1127. }