Github User Fetcher 1.0.0
C Application with Server and GUI
Loading...
Searching...
No Matches
LuaXML_lib.c File Reference
#include "LuaXML_lib.h"
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

Go to the source code of this file.

Data Structures

struct  Tokenizer_s
 

Macros

#define lua_rawlen(L, index)   lua_objlen(L, index)
 
#define luaL_newlib(L, funcs)
 
#define LUAXML_META   "LuaXML"
 
#define ESC   27 /* end of scope, closing tag */
 
#define OPN   28 /* "open", start of tag */
 
#define CLS   29 /* closes opening tag, actual content follows */
 
#define Tokenizer_print(tok)   /* ignore */
 

Typedefs

typedef struct Tokenizer_s Tokenizer
 

Enumerations

enum  whitespace_mode { WHITESPACE_TRIM , WHITESPACE_NORMALIZE , WHITESPACE_PRESERVE }
 strip all leading / trailing whitespace More...
 

Functions

static size_t find (const char *s, const char *pattern, size_t start)
 
static void push_TAG_key (lua_State *L)
 
static void make_xml_object (lua_State *L, int index)
 
static void push_indentStr (lua_State *L, int level)
 
static bool is_whitespace (const char *s)
 
static bool is_lead_token (const char *s)
 
static const char * do_gsub (lua_State *L, int index, const char *p, const char *r)
 
static int XMLencoding_replacement (lua_State *L)
 
static int find_on_match (lua_State *L)
 
static TokenizerTokenizer_new (const char *str, size_t str_size, enum whitespace_mode mode)
 
static void Tokenizer_delete (Tokenizer *tok)
 
static const char * Tokenizer_set (Tokenizer *tok, const char *s, size_t size)
 
static void Tokenizer_append (Tokenizer *tok, char ch)
 
static const char * Tokenizer_next (Tokenizer *tok)
 
static int Xml_tag (lua_State *L)
 
static int Xml_new (lua_State *L)
 
static int Xml_append (lua_State *L)
 
static void Xml_pushEncode (lua_State *L, int index)
 
static void Xml_pushDecode (lua_State *L, const char *s, int size)
 
static int Xml_eval (lua_State *L)
 
static int Xml_load (lua_State *L)
 
static int Xml_registerCode (lua_State *L)
 
static int Xml_encode (lua_State *L)
 
static int Xml_decode (lua_State *L)
 
static int Xml_str (lua_State *L)
 
static int Xml_match (lua_State *L)
 
static int Xml_iterate (lua_State *L)
 
static int Xml_find (lua_State *L)
 
int _EXPORT luaopen_LuaXML_lib (lua_State *L)
 

Variables

static int sv_code_ref
 

Macro Definition Documentation

◆ CLS

#define CLS   29 /* closes opening tag, actual content follows */

Definition at line 231 of file LuaXML_lib.c.

Referenced by Tokenizer_next(), and Xml_eval().

◆ ESC

#define ESC   27 /* end of scope, closing tag */

Definition at line 229 of file LuaXML_lib.c.

Referenced by Tokenizer_next(), and Xml_eval().

◆ lua_rawlen

#define lua_rawlen ( L,
index )   lua_objlen(L, index)

◆ luaL_newlib

#define luaL_newlib ( L,
funcs )
Value:
do { \
lua_newtable(L); \
luaL_register(L, NULL, funcs); \
} while (0)
#define NULL
Definition gmacros.h:924
static const luaL_Reg funcs[]

Definition at line 45 of file LuaXML_lib.c.

45#define luaL_newlib(L, funcs) \
46 do { \
47 lua_newtable(L); \
48 luaL_register(L, NULL, funcs); \
49 } while (0)

Referenced by luaopen_LuaXML_lib().

◆ LUAXML_META

#define LUAXML_META   "LuaXML"

Definition at line 72 of file LuaXML_lib.c.

Referenced by luaopen_LuaXML_lib(), and make_xml_object().

◆ OPN

#define OPN   28 /* "open", start of tag */

Definition at line 230 of file LuaXML_lib.c.

Referenced by Tokenizer_next(), and Xml_eval().

◆ Tokenizer_print

#define Tokenizer_print ( tok)    /* ignore */

Definition at line 293 of file LuaXML_lib.c.

Referenced by Tokenizer_next(), and Tokenizer_set().

Typedef Documentation

◆ Tokenizer

typedef struct Tokenizer_s Tokenizer

Enumeration Type Documentation

◆ whitespace_mode

strip all leading / trailing whitespace

remove "lead in" whitespace before tags preserve all whitespace, even between tags

Enumerator
WHITESPACE_TRIM 
WHITESPACE_NORMALIZE 
WHITESPACE_PRESERVE 

Definition at line 222 of file LuaXML_lib.c.

222 {
226};
@ WHITESPACE_NORMALIZE
Definition LuaXML_lib.c:224
@ WHITESPACE_PRESERVE
Definition LuaXML_lib.c:225
@ WHITESPACE_TRIM
Definition LuaXML_lib.c:223

Function Documentation

◆ do_gsub()

static const char * do_gsub ( lua_State * L,
int index,
const char * p,
const char * r )
static

Definition at line 162 of file LuaXML_lib.c.

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}
guint index
LUA_API int lua_gettop(lua_State *L)
LUALIB_API const char * luaL_gsub(lua_State *L, const char *s, const char *p, const char *r)
#define lua_tostring(L, i)
#define lua_replace(L, idx)

References index, lua_gettop(), lua_replace, lua_tostring, and luaL_gsub().

Referenced by Xml_pushDecode(), and Xml_pushEncode().

◆ find()

static size_t find ( const char * s,
const char * pattern,
size_t start )
static

Definition at line 77 of file LuaXML_lib.c.

78{
79 const char *found = strstr(s + start, pattern);
80 return found ? (size_t)(found - s) : strlen(s);
81}
CURL_EXTERN CURLMcode curl_socket_t s
Definition multi.h:318

References s.

Referenced by str_find_aux(), str_find_aux(), str_find_aux(), str_find_aux(), Tokenizer_next(), and Xml_eval().

◆ find_on_match()

static int find_on_match ( lua_State * L)
static

Definition at line 204 of file LuaXML_lib.c.

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}
LUA_API void lua_pushboolean(lua_State *L, int b)
LUA_API void lua_rawseti(lua_State *L, int idx, int n)
LUA_API void lua_settop(lua_State *L, int idx)
#define lua_upvalueindex(i)

References lua_pushboolean(), lua_rawseti(), lua_settop(), and lua_upvalueindex.

Referenced by Xml_find().

◆ is_lead_token()

static bool is_lead_token ( const char * s)
static

Definition at line 148 of file LuaXML_lib.c.

149{
150 return is_whitespace(s) && (*s == '\n' || *s == '\r');
151}
static bool is_whitespace(const char *s)
Definition LuaXML_lib.c:133

References is_whitespace(), and s.

Referenced by Xml_eval().

◆ is_whitespace()

static bool is_whitespace ( const char * s)
static

Definition at line 133 of file LuaXML_lib.c.

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}

References s.

Referenced by is_lead_token(), and Xml_eval().

◆ luaopen_LuaXML_lib()

int _EXPORT luaopen_LuaXML_lib ( lua_State * L)

Definition at line 1280 of file LuaXML_lib.c.

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}
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
#define LUAXML_META
Definition LuaXML_lib.c:72
static int Xml_tag(lua_State *L)
Definition LuaXML_lib.c:483
#define luaL_newlib(L, funcs)
Definition LuaXML_lib.c:45
static int Xml_eval(lua_State *L)
Definition LuaXML_lib.c:692
static int Xml_iterate(lua_State *L)
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 int sv_code_ref
Definition LuaXML_lib.c:463
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 int Xml_registerCode(lua_State *L)
Definition LuaXML_lib.c:836
LUA_API void lua_setfield(lua_State *L, int idx, const char *k)
LUA_API void lua_pushvalue(lua_State *L, int idx)
LUA_API void lua_pushinteger(lua_State *L, lua_Integer n)
LUA_API void lua_rawset(lua_State *L, int idx)
LUALIB_API int luaL_ref(lua_State *L, int t)
LUALIB_API int luaL_newmetatable(lua_State *L, const char *tname)
#define lua_pushcfunction(L, f)
#define LUA_REGISTRYINDEX
#define lua_pushliteral(L, s)
#define lua_newtable(L)
#define lua_pop(L, n)

References funcs, lua_newtable, lua_pop, lua_pushcfunction, lua_pushinteger(), lua_pushliteral, lua_pushvalue(), lua_rawset(), LUA_REGISTRYINDEX, lua_setfield(), luaL_newlib, luaL_newmetatable(), luaL_ref(), LUAXML_META, NULL, sv_code_ref, WHITESPACE_NORMALIZE, WHITESPACE_PRESERVE, WHITESPACE_TRIM, Xml_append(), Xml_decode(), Xml_encode(), Xml_eval(), Xml_find(), Xml_iterate(), Xml_load(), Xml_match(), Xml_new(), Xml_registerCode(), Xml_str(), and Xml_tag().

◆ make_xml_object()

static void make_xml_object ( lua_State * L,
int index )
static

Definition at line 100 of file LuaXML_lib.c.

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}
LUA_API int lua_setmetatable(lua_State *L, int objindex)
LUALIB_API int luaL_error(lua_State *L, const char *fmt,...)
#define luaL_getmetatable(L, n)
#define luaL_typename(L, i)
#define lua_istable(L, n)

References index, lua_gettop(), lua_istable, lua_setmetatable(), luaL_error(), luaL_getmetatable, luaL_typename, and LUAXML_META.

Referenced by Xml_eval(), Xml_match(), and Xml_new().

◆ push_indentStr()

static void push_indentStr ( lua_State * L,
int level )
static

Definition at line 117 of file LuaXML_lib.c.

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}
LUALIB_API void luaL_buffinit(lua_State *L, luaL_Buffer *B)
LUALIB_API void luaL_pushresult(luaL_Buffer *B)
#define luaL_addchar(B, c)

References lua_pushliteral, luaL_addchar, luaL_buffinit(), and luaL_pushresult().

Referenced by Xml_str().

◆ push_TAG_key()

static void push_TAG_key ( lua_State * L)
inlinestatic

Definition at line 85 of file LuaXML_lib.c.

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}

References lua_pushinteger().

Referenced by Xml_eval(), Xml_match(), Xml_str(), and Xml_tag().

◆ Tokenizer_append()

static void Tokenizer_append ( Tokenizer * tok,
char ch )
static

Definition at line 311 of file LuaXML_lib.c.

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}
#define realloc
Definition civetweb.c:1541
size_t m_token_capacity
capacity of current token
Definition LuaXML_lib.c:255
char * m_token
pointer to current token
Definition LuaXML_lib.c:251
size_t m_token_size
size of current token
Definition LuaXML_lib.c:253

References Tokenizer_s::m_token, Tokenizer_s::m_token_capacity, Tokenizer_s::m_token_size, and realloc.

Referenced by Tokenizer_next().

◆ Tokenizer_delete()

static void Tokenizer_delete ( Tokenizer * tok)
static

Definition at line 271 of file LuaXML_lib.c.

272{
273 free(tok->m_token);
274 free(tok);
275}
#define free
Definition civetweb.c:1542

References free, and Tokenizer_s::m_token.

Referenced by Xml_eval().

◆ Tokenizer_new()

static Tokenizer * Tokenizer_new ( const char * str,
size_t str_size,
enum whitespace_mode mode )
static

Definition at line 261 of file LuaXML_lib.c.

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}
#define calloc
Definition civetweb.c:1540
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
const char * s
stores string to be tokenized
Definition LuaXML_lib.c:237

References calloc, Tokenizer_s::mode, Tokenizer_s::s, and Tokenizer_s::s_size.

Referenced by Xml_eval().

◆ Tokenizer_next()

static const char * Tokenizer_next ( Tokenizer * tok)
static

Definition at line 323 of file LuaXML_lib.c.

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}
#define Tokenizer_print(tok)
Definition LuaXML_lib.c:293
#define ESC
Definition LuaXML_lib.c:229
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
#define CLS
Definition LuaXML_lib.c:231
#define OPN
Definition LuaXML_lib.c:230
static const char * Tokenizer_set(Tokenizer *tok, const char *s, size_t size)
Definition LuaXML_lib.c:297
size_t i
stores current read position
Definition LuaXML_lib.c:241
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
const char * m_next
stores next token, if already determined
Definition LuaXML_lib.c:247
int cdata
stores flag for "raw" byte sequence, DON'T decode any further
Definition LuaXML_lib.c:245

References Tokenizer_s::cdata, CLS, ESC, find(), free, Tokenizer_s::i, Tokenizer_s::m_next, Tokenizer_s::m_next_size, Tokenizer_s::m_token, Tokenizer_s::m_token_capacity, Tokenizer_s::m_token_size, Tokenizer_s::mode, NULL, OPN, Tokenizer_s::s, Tokenizer_s::s_size, Tokenizer_s::tagMode, Tokenizer_append(), Tokenizer_print, Tokenizer_set(), and WHITESPACE_TRIM.

Referenced by Xml_eval().

◆ Tokenizer_set()

static const char * Tokenizer_set ( Tokenizer * tok,
const char * s,
size_t size )
static

Definition at line 297 of file LuaXML_lib.c.

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}
#define malloc
Definition civetweb.c:1539

References free, Tokenizer_s::m_token, Tokenizer_s::m_token_capacity, Tokenizer_s::m_token_size, malloc, NULL, s, and Tokenizer_print.

Referenced by Tokenizer_next().

◆ Xml_append()

static int Xml_append ( lua_State * L)
static

appends a new subordinate LuaXML object to an existing one. optionally sets tag

@function append

Parameters
varthe parent LuaXML object
Template Parameters
?stringtag the tag of the appended LuaXML object
Returns
appended LuaXML object, or nil in case of errors

Definition at line 558 of file LuaXML_lib.c.

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}
#define lua_rawlen(L, index)
Definition LuaXML_lib.c:42
LUA_API int lua_type(lua_State *L, int idx)
#define LUA_TTABLE
#define lua_call(L, n, r)
#define lua_insert(L, idx)

References lua_call, lua_insert, lua_pushcfunction, lua_pushvalue(), lua_rawlen, lua_rawseti(), lua_settop(), LUA_TTABLE, lua_type(), and Xml_new().

Referenced by luaopen_LuaXML_lib().

◆ Xml_decode()

static int Xml_decode ( lua_State * L)
static

converts a string from XML encoding. This function transformsstr by replacing any special XML encodings with their "plain text" counterparts.

@usage print((xml.decode("&lt;-&gt;")) – "<->"

@function decode

Template Parameters
stringstr string to be transformed @treturn string the decoded string
See also
encode, registerCode

Definition at line 884 of file LuaXML_lib.c.

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}
static void Xml_pushDecode(lua_State *L, const char *s, int size)
Definition LuaXML_lib.c:638
LUALIB_API const char * luaL_checklstring(lua_State *L, int narg, size_t *len)

References lua_tostring, luaL_checklstring(), and Xml_pushDecode().

Referenced by luaopen_LuaXML_lib().

◆ Xml_encode()

static int Xml_encode ( lua_State * L)
static

converts a string to XML encoding. This function transformsstr by replacing any special characters with suitable XML encodings.

@usage print(xml.encode("<->")) – "&lt;-&gt;"

@function encode

Template Parameters
stringstr string to be transformed @treturn string the XML-encoded string
See also
decode, registerCode

Definition at line 864 of file LuaXML_lib.c.

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}
static void Xml_pushEncode(lua_State *L, int index)
Definition LuaXML_lib.c:575
#define luaL_checkstring(L, n)

References luaL_checkstring, and Xml_pushEncode().

Referenced by luaopen_LuaXML_lib().

◆ Xml_eval()

static int Xml_eval ( lua_State * L)
static

parses an XML string into a Lua table. The table will contain a representation of the XML tag, attributes (and their values), and element content / subelements (either as strings or nested LuaXML "objects").

Note: Parsing "wide" strings or Unicode (UCS-2, UCS-4, UTF-16) currently is not supported. If needed, convert such xml data to UTF-8 before passing it to eval(). UTF-8 should be safe to use, and this function will also recognize and ignore a UTF-8 BOM (byte order mark) at the start of xml.

@function eval

Template Parameters
string|userdataxml the XML to be converted. When passing a userdata type xml value, it must point to a C-style (NUL-terminated) string.
?numbermode whitespace handling mode, one of the WS_* constants - see Fields. defaults to WS_TRIM (compatible to previous LuaXML versions)
Returns
a LuaXML object containing the XML data, or nil in case of errors

Definition at line 692 of file LuaXML_lib.c.

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}
static const char * Tokenizer_next(Tokenizer *tok)
Definition LuaXML_lib.c:323
static Tokenizer * Tokenizer_new(const char *str, size_t str_size, enum whitespace_mode mode)
Definition LuaXML_lib.c:261
static void push_TAG_key(lua_State *L)
Definition LuaXML_lib.c:85
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
static bool is_lead_token(const char *s)
Definition LuaXML_lib.c:148
static void Tokenizer_delete(Tokenizer *tok)
Definition LuaXML_lib.c:271
LUA_API void lua_pushstring(lua_State *L, const char *s)
LUA_API int lua_isuserdata(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)
#define luaL_optint(L, n, d)

References Tokenizer_s::cdata, CLS, ESC, find(), Tokenizer_s::i, is_lead_token(), is_whitespace(), lua_gettop(), lua_isuserdata(), lua_newtable, lua_pop, lua_pushlstring(), lua_pushstring(), lua_pushvalue(), lua_rawlen, lua_rawset(), lua_rawseti(), lua_settop(), lua_touserdata(), luaL_checklstring(), luaL_error(), luaL_optint, make_xml_object(), OPN, push_TAG_key(), Tokenizer_delete(), Tokenizer_new(), Tokenizer_next(), WHITESPACE_NORMALIZE, WHITESPACE_TRIM, and Xml_pushDecode().

Referenced by luaopen_LuaXML_lib(), and Xml_load().

◆ Xml_find()

static int Xml_find ( lua_State * L)
static

recursively searches a Lua table for a subelement matching the provided tag and attribute. See the description of match for the logic involved with testing fortag, key and value.

@function find

Parameters
varthe table to be searched in
Template Parameters
?stringtag the XML tag to be found
?stringkey the attribute key (= exact name) to be found
Parameters
value(optional) the attribute value to be found
Returns
the first (sub-)table that satisfies the search condition, or nil for no match

Definition at line 1254 of file LuaXML_lib.c.

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}
static int find_on_match(lua_State *L)
Definition LuaXML_lib.c:204
LUA_API void lua_pushcclosure(lua_State *L, lua_CFunction fn, int n)
LUA_API void lua_rawgeti(lua_State *L, int idx, int n)

References find_on_match(), lua_call, lua_insert, lua_newtable, lua_pushboolean(), lua_pushcclosure(), lua_pushcfunction, lua_pushvalue(), lua_rawgeti(), lua_settop(), and Xml_iterate().

Referenced by luaopen_LuaXML_lib().

◆ Xml_iterate()

static int Xml_iterate ( lua_State * L)
static

iterates a LuaXML object, invoking a callback function for all matching (sub)elements.

The iteration starts with the variable var itself (= default depth 0). A callback function cb gets invoked for each match, depending on the specified criteria. If the r flag is set, the process will repeat recursively for the subelements of var (at depth + 1). You can limit the scope by setting a maximum depth, or have the callback function explicitly request to stop the iteration (by returning false).

@function iterate

Parameters
varthe table (LuaXML object) to iterate
Template Parameters
functioncb callback function. callback(var, depth) will be called for each matching element.
The function may return false to request a stop; if its result is any other value (including nil), the iteration will continue.
?stringtag XML tag to be matched
?stringkey attribute key to be matched
Parameters
value(optional) attribute value to be matched
Template Parameters
?booleanr recursive operation. If true, also iterate over the subelements of var
?numbermax maximum depth allowed
?numberd initial depth value, defaults to 0
Returns
The function returns two values: a counter representing the number of elements that were successfully matched (and processed), and a boolean completion flag. The latter is true for an exhaustive iteration, and false if was stopped from the callback.
See also
match

Definition at line 1182 of file LuaXML_lib.c.

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}
guint depth
LUA_API int lua_toboolean(lua_State *L, int idx)
LUA_API int lua_equal(lua_State *L, int index1, int index2)
LUALIB_API void luaL_checktype(lua_State *L, int narg, int t)
#define lua_isnil(L, n)
#define LUA_TFUNCTION
#define lua_tointeger(L, i)

References depth, lua_call, lua_equal(), lua_insert, lua_isnil, lua_pop, lua_pushboolean(), lua_pushcfunction, lua_pushinteger(), lua_pushvalue(), lua_rawgeti(), lua_settop(), LUA_TFUNCTION, lua_toboolean(), lua_tointeger, LUA_TTABLE, lua_type(), luaL_checktype(), luaL_optint, Xml_iterate(), and Xml_match().

Referenced by luaopen_LuaXML_lib(), Xml_find(), and Xml_iterate().

◆ Xml_load()

static int Xml_load ( lua_State * L)
static

loads XML data from a file and returns it as table. Basically, this is just calling eval on the given file's content.

@function load

Template Parameters
stringfilename the name and path of the file to be loaded
?numbermode whitespace handling mode, defaults to WS_TRIM
Returns
a Lua table representing the XML data, or nil in case of errors

Definition at line 791 of file LuaXML_lib.c.

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};
LUA_API void lua_pushlightuserdata(lua_State *L, void *p)
size_t fread(void *, size_t, size_t, FILE *)

References fread(), free, lua_pushlightuserdata(), lua_replace, luaL_checkstring, luaL_error(), malloc, and Xml_eval().

Referenced by luaopen_LuaXML_lib().

◆ Xml_match()

static int Xml_match ( lua_State * L)
static

match XML entity against given (optional) criteria. Passing nil for one of thetag, key, or value parameters means "don't care" (i.e. match anything for that particular aspect). So for example var:match(nil, "text", nil) – or shorter, but identical: var:match(nil, "text") will look for an XML attribute (name) "text" to be present in var, but won't consider its value or the tag of var.

Note: If you want to test for a specific attribute value, so also have to supply a key - otherwise value will be ignored.

@usage – each of these will either return x, or nil in case of no match

x:match("foo") – test for x:tag() == "foo" x:match(nil, "bar") – test if x has a "bar" attribute x:match(nil, "foo", "bar") – test if x has a "foo" attribute that equals "bar" x:match("foobar", "foo", "bar") – test for "foobar" tag, and attr "foo" == "bar"

@function match

Parameters
varthe variable to test, normally a Lua table or LuaXML object. (If var is not a table type, the test always fails.)
Template Parameters
?stringtag If set, has to match the XML tag (i.e. must be equal to the tag(var, nil) result)
?stringkey If set, a corresponding attribute key needs to be present (exact name match).
Parameters
value(optional) arbitrary Lua value. If set, the attribute value for key has to match it.
Returns
either nil for no match; or the var argument properly converted to a LuaXML object, equivalent to xml.new(var).

This allows you to either make direct use of the matched LuaXML object, or to use the return value in a boolean test (if xml.match(...)), which is a common Lua idiom.

Definition at line 1116 of file LuaXML_lib.c.

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}
LUA_API void lua_rawget(lua_State *L, int idx)
#define LUA_TSTRING
#define lua_isnoneornil(L, n)

References lua_equal(), lua_isnil, lua_isnoneornil, lua_pop, lua_pushvalue(), lua_rawget(), lua_settop(), LUA_TSTRING, LUA_TTABLE, lua_type(), make_xml_object(), and push_TAG_key().

Referenced by luaopen_LuaXML_lib(), and Xml_iterate().

◆ Xml_new()

static int Xml_new ( lua_State * L)
static

creates a LuaXML "object", and optionally sets its tag. The function either sets the metatable of an existing Lua table, or creates a new (empty) "object". If you pass an optionaltag string, it will be assigned to the result.

(It's also possible to call this as new(tag), which creates a new XML object with the given tag and is equivalent to new({}, tag).)

Note that it's not mandatory to use this function in order to treat a Lua table as LuaXML object. Setting the metatable just allows the usage of a more object-oriented syntax (e.g. xmlvar:str() instead of xml.str(xmlvar)). XML objects created by load or eval automatically offer the object-oriented syntax.

@function new

Parameters
arg(optional) _(1)_ a table to be converted to a LuaXML object, or _(2)_ the tag of the new LuaXML object
Template Parameters
?stringtag a tag value that will be assigned to the object
Returns
LuaXML object, either newly created or the conversion of arg; optionally tagged as requested

Definition at line 528 of file LuaXML_lib.c.

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}

References lua_call, lua_insert, lua_istable, lua_newtable, lua_pushcfunction, lua_pushvalue(), lua_settop(), LUA_TSTRING, lua_type(), make_xml_object(), and Xml_tag().

Referenced by luaopen_LuaXML_lib(), and Xml_append().

◆ Xml_pushDecode()

static void Xml_pushDecode ( lua_State * L,
const char * s,
int size )
static

Definition at line 638 of file LuaXML_lib.c.

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}
static const char * do_gsub(lua_State *L, int index, const char *p, const char *r)
Definition LuaXML_lib.c:162
static int XMLencoding_replacement(lua_State *L)
Definition LuaXML_lib.c:180
LUA_API void lua_pushnil(lua_State *L)
LUA_API void lua_gettable(lua_State *L, int idx)
LUA_API int lua_next(lua_State *L, int idx)

References do_gsub(), lua_call, lua_gettable(), lua_insert, lua_next(), lua_pop, lua_pushcfunction, lua_pushliteral, lua_pushlstring(), lua_pushnil(), lua_rawgeti(), LUA_REGISTRYINDEX, lua_tostring, s, sv_code_ref, and XMLencoding_replacement().

Referenced by Xml_decode(), and Xml_eval().

◆ Xml_pushEncode()

static void Xml_pushEncode ( lua_State * L,
int index )
static

Definition at line 575 of file LuaXML_lib.c.

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}
#define snprintf
Definition civetweb.c:1543
LUALIB_API void luaL_addlstring(luaL_Buffer *B, const char *s, size_t l)
#define lua_getglobal(L, s)

References do_gsub(), index, lua_call, lua_getglobal, lua_gettop(), lua_next(), lua_pop, lua_pushnil(), lua_pushvalue(), lua_rawgeti(), LUA_REGISTRYINDEX, lua_replace, lua_tostring, LUA_TSTRING, lua_type(), luaL_addchar, luaL_addlstring(), luaL_buffinit(), luaL_pushresult(), s, snprintf, and sv_code_ref.

Referenced by Xml_encode(), and Xml_str().

◆ Xml_registerCode()

static int Xml_registerCode ( lua_State * L)
static

registers a custom code for the conversion between non-standard characters and XML character entities.

By default, only the most basic entities are known to LuaXML: " < > ' On top (and independent) of that, the ampersand sign always gets encoded / decoded separately: &amp;&amp;amp;. Character codes above 127 are directly converted to an appropriate XML encoding, representing the character number (e.g. &amp;#160;). If other special encodings are needed, they can be registered using this function.

Note: LuaXML now manages these encodings in a (private) standard Lua table. This allows you to replace entries by calling registerCode() again, using the same decoded and a different encoded. Encodings may even be removed later, by explictly registering a nil value: registerCode(decoded, nil).

@function registerCode

Template Parameters
stringdecoded the character (sequence) to be used within Lua
stringencoded the character entity to be used in XML
See also
encode, decode

Definition at line 836 of file LuaXML_lib.c.

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}

References lua_insert, lua_isnoneornil, lua_rawgeti(), lua_rawset(), LUA_REGISTRYINDEX, lua_settop(), luaL_checkstring, and sv_code_ref.

Referenced by luaopen_LuaXML_lib().

◆ Xml_str()

static int Xml_str ( lua_State * L)
static

converts any Lua value to an XML string. @function str

Parameters
valuethe value to be converted, normally a table (LuaXML object). However this function will 'encapsulate' other Lua values (of arbitrary type) in a way that should make them valid XML.
Note: Passing no value will cause the function to return nil.
Template Parameters
?numberindent indentation level for 'pretty' output. Mainly for internal use, defaults to 0.
?stringtag the tag to be used in case value doesn't already have an 'implicit' tag. Mainly for internal use.

@treturn string an XML string, or nil in case of errors.

Definition at line 912 of file LuaXML_lib.c.

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}
static void push_indentStr(lua_State *L, int level)
Definition LuaXML_lib.c:117
LUA_API void lua_concat(lua_State *L, int n)
LUA_API const char * lua_pushfstring(lua_State *L, const char *fmt,...)
LUA_API const char * lua_typename(lua_State *L, int t)
LUALIB_API void luaL_addvalue(luaL_Buffer *B)
LUALIB_API void luaL_addstring(luaL_Buffer *B, const char *s)
#define LUA_TNIL
#define lua_remove(L, idx)

References lua_call, lua_concat(), lua_insert, lua_istable, lua_newtable, lua_next(), lua_pop, lua_pushcfunction, lua_pushfstring(), lua_pushinteger(), lua_pushliteral, lua_pushnil(), lua_pushvalue(), lua_rawget(), lua_rawgeti(), lua_rawlen, lua_rawseti(), lua_remove, lua_replace, lua_settop(), LUA_TNIL, lua_tointeger, lua_tostring, LUA_TSTRING, LUA_TTABLE, lua_type(), lua_typename(), luaL_addchar, luaL_addlstring(), luaL_addstring(), luaL_addvalue(), luaL_buffinit(), luaL_pushresult(), push_indentStr(), push_TAG_key(), Xml_pushEncode(), and Xml_str().

Referenced by luaopen_LuaXML_lib(), and Xml_str().

◆ Xml_tag()

static int Xml_tag ( lua_State * L)
static

sets or returns tag of a LuaXML object. This method is just "syntactic sugar" (using a typical Lua term) that allows the writing of clearer code. LuaXML stores the tag value of an XML statement at table index 0, hence it can be simply accessed or altered by var[0]. However, writing var:tag() for access or var:tag("newTag") for altering may be more self explanatory (and future-proof in case LuaXML's tag handling should ever change).

@function tag

Parameters
varthe variable whose tag should be accessed, a LuaXML object
Template Parameters
?stringtag the new tag to be set
Returns
If you have passed a new tag, the function will return var (with its tag changed); otherwise the result will be the current tag of var (normally a string).

Definition at line 483 of file LuaXML_lib.c.

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}

References lua_istable, lua_pushvalue(), lua_rawget(), lua_rawset(), lua_settop(), LUA_TSTRING, lua_type(), and push_TAG_key().

Referenced by luaopen_LuaXML_lib(), and Xml_new().

◆ XMLencoding_replacement()

static int XMLencoding_replacement ( lua_State * L)
static

Definition at line 180 of file LuaXML_lib.c.

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}

References lua_pushlstring(), lua_tostring, and NULL.

Referenced by Xml_pushDecode().

Variable Documentation

◆ sv_code_ref

int sv_code_ref
static

Definition at line 463 of file LuaXML_lib.c.

Referenced by luaopen_LuaXML_lib(), Xml_pushDecode(), Xml_pushEncode(), and Xml_registerCode().