chiark / gitweb /
989f782af553abcfe9eb607b6b20083780e3b50e
[trains.git] / hostside / client.c
1 /**/
2
3 #include <stdarg.h>
4 #include <string.h>
5 #include <stdlib.h>
6 #include <errno.h>
7
8 #include "hostside.h"
9 #include "../layout/dlist.h"
10
11 struct ClientList clients;
12
13 void vbadcmd(ParseState *ps, const char *fmt, va_list al) {
14   oprintf(&ps->cl->ch,"error ");
15   ovprintf(&ps->cl->ch,fmt,al);
16   owrite(&ps->cl->ch,"\n",1);
17 }
18
19 const void *any_lookup(ParseState *ps, const void *inf, size_t sz) {
20   const char *tname;
21   
22   for (;
23        (tname= *(const char *const*)inf);
24        inf= (const char*)inf + sz)
25     if (!thiswordstrcmp(ps,tname))
26       return inf;
27   return 0;
28 }
29
30 const void *any_needword_lookup(ParseState *ps, const void *infs,
31                                 size_t sz, const char *what) {
32   const void *r;
33   if (!ps_needword(ps)) return 0;
34   r= any_lookup(ps,infs,sz);
35   if (!r) { badcmd(ps,"unknown %s",what); return 0; }
36   return r;
37 }
38
39 void ps_callword(ParseState *ps, const CmdInfo *infs, const char *what) {
40   const CmdInfo *ci;
41   ci= some_needword_lookup(ps,infs,what);
42   if (ci) ci->fn(ps,ci);
43 }
44
45 static void *client_iferr(oop_source *evts, oop_read *cl_read,
46                           oop_rd_event evt, const char *errmsg, int errnoval,
47                           const char *data, size_t recsz, void *cl_v) {
48   Client *cl= cl_v;
49
50   cl->ch.error(&cl->ch, "read",
51                oop_rd_errmsg(cl_read, evt,
52                              errnoval, OOP_RD_STYLE_GETLINE));
53   return OOP_CONTINUE;
54 }
55
56 static void *client_ifok(oop_source *evts, oop_read *cl_read,
57                          oop_rd_event evt, const char *errmsg, int errnoval,
58                          const char *data, size_t recsz, void *cl_v) {
59   Client *cl= cl_v;
60   ParseState ps;
61
62   if (evt == OOP_RD_EOF) {
63     cl->ch.error(&cl->ch,0,0);
64     return OOP_CONTINUE;
65   }
66   
67   if (evt != OOP_RD_OK)
68     return client_iferr(evts,cl_read,evt,errmsg,errnoval,data,recsz,cl_v);
69
70   ps.cl= cl;
71   ps.remain= data;
72   ps_callword(&ps, toplevel_cmds, "command");
73   return OOP_CONTINUE;
74 }
75
76 static void *client_exception(oop_source *evts, int fd,
77                               oop_event evt, void *cl_v) {
78   Client *cl= cl_v;
79   cl->ch.error(&cl->ch,"comms error","exception");
80   return OOP_CONTINUE;
81 }
82
83 static void new_client(int fd, OutBufferError error,
84                        char *desc, Selector default_selectors) {
85   Client *cl;
86   int r;
87   
88   cl= mmalloc(sizeof(*cl));
89
90   cl->sel= default_selectors;
91   cl->ch.desc= desc;
92   cl->ch.fd= fd;
93   cl->ch.error= error;
94   obc_init(&cl->ch);
95
96   events->on_fd(events, fd, OOP_EXCEPTION, client_exception, cl);
97
98   cl->rd= oop_rd_new_fd(events, fd, 0,0);
99   if (!cl->rd) diee("oop_rd_new_fd");
100   r= oop_rd_read(cl->rd, OOP_RD_STYLE_GETLINE, 1024,
101                  client_ifok, cl,
102                  client_iferr, cl);
103   if (r) diee("oop_rd_read");
104
105   LIST_LINK_TAIL(clients, cl);
106 }
107
108 static void stdin_error(OutBufferChain *ch, const char *e1, const char *e2) {
109   if (!e1)
110     exit(0);
111   fprintf(stderr,"stdin: %s: %s\n", e1, e2);
112   exit(12);  
113 }
114
115 void stdin_client(void) {
116   new_client(0, stdin_error, (char*)"stdin", sel_picio|sel_picioh);
117 }