root / trunk / ext / lua / syck.c

Revision 316, 8.5 kB (checked in by slact, 7 months ago)

no more segfaults on load. no more leaks loading or dumping. added info table. dumping still a bit sketchy for high nesting levels

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * syck.c
3 *
4 * $Author$
5 * $Date$
6 *
7 * Copyright (C) 2005 Zachary P. Landau <kapheine@divineinvasion.net>
8 * slact touched this in 2008. blame him.
9 */
10
11#include <syck.h>
12#include <string.h>
13#include <stdlib.h>
14
15#include "lauxlib.h"
16#include "lua.h"
17#include "lualib.h"
18
19struct emitter_xtra {
20        lua_State *L;
21        luaL_Buffer output;
22        int id;
23};
24
25struct parser_xtra {
26        lua_State *L; //syck parser thread state
27        lua_State *orig; //original API stack state
28};
29
30/*
31static void stackDump (lua_State *L) {
32      int i;
33      int top = lua_gettop(L);
34      for (i = 1; i <= top; i++) {  // repeat for each level
35        int t = lua_type(L, i);
36                printf("%i:     ", (top-i+1));
37                switch (t) {
38   
39          case LUA_TSTRING:  // strings
40            printf("[string]");
41            break;
42   
43          case LUA_TBOOLEAN:  // booleans
44            printf(lua_toboolean(L, i) ? "true" : "false");
45            break;
46   
47          case LUA_TNUMBER:  // numbers
48            printf("%g", lua_tonumber(L, i));
49            break;
50   
51          default:  // other values
52            printf("%s", lua_typename(L, t));
53            break;
54   
55        }
56        printf("\n");  // put a separator
57      }
58      printf("\n----------\n");  // end the listing
59          }
60*/
61SYMID
62lua_syck_parser_handler(SyckParser *p, SyckNode *n)
63{
64        struct parser_xtra *bonus = (struct parser_xtra *)p->bonus;
65        int o, o2, o3 = -1;
66        SYMID oid;
67        int i;
68
69        if(!lua_checkstack(bonus->L, 1))
70                luaL_error(bonus->orig,"syck parser wanted too much stack space.");
71       
72        switch (n->kind) {
73                case syck_str_kind:
74                        if (n->type_id == NULL || strcmp(n->type_id, "str") == 0) {
75                                lua_pushlstring(bonus->L, n->data.str->ptr, n->data.str->len);
76                                o = lua_gettop(bonus->L);
77                        }
78                        else if (strcmp(n->type_id, "null") == 0)
79                        {
80                                lua_pushnil(bonus->L);
81                                o = lua_gettop(bonus->L);
82                        }
83                        else if (strcmp(n->type_id, "bool#yes") == 0)
84                        {
85                                lua_pushboolean(bonus->L, 1);
86                                o = lua_gettop(bonus->L);
87                        }
88                        else if (strcmp(n->type_id, "bool#no") == 0)
89                        {
90                                lua_pushboolean(bonus->L, 0);
91                                o = lua_gettop(bonus->L);
92                        }
93                        else if (strcmp(n->type_id, "float") == 0 || strcmp(n->type_id, "float#fix") == 0 || strcmp(n->type_id, "float#exp") == 0)
94                        {
95                                double f;
96                                syck_str_blow_away_commas(n);
97                                f = strtod(n->data.str->ptr, NULL);
98                                lua_pushnumber(bonus->L, f);
99                                o = lua_gettop(bonus->L);
100                        }
101                        else if (strcmp(n->type_id, "int#hex") == 0)
102                        {
103                                long intVal = strtol(n->data.str->ptr, NULL, 16);
104                                lua_pushnumber(bonus->L, intVal);
105                                o = lua_gettop(bonus->L);
106                        }
107                        else if (strcmp(n->type_id, "int") == 0)
108                        {
109                                long intVal = strtol(n->data.str->ptr, NULL, 10);
110                                lua_pushnumber(bonus->L, intVal);
111                                o = lua_gettop(bonus->L);                 
112                        }
113                        else
114                        {
115                                lua_pushlstring(bonus->L, n->data.str->ptr, n->data.str->len);
116                                o = lua_gettop(bonus->L);
117                        }
118                        break;
119
120                case syck_seq_kind:
121                        lua_newtable(bonus->L);
122                        o = lua_gettop(bonus->L);
123                        for ( i=0; i < n->data.list->idx; i++ )
124                        {
125                                oid = syck_seq_read(n, i);
126                                syck_lookup_sym(p, oid, (char **)&o2);
127                                lua_pushvalue(bonus->L, o2);
128                                lua_rawseti(bonus->L, o, i+1);
129                        }
130                        break;
131
132                case syck_map_kind:
133                        lua_newtable(bonus->L);
134                        o = lua_gettop(bonus->L);
135                        for ( i=0; i < n->data.pairs->idx; i++ )
136                        {
137                                oid = syck_map_read(n, map_key, i);
138                                syck_lookup_sym(p, oid, (char **)&o2);
139                                oid = syck_map_read(n, map_value, i);
140                                syck_lookup_sym(p, oid, (char **)&o3);
141
142                                lua_pushvalue(bonus->L, o2);
143                                lua_pushvalue(bonus->L, o3);
144                                lua_settable(bonus->L, o);
145                        }
146                        break;
147        }
148        oid = syck_add_sym(p, (char *)o);
149        return oid;
150}
151
152void lua_syck_emitter_handler(SyckEmitter *e, st_data_t data)
153{
154        struct emitter_xtra *bonus = (struct emitter_xtra *)e->bonus;
155        int type = lua_type(bonus->L, -1);
156        char buf[32];           /* find a better way, if possible */
157       
158        switch (type)
159        {
160                case LUA_TBOOLEAN:
161                        if (lua_toboolean(bonus->L, -1))
162                                strcpy(buf, "true");
163                        else
164                                strcpy(buf, "false");
165                        syck_emit_scalar(e, "boolean", scalar_none, 0, 0, 0, (char *)buf, strlen(buf));
166                        break;
167                case LUA_TSTRING:
168                        syck_emit_scalar(e, "string", scalar_none, 0, 0, 0, (char *)lua_tostring(bonus->L, -1), lua_strlen(bonus->L, -1));
169                        break;
170                case LUA_TNUMBER:
171                        ; lua_Number lnum; //is it an int or a float?
172                        lnum = lua_tonumber(bonus->L, -1);
173                        int asInt = lnum;
174                        if(asInt == lnum)
175                                snprintf(buf, sizeof(buf), "%i", asInt);
176                        else
177                        {
178                                snprintf(buf, sizeof(buf), "%f", lnum);
179                                /* Remove trailing zeroes after the decimal point */
180                                int k;
181                                for (k = strlen(buf) - 1; buf[k] == '0' && buf[k - 1] != '.'; k--)
182                                        buf[k] = '\0';
183                        }
184                        syck_emit_scalar(e, "number", scalar_none, 0, 0, 0, buf, strlen(buf));
185                        break;
186                case LUA_TTABLE:
187                        if (luaL_getn(bonus->L, -1) > 0) {                      /* treat it as an array */
188                                syck_emit_seq(e, "table", seq_none);
189                                lua_pushnil(bonus->L);  /* first key */
190                                while (lua_next(bonus->L, -2) != 0) {
191                                        /* `key' is at index -2 and `value' at index -1 */
192                                        syck_emit_item(e, bonus->id++);
193                                        lua_pop(bonus->L, 1);  /* removes `value'; keeps `key' for next iteration */
194
195                                }
196                                syck_emit_end(e);
197                        } else {                                                                        /* treat it as a map */
198                                syck_emit_map(e, "table", map_none);
199                                lua_pushnil(bonus->L);
200                                while (lua_next(bonus->L, -2) != 0) {
201                                        lua_pushvalue(bonus->L, -2);
202                                        syck_emit_item(e, bonus->id++);
203                                        lua_pop(bonus->L, 1);
204                                        syck_emit_item(e, bonus->id++);
205                                        lua_pop(bonus->L, 1);
206                                }
207                                syck_emit_end(e);
208                        }
209                        break;
210        }
211
212        bonus->id++;
213}
214
215static void lua_syck_mark_emitter(SyckEmitter *e, int idx)
216{
217        struct emitter_xtra *bonus = (struct emitter_xtra *)e->bonus;
218        int type = lua_type(bonus->L, idx);
219
220        switch (type) {
221                case LUA_TTABLE:
222                        lua_pushnil(bonus->L);  /* first key */
223                        while (lua_next(bonus->L, -2) != 0) {
224                                /* `key' is at index -2 and `value' at index -1 */
225                                //syck_emitter_mark_node(e, bonus->id++);
226                                syck_emitter_mark_node(e, bonus->id++);
227                                lua_syck_mark_emitter(e, -1);
228                                lua_pop(bonus->L, 1);
229                        }
230                        break;
231                default:
232                        syck_emitter_mark_node(e, bonus->id++);
233                        break;
234        }
235}
236
237
238void lua_syck_output_handler(SyckEmitter *e, char *str, long len)
239{
240        struct emitter_xtra *bonus = (struct emitter_xtra *)e->bonus;
241        luaL_addlstring(&bonus->output, str, len);
242}
243
244void lua_syck_error_handler(SyckParser *p, char *msg)
245{
246        //struct parser_xtra *bonus = (struct parser_xtra *)p->bonus;
247        luaL_error(((struct parser_xtra *)p->bonus)->orig, "Error at [Line %d, Col %d]: %s\n", p->linect, p->cursor - p->lineptr, msg );
248}
249
250
251static int syck_load(lua_State *L)
252{
253        struct parser_xtra *bonus;
254        SyckParser *parser;
255        SYMID v;
256        int obj;
257
258        if (!luaL_checkstring(L, 1))
259                luaL_typerror(L, 1, "string");
260
261        parser = syck_new_parser();
262        parser->bonus = S_ALLOC_N(struct parser_xtra, 1);
263
264        bonus = (struct parser_xtra *)parser->bonus;
265        bonus->orig = L;
266        bonus->L = lua_newthread(L);
267
268        syck_parser_str(parser, (char *)lua_tostring(L, 1), lua_strlen(L, 1), NULL);
269        syck_parser_handler(parser, lua_syck_parser_handler);
270        syck_parser_error_handler(parser, lua_syck_error_handler);
271        v = syck_parse(parser);
272        syck_lookup_sym(parser, v, (char **)&obj);
273
274        syck_free_parser(parser);
275
276        lua_pop(L,1); //pop the thread, we don't need it anymore.
277        lua_xmove(bonus->L, L, 1);
278
279        if ( parser->bonus != NULL )
280                S_FREE( parser->bonus );
281       
282        return 1;
283}
284
285
286
287static int syck_dump(lua_State *L)
288{
289        SyckEmitter *emitter;
290        struct emitter_xtra *bonus;
291
292        emitter = syck_new_emitter();
293        emitter->bonus = S_ALLOC_N(struct emitter_xtra, 1);
294
295
296        bonus = (struct emitter_xtra *)emitter->bonus;
297        bonus->L = lua_newthread(L);
298        luaL_buffinit(L, &bonus->output);
299
300        syck_emitter_handler(emitter, lua_syck_emitter_handler);
301        syck_output_handler(emitter, lua_syck_output_handler);
302
303        lua_pushvalue(L, -2);
304        lua_xmove(L, bonus->L, 1);
305
306        bonus->id = 1;
307        lua_syck_mark_emitter(emitter, bonus->id);
308
309        bonus->id = 1;
310        syck_emit(emitter, bonus->id);
311        syck_emitter_flush(emitter, 0);
312
313        luaL_pushresult(&bonus->output);
314       
315        syck_free_emitter(emitter);
316       
317        if (bonus != NULL )
318                S_FREE( bonus );
319       
320
321        return 1;
322}
323
324static const luaL_reg sycklib[] = {
325        {"load",        syck_load },
326        {"dump",        syck_dump },
327        {NULL, NULL}
328};
329
330
331static void set_info (lua_State *L)
332{
333// Assumes the table is on top of the stack.
334        lua_pushliteral (L, "_COPYRIGHT");
335        lua_pushliteral (L, "Copyright (C) why the lucky stiff");
336        lua_settable (L, -3);
337        lua_pushliteral (L, "_DESCRIPTION");
338        lua_pushliteral (L, "YAML handling through the syck library");
339        lua_settable (L, -3);
340        lua_pushliteral (L, "_VERSION");
341        lua_pushliteral (L, "0.56");
342        lua_settable (L, -3);
343}
344
345LUALIB_API int luaopen_syck(lua_State *L)
346{
347        luaL_openlib(L, "syck", sycklib, 0);
348        set_info(L);
349        return 1;
350}
Note: See TracBrowser for help on using the browser.