Github User Fetcher 1.0.0
C Application with Server and GUI
Loading...
Searching...
No Matches
LuaXML_lib.c
Go to the documentation of this file.
1/*
2LuaXML License
3
4LuaXML is licensed under the terms of the MIT license reproduced below,
5the same as Lua itself. This means that LuaXML is free software and can be
6used for both academic and commercial purposes at absolutely no cost.
7
8Copyright (C) 2007-2013 Gerald Franz, eludi.net
9
10Permission is hereby granted, free of charge, to any person obtaining a copy
11of this software and associated documentation files (the "Software"), to deal
12in the Software without restriction, including without limitation the rights
13to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14copies of the Software, and to permit persons to whom the Software is
15furnished to do so, subject to the following conditions:
16
17The above copyright notice and this permission notice shall be included in
18all copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26THE SOFTWARE.
27*/
28/// @module LuaXML
29
30#include "LuaXML_lib.h"
31
32#include <ctype.h>
33#include <stdbool.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37
38/* compatibility with older Lua versions (<5.2) */
39#if LUA_VERSION_NUM < 502
40
41// Substitute lua_objlen() for lua_rawlen()
42#define lua_rawlen(L, index) lua_objlen(L, index)
43
44// Make use of luaL_register() to achieve same result as luaL_newlib()
45#define luaL_newlib(L, funcs) \
46 do { \
47 lua_newtable(L); \
48 luaL_register(L, NULL, funcs); \
49 } while (0)
50
51#endif
52/* API changes for 5.2+ */
53#if LUA_VERSION_NUM >= 502
54
55// lua_compare() has replaced lua_equal()
56#if !defined(lua_equal)
57#define lua_equal(L, index1, index2) lua_compare(L, index1, index2, LUA_OPEQ)
58#endif
59
60#endif
61/* API changes for 5.3+ */
62#if LUA_VERSION_NUM >= 503
63
64// luaL_optinteger() has replaced luaL_optint()
65#if !defined(luaL_optint)
66#define luaL_optint(L, arg, d) luaL_optinteger(L, arg, d)
67#endif
68
69#endif
70
71
72#define LUAXML_META "LuaXML" // name to be used for metatable
73
74//--- auxliary functions -------------------------------------------
75
76static size_t
77find(const char *s, const char *pattern, size_t start)
78{
79 const char *found = strstr(s + start, pattern);
80 return found ? (size_t)(found - s) : strlen(s);
81}
82
83// push (arbitrary Lua) value to be used as tag key, placing it on top of stack
84static inline void
86{
87 /* Note: Currently this is the number 0, which fits in nicely with using
88 * string keys for attribute-value pairs and also 'stays clear' of the
89 * array of sub-elements (starting at index 1).
90 * Theoretically, this could be any kind of Lua value; but when using a
91 * string key (e.g. "TAG"), extra care needs to be taken that it doesn't
92 * get confused with an attribute - which means that the str() function
93 * should be modified accordingly (to recognise and avoid the tag key).
94 */
95 lua_pushinteger(L, 0);
96}
97
98// convert Lua table at given index to an XML "object", by setting its metatable
99static void
101{
102 if (index < 0)
103 index += lua_gettop(L) + 1; // relative to absolute index
104 if (!lua_istable(L, index))
105 luaL_error(L,
106 "%s() error: invalid type at %d - expected table, got %s",
107 __func__,
108 index,
109 luaL_typename(L, index));
110
112 lua_setmetatable(L, index); // assign metatable
113}
114
115// push an indentation string for the given level to the Lua stack
116static void
118{
119 if (level <= 0) {
120 lua_pushliteral(L, "");
121 return;
122 }
123 luaL_Buffer b;
124 luaL_buffinit(L, &b);
125 // while (level-- > 0) luaL_addlstring(&b, " ", 2);
126 while (level-- > 0)
127 luaL_addchar(&b, '\t'); // one TAB char per level
128 luaL_pushresult(&b);
129}
130
131// tests if a string consists entirely of whitespace
132static bool
133is_whitespace(const char *s)
134{
135 if (!s)
136 return false; // NULL pointer
137 if (*s == 0)
138 return false; // empty string
139 while (*s)
140 if (!isspace(*s++))
141 return false;
142 return true;
143}
144
145// We consider a token "lead in", if it 1) is all whitespace and 2) starts with
146// a newline. (This is typical for line breaks plus indentation on nested XML.)
147static bool
148is_lead_token(const char *s)
149{
150 return is_whitespace(s) && (*s == '\n' || *s == '\r');
151}
152
153/*
154 * For the string at given stack index, substitute any occurrence (exact string
155 * match) of pattern "p" with the replacement string "r".
156 * When done, this function will replace the original string with the result.
157 */
158// TODO / Caveat:
159// We return the luaL_gsub() pointer, but it's unclear (and untested) if that
160// persists after the lua_replace(). Currently the result isn't used anywhere.
161static const char *
162do_gsub(lua_State *L, int index, const char *p, const char *r)
163{
164 if (index < 0)
165 index += lua_gettop(L) + 1; // relative to absolute index
166 const char *result = luaL_gsub(L, lua_tostring(L, index), p, r);
167 lua_replace(L, index);
168 return result;
169}
170
171/*
172 * Lua C function to replace a gsub() match with the corresponding character.
173 * Xml_pushDecode() will use this as a replacement function argument to undo
174 * the XML encodings, passing one match (sequence of digits) at a time.
175 *
176 * Due to the pattern used, the matched string may also be 'x' followed by
177 * a sequence of hexadecimal characters ("xE4"), which is supported too.
178 */
179static int
181{
182 const char *matched = lua_tostring(L, 1);
183 if (matched) {
184 // support both decimal and hexadecimal conversion
185 char c = *matched == 'x' ? strtol(++matched, NULL, 16) : atoi(matched);
186 if (c) {
187 lua_pushlstring(L, &c, 1); // return character as Lua string
188 return 1;
189 } // c == 0 probably indicates conversion failure, return `nil`
190 }
191 return 0;
192}
193
194/* Lua C callback function for a `find()` match. Sets the upvalue (that will
195 * later be the result) and stops the iteration.
196 *
197 * A small problem here is that the callback handling by iterate() means this
198 * function cannot simply return the result on the Lua stack. Instead we need
199 * a "shared" upvalue that can be retrieved 'externally' later. Therefore a
200 * simple, 'flat' Lua value won't do (it can't be shared); so we'll use a table
201 * instead and assign the match to t[1].
202 */
203static int
205{
206 // Upon entry the Lua stack will have `var` and `depth`
207 lua_settop(L, 1); // discard depth, leaving var on the stack
208 lua_rawseti(L, lua_upvalueindex(1), 1); // store to upvalue table
209 lua_pushboolean(L, false); // return false to stop iteration
210 return 1;
211}
212
213/// strip all leading / trailing whitespace
214// @field WS_TRIM
215
216/// remove "lead in" whitespace before tags
217// @field WS_NORMALIZE
218
219/// preserve all whitespace, even between tags
220// @field WS_PRESERVE
221
227
228// control chars used by the Tokenizer to denote special meanings
229#define ESC 27 /* end of scope, closing tag */
230#define OPN 28 /* "open", start of tag */
231#define CLS 29 /* closes opening tag, actual content follows */
232
233//--- internal tokenizer -------------------------------------------
234
235typedef struct Tokenizer_s {
236 /// stores string to be tokenized
237 const char *s;
238 /// stores size of string to be tokenized
239 size_t s_size;
240 /// stores current read position
241 size_t i;
242 /// stores current read context
244 /// stores flag for "raw" byte sequence, *DON'T* decode any further
245 int cdata;
246 /// stores next token, if already determined
247 const char *m_next;
248 /// size of next token
250 /// pointer to current token
251 char *m_token;
252 /// size of current token
254 /// capacity of current token
256 /// whitespace handling
259
260static Tokenizer *
261Tokenizer_new(const char *str, size_t str_size, enum whitespace_mode mode)
262{
263 Tokenizer *tok = calloc(1, sizeof(Tokenizer));
264 tok->s_size = str_size;
265 tok->s = str;
266 tok->mode = mode;
267 return tok;
268}
269
270static void
272{
273 free(tok->m_token);
274 free(tok);
275}
276
277#if LUAXML_DEBUG
278static void
280{
281 printf(" @%u %s\n",
282 tok->i,
283 !tok->m_token ? "(null)"
284 : (tok->m_token[0] == ESC)
285 ? "(esc)"
286 : (tok->m_token[0] == OPN)
287 ? "(open)"
288 : (tok->m_token[0] == CLS) ? "(close)"
289 : tok->m_token);
290 fflush(stdout);
291}
292#else
293#define Tokenizer_print(tok) /* ignore */
294#endif
295
296static const char *
297Tokenizer_set(Tokenizer *tok, const char *s, size_t size)
298{
299 if (!size || !s)
300 return NULL;
301 free(tok->m_token);
302 tok->m_token = malloc(size + 1);
303 strncpy(tok->m_token, s, size);
304 tok->m_token[size] = 0;
305 tok->m_token_size = tok->m_token_capacity = size;
306 Tokenizer_print(tok);
307 return tok->m_token;
308}
309
310static void
312{
313 if (tok->m_token_size + 1 >= tok->m_token_capacity) {
314 tok->m_token_capacity =
315 tok->m_token_capacity ? tok->m_token_capacity * 2 : 16;
316 tok->m_token = realloc(tok->m_token, tok->m_token_capacity);
317 }
318 tok->m_token[tok->m_token_size] = ch;
319 tok->m_token[++tok->m_token_size] = 0;
320}
321
322static const char *
324{
325 // NUL-terminated strings for the special tokens
326 static const char ESC_str[] = {ESC, 0};
327 static const char OPEN_str[] = {OPN, 0};
328 static const char CLOSE_str[] = {CLS, 0};
329
330 if (tok->m_token) {
331 free(tok->m_token);
332 tok->m_token = NULL;
333 tok->m_token_size = tok->m_token_capacity = 0;
334 }
335
336 char quotMode = 0;
337 int tokenComplete = 0;
338 while (tok->m_next_size || (tok->i < tok->s_size)) {
339 tok->cdata = 0;
340
341 if (tok->m_next_size) {
342 Tokenizer_set(tok, tok->m_next, tok->m_next_size);
343 tok->m_next = NULL;
344 tok->m_next_size = 0;
345 return tok->m_token;
346 }
347
348 switch (tok->s[tok->i]) {
349 case '"':
350 case '\'':
351 if (tok->tagMode) {
352 // toggle quotation mode
353 if (!quotMode)
354 quotMode = tok->s[tok->i];
355 else if (quotMode == tok->s[tok->i])
356 quotMode = 0;
357 }
358 Tokenizer_append(tok, tok->s[tok->i]);
359 break;
360
361 case '<':
362 if (!quotMode && (tok->i + 4 < tok->s_size)
363 && (strncmp(tok->s + tok->i, "<!--", 4) == 0))
364 tok->i = find(tok->s, "-->", tok->i + 4) + 2; // strip comments
365 else if (!quotMode && (tok->i + 9 < tok->s_size)
366 && (strncmp(tok->s + tok->i, "<![CDATA[", 9) == 0)) {
367 if (tok->m_token_size > 0)
368 // finish current token first, after that reparse CDATA
369 tokenComplete = 1;
370 else {
371 // interpret CDATA
372 size_t b = tok->i + 9;
373 tok->i = find(tok->s, "]]>", b) + 3;
374 size_t cdata_len = tok->i - b - 3;
375 if (cdata_len > 0) {
376 tok->cdata = 1; // mark as "raw" byte sequence
377 return Tokenizer_set(tok, tok->s + b, cdata_len);
378 }
379 }
380 --tok->i;
381 } else if (!quotMode && (tok->i + 1 < tok->s_size)
382 && ((tok->s[tok->i + 1] == '?')
383 || (tok->s[tok->i + 1] == '!')))
384 tok->i =
385 find(tok->s, ">", tok->i + 2); // strip meta information
386 else if (!quotMode && !tok->tagMode) {
387 if ((tok->i + 1 < tok->s_size) && (tok->s[tok->i + 1] == '/')) {
388 // "</" sequence that starts a closing tag
389 tok->m_next = ESC_str;
390 tok->m_next_size = 1;
391 tok->i = find(tok->s, ">", tok->i + 2);
392 } else {
393 // regular '<' opening a new tag
394 tok->m_next = OPEN_str;
395 tok->m_next_size = 1;
396 tok->tagMode = 1;
397 }
398 tokenComplete = 1;
399 } else
400 Tokenizer_append(tok, tok->s[tok->i]);
401 break;
402
403 case '/':
404 if (tok->tagMode && !quotMode) {
405 tokenComplete = 1;
406 if ((tok->i + 1 < tok->s_size) && (tok->s[tok->i + 1] == '>')) {
407 // "/>" sequence = end of 'empty' tag
408 tok->tagMode = 0;
409 tok->m_next = ESC_str;
410 tok->m_next_size = 1;
411 ++tok->i;
412 } else
413 Tokenizer_append(tok, tok->s[tok->i]);
414 } else
415 Tokenizer_append(tok, tok->s[tok->i]);
416 break;
417
418 case '>':
419 if (!quotMode && tok->tagMode) {
420 // this '>' closes the current tag
421 tok->tagMode = 0;
422 tokenComplete = 1;
423 tok->m_next = CLOSE_str;
424 tok->m_next_size = 1;
425 } else
426 Tokenizer_append(tok, tok->s[tok->i]);
427 break;
428
429 case ' ':
430 case '\r':
431 case '\n':
432 case '\t':
433 if (tok->tagMode && !quotMode) {
434 // within a tag, any unquoted whitespace ends the current token
435 // (= attribute)
436 if (tok->m_token_size)
437 tokenComplete = 1;
438 } else if (tok->m_token_size || tok->mode != WHITESPACE_TRIM)
439 Tokenizer_append(tok, tok->s[tok->i]);
440 break;
441
442 default:
443 Tokenizer_append(tok, tok->s[tok->i]);
444 }
445 ++tok->i;
446 if (tok->i >= tok->s_size || (tokenComplete && tok->m_token_size)) {
447 tokenComplete = 0;
448 if (tok->mode == WHITESPACE_TRIM) // trim whitespace
449 while (tok->m_token_size
450 && isspace(tok->m_token[tok->m_token_size - 1]))
451 tok->m_token[--tok->m_token_size] = 0;
452 if (tok->m_token_size)
453 break;
454 }
455 }
456 Tokenizer_print(tok);
457 return tok->m_token;
458}
459
460//--- local variables ----------------------------------------------
461
462// 'private' table mapping between special chars and their XML substitutions
463static int sv_code_ref; // (will receive a LUA reference)
464
465//--- public methods -----------------------------------------------
466
467/** sets or returns tag of a LuaXML object.
468This method is just "syntactic sugar" (using a typical Lua term) that allows
469the writing of clearer code. LuaXML stores the tag value of an XML statement
470at table index 0, hence it can be simply accessed or altered by `var[0]`.
471However, writing `var:tag()` for access or `var:tag("newTag")` for altering
472may be more self explanatory (and future-proof in case LuaXML's tag handling
473should ever change).
474
475@function tag
476@param var the variable whose tag should be accessed, a LuaXML object
477@tparam ?string tag the new tag to be set
478@return If you have passed a new tag, the function will return `var` (with
479its tag changed); otherwise the result will be the current tag of `var`
480(normally a string).
481*/
482static int
484{
485 // the function will only operate on tables
486 if
487 lua_istable(L, 1)
488 {
489 lua_settop(L, 2);
490 push_TAG_key(L); // place tag key on top of stack (#3)
491 if (lua_type(L, 2) == LUA_TSTRING) {
492 lua_pushvalue(L, 2); // duplicate the value
493 lua_rawset(L, 1);
494 // we return the (modified) table
495 lua_settop(L, 1);
496 return 1;
497 } else {
498 // "tag" is empty or wrong type, retrieve the current tag
499 lua_rawget(L, 1);
500 return 1;
501 }
502 }
503 return 0;
504}
505
506/** creates a LuaXML "object", and optionally sets its tag.
507The function either sets the metatable of an existing Lua table, or creates a
508new (empty) "object". If you pass an optional` tag` string, it will be assigned
509to the result.
510
511(It's also possible to call this as `new(tag)`, which creates a new XML object
512with the given tag and is equivalent to `new({}, tag)`.)
513
514Note that it's not mandatory to use this function in order to treat a Lua table
515as LuaXML object. Setting the metatable just allows the usage of a more
516object-oriented syntax (e.g. `xmlvar:str()` instead of `xml.str(xmlvar)`).
517XML objects created by `load` or `eval` automatically offer the
518object-oriented syntax.
519
520@function new
521@param arg (optional) _(1)_ a table to be converted to a LuaXML object,
522or _(2)_ the tag of the new LuaXML object
523@tparam ?string tag a tag value that will be assigned to the object
524@return LuaXML object, either newly created or the conversion of `arg`;
525optionally tagged as requested
526*/
527static int
529{
530 if (!lua_istable(L, 1)) {
531 // create a new table and move it to the bottom of the stack (#1),
532 // possibly shifting other elements "one up"
533 lua_newtable(L);
534 lua_insert(L, 1);
535 }
536 // element at #1 now is a table, convert to "object"
537 make_xml_object(L, 1);
538
539 if (lua_type(L, 2) == LUA_TSTRING) {
541 lua_pushvalue(L, 1); // duplicate the object table
542 lua_pushvalue(L, 2); // duplicate the tag (string)
543 lua_call(L, 2, 0); // call the "tag" function, discarding any result
544 }
545 lua_settop(L, 1);
546 return 1;
547}
548
549/** appends a new subordinate LuaXML object to an existing one.
550optionally sets tag
551
552@function append
553@param var the parent LuaXML object
554@tparam ?string tag the tag of the appended LuaXML object
555@return appended LuaXML object, or `nil` in case of errors
556*/
557static int
559{
560 if (lua_type(L, 1) == LUA_TTABLE) {
561 lua_settop(L, 2);
563 lua_insert(L, 2);
564 lua_call(L, 1, 1); // new(tag)
565 lua_pushvalue(L, -1); // duplicate result
566 lua_rawseti(L, 1, lua_rawlen(L, 1) + 1); // append to parent (elements)
567 return 1;
568 }
569 return 0;
570}
571
572// Push XML-encoded string for the Lua value at given index.
573// Will automatically use a tostring() conversion first, if necessary.
574static void
576{
577 if (index < 0)
578 index += lua_gettop(L) + 1; // relative to absolute index
579 if (lua_type(L, index) == LUA_TSTRING)
580 lua_pushvalue(L, index); // already a string, just duplicate it
581 else {
582 lua_getglobal(L, "tostring");
583 lua_pushvalue(L, index); // duplicate value
584 lua_call(L, 1, 1); // tostring()
585 }
586
587 // always do "&amp;" first
588 // (avoids later affecting other substitutions, which may contain '&')
589 do_gsub(L, -1, "&", "&amp;");
590
591 // encode other special entities
593 lua_pushnil(L);
594 while (lua_next(L, -2)) {
595 // Lua stack has string to work on (-4), substitution table (-3),
596 // table key (-2 = special char) and value (-1 = replacement)
597 // (We want to replace the original char with the XML encoding.)
598 do_gsub(L, -4, lua_tostring(L, -2), lua_tostring(L, -1));
599 lua_pop(L, 1); // pop value, leaving key for the next iteration
600 }
601 lua_pop(L, 1); // pop substitution table to realign the stack
602
603 // transfer string one character at a time, encoding any chars with MSB set
604 char buf[8];
605 const unsigned char *s = (unsigned char *)lua_tostring(L, -1);
606 luaL_Buffer b;
607 luaL_buffinit(L, &b);
608 while (*s) {
609 if (*s < 128)
610 luaL_addchar(&b, *s); // copy character literally
611 else {
612 int len = snprintf(buf, sizeof(buf), "&#%d;", *s); // encode char
613 luaL_addlstring(&b, buf, len);
614 }
615 s++;
616 }
617 luaL_pushresult(&b);
618 lua_replace(L, -2); // (leaving the result on the stack)
619}
620
621/*
622// Push a string, then do XML conversion on it - result remains on top of stack.
623static void Xml_pushEncodeStr(lua_State *L, const char *s, int size) {
624 if (size == 0) {
625 lua_pushliteral(L, "");
626 return;
627 }
628 if (size < 0) size = strlen(s);
629 lua_pushlstring(L, s, size);
630 Xml_pushEncode(L, -1);
631 lua_replace(L, -2);
632}
633*/
634
635// Push Lua representation of the given string, while decoding any special XML
636// encodings
637static void
638Xml_pushDecode(lua_State *L, const char *s, int size)
639{
640 if (size == 0) {
641 lua_pushliteral(L, "");
642 return;
643 }
644 if (size < 0)
645 size = strlen(s);
646
647 // try a gsub() substition of decimal and hexadecimal character encodings
648 lua_pushlstring(L, s, size); // initial string
649 lua_pushliteral(L, "gsub");
650 lua_gettable(L, -2); // using string as object, retrieve the "gsub" function
651 lua_insert(L, -2); // swap with function, making string the arg #1
652 lua_pushliteral(L, "&#(x?%x+);"); // pattern for XML encodings (arg #2)
653 lua_pushcfunction(L, XMLencoding_replacement); // replacement func (arg #3)
654 lua_call(L, 3, 1); // three parameters, one result (the substituted string)
655
657 lua_pushnil(L);
658 while (lua_next(L, -2)) {
659 // Lua stack has string to work on (-4), substitution table (-3),
660 // table key (-2 = special char) and value (-1 = replacement)
661 // (We want to replace the XML encoding with the original char.)
662 do_gsub(L, -4, lua_tostring(L, -1), lua_tostring(L, -2));
663 lua_pop(L, 1); // pop value, leaving key for the next iteration
664 }
665 lua_pop(L, 1); // pop substitution table, leaving result string on stack
666 do_gsub(L, -1, "&amp;", "&"); // this should always be done last
667}
668
669/** parses an XML string into a Lua table.
670The table will contain a representation of the XML tag, attributes (and their
671values), and element content / subelements (either as strings or nested LuaXML
672"objects").
673
674Note: Parsing "wide" strings or Unicode (UCS-2, UCS-4, UTF-16) currently is
675__not__ supported. If needed, convert such `xml` data to UTF-8 before passing it
676to `eval()`. UTF-8 should be safe to use, and this function will also recognize
677and ignore a UTF-8 BOM (byte order mark) at the start of `xml`.
678
679@function eval
680
681@tparam string|userdata xml
682the XML to be converted. When passing a userdata type `xml` value, it must
683point to a C-style (NUL-terminated) string.
684
685@tparam ?number mode
686whitespace handling mode, one of the `WS_*` constants - see [Fields](#Fields).
687defaults to `WS_TRIM` (compatible to previous LuaXML versions)
688
689@return a LuaXML object containing the XML data, or `nil` in case of errors
690*/
691static int
693{
695 const char *str;
696 size_t str_size;
697 if (lua_isuserdata(L, 1)) {
698 str = lua_touserdata(L, 1);
699 str_size = strlen(str);
700 } else
701 str = luaL_checklstring(L, 1, &str_size);
702
703 if (str_size >= 3 && strncmp(str, "\xEF\xBB\xBF", 3) == 0) {
704 // ignore / skip over UTF-8 BOM (byte order mark)
705 str += 3;
706 str_size -= 3;
707 }
708
709 Tokenizer *tok = Tokenizer_new(str, str_size, mode);
710 lua_settop(L, 1);
711 const char *token;
712 int firstStatement = 1;
713 while ((token = Tokenizer_next(tok)))
714 if (*token == OPN) { // new tag found
715 if (lua_gettop(L) > 1) {
716 lua_newtable(L);
718 -1); // duplicate table (keep one copy on stack)
719 lua_rawseti(L,
720 -3,
721 lua_rawlen(L, -3) + 1); // set parent subelement
722 } else {
723 if (firstStatement) {
724 lua_newtable(L);
725 firstStatement = 0;
726 } else
727 return 0;
728 }
729 make_xml_object(L, -1); // assign metatable
730
731 // parse tag and content:
732 push_TAG_key(L); // place tag key on top of stack
734 lua_rawset(L, -3);
735
736 while ((token = Tokenizer_next(tok)) && (*token != CLS)
737 && (*token != ESC)) {
738 // parse tag header
739 size_t sepPos = find(token, "=", 0);
740 if (token[sepPos]) { // regular attribute (key="value")
741 const char *aVal = token + sepPos + 2;
742 lua_pushlstring(L, token, sepPos);
743 Xml_pushDecode(L, aVal, strlen(aVal) - 1);
744 lua_rawset(L, -3);
745 }
746 }
747 if (!token || (*token == ESC)) {
748 // this tag has no content, only attributes
749 if (lua_gettop(L) > 2)
750 lua_pop(L, 1);
751 else
752 break;
753 }
754 } else if (*token == ESC) { // previous tag is over
755 if (lua_gettop(L) > 2)
756 lua_pop(L, 1); // pop current table
757 else
758 break;
759 } else { // read elements
760 if (lua_gettop(L) > 1) {
761 // when normalizing, we ignore tokens considered "lead-in" type
762 if (mode != WHITESPACE_NORMALIZE || !is_lead_token(token)) {
763 if (tok->cdata) // "raw" mode, don't change token string!
764 lua_pushstring(L, token);
765 else
766 Xml_pushDecode(L, token, -1);
767 lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
768 }
769 } else // element stack is empty, i.e. we encountered a token
770 // *before* any tag
771 if (!is_whitespace(token))
772 luaL_error(L,
773 "Malformed XML: non-empty string '%s' before any "
774 "tag (parser pos %d)",
775 token,
776 (int)tok->i);
777 }
778 Tokenizer_delete(tok);
779 return lua_gettop(L) - 1;
780}
781
782/** loads XML data from a file and returns it as table.
783Basically, this is just calling `eval` on the given file's content.
784
785@function load
786@tparam string filename the name and path of the file to be loaded
787@tparam ?number mode whitespace handling mode, defaults to `WS_TRIM`
788@return a Lua table representing the XML data, or `nil` in case of errors
789*/
790static int
792{
793 const char *filename = luaL_checkstring(L, 1);
794 FILE *file = fopen(filename, "r");
795 if (!file)
796 return luaL_error(L,
797 "LuaXML ERROR: \"%s\" file error or file not found!",
798 filename);
799
800 fseek(file, 0, SEEK_END);
801 size_t sz = ftell(file);
802 rewind(file);
803 char *buffer = malloc(sz + 1);
804 sz = fread(buffer, 1, sz, file);
805 fclose(file);
806 buffer[sz] = 0;
807 lua_pushlightuserdata(L, buffer);
808 lua_replace(L, 1);
809 int result = Xml_eval(L);
810 free(buffer);
811 return result;
812};
813
814/** registers a custom code for the conversion between non-standard characters
815and XML character entities.
816
817By default, only the most basic entities are known to LuaXML:
818 " < > '
819On top (and independent) of that, the **ampersand** sign always gets encoded /
820decoded separately: `&amp;` &harr; `&amp;amp;`. Character codes above 127 are
821directly converted to an appropriate XML encoding, representing the character
822number (e.g. `&amp;#160;`). If other special encodings are needed, they can be
823registered using this function.
824
825Note: LuaXML now manages these encodings in a (private) standard Lua table.
826This allows you to replace entries by calling `registerCode()` again, using the
827same `decoded` and a different `encoded`. Encodings may even be removed later,
828by explictly registering a `nil` value: `registerCode(decoded, nil)`.
829
830@function registerCode
831@tparam string decoded the character (sequence) to be used within Lua
832@tparam string encoded the character entity to be used in XML
833@see encode, decode
834*/
835static int
837{
838 // We require the "decoded" string, but allow `nil` as argument #2.
839 // That way, users may remove entries from the table again.
840 luaL_checkstring(L, 1);
841 if (!lua_isnoneornil(L, 2))
842 luaL_checkstring(L, 2);
843
844 lua_settop(L, 2);
845 lua_rawgeti(L, LUA_REGISTRYINDEX, sv_code_ref); // get translation table
846 lua_insert(L, 1);
847 lua_rawset(L, 1); // assign key-value pair (k "decoded" -> v "encoded")
848 return 0;
849}
850
851/** converts a string to XML encoding.
852This function transforms` str` by replacing any special characters with
853suitable XML encodings.
854
855@usage
856print(xml.encode("<->")) -- "&lt;-&gt;"
857
858@function encode
859@tparam string str string to be transformed
860@treturn string the XML-encoded string
861@see decode, registerCode
862*/
863static int
865{
866 luaL_checkstring(L, 1); // make sure arg #1 is a string
867 Xml_pushEncode(L, 1); // and convert it
868 return 1;
869}
870
871/** converts a string from XML encoding.
872This function transforms` str` by replacing any special XML encodings with
873their "plain text" counterparts.
874
875@usage
876print((xml.decode("&lt;-&gt;")) -- "<->"
877
878@function decode
879@tparam string str string to be transformed
880@treturn string the decoded string
881@see encode, registerCode
882*/
883static int
885{
886 size_t size;
887 luaL_checklstring(L, 1, &size); // make sure arg #1 is a string
888 Xml_pushDecode(L, lua_tostring(L, 1), size); // and convert it
889 return 1;
890}
891
892/** converts any Lua value to an XML string.
893@function str
894
895@param value
896the value to be converted, normally a table (LuaXML object). However this
897function will 'encapsulate' other Lua values (of arbitrary type) in a way that
898should make them valid XML.
899<br>Note: Passing no `value` will cause the function to return `nil`.
900
901@tparam ?number indent
902indentation level for 'pretty' output. Mainly for internal use, defaults to 0.
903
904@tparam ?string tag
905the tag to be used in case `value` doesn't already have an 'implicit' tag.
906Mainly for internal use.
907
908@treturn string
909an XML string, or `nil` in case of errors.
910*/
911static int
913{
914 // Note:
915 // Be very careful about mixing Lua stack usage and buffer access here.
916 // The stack *must* be (re)balanced before accessing "b", i.e. any output
917 // should only occur at the same Lua stack level as the previous one!
918 luaL_Buffer b;
919
920 lua_settop(L, 3);
921 int type = lua_type(L, 1); // type of "value"
922 if (type == LUA_TNIL)
923 return 0;
924
925 if (type == LUA_TTABLE) {
926 push_TAG_key(L);
927 lua_rawget(L, 1); // retrieve tag entry from the table (may be `nil`)
928
929 // order of precedence: value[0], explicit tag string, Lua type name
930 const char *tag = lua_tostring(L, -1);
931 if (!tag)
932 tag = lua_tostring(L, 3);
933 if (!tag)
934 tag = lua_typename(L, type);
935
936 // Four elements already on stack: value, indent, tag, value[0]
937 // Use a string (#5) to manage (concatenate) simple attributes
938 lua_pushliteral(L, "");
939 // And a table (#6) to take care of (collect) 'extended' attributes
940 lua_newtable(L);
941 size_t table_attr = 0;
942
943 luaL_buffinit(L, &b);
945 luaL_addvalue(&b);
946 luaL_addchar(&b, '<');
947 luaL_addstring(&b, tag);
948
949 // Iterate over string keys (= attributes)
950 lua_pushnil(L);
951 while (lua_next(L, 1)) {
952 // (k, v) pair on the stack
953 if (lua_type(L, -2) == LUA_TSTRING) {
954 // (the "_M" test here is to avoid recursion on module tables)
955 if (lua_istable(L, -1) && strcmp(lua_tostring(L, -2), "_M")) {
957 lua_pushvalue(L, -2); // duplicate "v"
958 lua_pushinteger(L, lua_tointeger(L, 2) + 1); // indent + 1
959 lua_pushvalue(L, -4); // duplicate "k"
960 lua_call(L, 3, 1); // xml.str(v, indent + 1, k)
961 lua_rawseti(L, 6, ++table_attr); // append string to table
962 } else {
963 Xml_pushEncode(L, -1); // encode(tostring(v))
965 "%s %s=\"%s\"",
966 lua_tostring(L, 5),
967 lua_tostring(L, -3),
968 lua_tostring(L, -1));
969 lua_replace(L, 5); // new attribute string
970 lua_pop(L, 1); // realign stack
971 }
972 }
973 lua_pop(L, 1); // pop <v>alue, leaving <k>ey for next iteration
974 }
975 // append "simple" attribute string to the output
976 if (lua_rawlen(L, 5) > 0)
977 luaL_addstring(&b, lua_tostring(L, 5));
978
979 size_t count = lua_rawlen(L, 1); // number of "array" (sub)elements
980 if (count == 0 && table_attr == 0) {
981 // no sub-elements and no extended attr -> close tag and we're done
982 luaL_addlstring(&b, " />\n", 4);
983 luaL_pushresult(&b);
984 return 1;
985 }
986 luaL_addchar(&b, '>'); // close opening tag
987 if (count == 1 && table_attr == 0) {
988 // single subelement, no extended attributes
989 lua_rawgeti(L, 1, 1); // value[1]
990 if (!lua_istable(L, -1)) {
991 // output as single string, then close tag
992 Xml_pushEncode(L, -1); // encode(tostring(value[1]))
993 lua_replace(L, -2);
994 luaL_addvalue(&b); // add and pop
995 luaL_addlstring(&b, "</", 2);
996 luaL_addstring(&b, tag);
997 luaL_addlstring(&b, ">\n", 2);
998 luaL_pushresult(&b);
999 return 1;
1000 }
1001 lua_pop(L, 1); // discard (table) value, to realign stack
1002 }
1003 luaL_addchar(&b, '\n');
1004
1005 // Loop over all the sub-elements, placing each on a separate line
1006 size_t k;
1007 for (k = 1; k <= count; k++) {
1008#if LUA_VERSION_NUM < 503
1009 lua_rawgeti(L, 1, k);
1010 type = lua_type(L, -1);
1011#else
1012 type = lua_rawgeti(L, 1, k); // (Lua 5.3 returns type directly)
1013#endif
1014 if (type == LUA_TSTRING) {
1015 push_indentStr(L, lua_tointeger(L, 2) + 1); // indentation
1016 Xml_pushEncode(L, -2);
1017 lua_remove(L, -3);
1018 lua_pushliteral(L, "\n");
1019 lua_concat(L, 3);
1020 } else {
1022 lua_insert(L, -2); // place function before value
1023 lua_pushinteger(L, lua_tointeger(L, 2) + 1); // indent + 1
1024 lua_call(L, 2, 1); // xml.str(v, indent + 1)
1025 }
1026 luaL_addvalue(&b); // add (string) to output, pop from stack
1027 }
1028
1029 // Finally we'll take care of the "extended" (table-type) attributes.
1030 // The output is appended after the regular sub-elements, in order
1031 // not to affect their numbering.
1032 // Just process the corresponding table, concatenating all entries:
1033 for (k = 1; k <= table_attr; k++) {
1034 lua_rawgeti(L, 6, k);
1035 luaL_addvalue(&b);
1036 }
1037
1038 // closing tag
1039 push_indentStr(L, lua_tointeger(L, 2));
1040 luaL_addvalue(&b);
1041 luaL_addlstring(&b, "</", 2);
1042 luaL_addstring(&b, tag);
1043 luaL_addlstring(&b, ">\n", 2);
1044
1045 luaL_pushresult(&b);
1046 return 1;
1047 }
1048
1049 // Getting here means a "flat" Lua value, format to XML as a single string
1050 const char *tag = lua_tostring(L, 3);
1051 if (!tag)
1052 tag = lua_typename(L, type); // use either tag or the type name
1053 luaL_buffinit(L, &b);
1054 push_indentStr(L, lua_tointeger(L, 2));
1055 luaL_addvalue(&b);
1056 luaL_addchar(&b, '<');
1057 luaL_addstring(&b, tag);
1058 luaL_addchar(&b, '>');
1059
1060 Xml_pushEncode(L, 1); // encode(tostring(value))
1061 luaL_addvalue(&b);
1062
1063 luaL_addlstring(&b, "</", 2);
1064 luaL_addstring(&b, tag);
1065 luaL_addlstring(&b, ">\n", 2);
1066 luaL_pushresult(&b);
1067 return 1;
1068}
1069
1070/** match XML entity against given (optional) criteria.
1071Passing `nil` for one of the` tag`, `key`, or `value` parameters means "don't
1072care" (i.e. match anything for that particular aspect). So for example
1073 var:match(nil, "text", nil)
1074 -- or shorter, but identical: var:match(nil, "text")
1075will look for an XML attribute (name) "text" to be present in `var`, but won't
1076consider its value or the tag of `var`.
1077
1078Note: If you want to test for a specific attribute `value`, so also have to
1079supply a `key` - otherwise `value` will be ignored.
1080
1081@usage
1082-- each of these will either return `x`, or `nil` in case of no match
1083
1084x:match("foo") -- test for x:tag() == "foo"
1085x:match(nil, "bar") -- test if x has a "bar" attribute
1086x:match(nil, "foo", "bar") -- test if x has a "foo" attribute that equals "bar"
1087x:match("foobar", "foo", "bar") -- test for "foobar" tag, and attr "foo" ==
1088"bar"
1089
1090@function match
1091
1092@param var
1093the variable to test, normally a Lua table or LuaXML object. (If `var` is not
1094a table type, the test always fails.)
1095
1096@tparam ?string tag
1097If set, has to match the XML `tag` (i.e. must be equal to the `tag(var, nil)`
1098result)
1099
1100@tparam ?string key
1101If set, a corresponding **attribute key** needs to be present (exact name
1102match).
1103
1104@param value (optional)
1105arbitrary Lua value. If set, the **attribute value** for `key` has to match it.
1106
1107@return
1108either `nil` for no match; or the `var` argument properly converted to a
1109LuaXML object, equivalent to `xml.new(var)`.
1110
1111This allows you to either make direct use of the matched LuaXML object, or to
1112use the return value in a boolean test (`if xml.match(...)`), which is a common
1113Lua idiom.
1114*/
1115static int
1117{
1118 if (lua_type(L, 1) == LUA_TTABLE) {
1119 if (!lua_isnoneornil(L, 2)) {
1120 push_TAG_key(L);
1121 lua_rawget(L, 1); // get the tag value from var
1122 if (!lua_equal(L, -1, 2))
1123 return 0; // tag mismatch, return `nil`
1124 lua_pop(L, 1); // realign stack
1125 }
1126 if (lua_type(L, 3) == LUA_TSTRING) {
1127 lua_pushvalue(L, 3); // duplicate attribute key
1128 lua_rawget(L, 1); // try to get value from var
1129 if (lua_isnil(L, -1))
1130 return 0; // no such attribute
1131 if (!lua_isnoneornil(L, 4)) {
1132 if (!lua_equal(L, -1, 4))
1133 return 0; // attribute value mismatch
1134 }
1135 }
1136 lua_settop(L, 1);
1137 make_xml_object(L, 1);
1138 return 1;
1139 }
1140 return 0;
1141}
1142
1143/** iterates a LuaXML object,
1144invoking a callback function for all matching (sub)elements.
1145
1146The iteration starts with the variable `var` itself (= default depth 0).
1147A callback function `cb` gets invoked for each `match`, depending on the
1148specified criteria. If the `r` flag is set, the process will
1149repeat **recursively** for the subelements of `var` (at depth + 1). You can
1150limit the scope by setting a maximum depth, or have the callback function
1151explicitly request to stop the iteration (by returning `false`).
1152
1153@function iterate
1154
1155@param var the table (LuaXML object) to iterate
1156
1157@tparam function cb
1158callback function. `callback(var, depth)` will be called for each matching
1159element.<br>
1160The function may return `false` to request a stop; if its result is
1161any other value (including `nil`), the iteration will continue.
1162
1163@tparam ?string tag XML tag to be matched
1164@tparam ?string key attribute key to be matched
1165@param value (optional) attribute value to be matched
1166
1167@tparam ?boolean r
1168recursive operation. If `true`, also iterate over the subelements of `var`
1169
1170@tparam ?number max maximum depth allowed
1171@tparam ?number d initial depth value, defaults to 0
1172
1173@return
1174The function returns two values: a counter representing the number of elements
1175that were successfully matched (and processed), and a boolean completion flag.
1176The latter is `true` for an exhaustive iteration, and `false` if was stopped
1177from the callback.
1178
1179@see match
1180*/
1181static int
1183{
1184 lua_settop(L, 8);
1185 luaL_checktype(L, 2, LUA_TFUNCTION); // callback must be a function
1186 int maxdepth = luaL_optint(L, 7, -1); // default (< 0) indicates "no limit"
1187 int depth = lua_tointeger(L, 8);
1188 int count = 0;
1189 bool cont = true;
1190 // examine "var" element first
1192 lua_pushvalue(L, 1); // var
1193 lua_pushvalue(L, 3); // tag
1194 lua_pushvalue(L, 4); // key
1195 lua_pushvalue(L, 5); // value
1196 lua_call(L, 4, 1);
1197 if (!lua_isnil(L, -1)) { // "var" matches, invoke callback
1198 count = 1;
1199 lua_pushvalue(L, 2); // duplicate function
1200 lua_insert(L, -2);
1202 lua_call(L, 2, 1);
1203 lua_pushboolean(L, false);
1204 cont = !lua_equal(L, -1, -2);
1205 lua_pop(L, 2);
1206 } else
1207 lua_pop(L, 1);
1208 if (cont && lua_toboolean(L, 6) && lua_type(L, 1) == LUA_TTABLE) {
1209 // process "children" / sub-elements recursively
1210 depth += 1;
1211 if (maxdepth < 0 || depth <= maxdepth) {
1212 int k = 0;
1213 while (true) {
1215 lua_rawgeti(L, 1, ++k);
1216 if (lua_isnil(L, -1))
1217 break; // no element var[k], exit loop
1218 lua_pushvalue(L, 2);
1219 lua_pushvalue(L, 3);
1220 lua_pushvalue(L, 4);
1221 lua_pushvalue(L, 5);
1222 lua_pushboolean(L, true);
1223 lua_pushvalue(L, 7);
1225 lua_call(L, 8, 2); // done, continue = iterate(var[k], ...)
1226 count += lua_tointeger(L, -2);
1227 if (!lua_toboolean(L, -1)) {
1228 lua_pushinteger(L, count);
1229 lua_pushboolean(L, false);
1230 return 2;
1231 }
1232 lua_pop(L, 2);
1233 }
1234 }
1235 }
1236 lua_pushinteger(L, count);
1237 lua_pushboolean(L, true);
1238 return 2;
1239}
1240
1241/** recursively searches a Lua table for a subelement
1242matching the provided tag and attribute. See the description of `match` for
1243the logic involved with testing for` tag`, `key` and `value`.
1244
1245@function find
1246@param var the table to be searched in
1247@tparam ?string tag the XML tag to be found
1248@tparam ?string key the attribute key (= exact name) to be found
1249@param value (optional) the attribute value to be found
1250@return the first (sub-)table that satisfies the search condition,
1251or `nil` for no match
1252*/
1253static int
1255{
1256 lua_settop(L, 4); // accept at most four parameters for this function
1257
1258 lua_newtable(L); // upon a match, this table will receive our result as t[1]
1259 lua_insert(L, 1); // (move it before anything else)
1260
1262 lua_insert(L, 2); // iterate is now stack arg #2, `var` at #3
1263 lua_pushvalue(L, 1); // duplicate the table (for use as upvalue)
1264 lua_pushcclosure(L, find_on_match, 1); // create a C closure
1265 lua_insert(L, 4); // place the callback function (closure) at #4
1266 // (`tag`, `key` and `value` have moved to #5, #6 and #7 respectively)
1267 lua_pushboolean(L, true); // set "recursive" flag (#8)
1268
1269 // iterate(var, find_on_match, tag, key, value, true), discarding results
1270 // (but if something matches, we expect that `find_on_match` sets t[1])
1271 lua_call(L, 6, 0);
1272 lua_rawgeti(L, 1, 1);
1273 return 1; // returns result[1], which may be `nil` (if no match)
1274}
1275
1276#ifdef __cplusplus
1277extern "C" {
1278#endif
1279int _EXPORT
1281{
1282 static const struct luaL_Reg funcs[] = {{"append", Xml_append},
1283 {"decode", Xml_decode},
1284 {"encode", Xml_encode},
1285 {"eval", Xml_eval},
1286 {"find", Xml_find},
1287 {"iterate", Xml_iterate},
1288 {"load", Xml_load},
1289 {"match", Xml_match},
1290 {"new", Xml_new},
1291 {"registerCode", Xml_registerCode},
1292 {"str", Xml_str},
1293 {"tag", Xml_tag},
1294 {NULL, NULL}};
1295 luaL_newlib(L, funcs);
1296
1297 // create a metatable for LuaXML "objects"
1299 lua_pushliteral(L, "__index");
1300 lua_pushvalue(L, -3); // duplicate the module table
1301 lua_rawset(L, -3); // and set it as metaindex
1302 lua_pushliteral(L, "__tostring");
1304 lua_rawset(L, -3); // set metamethod
1305 lua_pop(L, 1); // drop value (metatable)
1306
1307 // expose API constants (via the module table)
1309 lua_setfield(L, -2, "WS_TRIM");
1311 lua_setfield(L, -2, "WS_NORMALIZE");
1313 lua_setfield(L, -2, "WS_PRESERVE");
1314
1315 // register default codes
1316 // Note: We'll always handle "&amp;" separately!
1317 lua_newtable(L);
1318 lua_pushliteral(L, "&lt;");
1319 lua_setfield(L, -2, "<");
1320 lua_pushliteral(L, "&gt;");
1321 lua_setfield(L, -2, ">");
1322 lua_pushliteral(L, "&quot;");
1323 lua_setfield(L, -2, "\"");
1324 lua_pushliteral(L, "&apos;");
1325 lua_setfield(L, -2, "'");
1326 sv_code_ref = luaL_ref(L, LUA_REGISTRYINDEX); // reference (and pop table)
1327
1328 return 1; // return module (table)
1329}
1330#ifdef __cplusplus
1331} // extern "C"
1332#endif
static int Xml_find(lua_State *L)
static int Xml_load(lua_State *L)
Definition LuaXML_lib.c:791
static int Xml_append(lua_State *L)
Definition LuaXML_lib.c:558
static const char * do_gsub(lua_State *L, int index, const char *p, const char *r)
Definition LuaXML_lib.c:162
#define LUAXML_META
Definition LuaXML_lib.c:72
int _EXPORT luaopen_LuaXML_lib(lua_State *L)
#define Tokenizer_print(tok)
Definition LuaXML_lib.c:293
static int Xml_tag(lua_State *L)
Definition LuaXML_lib.c:483
static void push_indentStr(lua_State *L, int level)
Definition LuaXML_lib.c:117
struct Tokenizer_s Tokenizer
#define ESC
Definition LuaXML_lib.c:229
#define luaL_newlib(L, funcs)
Definition LuaXML_lib.c:45
static const char * Tokenizer_next(Tokenizer *tok)
Definition LuaXML_lib.c:323
static void Xml_pushEncode(lua_State *L, int index)
Definition LuaXML_lib.c:575
static int Xml_eval(lua_State *L)
Definition LuaXML_lib.c:692
static Tokenizer * Tokenizer_new(const char *str, size_t str_size, enum whitespace_mode mode)
Definition LuaXML_lib.c:261
static int Xml_iterate(lua_State *L)
static int XMLencoding_replacement(lua_State *L)
Definition LuaXML_lib.c:180
static void push_TAG_key(lua_State *L)
Definition LuaXML_lib.c:85
static int find_on_match(lua_State *L)
Definition LuaXML_lib.c:204
static void make_xml_object(lua_State *L, int index)
Definition LuaXML_lib.c:100
whitespace_mode
strip all leading / trailing whitespace
Definition LuaXML_lib.c:222
@ WHITESPACE_NORMALIZE
Definition LuaXML_lib.c:224
@ WHITESPACE_PRESERVE
Definition LuaXML_lib.c:225
@ WHITESPACE_TRIM
Definition LuaXML_lib.c:223
static bool is_lead_token(const char *s)
Definition LuaXML_lib.c:148
static int Xml_str(lua_State *L)
Definition LuaXML_lib.c:912
static int Xml_match(lua_State *L)
static int Xml_encode(lua_State *L)
Definition LuaXML_lib.c:864
static void Xml_pushDecode(lua_State *L, const char *s, int size)
Definition LuaXML_lib.c:638
static void Tokenizer_append(Tokenizer *tok, char ch)
Definition LuaXML_lib.c:311
static size_t find(const char *s, const char *pattern, size_t start)
Definition LuaXML_lib.c:77
static int sv_code_ref
Definition LuaXML_lib.c:463
#define lua_rawlen(L, index)
Definition LuaXML_lib.c:42
#define CLS
Definition LuaXML_lib.c:231
static void Tokenizer_delete(Tokenizer *tok)
Definition LuaXML_lib.c:271
#define OPN
Definition LuaXML_lib.c:230
static int Xml_decode(lua_State *L)
Definition LuaXML_lib.c:884
static int Xml_new(lua_State *L)
Definition LuaXML_lib.c:528
static bool is_whitespace(const char *s)
Definition LuaXML_lib.c:133
static const char * Tokenizer_set(Tokenizer *tok, const char *s, size_t size)
Definition LuaXML_lib.c:297
static int Xml_registerCode(lua_State *L)
Definition LuaXML_lib.c:836
#define _EXPORT
Definition LuaXML_lib.h:20
#define realloc
Definition civetweb.c:1541
#define free
Definition civetweb.c:1542
#define calloc
Definition civetweb.c:1540
#define snprintf
Definition civetweb.c:1543
#define malloc
Definition civetweb.c:1539
guint depth
guint index
#define NULL
Definition gmacros.h:924
LUA_API void lua_pushstring(lua_State *L, const char *s)
LUA_API void lua_pushcclosure(lua_State *L, lua_CFunction fn, int n)
LUA_API int lua_setmetatable(lua_State *L, int objindex)
LUA_API void lua_pushnil(lua_State *L)
LUA_API void lua_concat(lua_State *L, int n)
LUA_API const char * lua_pushfstring(lua_State *L, const char *fmt,...)
LUA_API void lua_setfield(lua_State *L, int idx, const char *k)
LUA_API void lua_rawget(lua_State *L, int idx)
LUA_API int lua_toboolean(lua_State *L, int idx)
LUA_API void lua_pushboolean(lua_State *L, int b)
LUA_API void lua_pushvalue(lua_State *L, int idx)
LUA_API int lua_type(lua_State *L, int idx)
LUA_API void lua_gettable(lua_State *L, int idx)
LUA_API void lua_pushlightuserdata(lua_State *L, void *p)
LUA_API void lua_rawseti(lua_State *L, int idx, int n)
LUA_API int lua_isuserdata(lua_State *L, int idx)
LUA_API int lua_next(lua_State *L, int idx)
LUA_API void * lua_touserdata(lua_State *L, int idx)
LUA_API void lua_pushlstring(lua_State *L, const char *s, size_t len)
LUA_API void lua_settop(lua_State *L, int idx)
LUA_API void lua_pushinteger(lua_State *L, lua_Integer n)
LUA_API const char * lua_typename(lua_State *L, int t)
LUA_API void lua_rawgeti(lua_State *L, int idx, int n)
LUA_API int lua_equal(lua_State *L, int index1, int index2)
LUA_API void lua_rawset(lua_State *L, int idx)
LUA_API int lua_gettop(lua_State *L)
LUALIB_API void luaL_buffinit(lua_State *L, luaL_Buffer *B)
LUALIB_API void luaL_addlstring(luaL_Buffer *B, const char *s, size_t l)
LUALIB_API int luaL_ref(lua_State *L, int t)
LUALIB_API void luaL_checktype(lua_State *L, int narg, int t)
LUALIB_API int luaL_newmetatable(lua_State *L, const char *tname)
LUALIB_API void luaL_pushresult(luaL_Buffer *B)
LUALIB_API void luaL_addvalue(luaL_Buffer *B)
LUALIB_API int luaL_error(lua_State *L, const char *fmt,...)
LUALIB_API const char * luaL_checklstring(lua_State *L, int narg, size_t *len)
LUALIB_API const char * luaL_gsub(lua_State *L, const char *s, const char *p, const char *r)
LUALIB_API void luaL_addstring(luaL_Buffer *B, const char *s)
#define luaL_getmetatable(L, n)
#define luaL_typename(L, i)
#define luaL_addchar(B, c)
#define luaL_optint(L, n, d)
#define luaL_checkstring(L, n)
#define lua_istable(L, n)
#define lua_pushcfunction(L, f)
#define LUA_TTABLE
#define LUA_REGISTRYINDEX
#define lua_pushliteral(L, s)
#define LUA_TSTRING
#define lua_isnil(L, n)
#define lua_newtable(L)
#define lua_pop(L, n)
#define lua_getglobal(L, s)
#define lua_upvalueindex(i)
#define lua_tostring(L, i)
#define LUA_TFUNCTION
#define LUA_TNIL
#define lua_isnoneornil(L, n)
#define lua_tointeger(L, i)
#define lua_call(L, n, r)
#define lua_replace(L, idx)
#define lua_insert(L, idx)
#define lua_remove(L, idx)
static const luaL_Reg funcs[]
CURL_EXTERN CURLMcode curl_socket_t s
Definition multi.h:318
size_t fread(void *, size_t, size_t, FILE *)
size_t m_token_capacity
capacity of current token
Definition LuaXML_lib.c:255
size_t i
stores current read position
Definition LuaXML_lib.c:241
size_t s_size
stores size of string to be tokenized
Definition LuaXML_lib.c:239
enum whitespace_mode mode
whitespace handling
Definition LuaXML_lib.c:257
int tagMode
stores current read context
Definition LuaXML_lib.c:243
size_t m_next_size
size of next token
Definition LuaXML_lib.c:249
char * m_token
pointer to current token
Definition LuaXML_lib.c:251
const char * m_next
stores next token, if already determined
Definition LuaXML_lib.c:247
const char * s
stores string to be tokenized
Definition LuaXML_lib.c:237
size_t m_token_size
size of current token
Definition LuaXML_lib.c:253
int cdata
stores flag for "raw" byte sequence, DON'T decode any further
Definition LuaXML_lib.c:245
#define printf