tb_node_tree.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. // ================================================================================
  2. // == This file is a part of Turbo Badger. (C) 2011-2014, Emil Segerås ==
  3. // == See tb_core.h for more information. ==
  4. // ================================================================================
  5. #include "tb_node_tree.h"
  6. #include "tb_node_ref_tree.h"
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <assert.h>
  10. #include "tb_system.h"
  11. #include "tb_tempbuffer.h"
  12. #include "tb_language.h"
  13. namespace tb {
  14. TBNode::~TBNode()
  15. {
  16. Clear();
  17. }
  18. // static
  19. TBNode *TBNode::Create(const char *name)
  20. {
  21. TBNode *n = new TBNode;
  22. if (!n || !(n->m_name = strdup(name)))
  23. {
  24. delete n;
  25. return nullptr;
  26. }
  27. return n;
  28. }
  29. // static
  30. TBNode *TBNode::Create(const char *name, int name_len)
  31. {
  32. TBNode *n = new TBNode;
  33. if (!n || !(n->m_name = (char *) malloc(name_len + 1)))
  34. {
  35. delete n;
  36. return nullptr;
  37. }
  38. memcpy(n->m_name, name, name_len);
  39. n->m_name[name_len] = 0;
  40. return n;
  41. }
  42. //static
  43. const char *TBNode::GetNextNodeSeparator(const char *request)
  44. {
  45. while (*request != 0 && *request != '>')
  46. request++;
  47. return request;
  48. }
  49. TBNode *TBNode::GetNode(const char *request, GET_MISS_POLICY mp)
  50. {
  51. // Iterate one node deeper for each sub request (non recursive)
  52. TBNode *n = this;
  53. while (*request && n)
  54. {
  55. const char *nextend = GetNextNodeSeparator(request);
  56. int name_len = nextend - request;
  57. TBNode *n_child = n->GetNodeInternal(request, name_len);
  58. if (!n_child && mp == GET_MISS_POLICY_CREATE)
  59. {
  60. n_child = n->Create(request, name_len);
  61. if (n_child)
  62. n->Add(n_child);
  63. }
  64. n = n_child;
  65. request = *nextend == 0 ? nextend : nextend + 1;
  66. }
  67. return n;
  68. }
  69. TBNode *TBNode::GetNodeFollowRef(const char *request, GET_MISS_POLICY mp)
  70. {
  71. TBNode *node = GetNode(request, mp);
  72. if (node)
  73. node = TBNodeRefTree::FollowNodeRef(node);
  74. return node;
  75. }
  76. TBNode *TBNode::GetNodeInternal(const char *name, int name_len) const
  77. {
  78. for (TBNode *n = GetFirstChild(); n; n = n->GetNext())
  79. {
  80. if (strncmp(n->m_name, name, name_len) == 0 && n->m_name[name_len] == 0)
  81. return n;
  82. }
  83. return nullptr;
  84. }
  85. bool TBNode::CloneChildren(TBNode *source)
  86. {
  87. TBNode *item = source->GetFirstChild();
  88. while (item)
  89. {
  90. TBNode *new_child = Create(item->m_name);
  91. if (!new_child)
  92. return false;
  93. new_child->m_value.Copy(item->m_value);
  94. Add(new_child);
  95. if (!new_child->CloneChildren(item))
  96. return false;
  97. item = item->GetNext();
  98. }
  99. return true;
  100. }
  101. TBValue &TBNode::GetValueFollowRef()
  102. {
  103. return TBNodeRefTree::FollowNodeRef(this)->GetValue();
  104. }
  105. int TBNode::GetValueInt(const char *request, int def)
  106. {
  107. TBNode *n = GetNodeFollowRef(request);
  108. return n ? n->m_value.GetInt() : def;
  109. }
  110. float TBNode::GetValueFloat(const char *request, float def)
  111. {
  112. TBNode *n = GetNodeFollowRef(request);
  113. return n ? n->m_value.GetFloat() : def;
  114. }
  115. const char *TBNode::GetValueString(const char *request, const char *def)
  116. {
  117. if (TBNode *node = GetNodeFollowRef(request))
  118. {
  119. // We might have a language string. Those are not
  120. // looked up in GetNode/ResolveNode.
  121. if (node->GetValue().IsString())
  122. {
  123. const char *string = node->GetValue().GetString();
  124. if (*string == '@' && *TBNode::GetNextNodeSeparator(string) == 0)
  125. string = g_tb_lng->GetString(string + 1);
  126. return string;
  127. }
  128. return node->GetValue().GetString();
  129. }
  130. return def;
  131. }
  132. const char *TBNode::GetValueStringRaw(const char *request, const char *def)
  133. {
  134. TBNode *n = GetNodeFollowRef(request);
  135. return n ? n->m_value.GetString() : def;
  136. }
  137. class FileParser : public TBParserStream
  138. {
  139. public:
  140. bool Read(const char *filename, TBParserTarget *target)
  141. {
  142. f = TBFile::Open(filename, TBFile::MODE_READ);
  143. if (!f)
  144. return false;
  145. TBParser p;
  146. TBParser::STATUS status = p.Read(this, target);
  147. delete f;
  148. return status == TBParser::STATUS_OK ? true : false;
  149. }
  150. virtual int GetMoreData(char *buf, int buf_len)
  151. {
  152. return f->Read(buf, 1, buf_len);
  153. }
  154. private:
  155. TBFile *f;
  156. };
  157. class DataParser : public TBParserStream
  158. {
  159. public:
  160. bool Read(const char *data, int data_len, TBParserTarget *target)
  161. {
  162. m_data = data;
  163. m_data_len = data_len;
  164. TBParser p;
  165. TBParser::STATUS status = p.Read(this, target);
  166. return status == TBParser::STATUS_OK ? true : false;
  167. }
  168. virtual int GetMoreData(char *buf, int buf_len)
  169. {
  170. int consume = MIN(buf_len, m_data_len);
  171. memcpy(buf, m_data, consume);
  172. m_data += consume;
  173. m_data_len -= consume;
  174. return consume;
  175. }
  176. private:
  177. const char *m_data;
  178. int m_data_len;
  179. };
  180. class TBNodeTarget : public TBParserTarget
  181. {
  182. public:
  183. TBNodeTarget(TBNode *root, const char *filename)
  184. {
  185. m_root_node = m_target_node = root;
  186. m_filename = filename;
  187. }
  188. virtual void OnError(int line_nr, const char *error)
  189. {
  190. #ifdef TB_RUNTIME_DEBUG_INFO
  191. TBStr err;
  192. err.SetFormatted("%s(%d):Parse error: %s\n", m_filename, line_nr, error);
  193. TBDebugOut(err);
  194. #endif // TB_RUNTIME_DEBUG_INFO
  195. }
  196. virtual void OnComment(int line_nr, const char *comment)
  197. {
  198. }
  199. virtual void OnToken(int line_nr, const char *name, TBValue &value)
  200. {
  201. if (!m_target_node)
  202. return;
  203. if (strcmp(name, "@file") == 0)
  204. IncludeFile(line_nr, value.GetString());
  205. else if (strcmp(name, "@include") == 0)
  206. IncludeRef(line_nr, value.GetString());
  207. else if (TBNode *n = TBNode::Create(name))
  208. {
  209. n->m_value.TakeOver(value);
  210. m_target_node->Add(n);
  211. }
  212. }
  213. virtual void Enter()
  214. {
  215. if (m_target_node)
  216. m_target_node = m_target_node->GetLastChild();
  217. }
  218. virtual void Leave()
  219. {
  220. assert(m_target_node != m_root_node);
  221. if (m_target_node)
  222. m_target_node = m_target_node->m_parent;
  223. }
  224. void IncludeFile(int line_nr, const char *filename)
  225. {
  226. // Read the included file into a new TBNode and then
  227. // move all the children to m_target_node.
  228. TBTempBuffer include_filename;
  229. include_filename.AppendPath(m_filename);
  230. include_filename.AppendString(filename);
  231. TBNode content;
  232. if (content.ReadFile(include_filename.GetData()))
  233. {
  234. while (TBNode *content_n = content.GetFirstChild())
  235. {
  236. content.Remove(content_n);
  237. m_target_node->Add(content_n);
  238. }
  239. }
  240. else
  241. {
  242. TBStr err;
  243. err.SetFormatted("Referenced file \"%s\" was not found!", include_filename.GetData());
  244. OnError(line_nr, err);
  245. }
  246. }
  247. void IncludeRef(int line_nr, const char *refstr)
  248. {
  249. TBNode *refnode = nullptr;
  250. if (*refstr == '@')
  251. {
  252. TBNode tmp;
  253. tmp.GetValue().SetString(refstr, TBValue::SET_AS_STATIC);
  254. refnode = TBNodeRefTree::FollowNodeRef(&tmp);
  255. }
  256. else // Local look-up
  257. {
  258. // Note: If we read to a target node that already contains
  259. // nodes, we might look up nodes that's already there
  260. // instead of new nodes.
  261. refnode = m_root_node->GetNode(refstr, TBNode::GET_MISS_POLICY_NULL);
  262. // Detect cycles
  263. TBNode *cycle_detection = m_target_node;
  264. while (cycle_detection && refnode)
  265. {
  266. if (cycle_detection == refnode)
  267. refnode = nullptr; // We have a cycle, so just fail the inclusion.
  268. cycle_detection = cycle_detection->GetParent();
  269. }
  270. }
  271. if (refnode)
  272. m_target_node->CloneChildren(refnode);
  273. else
  274. {
  275. TBStr err;
  276. err.SetFormatted("Include \"%s\" was not found!", refstr);
  277. OnError(line_nr, err);
  278. }
  279. }
  280. private:
  281. TBNode *m_root_node;
  282. TBNode *m_target_node;
  283. const char *m_filename;
  284. };
  285. bool TBNode::ReadFile(const char *filename, TB_NODE_READ_FLAGS flags)
  286. {
  287. if (!(flags & TB_NODE_READ_FLAGS_APPEND))
  288. Clear();
  289. FileParser p;
  290. TBNodeTarget t(this, filename);
  291. if (p.Read(filename, &t))
  292. {
  293. TBNodeRefTree::ResolveConditions(this);
  294. return true;
  295. }
  296. return false;
  297. }
  298. void TBNode::ReadData(const char *data, TB_NODE_READ_FLAGS flags)
  299. {
  300. ReadData(data, strlen(data), flags);
  301. }
  302. void TBNode::ReadData(const char *data, int data_len, TB_NODE_READ_FLAGS flags)
  303. {
  304. if (!(flags & TB_NODE_READ_FLAGS_APPEND))
  305. Clear();
  306. DataParser p;
  307. TBNodeTarget t(this, "{data}");
  308. p.Read(data, data_len, &t);
  309. TBNodeRefTree::ResolveConditions(this);
  310. }
  311. void TBNode::Clear()
  312. {
  313. free(m_name);
  314. m_name = nullptr;
  315. m_children.DeleteAll();
  316. }
  317. }; // namespace tb