From d1f529f46f957c78a3db73b42c2fcd2d3c9f8a34 Mon Sep 17 00:00:00 2001 From: rsc Date: Sat, 29 Oct 2005 16:26:32 +0000 Subject: Thanks to John Cummings. --- src/cmd/upas/common/appendfiletombox.c | 155 +++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 src/cmd/upas/common/appendfiletombox.c (limited to 'src/cmd/upas/common/appendfiletombox.c') diff --git a/src/cmd/upas/common/appendfiletombox.c b/src/cmd/upas/common/appendfiletombox.c new file mode 100644 index 00000000..98f51578 --- /dev/null +++ b/src/cmd/upas/common/appendfiletombox.c @@ -0,0 +1,155 @@ +#include "common.h" + +enum { + Buffersize = 64*1024, +}; + +typedef struct Inbuf Inbuf; +struct Inbuf +{ + char buf[Buffersize]; + char *wp; + char *rp; + int eof; + int in; + int out; + int last; + ulong bytes; +}; + +static Inbuf* +allocinbuf(int in, int out) +{ + Inbuf *b; + + b = mallocz(sizeof(Inbuf), 1); + if(b == nil) + sysfatal("reading mailbox: %r"); + b->rp = b->wp = b->buf; + b->in = in; + b->out = out; + return b; +} + +static int +fill(Inbuf *b, int addspace) +{ + int i, n; + + if(b->eof && b->wp - b->rp == 0) + return 0; + + n = b->rp - b->buf; + if(n > 0){ + i = write(b->out, b->buf, n); + if(i != n) + return -1; + b->last = b->buf[n-1]; + b->bytes += n; + } + if(addspace){ + if(write(b->out, " ", 1) != 1) + return -1; + b->last = ' '; + b->bytes++; + } + + n = b->wp - b->rp; + memmove(b->buf, b->rp, n); + b->rp = b->buf; + b->wp = b->rp + n; + + i = read(b->in, b->buf+n, sizeof(b->buf)-n); + if(i < 0) + return -1; + b->wp += i; + + return b->wp - b->rp; +} + +/* code to escape ' '*From' ' at the beginning of a line */ +int +appendfiletombox(int in, int out) +{ + int addspace; + int n; + char *p; + int sol; + Inbuf *b; + + seek(out, 0, 2); + + b = allocinbuf(in, out); + addspace = 0; + sol = 1; + + for(;;){ + if(b->wp - b->rp < 5){ + n = fill(b, addspace); + addspace = 0; + if(n < 0) + goto error; + if(n == 0) + break; + if(n < 5){ + b->rp = b->wp; + continue; + } + } + + /* state machine looking for ' '*From' ' */ + if(!sol){ + p = memchr(b->rp, '\n', b->wp - b->rp); + if(p == nil) + b->rp = b->wp; + else{ + b->rp = p+1; + sol = 1; + } + continue; + } else { + if(*b->rp == ' ' || strncmp(b->rp, "From ", 5) != 0){ + b->rp++; + continue; + } + addspace = 1; + sol = 0; + } + } + + /* mailbox entries always terminate with two newlines */ + n = b->last == '\n' ? 1 : 2; + if(write(out, "\n\n", n) != n) + goto error; + n += b->bytes; + free(b); + return n; +error: + free(b); + return -1; +} + +int +appendfiletofile(int in, int out) +{ + int n; + Inbuf *b; + + seek(out, 0, 2); + + b = allocinbuf(in, out); + for(;;){ + n = fill(b, 0); + if(n < 0) + goto error; + if(n == 0) + break; + b->rp = b->wp; + } + n = b->bytes; + free(b); + return n; +error: + free(b); + return -1; +} -- cgit v1.2.3