diff --git a/http/http_response.c b/http/http_response.c
index f7d15f5..ec85013 100644
--- a/http/http_response.c
+++ b/http/http_response.c
@@ -14,6 +14,132 @@
#include <libkc3/kc3.h>
#include "http_response.h"
+
+s_http_response * http_response_buf_parse (s_http_response *response,
+ s_buf *buf, bool parse_body)
+{
+ sw content_length = -1;
+ s_str content_length_str = {0};
+ s_tag default_messages = {0};
+ s_ident ident = {0};
+ s_tag *key = NULL;
+ const s_list *l = NULL;
+ sw r = 0;
+ sw result = 0;
+ s_tag tag_code = {0};
+ s_tag tag_message = {0};
+ s_http_response tmp = {0};
+ s_tag *value = NULL;
+ assert(response);
+ assert(buf);
+ if ((r = buf_read_until_1_into_str(buf, ' ', &tmp.protocol)) < 0)
+ return r;
+ result += r;
+ tag_code.type = TAG_U16;
+ tag_code.data.u16 = response->code;
+ if (! tag_code.data.u16)
+ tag_code.data.u16 = 200;
+ if (tag_code.data.u16 < 100 || tag_code.data.u16 > 999) {
+ err_puts("http_response_buf_write: invalid response code");
+ return -1;
+ }
+ if ((r = buf_inspect_u16_decimal(buf, &tag_code.data.u16)) < 0)
+ return r;
+ result += r;
+ if ((r = buf_write_1(buf, " ")) < 0)
+ return r;
+ result += r;
+ if (! response->message.size) {
+ ident_init(&ident, sym_1("HTTP.Response"), sym_1("default_messages"));
+ ident_get(&ident, &default_messages);
+ if (! tag_is_alist(&default_messages)) {
+ err_puts("http_response_buf_write: invalid default_messages:"
+ " not an AList");
+ tag_clean(&default_messages);
+ return -1;
+ }
+ if (alist_get((const s_list * const *) &default_messages.data.list,
+ &tag_code, &tag_message)) {
+ if (tag_message.type != TAG_STR) {
+ err_puts("http_response_buf_write: invalid default message:"
+ " not a Str");
+ tag_clean(&tag_message);
+ tag_clean(&default_messages);
+ return -1;
+ }
+ }
+ }
+ else {
+ tag_message.type = TAG_STR;
+ tag_message.data.str = response->message;
+ tag_message.data.str.free.p = NULL;
+ }
+ if ((r = buf_write_str(buf, &tag_message.data.str)) < 0) {
+ tag_clean(&tag_message);
+ tag_clean(&default_messages);
+ return r;
+ }
+ result += r;
+ tag_clean(&tag_message);
+ tag_clean(&default_messages);
+ if ((r = buf_write_1(buf, "\r\n")) < 0)
+ return r;
+ result += r;
+ str_init_1(&content_length_str, NULL, "Content-Length");
+ l = response->headers;
+ while (l) {
+ if (l->tag.type != TAG_TUPLE ||
+ l->tag.data.tuple.count != 2) {
+ err_puts("http_response_buf_write: invalid header: not a Tuple");
+ return -1;
+ }
+ key = l->tag.data.tuple.tag;
+ value = key + 1;
+ if (key->type != TAG_STR || value->type != TAG_STR) {
+ err_puts("http_response_buf_write: invalid header: not a Str");
+ return -1;
+ }
+ if (! compare_str(&content_length_str, &key->data.str))
+ sw_init_str(&content_length, &value->data.str);
+ if ((r = buf_write_str(buf, &key->data.str)) < 0)
+ return r;
+ result += r;
+ if ((r = buf_write_1(buf, ": ")) < 0)
+ return r;
+ result += r;
+ if ((r = buf_write_str(buf, &value->data.str)) < 0)
+ return r;
+ result += r;
+ if ((r = buf_write_1(buf, "\r\n")) < 0)
+ return r;
+ result += r;
+ l = list_next(l);
+ }
+ if (content_length < 0) {
+ if ((r = buf_write_str(buf, &content_length_str)) < 0)
+ return r;
+ result += r;
+ if ((r = buf_write_1(buf, ": ")) < 0)
+ return r;
+ result += r;
+ if ((r = buf_inspect_uw_decimal(buf, &response->body.size)) < 0)
+ return r;
+ result += r;
+ if ((r = buf_write_1(buf, "\r\n")) < 0)
+ return r;
+ result += r;
+ }
+ if ((r = buf_write_1(buf, "\r\n")) < 0)
+ return r;
+ result += r;
+ if (send_body) {
+ if ((r = buf_write_str(buf, &response->body)) < 0)
+ return r;
+ result += r;
+ }
+ return result;
+}
+
sw http_response_buf_write (const s_http_response *response,
s_buf *buf, bool send_body)
{
diff --git a/json/json.c b/json/json.c
index 2d5de5f..b01f124 100644
--- a/json/json.c
+++ b/json/json.c
@@ -13,40 +13,236 @@
#include <libkc3/kc3.h>
#include "json.h"
-s_tag * json_buf_inspect (s_buf *buf, s_tag *tag)
+sw json_buf_inspect (s_buf *buf, const s_tag *tag)
{
- sw r;
+ const s_sym *type;
assert(buf);
- assert(dest);
+ assert(tag);
switch (tag->type) {
- case TAG_MAP:
- return json_buf_inspect_map(buf, dest);
+ case TAG_MAP:
+ return json_buf_inspect_map(buf, &tag->data.map);
+ case TAG_STR:
+ return buf_inspect_str(buf, &tag->data.str);
+ case TAG_F32:
+ case TAG_F64:
+ case TAG_F128:
+ case TAG_INTEGER:
+ case TAG_S8:
+ case TAG_S16:
+ case TAG_S32:
+ case TAG_S64:
+ case TAG_SW:
+ case TAG_U8:
+ case TAG_U16:
+ case TAG_U32:
+ case TAG_U64:
+ case TAG_UW:
+ return json_buf_inspect_tag_number(buf, tag);
+ case TAG_BOOL:
+ return json_buf_inspect_bool(buf, tag->data.bool);
+ default:
+ break;
+ }
+ err_write_1("json_buf_inspect: unknown tag type: ");
+ tag_type(tag, &type);
+ err_inspect_sym(&type);
+ err_write_1("\n");
+ assert(! "json_buf_inspect: unknown tag type");
+ return -1;
+}
+
+sw json_buf_inspect_map (s_buf *buf, const s_map *map)
+{
+ uw i;
+ s_pretty_save pretty_save;
+ sw r;
+ sw result = 0;
+ s_str str;
+ const s_sym *type = &g_sym_Str;
+ if ((r = buf_write_1(buf, "{")) < 0)
+ return r;
+ result += r;
+ pretty_save_init(&pretty_save, &buf->pretty);
+ pretty_indent_from_column(&buf->pretty, 0);
+ i = 0;
+ while (i < map->count) {
+ switch (map->key[i].type) {
case TAG_STR:
- return json_buf_inspect_str(buf, dest);
- case TAG_F32:
- case TAG_F64:
- case TAG_F128:
- case TAG_INTEGER:
- case TAG_S8:
- case TAG_S16:
- case TAG_S32:
- case TAG_S64:
- case TAG_SW;
- case TAG_U8:
- case TAG_U16:
- case TAG_U32:
- case TAG_U64:
- case TAG_UW:
- return json_buf_inspect_number(buf, dest);
+ if ((r = buf_inspect_str(buf, &map->key[i].data.str)) < 0)
+ return r;
+ result += r;
break;
- case 't':
- case 'f':
- return json_buf_parse_bool(buf, dest);
+ case TAG_SYM:
+ if ((r = buf_inspect_str(buf, &map->key[i].data.sym->str)) < 0)
+ return r;
+ result += r;
break;
default:
- return NULL;
+ if (! str_init_cast(&str, &type, map->key + i)) {
+ err_puts("json_buf_inspect_map: cannot cast key to Str");
+ assert(! "json_buf_inspect_map: cannot cast key to Str");
+ return -1;
+ }
+ if ((r = buf_inspect_str(buf, &str)) < 0)
+ return r;
+ result += r;
+ str_clean(&str);
+ }
+ if ((r = buf_write_1(buf, ": ")) < 0)
+ return r;
+ result += r;
+ if ((r = json_buf_inspect(buf, map->value + i)) <= 0)
+ return r;
+ result += r;
+ i++;
+ if (i < map->count) {
+ if ((r = buf_write_1(buf, ",\n")) < 0)
+ return r;
+ result += r;
+ }
}
- return NULL;
+ pretty_save_clean(&pretty_save, &buf->pretty);
+ if ((r = buf_write_1(buf, "}")) < 0)
+ return -1;
+ result += r;
+ return result;
+}
+
+sw json_buf_inspect_map_size (s_pretty *pretty, const s_map *map)
+{
+ uw i;
+ s_pretty_save pretty_save;
+ sw r;
+ sw result = 0;
+ s_str str;
+ const s_sym *type = &g_sym_Str;
+ assert(pretty);
+ assert(map);
+ if ((r = buf_write_1_size(pretty, "{")) < 0)
+ return r;
+ result += r;
+ pretty_save_init(&pretty_save, pretty);
+ pretty_indent_from_column(pretty, 0);
+ i = 0;
+ while (i < map->count) {
+ switch (map->key[i].type) {
+ case TAG_STR:
+ if ((r = buf_inspect_str_size(pretty, &map->key[i].data.str)) < 0)
+ return r;
+ result += r;
+ break;
+ case TAG_SYM:
+ if ((r = buf_inspect_str_size(pretty, &map->key[i].data.sym->str)) < 0)
+ return r;
+ result += r;
+ break;
+ default:
+ if (! str_init_cast(&str, &type, map->key + i)) {
+ err_puts("json_buf_inspect_map: cannot cast key to Str");
+ assert(! "json_buf_inspect_map: cannot cast key to Str");
+ return -1;
+ }
+ if ((r = buf_inspect_str_size(pretty, &str)) < 0)
+ return r;
+ result += r;
+ str_clean(&str);
+ }
+ if ((r = buf_write_1_size(pretty, ": ")) < 0)
+ return r;
+ result += r;
+ if ((r = json_buf_inspect_size(pretty, map->value + i)) <= 0)
+ return r;
+ result += r;
+ i++;
+ if (i < map->count) {
+ if ((r = buf_write_1_size(pretty, ",\n")) < 0)
+ return r;
+ result += r;
+ }
+ }
+ pretty_save_clean(&pretty_save, pretty);
+ if ((r = buf_write_1_size(pretty, "}")) < 0)
+ return -1;
+ result += r;
+ return result;
+}
+
+sw json_buf_inspect_size (s_pretty *pretty, const s_tag *tag)
+{
+ const s_sym *type;
+ assert(pretty);
+ assert(tag);
+ switch (tag->type) {
+ case TAG_MAP:
+ return json_buf_inspect_map_size(pretty, &tag->data.map);
+ case TAG_STR:
+ return buf_inspect_str_size(pretty, &tag->data.str);
+ case TAG_F32:
+ case TAG_F64:
+ case TAG_F128:
+ case TAG_INTEGER:
+ case TAG_S8:
+ case TAG_S16:
+ case TAG_S32:
+ case TAG_S64:
+ case TAG_SW:
+ case TAG_U8:
+ case TAG_U16:
+ case TAG_U32:
+ case TAG_U64:
+ case TAG_UW:
+ return json_buf_inspect_tag_number_size(pretty, tag);
+ case TAG_BOOL:
+ return json_buf_inspect_bool_size(pretty, tag->data.bool);
+ default:
+ break;
+ }
+ err_write_1("json_buf_inspect: unknown tag type: ");
+ tag_type(tag, &type);
+ err_inspect_sym(&type);
+ err_write_1("\n");
+ assert(! "json_buf_inspect: unknown tag type");
+ return -1;
+}
+
+sw json_buf_inspect_tag_number (s_buf *buf, const s_tag *tag)
+{
+ s_integer i;
+ sw r;
+ const s_sym *type = &g_sym_Integer;
+ assert(buf);
+ assert(tag);
+ if (! integer_init_cast(&i, &type, tag)) {
+ err_write_1("json_buf_inspect_tag_number: cannot cast to"
+ " Integer: ");
+ err_inspect_tag(tag);
+ err_write_1("\n");
+ assert(! "json_buf_inspect_tag_number: cannot cast to Integer: ");
+ return -1;
+ }
+ r = buf_inspect_integer(buf, &i);
+ integer_clean(&i);
+ return r;
+}
+
+sw json_buf_inspect_tag_number_size (s_pretty *pretty, const s_tag *tag)
+{
+ s_integer i;
+ sw r;
+ const s_sym *type = &g_sym_Integer;
+ assert(pretty);
+ assert(tag);
+ if (! integer_init_cast(&i, &type, tag)) {
+ err_write_1("json_buf_inspect_tag_number: cannot cast to"
+ " Integer: ");
+ err_inspect_tag(tag);
+ err_write_1("\n");
+ assert(! "json_buf_inspect_tag_number: cannot cast to Integer: ");
+ return -1;
+ }
+ r = buf_inspect_integer_size(pretty, &i);
+ integer_clean(&i);
+ return r;
}
s_tag * json_buf_parse (s_buf *buf, s_tag *dest)
@@ -199,3 +395,29 @@ s_tag * json_from_str (const s_str *src, s_tag *dest)
buf_init_str_const(&buf, src);
return json_buf_parse(&buf, dest);
}
+
+s_str * json_to_str (const s_tag *tag, s_str *dest)
+{
+ s_pretty pretty = {0};
+ sw size;
+ s_buf tmp;
+ size = json_buf_inspect_size(&pretty, tag);
+ if (size < 0) {
+ err_puts("json_to_str: buf_inspect_array_size error");
+ assert(! "json_to_str: buf_inspect_array_size error");
+ return NULL;
+ }
+ if (! buf_init_alloc(&tmp, size)) {
+ err_puts("json_to_str: buf_init alloc");
+ assert(! "json_to_str: buf_init_alloc");
+ return NULL;
+ }
+ json_buf_inspect(&tmp, tag);
+ if (tmp.wpos != tmp.size) {
+ err_puts("json_to_str: tmp.wpos != tmp.size");
+ assert(! "json_to_str: tmp.wpos != tmp.size");
+ buf_clean(&tmp);
+ return NULL;
+ }
+ return buf_to_str(&tmp, dest);
+}
diff --git a/json/json.h b/json/json.h
index 809fb76..6b1e35c 100644
--- a/json/json.h
+++ b/json/json.h
@@ -15,6 +15,15 @@
#include <libkc3/types.h>
+sw json_buf_inspect (s_buf *buf, const s_tag *tag);
+sw json_buf_inspect_bool (s_buf *buf, bool b);
+sw json_buf_inspect_bool_size (s_pretty *pretty, bool b);
+sw json_buf_inspect_map (s_buf *buf, const s_map *map);
+sw json_buf_inspect_map_size (s_pretty *pretty, const s_map *map);
+sw json_buf_inspect_size (s_pretty *pretty, const s_tag *tag);
+sw json_buf_inspect_tag_number (s_buf *buf, const s_tag *tag);
+sw json_buf_inspect_tag_number_size (s_pretty *pretty,
+ const s_tag *tag);
s_tag * json_buf_parse (s_buf *buf, s_tag *dest);
s_tag * json_buf_parse_bool (s_buf *buf, s_tag *dest);
s_tag * json_buf_parse_map (s_buf *buf, s_tag *dest);
diff --git a/lib/kc3/0.1/json.kc3 b/lib/kc3/0.1/json.kc3
index 0ee98a1..9cc3dc8 100644
--- a/lib/kc3/0.1/json.kc3
+++ b/lib/kc3/0.1/json.kc3
@@ -2,8 +2,12 @@ defmodule JSON do
dlopen(__DIR__ + "json.so")
+ def buf_inspect = cfn Sw "json_buf_inspect" (Buf, Tag)
+
def buf_parse = cfn Tag "json_buf_parse" (Buf, Result)
def from_str = cfn Tag "json_from_str" (Str, Result)
+ def to_str = cfn Str "json_to_str" (Tag, Result)
+
end
diff --git a/libkc3/buf_parse.c b/libkc3/buf_parse.c
index 95bf7f6..3abdfdc 100644
--- a/libkc3/buf_parse.c
+++ b/libkc3/buf_parse.c
@@ -36,6 +36,7 @@
#include "list.h"
#include "map.h"
#include "operator.h"
+#include "ratio.h"
#include "special_operator.h"
#include "str.h"
#include "struct.h"
@@ -43,7 +44,7 @@
#include "tag.h"
#include "time.h"
#include "tuple.h"
-#include "ratio.h"
+#include "u16.h"
sw buf_parse_array_data_rec (s_buf *buf, s_array *dest, uw *address,
s_tag **tag, uw dimension);
@@ -4203,6 +4204,29 @@ sw buf_parse_tag_tuple (s_buf *buf, s_tag *dest)
return r;
}
+s_tag * buf_parse_tag_u16 (s_buf *buf, s_tag *dest)
+{
+ sw r;
+ s_buf_save save;
+ s_tag tag;
+ const s_sym *type = &g_sym_U16;
+ u16 u;
+ assert(buf);
+ assert(dest);
+ buf_save_init(buf, &save);
+ r = buf_parse_tag_integer(buf, &tag);
+ if (r > 0) {
+ if (! u16_init_cast(&u, &type, &tag))
+ goto restore;
+ buf_save_clean(buf, &save);
+ return tag_init_u16(dest, u);
+ }
+ restore:
+ buf_save_restore_rpos(buf, &save);
+ buf_save_clean(buf, &save);
+ return NULL;
+}
+
sw buf_parse_tag_unquote (s_buf *buf, s_tag *dest)
{
sw r;
diff --git a/libkc3/kc3.h b/libkc3/kc3.h
index c76c8a9..5cf7858 100644
--- a/libkc3/kc3.h
+++ b/libkc3/kc3.h
@@ -70,6 +70,7 @@
#include "ptr_free.h"
#include "module.h"
#include "operator.h"
+#include "pretty.h"
#include "quote.h"
#include "s8.h"
#include "s16.h"
diff --git a/test/json/to_str.kc3 b/test/json/to_str.kc3
new file mode 100644
index 0000000..8f52f73
--- /dev/null
+++ b/test/json/to_str.kc3
@@ -0,0 +1,6 @@
+quote JSON.to_str(%{})
+JSON.to_str(%{})
+quote JSON.to_str(%{"a" => "b"})
+JSON.to_str(%{"a" => "b"})
+quote JSON.to_str(%{"a" => 1})
+JSON.to_str(%{"a" => 1})
diff --git a/test/json/to_str.out.expected b/test/json/to_str.out.expected
new file mode 100644
index 0000000..edaa6ca
--- /dev/null
+++ b/test/json/to_str.out.expected
@@ -0,0 +1,6 @@
+JSON.to_str(%{})
+"{}"
+JSON.to_str(%{"a" => "b"})
+"{\"a\": \"b\"}"
+JSON.to_str(%{"a" => 1})
+"{\"a\": 1}"
diff --git a/test/json/to_str.ret.expected b/test/json/to_str.ret.expected
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/test/json/to_str.ret.expected
@@ -0,0 +1 @@
+0