webmcp
changeset 163:581878c613d6
Always sort keys in JSON objects when exporting
author | jbe |
---|---|
date | Thu Jul 31 19:27:29 2014 +0200 (2014-07-31) |
parents | 3b8c1e2aef9c |
children | 8e969519f7c7 |
files | libraries/json/json.c |
line diff
1.1 --- a/libraries/json/json.c Thu Jul 31 16:24:39 2014 +0200 1.2 +++ b/libraries/json/json.c Thu Jul 31 19:27:29 2014 +0200 1.3 @@ -678,6 +678,35 @@ 1.4 return 3; 1.5 } 1.6 1.7 +typedef struct { 1.8 + size_t length; 1.9 + const char *data; 1.10 +} json_key_t; 1.11 + 1.12 +static int json_key_cmp(json_key_t *key1, json_key_t *key2) { 1.13 + size_t pos = 0; 1.14 + unsigned char c1, c2; 1.15 + while (1) { 1.16 + if (key1->length > pos) { 1.17 + if (key2->length > pos) { 1.18 + c1 = key1->data[pos]; 1.19 + c2 = key2->data[pos]; 1.20 + if (c1 < c2) return -1; 1.21 + else if (c1 > c2) return 1; 1.22 + } else { 1.23 + return 1; 1.24 + } 1.25 + } else { 1.26 + if (key2->length > pos) { 1.27 + return -1; 1.28 + } else { 1.29 + return 0; 1.30 + } 1.31 + } 1.32 + pos++; 1.33 + } 1.34 +} 1.35 + 1.36 #define JSON_TABLETYPE_UNKNOWN 0 1.37 #define JSON_TABLETYPE_OBJECT 1 1.38 #define JSON_TABLETYPE_ARRAY 2 1.39 @@ -693,6 +722,9 @@ 1.40 int luatype; 1.41 int tabletype = JSON_TABLETYPE_UNKNOWN; 1.42 int needsep = 0; 1.43 + size_t keycount = 0; 1.44 + size_t keypos = 0; 1.45 + json_key_t *keybuf; 1.46 lua_Integer idx; 1.47 lua_settop(L, 1); 1.48 if (json_isnullmark(L, 1)) { 1.49 @@ -768,33 +800,43 @@ 1.50 } 1.51 switch (tabletype) { 1.52 case JSON_TABLETYPE_OBJECT: 1.53 - lua_settop(L, 3); 1.54 + for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) { 1.55 + if (lua_type(L, -2) == LUA_TSTRING) keycount++; 1.56 + } 1.57 + if (keycount) { 1.58 + keybuf = calloc(keycount, sizeof(json_key_t)); 1.59 + if (!keybuf) return luaL_error(L, "Memory allocation failed in JSON library"); 1.60 + for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) { 1.61 + if (lua_type(L, -2) == LUA_TSTRING) { 1.62 + json_key_t *key = keybuf + (keypos++); 1.63 + key->data = lua_tolstring(L, -2, &key->length); 1.64 + } 1.65 + } 1.66 + qsort(keybuf, keycount, sizeof(json_key_t), (void *)json_key_cmp); 1.67 + } 1.68 luaL_buffinit(L, &buf); 1.69 luaL_addchar(&buf, '{'); 1.70 - for (lua_pushnil(L); lua_next(L, 1); ) { 1.71 - if (lua_type(L, -2) == LUA_TSTRING) { 1.72 - lua_replace(L, 3); 1.73 - lua_replace(L, 2); 1.74 - if (needsep) luaL_addchar(&buf, ','); 1.75 - else needsep = 1; 1.76 - lua_pushcfunction(L, json_export); 1.77 - lua_pushvalue(L, 2); 1.78 - lua_call(L, 1, 1); 1.79 - luaL_addvalue(&buf); 1.80 - luaL_addchar(&buf, ':'); 1.81 - if (json_isnullmark(L, 3)) { 1.82 - luaL_addstring(&buf, "null"); 1.83 - } else { 1.84 - lua_pushcfunction(L, json_export); 1.85 - lua_pushvalue(L, 3); 1.86 - lua_call(L, 1, 1); 1.87 - luaL_addvalue(&buf); 1.88 - } 1.89 - lua_pushvalue(L, 2); 1.90 - } else { 1.91 - lua_pop(L, 1); 1.92 + for (keypos=0; keypos<keycount; keypos++) { 1.93 + json_key_t *key = keybuf + keypos; 1.94 + if (keypos) luaL_addchar(&buf, ','); 1.95 + lua_pushcfunction(L, json_export); 1.96 + lua_pushlstring(L, key->data, key->length); 1.97 + if (lua_pcall(L, 1, 1, 0)) { 1.98 + if (keybuf) free(keybuf); 1.99 + return lua_error(L); 1.100 } 1.101 + luaL_addvalue(&buf); 1.102 + luaL_addchar(&buf, ':'); 1.103 + lua_pushcfunction(L, json_export); 1.104 + lua_pushlstring(L, key->data, key->length); 1.105 + lua_rawget(L, 1); 1.106 + if (lua_pcall(L, 1, 1, 0)) { 1.107 + if (keybuf) free(keybuf); 1.108 + return lua_error(L); 1.109 + } 1.110 + luaL_addvalue(&buf); 1.111 } 1.112 + if (keybuf) free(keybuf); 1.113 luaL_addchar(&buf, '}'); 1.114 luaL_pushresult(&buf); 1.115 return 1;