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