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