diff --git a/httpd/httpd.c b/httpd/httpd.c
index 38df504..4fb5d69 100644
--- a/httpd/httpd.c
+++ b/httpd/httpd.c
@@ -11,20 +11,83 @@
* THIS SOFTWARE.
*/
#include <signal.h>
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
#include <libkc3/kc3.h>
#include "config.h"
int main (int argc, char **argv)
{
+ bool daemonize = true;
+ s_ident daemonize_ident;
+ s_tag daemonize_value;
+ char log_buf[64] = {0};
+ s32 log_fd = -1;
+ s_str log_str = {0};
s_call call = {0};
const s_sym *module = NULL;
+ char *p;
int r = 1;
+ time_t t;
s_tag tmp = {0};
+ const struct tm *utc = NULL;
kc3_init(NULL, &argc, &argv);
+ if (argc > 0 && argv[0] && argv[0][0] == '-') {
+ p = argv[0] + 1;
+ while (*p) {
+ switch (*p) {
+ case 'd':
+ daemonize = false;
+ break;
+ default:
+ err_write_1("kc3_httpd: unknown flag: -");
+ err_write_u8(*p);
+ err_write_1("\n");
+ assert(! "kc3_httpd: unknown flag");
+ kc3_clean(NULL);
+ return 1;
+ }
+ p++;
+ }
+ argc--;
+ argv++;
+ }
+ if (daemonize) {
+ if ((t = time(NULL)) == -1) {
+ kc3_clean(NULL);
+ return 1;
+ }
+ if (! (utc = gmtime(&t))) {
+ kc3_clean(NULL);
+ return 1;
+ }
+ strftime(log_buf, sizeof(log_buf) - 1, "log/kc3_httpd_%F_%T.log",
+ utc);
+ str_init_1(&log_str, NULL, log_buf);
+ if (! file_open_w(&log_str, &log_fd)) {
+ str_clean(&log_str);
+ kc3_clean(NULL);
+ return 1;
+ }
+ buf_file_close(&g_kc3_env.out);
+ dup2(log_fd, 1);
+ buf_fd_open_w(&g_kc3_env.out, 1);
+ buf_file_close(&g_kc3_env.err);
+ dup2(log_fd, 2);
+ buf_fd_open_w(&g_kc3_env.err, 2);
+ buf_file_close(&g_kc3_env.in);
+ close(0);
+ }
+ ident_init(&daemonize_ident, &g_sym_KC3, sym_1("daemonize"));
+ tag_init_bool(&daemonize_value, daemonize);
+ env_def(&g_kc3_env, &daemonize_ident, &daemonize_value);
io_puts("KC3 HTTPd loading, please wait...");
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
err_puts("http_event_base_new: signal");
assert(! "http_event_base_new: signal");
+ kc3_clean(NULL);
return 1;
}
module = sym_1("HTTPd");
diff --git a/lib/kc3/0.1/httpd.kc3 b/lib/kc3/0.1/httpd.kc3
index d706474..fe9c232 100644
--- a/lib/kc3/0.1/httpd.kc3
+++ b/lib/kc3/0.1/httpd.kc3
@@ -63,6 +63,15 @@ defmodule HTTPd do
end
end
+ def daemonize = fn () {
+ if (KC3.daemonize) do
+ puts("forking to background")
+ if fork() > 0 do
+ exit(0)
+ end
+ end
+ }
+
def timeout = %Time{}
def server = fn (host, port) {
@@ -72,6 +81,7 @@ defmodule HTTPd do
acceptor_ev = Event.new(event_base, socket.fd, [:read, :persist],
acceptor, void)
r = Event.add(acceptor_ev, timeout)
+ daemonize()
r = Event.dispatch(event_base)
if r do
e = errno()
diff --git a/lib/kc3/0.1/kc3.facts b/lib/kc3/0.1/kc3.facts
index 56a10da..5cffdb2 100644
--- a/lib/kc3/0.1/kc3.facts
+++ b/lib/kc3/0.1/kc3.facts
@@ -293,3 +293,12 @@ add {KC3, :symbol, KC3.to_lisp}
replace {KC3.to_lisp, :symbol_value, cfn Tag "to_lisp" (Tag, Result)}
add {KC3, :symbol, KC3.inspect}
replace {KC3.inspect, :symbol_value, cfn Str "inspect_tag" (Tag, Result)}
+add {KC3, :symbol, KC3.exit_cfn}
+replace {KC3.exit_cfn, :symbol_value, cfn Void "exit" (S32)}
+add {KC3, :symbol, KC3.exit}
+replace {KC3.exit, :symbol_value, fn (exit_code) {
+ exit_cfn((S32) exit_code)
+}}
+add {KC3, :symbol, KC3.fork}
+replace {KC3.fork, :symbol_value, cfn S32 "fork" ()}
+
diff --git a/libkc3/env.c b/libkc3/env.c
index 8d8a6c7..e720437 100644
--- a/libkc3/env.c
+++ b/libkc3/env.c
@@ -200,29 +200,18 @@ void env_clean_toplevel (s_env *env)
frame_delete_all(env->frame);
}
-s_tag * env_def (s_env *env, const s_call *call, s_tag *dest)
+bool env_def (s_env *env, const s_ident *ident, const s_tag *value)
{
- s_ident *ident;
- s_struct *s;
+ const s_struct *s;
+ s_tag tag;
s_tag tag_ident;
s_tag tag_module;
s_tag tag_symbol;
s_tag tag_symbol_value;
- s_tag tag_value;
(void) env;
assert(env);
- assert(call);
- assert(dest);
- if (call->ident.module != &g_sym_KC3 ||
- call->ident.sym != &g_sym_operator_equal ||
- call->arguments->tag.type != TAG_IDENT ||
- ! list_next(call->arguments) ||
- list_next(list_next(call->arguments))) {
- err_puts("env_def: invalid assignment: expected Ident = value");
- assert(! "env_def: invalid assignment: expected Ident = value");
- return NULL;
- }
- ident = &call->arguments->tag.data.ident;
+ assert(ident);
+ assert(value);
tag_ident.type = TAG_IDENT;
tag_ident.data.ident.sym = ident->sym;
if (ident->module)
@@ -233,48 +222,38 @@ s_tag * env_def (s_env *env, const s_call *call, s_tag *dest)
tag_init_sym(&tag_symbol, &g_sym_symbol);
if (! facts_add_tags(&env->facts, &tag_module, &tag_symbol,
&tag_ident))
- return NULL;
- if (! env_eval_tag(env, &list_next(call->arguments)->tag,
- &tag_value)) {
- err_puts("env_def: env_eval_tag");
- assert(! "env_def: env_eval_tag");
- return NULL;
- }
- if (tag_value.type == TAG_STRUCT &&
- (s = &tag_value.data.struct_) &&
+ return false;
+ if (value->type == TAG_STRUCT &&
+ (s = &value->data.struct_) &&
s->type->module == &g_sym_KC3_Operator) {
if (! env_defoperator(env, &tag_ident.data.ident.sym,
- struct_get_sym(&tag_value.data.struct_,
+ struct_get_sym(&value->data.struct_,
&g_sym_sym),
- struct_get_tag(&tag_value.data.struct_,
+ struct_get_tag(&value->data.struct_,
&g_sym_symbol_value),
- struct_get_u8(&tag_value.data.struct_,
+ struct_get_u8(&value->data.struct_,
&g_sym_operator_precedence),
- struct_get_sym(&tag_value.data.struct_,
+ struct_get_sym(&value->data.struct_,
&g_sym_operator_associativity),
- dest)) {
- tag_clean(&tag_value);
- return NULL;
+ &tag)) {
+ return false;
}
+ tag_clean(&tag);
}
else {
tag_init_sym(&tag_symbol_value, &g_sym_symbol_value);
if (! facts_replace_tags(&env->facts, &tag_ident, &tag_symbol_value,
- &tag_value)) {
- tag_clean(&tag_value);
- return NULL;
+ value)) {
+ return false;
}
if (tag_ident.data.ident.module == env->current_defmodule &&
tag_ident.data.ident.sym == &g_sym_clean) {
- if (! env_def_clean(env, env->current_defmodule, &tag_value)) {
- tag_clean(&tag_value);
- return NULL;
+ if (! env_def_clean(env, env->current_defmodule, value)) {
+ return false;
}
}
}
- tag_clean(&tag_value);
- tag_init_ident(dest, &tag_ident.data.ident);
- return dest;
+ return true;
}
const s_sym * env_def_clean (s_env *env, const s_sym *module,
@@ -2478,6 +2457,46 @@ s_env * env_init_toplevel (s_env *env)
return env;
}
+s_tag * env_kc3_def (s_env *env, const s_call *call, s_tag *dest)
+{
+ s_ident *ident;
+ s_tag tag_ident;
+ s_tag tag_value;
+ (void) env;
+ assert(env);
+ assert(call);
+ assert(dest);
+ if (call->ident.module != &g_sym_KC3 ||
+ call->ident.sym != &g_sym_operator_equal ||
+ call->arguments->tag.type != TAG_IDENT ||
+ ! list_next(call->arguments) ||
+ list_next(list_next(call->arguments))) {
+ err_puts("env_kc3_def: invalid assignment: expected Ident = value");
+ assert(! "env_kc3_def: invalid assignment: expected Ident = value");
+ return NULL;
+ }
+ ident = &call->arguments->tag.data.ident;
+ tag_ident.type = TAG_IDENT;
+ tag_ident.data.ident.sym = ident->sym;
+ if (ident->module)
+ tag_ident.data.ident.module = ident->module;
+ else
+ tag_ident.data.ident.module = env->current_defmodule;
+ if (! env_eval_tag(env, &list_next(call->arguments)->tag,
+ &tag_value)) {
+ err_puts("env_kc3_def: env_eval_tag");
+ assert(! "env_kc3_def: env_eval_tag");
+ return NULL;
+ }
+ if (! env_def(env, ident, &tag_value)) {
+ tag_clean(&tag_value);
+ return NULL;
+ }
+ tag_clean(&tag_value);
+ tag_init_ident(dest, &tag_ident.data.ident);
+ return dest;
+}
+
s_tag * env_let (s_env *env, const s_tag *tag, const s_block *block,
s_tag *dest)
{
diff --git a/libkc3/env.h b/libkc3/env.h
index cf3ca92..0915642 100644
--- a/libkc3/env.h
+++ b/libkc3/env.h
@@ -42,7 +42,8 @@ bool env_sym_search_modules (s_env *env,
const s_sym **dest);
/* Operators. */
-s_tag * env_def (s_env *env, const s_call *call, s_tag *dest);
+bool env_def (s_env *env, const s_ident *ident,
+ const s_tag *value);
const s_sym * env_def_clean (s_env *env, const s_sym *module,
const s_tag *tag_clean);
s_tag * env_defmodule (s_env *env, const s_sym * const *name,
@@ -76,6 +77,7 @@ s_tag * env_ident_get (s_env *env, const s_ident *ident,
bool * env_ident_is_special_operator (s_env *env,
const s_ident *ident,
bool *dest);
+s_tag * env_kc3_def (s_env *env, const s_call *call, s_tag *dest);
s_tag * env_let (s_env *env, const s_tag *tag,
const s_block *block, s_tag *dest);
bool env_load (s_env *env, const s_str *path);
diff --git a/libkc3/file.c b/libkc3/file.c
index f4bbb27..3a7af28 100644
--- a/libkc3/file.c
+++ b/libkc3/file.c
@@ -272,6 +272,26 @@ s32 * file_open_r (const s_str *path, s32 *dest)
return dest;
}
+s32 * file_open_w (const s_str *path, s32 *dest)
+{
+ sw e;
+ s32 fd;
+ mode_t mode = 0777;
+ assert(path);
+ assert(dest);
+ if ((fd = open(path->ptr.pchar, O_WRONLY | O_BINARY | O_CREAT,
+ mode)) < 0) {
+ e = errno;
+ err_write_1("file_open_w: ");
+ err_inspect_str(path);
+ err_write_1(": ");
+ err_puts(strerror(e));
+ return NULL;
+ }
+ *dest = fd;
+ return dest;
+}
+
s_str * file_pwd (s_str *dest)
{
char buf[PATH_MAX];
diff --git a/libkc3/file.h b/libkc3/file.h
index 2069e0d..7a68d58 100644
--- a/libkc3/file.h
+++ b/libkc3/file.h
@@ -39,5 +39,6 @@ s_file_stat * file_stat (const s_str *path, s_file_stat *dest);
s_str * file_pwd (s_str *dest);
FILE * file_open (const char *path, const char *mode);
s32 * file_open_r (const s_str *path, s32 *dest);
+s32 * file_open_w (const s_str *path, s32 *dest);
#endif /* LIBKC3_FILE_H */
diff --git a/libkc3/io.c b/libkc3/io.c
index aa6e31f..fc68519 100644
--- a/libkc3/io.c
+++ b/libkc3/io.c
@@ -115,6 +115,14 @@ sw err_write_str (const s_str *x)
return r;
}
+sw err_write_u8 (u8 x)
+{
+ sw r;
+ if ((r = buf_write_u8(&g_kc3_env.err, x)) > 0)
+ buf_flush(&g_kc3_env.err);
+ return r;
+}
+
sw io_flush (void)
{
return buf_flush(&g_kc3_env.out);
@@ -185,6 +193,14 @@ sw io_write_str (const s_str *x)
return r;
}
+sw io_write_u8 (u8 x)
+{
+ sw r;
+ if ((r = buf_write_u8(&g_kc3_env.out, x)) > 0)
+ buf_flush(&g_kc3_env.out);
+ return r;
+}
+
DEF_ERR_IO_INSPECT(array, const s_array *)
DEF_ERR_IO_INSPECT(call, const s_call *)
DEF_ERR_IO_INSPECT(character, const character *)
diff --git a/libkc3/io.h b/libkc3/io.h
index 8bbae76..d86cc67 100644
--- a/libkc3/io.h
+++ b/libkc3/io.h
@@ -32,6 +32,7 @@ sw err_puts (const char *x);
sw err_write (const void *x, uw len);
sw err_write_1 (const char *x);
sw err_write_str (const s_str *x);
+sw err_write_u8 (u8 x);
/* standard output */
sw io_flush (void);
@@ -40,6 +41,7 @@ sw io_puts (const char *x);
sw io_write (const void *x, uw len);
sw io_write_1 (const char *x);
sw io_write_str (const s_str *x);
+sw io_write_u8 (u8 x);
PROTOTYPES_ERR_IO_INSPECT(array, const s_array *);
PROTOTYPES_ERR_IO_INSPECT(bool, const bool *);
diff --git a/libkc3/kc3.c b/libkc3/kc3.c
index 9b6571c..996e0b8 100644
--- a/libkc3/kc3.c
+++ b/libkc3/kc3.c
@@ -92,7 +92,7 @@ void kc3_clean (s_env *env)
s_tag * kc3_def (const s_call *call, s_tag *dest)
{
- return env_def(&g_kc3_env, call, dest);
+ return env_kc3_def(&g_kc3_env, call, dest);
}
s_tag * kc3_defmodule (const s_sym **name, const s_block *block, s_tag *dest)
diff --git a/libkc3/kc3.h b/libkc3/kc3.h
index 5cf7858..893c332 100644
--- a/libkc3/kc3.h
+++ b/libkc3/kc3.h
@@ -21,6 +21,7 @@
#include "block.h"
#include "bool.h"
#include "buf.h"
+#include "buf_fd.h"
#include "buf_file.h"
#include "buf_inspect.h"
#include "buf_parse.h"
diff --git a/test/Makefile b/test/Makefile
index bfb4160..574e036 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -167,16 +167,16 @@ test_http_debug:
KC3S=${SRC_TOP}/kc3s/kc3s_debug time ./http_test
test_httpd:
- cd httpd && ../../httpd/.libs/kc3_httpd
+ cd httpd && ../../httpd/.libs/kc3_httpd -d
test_httpd_asan:
- cd httpd && ../../httpd/.libs/kc3_httpd_asan
+ cd httpd && ../../httpd/.libs/kc3_httpd_asan -d
test_httpd_cov:
- cd httpd && ../../httpd/.libs/kc3_httpd_cov
+ cd httpd && ../../httpd/.libs/kc3_httpd_cov -d
test_httpd_debug:
- cd httpd && ../../httpd/.libs/kc3_httpd_debug
+ cd httpd && ../../httpd/.libs/kc3_httpd_debug -d
test_ikc3:
IKC3=${SRC_TOP}/ikc3/ikc3 time ./ikc3_test
diff --git a/test/http/03_client_server.kc3 b/test/http/03_client_server.kc3
index bd0ef74..b123f88 100644
--- a/test/http/03_client_server.kc3
+++ b/test/http/03_client_server.kc3
@@ -1,7 +1,7 @@
-quote server = Socket.listen("localhost", "58000")
-server = Socket.listen("localhost", "58000")
-quote client = Socket.Buf.connect("localhost", "58000")
-client = Socket.Buf.connect("localhost", "58000")
+quote server = Socket.listen("localhost", "57000")
+server = Socket.listen("localhost", "57000")
+quote client = Socket.Buf.connect("localhost", "57000")
+client = Socket.Buf.connect("localhost", "57000")
quote server_client = Socket.Buf.accept(server)
server_client = Socket.Buf.accept(server)
quote Socket.Buf.close(server_client)
diff --git a/test/http/04_server_request.kc3 b/test/http/04_server_request.kc3
index 4c99fb4..beab795 100644
--- a/test/http/04_server_request.kc3
+++ b/test/http/04_server_request.kc3
@@ -1,7 +1,7 @@
-quote server = Socket.listen("localhost", "58000")
-server = Socket.listen("localhost", "58000")
-quote client = Socket.Buf.connect("localhost", "58000")
-client = Socket.Buf.connect("localhost", "58000")
+quote server = Socket.listen("localhost", "57000")
+server = Socket.listen("localhost", "57000")
+quote client = Socket.Buf.connect("localhost", "57000")
+client = Socket.Buf.connect("localhost", "57000")
quote server_client = Socket.accept(server)
server_client = Socket.Buf.accept(server)
quote Buf.write_str(client.buf_rw.w, "GET / HTTP/1.0\r\n\r\n")
diff --git a/test/httpd/log/.keep b/test/httpd/log/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/httpd/log/.keep