default: abort();
}
}
+
+enum async_linebuf_result
+async_linebuf_read(struct pollfd *pfd, struct buffer_if *buf,
+ const char **emsg_out)
+{
+ int revents=pfd->revents;
+
+#define BAD(m) do{ *emsg_out=(m); return async_linebuf_broken; }while(0)
+#define BADBIT(b) \
+ if (!(revents & b)) ; else BAD(#b)
+ BADBIT(POLLERR);
+ BADBIT(POLLHUP);
+ BADBIT(POLLNVAL);
+#undef BADBIT
+
+ if (!(revents & POLLIN))
+ return async_linebuf_nothing;
+
+ /* Data structure: A line which has been returned to the user is
+ * stored in buf at base before start. But we retain the usual
+ * buffer meaning of len. So the buffer has valid but used data
+ * from base to start, and valid but waiting data from start to
+ * start+len. */
+
+ BUF_ASSERT_USED(buf);
+
+ /* firstly, eat any previous */
+ if (buf->start != buf->base) {
+ memmove(buf->base,buf->start,buf->size);
+ buf->start=buf->base;
+ }
+
+ uint8_t *searched=buf->base;
+ uint8_t *dataend=buf->base+buf->size;
+ for (;;) {
+ char *newline=memchr(searched,'\n',dataend-searched);
+ if (newline) {
+ *newline=0;
+ buf->start=newline+1;
+ buf->size=dataend-buf->start;
+ return async_linebuf_ok;
+ }
+ searched=dataend;
+ ssize_t space=(buf->start+buf->alloclen)-searched;
+ if (!space) BAD("input line too long");
+ ssize_t r=read(pfd->fd,searched,space);
+ if (r==0) {
+ *searched=0;
+ *emsg_out=buf->size?"no newline at eof":0;
+ buf->start=searched+1;
+ buf->size=0;
+ return async_linebuf_eof;
+ }
+ if (r<0) {
+ if (errno==EINTR)
+ continue;
+ if (iswouldblock(errno))
+ return async_linebuf_nothing;
+ BAD(strerror(errno));
+ }
+ if (memchr(searched,0,r)) BAD("nul in input data");
+ assert(r<=space);
+ dataend+=r;
+ buf->size+=r;
+ }
+
+#undef BAD
+}
void text2iaddr(const item_t *item, uint16_t port, union iaddr *ia,
const char *desc);
+
+/*----- line-buffered asynch input -----*/
+
+enum async_linebuf_result {
+ async_linebuf_nothing,
+ async_linebuf_ok,
+ async_linebuf_eof,
+ async_linebuf_broken,
+};
+
+enum async_linebuf_result
+async_linebuf_read(struct pollfd *pfd, struct buffer_if *buf,
+ const char **emsg_out);
+ /* Implements reading whole lines, asynchronously. Use like
+ * this:
+ * - set up the fd, which should be readable, O_NONBLOCK
+ * - set up and initialise buffer, which should be big enough
+ * for one lines plus its trailing newline, and be empty
+ * with start==base
+ * - in your beforepoll_fn, be interested in POLLIN
+ * - in your afterpoll_fn, repeatedly call this function
+ * until it doesn't return `nothing'
+ * - after you're done, simply close fd and free or reset buf
+ * State on exit depends on return value:
+ * nothing: don't touch buf, return from beforepoll
+ * ok: buf->base contains a input line
+ * as a nul-terminated string (\n replaced by \0);
+ * *emsg_out==0.
+ * eof: buf->base contains any partial
+ * (non-newline-terminated) line;
+ * *emsg_out!=0 iff there was such a line.
+ * broken: *emsg_out is the error message describing the problem.
+ * this may be stored in buf
+ * buf contents is undefined
+ * While using this function, do not look at buf->start or ->size.
+ */
+
+/*----- some handy macros -----*/
+
#define MINMAX(ae,be,op) ({ \
typeof((ae)) a=(ae); \
typeof((be)) b=(be); \