Annotation of 43BSD/contrib/rcs/src/rcs.c, revision 1.1

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

unix.superglobalmegacorp.com

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