]> git.proxmox.com Git - ceph.git/blob - ceph/src/civetweb/src/third_party/LuaXML_lib.c
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / civetweb / src / third_party / LuaXML_lib.c
1 /**
2 LuaXML License
3
4 LuaXml is licensed under the terms of the MIT license reproduced below,
5 the same as Lua itself. This means that LuaXml is free software and can be
6 used for both academic and commercial purposes at absolutely no cost.
7
8 Copyright (C) 2007-2013 Gerald Franz, eludi.net
9
10 Permission is hereby granted, free of charge, to any person obtaining a copy
11 of this software and associated documentation files (the "Software"), to deal
12 in the Software without restriction, including without limitation the rights
13 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 copies of the Software, and to permit persons to whom the Software is
15 furnished to do so, subject to the following conditions:
16
17 The above copyright notice and this permission notice shall be included in
18 all copies or substantial portions of the Software.
19
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 THE SOFTWARE.
27 */
28
29 #if defined __WIN32__ || defined WIN32
30 # include <windows.h>
31 # define _EXPORT __declspec(dllexport)
32 #else
33 # define _EXPORT
34 #endif
35
36 #ifdef __cplusplus
37 extern "C" {
38 #endif
39
40 #include "civetweb_lua.h"
41
42 #ifdef __cplusplus
43 } // extern "C"
44 #endif
45
46 #include <stdio.h>
47 #include <string.h>
48 #include <ctype.h>
49 #include <stdlib.h>
50
51 static const char ESC=27;
52 static const char OPN=28;
53 static const char CLS=29;
54
55 //--- auxliary functions -------------------------------------------
56
57 static const char* char2code(unsigned char ch, char buf[8]) {
58 unsigned char i=0;
59 buf[i++]='&';
60 buf[i++]='#';
61 if(ch>99) buf[i++]=ch/100+48;
62 if(ch>9) buf[i++]=(ch%100)/10+48;
63 buf[i++]=ch%10+48;
64 buf[i++]=';';
65 buf[i]=0;
66 return buf;
67 }
68
69 static size_t find(const char* s, const char* pattern, size_t start) {
70 const char* found =strstr(s+start, pattern);
71 return found ? found-s : strlen(s);
72 }
73
74 //--- internal tokenizer -------------------------------------------
75
76 typedef struct Tokenizer_s {
77 /// stores string to be tokenized
78 const char* s;
79 /// stores size of string to be tokenized
80 size_t s_size;
81 /// stores current read position
82 size_t i;
83 /// stores current read context
84 int tagMode;
85 /// stores next token, if already determined
86 const char* m_next;
87 /// size of next token
88 size_t m_next_size;
89 /// pointer to current token
90 char* m_token;
91 /// size of current token
92 size_t m_token_size;
93 /// capacity of current token
94 size_t m_token_capacity;
95 } Tokenizer;
96
97 Tokenizer* Tokenizer_new(const char* str, size_t str_size) {
98 Tokenizer *tok = (Tokenizer*)malloc(sizeof(Tokenizer));
99 memset(tok, 0, sizeof(Tokenizer));
100 tok->s_size = str_size;
101 tok->s = str;
102 return tok;
103 }
104
105 void Tokenizer_delete(Tokenizer* tok) {
106 free(tok->m_token);
107 free(tok);
108 }
109
110 //void Tokenizer_print(Tokenizer* tok) { printf(" @%u %s\n", tok->i, !tok->m_token ? "(null)" : (tok->m_token[0]==ESC)?"(esc)" : (tok->m_token[0]==OPN)?"(open)": (tok->m_token[0]==CLS)?"(close)" : tok->m_token); fflush(stdout); }
111
112 static const char* Tokenizer_set(Tokenizer* tok, const char* s, size_t size) {
113 if(!size||!s) return 0;
114 free(tok->m_token);
115 tok->m_token = (char*)malloc(size+1);
116 strncpy(tok->m_token,s, size);
117 tok->m_token[size] = 0;
118 tok->m_token_size = tok->m_token_capacity = size;
119 //Tokenizer_print(tok);
120 return tok->m_token;
121 }
122
123 static void Tokenizer_append(Tokenizer* tok, char ch) {
124 if(tok->m_token_size+1>=tok->m_token_capacity) {
125 tok->m_token_capacity = (tok->m_token_capacity==0) ? 16 : tok->m_token_capacity*2;
126 tok->m_token = (char*)realloc(tok->m_token, tok->m_token_capacity);
127 }
128 tok->m_token[tok->m_token_size]=ch;
129 tok->m_token[++tok->m_token_size]=0;
130 }
131
132 const char* Tokenizer_next(Tokenizer* tok) {
133 const char* ESC_str = "\033";
134 const char* OPEN_str = "\034";
135 const char* CLOSE_str = "\035";
136 int quotMode=0;
137 int tokenComplete = 0;
138
139 if(tok->m_token) {
140 free(tok->m_token);
141 tok->m_token = 0;
142 tok->m_token_size=tok->m_token_capacity = 0;
143 }
144
145 while(tok->m_next_size || (tok->i < tok->s_size)) {
146
147 if(tok->m_next_size) {
148 Tokenizer_set(tok, tok->m_next, tok->m_next_size);
149 tok->m_next=0;
150 tok->m_next_size=0;
151 return tok->m_token;
152 }
153
154 switch(tok->s[tok->i]) {
155 case '"':
156 case '\'':
157 if(tok->tagMode) {
158 if(!quotMode) quotMode=tok->s[tok->i];
159 else if(quotMode==tok->s[tok->i]) quotMode=0;
160 }
161 Tokenizer_append(tok, tok->s[tok->i]);
162 break;
163 case '<':
164 if(!quotMode&&(tok->i+4<tok->s_size)&&(strncmp(tok->s+tok->i,"<!--",4)==0)) // strip comments
165 tok->i=find(tok->s, "-->", tok->i+4)+2;
166 else if(!quotMode&&(tok->i+9<tok->s_size)&&(strncmp(tok->s+tok->i,"<![CDATA[",9)==0)) { // interpet CDATA
167 size_t b=tok->i+9;
168 tok->i=find(tok->s, "]]>",b)+3;
169 if(!tok->m_token_size) return Tokenizer_set(tok, tok->s+b, tok->i-b-3);
170 tokenComplete = 1;
171 tok->m_next = tok->s+b;
172 tok->m_next_size = tok->i-b-3;
173 --tok->i;
174 }
175 else if(!quotMode&&(tok->i+1<tok->s_size)&&((tok->s[tok->i+1]=='?')||(tok->s[tok->i+1]=='!'))) // strip meta information
176 tok->i=find(tok->s, ">", tok->i+2);
177 else if(!quotMode&&!tok->tagMode) {
178 if((tok->i+1<tok->s_size)&&(tok->s[tok->i+1]=='/')) {
179 tok->m_next=ESC_str;
180 tok->m_next_size = 1;
181 tok->i=find(tok->s, ">", tok->i+2);
182 }
183 else {
184 tok->m_next = OPEN_str;
185 tok->m_next_size = 1;
186 tok->tagMode=1;
187 }
188 tokenComplete = 1;
189 }
190 else Tokenizer_append(tok, tok->s[tok->i]);
191 break;
192 case '/':
193 if(tok->tagMode&&!quotMode) {
194 tokenComplete = 1;
195 if((tok->i+1 < tok->s_size) && (tok->s[tok->i+1]=='>')) {
196 tok->tagMode=0;
197 tok->m_next=ESC_str;
198 tok->m_next_size = 1;
199 ++tok->i;
200 }
201 else Tokenizer_append(tok, tok->s[tok->i]);
202 }
203 else Tokenizer_append(tok, tok->s[tok->i]);
204 break;
205 case '>':
206 if(!quotMode&&tok->tagMode) {
207 tok->tagMode=0;
208 tokenComplete = 1;
209 tok->m_next = CLOSE_str;
210 tok->m_next_size = 1;
211 }
212 else Tokenizer_append(tok, tok->s[tok->i]);
213 break;
214 case ' ':
215 case '\r':
216 case '\n':
217 case '\t':
218 if(tok->tagMode&&!quotMode) {
219 if(tok->m_token_size) tokenComplete=1;
220 }
221 else if(tok->m_token_size) Tokenizer_append(tok, tok->s[tok->i]);
222 break;
223 default: Tokenizer_append(tok, tok->s[tok->i]);
224 }
225 ++tok->i;
226 if((tok->i>=tok->s_size)||(tokenComplete&&tok->m_token_size)) {
227 tokenComplete=0;
228 while(tok->m_token_size&&isspace(tok->m_token[tok->m_token_size-1])) // trim whitespace
229 tok->m_token[--tok->m_token_size]=0;
230 if(tok->m_token_size) break;
231 }
232 }
233 //Tokenizer_print(tok);
234 return tok->m_token;
235 }
236
237 //--- local variables ----------------------------------------------
238
239 /// stores number of special character codes
240 static size_t sv_code_size=0;
241 /// stores currently allocated capacity for special character codes
242 static size_t sv_code_capacity=16;
243 /// stores code table for special characters
244 static char** sv_code=0;
245
246 //--- public methods -----------------------------------------------
247
248 static void Xml_pushDecode(lua_State* L, const char* s, size_t s_size) {
249
250 luaL_Buffer b;
251 const char* found = strstr(s, "&#");
252 size_t start=0, pos, i;
253
254 if(!s_size)
255 s_size=strlen(s);
256
257 luaL_buffinit(L, &b);
258 found = strstr(s, "&#");
259 pos = found ? found-s : s_size;
260
261 while(found) {
262 char ch = 0;
263 size_t i=0;
264 for(found += 2; i<3; ++i, ++found)
265 if(isdigit(*found))
266 ch = ch * 10 + (*found - 48);
267 else break;
268 if(*found == ';') {
269 if(pos>start)
270 luaL_addlstring(&b, s+start, pos-start);
271 luaL_addchar(&b, ch);
272 start = pos + 3 + i;
273 }
274 found = strstr(found+1, "&#");
275 pos = found ? found-s : s_size;
276 }
277 if(pos>start)
278 luaL_addlstring(&b,s+start, pos-start);
279 luaL_pushresult(&b);
280
281 for(i=sv_code_size-1; i<sv_code_size; i-=2) {
282 luaL_gsub(L, lua_tostring(L,-1), sv_code[i], sv_code[i-1]);
283 lua_remove(L,-2);
284 }
285 }
286
287 int Xml_eval(lua_State *L) {
288 char* str = 0;
289 size_t str_size=0;
290 Tokenizer* tok;
291 const char* token=0;
292 int firstStatement = 1;
293
294 if(lua_isuserdata(L,1))
295 str = (char*)lua_touserdata(L,1);
296 else {
297 const char * sTmp = luaL_checklstring(L,1,&str_size);
298 str = (char*)malloc(str_size+1);
299 memcpy(str, sTmp, str_size);
300 str[str_size]=0;
301 }
302 tok = Tokenizer_new(str, str_size ? str_size : strlen(str));
303 lua_settop(L,0);
304
305 while((token=Tokenizer_next(tok))!=0) if(token[0]==OPN) { // new tag found
306 if(lua_gettop(L)) {
307 int newIndex=lua_rawlen(L,-1)+1;
308 lua_pushnumber(L,newIndex);
309 lua_newtable(L);
310 lua_settable(L, -3);
311 lua_pushnumber(L,newIndex);
312 lua_gettable(L,-2);
313 }
314 else {
315 if (firstStatement) {
316 lua_newtable(L);
317 firstStatement = 0;
318 }
319 else return lua_gettop(L);
320 }
321 // set metatable:
322 lua_newtable(L);
323 lua_pushliteral(L, "__index");
324 lua_getglobal(L, "xml");
325 lua_settable(L, -3);
326
327 lua_pushliteral(L, "__tostring"); // set __tostring metamethod
328 lua_getglobal(L, "xml");
329 lua_pushliteral(L,"str");
330 lua_gettable(L, -2);
331 lua_remove(L, -2);
332 lua_settable(L, -3);
333 lua_setmetatable(L, -2);
334
335 // parse tag and content:
336 lua_pushnumber(L,0); // use index 0 for storing the tag
337 lua_pushstring(L, Tokenizer_next(tok));
338 lua_settable(L, -3);
339
340 while(((token = Tokenizer_next(tok))!=0)&&(token[0]!=CLS)&&(token[0]!=ESC)) { // parse tag header
341 size_t sepPos=find(token, "=", 0);
342 if(token[sepPos]) { // regular attribute
343 const char* aVal =token+sepPos+2;
344 size_t lenVal;
345
346 lua_pushlstring(L, token, sepPos);
347 lenVal = strlen(aVal)-1;
348 if(!lenVal) Xml_pushDecode(L, "", 0);
349 else Xml_pushDecode(L, aVal, lenVal);
350 lua_settable(L, -3);
351 }
352 }
353 if(!token||(token[0]==ESC)) {
354 if(lua_gettop(L)>1) lua_settop(L,-2); // this tag has no content, only attributes
355 else break;
356 }
357 }
358 else if(token[0]==ESC) { // previous tag is over
359 if(lua_gettop(L)>1) lua_settop(L,-2); // pop current table
360 else break;
361 }
362 else { // read elements
363 lua_pushnumber(L,lua_rawlen(L,-1)+1);
364 Xml_pushDecode(L, token, 0);
365 lua_settable(L, -3);
366 }
367 Tokenizer_delete(tok);
368 free(str);
369 return lua_gettop(L);
370 }
371
372 int Xml_load (lua_State *L) {
373 const char * filename = luaL_checkstring(L,1);
374 FILE * file=fopen(filename,"r");
375 char* buffer;
376 size_t sz;
377
378 if(!file)
379 return luaL_error(L,"LuaXml ERROR: \"%s\" file error or file not found!",filename);
380
381 fseek (file , 0 , SEEK_END);
382 sz = ftell (file);
383 rewind (file);
384 buffer = (char*)malloc(sz+1);
385 sz = fread (buffer,1,sz,file);
386 fclose(file);
387 buffer[sz]=0;
388 lua_pushlightuserdata(L,buffer);
389 lua_replace(L,1);
390 return Xml_eval(L);
391 };
392
393 int Xml_registerCode(lua_State *L) {
394 const char * decoded = luaL_checkstring(L,1);
395 const char * encoded = luaL_checkstring(L,2);
396
397 size_t i;
398 for(i=0; i<sv_code_size; i+=2)
399 if(strcmp(sv_code[i],decoded)==0)
400 return luaL_error(L,"LuaXml ERROR: code already exists.");
401 if(sv_code_size+2>sv_code_capacity) {
402 sv_code_capacity*=2;
403 sv_code = (char**)realloc(sv_code, sv_code_capacity*sizeof(char*));
404 }
405 sv_code[sv_code_size]=(char*)malloc(strlen(decoded)+1);
406 strcpy(sv_code[sv_code_size++], decoded);
407 sv_code[sv_code_size]=(char*)malloc(strlen(encoded)+1);
408 strcpy(sv_code[sv_code_size++],encoded);
409 return 0;
410 }
411
412 int Xml_encode(lua_State *L) {
413
414 char buf[8];
415 size_t start, pos;
416 luaL_Buffer b;
417 const char* s;
418 size_t i;
419
420 if(lua_gettop(L)!=1)
421 return 0;
422 luaL_checkstring(L,-1);
423
424 for(i=0; i<sv_code_size; i+=2) {
425 luaL_gsub(L, lua_tostring(L,-1), sv_code[i], sv_code[i+1]);
426 lua_remove(L,-2);
427 }
428 s=lua_tostring(L,1);
429 luaL_buffinit(L, &b);
430 for(start=pos=0; s[pos]!=0; ++pos) if(s[pos]<0) {
431 if(pos>start) luaL_addlstring(&b,s+start, pos-start);
432 luaL_addstring(&b,char2code((unsigned char)(s[pos]),buf));
433 start=pos+1;
434 }
435 if(pos>start)
436 luaL_addlstring(&b,s+start, pos-start);
437 luaL_pushresult(&b);
438 lua_remove(L,-2);
439 return 1;
440 }
441
442 #ifdef __cplusplus
443 extern "C" {
444 #endif
445 int _EXPORT luaopen_LuaXML_lib (lua_State* L) {
446 static const struct luaL_Reg funcs[] = {
447 {"load", Xml_load},
448 {"eval", Xml_eval},
449 {"encode", Xml_encode},
450 {"registerCode", Xml_registerCode},
451 {NULL, NULL}
452 };
453
454 luaL_newlibtable(L, funcs);
455 luaL_setfuncs(L, funcs, 0);
456 lua_setglobal(L, "xml");
457
458 // register default codes:
459 if(!sv_code) {
460 sv_code=(char**)malloc(sv_code_capacity*sizeof(char*));
461 sv_code[sv_code_size++]="&";
462 sv_code[sv_code_size++]="&amp;";
463 sv_code[sv_code_size++]="<";
464 sv_code[sv_code_size++]="&lt;";
465 sv_code[sv_code_size++]=">";
466 sv_code[sv_code_size++]="&gt;";
467 sv_code[sv_code_size++]="\"";
468 sv_code[sv_code_size++]="&quot;";
469 sv_code[sv_code_size++]="'";
470 sv_code[sv_code_size++]="&apos;";
471 }
472 return 1;
473 }
474 #ifdef __cplusplus
475 } // extern "C"
476 #endif