aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/upas/common/appendfiletombox.c
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2005-10-29 16:26:32 +0000
committerrsc <devnull@localhost>2005-10-29 16:26:32 +0000
commitd1f529f46f957c78a3db73b42c2fcd2d3c9f8a34 (patch)
treea4d6f28106cca984926b9dd5ecddd6053b654617 /src/cmd/upas/common/appendfiletombox.c
parent9f1fdc128738b2ed76258ac22a8574c681f3df3a (diff)
downloadplan9port-d1f529f46f957c78a3db73b42c2fcd2d3c9f8a34.tar.gz
plan9port-d1f529f46f957c78a3db73b42c2fcd2d3c9f8a34.tar.bz2
plan9port-d1f529f46f957c78a3db73b42c2fcd2d3c9f8a34.zip
Thanks to John Cummings.
Diffstat (limited to 'src/cmd/upas/common/appendfiletombox.c')
-rw-r--r--src/cmd/upas/common/appendfiletombox.c155
1 files changed, 155 insertions, 0 deletions
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;
+}