chiark / gitweb /
only autoflush if the message ends with \n
[trains.git] / hostside / obc.c
1 /*
2  * daemons
3  * output buffer chains
4  */
5
6 #include <assert.h>
7 #include <stdlib.h>
8 #include <errno.h>
9 #include <stdarg.h>
10 #include <string.h>
11
12 #include "daemons.h"
13 #include "../layout/dlist.h"
14
15 struct OutBuffer {
16   OutBuffer *back, *next;
17   char *m;
18   int l;
19 };
20
21 int obc_tryflush(OutBufferChain *ch) {
22   OutBuffer *ob;
23   int r;
24   
25   for (;;) {
26     ob= ch->obs.head;
27     if (!ob) {
28       events->cancel_fd(events, ch->fd, OOP_WRITE);
29       return 0;
30     }
31     if (ch->done_of_head == ob->l) {
32       LIST_UNLINK(ch->obs, ob);
33       free(ob->m);
34       free(ob);
35       ch->done_of_head= 0;
36       continue;
37     }
38     r= write(ch->fd, ob->m + ch->done_of_head, ob->l - ch->done_of_head);
39     if (r==-1) {
40       if (errno==EINTR) continue;
41       if (errno==EWOULDBLOCK) return errno;
42       ch->error(ch,"write",strerror(errno));
43       return errno;
44     }
45     assert(r>=0);
46     ch->done_of_head += r;
47     ch->total -= r;
48     assert(ch->done_of_head <= ob->l);
49   }
50 }
51
52 static void *writeable(oop_source *evts, int fd,
53                        oop_event evt, void *ch_v) {
54   OutBufferChain *ch= ch_v;
55   assert(fd == ch->fd);
56   assert(evt == OOP_WRITE);
57   obc_tryflush(ch);
58   return OOP_CONTINUE;
59 }
60
61 static void addlink(OutBufferChain *ch, OutBuffer *ob) {
62   if (!ch->obs.head)
63     events->on_fd(events, ch->fd, OOP_WRITE, writeable, ch);
64   LIST_LINK_TAIL(ch->obs, ob);
65   ch->total += ob->l;
66   if (ob->l>0 && ob->m[ob->l-1]=='\n')
67     obc_tryflush(ch);
68   if (ch->total > ch->limit) {
69     char what[128];
70     snprintf(what,sizeof(what)-1,"`%.*s...'", ob->l,ob->m);
71     what[sizeof(what)-1]= 0;
72     ch->error(ch,"buffer limit exceeded",what);
73   }
74 }
75
76 void obc_init(OutBufferChain *ch) {
77   int r;
78   ch->done_of_head= 0;
79   ch->total= 0;
80   if (!ch->limit) ch->limit= 128*1024;
81   r= oop_fd_nonblock(ch->fd, 1);
82   if (r) diee("nonblock(OutBufferChain->fd,1)");
83   LIST_INIT(ch->obs);
84 }
85
86 void ovprintf(OutBufferChain *ch, const char *fmt, va_list al) {
87   OutBuffer *ob;
88
89   ob= mmalloc(sizeof(*ob));
90   ob->l= vasprintf(&ob->m, fmt, al);  if (ob->l <= 0) diem();
91   addlink(ch, ob);
92 }
93
94 void oprintf(OutBufferChain *ch, const char *msg, ...) {
95   va_list al;
96   va_start(al,msg);
97   ovprintf(ch,msg,al);
98   va_end(al);
99 }
100
101 void voerror(OutBufferChain *ch, const char *fmt, va_list al) {
102   oprintf(ch,"error ");
103   ovprintf(ch,fmt,al);
104   owrite(ch,"\n",1);
105 }
106
107 void owrite(OutBufferChain *ch, const char *data, int l) {
108   OutBuffer *ob;
109   ob= mmalloc(sizeof(*ob));
110   ob->l= l;
111   ob->m= mmalloc(l);
112   memcpy(ob->m, data, l);
113   addlink(ch,ob);
114 }