int serialize_table_as_json(lua_sandbox* lsb, serialization_data* data, int isHash) { int result = 0; lua_checkstack(lsb->lua, 2); lua_pushnil(lsb->lua); int had_output = 0; size_t start = 0; while (result == 0 && lua_next(lsb->lua, -2) != 0) { if (had_output) { if (appendc(&lsb->output, ',')) return 1; } start = lsb->output.pos; result = serialize_kvp_as_json(lsb, data, isHash); lua_pop(lsb->lua, 1); // Remove the value leaving the key on top for // the next interation. if (start != lsb->output.pos) { had_output = 1; } else { had_output = 0; } } if (start != 0 && had_output == 0) { // remove the trailing comma size_t reset_pos = start - 1; if (lsb->output.data[reset_pos] == ',') { lsb->output.data[reset_pos] = 0; lsb->output.pos = reset_pos; } } return result; }
int output(lua_State* lua) { void* luserdata = lua_touserdata(lua, lua_upvalueindex(1)); if (NULL == luserdata) { luaL_error(lua, "output() invalid lightuserdata"); } lua_sandbox* lsb = (lua_sandbox*)luserdata; int n = lua_gettop(lua); if (n == 0) { luaL_error(lua, "output() must have at least one argument"); } int result = 0; void* ud = NULL; for (int i = 1; result == 0 && i <= n; ++i) { switch (lua_type(lua, i)) { case LUA_TNUMBER: if (serialize_double(&lsb->m_output, lua_tonumber(lua, i))) { result = 1; } break; case LUA_TSTRING: if (dynamic_snprintf(&lsb->m_output, "%s", lua_tostring(lua, i))) { result = 1; } break; case LUA_TNIL: if (dynamic_snprintf(&lsb->m_output, "nil")) { result = 1; } break; case LUA_TBOOLEAN: if (dynamic_snprintf(&lsb->m_output, "%s", lua_toboolean(lsb->m_lua, i) ? "true" : "false")) { result = 1; } break; case LUA_TTABLE: if (!dynamic_snprintf(&lsb->m_output, "{")) { serialization_data data; data.m_globals = NULL; data.m_tables.m_size = 64; data.m_tables.m_pos = 0; data.m_tables.m_array = malloc(data.m_tables.m_size * sizeof(table_ref)); if (data.m_tables.m_array == NULL) { snprintf(lsb->m_error_message, ERROR_SIZE, "json table serialization out of memory"); result = 1; } else { lua_checkstack(lsb->m_lua, 2); lua_getfield(lsb->m_lua, i, "_name"); if (lua_type(lsb->m_lua, -1) != LUA_TSTRING) { lua_pop(lsb->m_lua, 1); // remove the failed _name result lua_pushstring(lsb->m_lua, "table"); // add default name } lua_pushvalue(lsb->m_lua, i); result = serialize_kvp_as_json(lsb, &data, 1); if (result == 0) { result = dynamic_snprintf(&lsb->m_output, "}\n"); } lua_pop(lsb->m_lua, 2); // remove the name and copy of the table free(data.m_tables.m_array); } } else { result = 1; } break; case LUA_TUSERDATA: ud = lua_touserdata(lua, i); if (heka_circular_buffer == userdata_type(lua, ud, i)) { if (output_circular_buffer(lua, (circular_buffer*)ud, &lsb->m_output)) { result = 1; } } break; } } update_output_stats(lsb); if (result != 0 || lsb->m_usage[USAGE_TYPE_OUTPUT][USAGE_STAT_CURRENT] > lsb->m_usage[USAGE_TYPE_OUTPUT][USAGE_STAT_LIMIT]) { if (lsb->m_error_message[0] == 0) { luaL_error(lua, "output_limit exceeded"); } luaL_error(lua, lsb->m_error_message); } return 0; }