dma: initialize queue structures
[dragonfly.git] / gnu / usr.bin / rcs / co / co.c
bloba5b78a3640f9d6c6e693dfa22fc1b1882d372cec
1 /* Check out working files from revisions of RCS files. */
3 /* Copyright 1982, 1988, 1989 Walter Tichy
4 Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
5 Distributed under license by the Free Software Foundation, Inc.
7 This file is part of RCS.
9 RCS is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
14 RCS is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with RCS; see the file COPYING.
21 If not, write to the Free Software Foundation,
22 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 Report problems and direct all questions to:
26 rcs-bugs@cs.purdue.edu
31 * $FreeBSD: src/gnu/usr.bin/rcs/co/co.c,v 1.10 1999/08/27 23:36:40 peter Exp $
32 * $DragonFly: src/gnu/usr.bin/rcs/co/co.c,v 1.2 2003/06/17 04:25:47 dillon Exp $
34 * Revision 5.18 1995/06/16 06:19:24 eggert
35 * Update FSF address.
37 * Revision 5.17 1995/06/01 16:23:43 eggert
38 * (main, preparejoin): Pass argument instead of using `join' static variable.
39 * (main): Add -kb.
41 * Revision 5.16 1994/03/17 14:05:48 eggert
42 * Move buffer-flushes out of critical sections, since they aren't critical.
43 * Use ORCSerror to clean up after a fatal error. Remove lint.
44 * Specify subprocess input via file descriptor, not file name.
46 * Revision 5.15 1993/11/09 17:40:15 eggert
47 * -V now prints version on stdout and exits. Don't print usage twice.
49 * Revision 5.14 1993/11/03 17:42:27 eggert
50 * Add -z. Generate a value for the Name keyword.
51 * Don't arbitrarily limit the number of joins.
52 * Improve quality of diagnostics.
54 * Revision 5.13 1992/07/28 16:12:44 eggert
55 * Add -V. Check that working and RCS files are distinct.
57 * Revision 5.12 1992/02/17 23:02:08 eggert
58 * Add -T.
60 * Revision 5.11 1992/01/24 18:44:19 eggert
61 * Add support for bad_creat0. lint -> RCS_lint
63 * Revision 5.10 1992/01/06 02:42:34 eggert
64 * Update usage string.
66 * Revision 5.9 1991/10/07 17:32:46 eggert
67 * -k affects just working file, not RCS file.
69 * Revision 5.8 1991/08/19 03:13:55 eggert
70 * Warn before removing somebody else's file.
71 * Add -M. Fix co -j bugs. Tune.
73 * Revision 5.7 1991/04/21 11:58:15 eggert
74 * Ensure that working file is newer than RCS file after co -[lu].
75 * Add -x, RCSINIT, MS-DOS support.
77 * Revision 5.6 1990/12/04 05:18:38 eggert
78 * Don't checkaccesslist() unless necessary.
79 * Use -I for prompts and -q for diagnostics.
81 * Revision 5.5 1990/11/01 05:03:26 eggert
82 * Fix -j. Add -I.
84 * Revision 5.4 1990/10/04 06:30:11 eggert
85 * Accumulate exit status across files.
87 * Revision 5.3 1990/09/11 02:41:09 eggert
88 * co -kv yields a readonly working file.
90 * Revision 5.2 1990/09/04 08:02:13 eggert
91 * Standardize yes-or-no procedure.
93 * Revision 5.0 1990/08/22 08:10:02 eggert
94 * Permit multiple locks by same user. Add setuid support.
95 * Remove compile-time limits; use malloc instead.
96 * Permit dates past 1999/12/31. Switch to GMT.
97 * Make lock and temp files faster and safer.
98 * Ansify and Posixate. Add -k, -V. Remove snooping. Tune.
100 * Revision 4.7 89/05/01 15:11:41 narten
101 * changed copyright header to reflect current distribution rules
103 * Revision 4.6 88/08/09 19:12:15 eggert
104 * Fix "co -d" core dump; rawdate wasn't always initialized.
105 * Use execv(), not system(); fix putchar('\0') and diagnose() botches; remove lint
107 * Revision 4.5 87/12/18 11:35:40 narten
108 * lint cleanups (from Guy Harris)
110 * Revision 4.4 87/10/18 10:20:53 narten
111 * Updating version numbers changes relative to 1.1, are actually
112 * relative to 4.2
114 * Revision 1.3 87/09/24 13:58:30 narten
115 * Sources now pass through lint (if you ignore printf/sprintf/fprintf
116 * warnings)
118 * Revision 1.2 87/03/27 14:21:38 jenkins
119 * Port to suns
121 * Revision 4.2 83/12/05 13:39:48 wft
122 * made rewriteflag external.
124 * Revision 4.1 83/05/10 16:52:55 wft
125 * Added option -u and -f.
126 * Added handling of default branch.
127 * Replaced getpwuid() with getcaller().
128 * Removed calls to stat(); now done by pairfilenames().
129 * Changed and renamed rmoldfile() to rmworkfile().
130 * Replaced catchints() calls with restoreints(), unlink()--link() with rename();
132 * Revision 3.7 83/02/15 15:27:07 wft
133 * Added call to fastcopy() to copy remainder of RCS file.
135 * Revision 3.6 83/01/15 14:37:50 wft
136 * Added ignoring of interrupts while RCS file is renamed; this avoids
137 * deletion of RCS files during the unlink/link window.
139 * Revision 3.5 82/12/08 21:40:11 wft
140 * changed processing of -d to use DATEFORM; removed actual from
141 * call to preparejoin; re-fixed printing of done at the end.
143 * Revision 3.4 82/12/04 18:40:00 wft
144 * Replaced getdelta() with gettree(), SNOOPDIR with SNOOPFILE.
145 * Fixed printing of "done".
147 * Revision 3.3 82/11/28 22:23:11 wft
148 * Replaced getlogin() with getpwuid(), flcose() with ffclose(),
149 * %02d with %.2d, mode generation for working file with WORKMODE.
150 * Fixed nil printing. Fixed -j combined with -l and -p, and exit
151 * for non-existing revisions in preparejoin().
153 * Revision 3.2 82/10/18 20:47:21 wft
154 * Mode of working file is now maintained even for co -l, but write permission
155 * is removed.
156 * The working file inherits its mode from the RCS file, plus write permission
157 * for the owner. The write permission is not given if locking is strict and
158 * co does not lock.
159 * An existing working file without write permission is deleted automatically.
160 * Otherwise, co asks (empty answer: abort co).
161 * Call to getfullRCSname() added, check for write error added, call
162 * for getlogin() fixed.
164 * Revision 3.1 82/10/13 16:01:30 wft
165 * fixed type of variables receiving from getc() (char -> int).
166 * removed unused variables.
172 #include "rcsbase.h"
174 static char *addjoin P((char*));
175 static char const *getancestor P((char const*,char const*));
176 static int buildjoin P((char const*));
177 static int preparejoin P((char*));
178 static int rmlock P((struct hshentry const*));
179 static int rmworkfile P((void));
180 static void cleanup P((void));
182 static char const quietarg[] = "-q";
184 static char const *expandarg, *suffixarg, *versionarg, *zonearg;
185 static char const **joinlist; /* revisions to be joined */
186 static int joinlength;
187 static FILE *neworkptr;
188 static int exitstatus;
189 static int forceflag;
190 static int lastjoin; /* index of last element in joinlist */
191 static int lockflag; /* -1 -> unlock, 0 -> do nothing, 1 -> lock */
192 static int mtimeflag;
193 static struct hshentries *gendeltas; /* deltas to be generated */
194 static struct hshentry *targetdelta; /* final delta to be generated */
195 static struct stat workstat;
197 mainProg(coId, "co", "$DragonFly: src/gnu/usr.bin/rcs/co/co.c,v 1.2 2003/06/17 04:25:47 dillon Exp $")
199 static char const cmdusage[] =
200 "\nco usage: co -{fIlMpqru}[rev] -ddate -jjoins -ksubst -sstate -T -w[who] -Vn -xsuff -zzone file ...";
202 char *a, *joinflag, **newargv;
203 char const *author, *date, *rev, *state;
204 char const *joinname, *newdate, *neworkname;
205 int changelock; /* 1 if a lock has been changed, -1 if error */
206 int expmode, r, tostdout, workstatstat;
207 int Ttimeflag;
208 struct buf numericrev; /* expanded revision number */
209 char finaldate[datesize];
210 # if OPEN_O_BINARY
211 int stdout_mode = 0;
212 # endif
214 setrid();
215 author = date = rev = state = 0;
216 joinflag = 0;
217 bufautobegin(&numericrev);
218 expmode = -1;
219 suffixes = X_DEFAULT;
220 tostdout = false;
221 Ttimeflag = false;
223 argc = getRCSINIT(argc, argv, &newargv);
224 argv = newargv;
225 while (a = *++argv, 0<--argc && *a++=='-') {
226 switch (*a++) {
228 case 'r':
229 revno:
230 if (*a) {
231 if (rev) warn("redefinition of revision number");
232 rev = a;
234 break;
236 case 'f':
237 forceflag=true;
238 goto revno;
240 case 'l':
241 if (lockflag < 0) {
242 warn("-u overridden by -l.");
244 lockflag = 1;
245 goto revno;
247 case 'u':
248 if (0 < lockflag) {
249 warn("-l overridden by -u.");
251 lockflag = -1;
252 goto revno;
254 case 'p':
255 tostdout = true;
256 goto revno;
258 case 'I':
259 interactiveflag = true;
260 goto revno;
262 case 'q':
263 quietflag=true;
264 goto revno;
266 case 'd':
267 if (date)
268 redefined('d');
269 str2date(a, finaldate);
270 date=finaldate;
271 break;
273 case 'j':
274 if (*a) {
275 if (joinflag) redefined('j');
276 joinflag = a;
278 break;
280 case 'M':
281 mtimeflag = true;
282 goto revno;
284 case 's':
285 if (*a) {
286 if (state) redefined('s');
287 state = a;
289 break;
291 case 'T':
292 if (*a)
293 goto unknown;
294 Ttimeflag = true;
295 break;
297 case 'w':
298 if (author) redefined('w');
299 if (*a)
300 author = a;
301 else
302 author = getcaller();
303 break;
305 case 'x':
306 suffixarg = *argv;
307 suffixes = a;
308 break;
310 case 'V':
311 versionarg = *argv;
312 setRCSversion(versionarg);
313 break;
315 case 'z':
316 zonearg = *argv;
317 zone_set(a);
318 break;
320 case 'k': /* set keyword expand mode */
321 expandarg = *argv;
322 if (0 <= expmode) redefined('k');
323 if (0 <= (expmode = str2expmode(a)))
324 break;
325 /* fall into */
326 default:
327 unknown:
328 error("unknown option: %s%s", *argv, cmdusage);
331 } /* end of option processing */
333 /* Now handle all pathnames. */
334 if (nerror) cleanup();
335 else if (argc < 1) faterror("no input file%s", cmdusage);
336 else for (; 0 < argc; cleanup(), ++argv, --argc) {
337 ffree();
339 if (pairnames(argc, argv, lockflag?rcswriteopen:rcsreadopen, true, false) <= 0)
340 continue;
343 * RCSname contains the name of the RCS file, and finptr
344 * points at it. workname contains the name of the working file.
345 * Also, RCSstat has been set.
347 diagnose("%s --> %s\n", RCSname, tostdout?"standard output":workname);
349 workstatstat = -1;
350 if (tostdout) {
351 # if OPEN_O_BINARY
352 int newmode = Expand==BINARY_EXPAND ? OPEN_O_BINARY : 0;
353 if (stdout_mode != newmode) {
354 stdout_mode = newmode;
355 oflush();
356 VOID setmode(STDOUT_FILENO, newmode);
358 # endif
359 neworkname = 0;
360 neworkptr = workstdout = stdout;
361 } else {
362 workstatstat = stat(workname, &workstat);
363 if (workstatstat == 0 && same_file(RCSstat, workstat, 0)) {
364 rcserror("RCS file is the same as working file %s.",
365 workname
367 continue;
369 neworkname = makedirtemp(1);
370 if (!(neworkptr = fopenSafer(neworkname, FOPEN_W_WORK))) {
371 if (errno == EACCES)
372 workerror("permission denied on parent directory");
373 else
374 eerror(neworkname);
375 continue;
379 gettree(); /* reads in the delta tree */
381 if (!Head) {
382 /* no revisions; create empty file */
383 diagnose("no revisions present; generating empty revision 0.0\n");
384 if (lockflag)
385 warn(
386 "no revisions, so nothing can be %slocked",
387 lockflag < 0 ? "un" : ""
389 Ozclose(&fcopy);
390 if (workstatstat == 0)
391 if (!rmworkfile()) continue;
392 changelock = 0;
393 newdate = 0;
394 } else {
395 int locks = lockflag ? findlock(false, &targetdelta) : 0;
396 if (rev) {
397 /* expand symbolic revision number */
398 if (!expandsym(rev, &numericrev))
399 continue;
400 } else {
401 switch (locks) {
402 default:
403 continue;
404 case 0:
405 bufscpy(&numericrev, Dbranch?Dbranch:"");
406 break;
407 case 1:
408 bufscpy(&numericrev, targetdelta->num);
409 break;
412 /* get numbers of deltas to be generated */
413 if (!(targetdelta=genrevs(numericrev.string,date,author,state,&gendeltas)))
414 continue;
415 /* check reservations */
416 changelock =
417 lockflag < 0 ?
418 rmlock(targetdelta)
419 : lockflag == 0 ?
422 addlock(targetdelta, true);
424 if (
425 changelock < 0
426 || (changelock && !checkaccesslist())
427 || dorewrite(lockflag, changelock) != 0
429 continue;
431 if (0 <= expmode)
432 Expand = expmode;
433 if (0 < lockflag && Expand == VAL_EXPAND) {
434 rcserror("cannot combine -kv and -l");
435 continue;
438 if (joinflag && !preparejoin(joinflag))
439 continue;
441 diagnose("revision %s%s\n",targetdelta->num,
442 0<lockflag ? " (locked)" :
443 lockflag<0 ? " (unlocked)" : "");
445 /* Prepare to remove old working file if necessary. */
446 if (workstatstat == 0)
447 if (!rmworkfile()) continue;
449 /* skip description */
450 getdesc(false); /* don't echo*/
452 locker_expansion = 0 < lockflag;
453 targetdelta->name = namedrev(rev, targetdelta);
454 joinname = buildrevision(
455 gendeltas, targetdelta,
456 joinflag&&tostdout ? (FILE*)0 : neworkptr,
457 Expand < MIN_UNEXPAND
459 # if !large_memory
460 if (fcopy == neworkptr)
461 fcopy = 0; /* Don't close it twice. */
462 # endif
463 if_advise_access(changelock && gendeltas->first!=targetdelta,
464 finptr, MADV_SEQUENTIAL
467 if (donerewrite(changelock,
468 Ttimeflag ? RCSstat.st_mtime : (time_t)-1
469 ) != 0)
470 continue;
472 if (changelock) {
473 locks += lockflag;
474 if (1 < locks)
475 rcswarn("You now have %d locks.", locks);
478 newdate = targetdelta->date;
479 if (joinflag) {
480 newdate = 0;
481 if (!joinname) {
482 aflush(neworkptr);
483 joinname = neworkname;
485 if (Expand == BINARY_EXPAND)
486 workerror("merging binary files");
487 if (!buildjoin(joinname))
488 continue;
491 if (!tostdout) {
492 mode_t m = WORKMODE(RCSstat.st_mode,
493 ! (Expand==VAL_EXPAND || (lockflag<=0 && StrictLocks))
495 time_t t = mtimeflag&&newdate ? date2time(newdate) : (time_t)-1;
496 aflush(neworkptr);
497 ignoreints();
498 r = chnamemod(&neworkptr, neworkname, workname, 1, m, t);
499 keepdirtemp(neworkname);
500 restoreints();
501 if (r != 0) {
502 eerror(workname);
503 error("see %s", neworkname);
504 continue;
506 diagnose("done\n");
510 tempunlink();
511 Ofclose(workstdout);
512 exitmain(exitstatus);
514 } /* end of main (co) */
516 static void
517 cleanup()
519 if (nerror) exitstatus = EXIT_FAILURE;
520 Izclose(&finptr);
521 ORCSclose();
522 # if !large_memory
523 if (fcopy!=workstdout) Ozclose(&fcopy);
524 # endif
525 if (neworkptr!=workstdout) Ozclose(&neworkptr);
526 dirtempunlink();
529 #if RCS_lint
530 # define exiterr coExit
531 #endif
532 void
533 exiterr()
535 ORCSerror();
536 dirtempunlink();
537 tempunlink();
538 _exit(EXIT_FAILURE);
542 /*****************************************************************
543 * The following routines are auxiliary routines
544 *****************************************************************/
546 static int
547 rmworkfile()
549 * Prepare to remove workname, if it exists, and if
550 * it is read-only.
551 * Otherwise (file writable):
552 * if !quietmode asks the user whether to really delete it (default: fail);
553 * otherwise failure.
554 * Returns true if permission is gotten.
557 if (workstat.st_mode&(S_IWUSR|S_IWGRP|S_IWOTH) && !forceflag) {
558 /* File is writable */
559 if (!yesorno(false, "writable %s exists%s; remove it? [ny](n): ",
560 workname,
561 myself(workstat.st_uid) ? "" : ", and you do not own it"
562 )) {
563 error(!quietflag && ttystdin()
564 ? "checkout aborted"
565 : "writable %s exists; checkout aborted", workname);
566 return false;
569 /* Actual unlink is done later by caller. */
570 return true;
574 static int
575 rmlock(delta)
576 struct hshentry const *delta;
577 /* Function: removes the lock held by caller on delta.
578 * Returns -1 if someone else holds the lock,
579 * 0 if there is no lock on delta,
580 * and 1 if a lock was found and removed.
582 { register struct rcslock * next, * trail;
583 char const *num;
584 struct rcslock dummy;
585 int whomatch, nummatch;
587 num=delta->num;
588 dummy.nextlock=next=Locks;
589 trail = &dummy;
590 while (next) {
591 whomatch = strcmp(getcaller(), next->login);
592 nummatch=strcmp(num,next->delta->num);
593 if ((whomatch==0) && (nummatch==0)) break;
594 /*found a lock on delta by caller*/
595 if ((whomatch!=0)&&(nummatch==0)) {
596 rcserror("revision %s locked by %s; use co -r or rcs -u",
597 num, next->login
599 return -1;
601 trail=next;
602 next=next->nextlock;
604 if (next) {
605 /*found one; delete it */
606 trail->nextlock=next->nextlock;
607 Locks=dummy.nextlock;
608 next->delta->lockedby = 0;
609 return 1; /*success*/
610 } else return 0; /*no lock on delta*/
616 /*****************************************************************
617 * The rest of the routines are for handling joins
618 *****************************************************************/
621 static char *
622 addjoin(joinrev)
623 char *joinrev;
624 /* Add joinrev's number to joinlist, yielding address of char past joinrev,
625 * or 0 if no such revision exists.
628 register char *j;
629 register struct hshentry *d;
630 char terminator;
631 struct buf numrev;
632 struct hshentries *joindeltas;
634 j = joinrev;
635 for (;;) {
636 switch (*j++) {
637 default:
638 continue;
639 case 0:
640 case ' ': case '\t': case '\n':
641 case ':': case ',': case ';':
642 break;
644 break;
646 terminator = *--j;
647 *j = 0;
648 bufautobegin(&numrev);
649 d = 0;
650 if (expandsym(joinrev, &numrev))
651 d = genrevs(numrev.string,(char*)0,(char*)0,(char*)0,&joindeltas);
652 bufautoend(&numrev);
653 *j = terminator;
654 if (d) {
655 joinlist[++lastjoin] = d->num;
656 return j;
658 return 0;
661 static int
662 preparejoin(j)
663 register char *j;
664 /* Parse join list J and place pointers to the
665 * revision numbers into joinlist.
668 lastjoin= -1;
669 for (;;) {
670 while ((*j==' ')||(*j=='\t')||(*j==',')) j++;
671 if (*j=='\0') break;
672 if (lastjoin>=joinlength-2) {
673 joinlist =
674 (joinlength *= 2) == 0
675 ? tnalloc(char const *, joinlength = 16)
676 : trealloc(char const *, joinlist, joinlength);
678 if (!(j = addjoin(j))) return false;
679 while ((*j==' ') || (*j=='\t')) j++;
680 if (*j == ':') {
681 j++;
682 while((*j==' ') || (*j=='\t')) j++;
683 if (*j!='\0') {
684 if (!(j = addjoin(j))) return false;
685 } else {
686 rcsfaterror("join pair incomplete");
688 } else {
689 if (lastjoin==0) { /* first pair */
690 /* common ancestor missing */
691 joinlist[1]=joinlist[0];
692 lastjoin=1;
693 /*derive common ancestor*/
694 if (!(joinlist[0] = getancestor(targetdelta->num,joinlist[1])))
695 return false;
696 } else {
697 rcsfaterror("join pair incomplete");
701 if (lastjoin < 1)
702 rcsfaterror("empty join");
703 return true;
708 static char const *
709 getancestor(r1, r2)
710 char const *r1, *r2;
711 /* Yield the common ancestor of r1 and r2 if successful, 0 otherwise.
712 * Work reliably only if r1 and r2 are not branch numbers.
715 static struct buf t1, t2;
717 int l1, l2, l3;
718 char const *r;
720 l1 = countnumflds(r1);
721 l2 = countnumflds(r2);
722 if ((2<l1 || 2<l2) && cmpnum(r1,r2)!=0) {
723 /* not on main trunk or identical */
724 l3 = 0;
725 while (cmpnumfld(r1, r2, l3+1)==0 && cmpnumfld(r1, r2, l3+2)==0)
726 l3 += 2;
727 /* This will terminate since r1 and r2 are not the same; see above. */
728 if (l3==0) {
729 /* no common prefix; common ancestor on main trunk */
730 VOID partialno(&t1, r1, l1>2 ? 2 : l1);
731 VOID partialno(&t2, r2, l2>2 ? 2 : l2);
732 r = cmpnum(t1.string,t2.string)<0 ? t1.string : t2.string;
733 if (cmpnum(r,r1)!=0 && cmpnum(r,r2)!=0)
734 return r;
735 } else if (cmpnumfld(r1, r2, l3+1)!=0)
736 return partialno(&t1,r1,l3);
738 rcserror("common ancestor of %s and %s undefined", r1, r2);
739 return 0;
744 static int
745 buildjoin(initialfile)
746 char const *initialfile;
747 /* Function: merge pairs of elements in joinlist into initialfile
748 * If workstdout is set, copy result to stdout.
749 * All unlinking of initialfile, rev2, and rev3 should be done by tempunlink().
752 struct buf commarg;
753 struct buf subs;
754 char const *rev2, *rev3;
755 int i;
756 char const *cov[10], *mergev[11];
757 char const **p;
759 bufautobegin(&commarg);
760 bufautobegin(&subs);
761 rev2 = maketemp(0);
762 rev3 = maketemp(3); /* buildrevision() may use 1 and 2 */
764 cov[1] = CO;
765 /* cov[2] setup below */
766 p = &cov[3];
767 if (expandarg) *p++ = expandarg;
768 if (suffixarg) *p++ = suffixarg;
769 if (versionarg) *p++ = versionarg;
770 if (zonearg) *p++ = zonearg;
771 *p++ = quietarg;
772 *p++ = RCSname;
773 *p = 0;
775 mergev[1] = MERGE;
776 mergev[2] = mergev[4] = "-L";
777 /* rest of mergev setup below */
779 i=0;
780 while (i<lastjoin) {
781 /*prepare marker for merge*/
782 if (i==0)
783 bufscpy(&subs, targetdelta->num);
784 else {
785 bufscat(&subs, ",");
786 bufscat(&subs, joinlist[i-2]);
787 bufscat(&subs, ":");
788 bufscat(&subs, joinlist[i-1]);
790 diagnose("revision %s\n",joinlist[i]);
791 bufscpy(&commarg, "-p");
792 bufscat(&commarg, joinlist[i]);
793 cov[2] = commarg.string;
794 if (runv(-1, rev2, cov))
795 goto badmerge;
796 diagnose("revision %s\n",joinlist[i+1]);
797 bufscpy(&commarg, "-p");
798 bufscat(&commarg, joinlist[i+1]);
799 cov[2] = commarg.string;
800 if (runv(-1, rev3, cov))
801 goto badmerge;
802 diagnose("merging...\n");
803 mergev[3] = subs.string;
804 mergev[5] = joinlist[i+1];
805 p = &mergev[6];
806 if (quietflag) *p++ = quietarg;
807 if (lastjoin<=i+2 && workstdout) *p++ = "-p";
808 *p++ = initialfile;
809 *p++ = rev2;
810 *p++ = rev3;
811 *p = 0;
812 switch (runv(-1, (char*)0, mergev)) {
813 case DIFF_FAILURE: case DIFF_SUCCESS:
814 break;
815 default:
816 goto badmerge;
818 i=i+2;
820 bufautoend(&commarg);
821 bufautoend(&subs);
822 return true;
824 badmerge:
825 nerror++;
826 bufautoend(&commarg);
827 bufautoend(&subs);
828 return false;