static void f_keys(jv input[], jv output[]) { if (jv_get_kind(input[0]) == JV_KIND_OBJECT) { int nkeys = jv_object_length(jv_copy(input[0])); jv* keys = malloc(sizeof(jv) * nkeys); int kidx = 0; jv_object_foreach(i, input[0]) { keys[kidx++] = jv_object_iter_key(input[0], i); }
jv jv_keys(jv x) { if (jv_get_kind(x) == JV_KIND_OBJECT) { int nkeys = jv_object_length(jv_copy(x)); jv* keys = malloc(sizeof(jv) * nkeys); int kidx = 0; jv_object_foreach(i, x) { keys[kidx++] = jv_object_iter_key(x, i); }
static void f_length(jv input[], jv output[]) { if (jv_get_kind(input[0]) == JV_KIND_ARRAY) { output[0] = jv_number(jv_array_length(input[0])); } else if (jv_get_kind(input[0]) == JV_KIND_OBJECT) { output[0] = jv_number(jv_object_length(input[0])); } else if (jv_get_kind(input[0]) == JV_KIND_STRING) { output[0] = jv_number(jv_string_length(input[0])); } else { output[0] = jv_invalid_with_msg(jv_string_fmt("Cannot get the length of %s", jv_kind_name(jv_get_kind(input[0])))); jv_free(input[0]); } }
static pfunc token(struct jv_parser* p, char ch) { switch (ch) { case '[': if (jv_is_valid(p->next)) return "Expected separator between values"; push(p, jv_array()); break; case '{': if (jv_is_valid(p->next)) return "Expected separator between values"; push(p, jv_object()); break; case ':': if (!jv_is_valid(p->next)) return "Expected string key before ':'"; if (p->stackpos == 0 || jv_get_kind(p->stack[p->stackpos-1]) != JV_KIND_OBJECT) return "':' not as part of an object"; if (jv_get_kind(p->next) != JV_KIND_STRING) return "Object keys must be strings"; push(p, p->next); p->next = jv_invalid(); break; case ',': if (!jv_is_valid(p->next)) return "Expected value before ','"; if (p->stackpos == 0) return "',' not as part of an object or array"; if (jv_get_kind(p->stack[p->stackpos-1]) == JV_KIND_ARRAY) { p->stack[p->stackpos-1] = jv_array_append(p->stack[p->stackpos-1], p->next); p->next = jv_invalid(); } else if (jv_get_kind(p->stack[p->stackpos-1]) == JV_KIND_STRING) { assert(p->stackpos > 1 && jv_get_kind(p->stack[p->stackpos-2]) == JV_KIND_OBJECT); p->stack[p->stackpos-2] = jv_object_set(p->stack[p->stackpos-2], p->stack[p->stackpos-1], p->next); p->stackpos--; p->next = jv_invalid(); } else { // this case hits on input like {"a", "b"} return "Objects must consist of key:value pairs"; } break; case ']': if (p->stackpos == 0 || jv_get_kind(p->stack[p->stackpos-1]) != JV_KIND_ARRAY) return "Unmatched ']'"; if (jv_is_valid(p->next)) { p->stack[p->stackpos-1] = jv_array_append(p->stack[p->stackpos-1], p->next); p->next = jv_invalid(); } else { if (jv_array_length(jv_copy(p->stack[p->stackpos-1])) != 0) { // this case hits on input like [1,2,3,] return "Expected another array element"; } } jv_free(p->next); p->next = p->stack[--p->stackpos]; break; case '}': if (p->stackpos == 0) return "Unmatched '}'"; if (jv_is_valid(p->next)) { if (jv_get_kind(p->stack[p->stackpos-1]) != JV_KIND_STRING) return "Objects must consist of key:value pairs"; assert(p->stackpos > 1 && jv_get_kind(p->stack[p->stackpos-2]) == JV_KIND_OBJECT); p->stack[p->stackpos-2] = jv_object_set(p->stack[p->stackpos-2], p->stack[p->stackpos-1], p->next); p->stackpos--; p->next = jv_invalid(); } else { if (jv_get_kind(p->stack[p->stackpos-1]) != JV_KIND_OBJECT) return "Unmatched '}'"; if (jv_object_length(jv_copy(p->stack[p->stackpos-1])) != 0) return "Expected another key-value pair"; } jv_free(p->next); p->next = p->stack[--p->stackpos]; break; } return 0; }
static void php_jv_dump(zval **return_value, jv x TSRMLS_DC) { switch (jv_get_kind(x)) { default: case JV_KIND_INVALID: if (PHP_JQ_G(display_errors)) { PHP_JQ_ERR(E_WARNING, "json parse error"); } break; case JV_KIND_NULL: INIT_PZVAL(*return_value); ZVAL_NULL(*return_value); break; case JV_KIND_FALSE: INIT_PZVAL(*return_value); ZVAL_BOOL(*return_value, 0); break; case JV_KIND_TRUE: INIT_PZVAL(*return_value); ZVAL_BOOL(*return_value, 1); break; case JV_KIND_NUMBER: { double d = jv_number_value(x); INIT_PZVAL(*return_value); if (d != d || d > LONG_MAX || d < LONG_MIN) { ZVAL_DOUBLE(*return_value, jv_number_value(x)); } else if (d == (long)d) { ZVAL_LONG(*return_value, (long)d); } else { ZVAL_DOUBLE(*return_value, jv_number_value(x)); } break; } case JV_KIND_STRING: { int len = jv_string_length_bytes(jv_copy(x)); INIT_PZVAL(*return_value); if (len <= 0) { ZVAL_EMPTY_STRING(*return_value); } else { ZVAL_STRINGL(*return_value, jv_string_value(x), len, 1); } break; } case JV_KIND_ARRAY: { int i, len = jv_array_length(jv_copy(x)); INIT_PZVAL(*return_value); array_init(*return_value); if (len == 0) { break; } for (i = 0; i < len; i++) { jv value = jv_array_get(jv_copy(x), i); if (jv_is_valid(value)) { zval *zv; ALLOC_INIT_ZVAL(zv); php_jv_dump(&zv, value TSRMLS_CC); zend_hash_next_index_insert(Z_ARRVAL_PP(return_value), &zv, sizeof(zv), NULL); } else { jv_free(value); } } break; } case JV_KIND_OBJECT: { int i = 0, first = 1; INIT_PZVAL(*return_value); array_init(*return_value); if (jv_object_length(jv_copy(x)) == 0) { break; } while (1) { jv key, value; zval *zv; if (first) { i = jv_object_iter(x); } else { i = jv_object_iter_next(x, i); } if (!jv_object_iter_valid(x, i)) { break; } key = jv_object_iter_key(x, i); value = jv_object_iter_value(x, i); ALLOC_INIT_ZVAL(zv); php_jv_dump(&zv, value TSRMLS_CC); zend_symtable_update(Z_ARRVAL_PP(return_value), jv_string_value(key), jv_string_length_bytes(jv_copy(key)) + 1, &zv, sizeof(zv), NULL); first = 0; jv_free(key); } } } jv_free(x); }