Annotation of 43BSDReno/contrib/rcs/src/co.c, revision 1.1.1.1

1.1       root        1: /* Copyright (C) 1982, 1988, 1989 Walter Tichy
                      2:  * All rights reserved.
                      3:  *
                      4:  * Redistribution and use in source and binary forms are permitted
                      5:  * provided that the above copyright notice and this paragraph are
                      6:  * duplicated in all such forms and that any documentation,
                      7:  * advertising materials, and other materials related to such
                      8:  * distribution and use acknowledge that the software was developed
                      9:  * by Walter Tichy.
                     10:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
                     11:  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
                     12:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
                     13:  *
                     14:  * Report all problems and direct all questions to:
                     15:  *   [email protected]
                     16:  * 
                     17: 
                     18: 
                     19: 
                     20: 
                     21: 
                     22: 
                     23: 
                     24: */
                     25: 
                     26: /*
                     27:  *                     RCS checkout operation
                     28:  */
                     29: #ifndef lint
                     30: static char rcsid[]=
                     31: "$Header: /usr/src/local/bin/rcs/src/RCS/co.c,v 4.7 89/05/01 15:11:41 narten Exp $ Purdue CS";
                     32: #endif
                     33: /*****************************************************************************
                     34:  *                       check out revisions from RCS files
                     35:  *****************************************************************************
                     36:  */
                     37: 
                     38: 
                     39: /* $Log:       co.c,v $
                     40:  * Revision 4.7  89/05/01  15:11:41  narten
                     41:  * changed copyright header to reflect current distribution rules
                     42:  * 
                     43:  * Revision 4.6  88/11/08  12:02:31  narten
                     44:  * changes from  [email protected] (Paul Eggert)
                     45:  * 
                     46:  * Revision 4.6  88/08/09  19:12:15  eggert
                     47:  * Fix "co -d" core dump; rawdate wasn't always initialized.
                     48:  * Use execv(), not system(); fix putchar('\0') and diagnose() botches; remove lint
                     49:  * 
                     50:  * Revision 4.5  87/12/18  11:35:40  narten
                     51:  * lint cleanups (from Guy Harris)
                     52:  * 
                     53:  * Revision 4.4  87/10/18  10:20:53  narten
                     54:  * Updating version numbers changes relative to 1.1, are actually
                     55:  * relative to 4.2
                     56:  * 
                     57:  * Revision 1.3  87/09/24  13:58:30  narten
                     58:  * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
                     59:  * warnings)
                     60:  * 
                     61:  * Revision 1.2  87/03/27  14:21:38  jenkins
                     62:  * Port to suns
                     63:  * 
                     64:  * Revision 1.1  84/01/23  14:49:58  kcs
                     65:  * Initial revision
                     66:  * 
                     67:  * Revision 4.2  83/12/05  13:39:48  wft
                     68:  * made rewriteflag external.
                     69:  * 
                     70:  * Revision 4.1  83/05/10  16:52:55  wft
                     71:  * Added option -u and -f.
                     72:  * Added handling of default branch.
                     73:  * Replaced getpwuid() with getcaller().
                     74:  * Removed calls to stat(); now done by pairfilenames().
                     75:  * Changed and renamed rmoldfile() to rmworkfile().
                     76:  * Replaced catchints() calls with restoreints(), unlink()--link() with rename();
                     77:  * 
                     78:  * Revision 3.7  83/02/15  15:27:07  wft
                     79:  * Added call to fastcopy() to copy remainder of RCS file.
                     80:  *
                     81:  * Revision 3.6  83/01/15  14:37:50  wft
                     82:  * Added ignoring of interrupts while RCS file is renamed; this avoids
                     83:  * deletion of RCS files during the unlink/link window.
                     84:  *
                     85:  * Revision 3.5  82/12/08  21:40:11  wft
                     86:  * changed processing of -d to use DATEFORM; removed actual from
                     87:  * call to preparejoin; re-fixed printing of done at the end.
                     88:  *
                     89:  * Revision 3.4  82/12/04  18:40:00  wft
                     90:  * Replaced getdelta() with gettree(), SNOOPDIR with SNOOPFILE.
                     91:  * Fixed printing of "done".
                     92:  *
                     93:  * Revision 3.3  82/11/28  22:23:11  wft
                     94:  * Replaced getlogin() with getpwuid(), flcose() with ffclose(),
                     95:  * %02d with %.2d, mode generation for working file with WORKMODE.
                     96:  * Fixed nil printing. Fixed -j combined with -l and -p, and exit
                     97:  * for non-existing revisions in preparejoin().
                     98:  *
                     99:  * Revision 3.2  82/10/18  20:47:21  wft
                    100:  * Mode of working file is now maintained even for co -l, but write permission
                    101:  * is removed.
                    102:  * The working file inherits its mode from the RCS file, plus write permission
                    103:  * for the owner. The write permission is not given if locking is strict and
                    104:  * co does not lock.
                    105:  * An existing working file without write permission is deleted automatically.
                    106:  * Otherwise, co asks (empty answer: abort co).
                    107:  * Call to getfullRCSname() added, check for write error added, call
                    108:  * for getlogin() fixed.
                    109:  *
                    110:  * Revision 3.1  82/10/13  16:01:30  wft
                    111:  * fixed type of variables receiving from getc() (char -> int).
                    112:  * removed unused variables.
                    113:  */
                    114: 
                    115: 
                    116: 
                    117: 
                    118: #include "rcsbase.h"
                    119: #include "time.h"
                    120: #include <sys/types.h>
                    121: #include <sys/stat.h>
                    122: 
                    123: #ifndef lint
                    124: static char rcsbaseid[] = RCSBASE;
                    125: #endif
                    126: static char co[] = CO;
                    127: static char merge[] = MERGE;
                    128: 
                    129: extern FILE * fopen();
                    130: extern int    rename();
                    131: extern char * getcaller();          /*get login of caller                   */
                    132: extern struct hshentry * genrevs(); /*generate delta numbers                */
                    133: extern char * getancestor();
                    134: extern int  nextc;                  /*next input character                  */
                    135: extern int  nerror;                 /*counter for errors                    */
                    136: extern char Kdesc[];               /*keyword for description               */
                    137: extern char * buildrevision();      /*constructs desired revision           */
                    138: extern int    buildjoin();          /*join several revisions                */
                    139: extern char * mktempfile();         /*temporary file name generator         */
                    140: extern struct hshentry * findlock();/*find (and delete) a lock              */
                    141: extern struct lock * addlock();     /*add a new lock                        */
                    142: extern long   maketime();           /*convert parsed time to unix time.     */
                    143: extern struct tm * localtime();     /*convert unixtime into a tm-structure  */
                    144: extern FILE * finptr;               /* RCS input file                       */
                    145: extern FILE * frewrite;             /* new RCS file                         */
                    146: extern int    rewriteflag;          /* indicates whether input should be    */
                    147:                                    /* echoed to frewrite                   */
                    148: 
                    149: char * newRCSfilename, * neworkfilename;
                    150: char * RCSfilename, * workfilename;
                    151: extern struct stat RCSstat, workstat; /* file status of RCS and work file   */
                    152: extern int  haveRCSstat, haveworkstat;/* status indicators                  */
                    153: 
                    154: char * date, * rev, * state, * author, * join;
                    155: char finaldate[datelength];
                    156: 
                    157: int forceflag, lockflag, unlockflag, tostdout;
                    158: char * caller;                        /* caller's login;                    */
                    159: extern quietflag;
                    160: 
                    161: char numericrev[revlength];           /* holds expanded revision number     */
                    162: struct hshentry * gendeltas[hshsize]; /* stores deltas to be generated      */
                    163: struct hshentry * targetdelta;        /* final delta to be generated        */
                    164: 
                    165: char * joinlist[joinlength];          /* pointers to revisions to be joined */
                    166: int lastjoin;                         /* index of last element in joinlist  */
                    167: 
                    168: main (argc, argv)
                    169: int argc;
                    170: char * argv[];
                    171: {
                    172:         int killock;                  /* indicates whether a lock is removed*/
                    173:         char * cmdusage;
                    174:         struct tm parseddate, *ftm;
                    175:         char * rawdate;
                    176:         long unixtime;
                    177: 
                    178:        catchints();
                    179:         cmdid = "co";
                    180:        cmdusage = "command format:\nco -f[rev] -l[rev] -p[rev] -q[rev] -r[rev] -ddate -sstate -w[login] -jjoinlist file ...";
                    181:         date = rev = state = author = join = nil;
                    182:        forceflag = lockflag = unlockflag = tostdout = quietflag = false;
                    183:        caller=getcaller();
                    184:        rawdate = "";
                    185: 
                    186:         while (--argc,++argv, argc>=1 && ((*argv)[0] == '-')) {
                    187:                 switch ((*argv)[1]) {
                    188: 
                    189:                 case 'r':
                    190:                 revno:  if ((*argv)[2]!='\0') {
                    191:                                 if (rev!=nil) warn("Redefinition of revision number");
                    192:                                 rev = (*argv)+2;
                    193:                         }
                    194:                         break;
                    195: 
                    196:                case 'f':
                    197:                        forceflag=true;
                    198:                        goto revno;
                    199: 
                    200:                 case 'l':
                    201:                         lockflag=true;
                    202:                         if (unlockflag) {
                    203:                                 warn("-l has precedence over -u");
                    204:                                 unlockflag=false;
                    205:                         }
                    206:                         goto revno;
                    207: 
                    208:                 case 'u':
                    209:                         unlockflag=true;
                    210:                         if (lockflag) {
                    211:                                 warn("-l has precedence over -u");
                    212:                                 unlockflag=false;
                    213:                         }
                    214:                         goto revno;
                    215: 
                    216:                 case 'p':
                    217:                         tostdout=true;
                    218:                         goto revno;
                    219: 
                    220:                 case 'q':
                    221:                         quietflag=true;
                    222:                         goto revno;
                    223: 
                    224:                 case 'd':
                    225:                         if ((*argv)[2]!='\0') {
                    226:                                 if (date!=nil) warn("Redefinition of -d option");
                    227:                                 rawdate=(*argv)+2;
                    228:                         }
                    229:                         /* process date/time */
                    230:                         if (partime(rawdate,&parseddate)==0)
                    231:                                 faterror("Can't parse date/time: %s",rawdate);
                    232:                         if ((unixtime=maketime(&parseddate))== 0L)
                    233:                                 faterror("Inconsistent date/time: %s",rawdate);
                    234:                         ftm=localtime(&unixtime);
                    235:                         VOID sprintf(finaldate,DATEFORM,
                    236:                         ftm->tm_year,ftm->tm_mon+1,ftm->tm_mday,ftm->tm_hour,ftm->tm_min,ftm->tm_sec);
                    237:                         date=finaldate;
                    238:                         break;
                    239: 
                    240:                 case 'j':
                    241:                         if ((*argv)[2]!='\0'){
                    242:                                 if (join!=nil)warn("Redefinition of -j option");
                    243:                                 join = (*argv)+2;
                    244:                         }
                    245:                         break;
                    246: 
                    247:                 case 's':
                    248:                         if ((*argv)[2]!='\0'){
                    249:                                 if (state!=nil)warn("Redefinition of -s option");
                    250:                                 state = (*argv)+2;
                    251:                         }
                    252:                         break;
                    253: 
                    254:                 case 'w':
                    255:                         if (author!=nil)warn("Redefinition of -w option");
                    256:                         if ((*argv)[2]!='\0')
                    257:                                 author = (*argv)+2;
                    258:                         else    author = caller;
                    259:                         break;
                    260: 
                    261:                 default:
                    262:                         faterror("unknown option: %s\n%s", *argv,cmdusage);
                    263: 
                    264:                 };
                    265:         } /* end of option processing */
                    266: 
                    267:         if (argc<1) faterror("No input file\n%s",cmdusage);
                    268: 
                    269:         /* now handle all filenames */
                    270:         do {
                    271:         rewriteflag=false;
                    272:         finptr=frewrite=NULL;
                    273:         neworkfilename=nil;
                    274: 
                    275:         if (!pairfilenames(argc,argv,true,tostdout)) continue;
                    276: 
                    277:         /* now RCSfilename contains the name of the RCS file, and finptr
                    278:          * the file descriptor. If tostdout is false, workfilename contains
                    279:          * the name of the working file, otherwise undefined (not nil!).
                    280:          * Also, RCSstat, workstat, and haveworkstat have been set.
                    281:          */
                    282:         diagnose("%s  -->  %s", RCSfilename,tostdout?"stdout":workfilename);
                    283: 
                    284: 
                    285:         if (!tostdout && !trydiraccess(workfilename)) continue; /* give up */
                    286:         if ((lockflag||unlockflag) && !checkaccesslist(caller)) continue;     /* give up */
                    287:         if (!trysema(RCSfilename,lockflag||unlockflag)) continue;           /* give up */
                    288: 
                    289: 
                    290:         gettree();  /* reads in the delta tree */
                    291: 
                    292:         if (Head==nil) {
                    293:                 /* no revisions; create empty file */
                    294:                 diagnose("no revisions present; generating empty revision 0.0");
                    295:                 if (!tostdout)
                    296:                         if (!creatempty()) continue;
                    297:                 /* Can't reserve a delta, so don't call addlock */
                    298:         } else {
                    299:                 if (rev!=nil) {
                    300:                         /* expand symbolic revision number */
                    301:                         if (!expandsym(rev,numericrev))
                    302:                                 continue;
                    303:                } elsif (unlockflag && (targetdelta=findlock(caller,false))!=nil) {
                    304:                        VOID strcpy(numericrev,targetdelta->num);
                    305:                 } elsif (Dbranch!=nil) {
                    306:                         VOID strcpy(numericrev,Dbranch->num);
                    307:                } else  numericrev[0]='\0'; /* empty */
                    308:                 /* get numbers of deltas to be generated */
                    309:                 if (!(targetdelta=genrevs(numericrev,date,author,state,gendeltas)))
                    310:                         continue;
                    311:                 /* check reservations */
                    312:                 if (lockflag && !addlock(targetdelta,caller))
                    313:                         continue;
                    314: 
                    315:                 if (unlockflag) {
                    316:                         if((killock=rmlock(caller,targetdelta))== -1)
                    317:                                 continue;
                    318:                 } else {
                    319:                         killock=0;
                    320:                 }
                    321: 
                    322:                 if (join && !preparejoin()) continue;
                    323: 
                    324:                diagnose("revision %s%s",targetdelta->num,
                    325:                         lockflag?" (locked)":
                    326:                         unlockflag?" (unlocked)":"");
                    327: 
                    328:                 /* remove old working file if necessary */
                    329:                 if (!tostdout)
                    330:                         if (!rmworkfile()) continue;
                    331: 
                    332:                 /* prepare for rewriting the RCS file */
                    333:                 if (lockflag||(killock==1)) {
                    334:                         newRCSfilename=mktempfile(RCSfilename,NEWRCSFILE);
                    335:                         if ((frewrite=fopen(newRCSfilename, "w"))==NULL) {
                    336:                                 error("Can't open file %s",newRCSfilename);
                    337:                                 continue;
                    338:                         }
                    339:                         putadmin(frewrite);
                    340:                         puttree(Head,frewrite);
                    341:                         VOID fprintf(frewrite, "\n\n%s%c",Kdesc,nextc);
                    342:                         rewriteflag=true;
                    343:                 }
                    344: 
                    345:                 /* skip description */
                    346:                 getdesc(false); /* don't echo*/
                    347: 
                    348:                 if (!(neworkfilename=buildrevision(gendeltas,targetdelta,
                    349:                       tostdout?(join!=nil?"/tmp/":(char *)nil):workfilename,true)))
                    350:                                 continue;
                    351: 
                    352:                 if ((lockflag||killock==1)&&nerror==0) {
                    353:                         /* rewrite the rest of the RCSfile */
                    354:                         fastcopy(finptr,frewrite);
                    355:                         ffclose(frewrite); frewrite=NULL;
                    356:                        ignoreints();
                    357:                         if (rename(newRCSfilename,RCSfilename)<0) {
                    358:                                 error("Can't rewrite %s; saved in: %s",
                    359:                                 RCSfilename, newRCSfilename);
                    360:                                 newRCSfilename[0]='\0'; /* avoid deletion*/
                    361:                                 restoreints();
                    362:                                 break;
                    363:                         }
                    364:                         newRCSfilename[0]='\0'; /* avoid re-deletion by cleanup()*/
                    365:                         if (chmod(RCSfilename,RCSstat.st_mode & ~0222)<0)
                    366:                             warn("Can't preserve mode of %s",RCSfilename);
                    367:                         restoreints();
                    368:                 }
                    369: 
                    370: #               ifdef SNOOPFILE
                    371:                 logcommand("co",targetdelta,gendeltas,caller);
                    372: #               endif
                    373: 
                    374:                 if (join) {
                    375:                         rmsema(); /* kill semaphore file so other co's can proceed */
                    376:                        if (!buildjoin(neworkfilename)) continue;
                    377:                 }
                    378:                 if (!tostdout) {
                    379:                        if (rename(neworkfilename,workfilename) <0) {
                    380:                                 error("Can't create %s; see %s",workfilename,neworkfilename);
                    381:                                 neworkfilename[0]= '\0'; /*avoid deletion*/
                    382:                                 continue;
                    383:                         }
                    384:                        neworkfilename[0]= '\0'; /*avoid re-deletion by cleanup()*/
                    385:                }
                    386:         }
                    387:        if (!tostdout)
                    388:             if (chmod(workfilename, WORKMODE(RCSstat.st_mode))<0)
                    389:                 warn("Can't adjust mode of %s",workfilename);
                    390: 
                    391: 
                    392:         if (!tostdout) diagnose("done");
                    393:         } while (cleanup(),
                    394:                  ++argv, --argc >=1);
                    395: 
                    396:         exit(nerror!=0);
                    397: 
                    398: }       /* end of main (co) */
                    399: 
                    400: 
                    401: /*****************************************************************
                    402:  * The following routines are auxiliary routines
                    403:  *****************************************************************/
                    404: 
                    405: int rmworkfile()
                    406: /* Function: unlinks workfilename, if it exists, under the following conditions:
                    407:  * If it is read-only, workfilename is unlinked.
                    408:  * Otherwise (file writable):
                    409:  *   if !quietmode asks the user whether to really delete it (default: fail);
                    410:  *   otherwise failure.
                    411:  * Returns false on failure to unlink, true otherwise.
                    412:  */
                    413: {
                    414:         int response, c;    /* holds user response to queries */
                    415: 
                    416:         if (haveworkstat< 0)      /* File doesn't exist; set by pairfilenames*/
                    417:             return (true);        /* No problem */
                    418: 
                    419:        if ((workstat.st_mode & 0222)&&!forceflag) {    /* File is writable */
                    420:             if (!quietflag) {
                    421:                 VOID fprintf(stderr,"writable %s exists; overwrite? [ny](n): ",workfilename);
                    422:                 /* must be stderr in case of IO redirect */
                    423:                 c=response=getchar();
                    424:                 while (!(c==EOF || c=='\n')) c=getchar(); /*skip rest*/
                    425:                 if (!(response=='y'||response=='Y')) {
                    426:                         warn("checkout aborted.");
                    427:                         return false;
                    428:                 }
                    429:             } else {
                    430:                 error("writable %s exists; checkout aborted.",workfilename);
                    431:                 return false;
                    432:             }
                    433:         }
                    434:        /* now unlink: either not writable, forceflag, or permission given */
                    435:         if (unlink(workfilename) != 0) {            /* Remove failed   */
                    436:             error("Can't unlink %s",workfilename);
                    437:             return false;
                    438:         }
                    439:         return true;
                    440: }
                    441: 
                    442: 
                    443: creatempty()
                    444: /* Function: creates an empty working file.
                    445:  * First, removes an existing working file with rmworkfile().
                    446:  */
                    447: {
                    448:         int  fdesc;              /* file descriptor */
                    449: 
                    450:         if (!rmworkfile()) return false;
                    451:         fdesc=creat(workfilename,0);
                    452:         if (fdesc < 0) {
                    453:                 faterror("Cannot create %s",workfilename);
                    454:                 return false;
                    455:         } else {
                    456:                 VOID close(fdesc); /* empty file */
                    457:                 return true;
                    458:         }
                    459: }
                    460: 
                    461: 
                    462: int rmlock(who,delta)
                    463: char * who; struct hshentry * delta;
                    464: /* Function: removes the lock held by who on delta.
                    465:  * Returns -1 if someone else holds the lock,
                    466:  * 0 if there is no lock on delta,
                    467:  * and 1 if a lock was found and removed.
                    468:  */
                    469: {       register struct lock * next, * trail;
                    470:         char * num;
                    471:         struct lock dummy;
                    472:         int whomatch, nummatch;
                    473: 
                    474:         num=delta->num;
                    475:         dummy.nextlock=next=Locks;
                    476:         trail = &dummy;
                    477:         while (next!=nil) {
                    478:                 whomatch=strcmp(who,next->login);
                    479:                 nummatch=strcmp(num,next->delta->num);
                    480:                 if ((whomatch==0) && (nummatch==0)) break;
                    481:                      /*found a lock on delta by who*/
                    482:                 if ((whomatch!=0)&&(nummatch==0)) {
                    483:                     error("revision %s locked by %s; use co -r or rcs -u",num,next->login);
                    484:                     return -1;
                    485:                 }
                    486:                 trail=next;
                    487:                 next=next->nextlock;
                    488:         }
                    489:         if (next!=nil) {
                    490:                 /*found one; delete it */
                    491:                 trail->nextlock=next->nextlock;
                    492:                 Locks=dummy.nextlock;
                    493:                 next->delta->lockedby=nil; /* reset locked-by */
                    494:                 return 1; /*success*/
                    495:         } else  return 0; /*no lock on delta*/
                    496: }
                    497: 
                    498: 
                    499: 
                    500: 
                    501: /*****************************************************************
                    502:  * The rest of the routines are for handling joins
                    503:  *****************************************************************/
                    504: 
                    505: char * getrev(sp, tp, buffsize)
                    506: register char * sp, *tp; int buffsize;
                    507: /* Function: copies a symbolic revision number from sp to tp,
                    508:  * appends a '\0', and returns a pointer to the character following
                    509:  * the revision number; returns nil if the revision number is more than
                    510:  * buffsize characters long.
                    511:  * The revision number is terminated by space, tab, comma, colon,
                    512:  * semicolon, newline, or '\0'.
                    513:  * used for parsing the -j option.
                    514:  */
                    515: {
                    516:         register char c;
                    517:         register int length;
                    518: 
                    519:         length = 0;
                    520:         while (((c= *sp)!=' ')&&(c!='\t')&&(c!='\n')&&(c!=':')&&(c!=',')
                    521:                 &&(c!=';')&&(c!='\0')) {
                    522:                 if (length>=buffsize) return false;
                    523:                 *tp++= *sp++;
                    524:                 length++;
                    525:         }
                    526:         *tp= '\0';
                    527:         return sp;
                    528: }
                    529: 
                    530: 
                    531: 
                    532: int preparejoin()
                    533: /* Function: Parses a join list pointed to by join and places pointers to the
                    534:  * revision numbers into joinlist.
                    535:  */
                    536: {
                    537:         struct hshentry * * joindeltas;
                    538:         struct hshentry * tmpdelta;
                    539:         register char * j;
                    540:         char symbolrev[revlength],numrev[revlength];
                    541: 
                    542:         joindeltas = (struct hshentry * *)talloc(hshsize*sizeof(struct hshentry *));
                    543:         j=join;
                    544:         lastjoin= -1;
                    545:         for (;;) {
                    546:                 while ((*j==' ')||(*j=='\t')||(*j==',')) j++;
                    547:                 if (*j=='\0') break;
                    548:                 if (lastjoin>=joinlength-2) {
                    549:                         error("too many joins");
                    550:                         return(false);
                    551:                 }
                    552:                 if(!(j=getrev(j,symbolrev,revlength))) return false;
                    553:                 if (!expandsym(symbolrev,numrev)) return false;
                    554:                 tmpdelta=genrevs(numrev,(char *)nil,(char *)nil,(char *)nil,(struct hshentry * *)joindeltas);
                    555:                 if (tmpdelta==nil)
                    556:                         return false;
                    557:                 else    joinlist[++lastjoin]=tmpdelta->num;
                    558:                 while ((*j==' ') || (*j=='\t')) j++;
                    559:                 if (*j == ':') {
                    560:                         j++;
                    561:                         while((*j==' ') || (*j=='\t')) j++;
                    562:                         if (*j!='\0') {
                    563:                                 if(!(j=getrev(j,symbolrev,revlength))) return false;
                    564:                                 if (!expandsym(symbolrev,numrev)) return false;
                    565:                                 tmpdelta=genrevs(numrev,(char *)nil,(char *)nil,(char *)nil, (struct hshentry * *) joindeltas);
                    566:                                 if (tmpdelta==nil)
                    567:                                         return false;
                    568:                                 else    joinlist[++lastjoin]=tmpdelta->num;
                    569:                         } else {
                    570:                                 error("join pair incomplete");
                    571:                                 return false;
                    572:                         }
                    573:                 } else {
                    574:                         if (lastjoin==0) { /* first pair */
                    575:                                 /* common ancestor missing */
                    576:                                 joinlist[1]=joinlist[0];
                    577:                                 lastjoin=1;
                    578:                                 /*derive common ancestor*/
                    579:                                 joinlist[0]=talloc(revlength);
                    580:                                 if (!getancestor(targetdelta->num,joinlist[1],joinlist[0]))
                    581:                                        return false;
                    582:                         } else {
                    583:                                 error("join pair incomplete");
                    584:                                 return false;
                    585:                         }
                    586:                 }
                    587:         }
                    588:         if (lastjoin<1) {
                    589:                 error("empty join");
                    590:                 return false;
                    591:         } else  return true;
                    592: }
                    593: 
                    594: 
                    595: 
                    596: buildjoin(initialfile)
                    597: char * initialfile;
                    598: /* Function: merge pairs of elements in joinlist into initialfile
                    599:  * If tostdout==true, copy result to stdout.
                    600:  * All unlinking of initialfile, rev2, and rev3 should be done by cleanup().
                    601:  */
                    602: {
                    603:        char commarg[revlength+3];
                    604:         char subs[revlength];
                    605:         char * rev2, * rev3;
                    606:         int i;
                    607: 
                    608:         rev2=mktempfile("/tmp/",JOINFIL2);
                    609:         rev3=mktempfile("/tmp/",JOINFIL3);
                    610: 
                    611:         i=0;
                    612:         while (i<lastjoin) {
                    613:                 /*prepare marker for merge*/
                    614:                 if (i==0)
                    615:                         VOID strcpy(subs,targetdelta->num);
                    616:                 else    VOID sprintf(subs, "merge%d",i/2);
                    617:                 diagnose("revision %s",joinlist[i]);
                    618:                 VOID sprintf(commarg,"-p%s",joinlist[i]);
                    619:                 if (run((char*)nil,rev2, co,commarg,"-q",RCSfilename,(char*)nil)) {
                    620:                         nerror++;return false;
                    621:                 }
                    622:                 diagnose("revision %s",joinlist[i+1]);
                    623:                 VOID sprintf(commarg,"-p%s",joinlist[i+1]);
                    624:                 if (run((char *)nil,rev3, co,commarg,"-q",RCSfilename,(char*)nil)) {
                    625:                         nerror++; return false;
                    626:                 }
                    627:                 diagnose("merging...");
                    628:                if (
                    629:                         (i+2)>=lastjoin && tostdout
                    630:                    ?   run((char*)nil,(char*)nil, merge,"-p",initialfile,rev2,rev3,subs,joinlist[i+1],(char*)nil)
                    631:                    :   run((char*)nil,(char*)nil, merge,     initialfile,rev2,rev3,subs,joinlist[i+1],(char*)nil)) {
                    632:                         nerror++; return false;
                    633:                 }
                    634:                 i=i+2;
                    635:         }
                    636:         return true;
                    637: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.