git clone https://orangeshoelaces.net/git/tttm.git
Author: Vasily Kolobkov on 07/16/2017
Committer: Vasily Kolobkov on 07/16/2017
Do away with stowing responses away to disk
Makefile | 14 +-
errors.c | 5 -
errors.h | 5 -
imap.c | 173 ++-
imap.h | 12 +-
laxsrc.c | 139 ---
laxsrc.h | 13 -
parser.c | 434 ++------
parser.h | 4 +-
pshades.c | 12 +-
tttm.c | 83 +-
11 files changed, 234 insertions(+), 660 deletions(-)
diff --git a/Makefile b/Makefile
index fbb224b..cc99401 100644
--- a/Makefile
+++ b/Makefile
@@ -4,10 +4,10 @@ PREFIX ?= /usr/local
BINDIR ?= ${PREFIX}/bin
MAN1DIR ?= ${PREFIX}/man/man1
-TTTMSRC = tttm.c errors.c laxsrc.c parser.c imap.c
+TTTMSRC = tttm.c errors.c parser.c imap.c
TTTMOBJ = ${TTTMSRC:.c=.o}
-PSHADESSRC = pshades.c errors.c laxsrc.c parser.c
+PSHADESSRC = pshades.c errors.c parser.c
PSHADESOBJ = ${PSHADESSRC:.c=.o}
.SUFFIXES: .c .o
@@ -36,14 +36,12 @@ uninstall:
errors.o: errors.c errors.h
-laxsrc.o: laxsrc.c errors.h laxsrc.h
+parser.o: parser.c errors.h parser.h
-parser.o: parser.c errors.h laxsrc.h parser.h
+imap.o: imap.c errors.h parser.h imap.h
-imap.o: imap.c errors.h laxsrc.h parser.h imap.h
+pshades.o: pshades.c errors.h parser.h
-pshades.o: pshades.c errors.h laxsrc.h parser.h
-
-tttm.o: tttm.c errors.h laxsrc.h parser.h imap.h
+tttm.o: tttm.c errors.h parser.h imap.h
.PHONY: all clean install uninstall
diff --git a/errors.c b/errors.c
index 27e56f9..20992f6 100644
--- a/errors.c
+++ b/errors.c
@@ -4,9 +4,6 @@ const char *errmsgs[] = {
[TE_PARSE] = "input not recognized",
[TE_EOF] = "unexpected eof",
[TE_TIMEOUT] = "source read timed out",
- [TE_BBOFLOW] = "source back buffer overflown",
- [TE_BUFOFLOW] = "response buffer overflown",
- [TE_CACHEOFLOW] = "cache overflown",
[TE_PTOFLOW] = "cannot fit parse tree within supplied space",
[TE_XLSTR] = "stalled upon a string longer than 2^32 - 1",
[TE_PROTO] = "IMAP protocol violated",
@@ -19,6 +16,4 @@ const char *errmsgs[] = {
[TE_NOMEM] = "not enough memory",
[TE_IN] = "input error",
[TE_OUT] = "output error",
- [TE_VM] = "cache vm mapping",
- [TE_CACHEIO] = "cache i/o",
};
diff --git a/errors.h b/errors.h
index 0da8aa2..98385ec 100644
--- a/errors.h
+++ b/errors.h
@@ -5,10 +5,7 @@ enum {
TE_EOF,
TE_TIMEOUT,
- TE_BBOFLOW,
- TE_BUFOFLOW,
- TE_CACHEOFLOW,
TE_PTOFLOW,
TE_XLSTR,
@@ -24,8 +21,6 @@ enum {
TE_NOMEM = TE_ERRNO,
TE_IN,
TE_OUT,
- TE_VM,
- TE_CACHEIO,
};
extern const char *errmsgs[];
diff --git a/imap.c b/imap.c
index 85794b8..3e0eb32 100644
--- a/imap.c
+++ b/imap.c
@@ -1,5 +1,6 @@
#include <errno.h>
#include <limits.h>
+#include <poll.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
@@ -10,7 +11,6 @@
#include <unistd.h>
#include "errors.h"
-#include "laxsrc.h"
#include "parser.h"
#include "imap.h"
@@ -32,7 +32,7 @@ static struct capmap {
struct respcard {
int sel;
- int (*handler)(struct imapctx *, int, void *);
+ int (*handler)(struct imapctx *, void *);
int req:1;
int met:1;
void *ctx;
@@ -41,30 +41,29 @@ struct respcard {
struct fetargs {
uint32_t lo;
uint32_t hi;
- int stor;
struct msgd *bag;
};
static int imap_cmd(struct imapctx *, int, const char *, struct respcard *,
- struct respcard *, int, ...);
+ struct respcard *, ...);
static int imap_confirm(struct imapctx *, const char *, struct respcard *,
va_list);
static int imap_cooloff(struct imapctx *);
-static int imap_matchres(struct imapctx *, int, int *);
-static int imap_matchresp(struct imapctx *, struct respcard *, int, int *);
+static int imap_ishot(struct imapctx *);
+static int imap_matchres(struct imapctx *, int *);
+static int imap_matchresp(struct imapctx *, struct respcard *, int *);
static int imap_parcaps(struct imapctx *, union parnode *);
static int imap_readln(struct imapctx *);
-static int imap_readlnc(struct imapctx *, int, int *);
static int imap_recvgreets(struct imapctx *);
static int imap_send(struct imapctx *, const char *, struct respcard *,
va_list);
-static int dig_bye(struct imapctx *, int, void *);
-static int dig_uxbye(struct imapctx *, int, void *);
-static int dig_caps(struct imapctx *, int, void *);
-static int dig_exists(struct imapctx *, int, void *);
-static int dig_expunge(struct imapctx *, int, void *);
-static int dig_fetch(struct imapctx *, int, void *);
+static int dig_bye(struct imapctx *, void *);
+static int dig_uxbye(struct imapctx *, void *);
+static int dig_caps(struct imapctx *, void *);
+static int dig_exists(struct imapctx *, void *);
+static int dig_expunge(struct imapctx *, void *);
+static int dig_fetch(struct imapctx *, void *);
static int state2res(union parnode *);
static int str2cap(struct capmap *, char *, size_t);
@@ -92,16 +91,13 @@ static struct respcard fetresp[] = { { IP_FETCH, dig_fetch }, { -1 } };
static struct respcard byeresp[] = { { IP_RESPBYE, dig_bye, 1 }, { -1 } };
int
-imap_init(struct imapctx *con, int in, int out, size_t buflen)
+imap_init(struct imapctx *con, int in, int out)
{
int e;
bzero(con, sizeof(*con));
- if (!(con->rep = malloc(buflen)))
- goto emem;
- con->replen = buflen;
con->state = IS_GREET;
- laxsrc_init(&con->in, in, buflen);
+ con->in = in;
con->out = out;
if ((e = imap_recvgreets(con)))
goto exit;
@@ -117,34 +113,31 @@ imap_init(struct imapctx *con, int in, int out, size_t buflen)
void
imap_free(struct imapctx *con)
{
- laxsrc_free(&con->in);
- free(con->rep);
+ free(con->resp);
}
int
imap_discocap(struct imapctx *con)
{
- return imap_cmd(con, -1, "%u CAPABILITY\r\n", capresp, unilat,
- -1, con->tag++);
+ return imap_cmd(con, -1, "%u CAPABILITY\r\n", capresp, unilat, con->tag++);
}
int
imap_login(struct imapctx *con, const char *user, const char *pass)
{
return imap_cmd(con, IS_AUTH, "%u LOGIN %LS %LS\r\n", 0, unilat,
- -1, con->tag++, user, pass);
+ con->tag++, user, pass);
}
int
imap_select(struct imapctx *con, const char *mb)
{
return imap_cmd(con, IS_SEL, "%u SELECT %LS\r\n", selresp, unilat,
- -1, con->tag++, mb);
+ con->tag++, mb);
}
int
-imap_fetch(struct imapctx *con, uint32_t lo, uint32_t hi, int stor,
- struct msgd *bag)
+imap_fetch(struct imapctx *con, uint32_t lo, uint32_t hi, struct msgd *bag)
{
int e;
struct msgd *m, *bend;
@@ -154,10 +147,10 @@ imap_fetch(struct imapctx *con, uint32_t lo, uint32_t hi, int stor,
for (m = bag; m < bend; m++) {
m->off = -1;
}
- args = (struct fetargs){ lo, hi, stor, bag };
+ args = (struct fetargs){ lo, hi, bag };
fetresp->ctx = &args;
- e = imap_cmd(con, -1, "%u FETCH %u:%u RFC822\r\n", fetresp,
- unisexp, stor, con->tag++, (unsigned)lo, (unsigned)hi);
+ e = imap_cmd(con, -1, "%u FETCH %u:%u RFC822\r\n", fetresp, unisexp,
+ con->tag++, (unsigned)lo, (unsigned)hi);
if (e)
goto exit;
for (m = bag; m < bend; m++) {
@@ -175,45 +168,50 @@ int
imap_delete(struct imapctx *con, uint32_t lo, uint32_t hi)
{
return imap_cmd(con, -1, "%u STORE %u:%u +FLAGS.SILENT (\\Deleted)\r\n",
- 0, unisexp, -1, con->tag++, (unsigned)lo, (unsigned)hi);
+ 0, unisexp, con->tag++, (unsigned)lo, (unsigned)hi);
}
int
imap_expunge(struct imapctx *con)
{
- return imap_cmd(con, -1, "%u EXPUNGE\r\n", 0, unilat, -1, con->tag++);
+ return imap_cmd(con, -1, "%u EXPUNGE\r\n", 0, unilat, con->tag++);
}
int
imap_nop(struct imapctx *con)
{
- return imap_cmd(con, -1, "%u NOOP\r\n", 0, unilat, -1, con->tag++);
+ return imap_cmd(con, -1, "%u NOOP\r\n", 0, unilat, con->tag++);
}
int
imap_close(struct imapctx *con)
{
- return imap_cmd(con, IS_AUTH, "%u CLOSE\r\n", 0, unilat,
- -1, con->tag++);
+ return imap_cmd(con, IS_AUTH, "%u CLOSE\r\n", 0, unilat, con->tag++);
}
int
imap_logout(struct imapctx *con)
{
return imap_cmd(con, IS_LOGOUT, "%u LOGOUT\r\n", byeresp, unilat,
- -1, con->tag++);
+ con->tag++);
}
int
imap_cmd(struct imapctx *con, int nstate, const char *cmd,
- struct respcard *cmdresp, struct respcard *unilat, int cache, ...)
+ struct respcard *cmdresp, struct respcard *unilat, ...)
{
- int e, b;
+ int e;
va_list ap;
union parnode *s;
struct respcard *c;
- va_start(ap, cache);
+ va_start(ap, unilat);
+ if (con->rpar > con->rcap / 2) {
+ memmove(con->resp, con->resp + con->rpar,
+ con->rlen - con->rpar);
+ con->rlen -= con->rpar;
+ con->rpar = 0;
+ }
if ((e = imap_cooloff(con))) {
goto exit;
}
@@ -223,16 +221,14 @@ imap_cmd(struct imapctx *con, int nstate, const char *cmd,
for (c = cmdresp; c && c->sel != -1; c++) {
c->met = 0;
}
- while (!(e = imap_readlnc(con, cache, &b))) {
- if (imap_matchres(con, b, &e)) {
+ while (!(e = imap_readln(con))) {
+ if (imap_matchres(con, &e)) {
break;
}
- if ((imap_matchresp(con, cmdresp, b, &e) ||
- imap_matchresp(con, unilat, b, &e)) && e) {
+ if ((imap_matchresp(con, cmdresp, &e) ||
+ imap_matchresp(con, unilat, &e)) && e) {
break;
}
- if (cache != -1 && lseek(cache, 0, SEEK_END) == -1)
- goto eio;
}
if (e) {
goto exit;
@@ -248,9 +244,6 @@ imap_cmd(struct imapctx *con, int nstate, const char *cmd,
exit:
va_end(ap);
return e;
- eio:
- e = TE_CACHEIO;
- goto exit;
eproto:
e = TE_PROTO;
goto exit;
@@ -267,10 +260,10 @@ imap_confirm(struct imapctx *con, const char *excerpt,
while (!(e = imap_readln(con))) {
if (isprod(con->par, IP_CONTREQ) ||
- imap_matchres(con, 1, &e)) {
+ imap_matchres(con, &e)) {
break;
}
- if (imap_matchresp(con, unilat, 1, &e) && e) {
+ if (imap_matchresp(con, unilat, &e) && e) {
break;
}
}
@@ -286,10 +279,10 @@ imap_cooloff(struct imapctx *con)
{
int e;
- while (!(e = laxsrc_ishot(&con->in))) {
+ while (!(e = imap_ishot(con))) {
if ((e = imap_readln(con)))
goto exit;
- if (imap_matchresp(con, unisexp, 1, &e) && e)
+ if (imap_matchresp(con, unisexp, &e) && e)
goto exit;
}
if (e == TE_TIMEOUT) {
@@ -300,13 +293,34 @@ imap_cooloff(struct imapctx *con)
}
int
-imap_matchres(struct imapctx *con, int buf, int *e)
+imap_ishot(struct imapctx *con)
+{
+ int e, ready;
+ struct pollfd pd;
+
+ e = 0;
+ if (con->rlen > con->rpar)
+ goto exit;
+
+ pd.fd = con->in;
+ pd.events = POLLIN | POLLHUP;
+ if ((ready = poll(&pd, 1, 0)) == -1) {
+ e = TE_IN;
+ } else if (ready == 0) {
+ e = TE_TIMEOUT;
+ }
+
+ exit:
+ return e;
+}
+
+int
+imap_matchres(struct imapctx *con, int *e)
{
union parnode *s, *c;
if ((s = par_sel(con->par, IP_TAGGEDRESP, IP_RESPSTATE, -1))) {
- c = par_seld(s, IP_RESPTXTCODE, IP_CAPDATA, -1);
- if (buf && c) {
+ if ((c = par_seld(s, IP_RESPTXTCODE, IP_CAPDATA, -1))) {
imap_parcaps(con, c);
}
*e = state2res(s);
@@ -315,7 +329,7 @@ imap_matchres(struct imapctx *con, int buf, int *e)
}
int
-imap_matchresp(struct imapctx *con, struct respcard *set, int buf, int *e)
+imap_matchresp(struct imapctx *con, struct respcard *set, int *e)
{
int match;
struct respcard *c;
@@ -324,7 +338,7 @@ imap_matchresp(struct imapctx *con, struct respcard *set, int buf, int *e)
for (c = set; c && c->sel != -1; c++) {
if (par_sel(con->par, IP_RESPDATA, c->sel, -1)) {
c->met = match = 1;
- *e = c->handler ? c->handler(con, buf, c->ctx) : 0;
+ *e = c->handler ? c->handler(con, c->ctx) : 0;
break;
}
}
@@ -342,7 +356,7 @@ imap_parcaps(struct imapctx *con, union parnode *n)
if (!isprod(n, IP_CAP))
continue;
atom = par_seld(n, IP_ATOM, -1);
- str = con->rep + (atom + 1)->str.off;
+ str = con->resp + (atom + 1)->str.off;
len = (atom + 1)->str.len;
if (islit(n + 1, IL_AUTHEQ)) {
con->caps |= str2cap(authcaps, str, len);
@@ -357,15 +371,8 @@ imap_parcaps(struct imapctx *con, union parnode *n)
int
imap_readln(struct imapctx *con)
{
- return par_readln(&con->in, con->rep, con->replen,
- -1, 0, con->par, LEN(con->par));
-}
-
-int
-imap_readlnc(struct imapctx *con, int cache, int *buf)
-{
- return par_readln(&con->in, con->rep, con->replen,
- cache, buf, con->par, LEN(con->par));
+ return par_parseln(con->in, &con->resp, &con->rcap, &con->rlen,
+ &con->rpar, con->par, LEN(con->par));
}
int
@@ -468,30 +475,30 @@ imap_send(struct imapctx *con, const char *cmd, struct respcard *unilat,
}
int
-dig_bye(struct imapctx *con, int buf, void *ctx)
+dig_bye(struct imapctx *con, void *ctx)
{
con->state = IS_LOGOUT;
return 0;
}
int
-dig_uxbye(struct imapctx *con, int buf, void *ctx)
+dig_uxbye(struct imapctx *con, void *ctx)
{
con->state = IS_LOGOUT;
return TE_BYE;
}
int
-dig_caps(struct imapctx *con, int buf, void *ctx)
+dig_caps(struct imapctx *con, void *ctx)
{
union parnode *c;
c = par_sel(con->par, IP_RESPDATA, IP_CAPDATA, -1);
- return (c && buf) ? imap_parcaps(con, c) : 0;
+ return c ? imap_parcaps(con, c) : 0;
}
int
-dig_exists(struct imapctx *con, int buf, void *ctx)
+dig_exists(struct imapctx *con, void *ctx)
{
union parnode *ex;
@@ -501,7 +508,7 @@ dig_exists(struct imapctx *con, int buf, void *ctx)
}
int
-dig_expunge(struct imapctx *con, int buf, void *ctx)
+dig_expunge(struct imapctx *con, void *ctx)
{
if (con->mb.exists > 0)
con->mb.exists--;
@@ -509,7 +516,7 @@ dig_expunge(struct imapctx *con, int buf, void *ctx)
}
int
-dig_fetch(struct imapctx *con, int buf, void *ctx)
+dig_fetch(struct imapctx *con, void *ctx)
{
int e;
struct fetargs *args;
@@ -534,30 +541,10 @@ dig_fetch(struct imapctx *con, int buf, void *ctx)
m = args->bag + (msn - args->lo);
m->off = nstr->str.off;
m->len = nstr->str.len;
- if (buf) {
- if ((m->off = lseek(args->stor, 0, SEEK_END)) == -1)
- goto eio;
- bcur = con->rep + nstr->str.off;
- blen = nstr->str.len;
- while (blen) {
- if ((n = write(args->stor, bcur, blen)) == 0) {
- goto eio;
- } else if (n == -1) {
- if (errno == EINTR || errno == EAGAIN)
- continue;
- else goto eio;
- }
- blen -= n;
- bcur += n;
- }
- }
if (nstr->type != PN_LSTR)
goto eproto;
exit:
return e;
- eio:
- e = TE_CACHEIO;
- goto exit;
enil:
e = TE_NIL;
goto exit;
diff --git a/imap.h b/imap.h
index 6c465d9..3cb8d91 100644
--- a/imap.h
+++ b/imap.h
@@ -4,12 +4,14 @@ enum { CAP_KNOWN = 1, CAP_IMAP4R1, CAP_NOLOGIN, CAP_AUTHPLAIN };
struct imapctx {
int state;
- struct laxsrc in;
+ int in;
int out;
unsigned int tag;
- char *rep;
- size_t replen;
+ char *resp;
+ size_t rlen;
+ size_t rcap;
+ size_t rpar;
union parnode par[1024];
int caps;
@@ -23,12 +25,12 @@ struct msgd {
size_t len;
};
-int imap_init(struct imapctx *, int, int, size_t);
+int imap_init(struct imapctx *, int, int);
void imap_free(struct imapctx *);
int imap_discocap(struct imapctx *);
int imap_login(struct imapctx *, const char *, const char *);
int imap_select(struct imapctx *, const char *);
-int imap_fetch(struct imapctx *, uint32_t, uint32_t, int, struct msgd *);
+int imap_fetch(struct imapctx *, uint32_t, uint32_t, struct msgd *);
int imap_delete(struct imapctx *, uint32_t, uint32_t);
int imap_expunge(struct imapctx *);
int imap_nop(struct imapctx *);
diff --git a/laxsrc.c b/laxsrc.c
deleted file mode 100644
index 9a34b6b..0000000
--- a/laxsrc.c
+++ /dev/null
@@ -1,139 +0,0 @@
-#include <errno.h>
-#include <poll.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include <unistd.h>
-
-#include "errors.h"
-#include "laxsrc.h"
-
-#define MIN(a, b) ((a) <= (b) ? (a) : (b))
-
-static int timeout = 2 * 60 * 1000;
-
-int
-laxsrc_init(struct laxsrc *s, int fd, size_t buflen)
-{
- int e;
-
- e = 0;
- bzero(s, sizeof(*s));
- s->fd = fd;
- if (!(s->buf = malloc(buflen)))
- goto emem;
- s->buflen = buflen;
- exit:
- return e;
- emem:
- e = TE_NOMEM;
- goto exit;
-}
-
-void
-laxsrc_free(struct laxsrc *s)
-{
- free(s->buf);
-}
-
-int
-laxsrc_ishot(struct laxsrc *s)
-{
- int e, ready;
- struct pollfd pd;
-
- e = 0;
- if (s->bufill > 0)
- goto exit;
- pd.fd = s->fd;
- pd.events = POLLIN | POLLHUP;
- if ((ready = poll(&pd, 1, 0)) == -1) {
- e = TE_IN;
- } else if (ready == 0) {
- e = TE_TIMEOUT;
- }
- exit:
- return e;
-}
-
-int
-laxsrc_read(struct laxsrc *s, char *dst, size_t lo, size_t hi, int *e)
-{
- size_t boff;
- size_t len;
- struct pollfd pd;
- int ready;
- ssize_t n;
-
- *e = TE_OK;
- len = 0;
- pd.fd = s->fd;
- pd.events = POLLIN | POLLHUP;
-
- if (s->bufill > 0) {
- boff = s->buflen - s->bufill;
- len = MIN(s->bufill, hi);
- memcpy(dst, s->buf + boff, len);
- s->bufill -= len;
- }
-
- if (s->eof) goto eof;
-
- while (len < lo) {
- ready = poll(&pd, 1, timeout);
-
- if (ready == -1) goto ein;
- if (ready == 0) goto eto;
-
- if (pd.revents & (POLLIN | POLLHUP)) {
- if ((n = read(pd.fd, dst + len, hi - len)) == 0) {
- goto eof;
- } else if (n == -1) {
- if (errno == EINTR || errno == EAGAIN)
- continue;
- else goto ein;
- }
- len += n;
- }
- }
-
- exit:
- return len;
- ein:
- *e = TE_IN;
- len = 0;
- goto exit;
- eto:
- *e = TE_TIMEOUT;
- len = 0;
- goto exit;
- eof:
- if (len < lo) {
- *e = TE_EOF;
- len = 0;
- } else {
- *e = TE_OK;
- }
- s->eof = 1;
- goto exit;
-}
-
-int
-laxsrc_putback(struct laxsrc *s, char *chunk, size_t len)
-{
- int e;
- size_t boff;
-
- e = TE_OK;
- if (s->bufill + len > s->buflen)
- goto eoflow;
- s->bufill += len;
- boff = s->buflen - s->bufill;
- memcpy(s->buf + boff, chunk, len);
- exit:
- return e;
- eoflow:
- e = TE_BBOFLOW;
- goto exit;
-}
diff --git a/laxsrc.h b/laxsrc.h
deleted file mode 100644
index 04f524b..0000000
--- a/laxsrc.h
+++ /dev/null
@@ -1,13 +0,0 @@
-struct laxsrc {
- int fd;
- int eof;
- char *buf;
- size_t buflen;
- size_t bufill;
-};
-
-int laxsrc_init(struct laxsrc *, int, size_t);
-void laxsrc_free(struct laxsrc *);
-int laxsrc_ishot(struct laxsrc *);
-int laxsrc_read(struct laxsrc *, char *, size_t, size_t, int *);
-int laxsrc_putback(struct laxsrc *, char *, size_t);
diff --git a/parser.c b/parser.c
index 51482c5..1d7733f 100644
--- a/parser.c
+++ b/parser.c
@@ -1,10 +1,11 @@
/*
Be warned! p_* functions bear unconventional call semantics
returning 1 on success and 0 otherwise. Specific error code
- or 0 is dispensed to the parse context.
+ is dispensed to the parse context.
*/
#include <errno.h>
+#include <poll.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdlib.h>
@@ -15,7 +16,6 @@
#include <sys/stat.h>
#include "errors.h"
-#include "laxsrc.h"
#include "parser.h"
#define LEN(x) (sizeof(x) / sizeof((x)[0]))
@@ -26,6 +26,9 @@
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" \
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+static int timeout = 2 * 60 * 1000;
+static size_t minstrcap = 1 << 13;
+
static struct literal {
char *srep;
size_t slen;
@@ -137,22 +140,16 @@ struct parcur {
};
struct parctx {
- struct parcur cur;
int e;
- char *wnd;
- size_t wndcap;
- size_t wndlee;
- size_t wndoff;
+ int src;
+ char *str;
+ size_t strcap;
+ size_t strlen;
+ size_t stroff;
+ struct parcur cur;
union parnode *pt;
union parnode *ptend;
size_t ptlen;
- char *buf;
- size_t buflen;
- int cache;
- off_t corig;
- struct laxsrc *in;
- size_t strlen;
- enum { SS_MEM, SS_CACHE } strstor;
};
typedef int parfn(struct parctx *);
@@ -161,17 +158,9 @@ static union parnode * par_vseld(union parnode *, va_list);
static int cmpchr(const void *, const void *);
static int contains(const char *, size_t, char);
-static void par_init(struct parctx *, struct laxsrc *,
- char *, size_t, int, union parnode *, size_t);
-static int par_free(struct parctx *);
-static int par_procure(struct parctx *, size_t, size_t);
-static int par_movewnd(struct parctx *, size_t);
-static int par_primecache(struct parctx *);
-static void par_offsetpt(union parnode *, union parnode *, off_t);
-static int par_prycache(struct parctx *, size_t);
-static int par_readnup(struct parctx *, size_t);
-static int par_peek(struct parctx *, size_t, char *);
-static int par_backup(struct parctx *);
+static void par_init(struct parctx *, int,
+ char *, size_t, size_t, size_t, union parnode *, size_t);
+static int par_fillstr(struct parctx *, size_t);
static int p_chk(struct parctx *, struct parcur *);
static int p_insint(struct parctx *, int, size_t);
@@ -311,18 +300,18 @@ static int p_opar(struct parctx *);
static int p_sp(struct parctx *);
int
-par_readln(struct laxsrc *in, char *buf, size_t buflen, int cache,
- int *bufd, union parnode *pt, size_t ptlen)
+par_parseln(int src, char **str, size_t *strcap, size_t *strlen, size_t *stroff,
+ union parnode *pt, size_t ptlen)
{
- int e;
struct parctx p;
- par_init(&p, in, buf, buflen, cache, pt, ptlen);
+ par_init(&p, src, *str, *strcap, *strlen, *stroff, pt, ptlen);
p_respln(&p);
- if (bufd)
- *bufd = p.strstor == SS_MEM;
- e = par_free(&p);
- return e ? e : p.e;
+ *str = p.str;
+ *strcap = p.strcap;
+ *strlen = p.strlen;
+ *stroff = p.cur.off;
+ return p.e;
}
union parnode *
@@ -402,267 +391,82 @@ contains(const char *s, size_t slen, char c)
}
void
-par_init(struct parctx *p, struct laxsrc *in, char *buf, size_t buflen,
- int cache, union parnode *pt, size_t ptlen)
+par_init(struct parctx *p, int src, char *str, size_t strcap, size_t strlen,
+ size_t stroff, union parnode *pt, size_t ptlen)
{
bzero(p, sizeof(*p));
+ p->src = src;
+ p->str = str;
+ p->strcap = strcap;
+ p->strlen = strlen;
+ p->stroff = stroff;
+ p->cur.off = stroff;
p->cur.pt = pt;
- p->wnd = buf;
- p->wndcap = buflen;
p->pt = pt;
p->ptend = pt + ptlen;
p->ptlen = ptlen;
- p->buf = buf;
- p->buflen = buflen;
- p->cache = cache;
- p->in = in;
- p->strstor = SS_MEM;
-}
-
-int
-par_free(struct parctx *p)
-{
- int e;
-
- if (e = par_backup(p))
- goto exit;
- if (p->strstor == SS_CACHE && munmap(p->wnd, p->wndcap) == -1)
- goto evm;
- exit:
- return e;
- evm:
- e = TE_VM;
- goto exit;
}
-/*
- Prepare window for accessing string symbols with indexes [off..off + len).
- When reading from source to fulfill the request, no less than the needed
- amount and anything over that that fits the window is transfered.
-
- precond: len <= p->wndcap
-*/
int
-par_procure(struct parctx *p, size_t off, size_t len)
+par_fillstr(struct parctx *p, size_t len)
{
- int e;
- size_t send, wndshort;
-
- e = TE_OK;
- send = off + len;
+ char *newstr;
+ struct pollfd pd;
+ int ready;
+ ssize_t n;
- if (off >= p->wndoff && send <= p->wndoff + p->wndlee)
+ if (len <= p->strlen) {
+ p->e = TE_OK;
goto exit;
-
- while (send > p->strlen) {
- if ((p->wndlee == p->wndcap) && (e = par_movewnd(p, p->strlen)))
- goto exit;
- wndshort = MIN(send - p->strlen, p->wndcap - p->wndlee);
- if ((e = par_readnup(p, wndshort)))
- goto exit;
- }
-
- if (off < p->wndoff || send > p->wndoff + p->wndcap)
- e = par_movewnd(p, off);
- exit:
- return e;
-}
-
-int
-par_movewnd(struct parctx *p, size_t off)
-{
- int e;
- char *ci;
-
- e = TE_OK;
- if (p->strstor == SS_MEM && off + p->wndcap <= p->buflen) {
- p->wnd = p->buf + off;
- goto finwnd;
}
-
- if (p->cache == -1)
- goto ebufoflow;
-
- if (p->strstor == SS_MEM) {
- if ((e = par_primecache(p)))
- goto exit;
- } else {
- if (munmap(p->wnd, p->wndcap) == -1)
- goto evm;
- }
- if ((e = par_prycache(p, off + p->wndcap)))
- goto exit;
-
- ci = mmap(0, p->wndcap, PROT_READ | PROT_WRITE,
- MAP_SHARED, p->cache, p->corig + off);
- if (ci == MAP_FAILED)
- goto evm;
-
- p->wnd = ci;
- goto finwnd;
-
- finwnd:
- p->wndlee = MIN(p->wndcap, p->strlen - off);
- p->wndoff = off;
- exit:
- return e;
- ebufoflow:
- e = TE_BUFOFLOW;
- goto exit;
- evm:
- e = TE_VM;
- goto exit;
-}
-
-int
-par_primecache(struct parctx *p)
-{
- int e;
- off_t off;
- void *ci;
-
- e = TE_OK;
- if ((off = lseek(p->cache, 0, SEEK_CUR)) == -1)
- goto eio;
-
- p->corig = off;
- if ((e = par_prycache(p, p->buflen)))
- goto exit;
-
- p->strstor = SS_CACHE;
- if (p->buflen == 0)
- goto exit;
-
- ci = mmap(0, p->buflen, PROT_WRITE, MAP_SHARED, p->cache, p->corig);
- if (ci == MAP_FAILED)
- goto evm;
-
- memcpy(ci, p->buf, p->buflen);
- if (munmap(ci, p->buflen) == -1)
- goto evm;
-
- par_offsetpt(p->pt, p->ptend, off);
-
- exit:
- return e;
- eio:
- e = TE_CACHEIO;
- goto exit;
- evm:
- e = TE_VM;
- goto exit;
-}
-
-void
-par_offsetpt(union parnode *cur, union parnode *end, off_t off)
-{
- union parnode *iend;
-
- while (cur < end) {
- switch (cur->type) {
- case PN_INTER:
- iend = cur + cur->inter.len + 1;
- par_offsetpt(cur + 1, MIN(iend, end), off);
- cur = iend;
- break;
- case PN_STR:
- case PN_QSTR:
- case PN_LSTR:
- cur->str.off += off;
- /* fall through */
- default:
- cur++;
+ if (len > p->strcap) {
+ p->strcap = MAX(minstrcap, p->strcap);
+ do {
+ p->strcap *= 2;
+ } while (len > p->strcap);
+ newstr = realloc(p->str, p->strcap);
+ if (newstr == 0) {
+ goto emem;
}
+ p->str = newstr;
}
-}
-int
-par_prycache(struct parctx *p, size_t len)
-{
- int e;
- size_t flen;
- ssize_t n;
- struct stat cs;
+ pd.fd = p->src;
+ pd.events = POLLIN | POLLHUP;
- e = TE_OK;
- if (fstat(p->cache, &cs) == -1)
- goto eio;
+ while (len > p->strlen) {
+ ready = poll(&pd, 1, timeout);
- flen = len + p->corig;
- if (flen < MAX(len, p->corig) || flen > INT64_MAX)
- goto eover;
+ if (ready == -1) goto ein;
+ if (ready == 0) goto eto;
- if (cs.st_size < flen) {
- while ((n = pwrite(p->cache, "", 1, flen - 1)) <= 0) {
- if (n == -1 && (errno == EINTR || errno == EAGAIN))
- continue;
- else goto eio;
+ if (pd.revents & (POLLIN | POLLHUP)) {
+ n = read(pd.fd, p->str + p->strlen, p->strcap - p->strlen);
+ if (n == 0) {
+ goto eof;
+ } else if (n == -1) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ else goto ein;
+ }
+ p->strlen += n;
}
}
exit:
- return e;
- eio:
- e = TE_CACHEIO;
+ return p->e;
+ emem:
+ p->e = TE_NOMEM;
goto exit;
- eover:
- e = TE_CACHEOFLOW;
+ ein:
+ p->e = TE_IN;
+ goto exit;
+ eto:
+ p->e = TE_TIMEOUT;
+ goto exit;
+ eof:
+ p->e = TE_EOF;
goto exit;
-}
-
-int
-par_readnup(struct parctx *p, size_t n)
-{
- int e;
- size_t hi, nr;
-
- hi = p->wndcap - p->wndlee;
- nr = laxsrc_read(p->in, p->wnd + p->wndlee, n, hi, &e);
- if (e == TE_OK && nr > 0) {
- p->wndlee += nr;
- p->strlen += nr;
- }
-
- return e;
-}
-
-int
-par_peek(struct parctx *p, size_t off, char *c)
-{
- int e;
- size_t wndlag;
-
- if ((e = par_procure(p, off, 1)))
- goto exit;
-
- wndlag = off - p->wndoff;
- *c = p->wnd[wndlag];
- exit:
- return e;
-}
-
-int
-par_backup(struct parctx *p)
-{
- int e;
- size_t w, shed, nwnd;
- size_t off, wndlag;
-
- e = TE_OK;
- shed = p->cur.off / p->wndcap + 1;
- nwnd = p->strlen / p->wndcap + (p->strlen % p->wndcap > 0);
- off = (nwnd - 1) * p->wndcap;
-
- for (w = nwnd; w >= shed; w--, off -= p->wndcap) {
- if ((e = par_movewnd(p, off)))
- break;
-
- wndlag = MAX(off, p->cur.off) - p->wndoff;
- e = laxsrc_putback(p->in, p->wnd + wndlag, p->wndlee - wndlag);
- if (e)
- break;
- }
- return e;
}
/*
@@ -813,19 +617,16 @@ p_repchr(struct parctx *p, const char *except, size_t elen, int strtype)
{
size_t pr;
char *prp;
- size_t wndlag;
- size_t leeway;
size_t len;
if (p->e > TE_PARSE)
goto exit;
+ p->e = TE_OK;
pr = p->cur.off;
- while ((p->e = par_procure(p, pr, 1)) == TE_OK) {
- wndlag = pr - p->wndoff;
- leeway = p->wndoff + p->wndlee;
- for (prp = p->wnd + wndlag; pr < leeway; pr++, prp++) {
+ while (par_fillstr(p, pr + 1) == TE_OK) {
+ for (prp = p->str + pr; pr < p->strlen; ++pr, ++prp) {
if (contains(except, elen, *prp))
goto stop;
}
@@ -1193,8 +994,6 @@ p_dig(struct parctx *p, size_t count)
{
size_t pr;
char *prp;
- size_t wndlag;
- size_t leeway;
size_t len;
uint32_t n, prev;
size_t d;
@@ -1202,19 +1001,17 @@ p_dig(struct parctx *p, size_t count)
if (p->e > TE_PARSE)
goto exit;
+ p->e = TE_OK;
pr = p->cur.off;
n = prev = 0;
d = count == SIZE_MAX ? 0 : 1;
- while ((p->e = par_procure(p, pr, 1)) == TE_OK) {
- wndlag = pr - p->wndoff;
- leeway = p->wndoff + p->wndlee;
-
- for (prp = p->wnd + wndlag; pr < leeway; pr++, prp++) {
+ while (par_fillstr(p, pr + 1) == TE_OK) {
+ for (prp = p->str + pr; pr < p->strlen; ++pr, ++prp) {
if (count == 0 || *prp < '0' || *prp > '9')
goto stop;
prev = n;
- n = UINT32_MAX & (10 * n + (*prp - 48));
+ n = UINT32_MAX & (10 * n + (*prp - '0'));
if (prev > n) {
p->e = TE_PARSE;
goto stop;
@@ -1335,19 +1132,16 @@ p_genctext(struct parctx *p)
{
size_t pr;
char *prp;
- size_t wndlag;
- size_t leeway;
size_t len;
if (p->e > TE_PARSE)
goto exit;
+ p->e = TE_OK;
pr = p->cur.off;
- while ((p->e = par_procure(p, pr, 1)) == TE_OK) {
- wndlag = pr - p->wndoff;
- leeway = p->wndoff + p->wndlee;
- for (prp = p->wnd + wndlag; pr < leeway; pr++, prp++) {
+ while (par_fillstr(p, pr + 1) == TE_OK) {
+ for (prp = p->str + pr; pr < p->strlen; ++pr, ++prp) {
if (*prp == 0 || *prp > '\x7f' || *prp == ']' ||
*prp == '\r' || *prp == '\n')
goto stop;
@@ -1393,26 +1187,17 @@ int
p_lit(struct parctx *p, int val)
{
struct literal *lit;
- size_t match, chunk, wndlag;
if (p->e > TE_PARSE)
goto exit;
+ p->e = TE_OK;
lit = literals + val;
- match = 0;
-
- while (match < lit->slen) {
- if ((p->e = par_procure(p, p->cur.off + match, 1)))
- goto exit;
- wndlag = p->cur.off + match - p->wndoff;
- chunk = MIN(lit->slen - match, p->wndlee - wndlag);
- if (strncasecmp(p->wnd + wndlag, lit->srep + match,
- chunk) == 0) {
- match += chunk;
- } else {
- goto eparse;
- }
- }
+
+ if (par_fillstr(p, p->cur.off + lit->slen) != TE_OK)
+ goto exit;
+ if (strncasecmp(p->str + p->cur.off, lit->srep, lit->slen) != 0)
+ goto eparse;
if (p_inslit(p, val))
p->cur.off += lit->slen;
@@ -1437,13 +1222,14 @@ p_lstr(struct parctx *p)
if (!prefix)
goto exit;
+ p->e = TE_OK;
len = n.pt->num.val;
p->cur.pt = b.pt;
if (len > UINT32_MAX) goto exl;
- if (len > 0 && (p->e = par_procure(p, p->cur.off + len - 1, 1)))
+ if (par_fillstr(p, p->cur.off + len) != TE_OK)
goto exit;
- if (!p_insstr(p, PN_LSTR, p->corig + p->cur.off, len))
+ if (!p_insstr(p, PN_LSTR, p->cur.off, len))
goto exit;
p->cur.off += len;
@@ -1743,18 +1529,17 @@ p_num(struct parctx *p)
int
p_nznum(struct parctx *p)
{
- size_t wndlag;
const char *prp;
if (p->e > TE_PARSE)
goto exit;
- if ((p->e = par_procure(p, p->cur.off, 1)))
- goto exit;
+ p->e = TE_OK;
- wndlag = p->cur.off - p->wndoff;
- prp = p->wnd + wndlag;
+ if (par_fillstr(p, p->cur.off + 1) != TE_OK)
+ goto exit;
+ prp = p->str + p->cur.off;
if (*prp < '1' || *prp > '9')
goto eparse;
@@ -1792,15 +1577,19 @@ p_qchar(struct parctx *p)
if (p->e > TE_PARSE)
goto exit;
- if ((p->e = par_peek(p, p->cur.off, &x)))
+ p->e = TE_OK;
+
+ if (par_fillstr(p, p->cur.off + 1) != TE_OK)
goto exit;
+ x = p->str[p->cur.off];
if (x >= '\1' && x <= '\x7f' && x != '\r' &&
x != '\n' && x != '"' && x != '\\') {
len = 1;
goto ins;
}
- if ((p->e = par_peek(p, p->cur.off + 1, &y)))
+ if (par_fillstr(p, p->cur.off + 2) != TE_OK)
goto exit;
+ y = p->str[p->cur.off + 1];
if (x == '\\' && (y == '"' || y == '\\')) {
len = 2;
goto ins;
@@ -1824,22 +1613,18 @@ p_qchars(struct parctx *p)
{
size_t pr;
char *prp;
- size_t wndlag;
- size_t leeway;
size_t len;
int esc;
if (p->e > TE_PARSE)
goto exit;
+ p->e = TE_OK;
pr = p->cur.off;
esc = 0;
- while ((p->e = par_procure(p, pr, 1)) == TE_OK) {
- wndlag = pr - p->wndoff;
- leeway = p->wndoff + p->wndlee;
-
- for (prp = p->wnd + wndlag; pr < leeway; pr++, prp++) {
+ while (par_fillstr(p, pr + 1) == TE_OK) {
+ for (prp = p->str + pr; pr < p->strlen; ++pr, ++prp) {
if (esc) {
if (*prp == '"' || *prp == '\\') {
esc = 0;
@@ -2041,19 +1826,16 @@ p_text(struct parctx *p)
{
size_t pr;
char *prp;
- size_t wndlag;
- size_t leeway;
size_t len;
if (p->e > TE_PARSE)
goto exit;
+ p->e = TE_OK;
pr = p->cur.off;
- while ((p->e = par_procure(p, pr, 1)) == TE_OK) {
- wndlag = pr - p->wndoff;
- leeway = p->wndoff + p->wndlee;
- for (prp = p->wnd + wndlag; pr < leeway; pr++, prp++) {
+ while (par_fillstr(p, pr + 1) == TE_OK) {
+ for (prp = p->str + pr; pr < p->strlen; ++pr, ++prp) {
if (*prp == 0 || *prp > '\x7f' ||
*prp == '\r' || *prp == '\n')
goto stop;
diff --git a/parser.h b/parser.h
index 061d427..d897d94 100644
--- a/parser.h
+++ b/parser.h
@@ -56,9 +56,7 @@ union parnode {
} str;
};
-struct laxsrc;
-
-int par_readln(struct laxsrc *, char *, size_t, int, int *,
+int par_parseln(int, char **, size_t *, size_t *, size_t *,
union parnode *, size_t);
union parnode *par_nn(union parnode *);
union parnode *par_sel(union parnode *, ...);
diff --git a/pshades.c b/pshades.c
index 97b66ca..e6c1645 100644
--- a/pshades.c
+++ b/pshades.c
@@ -4,10 +4,10 @@
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
+#include <stdlib.h>
#include <unistd.h>
#include "errors.h"
-#include "laxsrc.h"
#include "parser.h"
#define LEN(a) (sizeof(a) / sizeof(a)[0])
@@ -51,16 +51,16 @@ int
main(int argc, char **argv)
{
int e;
- struct laxsrc in;
- char ln[1024];
+ char *ln;
+ size_t cap, len, parsed;
union parnode pt[1024];
- laxsrc_init(&in, STDIN_FILENO, LEN(ln));
- if ((e = par_readln(&in, ln, LEN(ln), -1, 0, pt, LEN(pt))))
+ cap = len = parsed = 0;
+ if ((e = par_parseln(STDIN_FILENO, &ln, &cap, &len, &parsed, pt, LEN(pt))))
errx(1, "error parsing input: %s", errmsgs[e]);
ptprint(pt, ln, 0);
- laxsrc_free(&in);
+ free(ln);
return 0;
}
diff --git a/tttm.c b/tttm.c
index c876fa5..74ddc80 100644
--- a/tttm.c
+++ b/tttm.c
@@ -10,7 +10,6 @@
#include <sys/stat.h>
#include "errors.h"
-#include "laxsrc.h"
#include "parser.h"
#include "imap.h"
@@ -22,7 +21,7 @@
/* Retry fetching mail at most this many times after getting a nil fetch. */
#define MAXREFC 2
-static int pipemsg(struct msgd *, int, char **);
+static int pipemsg(struct msgd *, char *, char **);
static int sink_init(char **, pid_t *, int *);
static int sink_free(pid_t, int);
static void fin(struct imapctx *, int, const char *);
@@ -30,8 +29,6 @@ static void terr(int, const char *);
static void twarn(int, const char *);
static void usage(void);
-static size_t page;
-static char stortpl[] = "/tmp/tttm.XXXXXX";
static char *userkey = "IMAP_USER";
static char *passkey = "IMAP_PASS";
@@ -41,7 +38,6 @@ main(int argc, char **argv)
int e;
struct imapctx con;
char *user, *pass;
- int stor;
int refetchc, batchsz, mpiped;
struct msgd bag[BATCHSZ], *m, *bend;
long sysvar;
@@ -50,16 +46,7 @@ main(int argc, char **argv)
usage();
}
- if ((sysvar = sysconf(_SC_PAGESIZE)) == -1)
- err(1, "failed to find out page size");
- page = sysvar;
-
- if ((stor = mkstemp(stortpl)) == -1)
- err(1, "failed to set up temporary storage");
- if (unlink(stortpl) == -1)
- warn("failed to unlink temporary storage");
-
- if ((e = imap_init(&con, 0, 1, page))) {
+ if ((e = imap_init(&con, STDIN_FILENO, STDOUT_FILENO))) {
terr(e, "failed to initialize session");
}
if (con.state == IS_AUTH) {
@@ -97,13 +84,9 @@ main(int argc, char **argv)
}
refetchc = 0;
while (con.mb.exists > 0) {
- if (lseek(stor, 0, SEEK_SET) == -1) {
- warn("failed to rewind temporary storage");
- goto logout;
- }
batchsz = MIN(BATCHSZ, con.mb.exists);
bend = bag + batchsz;
- e = imap_fetch(&con, 1, batchsz, stor, bag);
+ e = imap_fetch(&con, 1, batchsz, bag);
if (e == TE_NIL && refetchc < MAXREFC) {
if ((e = imap_nop(&con))) {
fin(&con, e, "failed to receive updates");
@@ -115,7 +98,7 @@ main(int argc, char **argv)
}
refetchc = 0;
for (m = bag; m < bend; m++) {
- if (pipemsg(m, stor, argv + 1) == -1)
+ if (pipemsg(m, con.resp, argv + 1) == -1)
break;
}
mpiped = m - bag;
@@ -145,20 +128,20 @@ main(int argc, char **argv)
}
int
-pipemsg(struct msgd *m, int stor, char **argv)
+pipemsg(struct msgd *m, char *stor, char **argv)
{
int e, sin;
void (*origpipe)(int);
- size_t scur, send, wlen, wlee;
- char *wnd, *wcur;
+ char *cur;
+ size_t len;
pid_t sid;
ssize_t n;
e = -1;
- if (lseek(stor, m->off, SEEK_SET) == -1) {
- warn("failed to seek in temporary file");
- goto exit;
- }
+ cur = stor + m->off;
+ len = m->len;
+ n = -2;
+
if ((origpipe = signal(SIGPIPE, SIG_IGN)) == SIG_ERR) {
warn("failed to install SIGPIPE handler");
goto exit;
@@ -166,37 +149,23 @@ pipemsg(struct msgd *m, int stor, char **argv)
if (sink_init(argv, &sid, &sin) == -1)
goto csig;
- for (scur = m->off, send = scur + m->len; scur < send; scur += wlen) {
- wlen = MIN(send - scur, page);
- wnd = mmap(0, wlen, PROT_READ, MAP_PRIVATE, stor, scur);
- if (wnd == MAP_FAILED) {
- warn("failed to map temporary file");
- goto csink;
- }
- wcur = wnd;
- wlee = wlen;
- while (wlee) {
- if ((n = write(sin, wcur, wlee)) == 0) {
- break;
- } else if (n == -1) {
- if (errno == EINTR || errno == EAGAIN)
- continue;
- else break;
- }
- wcur += n;
- wlee -= n;
- }
- if (munmap(wnd, wlen) == -1) {
- warn("failed to unmap temporary file");
- goto csink;
- }
- if (n == 0) {
- warn("sink shut down unexpectedly");
- goto csink;
+ while (len > 0) {
+ if ((n = write(sin, cur, len)) == 0) {
+ break;
} else if (n == -1) {
- warn("failed to write to sink");
- goto csink;
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ else break;
}
+ cur += n;
+ len -= n;
+ }
+ if (n == 0) {
+ warn("sink shut down unexpectedly");
+ goto csink;
+ } else if (n == -1) {
+ warn("failed to write to sink");
+ goto csink;
}
e = 0;
csink: