xref: /plan9/sys/src/cmd/idiff.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1*9a747e4fSDavid du Colombier /*
2*9a747e4fSDavid du Colombier  * interactive diff, inspired/stolen from
3*9a747e4fSDavid du Colombier  * kernighan and pike, _unix programming environment_.
4*9a747e4fSDavid du Colombier  */
5*9a747e4fSDavid du Colombier 
6*9a747e4fSDavid du Colombier #include <u.h>
7*9a747e4fSDavid du Colombier #include <libc.h>
8*9a747e4fSDavid du Colombier #include <bio.h>
9*9a747e4fSDavid du Colombier 
10*9a747e4fSDavid du Colombier int diffbflag;
11*9a747e4fSDavid du Colombier int diffwflag;
12*9a747e4fSDavid du Colombier 
13*9a747e4fSDavid du Colombier void copy(Biobuf*, char*, Biobuf*, char*);
14*9a747e4fSDavid du Colombier void idiff(Biobuf*, char*, Biobuf*, char*, Biobuf*, char*, Biobuf*, char*);
15*9a747e4fSDavid du Colombier int opentemp(char*, int, long);
16*9a747e4fSDavid du Colombier void rundiff(char*, char*, int);
17*9a747e4fSDavid du Colombier 
18*9a747e4fSDavid du Colombier void
usage(void)19*9a747e4fSDavid du Colombier usage(void)
20*9a747e4fSDavid du Colombier {
21*9a747e4fSDavid du Colombier 	fprint(2, "usage: idiff [-bw] file1 file2\n");
22*9a747e4fSDavid du Colombier 	exits("usage");
23*9a747e4fSDavid du Colombier }
24*9a747e4fSDavid du Colombier 
25*9a747e4fSDavid du Colombier void
main(int argc,char ** argv)26*9a747e4fSDavid du Colombier main(int argc, char **argv)
27*9a747e4fSDavid du Colombier {
28*9a747e4fSDavid du Colombier 	int fd, ofd;
29*9a747e4fSDavid du Colombier 	char diffout[40], idiffout[40];
30*9a747e4fSDavid du Colombier 	Biobuf *b1, *b2, bdiff, bout, bstdout;
31*9a747e4fSDavid du Colombier 	Dir *d;
32*9a747e4fSDavid du Colombier 
33*9a747e4fSDavid du Colombier 	ARGBEGIN{
34*9a747e4fSDavid du Colombier 	default:
35*9a747e4fSDavid du Colombier 		usage();
36*9a747e4fSDavid du Colombier 	case 'b':
37*9a747e4fSDavid du Colombier 		diffbflag++;
38*9a747e4fSDavid du Colombier 		break;
39*9a747e4fSDavid du Colombier 	case 'w':
40*9a747e4fSDavid du Colombier 		diffwflag++;
41*9a747e4fSDavid du Colombier 		break;
42*9a747e4fSDavid du Colombier 	}ARGEND
43*9a747e4fSDavid du Colombier 
44*9a747e4fSDavid du Colombier 	if(argc != 2)
45*9a747e4fSDavid du Colombier 		usage();
46*9a747e4fSDavid du Colombier 
47*9a747e4fSDavid du Colombier 	if((d = dirstat(argv[0])) == nil)
48*9a747e4fSDavid du Colombier 		sysfatal("stat %s: %r", argv[0]);
49*9a747e4fSDavid du Colombier 	if(d->mode&DMDIR)
50*9a747e4fSDavid du Colombier 		sysfatal("%s is a directory", argv[0]);
51*9a747e4fSDavid du Colombier 	free(d);
52*9a747e4fSDavid du Colombier 	if((d = dirstat(argv[1])) == nil)
53*9a747e4fSDavid du Colombier 		sysfatal("stat %s: %r", argv[1]);
54*9a747e4fSDavid du Colombier 	if(d->mode&DMDIR)
55*9a747e4fSDavid du Colombier 		sysfatal("%s is a directory", argv[1]);
56*9a747e4fSDavid du Colombier 	free(d);
57*9a747e4fSDavid du Colombier 
58*9a747e4fSDavid du Colombier 	if((b1 = Bopen(argv[0], OREAD)) == nil)
59*9a747e4fSDavid du Colombier 		sysfatal("open %s: %r", argv[0]);
60*9a747e4fSDavid du Colombier 	if((b2 = Bopen(argv[1], OREAD)) == nil)
61*9a747e4fSDavid du Colombier 		sysfatal("open %s: %r", argv[1]);
62*9a747e4fSDavid du Colombier 
63*9a747e4fSDavid du Colombier 	strcpy(diffout, "/tmp/idiff.XXXXXX");
64*9a747e4fSDavid du Colombier 	fd = opentemp(diffout, ORDWR|ORCLOSE, 0);
65*9a747e4fSDavid du Colombier 	strcpy(idiffout, "/tmp/idiff.XXXXXX");
66*9a747e4fSDavid du Colombier 	ofd = opentemp(idiffout, ORDWR|ORCLOSE, 0);
67*9a747e4fSDavid du Colombier 	rundiff(argv[0], argv[1], fd);
68*9a747e4fSDavid du Colombier 	seek(fd, 0, 0);
69*9a747e4fSDavid du Colombier 	Binit(&bdiff, fd, OREAD);
70*9a747e4fSDavid du Colombier 	Binit(&bout, ofd, OWRITE);
71*9a747e4fSDavid du Colombier 	idiff(b1, argv[0], b2, argv[1], &bdiff, diffout, &bout, idiffout);
72*9a747e4fSDavid du Colombier 	Bterm(&bdiff);
73*9a747e4fSDavid du Colombier 	Bflush(&bout);
74*9a747e4fSDavid du Colombier 	seek(ofd, 0, 0);
75*9a747e4fSDavid du Colombier 	Binit(&bout, ofd, OREAD);
76*9a747e4fSDavid du Colombier 	Binit(&bstdout, 1, OWRITE);
77*9a747e4fSDavid du Colombier 	copy(&bout, idiffout, &bstdout, "<stdout>");
78*9a747e4fSDavid du Colombier 	exits(nil);
79*9a747e4fSDavid du Colombier }
80*9a747e4fSDavid du Colombier 
81*9a747e4fSDavid du Colombier int
opentemp(char * template,int mode,long perm)82*9a747e4fSDavid du Colombier opentemp(char *template, int mode, long perm)
83*9a747e4fSDavid du Colombier {
84*9a747e4fSDavid du Colombier 	int fd, i;
85*9a747e4fSDavid du Colombier 	char *p;
86*9a747e4fSDavid du Colombier 
87*9a747e4fSDavid du Colombier 	p = strdup(template);
88*9a747e4fSDavid du Colombier 	if(p == nil)
89*9a747e4fSDavid du Colombier 		sysfatal("strdup out of memory");
90*9a747e4fSDavid du Colombier 	fd = -1;
91*9a747e4fSDavid du Colombier 	for(i=0; i<10; i++){
92*9a747e4fSDavid du Colombier 		mktemp(p);
93*9a747e4fSDavid du Colombier 		if(access(p, 0) < 0 && (fd=create(p, mode, perm)) >= 0)
94*9a747e4fSDavid du Colombier 			break;
95*9a747e4fSDavid du Colombier 		strcpy(p, template);
96*9a747e4fSDavid du Colombier 	}
97*9a747e4fSDavid du Colombier 	if(fd < 0)
98*9a747e4fSDavid du Colombier 		sysfatal("could not create temporary file");
99*9a747e4fSDavid du Colombier 	strcpy(template, p);
100*9a747e4fSDavid du Colombier 	free(p);
101*9a747e4fSDavid du Colombier 
102*9a747e4fSDavid du Colombier 	return fd;
103*9a747e4fSDavid du Colombier }
104*9a747e4fSDavid du Colombier 
105*9a747e4fSDavid du Colombier void
rundiff(char * arg1,char * arg2,int outfd)106*9a747e4fSDavid du Colombier rundiff(char *arg1, char *arg2, int outfd)
107*9a747e4fSDavid du Colombier {
108*9a747e4fSDavid du Colombier 	char *arg[10], *p;
109*9a747e4fSDavid du Colombier 	int narg, pid;
110*9a747e4fSDavid du Colombier 	Waitmsg *w;
111*9a747e4fSDavid du Colombier 
112*9a747e4fSDavid du Colombier 	narg = 0;
113*9a747e4fSDavid du Colombier 	arg[narg++] = "/bin/diff";
114*9a747e4fSDavid du Colombier 	arg[narg++] = "-n";
115*9a747e4fSDavid du Colombier 	if(diffbflag)
116*9a747e4fSDavid du Colombier 		arg[narg++] = "-b";
117*9a747e4fSDavid du Colombier 	if(diffwflag)
118*9a747e4fSDavid du Colombier 		arg[narg++] = "-w";
119*9a747e4fSDavid du Colombier 	arg[narg++] = arg1;
120*9a747e4fSDavid du Colombier 	arg[narg++] = arg2;
121*9a747e4fSDavid du Colombier 	arg[narg] = nil;
122*9a747e4fSDavid du Colombier 
123*9a747e4fSDavid du Colombier 	switch(pid = fork()){
124*9a747e4fSDavid du Colombier 	case -1:
125*9a747e4fSDavid du Colombier 		sysfatal("fork: %r");
126*9a747e4fSDavid du Colombier 
127*9a747e4fSDavid du Colombier 	case 0:
128*9a747e4fSDavid du Colombier 		dup(outfd, 1);
129*9a747e4fSDavid du Colombier 		close(0);
130*9a747e4fSDavid du Colombier 		exec("/bin/diff", arg);
131*9a747e4fSDavid du Colombier 		sysfatal("exec: %r");
132*9a747e4fSDavid du Colombier 
133*9a747e4fSDavid du Colombier 	default:
134*9a747e4fSDavid du Colombier 		w = wait();
135*9a747e4fSDavid du Colombier 		if(w==nil)
136*9a747e4fSDavid du Colombier 			sysfatal("wait: %r");
137*9a747e4fSDavid du Colombier 		if(w->pid != pid)
138*9a747e4fSDavid du Colombier 			sysfatal("wait got unexpected pid %d", w->pid);
139*9a747e4fSDavid du Colombier 		if((p = strchr(w->msg, ':')) && strcmp(p, ": some") != 0)
140*9a747e4fSDavid du Colombier 			sysfatal("%s", w->msg);
141*9a747e4fSDavid du Colombier 		free(w);
142*9a747e4fSDavid du Colombier 	}
143*9a747e4fSDavid du Colombier }
144*9a747e4fSDavid du Colombier 
145*9a747e4fSDavid du Colombier void
runcmd(char * cmd)146*9a747e4fSDavid du Colombier runcmd(char *cmd)
147*9a747e4fSDavid du Colombier {
148*9a747e4fSDavid du Colombier 	char *arg[10];
149*9a747e4fSDavid du Colombier 	int narg, pid, wpid;
150*9a747e4fSDavid du Colombier 
151*9a747e4fSDavid du Colombier 	narg = 0;
152*9a747e4fSDavid du Colombier 	arg[narg++] = "/bin/rc";
153*9a747e4fSDavid du Colombier 	arg[narg++] = "-c";
154*9a747e4fSDavid du Colombier 	arg[narg++] = cmd;
155*9a747e4fSDavid du Colombier 	arg[narg] = nil;
156*9a747e4fSDavid du Colombier 
157*9a747e4fSDavid du Colombier 	switch(pid = fork()){
158*9a747e4fSDavid du Colombier 	case -1:
159*9a747e4fSDavid du Colombier 		sysfatal("fork: %r");
160*9a747e4fSDavid du Colombier 
161*9a747e4fSDavid du Colombier 	case 0:
162*9a747e4fSDavid du Colombier 		exec("/bin/rc", arg);
163*9a747e4fSDavid du Colombier 		sysfatal("exec: %r");
164*9a747e4fSDavid du Colombier 
165*9a747e4fSDavid du Colombier 	default:
166*9a747e4fSDavid du Colombier 		wpid = waitpid();
167*9a747e4fSDavid du Colombier 		if(wpid < 0)
168*9a747e4fSDavid du Colombier 			sysfatal("wait: %r");
169*9a747e4fSDavid du Colombier 		if(wpid != pid)
170*9a747e4fSDavid du Colombier 			sysfatal("wait got unexpected pid %d", wpid);
171*9a747e4fSDavid du Colombier 	}
172*9a747e4fSDavid du Colombier }
173*9a747e4fSDavid du Colombier 
174*9a747e4fSDavid du Colombier void
parse(char * s,int * pfrom1,int * pto1,int * pcmd,int * pfrom2,int * pto2)175*9a747e4fSDavid du Colombier parse(char *s, int *pfrom1, int *pto1, int *pcmd, int *pfrom2, int *pto2)
176*9a747e4fSDavid du Colombier {
177*9a747e4fSDavid du Colombier 	*pfrom1 = *pto1 = *pfrom2 = *pto2 = 0;
178*9a747e4fSDavid du Colombier 
179*9a747e4fSDavid du Colombier 	s = strchr(s, ':');
180*9a747e4fSDavid du Colombier 	if(s == nil)
181*9a747e4fSDavid du Colombier 		sysfatal("bad diff output0");
182*9a747e4fSDavid du Colombier 	s++;
183*9a747e4fSDavid du Colombier 	*pfrom1 = strtol(s, &s, 10);
184*9a747e4fSDavid du Colombier 	if(*s == ','){
185*9a747e4fSDavid du Colombier 		s++;
186*9a747e4fSDavid du Colombier 		*pto1 = strtol(s, &s, 10);
187*9a747e4fSDavid du Colombier 	}else
188*9a747e4fSDavid du Colombier 		*pto1 = *pfrom1;
189*9a747e4fSDavid du Colombier 	if(*s++ != ' ')
190*9a747e4fSDavid du Colombier 		sysfatal("bad diff output1");
191*9a747e4fSDavid du Colombier 	*pcmd = *s++;
192*9a747e4fSDavid du Colombier 	if(*s++ != ' ')
193*9a747e4fSDavid du Colombier 		sysfatal("bad diff output2");
194*9a747e4fSDavid du Colombier 	s = strchr(s, ':');
195*9a747e4fSDavid du Colombier 	if(s == nil)
196*9a747e4fSDavid du Colombier 		sysfatal("bad diff output3");
197*9a747e4fSDavid du Colombier 	s++;
198*9a747e4fSDavid du Colombier 	*pfrom2 = strtol(s, &s, 10);
199*9a747e4fSDavid du Colombier 	if(*s == ','){
200*9a747e4fSDavid du Colombier 		s++;
201*9a747e4fSDavid du Colombier 		*pto2 = strtol(s, &s, 10);
202*9a747e4fSDavid du Colombier 	}else
203*9a747e4fSDavid du Colombier 		*pto2 = *pfrom2;
204*9a747e4fSDavid du Colombier }
205*9a747e4fSDavid du Colombier 
206*9a747e4fSDavid du Colombier void
skiplines(Biobuf * b,char * name,int n)207*9a747e4fSDavid du Colombier skiplines(Biobuf *b, char *name, int n)
208*9a747e4fSDavid du Colombier {
209*9a747e4fSDavid du Colombier 	int i;
210*9a747e4fSDavid du Colombier 
211*9a747e4fSDavid du Colombier 	for(i=0; i<n; i++){
212*9a747e4fSDavid du Colombier 		while(Brdline(b, '\n')==nil){
213*9a747e4fSDavid du Colombier 			if(Blinelen(b) <= 0)
214*9a747e4fSDavid du Colombier 				sysfatal("early end of file on %s", name);
215*9a747e4fSDavid du Colombier 			Bseek(b, Blinelen(b), 1);
216*9a747e4fSDavid du Colombier 		}
217*9a747e4fSDavid du Colombier 	}
218*9a747e4fSDavid du Colombier }
219*9a747e4fSDavid du Colombier 
220*9a747e4fSDavid du Colombier void
copylines(Biobuf * bin,char * nin,Biobuf * bout,char * nout,int n)221*9a747e4fSDavid du Colombier copylines(Biobuf *bin, char *nin, Biobuf *bout, char *nout, int n)
222*9a747e4fSDavid du Colombier {
223*9a747e4fSDavid du Colombier 	char buf[4096], *p;
224*9a747e4fSDavid du Colombier 	int i, m;
225*9a747e4fSDavid du Colombier 
226*9a747e4fSDavid du Colombier 	for(i=0; i<n; i++){
227*9a747e4fSDavid du Colombier 		while((p=Brdline(bin, '\n'))==nil){
228*9a747e4fSDavid du Colombier 			if(Blinelen(bin) <= 0)
229*9a747e4fSDavid du Colombier 				sysfatal("early end of file on %s", nin);
230*9a747e4fSDavid du Colombier 			m = Blinelen(bin);
231*9a747e4fSDavid du Colombier 			if(m > sizeof buf)
232*9a747e4fSDavid du Colombier 				m = sizeof buf;
233*9a747e4fSDavid du Colombier 			m = Bread(bin, buf, m);
234*9a747e4fSDavid du Colombier 			if(Bwrite(bout, buf, m) != m)
235*9a747e4fSDavid du Colombier 				sysfatal("error writing %s: %r", nout);
236*9a747e4fSDavid du Colombier 		}
237*9a747e4fSDavid du Colombier 		if(Bwrite(bout, p, Blinelen(bin)) != Blinelen(bin))
238*9a747e4fSDavid du Colombier 			sysfatal("error writing %s: %r", nout);
239*9a747e4fSDavid du Colombier 	}
240*9a747e4fSDavid du Colombier }
241*9a747e4fSDavid du Colombier 
242*9a747e4fSDavid du Colombier void
copy(Biobuf * bin,char * nin,Biobuf * bout,char * nout)243*9a747e4fSDavid du Colombier copy(Biobuf *bin, char *nin, Biobuf *bout, char *nout)
244*9a747e4fSDavid du Colombier {
245*9a747e4fSDavid du Colombier 	char buf[4096];
246*9a747e4fSDavid du Colombier 	int m;
247*9a747e4fSDavid du Colombier 
248*9a747e4fSDavid du Colombier 	USED(nin);
249*9a747e4fSDavid du Colombier 	while((m = Bread(bin, buf, sizeof buf)) > 0)
250*9a747e4fSDavid du Colombier 		if(Bwrite(bout, buf, m) != m)
251*9a747e4fSDavid du Colombier 			sysfatal("error writing %s: %r", nout);
252*9a747e4fSDavid du Colombier }
253*9a747e4fSDavid du Colombier 
254*9a747e4fSDavid du Colombier void
idiff(Biobuf * b1,char * name1,Biobuf * b2,char * name2,Biobuf * bdiff,char * namediff,Biobuf * bout,char * nameout)255*9a747e4fSDavid du Colombier idiff(Biobuf *b1, char *name1, Biobuf *b2, char *name2, Biobuf *bdiff, char *namediff, Biobuf *bout, char *nameout)
256*9a747e4fSDavid du Colombier {
257*9a747e4fSDavid du Colombier 	char buf[256], *p;
258*9a747e4fSDavid du Colombier 	int interactive, defaultanswer, cmd, diffoffset;
259*9a747e4fSDavid du Colombier 	int n, from1, to1, from2, to2, nf1, nf2;
260*9a747e4fSDavid du Colombier 	Biobuf berr;
261*9a747e4fSDavid du Colombier 
262*9a747e4fSDavid du Colombier 	nf1 = 1;
263*9a747e4fSDavid du Colombier 	nf2 = 1;
264*9a747e4fSDavid du Colombier 	interactive = 1;
265*9a747e4fSDavid du Colombier 	defaultanswer = 0;
266*9a747e4fSDavid du Colombier 	Binit(&berr, 2, OWRITE);
267*9a747e4fSDavid du Colombier 	while(diffoffset = Boffset(bdiff), p = Brdline(bdiff, '\n')){
268*9a747e4fSDavid du Colombier 		p[Blinelen(bdiff)-1] = '\0';
269*9a747e4fSDavid du Colombier 		parse(p, &from1, &to1, &cmd, &from2, &to2);
270*9a747e4fSDavid du Colombier 		p[Blinelen(bdiff)-1] = '\n';
271*9a747e4fSDavid du Colombier 		n = to1-from1 + to2-from2 + 1;	/* #lines from diff */
272*9a747e4fSDavid du Colombier 		if(cmd == 'c')
273*9a747e4fSDavid du Colombier 			n += 2;
274*9a747e4fSDavid du Colombier 		else if(cmd == 'a')
275*9a747e4fSDavid du Colombier 			from1++;
276*9a747e4fSDavid du Colombier 		else if(cmd == 'd')
277*9a747e4fSDavid du Colombier 			from2++;
278*9a747e4fSDavid du Colombier 		to1++;	/* make half-open intervals */
279*9a747e4fSDavid du Colombier 		to2++;
280*9a747e4fSDavid du Colombier 		if(interactive){
281*9a747e4fSDavid du Colombier 			p[Blinelen(bdiff)-1] = '\0';
282*9a747e4fSDavid du Colombier 			fprint(2, "%s\n", p);
283*9a747e4fSDavid du Colombier 			p[Blinelen(bdiff)-1] = '\n';
284*9a747e4fSDavid du Colombier 			copylines(bdiff, namediff, &berr, "<stderr>", n);
285*9a747e4fSDavid du Colombier 			Bflush(&berr);
286*9a747e4fSDavid du Colombier 		}else
287*9a747e4fSDavid du Colombier 			skiplines(bdiff, namediff, n);
288*9a747e4fSDavid du Colombier 		do{
289*9a747e4fSDavid du Colombier 			if(interactive){
290*9a747e4fSDavid du Colombier 				fprint(2, "? ");
291*9a747e4fSDavid du Colombier 				memset(buf, 0, sizeof buf);
292*9a747e4fSDavid du Colombier 				if(read(0, buf, sizeof buf - 1) < 0)
293*9a747e4fSDavid du Colombier 					sysfatal("read console: %r");
294*9a747e4fSDavid du Colombier 			}else
295*9a747e4fSDavid du Colombier 				buf[0] = defaultanswer;
296*9a747e4fSDavid du Colombier 
297*9a747e4fSDavid du Colombier 			switch(buf[0]){
298*9a747e4fSDavid du Colombier 			case '>':
299*9a747e4fSDavid du Colombier 				copylines(b1, name1, bout, nameout, from1-nf1);
300*9a747e4fSDavid du Colombier 				skiplines(b1, name1, to1-from1);
301*9a747e4fSDavid du Colombier 				skiplines(b2, name2, from2-nf2);
302*9a747e4fSDavid du Colombier 				copylines(b2, name2, bout, nameout, to2-from2);
303*9a747e4fSDavid du Colombier 				break;
304*9a747e4fSDavid du Colombier 			case '<':
305*9a747e4fSDavid du Colombier 				copylines(b1, name1, bout, nameout, to1-nf1);
306*9a747e4fSDavid du Colombier 				skiplines(b2, name2, to2-nf2);
307*9a747e4fSDavid du Colombier 				break;
308*9a747e4fSDavid du Colombier 			case '=':
309*9a747e4fSDavid du Colombier 				copylines(b1, name1, bout, nameout, from1-nf1);
310*9a747e4fSDavid du Colombier 				skiplines(b1, name1, to1-from1);
311*9a747e4fSDavid du Colombier 				skiplines(b2, name2, to2-nf2);
312*9a747e4fSDavid du Colombier 				if(Bseek(bdiff, diffoffset, 0) != diffoffset)
313*9a747e4fSDavid du Colombier 					sysfatal("seek in diff output: %r");
314*9a747e4fSDavid du Colombier 				copylines(bdiff, namediff, bout, nameout, n+1);
315*9a747e4fSDavid du Colombier 				break;
316*9a747e4fSDavid du Colombier 			case '!':
317*9a747e4fSDavid du Colombier 				runcmd(buf+1);
318*9a747e4fSDavid du Colombier 				break;
319*9a747e4fSDavid du Colombier 			case 'q':
320*9a747e4fSDavid du Colombier 				if(buf[1]=='<' || buf[1]=='>' || buf[1]=='='){
321*9a747e4fSDavid du Colombier 					interactive = 0;
322*9a747e4fSDavid du Colombier 					defaultanswer = buf[1];
323*9a747e4fSDavid du Colombier 				}else
324*9a747e4fSDavid du Colombier 					fprint(2, "must be q<, q>, or q=\n");
325*9a747e4fSDavid du Colombier 				break;
326*9a747e4fSDavid du Colombier 			default:
327*9a747e4fSDavid du Colombier 				fprint(2, "expect: <, >, =, q<, q>, q=, !cmd\n");
328*9a747e4fSDavid du Colombier 				break;
329*9a747e4fSDavid du Colombier 			}
330*9a747e4fSDavid du Colombier 		}while(buf[0] != '<' && buf[0] != '>' && buf[0] != '=');
331*9a747e4fSDavid du Colombier 		nf1 = to1;
332*9a747e4fSDavid du Colombier 		nf2 = to2;
333*9a747e4fSDavid du Colombier 	}
334*9a747e4fSDavid du Colombier 	copy(b1, name1, bout, nameout);
335*9a747e4fSDavid du Colombier }
336