xref: /plan9/sys/src/cmd/upas/common/appendfiletombox.c (revision ec59a3ddbfceee0efe34584c2c9981a5e5ff1ec4)
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 }
156