appendfiletombox.c (2153B)
1 #include "common.h" 2 3 enum { 4 Buffersize = 64*1024 5 }; 6 7 typedef struct Inbuf Inbuf; 8 struct Inbuf 9 { 10 char buf[Buffersize]; 11 char *wp; 12 char *rp; 13 int eof; 14 int in; 15 int out; 16 int last; 17 ulong bytes; 18 }; 19 20 static Inbuf* 21 allocinbuf(int in, int out) 22 { 23 Inbuf *b; 24 25 b = mallocz(sizeof(Inbuf), 1); 26 if(b == nil) 27 sysfatal("reading mailbox: %r"); 28 b->rp = b->wp = b->buf; 29 b->in = in; 30 b->out = out; 31 return b; 32 } 33 34 static int 35 fill(Inbuf *b, int addspace) 36 { 37 int i, n; 38 39 if(b->eof && b->wp - b->rp == 0) 40 return 0; 41 42 n = b->rp - b->buf; 43 if(n > 0){ 44 i = write(b->out, b->buf, n); 45 if(i != n) 46 return -1; 47 b->last = b->buf[n-1]; 48 b->bytes += n; 49 } 50 if(addspace){ 51 if(write(b->out, " ", 1) != 1) 52 return -1; 53 b->last = ' '; 54 b->bytes++; 55 } 56 57 n = b->wp - b->rp; 58 memmove(b->buf, b->rp, n); 59 b->rp = b->buf; 60 b->wp = b->rp + n; 61 62 i = read(b->in, b->buf+n, sizeof(b->buf)-n); 63 if(i < 0) 64 return -1; 65 b->wp += i; 66 67 return b->wp - b->rp; 68 } 69 70 /* code to escape ' '*From' ' at the beginning of a line */ 71 int 72 appendfiletombox(int in, int out) 73 { 74 int addspace; 75 int n; 76 char *p; 77 int sol; 78 Inbuf *b; 79 80 seek(out, 0, 2); 81 82 b = allocinbuf(in, out); 83 addspace = 0; 84 sol = 1; 85 86 for(;;){ 87 if(b->wp - b->rp < 5){ 88 n = fill(b, addspace); 89 addspace = 0; 90 if(n < 0) 91 goto error; 92 if(n == 0) 93 break; 94 if(n < 5){ 95 b->rp = b->wp; 96 continue; 97 } 98 } 99 100 /* state machine looking for ' '*From' ' */ 101 if(!sol){ 102 p = memchr(b->rp, '\n', b->wp - b->rp); 103 if(p == nil) 104 b->rp = b->wp; 105 else{ 106 b->rp = p+1; 107 sol = 1; 108 } 109 continue; 110 } else { 111 if(*b->rp == ' ' || strncmp(b->rp, "From ", 5) != 0){ 112 b->rp++; 113 continue; 114 } 115 addspace = 1; 116 sol = 0; 117 } 118 } 119 120 /* mailbox entries always terminate with two newlines */ 121 n = b->last == '\n' ? 1 : 2; 122 if(write(out, "\n\n", n) != n) 123 goto error; 124 n += b->bytes; 125 free(b); 126 return n; 127 error: 128 free(b); 129 return -1; 130 } 131 132 int 133 appendfiletofile(int in, int out) 134 { 135 int n; 136 Inbuf *b; 137 138 seek(out, 0, 2); 139 140 b = allocinbuf(in, out); 141 for(;;){ 142 n = fill(b, 0); 143 if(n < 0) 144 goto error; 145 if(n == 0) 146 break; 147 b->rp = b->wp; 148 } 149 n = b->bytes; 150 free(b); 151 return n; 152 error: 153 free(b); 154 return -1; 155 }