| 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 | |
|---|
| 19 | struct emitter_xtra { |
|---|
| 20 | lua_State *L; |
|---|
| 21 | luaL_Buffer output; |
|---|
| 22 | int id; |
|---|
| 23 | }; |
|---|
| 24 | |
|---|
| 25 | struct parser_xtra { |
|---|
| 26 | lua_State *L; //syck parser thread state |
|---|
| 27 | lua_State *orig; //original API stack state |
|---|
| 28 | }; |
|---|
| 29 | |
|---|
| 30 | /* |
|---|
| 31 | static 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 | */ |
|---|
| 61 | SYMID |
|---|
| 62 | lua_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 | |
|---|
| 152 | void 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 | |
|---|
| 215 | static 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 | |
|---|
| 238 | void 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 | |
|---|
| 244 | void 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 | |
|---|
| 251 | static 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 | |
|---|
| 287 | static 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 | |
|---|
| 324 | static const luaL_reg sycklib[] = { |
|---|
| 325 | {"load", syck_load }, |
|---|
| 326 | {"dump", syck_dump }, |
|---|
| 327 | {NULL, NULL} |
|---|
| 328 | }; |
|---|
| 329 | |
|---|
| 330 | |
|---|
| 331 | static 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 | |
|---|
| 345 | LUALIB_API int luaopen_syck(lua_State *L) |
|---|
| 346 | { |
|---|
| 347 | luaL_openlib(L, "syck", sycklib, 0); |
|---|
| 348 | set_info(L); |
|---|
| 349 | return 1; |
|---|
| 350 | } |
|---|