diff --git a/src/control.c b/src/control.c index c72b38e..c94b85b 100644 --- a/src/control.c +++ b/src/control.c @@ -6,11 +6,14 @@ #include #include #include +#include +#include +#include +#include static int opensocket(const char *hostname, const char *port) { struct addrinfo *res = NULL, pref; - int ret; - int s; + int ret, s, val; pref.ai_flags = 0; pref.ai_family = PF_UNSPEC; @@ -35,9 +38,18 @@ static int opensocket(const char *hostname, const char *port) { if (0 != connect(s, res->ai_addr, res->ai_addrlen)) { fprintf(stderr, "Couldn't connect socket to '%s:%s': %s\n", hostname, port, strerror(errno)); freeaddrinfo(res); + close(s); return -1; } - + + val = 1; + if (0 != setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val))) { + fprintf(stderr, "Couldn't set socket option TCP_NODELAY: %s\n", strerror(errno)); + freeaddrinfo(res); + close(s); + return -1; + } + freeaddrinfo(res); return s; } @@ -82,10 +94,43 @@ void trial_wait_for_start(trial *t) { } } +static char buffer[16*1024]; + void trial_check_input(trial *t) { + ssize_t len; + struct pollfd p; + p.fd = t->socket; + p.events = POLLIN; + switch (poll(&p, 1, 0)) { + case -1: + switch (errno) { + case EAGAIN: + case EINTR: + return; + } + fprintf(stderr, "poll error: %s\n", strerror(errno)); + exit(127); + break; + case 0: + return; + } + len = read(t->socket, buffer, sizeof(buffer)); + if (len < 0) { + fprintf(stderr, "read error: %s\n", strerror(errno)); + exit(127); + } + g_string_append_len(t->parse_ctx->buffer, buffer, len); + control_parse(t); } void trial_wait_for_input(trial *t) { + ssize_t len = read(t->socket, buffer, sizeof(buffer)); + if (len < 0) { + fprintf(stderr, "read error: %s\n", strerror(errno)); + exit(127); + } + g_string_append_len(t->parse_ctx->buffer, buffer, len); + control_parse(t); } void trial_free(trial *t) { diff --git a/src/control.h b/src/control.h index 6b31c64..8d7fbc3 100644 --- a/src/control.h +++ b/src/control.h @@ -1,6 +1,8 @@ #ifndef _CONTROL_H #define _CONTROL_H +#include "config.h" + #include #include @@ -29,7 +31,7 @@ typedef struct trial trial; typedef unsigned int timestamp; - +#include "control_parser.h" struct object { object_t type; @@ -67,6 +69,7 @@ struct trial { /* internal */ int socket; + control_parser_ctx *parse_ctx; }; /* trial */ diff --git a/src/control_parser.h b/src/control_parser.h new file mode 100644 index 0000000..1abe808 --- /dev/null +++ b/src/control_parser.h @@ -0,0 +1,26 @@ +#ifndef _CONTROL_PARSER_H +#define _CONTROL_PARSER_H + +struct control_parser_ctx; +typedef struct control_parser_ctx control_parser_ctx; + +typedef enum { RUN_ERROR, RUN_DONE, RUN_GO_ON } run_t; + +#include "control.h" + +struct control_parser_ctx { + int cs; + GString *buffer; + gsize read; + size_t mark; + + GString *tmp; + double d; +}; + +void control_parser_new(trial *t); +void control_parser_reset(trial *t); +void control_parser_free(trial *t); +run_t control_parse(trial *t); + +#endif diff --git a/src/control_parser.rl b/src/control_parser.rl new file mode 100644 index 0000000..500f00a --- /dev/null +++ b/src/control_parser.rl @@ -0,0 +1,89 @@ + +#include "control_parser.h" + +#include +#include + +typedef control_parser_ctx context; + +static void extract(context *ctx, char *fpc) { + gsize len = (fpc - ctx->buffer->str) - ctx->mark; + g_string_truncate(ctx->tmp, 0); + g_string_append_len(ctx->tmp, ctx->buffer->str + ctx->mark, len); + ctx->read += len; +} + +%%{ + + machine control_parser; + variable cs ctx->cs; + + action done { fbreak; } + action mark { ctx->mark = fpc - ctx->buffer->str; } + action parsedouble { + extract(ctx, fpc); + ctx->d = strtod(ctx->tmp->str, NULL); + } + + sp = " "; + + double = ( (digit | '.')* ) >mark %parsedouble; + + init = "I" sp double sp double sp double sp double sp double sp double sp double sp double ";"; + + main := init @ done; +}%% + +%% write data; + +static int control_parser_has_error(context *ctx) { + return ctx->cs == control_parser_error; +} + +static int control_parser_is_finished(context *ctx) { + return ctx->cs >= control_parser_first_final; +} + +void control_parser_new(trial *t) { + context *ctx = t->parse_ctx = g_slice_new(context); + %% write init; + ctx->buffer = g_string_sized_new(0); + ctx->tmp = g_string_sized_new(0); +} + +void control_parser_reset(trial *t) { + context *ctx = t->parse_ctx; + %% write init; + g_string_truncate(ctx->tmp, 0); +} + +void control_parser_free(trial *t) { + g_string_free(t->parse_ctx->buffer, TRUE); + g_string_free(t->parse_ctx->tmp, TRUE); + g_slice_free(context, t->parse_ctx); +} + +run_t control_parse(trial *t) { + context *ctx = t->parse_ctx; + gsize wehave; + + if (0 < (wehave = ctx->buffer->len - ctx->read)) { + char *p, *pe; + + p = ctx->buffer->str + ctx->read; + pe = p + wehave; + + %% write exec; + + g_string_erase(ctx->buffer, 0, ctx->read); + ctx->mark -= ctx->read; + ctx->read = 0; + } + + if (control_parser_has_error(ctx)) { + fprintf(stderr, "Parse error\n"); + return RUN_ERROR; + } + if (control_parser_is_finished(ctx)) return RUN_DONE; + return RUN_GO_ON; +} diff --git a/src/wscript b/src/wscript index 0f2bcbc..6e85773 100644 --- a/src/wscript +++ b/src/wscript @@ -6,6 +6,7 @@ main_source = ''' main.c control.c + control_parser.rl ''' def build(bld): diff --git a/wscript b/wscript index af0823b..a40f3da 100644 --- a/wscript +++ b/wscript @@ -78,6 +78,8 @@ def configure(conf): incdir = conf.env['CPPPATH_glib'][0] conf.env['CPPPATH_glib'] += [ incdir+'/glib-2.0/', incdir + '/glib-2.0/include/' ] CHECK_INCLUDE_FILES(conf, "glib.h", "HAVE_GLIB_H", uselib = 'glib', use = ['glib'], mandatory = 1) + + conf.write_config_header('src/config.h') def build(bld):