diff --git a/README.md b/README.md
index 625ed2a..652844a 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,12 @@
-# KC3 v0.1.14
+# KC3 v0.1.15
KC3 is a programming language with meta-programmation and a graph
database embedded into the language. It aims to be the language
for semantic programming, and programming the semantic web.
-This is a stable release, for the development branch see
-[the KC3 git repository master branch](https://git.kmx.io/kc3-lang/kc3).
+This is a development branch see
+[KC3 v0.1.14](https://git.kmx.io/kc3-lang/kc3/_tree/v0.1.14)
+for a stable release.
KC3 is currently a programming language project, inspired by C, Elixir
and Common Lisp. It could be described as C with Elixir modules,
diff --git a/env b/env
index c160898..8923f71 100644
--- a/env
+++ b/env
@@ -1,4 +1,4 @@
-export LD_LIBRARY_PATH="$PWD/libkc3/.libs:$PWD/ekc3/.libs:$PWD/http/.libs:$PWD/markdown/.libs:$PWD/lib/kc3/0.1:$LD_LIBRARY_PATH"
+export LD_LIBRARY_PATH="$PWD/libkc3/.libs:$PWD/ekc3/.libs:$PWD/http/.libs:$PWD/markdown/.libs:$PWD/lib/kc3/0.1:$PWD/window/.libs:$PWD/window/sdl2/.libs:$LD_LIBRARY_PATH"
export DYLD_LIBRARY_PATH="$PWD/libkc3/.libs:$PWD/ekc3/.libs:$PWD/http/.libs:$PWD/markdown/.libs:$PWD/lib/kc3/0.1:$DYLD_LIBRARY_PATH"
export KC3_HTTPD_HOST=0.0.0.0
export KC3_HTTPD_PORT=58000
diff --git a/http/http_request.c b/http/http_request.c
index f617f47..6c4b687 100644
--- a/http/http_request.c
+++ b/http/http_request.c
@@ -18,8 +18,10 @@
s_tag * http_request_buf_parse (s_tag *req, s_buf *buf)
{
+ bool b;
s_tag body;
s_str *body_str;
+ s_str boundary;
const s_str content_length_str = {{NULL}, 14, {"Content-Length"}};
uw content_length_uw = 0;
s_str *content_type = NULL;
@@ -29,6 +31,8 @@ s_tag * http_request_buf_parse (s_tag *req, s_buf *buf)
s_str line;
s_tag method_key = {0};
s_tag method_value = {0};
+ static const s_str multipart_form_data =
+ {{NULL}, 30, {"multipart/form-data; boundary="}};
s_buf_save save;
s_list **tail;
s_tag tmp = {0};
@@ -109,23 +113,38 @@ s_tag * http_request_buf_parse (s_tag *req, s_buf *buf)
err_inspect_str(body_str);
err_write_1("\n");
}
- if (content_type &&
- ! compare_str_case_insensitive(&urlencoded, content_type)) {
- if (! url_www_form_decode(body_str, &body))
- goto restore;
- if (false) {
- err_write_1("http_request_buf_parse: body: ");
- err_inspect_tag(&body);
- err_write_1("\n");
+ if (content_type) {
+ if (! compare_str_case_insensitive(&urlencoded, content_type)) {
+ if (! url_www_form_decode(body_str, &body))
+ goto restore;
+ if (false) {
+ err_write_1("http_request_buf_parse: body: ");
+ err_inspect_tag(&body);
+ err_write_1("\n");
+ }
+ if (alist_get(body.data.list,
+ &method_key, &method_value)) {
+ http_request_method_from_str(&method_value.data.str,
+ &tmp_req.method);
+ tag_clean(&method_value);
+ }
+ str_clean(body_str);
+ tmp_req.body = body;
}
- if (alist_get(body.data.list,
- &method_key, &method_value)) {
- http_request_method_from_str(&method_value.data.str,
- &tmp_req.method);
- tag_clean(&method_value);
+ }
+ if (! str_starts_with_case_insensitive(content_type,
+ &multipart_form_data,
+ &b)) {
+ if (b) {
+ if (! str_init_slice(&boundary, content_type,
+ multipart_form_data.size, -1))
+ goto restore;
+ if (true) {
+ err_write_1("http_request_buf_parse: boundary ");
+ err_inspect_str(&boundary);
+ err_write_1("\n");
+ }
}
- str_clean(body_str);
- tmp_req.body = body;
}
}
if (! tag_init_struct(&tmp, sym_1("HTTP.Request")))
diff --git a/kc3.version b/kc3.version
index 71d6a66..c34958a 100644
--- a/kc3.version
+++ b/kc3.version
@@ -1 +1 @@
-0.1.14
+0.1.15
diff --git a/libkc3/str.c b/libkc3/str.c
index ce97797..de70557 100644
--- a/libkc3/str.c
+++ b/libkc3/str.c
@@ -1405,6 +1405,42 @@ bool * str_starts_with (const s_str *str, const s_str *start,
return dest;
}
+bool * str_starts_with_case_insensitive (const s_str *str,
+ const s_str *start,
+ bool *dest)
+{
+ character str_c;
+ s_str str_i;
+ character start_c;
+ s_str start_i;
+ assert(str);
+ assert(start);
+ if (! start->size) {
+ *dest = true;
+ return dest;
+ }
+ if (str->size < start->size) {
+ *dest = false;
+ return dest;
+ }
+ str_i = *str;
+ start_i = *start;
+ while (start_i.size > 0) {
+ if (str_read_character_utf8(&start_i, &start_c) < 0)
+ return NULL;
+ if (str_read_character_utf8(&str_i, &str_c) < 0)
+ return NULL;
+ start_c = character_to_lower(start_c);
+ str_c = character_to_lower(str_c);
+ if (start_c != str_c) {
+ *dest = false;
+ return dest;
+ }
+ }
+ *dest = true;
+ return dest;
+}
+
uw * str_sw_pos_to_uw (sw pos, uw max_pos, uw *dest)
{
assert(dest);
diff --git a/libkc3/str.h b/libkc3/str.h
index 3d36a89..82a6dc9 100644
--- a/libkc3/str.h
+++ b/libkc3/str.h
@@ -138,6 +138,9 @@ s_list ** str_split (const s_str *str, const s_str *separator,
s_list **dest);
bool * str_starts_with (const s_str *str, const s_str *start,
bool *dest);
+bool * str_starts_with_case_insensitive (const s_str *str,
+ const s_str *start,
+ bool *dest);
uw * str_sw_pos_to_uw (sw pos, uw max_pos, uw *dest);
s_str * str_to_hex (const s_str *str, s_str *dest);
s_ident * str_to_ident (const s_str *str, s_ident *dest);
diff --git a/window/sdl2/Makefile b/window/sdl2/Makefile
index b9b5416..2faa40c 100644
--- a/window/sdl2/Makefile
+++ b/window/sdl2/Makefile
@@ -21,6 +21,7 @@ DISTCLEANFILES = ${CLEANFILES} config.h config.mk
build:
${MAKE} ${LIB}
${MAKE} -C demo build
+ ${MAKE} -C kubz build
all:
${MAKE} build
diff --git a/window/window.c b/window/window.c
index 19f60e8..86964c5 100644
--- a/window/window.c
+++ b/window/window.c
@@ -35,7 +35,8 @@ bool window_animate (s_window *window)
seq->frame++;
seq->t = t;
/* printf("window_animate: %f\n", t); */
- if (t > seq->duration &&
+ if (seq->duration > 0 &&
+ t > seq->duration &&
! window_set_sequence_pos(window, (window->sequence_pos + 1) %
window->sequence_count))
return false;