Annotation of 43BSDTahoe/new/rcs/src/rcs.c, revision 1.1

1.1     ! root        1: /*
        !             2:  *                      RCS create/change operation
        !             3:  */
        !             4: #ifndef lint
        !             5: static char rcsid[]=
        !             6: "$Header: /usr/src/local/bin/rcs/src/RCS/rcs.c,v 4.7 87/12/18 11:37:17 narten Exp $ Purdue CS";
        !             7: #endif
        !             8: /***************************************************************************
        !             9:  *                       create RCS files or change RCS file attributes
        !            10:  *                       Compatibility with release 2: define COMPAT2
        !            11:  ***************************************************************************
        !            12:  *
        !            13:  * Copyright (C) 1982 by Walter F. Tichy
        !            14:  *                       Purdue University
        !            15:  *                       Computer Science Department
        !            16:  *                       West Lafayette, IN 47907
        !            17:  *
        !            18:  * All rights reserved. No part of this software may be sold or distributed
        !            19:  * in any form or by any means without the prior written permission of the
        !            20:  * author.
        !            21:  */
        !            22: 
        !            23: 
        !            24: 
        !            25: /* $Log:       rcs.c,v $
        !            26:  * Revision 4.7  87/12/18  11:37:17  narten
        !            27:  * lint cleanups (Guy Harris)
        !            28:  * 
        !            29:  * Revision 4.6  87/10/18  10:28:48  narten
        !            30:  * Updating verison numbers. Changes relative to 1.1 are actually 
        !            31:  * relative to 4.3
        !            32:  * 
        !            33:  * Revision 1.4  87/09/24  13:58:52  narten
        !            34:  * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
        !            35:  * warnings)
        !            36:  * 
        !            37:  * Revision 1.3  87/03/27  14:21:55  jenkins
        !            38:  * Port to suns
        !            39:  * 
        !            40:  * Revision 1.2  85/12/17  13:59:09  albitz
        !            41:  * Changed setstate to rcs_setstate because of conflict with random.o.
        !            42:  * 
        !            43:  * Revision 1.1  84/01/23  14:50:09  kcs
        !            44:  * Initial revision
        !            45:  * 
        !            46:  * Revision 4.3  83/12/15  12:27:33  wft
        !            47:  * rcs -u now breaks most recent lock if it can't find a lock by the caller.
        !            48:  * 
        !            49:  * Revision 4.2  83/12/05  10:18:20  wft
        !            50:  * Added conditional compilation for sending mail.
        !            51:  * Alternatives: V4_2BSD, V6, USG, and other.
        !            52:  * 
        !            53:  * Revision 4.1  83/05/10  16:43:02  wft
        !            54:  * Simplified breaklock(); added calls to findlock() and getcaller().
        !            55:  * Added option -b (default branch). Updated -s and -w for -b.
        !            56:  * Removed calls to stat(); now done by pairfilenames().
        !            57:  * Replaced most catchints() calls with restoreints().
        !            58:  * Removed check for exit status of delivermail().
        !            59:  * Directed all interactive output to stderr.
        !            60:  * 
        !            61:  * Revision 3.9.1.1  83/12/02  22:08:51  wft
        !            62:  * Added conditional compilation for 4.2 sendmail and 4.1 delivermail.
        !            63:  * 
        !            64:  * Revision 3.9  83/02/15  15:38:39  wft
        !            65:  * Added call to fastcopy() to copy remainder of RCS file.
        !            66:  *
        !            67:  * Revision 3.8  83/01/18  17:37:51  wft
        !            68:  * Changed sendmail(): now uses delivermail, and asks whether to break the lock.
        !            69:  *
        !            70:  * Revision 3.7  83/01/15  18:04:25  wft
        !            71:  * Removed putree(); replaced with puttree() in rcssyn.c.
        !            72:  * Combined putdellog() and scanlogtext(); deleted putdellog().
        !            73:  * Cleaned up diagnostics and error messages. Fixed problem with
        !            74:  * mutilated files in case of deletions in 2 files in a single command.
        !            75:  * Changed marking of selector from 'D' to DELETE.
        !            76:  *
        !            77:  * Revision 3.6  83/01/14  15:37:31  wft
        !            78:  * Added ignoring of interrupts while new RCS file is renamed;
        !            79:  * Avoids deletion of RCS files by interrupts.
        !            80:  *
        !            81:  * Revision 3.5  82/12/10  21:11:39  wft
        !            82:  * Removed unused variables, fixed checking of return code from diff,
        !            83:  * introduced variant COMPAT2 for skipping Suffix on -A files.
        !            84:  *
        !            85:  * Revision 3.4  82/12/04  13:18:20  wft
        !            86:  * Replaced getdelta() with gettree(), changed breaklock to update
        !            87:  * field lockedby, added some diagnostics.
        !            88:  *
        !            89:  * Revision 3.3  82/12/03  17:08:04  wft
        !            90:  * Replaced getlogin() with getpwuid(), flcose() with ffclose(),
        !            91:  * /usr/ucb/Mail with macro MAIL. Removed handling of Suffix (-x).
        !            92:  * fixed -u for missing revno. Disambiguated structure members.
        !            93:  *
        !            94:  * Revision 3.2  82/10/18  21:05:07  wft
        !            95:  * rcs -i now generates a file mode given by the umask minus write permission;
        !            96:  * otherwise, rcs keeps the mode, but removes write permission.
        !            97:  * I added a check for write error, fixed call to getlogin(), replaced
        !            98:  * curdir() with getfullRCSname(), cleaned up handling -U/L, and changed
        !            99:  * conflicting, long identifiers.
        !           100:  *
        !           101:  * Revision 3.1  82/10/13  16:11:07  wft
        !           102:  * fixed type of variables receiving from getc() (char -> int).
        !           103:  */
        !           104: 
        !           105: 
        !           106: #include <sys/types.h>
        !           107: #include <sys/stat.h>
        !           108: #include "rcsbase.h"
        !           109: #ifndef lint
        !           110: static char rcsbaseid[] = RCSBASE;
        !           111: #endif
        !           112: 
        !           113: extern FILE * fopen();
        !           114: extern char * bindex();
        !           115: extern int  expandsym();                /* get numeric revision name        */
        !           116: extern struct  hshentry  * getnum();
        !           117: extern struct  lock      * addlock();   /* add a lock                       */
        !           118: extern char              * getid();
        !           119: extern char              * getkeyval();
        !           120: extern char              * Klog, *Khead, *Kaccess, *Ktext;
        !           121: #ifdef COMPAT2
        !           122: extern char * Ksuffix;
        !           123: #endif
        !           124: extern char * getcaller();              /* get login of caller              */
        !           125: extern char * malloc();
        !           126: extern struct hshentry   * genrevs();
        !           127: extern struct hshentry   * breaklock(); /* remove locks (forward)           */
        !           128: extern struct hshentry   * findlock();  /* find and remove lock             */
        !           129: extern char * checkid();                /* check an identifier              */
        !           130: extern char * getfullRCSname();         /* get full path name of RCS file   */
        !           131: extern char * mktempfile();             /* temporary file name generator    */
        !           132: extern free();
        !           133: extern void catchints();
        !           134: extern void ignoreints();
        !           135: extern int nextc;                       /* next input character             */
        !           136: extern int  nerror;                     /* counter for errors               */
        !           137: extern int  quietflag;                  /* diagnoses suppressed if true     */
        !           138: extern char curlogmsg[];                /* current log message              */
        !           139: extern char * resultfile, *editfile;    /* filename for fcopy and fedit     */
        !           140: extern FILE *fcopy;                     /* result file during editing       */
        !           141: extern FILE *fedit;                     /* edit file                        */
        !           142: extern FILE * finptr;                   /* RCS input file                   */
        !           143: extern FILE * frewrite;                 /* new RCS file                     */
        !           144: extern int    rewriteflag;              /* indicates whether input should be*/
        !           145:                                        /* echoed to frewrite               */
        !           146: 
        !           147: char * newRCSfilename, * diffilename, * cutfilename;
        !           148: char * RCSfilename, * workfilename;
        !           149: extern struct stat RCSstat, workstat; /* file status of RCS and work file   */
        !           150: extern int  haveRCSstat, haveworkstat;/* status indicators                  */
        !           151: 
        !           152: char accessorlst[strtsize];
        !           153: FILE * fcut;        /* temporary file to rebuild delta tree                 */
        !           154: int    oldumask;    /* save umask                                           */
        !           155: 
        !           156: int initflag, strictlock, strict_selected, textflag;
        !           157: char * textfile, * accessfile;
        !           158: char * caller, numrev[30];            /* caller's login;               */
        !           159: struct  access  * newaccessor,  * rmvaccessor,  * rplaccessor;
        !           160: struct  access  *curaccess,  *rmaccess;
        !           161: struct  hshentry        * gendeltas[hshsize];
        !           162: 
        !           163: struct  Lockrev {
        !           164:         char    * revno;
        !           165:         struct  Lockrev   * nextrev;
        !           166: };
        !           167: 
        !           168: struct  Symrev {
        !           169:         char    * revno;
        !           170:         char    * ssymbol;
        !           171:         int     override;
        !           172:         struct  Symrev  * nextsym;
        !           173: };
        !           174: 
        !           175: struct  Status {
        !           176:         char    * revno;
        !           177:         char    * status;
        !           178:         struct  Status  * nextstatus;
        !           179: };
        !           180: 
        !           181: struct delrevpair {
        !           182:         char    * strt;
        !           183:         char    * end;
        !           184:         int     code;
        !           185: };
        !           186: 
        !           187: struct  Lockrev * newlocklst,   * rmvlocklst;
        !           188: struct  Symrev  * assoclst,  * lastassoc;
        !           189: struct  Status  * statelst,  * laststate;
        !           190: struct  delrevpair      * delrev;
        !           191: struct  hshentry        * cuthead,  *cuttail,  * delstrt;
        !           192: char    branchnum[revlength], * branchsym;
        !           193: struct  hshentry branchdummy;
        !           194: char    command[80], * commsyml;
        !           195: char    * headstate;
        !           196: int     lockhead,unlockcaller,chgheadstate,branchflag,commentflag;
        !           197: int     delaccessflag;
        !           198: enum    stringwork {copy, edit, empty}; /* expand and edit_expand not needed */
        !           199: 
        !           200: 
        !           201: main (argc, argv)
        !           202: int argc;
        !           203: char * argv[];
        !           204: {
        !           205:         char    *comdusge;
        !           206:         int     result;
        !           207:        struct  access  *removeaccess(),  * getaccessor();
        !           208:         struct  Lockrev *rmnewlocklst();
        !           209:         struct  Lockrev *curlock,  * rmvlock, *lockpt;
        !           210:         struct  Status  * curstate;
        !           211:         struct  access    *temp, *temptr;
        !           212: 
        !           213:         nerror = 0;
        !           214:        catchints();
        !           215:         cmdid = "rcs";
        !           216:         quietflag = false;
        !           217:         comdusge ="command format:\nrcs -i -alogins -Alogins -e[logins] -b[rev] -c[commentleader] -l[rev] -u[rev] -L -U -nname[:rev] -Nname[:rev] -orange -sstate[:rev] -t[textfile] file....";
        !           218:         rplaccessor = nil;     delstrt = nil;
        !           219:         accessfile = textfile = caller = nil;
        !           220:         branchflag = commentflag = chgheadstate = false;
        !           221:         lockhead = false; unlockcaller=false;
        !           222:         initflag= textflag = false;
        !           223:         strict_selected = 0;
        !           224: 
        !           225:        caller=getcaller();
        !           226:         laststate = statelst = nil;
        !           227:         lastassoc = assoclst = nil;
        !           228:         curlock = rmvlock = newlocklst = rmvlocklst = nil;
        !           229:         curaccess = rmaccess = rmvaccessor = newaccessor = nil;
        !           230:         delaccessflag = false;
        !           231: 
        !           232:         /*  preprocessing command options    */
        !           233:         while (--argc,++argv, argc>=1 && ((*argv)[0] == '-')) {
        !           234:                 switch ((*argv)[1]) {
        !           235: 
        !           236:                 case 'i':   /*  initail version  */
        !           237:                         initflag = true;
        !           238:                         break;
        !           239: 
        !           240:                 case 'b':  /* change default branch */
        !           241:                         if (branchflag)warn("Redfinition of option -b");
        !           242:                         branchflag= true;
        !           243:                         branchsym = (*argv)+2;
        !           244:                         break;
        !           245: 
        !           246:                 case 'c':   /*  change comment symbol   */
        !           247:                         if (commentflag)warn("Redefinition of option -c");
        !           248:                         commentflag = true;
        !           249:                         commsyml = (*argv)+2;
        !           250:                         break;
        !           251: 
        !           252:                 case 'a':  /*  add new accessor   */
        !           253:                         if ( (*argv)[2] == '\0') {
        !           254:                             error("Login name missing after -a");
        !           255:                         }
        !           256:                         if ( (temp = getaccessor((*argv)+1)) ) {
        !           257:                             if ( newaccessor )
        !           258:                                 curaccess->nextaccess = temp->nextaccess;
        !           259:                             else
        !           260:                                 newaccessor = temp->nextaccess;
        !           261:                             temp->nextaccess = nil;
        !           262:                             curaccess = temp;
        !           263:                         }
        !           264:                         break;
        !           265: 
        !           266:                 case 'A':  /*  append access list according to accessfile  */
        !           267:                         if ( (*argv)[2] == '\0') {
        !           268:                             error("Missing file name after -A");
        !           269:                             break;
        !           270:                         }
        !           271:                         if ( accessfile) warn("Redefinition of option -A");
        !           272:                         *argv = *argv+2;
        !           273:                         if( pairfilenames(1, argv, true, false) > 0) {
        !           274:                             releaselst(newaccessor);
        !           275:                             newaccessor = curaccess = nil;
        !           276:                             releaselst(rmvaccessor);
        !           277:                             rmvaccessor = rmaccess = nil;
        !           278:                             accessfile = RCSfilename;
        !           279:                         }
        !           280:                         else
        !           281:                             accessfile = nil;
        !           282:                         break;
        !           283: 
        !           284:                 case 'e':    /*  remove accessors   */
        !           285:                         if ( (*argv)[2] == '\0' ) {
        !           286:                             delaccessflag = true;
        !           287:                             break;
        !           288:                         }
        !           289:                         if ( (temp = getaccessor((*argv)+1))  ) {
        !           290:                             if ( rmvaccessor )
        !           291:                                 rmaccess->nextaccess = temp->nextaccess;
        !           292:                             else
        !           293:                                 rmvaccessor = temp->nextaccess;
        !           294:                             temptr = temp->nextaccess;
        !           295:                             temp->nextaccess = nil;
        !           296:                             rmaccess = temp;
        !           297:                             while( temptr ) {
        !           298:                                 newaccessor = removeaccess(temptr,newaccessor,false);
        !           299:                                 temptr = temptr->nextaccess;
        !           300:                             }
        !           301:                             curaccess = temp = newaccessor;
        !           302:                             while( temp){
        !           303:                                 curaccess = temp;
        !           304:                                 temp = temp->nextaccess;
        !           305:                             }
        !           306:                         }
        !           307:                         break;
        !           308: 
        !           309:                 case 'l':    /*   lock a revision if it is unlocked   */
        !           310:                         if ( (*argv)[2] == '\0'){ /* lock head or def. branch */
        !           311:                             lockhead = true;
        !           312:                             break;
        !           313:                         }
        !           314:                         lockpt = (struct Lockrev *)malloc(sizeof(struct Lockrev));
        !           315:                         lockpt->revno = (*argv)+2;
        !           316:                         lockpt->nextrev = nil;
        !           317:                         if ( curlock )
        !           318:                             curlock->nextrev = lockpt;
        !           319:                         else
        !           320:                             newlocklst = lockpt;
        !           321:                         curlock = lockpt;
        !           322:                         break;
        !           323: 
        !           324:                 case 'u':   /*  release lock of a locked revision   */
        !           325:                         if ( (*argv)[2] == '\0'){ /*  unlock head  */
        !           326:                             unlockcaller=true;
        !           327:                             break;
        !           328:                         }
        !           329:                         lockpt = (struct Lockrev *)malloc(sizeof(struct Lockrev));
        !           330:                         lockpt->revno = (*argv)+2;
        !           331:                         lockpt->nextrev = nil;
        !           332:                         if (rmvlock)
        !           333:                             rmvlock->nextrev = lockpt;
        !           334:                         else
        !           335:                             rmvlocklst = lockpt;
        !           336:                         rmvlock = lockpt;
        !           337: 
        !           338:                         curlock = rmnewlocklst(lockpt);
        !           339:                         break;
        !           340: 
        !           341:                 case 'L':   /*  set strict locking */
        !           342:                         if (strict_selected++) {  /* Already selected L or U? */
        !           343:                           if (!strictlock)       /* Already selected -U? */
        !           344:                               warn("Option -L overrides -U");
        !           345:                         }
        !           346:                         strictlock = true;
        !           347:                         break;
        !           348: 
        !           349:                 case 'U':   /*  release strict locking */
        !           350:                         if (strict_selected++) {  /* Already selected L or U? */
        !           351:                           if (strictlock)        /* Already selected -L? */
        !           352:                               warn("Option -L overrides -U");
        !           353:                         }
        !           354:                        else
        !           355:                            strictlock = false;
        !           356:                         break;
        !           357: 
        !           358:                 case 'n':    /*  add new association: error, if name exists */
        !           359:                         if ( (*argv)[2] == '\0') {
        !           360:                             error("Missing symbolic name after -n");
        !           361:                             break;
        !           362:                         }
        !           363:                         getassoclst(false, (*argv)+1);
        !           364:                         break;
        !           365: 
        !           366:                 case 'N':   /*  add or change association   */
        !           367:                         if ( (*argv)[2] == '\0') {
        !           368:                             error("Missing symbolic name after -N");
        !           369:                             break;
        !           370:                         }
        !           371:                         getassoclst(true, (*argv)+1);
        !           372:                         break;
        !           373: 
        !           374:                 case 'o':   /*  delete revisins  */
        !           375:                         if (delrev) warn("Redefinition of option -o");
        !           376:                         if ( (*argv)[2] == '\0' ) {
        !           377:                             error("Missing revision range after -o");
        !           378:                             break;
        !           379:                         }
        !           380:                         getdelrev( (*argv)+1 );
        !           381:                         break;
        !           382: 
        !           383:                 case 's':   /*  change state attribute of a revision  */
        !           384:                         if ( (*argv)[2] == '\0') {
        !           385:                             error("State missing after -s");
        !           386:                             break;
        !           387:                         }
        !           388:                         getstates( (*argv)+1);
        !           389:                         break;
        !           390: 
        !           391:                 case 't':   /*  change descriptive text   */
        !           392:                         textflag=true;
        !           393:                         if ((*argv)[2]!='\0'){
        !           394:                                 if (textfile!=nil)warn("Redefinition of -t option");
        !           395:                                 textfile = (*argv)+2;
        !           396:                         }
        !           397:                         break;
        !           398: 
        !           399:                 case 'q':
        !           400:                         quietflag = true;
        !           401:                         break;
        !           402:                 default:
        !           403:                         faterror("Unknown option: %s\n%s", *argv, comdusge);
        !           404:                 };
        !           405:         }  /* end processing of options */
        !           406: 
        !           407:         if (argc<1) faterror("No input file\n%s", comdusge);
        !           408:         if (nerror) {   /*  exit, if any error in command options  */
        !           409:             diagnose("%s aborted",cmdid);
        !           410:             exit(1);
        !           411:         }
        !           412:         if (accessfile) /*  get replacement for access list   */
        !           413:             getrplaccess();
        !           414:         if (nerror) {
        !           415:             diagnose("%s aborted",cmdid);
        !           416:             exit(1);
        !           417:         }
        !           418: 
        !           419:         /* now handle all filenames */
        !           420:         do {
        !           421:         rewriteflag = false;
        !           422:         finptr=frewrite=NULL;
        !           423:         nerror=0;
        !           424: 
        !           425:         if ( initflag ) {
        !           426:             switch( pairfilenames(argc, argv, false, false) ) {
        !           427:                 case -1: break;        /*  not exist; ok */
        !           428:                 case  0: continue;     /*  error         */
        !           429:                 case  1: error("file %s exists already", RCSfilename);
        !           430:                          VOID fclose(finptr);
        !           431:                          continue;
        !           432:             }
        !           433:        }
        !           434:         else  {
        !           435:             switch( pairfilenames(argc, argv, true, false) ) {
        !           436:                 case -1: continue;    /*  not exist      */
        !           437:                 case  0: continue;    /*  errors         */
        !           438:                 case  1: break;       /*  file exists; ok*/
        !           439:             }
        !           440:        }
        !           441: 
        !           442: 
        !           443:         /* now RCSfilename contains the name of the RCS file, and
        !           444:          * workfilename contains the name of the working file.
        !           445:          * if !initflag, finptr contains the file descriptor for the
        !           446:          * RCS file. The admin node is initialized.
        !           447:          */
        !           448: 
        !           449:         diagnose("RCS file: %s", RCSfilename);
        !           450: 
        !           451:         if (!trydiraccess(RCSfilename))            continue; /* give up */
        !           452:         if (!initflag && !checkaccesslist(caller)) continue; /* give up */
        !           453:         if (!trysema(RCSfilename,true))            continue; /* give up */
        !           454: 
        !           455:         gettree(); /* read in delta tree */
        !           456: 
        !           457:         /*  update admin. node    */
        !           458:         if (strict_selected) StrictLocks = strictlock;
        !           459:         if (commentflag) Comment = commsyml;
        !           460: 
        !           461:         /* update default branch */
        !           462:         if (branchflag && expandsym(branchsym, branchnum)) {
        !           463:             if (countnumflds(branchnum)>0) {
        !           464:                 branchdummy.num=branchnum;
        !           465:                 Dbranch = &branchdummy;
        !           466:             } else
        !           467:                 Dbranch = nil;
        !           468:         }
        !           469: 
        !           470:         /*  update access list   */
        !           471:         if ( delaccessflag ) AccessList = nil;
        !           472:         if ( accessfile ) {
        !           473:             temp = rplaccessor;
        !           474:             while( temp ) {
        !           475:                 temptr = temp->nextaccess;
        !           476:                 if ( addnewaccess(temp) )
        !           477:                     temp->nextaccess = nil;
        !           478:                 temp = temptr;
        !           479:             }
        !           480:         }
        !           481:         temp = rmvaccessor;
        !           482:         while(temp)   {         /*  remove accessors from accesslist   */
        !           483:             AccessList = removeaccess(temp, AccessList,true);
        !           484:             temp = temp->nextaccess;
        !           485:         }
        !           486:         temp = newaccessor;
        !           487:         while( temp)  {         /*  add new accessors   */
        !           488:             temptr = temp->nextaccess;
        !           489:             if ( addnewaccess( temp ) )
        !           490:                 temp->nextaccess = nil;
        !           491:             temp = temptr;
        !           492:         }
        !           493: 
        !           494:         updateassoc();          /*  update association list   */
        !           495: 
        !           496:         updatelocks();          /*  update locks              */
        !           497: 
        !           498:         /*  update state attribution  */
        !           499:         if (chgheadstate) {
        !           500:             /* change state of default branch or head */
        !           501:             if (Dbranch==nil) {
        !           502:                 if (Head==nil)
        !           503:                      warn("Can't change states in an empty tree");
        !           504:                 else Head->state = headstate;
        !           505:             } else {
        !           506:                 rcs_setstate(Dbranch->num,headstate); /* Can't set directly */
        !           507:             }
        !           508:         }
        !           509:         curstate = statelst;
        !           510:         while( curstate ) {
        !           511:             rcs_setstate(curstate->revno,curstate->status);
        !           512:             curstate = curstate->nextstatus;
        !           513:         }
        !           514: 
        !           515:         cuthead = cuttail = nil;
        !           516:         if ( delrev && removerevs()) {
        !           517:             /*  rebuild delta tree if some deltas are deleted   */
        !           518:             if ( cuttail )
        !           519:                VOID genrevs(cuttail->num, (char *)nil,(char *)nil,
        !           520:                             (char *)nil, gendeltas);
        !           521:             buildtree();
        !           522:         }
        !           523: 
        !           524: 
        !           525:         /* prepare for rewriting the RCS file */
        !           526:         newRCSfilename=mktempfile(RCSfilename,NEWRCSFILE);
        !           527:         oldumask = umask(0222); /* turn off write bits */
        !           528:         if ((frewrite=fopen(newRCSfilename, "w"))==NULL) {
        !           529:                 VOID fclose(finptr);
        !           530:                 error("Can't open file %s",newRCSfilename);
        !           531:                 continue;
        !           532:         }
        !           533:         VOID umask(oldumask);
        !           534:         putadmin(frewrite);
        !           535:         if ( Head )
        !           536:            puttree(Head, frewrite);
        !           537:        VOID putdesc(initflag,textflag,textfile,quietflag);
        !           538:         rewriteflag = false;
        !           539: 
        !           540:         if ( Head) {
        !           541:             if (!delrev) {
        !           542:                 /* no revision deleted */
        !           543:                 fastcopy(finptr,frewrite);
        !           544:             } else {
        !           545:                 if ( cuttail )
        !           546:                     buildeltatext(gendeltas);
        !           547:                 else
        !           548:                     scanlogtext((struct hshentry *)nil,empty);
        !           549:                     /* copy rest of delta text nodes that are not deleted      */
        !           550:             }
        !           551:         }
        !           552:         ffclose(frewrite);   frewrite = NULL;
        !           553:         if ( ! nerror ) {  /*  move temporary file to RCS file if no error */
        !           554:            ignoreints();               /* ignore interrupts */
        !           555:             if(rename(newRCSfilename,RCSfilename)<0) {
        !           556:                 error("Can't create RCS file %s; saved in %s",
        !           557:                    RCSfilename, newRCSfilename);
        !           558:                 newRCSfilename[0] = '\0';  /*  avoid deletion by cleanup  */
        !           559:                 restoreints();
        !           560:                 VOID cleanup();
        !           561:                 break;
        !           562:             }
        !           563:             newRCSfilename[0]='\0'; /* avoid re-unlinking by cleanup()*/
        !           564:             /* update mode */
        !           565:             result=0;
        !           566:             if (!initflag) /* preserve mode bits */
        !           567:                 result=chmod(RCSfilename,RCSstat.st_mode & ~0222);
        !           568:             elsif (haveworkstat==0)  /* initialization, and work file exists */
        !           569:                 result=chmod(RCSfilename,workstat.st_mode & ~0222);
        !           570:             if (result<0) warn("Can't set mode of %s",RCSfilename);
        !           571: 
        !           572:             restoreints();                /* catch them all again */
        !           573:             diagnose("done");
        !           574:         } else {
        !           575:            diagnose("%s aborted; %s unchanged.",cmdid,RCSfilename);
        !           576:         }
        !           577:         } while (cleanup(),
        !           578:                  ++argv, --argc >=1);
        !           579: 
        !           580:         exit(nerror!=0);
        !           581: }       /* end of main (rcs) */
        !           582: 
        !           583: 
        !           584: 
        !           585: getassoclst(flag, sp)
        !           586: int     flag;
        !           587: char    * sp;
        !           588: /*  Function:   associate a symbolic name to a revision or branch,      */
        !           589: /*              and store in assoclst                                   */
        !           590: 
        !           591: {
        !           592:         struct   Symrev  * pt;
        !           593:         char             * temp, *temp2;
        !           594:         int                c;
        !           595: 
        !           596:         while( (c=(*++sp)) == ' ' || c == '\t' || c =='\n')  ;
        !           597:         temp = sp;
        !           598:         temp2=checkid(sp, ':');  /*  check for invalid symbolic name  */
        !           599:         sp = temp2; c = *sp;   *sp = '\0';
        !           600:         while( c == ' ' || c == '\t' || c == '\n')  c = *++sp;
        !           601: 
        !           602:         if ( c != ':' && c != '\0') {
        !           603:            error("Invalid string %s after option -n or -N",sp);
        !           604:             return;
        !           605:         }
        !           606: 
        !           607:         pt = (struct Symrev *)malloc(sizeof(struct Symrev));
        !           608:         pt->ssymbol = temp;
        !           609:         pt->override = flag;
        !           610:        if (c == '\0')  /*  delete symbol  */
        !           611:             pt->revno = nil;
        !           612:         else {
        !           613:             while( (c = *++sp) == ' ' || c == '\n' || c == '\t')  ;
        !           614:            if ( c == '\0' )
        !           615:                 pt->revno = nil;
        !           616:            else
        !           617:                 pt->revno = sp;
        !           618:         }
        !           619:         pt->nextsym = nil;
        !           620:         if (lastassoc)
        !           621:             lastassoc->nextsym = pt;
        !           622:         else
        !           623:             assoclst = pt;
        !           624:         lastassoc = pt;
        !           625:         return;
        !           626: }
        !           627: 
        !           628: 
        !           629: 
        !           630: struct access * getaccessor( sp)
        !           631: char            *sp;
        !           632: /*   Function:  get the accessor list of options -e and -a,     */
        !           633: /*              and store in curpt                              */
        !           634: 
        !           635: 
        !           636: {
        !           637:         struct  access  * curpt, * pt,  *pre;
        !           638:         char    *temp;
        !           639:         register c;
        !           640: 
        !           641:         while( ( c = *++sp) == ' ' || c == '\n' || c == '\t' || c == ',') ;
        !           642:         if ( c == '\0') {
        !           643:             error("Missing login name after option -a or -e");
        !           644:             return nil;
        !           645:         }
        !           646: 
        !           647:         curpt = pt = nil;
        !           648:         while( c != '\0') {
        !           649:                 temp=checkid(sp,',');
        !           650:                 pt = (struct access *)malloc(sizeof(struct access));
        !           651:                 pt->login = sp;
        !           652:                 if ( curpt )
        !           653:                     pre->nextaccess = pt;
        !           654:                 else
        !           655:                     curpt = pt;
        !           656:                 pt->nextaccess = curpt;
        !           657:                 pre = pt;
        !           658:                 sp = temp;    c = *sp;   *sp = '\0';
        !           659:                 while( c == ' ' || c == '\n' || c == '\t'|| c == ',')c =(*++sp);
        !           660:         }
        !           661:         return pt;
        !           662: }
        !           663: 
        !           664: 
        !           665: 
        !           666: getstates(sp)
        !           667: char    *sp;
        !           668: /*   Function:  get one state attribute and the corresponding   */
        !           669: /*              revision and store in statelst                  */
        !           670: 
        !           671: {
        !           672:         char    *temp, *temp2;
        !           673:         struct  Status  *pt;
        !           674:         register        c;
        !           675: 
        !           676:         while( (c=(*++sp)) ==' ' || c == '\t' || c == '\n')  ;
        !           677:         temp = sp;
        !           678:         temp2=checkid(sp,':');  /* check for invalid state attribute */
        !           679:         sp = temp2;   c = *sp;   *sp = '\0';
        !           680:         while( c == ' ' || c == '\t' || c == '\n' )  c = *++sp;
        !           681: 
        !           682:         if ( c == '\0' ) {  /*  change state of def. branch or Head  */
        !           683:             chgheadstate = true;
        !           684:             headstate  = temp;
        !           685:             return;
        !           686:         }
        !           687:         else if ( c != ':' ) {
        !           688:             error("Missing ':' after state in option -s");
        !           689:             return;
        !           690:         }
        !           691: 
        !           692:         while( (c = *++sp) == ' ' || c == '\t' || c == '\n')  ;
        !           693:         pt = (struct Status *)malloc(sizeof(struct Status));
        !           694:         pt->status     = temp;
        !           695:         pt->revno      = sp;
        !           696:         pt->nextstatus = nil;
        !           697:         if (laststate)
        !           698:             laststate->nextstatus = pt;
        !           699:         else
        !           700:             statelst = pt;
        !           701:         laststate = pt;
        !           702: }
        !           703: 
        !           704: 
        !           705: 
        !           706: getrplaccess()
        !           707: /*   Function : get the accesslist of the 'accessfile'  */
        !           708: /*              and place in rplaccessor                */
        !           709: {
        !           710:         register        char    *id, *nextp;
        !           711:         struct          access  *newaccess, *curaccess;
        !           712: 
        !           713:         if ( (finptr=fopen(accessfile, "r")) == NULL) {
        !           714:             faterror("Can't open file %s", accessfile);
        !           715:         }
        !           716:         Lexinit();
        !           717:         nextp = &accessorlst[0];
        !           718: 
        !           719:         if ( ! getkey(Khead)) faterror("Missing head in %s", accessfile);
        !           720:         VOID getnum();
        !           721:         if ( ! getlex(SEMI) ) serror("Missing ';' after head in %s",accessfile);
        !           722: 
        !           723: #ifdef COMPAT2
        !           724:         /* read suffix. Only in release 2 format */
        !           725:         if (getkey(Ksuffix)) {
        !           726:             if (nexttok==STRING) {
        !           727:                 readstring(); nextlex(); /*through away the suffix*/
        !           728:             } elsif(nexttok==ID) {
        !           729:                 nextlex();
        !           730:             }
        !           731:             if ( ! getlex(SEMI) ) serror("Missing ';' after suffix in %s",accessfile);
        !           732:         }
        !           733: #endif
        !           734: 
        !           735:         if (! getkey(Kaccess))fatserror("Missing access list in %s",accessfile);
        !           736:         curaccess = nil;
        !           737:         while( id =getid() ) {
        !           738:             newaccess = (struct access *)malloc(sizeof(struct access));
        !           739:             newaccess->login = nextp;
        !           740:             newaccess->nextaccess = nil;
        !           741:             while( ( *nextp++ = *id++) != '\0')  ;
        !           742:             if ( curaccess )
        !           743:                 curaccess->nextaccess = newaccess;
        !           744:             else
        !           745:                 rplaccessor = newaccess;
        !           746:             curaccess = newaccess;
        !           747:         }
        !           748:         if ( ! getlex(SEMI))serror("Missing ';' after access list in %s",accessfile);
        !           749:         return;
        !           750: }
        !           751: 
        !           752: 
        !           753: 
        !           754: getdelrev(sp)
        !           755: char    *sp;
        !           756: /*   Function:  get revision range or branch to be deleted,     */
        !           757: /*              and place in delrev                             */
        !           758: {
        !           759:         int    c;
        !           760:         struct  delrevpair      *pt;
        !           761: 
        !           762:         if (delrev) free((char *)delrev);
        !           763: 
        !           764:         pt = (struct delrevpair *)malloc(sizeof(struct delrevpair));
        !           765:         while((c = (*++sp)) == ' ' || c == '\n' || c == '\t') ;
        !           766: 
        !           767:         if ( c == '<' || c == '-' ) {  /*  -o  -rev  or <rev  */
        !           768:             while( (c = (*++sp)) == ' ' || c == '\n' || c == '\t')  ;
        !           769:             pt->strt = sp;    pt->code = 1;
        !           770:             while( c != ' ' && c != '\n' && c != '\t' && c != '\0') c =(*++sp);
        !           771:             *sp = '\0';
        !           772:             pt->end = nil;  delrev = pt;
        !           773:             return;
        !           774:         }
        !           775:         else {
        !           776:             pt->strt = sp;
        !           777:             while( c != ' ' && c != '\n' && c != '\t' && c != '\0'
        !           778:                    && c != '-' && c != '<' )  c = *++sp;
        !           779:             *sp = '\0';
        !           780:             while( c == ' ' || c == '\n' || c == '\t' )  c = *++sp;
        !           781:             if ( c == '\0' )  {  /*   -o rev or branch   */
        !           782:                 pt->end = nil;   pt->code = 0;
        !           783:                 delrev = pt;
        !           784:                 return;
        !           785:             }
        !           786:             if ( c != '-' && c != '<') {
        !           787:                 faterror("Invalid range %s %s after -o", pt->strt, sp);
        !           788:                 free((char *)pt);
        !           789:                 return;
        !           790:             }
        !           791:             while( (c = *++sp) == ' ' || c == '\n' || c == '\t')  ;
        !           792:             if ( c == '\0') {  /*  -o   rev-   or   rev<   */
        !           793:                 pt->end = nil;   pt->code = 2;
        !           794:                 delrev = pt;
        !           795:                 return;
        !           796:             }
        !           797:         }
        !           798:         /*   -o   rev1-rev2    or   rev1<rev2   */
        !           799:         pt->end = sp;  pt->code = 3;   delrev = pt;
        !           800:         while( c!= ' ' && c != '\n' && c != '\t' && c != '\0') c = *++sp;
        !           801:         *sp = '\0';
        !           802: }
        !           803: 
        !           804: 
        !           805: 
        !           806: 
        !           807: scanlogtext(delta,func)
        !           808: struct hshentry * delta; enum stringwork func;
        !           809: /* Function: Scans delta text nodes up to and including the one given
        !           810:  * by delta, or up to last one present, if delta==nil.
        !           811:  * For the one given by delta (if delta!=nil), the log message is saved into
        !           812:  * curlogmsg and the text is processed according to parameter func.
        !           813:  * Assumes the initial lexeme must be read in first.
        !           814:  * Does not advance nexttok after it is finished, except if delta==nil.
        !           815:  */
        !           816: {       struct hshentry * nextdelta;
        !           817: 
        !           818:         do {
        !           819:                 rewriteflag = false;
        !           820:                 nextlex();
        !           821:                 if (!(nextdelta=getnum())) {
        !           822:                     if(delta)
        !           823:                         faterror("Can't find delta for revision %s", delta->num);
        !           824:                     else return; /* no more delta text nodes */
        !           825:                 }
        !           826:                 if ( nextdelta->selector != DELETE) {
        !           827:                         rewriteflag = true;
        !           828:                         VOID fprintf(frewrite,DELNUMFORM,nextdelta->num,Klog);
        !           829:                 }
        !           830:                 if (!getkey(Klog) || nexttok!=STRING)
        !           831:                         serror("Missing log entry");
        !           832:                 elsif (delta==nextdelta) {
        !           833:                         VOID savestring(curlogmsg,logsize);
        !           834:                         delta->log=curlogmsg;
        !           835:                 } else {readstring();
        !           836:                         if (delta!=nil) delta->log="";
        !           837:                 }
        !           838:                 nextlex();
        !           839:                 if (!getkey(Ktext) || nexttok!=STRING)
        !           840:                         fatserror("Missing delta text");
        !           841: 
        !           842:                 if(delta==nextdelta)
        !           843:                         /* got the one we're looking for */
        !           844:                         switch (func) {
        !           845:                         case copy:      copystring();
        !           846:                                         break;
        !           847:                         case edit:      editstring((struct hshentry *)nil);
        !           848:                                         break;
        !           849:                         default:        faterror("Wrong scanlogtext");
        !           850:                         }
        !           851:                 else    readstring(); /* skip over it */
        !           852: 
        !           853:         } while (delta!=nextdelta);
        !           854: }
        !           855: 
        !           856: 
        !           857: 
        !           858: releaselst(sourcelst)
        !           859: struct  access  * sourcelst;
        !           860: /*   Function:  release the storages whose address are in sourcelst   */
        !           861: 
        !           862: {
        !           863:         struct  access  * pt;
        !           864: 
        !           865:         pt = sourcelst;
        !           866:         while(pt) {
        !           867:             free((char *)pt);
        !           868:             pt = pt->nextaccess;
        !           869:         }
        !           870: }
        !           871: 
        !           872: 
        !           873: 
        !           874: struct  Lockrev  * rmnewlocklst(which)
        !           875: struct  Lockrev  * which;
        !           876: /*   Function:  remove lock to revision which->revno form newlocklst   */
        !           877: 
        !           878: {
        !           879:         struct  Lockrev   * pt, *pre;
        !           880: 
        !           881:         while( newlocklst && (! strcmp(newlocklst->revno, which->revno))){
        !           882:             free((char *)newlocklst);
        !           883:             newlocklst = newlocklst->nextrev;
        !           884:         }
        !           885: 
        !           886:         pt = pre = newlocklst;
        !           887:         while( pt ) {
        !           888:             if ( ! strcmp(pt->revno, which->revno) ) {
        !           889:                 free((char *)pt);
        !           890:                 pt = pt->nextrev;
        !           891:                 pre->nextrev = pt;
        !           892:             }
        !           893:             else {
        !           894:                 pre = pt;
        !           895:                 pt = pt->nextrev;
        !           896:             }
        !           897:         }
        !           898:         return pre;
        !           899: }
        !           900: 
        !           901: 
        !           902: 
        !           903: struct  access  * removeaccess( who, sourcelst,flag)
        !           904: struct  access  * who, * sourcelst;
        !           905: int     flag;
        !           906: /*   Function:  remove the accessor-- who from sourcelst     */
        !           907: 
        !           908: {
        !           909:         struct  access  *pt, *pre;
        !           910: 
        !           911:         pt = sourcelst;
        !           912:         while( pt && (! strcmp(who->login, pt->login) )) {
        !           913:             free((char *)pt);
        !           914:             flag = false;
        !           915:             pt = pt->nextaccess;
        !           916:        }
        !           917:         pre = sourcelst = pt;
        !           918:         while( pt ) {
        !           919:             if ( ! strcmp(who->login, pt->login) ) {
        !           920:                free((char *)pt);
        !           921:                 flag = false;
        !           922:                 pt = pt->nextaccess;
        !           923:                 pre->nextaccess = pt;
        !           924:             }
        !           925:             else {
        !           926:                 pre = pt;
        !           927:                 pt = pt->nextaccess;
        !           928:             }
        !           929:         }
        !           930:         if ( flag ) warn("Can't remove a nonexisting accessor %s",who->login);
        !           931:         return sourcelst;
        !           932: }
        !           933: 
        !           934: 
        !           935: 
        !           936: int addnewaccess( who )
        !           937: struct  access  * who;
        !           938: /*   Function:  add new accessor-- who into AccessList    */
        !           939: 
        !           940: {
        !           941:         struct  access  *pt,  *pre;
        !           942: 
        !           943:         pre = pt = AccessList;
        !           944: 
        !           945:         while( pt ) {
        !           946:             if ( strcmp( who->login, pt->login) ) {
        !           947:                 pre = pt;
        !           948:                 pt = pt->nextaccess;
        !           949:             }
        !           950:             else
        !           951:                 return 0;
        !           952:         }
        !           953:         if ( pre == pt )
        !           954:             AccessList = who;
        !           955:         else
        !           956:             pre->nextaccess = who;
        !           957:         return 1;
        !           958: }
        !           959: 
        !           960: 
        !           961: sendmail(Delta, who)
        !           962: char    * Delta,  *who;
        !           963: /*   Function:  mail to who, informing him that his lock on delta was
        !           964:  *   broken by caller. Ask first whether to go ahead. Return false on
        !           965:  *   error or if user decides not to break the lock.
        !           966:  */
        !           967: {
        !           968:         char    * messagefile;
        !           969:         int   old1, old2, c, response;
        !           970:         FILE    * mailmess;
        !           971: 
        !           972: 
        !           973:        VOID fprintf(stderr, "Revision %s is already locked by %s.\n", Delta, who);
        !           974:         VOID fprintf(stderr, "Do you want to break the lock? [ny](n): ");
        !           975:         response=c=getchar();
        !           976:         while (!(c==EOF || c=='\n')) c=getchar();/*skip to end of line*/
        !           977:         if (response=='\n'||response=='n'||response=='N') return false;
        !           978: 
        !           979:         /* go ahead with breaking  */
        !           980:         messagefile=mktempfile("/tmp/", "RCSmailXXXXXX");
        !           981:         if ( (mailmess = fopen(messagefile, "w")) == NULL) {
        !           982:             faterror("Can't open file %s", messagefile);
        !           983:         }
        !           984: 
        !           985:        VOID fprintf(mailmess, "Subject: Broken lock on %s\n\n",bindex(RCSfilename,'/'));
        !           986:         VOID fprintf(mailmess, "Your lock on revision %s of file %s\n",Delta, getfullRCSname());
        !           987:         VOID fprintf(mailmess,"has been broken by %s for the following reason:\n",caller);
        !           988:         VOID fputs("State the reason for breaking the lock:\n", stderr);
        !           989:         VOID fputs("(terminate with ^D or single '.')\n>> ", stderr);
        !           990: 
        !           991:         old1 = '\n';    old2 = ' ';
        !           992:         for (; ;) {
        !           993:             c = getchar();
        !           994:             if ( c == EOF ) {
        !           995:                 VOID putc('\n',stderr);
        !           996:                 VOID fprintf(mailmess, "%c\n", old1);
        !           997:                 break;
        !           998:             }
        !           999:             else if ( c == '\n' && old1 == '.' && old2 == '\n')
        !          1000:                 break;
        !          1001:             else {
        !          1002:                 VOID fputc( old1, mailmess);
        !          1003:                 old2 = old1;   old1 = c;
        !          1004:                 if (c== '\n') VOID fputs(">> ", stderr);
        !          1005:             }
        !          1006:         }
        !          1007:         ffclose(mailmess);
        !          1008: 
        !          1009: #ifdef SENDMAIL
        !          1010:      VOID sprintf(command, "/usr/lib/sendmail %s < %s",who,messagefile);
        !          1011: #else
        !          1012: #    ifdef DELIVERMAIL
        !          1013:         VOID sprintf(command, "/etc/delivermail -w %s < %s",who,messagefile);
        !          1014: #    else
        !          1015:        VOID sprintf(command, "/bin/mail %s < %s",who,messagefile);
        !          1016: #    endif DELIVERMAIL
        !          1017: #endif SENDMAIL
        !          1018: 
        !          1019:         VOID system(command);
        !          1020:            /* ignore the exit status, even if delivermail unsuccessful */
        !          1021:         VOID unlink(messagefile);
        !          1022:        return(true);
        !          1023: }
        !          1024: 
        !          1025: 
        !          1026: 
        !          1027: struct hshentry * breaklock(who,delta)
        !          1028: char * who; struct hshentry * delta;
        !          1029: /* function: Finds the lock held by who on delta,
        !          1030:  * removes it, and returns a pointer to the delta.
        !          1031:  * Sends mail if a lock different from the caller's is broken.
        !          1032:  * Prints an error message and returns nil if there is no such lock or error.
        !          1033:  */
        !          1034: {
        !          1035:         register struct lock * next, * trail;
        !          1036:         char * num;
        !          1037:         struct lock dummy;
        !          1038:         int whor, numr;
        !          1039: 
        !          1040:        num=delta->num;
        !          1041:         dummy.nextlock=next=Locks;
        !          1042:         trail = &dummy;
        !          1043:         while (next!=nil) {
        !          1044:                if (num != nil)
        !          1045:                        numr = strcmp(num, next->delta->num);
        !          1046: 
        !          1047:                whor=strcmp(who,next->login);
        !          1048:                if (whor==0 && numr==0) break; /* exact match */
        !          1049:                if (numr==0 && whor !=0) {
        !          1050:                         if (!sendmail( num, next->login)){
        !          1051:                             diagnose("%s still locked by %s",num,next->login);
        !          1052:                             return nil;
        !          1053:                         } else break; /* continue after loop */
        !          1054:                 }
        !          1055:                 trail=next;
        !          1056:                 next=next->nextlock;
        !          1057:         }
        !          1058:         if (next!=nil) {
        !          1059:                 /*found one */
        !          1060:                 diagnose("%s unlocked",next->delta->num);
        !          1061:                 trail->nextlock=next->nextlock;
        !          1062:                 next->delta->lockedby=nil;
        !          1063:                 Locks=dummy.nextlock;
        !          1064:                 return next->delta;
        !          1065:         } else  {
        !          1066:                error("no lock set on revision %s", num);
        !          1067:                 return nil;
        !          1068:         }
        !          1069: }
        !          1070: 
        !          1071: 
        !          1072: 
        !          1073: struct hshentry *searchcutpt(object, length, store)
        !          1074: char    * object;
        !          1075: int     length;
        !          1076: struct  hshentry   * * store;
        !          1077: /*   Function:  Search store and return entry with number being object. */
        !          1078: /*              cuttail = nil, if the entry is Head; otherwise, cuttail */
        !          1079: /*              is the entry point to the one with number being object  */
        !          1080: 
        !          1081: {
        !          1082:         while( compartial( (*store++)->num, object, length)  )  ;
        !          1083:         store--;
        !          1084: 
        !          1085:         if ( *store == Head)
        !          1086:             cuthead = nil;
        !          1087:         else
        !          1088:             cuthead = *(store -1);
        !          1089:         return *store;
        !          1090: }
        !          1091: 
        !          1092: 
        !          1093: 
        !          1094: int  branchpoint(strt, tail)
        !          1095: struct  hshentry        *strt,  *tail;
        !          1096: /*   Function: check whether the deltas between strt and tail  */
        !          1097: /*             are locked or branch point, return 1 if any is  */
        !          1098: /*             locked or branch point; otherwise, return 0 and */
        !          1099: /*              mark DELETE on selector                         */
        !          1100: 
        !          1101: {
        !          1102:         struct  hshentry    *pt;
        !          1103:        struct lock  *lockpt;
        !          1104:         int     flag;
        !          1105: 
        !          1106: 
        !          1107:         pt = strt;
        !          1108:         flag = false;
        !          1109:         while( pt != tail) {
        !          1110:             if ( pt->branches ){ /*  a branch point  */
        !          1111:                 flag = true;
        !          1112:                 error("Can't remove branch point %s", pt->num);
        !          1113:             }
        !          1114:            lockpt = Locks;
        !          1115:            while(lockpt && lockpt->delta != pt)
        !          1116:                lockpt = lockpt->nextlock;
        !          1117:            if ( lockpt ) {
        !          1118:                flag = true;
        !          1119:                error("Can't remove locked revision %s",pt->num);
        !          1120:            }
        !          1121:             pt = pt->next;
        !          1122:         }
        !          1123: 
        !          1124:         if ( ! flag ) {
        !          1125:             pt = strt;
        !          1126:             while( pt != tail ) {
        !          1127:                 pt->selector = DELETE;
        !          1128:                 diagnose("deleting revision %s ",pt->num);
        !          1129:                 pt = pt->next;
        !          1130:             }
        !          1131:         }
        !          1132:         return flag;
        !          1133: }
        !          1134: 
        !          1135: 
        !          1136: 
        !          1137: removerevs()
        !          1138: /*   Function:  get the revision range to be removed, and place the     */
        !          1139: /*              first revision removed in delstrt, the revision before  */
        !          1140: /*              delstrt in cuthead( nil, if delstrt is head), and the   */
        !          1141: /*              revision after the last removed revision in cuttail(nil */
        !          1142: /*              if the last is a leaf                                   */
        !          1143: 
        !          1144: {
        !          1145:         struct  hshentry    *target, *target2, * temp, *searchcutpt();
        !          1146:         int     length, flag;
        !          1147: 
        !          1148:         flag = false;
        !          1149:         if ( ! expandsym(delrev->strt, &numrev[0]) ) return 0;
        !          1150:         target = genrevs(&numrev[0], (char *)nil, (char *)nil, (char *)nil, gendeltas);
        !          1151:         if ( ! target ) return 0;
        !          1152:         if ( cmpnum(target->num, &numrev[0]) ) flag = true;
        !          1153:         length = countnumflds( &numrev[0] );
        !          1154: 
        !          1155:         if ( delrev->code == 0 ) {  /*  -o  rev    or    -o  branch   */
        !          1156:            if ( length % 2)
        !          1157:                temp=searchcutpt(target->num,length+1,gendeltas);
        !          1158:            else if (flag) {
        !          1159:                 error("Revision %s does not exist", &numrev[0]);
        !          1160:                return 0;
        !          1161:            }
        !          1162:            else
        !          1163:                temp = searchcutpt(&numrev[0],length,gendeltas);
        !          1164:            cuttail = target->next;
        !          1165:             if ( branchpoint(temp, cuttail) ) {
        !          1166:                 cuttail = nil;
        !          1167:                 return 0;
        !          1168:             }
        !          1169:             delstrt = temp;     /* first revision to be removed   */
        !          1170:             return 1;
        !          1171:         }
        !          1172: 
        !          1173:         if ( length % 2 ) {   /*  invalid branch after -o   */
        !          1174:             error("Invalid branch range %s after -o", &numrev[0]);
        !          1175:             return 0;
        !          1176:         }
        !          1177: 
        !          1178:         if ( delrev->code == 1 )  {  /*  -o  -rev   */
        !          1179:             if ( length > 2 ) {
        !          1180:                 temp = searchcutpt( target->num, length-1, gendeltas);
        !          1181:                 cuttail = target->next;
        !          1182:             }
        !          1183:             else {
        !          1184:                 temp = searchcutpt(target->num, length, gendeltas);
        !          1185:                 cuttail = target;
        !          1186:                 while( cuttail && ! cmpnumfld(target->num,cuttail->num,1) )
        !          1187:                     cuttail = cuttail->next;
        !          1188:             }
        !          1189:             if ( branchpoint(temp, cuttail) ){
        !          1190:                 cuttail = nil;
        !          1191:                 return 0;
        !          1192:             }
        !          1193:             delstrt = temp;
        !          1194:             return 1;
        !          1195:         }
        !          1196: 
        !          1197:         if ( delrev->code == 2 )  {   /*  -o  rev-   */
        !          1198:             if ( length == 2 ) {
        !          1199:                 temp = searchcutpt(target->num, 1,gendeltas);
        !          1200:                 if ( flag)
        !          1201:                     cuttail = target;
        !          1202:                 else
        !          1203:                     cuttail = target->next;
        !          1204:             }
        !          1205:             else  {
        !          1206:                 if ( flag){
        !          1207:                     cuthead = target;
        !          1208:                     if ( !(temp = target->next) ) return 0;
        !          1209:                 }
        !          1210:                 else
        !          1211:                     temp = searchcutpt(target->num, length, gendeltas);
        !          1212:                 getbranchno(temp->num, &numrev[0]);  /*  get branch number  */
        !          1213:                 target = genrevs(&numrev[0], (char *)nil, (char *)nil, (char *)nil, gendeltas);
        !          1214:             }
        !          1215:             if ( branchpoint( temp, cuttail ) ) {
        !          1216:                 cuttail = nil;
        !          1217:                 return 0;
        !          1218:             }
        !          1219:             delstrt = temp;
        !          1220:             return 1;
        !          1221:         }
        !          1222: 
        !          1223:         /*   -o   rev1-rev2   */
        !          1224:         if ( ! expandsym(delrev->end, &numrev[0])  )  return 0;
        !          1225:         if ( length != countnumflds( &numrev[0] ) ) {
        !          1226:             error("Invalid revision range %s-%s", target->num, &numrev[0]);
        !          1227:             return 0;
        !          1228:         }
        !          1229:         if ( length > 2 && compartial( &numrev[0], target->num, length-1) ) {
        !          1230:             error("Invalid revision range %s-%s", target->num, &numrev[0]);
        !          1231:             return 0;
        !          1232:         }
        !          1233: 
        !          1234:         target2 = genrevs( &numrev[0], (char *)nil, (char *)nil, (char *)nil,gendeltas);
        !          1235:         if ( ! target2 ) return 0;
        !          1236: 
        !          1237:         if ( length > 2) {  /* delete revisions on branches  */
        !          1238:             if ( cmpnum(target->num, target2->num) > 0) {
        !          1239:                 if ( cmpnum(target2->num, &numrev[0]) )
        !          1240:                     flag = true;
        !          1241:                 else
        !          1242:                     flag = false;
        !          1243:                 temp = target;
        !          1244:                 target = target2;
        !          1245:                 target2 = temp;
        !          1246:             }
        !          1247:             if ( flag ) {
        !          1248:                 if ( ! cmpnum(target->num, target2->num) ) {
        !          1249:                     error("Revisions %s-%s don't exist", delrev->strt,delrev->end);
        !          1250:                     return 0;
        !          1251:                 }
        !          1252:                 cuthead = target;
        !          1253:                 temp = target->next;
        !          1254:             }
        !          1255:             else
        !          1256:                 temp = searchcutpt(target->num, length, gendeltas);
        !          1257:             cuttail = target2->next;
        !          1258:         }
        !          1259:         else { /*  delete revisions on trunk  */
        !          1260:             if ( cmpnum( target->num, target2->num) < 0 ) {
        !          1261:                 temp = target;
        !          1262:                 target = target2;
        !          1263:                 target2 = temp;
        !          1264:             }
        !          1265:             else
        !          1266:                 if ( cmpnum(target2->num, &numrev[0]) )
        !          1267:                     flag = true;
        !          1268:                 else
        !          1269:                     flag = false;
        !          1270:             if ( flag ) {
        !          1271:                 if ( ! cmpnum(target->num, target2->num) ) {
        !          1272:                     error("Revisions %s-%s don't exist", delrev->strt, delrev->end);
        !          1273:                     return 0;
        !          1274:                 }
        !          1275:                 cuttail = target2;
        !          1276:             }
        !          1277:             else
        !          1278:                 cuttail = target2->next;
        !          1279:             temp = searchcutpt(target->num, length, gendeltas);
        !          1280:         }
        !          1281:         if ( branchpoint(temp, cuttail) )  {
        !          1282:             cuttail = nil;
        !          1283:             return 0;
        !          1284:         }
        !          1285:         delstrt = temp;
        !          1286:         return 1;
        !          1287: }
        !          1288: 
        !          1289: 
        !          1290: 
        !          1291: updateassoc()
        !          1292: /*   Function: add or delete(if revno is nil) association      */
        !          1293: /*             which is stored in assoclst                     */
        !          1294: 
        !          1295: {
        !          1296:         struct  Symrev  * curassoc;
        !          1297:        struct  assoc   * pre,  * pt;
        !          1298:         struct  hshentry    * target;
        !          1299: 
        !          1300:         /*  add new associations   */
        !          1301:         curassoc = assoclst;
        !          1302:         while( curassoc ) {
        !          1303:             if ( curassoc->revno == nil ) {  /* delete symbol  */
        !          1304:                pre = pt = Symbols;
        !          1305:                 while( pt && strcmp(pt->symbol,curassoc->ssymbol) ) {
        !          1306:                    pre = pt;
        !          1307:                    pt = pt->nextassoc;
        !          1308:                }
        !          1309:                if ( pt )
        !          1310:                    if ( pre == pt )
        !          1311:                        Symbols = pt->nextassoc;
        !          1312:                    else
        !          1313:                        pre->nextassoc = pt->nextassoc;
        !          1314:                else
        !          1315:                     warn("Can't delete nonexisting symbol %s",curassoc->ssymbol);
        !          1316:            }
        !          1317:             else if ( expandsym( curassoc->revno, &numrev[0] ) ) {
        !          1318:            /*   add symbol  */
        !          1319:                target = (struct hshentry *) malloc(sizeof(struct hshentry));
        !          1320:                target->num = &numrev[0];
        !          1321:                VOID addsymbol(target, curassoc->ssymbol, curassoc->override);
        !          1322:             }
        !          1323:             curassoc = curassoc->nextsym;
        !          1324:         }
        !          1325: 
        !          1326: }
        !          1327: 
        !          1328: 
        !          1329: 
        !          1330: updatelocks()
        !          1331: /* Function: remove lock for caller or first lock if unlockcaller==true;
        !          1332:  *           remove locks which are stored in rmvlocklst,
        !          1333:  *           add new locks which are stored in newlocklst,
        !          1334:  *           add lock for Dbranch or Head if lockhead==true.
        !          1335:  */
        !          1336: {
        !          1337:         struct  hshentry        *target;
        !          1338:         struct  Lockrev         *lockpt;
        !          1339: 
        !          1340:         if(unlockcaller == true) { /*  find lock for caller  */
        !          1341:             if ( Head ) {
        !          1342:                if (Locks) {
        !          1343:                    target=findlock(caller,true);
        !          1344:                    if (target==nil) {
        !          1345:                        breaklock(caller, Locks->delta); /* remove most recent lock */
        !          1346:                    } else {
        !          1347:                        diagnose("%s unlocked",target->num);
        !          1348:                    }
        !          1349:                } else {
        !          1350:                    warn("There are no locks set.");
        !          1351:                }
        !          1352:             } else {
        !          1353:                 warn("Can't unlock an empty tree");
        !          1354:             }
        !          1355:         }
        !          1356: 
        !          1357:         /*  remove locks which are stored in rmvlocklst   */
        !          1358:         lockpt = rmvlocklst;
        !          1359:         while( lockpt ) {
        !          1360:            if (expandsym(lockpt->revno, numrev)) {
        !          1361:                target = genrevs(numrev, (char *)nil, (char *)nil, (char *)nil, gendeltas);
        !          1362:                 if ( target )
        !          1363:                   if ( !(countnumflds(numrev)%2) && cmpnum(target->num,numrev))
        !          1364:                        error("Can't unlock nonexisting revision %s",lockpt->revno);
        !          1365:                    else
        !          1366:                         breaklock(caller, target);
        !          1367:                         /* breaklock does its own diagnose */
        !          1368:             }
        !          1369:             lockpt = lockpt->nextrev;
        !          1370:         }
        !          1371: 
        !          1372:         /*  add new locks which stored in newlocklst  */
        !          1373:         lockpt = newlocklst;
        !          1374:         while( lockpt ) {
        !          1375:             setlock(lockpt->revno,caller);
        !          1376:             lockpt = lockpt->nextrev;
        !          1377:         }
        !          1378: 
        !          1379:         if ( lockhead == true) {  /*  lock default branch or head  */
        !          1380:             if (Dbranch) {
        !          1381:                 setlock(Dbranch->num,caller);
        !          1382:             } elsif ( Head) {
        !          1383:                 if (addlock(Head, caller))
        !          1384:                     diagnose("%s locked",Head->num);
        !          1385:             } else {
        !          1386:                 warn("Can't lock an empty tree");
        !          1387:             }
        !          1388:         }
        !          1389: 
        !          1390: }
        !          1391: 
        !          1392: 
        !          1393: 
        !          1394: setlock(rev,who)
        !          1395: char * rev, * who;
        !          1396: /* Function: Given a revision or branch number, finds the correponding
        !          1397:  * delta and locks it for who.
        !          1398:  */
        !          1399: {
        !          1400:         struct  lock     *lpt;
        !          1401:         struct  hshentry *target;
        !          1402: 
        !          1403:         if (expandsym(rev, &numrev[0]) ){
        !          1404:             target = genrevs(&numrev[0],(char *) nil,(char *) nil,
        !          1405:                             (char *)nil, gendeltas);
        !          1406:             if ( target )
        !          1407:                if ( !(countnumflds(&numrev[0])%2) && cmpnum(target->num,&numrev[0]))
        !          1408:                     error("Can't lock nonexisting revision %s",numrev);
        !          1409:                else
        !          1410:                     if(lpt=addlock(target, who))
        !          1411:                         diagnose("%s locked",lpt->delta->num);
        !          1412:         }
        !          1413: }
        !          1414: 
        !          1415: 
        !          1416: 
        !          1417: rcs_setstate(rev,status)
        !          1418: char * rev, * status;
        !          1419: /* Function: Given a revision or branch number, finds the corresponding delta
        !          1420:  * and sets its state to status.
        !          1421:  */
        !          1422: {
        !          1423:         struct  hshentry *target;
        !          1424: 
        !          1425:         if ( expandsym(rev, &numrev[0]) ) {
        !          1426:             target = genrevs(&numrev[0],(char *) nil, (char *)nil,
        !          1427:                             (char *) nil, gendeltas);
        !          1428:             if ( target )
        !          1429:                if ( !(countnumflds(&numrev[0])%2) && cmpnum(target->num, &numrev[0]) )
        !          1430:                     error("Can't set state of nonexisting revision %s to %s",
        !          1431:                            numrev,status);
        !          1432:                else
        !          1433:                     target->state = status;
        !          1434:         }
        !          1435: }
        !          1436: 
        !          1437: 
        !          1438: 
        !          1439: 
        !          1440: 
        !          1441: buildeltatext(deltas)
        !          1442: struct  hshentry        ** deltas;
        !          1443: /*   Function:  put the delta text on frewrite and make necessary   */
        !          1444: /*              change to delta text                                */
        !          1445: {
        !          1446:         int  i, c, exit_stats;
        !          1447: 
        !          1448:         cuttail->selector = DELETE;
        !          1449:         initeditfiles("/tmp/");
        !          1450:         scanlogtext(deltas[0], copy);
        !          1451:         i = 1;
        !          1452:         if ( cuthead )  {
        !          1453:             cutfilename=mktempfile("/tmp/", "RCScutXXXXXX");
        !          1454:             if ( (fcut = fopen(cutfilename, "w")) == NULL) {
        !          1455:                 faterror("Can't open temporary file %s", cutfilename);
        !          1456:             }
        !          1457: 
        !          1458:             while( deltas[i-1] != cuthead )  {
        !          1459:                 scanlogtext(deltas[i++], edit);
        !          1460:             }
        !          1461: 
        !          1462:             finishedit((struct hshentry *)nil);    rewind(fcopy);
        !          1463:             while( (c = getc(fcopy)) != EOF) VOID putc(c, fcut);
        !          1464:             swapeditfiles(false);
        !          1465:             ffclose(fcut);
        !          1466:         }
        !          1467: 
        !          1468:         while( deltas[i-1] != cuttail)
        !          1469:             scanlogtext(deltas[i++], edit);
        !          1470:         finishedit((struct hshentry *)nil);    ffclose(fcopy);
        !          1471: 
        !          1472:         if ( cuthead ) {
        !          1473:             diffilename=mktempfile("/tmp/", "RCSdifXXXXXX");
        !          1474:             VOID sprintf(command, "%s -n %s %s > %s", DIFF,cutfilename, resultfile, diffilename);
        !          1475:             exit_stats = system (command);
        !          1476:             if (exit_stats != 0 && exit_stats != (1 << BYTESIZ))
        !          1477:                 faterror ("diff failed");
        !          1478:             if(!putdtext(cuttail->num,curlogmsg,diffilename,frewrite)) return;
        !          1479:         }
        !          1480:         else
        !          1481:             if (!putdtext(cuttail->num,curlogmsg,resultfile,frewrite)) return;
        !          1482: 
        !          1483:         scanlogtext((struct hshentry *)nil,empty); /* read the rest of the deltas */
        !          1484: }
        !          1485: 
        !          1486: 
        !          1487: 
        !          1488: buildtree()
        !          1489: /*   Function:  actually removes revisions whose selector field  */
        !          1490: /*              is DELETE, and rebuilds  the linkage of deltas.  */
        !          1491: /*              asks for reconfirmation if deleting last revision*/
        !          1492: {
        !          1493:        int c,  response;
        !          1494: 
        !          1495:        struct  hshentry   * Delta;
        !          1496:         struct  branchhead      *pt, *pre;
        !          1497: 
        !          1498:         if ( cuthead )
        !          1499:            if ( cuthead->next == delstrt )
        !          1500:                 cuthead->next = cuttail;
        !          1501:            else {
        !          1502:                 pre = pt = cuthead->branches;
        !          1503:                 while( pt && pt->hsh != delstrt )  {
        !          1504:                     pre = pt;
        !          1505:                     pt = pt->nextbranch;
        !          1506:                 }
        !          1507:                 if ( cuttail )
        !          1508:                     pt->hsh = cuttail;
        !          1509:                 else if ( pt == pre )
        !          1510:                     cuthead->branches = pt->nextbranch;
        !          1511:                 else
        !          1512:                     pre->nextbranch = pt->nextbranch;
        !          1513:             }
        !          1514:        else {
        !          1515:             if ( cuttail == nil && !quietflag) {
        !          1516:                 VOID fprintf(stderr,"Do you really want to delete all revisions ?[ny](n): ");
        !          1517:                c = response = getchar();
        !          1518:                while( c != EOF && c != '\n') c = getchar();
        !          1519:                 if ( response != 'y' && response != 'Y') {
        !          1520:                     diagnose("No revision deleted");
        !          1521:                    Delta = delstrt;
        !          1522:                    while( Delta) {
        !          1523:                        Delta->selector = 'S';
        !          1524:                        Delta = Delta->next;
        !          1525:                    }
        !          1526:                    return;
        !          1527:                }
        !          1528:            }
        !          1529:             Head = cuttail;
        !          1530:        }
        !          1531:         return;
        !          1532: }
        !          1533: 

unix.superglobalmegacorp.com

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