--- /dev/null
+/**/
+
+#include <assert.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <oop.h>
+#include <oop-read.h>
+
+#include "../layout/dlist.h"
+#include "hostside.h"
+
+oop_source *events;
+FILE *dump_stream= 0;
+
+typedef struct OutBuffer OutBuffer;
+struct OutBuffer {
+ OutBuffer *back, *next;
+ char *m;
+ int l;
+};
+typedef struct OutBufferChain OutBufferChain;
+struct OutBufferChain {
+ const char *what;
+ int fd;
+ int done_of_head;
+ struct { OutBuffer *head, *tail; } obs;
+};
+static OutBufferChain stdin_ochain= { "stdin", 0 };
+static OutBufferChain serial_ochain= { "serial", -1 };
+
+static void *ochain_writeable(oop_source *evts, int fd,
+ oop_event evt, void *ch_v) {
+ OutBufferChain *ch= ch_v;
+ OutBuffer *ob;
+ int r;
+
+ assert(fd == ch->fd);
+ assert(evt == OOP_WRITE);
+
+ for (;;) {
+ ob= ch->obs.head;
+ if (!ob) {
+ events->cancel_fd(events, fd, OOP_WRITE);
+ events->cancel_fd(events, fd, OOP_EXCEPTION);
+ return OOP_CONTINUE;
+ }
+ if (ch->done_of_head == ob->l) {
+ LIST_UNLINK(ch->obs, ob);
+ free(ob);
+ free(ob->m);
+ ch->done_of_head= 0;
+ continue;
+ }
+ r= write(ch->fd, ob->m + ch->done_of_head, ob->l - ch->done_of_head);
+ if (r==-1) {
+ if (errno==EINTR) continue;
+ if (errno==EWOULDBLOCK) return OOP_CONTINUE;
+ diee(ch->what);
+ }
+ assert(r>=0);
+ ch->done_of_head += r;
+ assert(ch->done_of_head <= ob->l);
+ }
+}
+
+static void *ochain_exception(oop_source *evts, int fd,
+ oop_event evt, void *ch_v) {
+ OutBufferChain *ch= ch_v;
+ die(ch->what);
+}
+
+static void ochain_addlink(OutBufferChain *ch, OutBuffer *ob) {
+ if (!ch->obs.head) {
+ events->on_fd(events, ch->fd, OOP_WRITE, ochain_writeable, ch);
+ events->on_fd(events, ch->fd, OOP_EXCEPTION, ochain_exception, ch);
+ }
+ LIST_LINK_TAIL(ch->obs, ob);
+}
+
+static void ovprintf(const char *fmt, va_list al)
+ __attribute__((format(printf,1,0)));
+static void ovprintf(const char *fmt, va_list al) {
+ OutBuffer *ob;
+
+ ob= malloc(sizeof(*ob)); if (!ob) diem();
+ ob->l= vasprintf(&ob->m, fmt, al); if (ob->l <= 0) diem();
+ ochain_addlink(&stdin_ochain, ob);
+}
+
+static void oprintf(const char *msg, ...) __attribute__((format(printf,1,2)));
+static void oprintf(const char *msg, ...) {
+ va_list al;
+ va_start(al,msg);
+ ovprintf(msg,al);
+ va_end(al);
+}
+
+static void badcmd(const char *how) {
+ oprintf("error %s\n",how);
+}
+
+static void cmd_noop(ParseState *ps, const CmdInfo *ci) {
+ oprintf("noop successful\n");
+}
+
+static const CmdInfo toplevel_cmds[]= {
+#if 0
+ { "nmra-x", cmd_nmra_x },
+ { "nmra-1", cmd_nmra_1 },
+ { "xmit-x", cmd_xmit_x },
+ { "xmit-1", cmd_xmit_1 },
+ { "pic", cmd_pic },
+ { "raw", cmd_raw },
+#endif
+ { "noop", cmd_noop },
+ { 0 }
+};
+
+static int ps_needword(ParseState *ps) {
+ const char *space;
+ if (!ps->remain) { badcmd("too few args"); return 0; }
+ space= strchr(ps->remain, ' ');
+ ps->thisword= ps->remain;
+ if (space) {
+ ps->lthisword= space - ps->thisword;
+ ps->remain= space + 1;
+ } else {
+ ps->lthisword= strlen(ps->remain);
+ ps->remain= 0;
+ }
+ return 1;
+}
+
+static const CmdInfo *ps_lookup(ParseState *ps, const CmdInfo *inf) {
+ for (;
+ inf->name;
+ inf++)
+ if (ps->lthisword == strlen(inf->name) &&
+ !memcmp(ps->thisword, inf->name, ps->lthisword))
+ return inf;
+ return 0;
+}
+
+static const CmdInfo *ps_needword_lookup(ParseState *ps, const CmdInfo *infs) {
+ if (!ps_needword(ps)) return 0;
+ return ps_lookup(ps,infs);
+}
+
+static void *stdin_iferr(oop_source *evts, oop_read *stdin_read,
+ oop_rd_event evt, const char *errmsg, int errnoval,
+ const char *data, size_t recsz, void *u0)
+ __attribute__((noreturn));
+static void *stdin_iferr(oop_source *evts, oop_read *stdin_read,
+ oop_rd_event evt, const char *errmsg, int errnoval,
+ const char *data, size_t recsz, void *u0) {
+ fprintf(stderr,"stdin %s\n",
+ oop_rd_errmsg(stdin_read, evt, errnoval, OOP_RD_STYLE_GETLINE));
+ exit(4);
+}
+
+static void *stdin_ifok(oop_source *evts, oop_read *stdin_read,
+ oop_rd_event evt, const char *errmsg, int errnoval,
+ const char *data, size_t recsz, void *u0) {
+ ParseState ps;
+ const CmdInfo *ci;
+
+ if (evt == OOP_RD_EOF)
+ exit(0);
+ if (evt != OOP_RD_OK)
+ stdin_iferr(evts,stdin_read,evt,errmsg,errnoval,data,recsz,u0);
+
+ ps.remain= data;
+ ci= ps_needword_lookup(&ps, toplevel_cmds);
+ if (!ci) { badcmd("unknown command"); return OOP_CONTINUE; }
+ ci->fn(&ps,ci);
+ return OOP_CONTINUE;
+}
+
+static void *serial_readable(oop_source *evts, int fd,
+ oop_event evt, void *u0) {
+ abort();
+}
+
+const char *device;
+
+int main(int argc, const char **argv) {
+ oop_read *stdin_source;
+ oop_source_sys *sys_events;
+ int r;
+
+ device= argv[1];
+ if (!device) device= "/dev/ttyS0";
+
+ serial_open(device);
+ r= oop_fd_nonblock(serial_fd, 1); if (r) diee("nonblock(serial_fd,1)");
+ serial_ochain.fd= serial_fd;
+
+ sys_events= oop_sys_new(); if (!sys_events) diee("oop_sys_new");
+ events= oop_sys_source(sys_events); assert(events);
+
+ stdin_source= oop_rd_new_fd(events, 0, 0,0);
+ if (!stdin_source) diee("oop_rd_new_fd(,0,,)");
+ r= oop_rd_read(stdin_source, OOP_RD_STYLE_GETLINE, 1024,
+ stdin_ifok, 0, stdin_iferr, 0);
+ if (r) diee("oop_rd_read(stdin_source,...)");
+
+ events->on_fd(events, serial_fd, OOP_READ, serial_readable, 0);
+ oop_sys_run(sys_events);
+ abort();
+}