y_xml.inc 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893
  1. /*----------------------------------------------------------------------------*-
  2. =============================
  3. y_xml - XML file functions!
  4. =============================
  5. Description:
  6. Parses XML files according to a set of defined rules. A rule is a custom
  7. function called on a tag when all the data for that tag has been collected.
  8. The data for a tag could consist of simple bla="bla" pairs, <tag>data</tag>
  9. pairs or cominations of the two, including subtags, each with their own
  10. possible custom handlers.
  11. Data for the tag is retrieved from a custom function using only:
  12. while (XML_GetKeyValue(ident, data)) {}
  13. Legal:
  14. Version: MPL 1.1
  15. The contents of this file are subject to the Mozilla Public License Version
  16. 1.1 (the "License"); you may not use this file except in compliance with
  17. the License. You may obtain a copy of the License at
  18. http://www.mozilla.org/MPL/
  19. Software distributed under the License is distributed on an "AS IS" basis,
  20. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  21. for the specific language governing rights and limitations under the
  22. License.
  23. The Original Code is the SA:MP script information include.
  24. The Initial Developer of the Original Code is Alex "Y_Less" Cole.
  25. Portions created by the Initial Developer are Copyright (C) 2008
  26. the Initial Developer. All Rights Reserved.
  27. Contributors:
  28. ZeeX, koolk
  29. Thanks:
  30. Peter, Cam - Support.
  31. ZeeX - Very productive conversations.
  32. koolk - IsPlayerinAreaEx code.
  33. TheAlpha - Danish translation.
  34. breadfish - German translation.
  35. Fireburn - Dutch translation.
  36. yom - French translation.
  37. 50p - Polish translation.
  38. Zamaroht - Spanish translation.
  39. Dracoblue, sintax, mabako, Xtreme, other coders - Producing other modes
  40. for me to strive to better.
  41. Pixels^ - Running XScripters where the idea was born.
  42. Matite - Pestering me to release it and using it.
  43. Very special thanks to:
  44. Thiadmer - PAWN.
  45. Kye/Kalcor - SA:MP.
  46. SA:MP Team past, present and future - SA:MP.
  47. Version:
  48. 1.0
  49. Changelog:
  50. 06/08/10:
  51. First version
  52. -*----------------------------------------------------------------------------*/
  53. #include <YSI\internal\y_version>
  54. #include <a_samp>
  55. #include <YSI\y_debug>
  56. #include <YSI\y_utils>
  57. #if !defined MAX_XML_FILES
  58. #define MAX_XML_FILES (5)
  59. #endif
  60. #define XML_MAX_XML_FILES (XML:MAX_XML_FILES)
  61. #define NO_XML_FILE (XML:-1)
  62. #define MAX_XML_ENTRY_NAME (32)
  63. #define MAX_XML_ENTRY_TEXT (80)
  64. #define MAX_XML_FUNCTION (32)
  65. #define XML_BUFFER_SIZE (64)
  66. #define MAX_XML_HANDLERS (16)
  67. #define XML_WRITE_BUFFER_SIZE (170)
  68. #if !defined MAX_STRING
  69. #define MAX_STRING (512)
  70. #endif
  71. enum E_XML_PARA
  72. {
  73. E_XML_PARA_NAME[MAX_XML_ENTRY_NAME],
  74. E_XML_PARA_VALUE[MAX_XML_ENTRY_TEXT],
  75. E_XML_PARA_LEVEL
  76. }
  77. enum E_XML_HANDLER
  78. {
  79. E_XML_HANDLER_TRIGGER[MAX_XML_ENTRY_NAME],
  80. E_XML_HANDLER_FUNCTION[MAX_XML_FUNCTION]
  81. }
  82. enum E_XML_WRITE
  83. {
  84. E_XML_WRITE_TAG[MAX_XML_ENTRY_NAME],
  85. E_XML_WRITE_VALUE[MAX_XML_ENTRY_TEXT],
  86. E_XML_WRITE_CHILDREN,
  87. E_XML_WRITE_SIBLINGS
  88. }
  89. static stock
  90. YSI_g_sXMLWriteBuffer[XML_WRITE_BUFFER_SIZE][E_XML_WRITE],
  91. YSI_g_sXMLWritePointer,
  92. YSI_g_sParameters[XML_BUFFER_SIZE][E_XML_PARA],
  93. YSI_g_sHandlers[XML_MAX_XML_FILES][MAX_XML_HANDLERS][E_XML_HANDLER],
  94. YSI_g_sCurHandler[XML_MAX_XML_FILES] = {-1, ...},
  95. YSI_g_sCurBuffer = -1,
  96. YSI_g_sEndTag = 0;
  97. /*----------------------------------------------------------------------------*-
  98. Function:
  99. XML_IsValid
  100. Params:
  101. XML:file - File to check validity of.
  102. Return:
  103. -
  104. Notes:
  105. -
  106. -*----------------------------------------------------------------------------*/
  107. #define XML_IsValid(%1) \
  108. ((%1) >= XML:0 && (%1) < XML_MAX_XML_FILES && YSI_g_sCurHandler[(%1)] != -1)
  109. /*----------------------------------------------------------------------------*-
  110. Function:
  111. XML_IsChar
  112. Params:
  113. char - Checks if a cell is a valid identifier character.
  114. Return:
  115. -
  116. Notes:
  117. -
  118. -*----------------------------------------------------------------------------*/
  119. #define XML_IsChar(%1) \
  120. (((%1) >= 'a' && (%1) <= 'z') || ((%1) >= 'A' && (%1) <= 'Z') || ((%1) >= '0' && (%1) <= '9') || (%1 == '_'))
  121. /*----------------------------------------------------------------------------*-
  122. Function:
  123. XML_New
  124. Params:
  125. -
  126. Return:
  127. XML
  128. Notes:
  129. Creates a new set of rules for parsing XML files.
  130. -*----------------------------------------------------------------------------*/
  131. stock XML:XML_New()
  132. {
  133. new
  134. XML:i;
  135. while (i < XML_MAX_XML_FILES && YSI_g_sCurHandler[i] != -1) i++;
  136. if (i == XML_MAX_XML_FILES) return NO_XML_FILE;
  137. YSI_g_sCurHandler[i] = 0;
  138. YSI_g_sCurBuffer = 0;
  139. return i;
  140. }
  141. /*----------------------------------------------------------------------------*-
  142. Function:
  143. XML_Destroy
  144. Params:
  145. XML:rule - Removes a set of rules from the system
  146. Return:
  147. -
  148. Notes:
  149. -
  150. -*----------------------------------------------------------------------------*/
  151. stock XML_Destroy(XML:rule)
  152. {
  153. if (!XML_IsValid(rule)) return 0;
  154. YSI_g_sCurBuffer = -1;
  155. YSI_g_sCurHandler[rule] = -1;
  156. return 1;
  157. }
  158. /*----------------------------------------------------------------------------*-
  159. Function:
  160. XML_Parse
  161. Params:
  162. XML:rule - Set of XML rules to parse against.
  163. filename[] - XML file to parse.
  164. Return:
  165. -
  166. Notes:
  167. -
  168. -*----------------------------------------------------------------------------*/
  169. stock XML_Parse(XML:rule, filename[])
  170. {
  171. if (!XML_IsValid(rule)) return 0;
  172. new
  173. File:xFile = fopen(filename);
  174. if (xFile)
  175. {
  176. new
  177. line[MAX_STRING],
  178. tagCount,
  179. gotLastValue,
  180. inClose,
  181. inOpen,
  182. value[MAX_XML_ENTRY_TEXT],
  183. name[MAX_XML_ENTRY_NAME],
  184. inPar;
  185. while (fread(xFile, line))
  186. {
  187. P:5("XML_Parse() line: %s", line);
  188. new
  189. pos,
  190. ch;
  191. while ((ch = line[pos]) && ch <= ' ') pos++;
  192. while (ch)
  193. {
  194. if (ch <= ' ') pos++;
  195. else if (ch == '<')
  196. {
  197. if (line[++pos] == '/')
  198. {
  199. pos++;
  200. tagCount--;
  201. if (gotLastValue)
  202. {
  203. XML_Push(XML_GetName(line, pos), value, tagCount);
  204. }
  205. else
  206. {
  207. name = XML_GetName(line, pos);
  208. value = XML_ParseTag(rule, name, tagCount);
  209. if (value[0] && tagCount > 1)
  210. {
  211. XML_Push(name, value, tagCount);
  212. }
  213. }
  214. inClose = 1;
  215. }
  216. else
  217. {
  218. inOpen = 1;
  219. tagCount++;
  220. while ((ch = line[pos]) && XML_IsChar(ch)) pos++;
  221. }
  222. gotLastValue = 0;
  223. inPar = 0;
  224. }
  225. else if (ch == '>')
  226. {
  227. inPar = inClose ? 0 : 1;
  228. inOpen = 0;
  229. inClose = 0;
  230. pos++;
  231. }
  232. else if (inPar)
  233. {
  234. value = XML_GetValue(line, pos);
  235. gotLastValue = 1;
  236. }
  237. else if (inOpen)
  238. {
  239. name = XML_GetName(line, pos);
  240. value = XML_GetParameter(line, pos);
  241. XML_Push(name, value, tagCount);
  242. }
  243. else pos++;
  244. ch = line[pos];
  245. }
  246. }
  247. fclose(xFile);
  248. return 1;
  249. }
  250. return 0;
  251. }
  252. /*----------------------------------------------------------------------------*-
  253. Function:
  254. XML_Push
  255. Params:
  256. name[] - Identifer of data.
  257. text[] - Data.
  258. depth - Current XML tree depth.
  259. Return:
  260. -
  261. Notes:
  262. Pushes an identifier and it's value (either explicitaly stated or returned
  263. from another function) to the stack with basic parent info.
  264. -*----------------------------------------------------------------------------*/
  265. stock XML_Push(name[], text[], depth)
  266. {
  267. if (YSI_g_sCurBuffer < XML_BUFFER_SIZE && YSI_g_sCurBuffer >= 0)
  268. {
  269. strcpy(YSI_g_sParameters[YSI_g_sCurBuffer][E_XML_PARA_NAME], name, MAX_XML_ENTRY_NAME);
  270. strcpy(YSI_g_sParameters[YSI_g_sCurBuffer][E_XML_PARA_VALUE], text, MAX_XML_ENTRY_TEXT);
  271. YSI_g_sParameters[YSI_g_sCurBuffer][E_XML_PARA_LEVEL] = depth;
  272. YSI_g_sCurBuffer++;
  273. }
  274. }
  275. /*----------------------------------------------------------------------------*-
  276. Function:
  277. XML_GetParameter
  278. Params:
  279. line[] - Data to extract from.
  280. &pos - Start/end point of the text.
  281. Return:
  282. -
  283. Notes:
  284. Gets the data from inside ""s in an identifier. Now supports
  285. \ for escape characters.
  286. -*----------------------------------------------------------------------------*/
  287. stock XML_GetParameter(line[], &pos)
  288. {
  289. new
  290. ch,
  291. ret[MAX_XML_ENTRY_TEXT],
  292. i;
  293. while ((ch = line[pos++]) && ch != '"') {}
  294. if (ch)
  295. {
  296. while ((ch = line[pos++]) && i < (sizeof (ret) - 1))
  297. {
  298. if (ch == '\\')
  299. {
  300. switch (line[pos++])
  301. {
  302. case '"':
  303. {
  304. ch = '"';
  305. }
  306. case 'n':
  307. {
  308. ch = '\n';
  309. }
  310. case 'r':
  311. {
  312. ch = '\r';
  313. }
  314. case '\\': {}
  315. default:
  316. {
  317. pos--;
  318. continue;
  319. }
  320. }
  321. }
  322. else if (ch == '"')
  323. {
  324. break;
  325. }
  326. ret[i++] = ch;
  327. }
  328. }
  329. if (i == (sizeof (ret) - 1))
  330. {
  331. while ((ch = line[pos++]))
  332. {
  333. if (ch == '\\')
  334. {
  335. switch (line[pos++])
  336. {
  337. case '\\', '"', 'n', 'r': {}
  338. default:
  339. {
  340. pos--;
  341. }
  342. }
  343. }
  344. else if (ch == '"') break;
  345. }
  346. }
  347. ret[i] = '\0';
  348. return ret;
  349. }
  350. /*----------------------------------------------------------------------------*-
  351. Function:
  352. XML_GetValue
  353. Params:
  354. line[] - Line to get data from.
  355. &pos - Start and end position of the data.
  356. Return:
  357. -
  358. Notes:
  359. Gets the text between tags.
  360. -*----------------------------------------------------------------------------*/
  361. stock XML_GetValue(line[], &pos)
  362. {
  363. new
  364. ch,
  365. ret[MAX_XML_ENTRY_TEXT],
  366. i;
  367. while (((ch = line[pos++]) >= ' ' || ch == '\t') && (ch != '<') && i < (sizeof (ret) - 1)) ret[i++] = ch;
  368. pos--;
  369. if (i == (sizeof (ret) - 1))
  370. {
  371. while (((ch = line[pos]) >= ' ' || ch == '\t') && (ch != '<')) pos++;
  372. }
  373. ret[i] = '\0';
  374. return ret;
  375. }
  376. /*----------------------------------------------------------------------------*-
  377. Function:
  378. XML_GetName
  379. Params:
  380. line[] - Line to get data from.
  381. &pos - Start and end position of text.
  382. Return:
  383. -
  384. Notes:
  385. Gets the identifier of a piece of data.
  386. -*----------------------------------------------------------------------------*/
  387. stock XML_GetName(line[], &pos)
  388. {
  389. new
  390. ch,
  391. ret[MAX_XML_ENTRY_NAME],
  392. i;
  393. while ((ch = line[pos++]) && XML_IsChar(ch) && i < (sizeof (ret) - 1)) ret[i++] = ch;
  394. pos--;
  395. if (i == (sizeof (ret) - 1))
  396. {
  397. while ((ch = line[pos]) >= ' ' && XML_IsChar(ch)) pos++;
  398. }
  399. ret[i] = '\0';
  400. return ret;
  401. }
  402. /*----------------------------------------------------------------------------*-
  403. Function:
  404. XML_ParseTag
  405. Params:
  406. XML:rule - Rule set to parse according to.
  407. name[] - Name if identifier.
  408. tagCount - New tree depth.
  409. Return:
  410. -
  411. Notes:
  412. -
  413. -*----------------------------------------------------------------------------*/
  414. stock XML_ParseTag(XML:rule, name[], tagCount)
  415. {
  416. new
  417. i,
  418. j = YSI_g_sCurHandler[rule],
  419. ret[MAX_XML_ENTRY_TEXT] = "\1";
  420. YSI_g_sEndTag = tagCount;
  421. while (i < j)
  422. {
  423. if (!strcmp(YSI_g_sHandlers[rule][i][E_XML_HANDLER_TRIGGER], name, true))
  424. {
  425. break;
  426. }
  427. i++;
  428. }
  429. if (i != j)
  430. {
  431. //format(ret, sizeof (ret), "%d", CallLocalFunction(YSI_g_sHandlers[rule][i][E_XML_HANDLER_FUNCTION], ""));
  432. valstr(ret, CallLocalFunction(YSI_g_sHandlers[rule][i][E_XML_HANDLER_FUNCTION], ""));
  433. }
  434. while (YSI_g_sCurBuffer)
  435. {
  436. if (YSI_g_sParameters[--YSI_g_sCurBuffer][E_XML_PARA_LEVEL] <= tagCount) break;
  437. }
  438. return ret;
  439. }
  440. /*----------------------------------------------------------------------------*-
  441. Function:
  442. XML_GetKeyValue
  443. Params:
  444. key[] - Variable to return identifier in.
  445. value[] - Variable to return value in.
  446. Return:
  447. Data found.
  448. Notes:
  449. Pops items off the stack for use in custom functions.
  450. -*----------------------------------------------------------------------------*/
  451. stock XML_GetKeyValue(key[], value[])
  452. {
  453. key[0] = 1;
  454. key[1] = 0;
  455. value[0] = 1;
  456. value[1] = 0;
  457. if (YSI_g_sCurBuffer)
  458. {
  459. YSI_g_sCurBuffer--;
  460. if (YSI_g_sParameters[YSI_g_sCurBuffer][E_XML_PARA_LEVEL] <= YSI_g_sEndTag) return 0;
  461. strcpy(key, YSI_g_sParameters[YSI_g_sCurBuffer][E_XML_PARA_NAME], MAX_XML_ENTRY_NAME);
  462. strcpy(value, YSI_g_sParameters[YSI_g_sCurBuffer][E_XML_PARA_VALUE], MAX_XML_ENTRY_TEXT);
  463. return 1;
  464. }
  465. return 0;
  466. }
  467. /*----------------------------------------------------------------------------*-
  468. Function:
  469. XML_AddHandler
  470. Params:
  471. XML:ruls - Rule set to add data to.
  472. trigger[] - Identifier which calls it.
  473. function[] - Function to parse identifier in.
  474. Return:
  475. -
  476. Notes:
  477. -
  478. -*----------------------------------------------------------------------------*/
  479. stock XML_AddHandler(XML:rule, trigger[], function[])
  480. {
  481. new
  482. handle;
  483. if (!XML_IsValid(rule) || (handle = YSI_g_sCurHandler[rule]) >= MAX_XML_HANDLERS && handle >= 0) return 0;
  484. strcpy(YSI_g_sHandlers[rule][handle][E_XML_HANDLER_TRIGGER], trigger, MAX_XML_ENTRY_NAME);
  485. strcpy(YSI_g_sHandlers[rule][handle][E_XML_HANDLER_FUNCTION], function, MAX_XML_FUNCTION);
  486. YSI_g_sCurHandler[rule]++;
  487. return 1;
  488. }
  489. /*----------------------------------------------------------------------------*-
  490. Function:
  491. XML_RemoveHandler
  492. Params:
  493. XML:rule - Set to remove handler from.
  494. trigger[] - Handler name to remove.
  495. Return:
  496. -
  497. Notes:
  498. -
  499. -*----------------------------------------------------------------------------*/
  500. stock XML_RemoveHandler(XML:rule, trigger[])
  501. {
  502. if (XML_IsValid(rule))
  503. {
  504. for (new i = 0, j = YSI_g_sCurHandler[rule]; i < j; i++)
  505. {
  506. if (!strcmp(YSI_g_sHandlers[rule][i][E_XML_HANDLER_TRIGGER], trigger, true))
  507. {
  508. new
  509. last = --YSI_g_sCurHandler[rule];
  510. if (last)
  511. {
  512. strcpy(YSI_g_sHandlers[rule][i][E_XML_HANDLER_TRIGGER], YSI_g_sHandlers[rule][last][E_XML_HANDLER_TRIGGER], MAX_XML_ENTRY_NAME);
  513. strcpy(YSI_g_sHandlers[rule][i][E_XML_HANDLER_FUNCTION], YSI_g_sHandlers[rule][last][E_XML_HANDLER_FUNCTION], MAX_XML_FUNCTION);
  514. }
  515. return 1;
  516. }
  517. }
  518. }
  519. return 0;
  520. }
  521. /*----------------------------------------------------------------------------*-
  522. Function:
  523. XML_AddParameter
  524. Params:
  525. parent - Tag this is a parameter of.
  526. tag[] - Name of this data.
  527. value[] - Value of this data, if this is blank there is sub parameters.
  528. Return:
  529. -
  530. Notes:
  531. -
  532. -*----------------------------------------------------------------------------*/
  533. //#define XML_AddSubEntry XML_AddParameter
  534. stock XMLEntry:XML_AddParameter(XMLEntry:parent, tag[], value[] = "")
  535. {
  536. if (_:parent < YSI_g_sXMLWritePointer < XML_WRITE_BUFFER_SIZE)
  537. {
  538. strcpy(YSI_g_sXMLWriteBuffer[YSI_g_sXMLWritePointer][E_XML_WRITE_TAG], tag, MAX_XML_ENTRY_NAME);
  539. strcpy(YSI_g_sXMLWriteBuffer[YSI_g_sXMLWritePointer][E_XML_WRITE_VALUE], value, MAX_XML_ENTRY_TEXT);
  540. YSI_g_sXMLWriteBuffer[YSI_g_sXMLWritePointer][E_XML_WRITE_CHILDREN] = -1;
  541. YSI_g_sXMLWriteBuffer[YSI_g_sXMLWritePointer][E_XML_WRITE_SIBLINGS] = YSI_g_sXMLWriteBuffer[_:parent][E_XML_WRITE_CHILDREN];
  542. YSI_g_sXMLWriteBuffer[_:parent][E_XML_WRITE_CHILDREN] = YSI_g_sXMLWritePointer;
  543. return XMLEntry:YSI_g_sXMLWritePointer++;
  544. }
  545. return XMLEntry:cellmax;
  546. }
  547. /*----------------------------------------------------------------------------*-
  548. Function:
  549. XML_AddItem
  550. Params:
  551. tag[] - Type of data being added.
  552. name[] - The optional name parameter for identifying tags.
  553. Return:
  554. -
  555. Notes:
  556. Starts the creation of a new tag to be written to a file, the structure
  557. has to be manually created then written. There is no buffering of multiple
  558. tags before writing as a single tag can have quite a bit of data.
  559. -*----------------------------------------------------------------------------*/
  560. #define XML_CreateEntry XML_AddItem
  561. #define XML_AddSubEntry XML_AddItem
  562. stock XMLEntry:XML_AddItem(tag[], name[] = "", XMLEntry:parent = XMLEntry:cellmax)
  563. {
  564. if (_:parent != cellmax)
  565. {
  566. return XML_AddParameter(parent, tag, name);
  567. }
  568. if (YSI_g_sXMLWritePointer < XML_WRITE_BUFFER_SIZE)
  569. {
  570. strcpy(YSI_g_sXMLWriteBuffer[YSI_g_sXMLWritePointer][E_XML_WRITE_TAG], tag, MAX_XML_ENTRY_NAME);
  571. strcpy(YSI_g_sXMLWriteBuffer[YSI_g_sXMLWritePointer][E_XML_WRITE_VALUE], name, MAX_XML_ENTRY_TEXT);
  572. YSI_g_sXMLWriteBuffer[YSI_g_sXMLWritePointer][E_XML_WRITE_CHILDREN] = -1;
  573. YSI_g_sXMLWriteBuffer[YSI_g_sXMLWritePointer][E_XML_WRITE_SIBLINGS] = -1;
  574. return XMLEntry:YSI_g_sXMLWritePointer++;
  575. }
  576. return XMLEntry:cellmax;
  577. }
  578. /*----------------------------------------------------------------------------*-
  579. Function:
  580. XML_WriteItem
  581. Params:
  582. filename[] - File to write to.
  583. item - Handle to the tag to write.
  584. Return:
  585. -
  586. Notes:
  587. Writea the data for a tag to a file.
  588. -*----------------------------------------------------------------------------*/
  589. #define XML_WriteEntry XML_WriteItem
  590. stock XML_WriteItem(filename[], XMLEntry:item)
  591. {
  592. if (_:item < YSI_g_sXMLWritePointer)
  593. {
  594. new
  595. data;
  596. if (fexist(filename))
  597. {
  598. new
  599. File:fHnd = fopen(filename, io_read),
  600. File:fTemp = ftemp();//fopen("_temp_ysi_user_file_.ysi", io_write);
  601. if (fHnd && fTemp)
  602. {
  603. new
  604. str[MAX_STRING];
  605. while (fread(fHnd, str))
  606. {
  607. fwrite(fTemp, str);
  608. if (!data)
  609. {
  610. new
  611. i,
  612. ch;
  613. while ((ch = str[i++]) && ch <= ' ') {}
  614. if (ch == '<')
  615. {
  616. XML_WriteItemData(_:item, fTemp, 2);
  617. data = 1;
  618. }
  619. }
  620. }
  621. fclose(fHnd);
  622. //fclose(fTemp);
  623. fremove(filename);
  624. if (data)
  625. {
  626. fHnd = fopen(filename, io_write);
  627. fseek(fTemp);
  628. //fTemp = fopen("_temp_ysi_user_file_.ysi", io_read);
  629. if (fHnd)// && fTemp)
  630. {
  631. while (fread(fTemp, str)) fwrite(fHnd, str);
  632. fclose(fHnd);
  633. fclose(fTemp);
  634. //fremove("_temp_ysi_user_file_.ysi");
  635. YSI_g_sXMLWritePointer = _:item;
  636. return 1;
  637. }
  638. }
  639. }
  640. if (fHnd)
  641. {
  642. fclose(fHnd);
  643. }
  644. if (fTemp)
  645. {
  646. fclose(fTemp);
  647. //fremove("_temp_ysi_user_file_.ysi");
  648. }
  649. }
  650. if (!data)
  651. {
  652. new
  653. File:fHnd = fopen(filename, io_write);
  654. if (fHnd)
  655. {
  656. fwrite(fHnd, "<XML>\r\n");
  657. XML_WriteItemData(_:item, fHnd, 2);
  658. fwrite(fHnd, "</XML>");
  659. fclose(fHnd);
  660. YSI_g_sXMLWritePointer = _:item;
  661. return 1;
  662. }
  663. }
  664. }
  665. return 0;
  666. }
  667. /*----------------------------------------------------------------------------*-
  668. Function:
  669. XML_WriteItemData
  670. Params:
  671. item - Item to write data for.
  672. File:fHnd - File to write to.
  673. depth - Current indentation.
  674. Return:
  675. -
  676. Notes:
  677. Recursive function to write a tag and it's children to a file.
  678. -*----------------------------------------------------------------------------*/
  679. static stock XML_WriteItemData(item, File:fHnd, depth)
  680. {
  681. new
  682. str[MAX_STRING],
  683. i = YSI_g_sXMLWriteBuffer[item][E_XML_WRITE_CHILDREN];
  684. if (i == -1)
  685. {
  686. format(str, sizeof (str), "%*s<%s>%s</%s>\n", depth, "", YSI_g_sXMLWriteBuffer[item][E_XML_WRITE_TAG], YSI_g_sXMLWriteBuffer[item][E_XML_WRITE_VALUE], YSI_g_sXMLWriteBuffer[item][E_XML_WRITE_TAG]);
  687. fwrite(fHnd, str);
  688. }
  689. else
  690. {
  691. if (YSI_g_sXMLWriteBuffer[item][E_XML_WRITE_VALUE][0]) format(str, sizeof (str), "%*s<%s name=\"%s\">\n", depth, "", YSI_g_sXMLWriteBuffer[item][E_XML_WRITE_TAG], YSI_g_sXMLWriteBuffer[item][E_XML_WRITE_VALUE]);
  692. else format(str, sizeof (str), "%*s<%s>\n", depth, "", YSI_g_sXMLWriteBuffer[item][E_XML_WRITE_TAG]);
  693. fwrite(fHnd, str);
  694. depth += 2;
  695. while (i != -1)
  696. {
  697. XML_WriteItemData(i, fHnd, depth);
  698. i = YSI_g_sXMLWriteBuffer[i][E_XML_WRITE_SIBLINGS];
  699. }
  700. depth -= 2;
  701. format(str, sizeof (str), "%*s</%s>\n", depth, "", YSI_g_sXMLWriteBuffer[item][E_XML_WRITE_TAG]);
  702. fwrite(fHnd, str);
  703. }
  704. }
  705. /*----------------------------------------------------------------------------*-
  706. Function:
  707. XML_RemoveItem
  708. Params:
  709. file[] - File to remove the tag from.
  710. tag[] - Type of tag to remove.
  711. name[] - Name of the tag to remove.
  712. Return:
  713. -
  714. Notes:
  715. Does a replace on data in a file with no new data.
  716. -*----------------------------------------------------------------------------*/
  717. stock XML_RemoveItem(file[], tag[], name[])
  718. {
  719. return XML_ReplaceItem(file, tag, name, -1);
  720. }
  721. /*----------------------------------------------------------------------------*-
  722. Function:
  723. XML_ReplaceItem
  724. Params:
  725. file[] - File to replace an item in.
  726. tag[] - Tag type of data to replace.
  727. name[] - Name of data to replace.
  728. replacement - Handle to the replacement data.
  729. Return:
  730. -
  731. Notes:
  732. Replaces a tag's data with new data, basically changes a tag's value.
  733. -*----------------------------------------------------------------------------*/
  734. stock XML_ReplaceItem(file[], tag[], name[], replacement)
  735. {
  736. if (fexist(file))
  737. {
  738. new
  739. File:fHnd = fopen(file, io_read),
  740. File:fTemp = ftemp();//fopen("_temp_ysi_user_file_.ysi", io_write);
  741. if (fHnd && fTemp)
  742. {
  743. new
  744. tagCount,
  745. line[MAX_STRING],
  746. inTag,
  747. atStart;
  748. while (fread(fHnd, line))
  749. {
  750. new
  751. pos,
  752. ch;
  753. while ((ch = line[pos]) && ch <= ' ') pos++;
  754. while (ch)
  755. {
  756. if (ch <= ' ') pos++;
  757. else if (ch == '<')
  758. {
  759. if (line[++pos] == '/')
  760. {
  761. pos++;
  762. tagCount--;
  763. if (inTag && tagCount <= atStart) inTag = 3;
  764. }
  765. else
  766. {
  767. tagCount++;
  768. if (!inTag)
  769. {
  770. if (!strcmp(XML_GetName(line, pos), tag)) inTag = 1;
  771. }
  772. else while ((ch = line[pos]) && XML_IsChar(ch)) pos++;
  773. }
  774. }
  775. else if (ch == '>')
  776. {
  777. if (inTag == 1) inTag = 0;
  778. pos++;
  779. }
  780. else if (inTag == 1)
  781. {
  782. if (!strcmp(XML_GetName(line, pos), "name"))
  783. {
  784. if (!(strcmp(XML_GetParameter(line, pos), name)))
  785. {
  786. inTag = 2;
  787. atStart = tagCount - 1;
  788. if (replacement != -1)
  789. {
  790. if (replacement >= YSI_g_sXMLWritePointer) replacement = -1;
  791. else XML_WriteItemData(replacement, fTemp, (tagCount - 1) * 2);
  792. }
  793. }
  794. }
  795. else XML_GetParameter(line, pos);
  796. }
  797. else pos++;
  798. ch = line[pos];
  799. }
  800. if (!inTag) fwrite(fTemp, line);
  801. if (inTag == 3) inTag = 0;
  802. }
  803. fclose(fHnd);
  804. //fclose(fTemp);
  805. fremove(file);
  806. fHnd = fopen(file, io_write);
  807. //fTemp = fopen("_temp_ysi_user_file_.ysi", io_read);
  808. fseek(fTemp);
  809. if (fHnd && fTemp)
  810. {
  811. while (fread(fTemp, line)) fwrite(fHnd, line);
  812. fclose(fHnd);
  813. fclose(fTemp);
  814. //fremove("_temp_ysi_user_file_.ysi");
  815. if (replacement != -1) YSI_g_sXMLWritePointer = replacement;
  816. return 1;
  817. }
  818. }
  819. if (fHnd)
  820. {
  821. fclose(fHnd);
  822. }
  823. if (fTemp)
  824. {
  825. fclose(fTemp);
  826. //fremove("_temp_ysi_user_file_.ysi");
  827. }
  828. return 0;
  829. }
  830. return 1;
  831. }