|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.