Annotation of 43BSD/contrib/rcs/src/rcs.c, revision 1.1.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.