111894Speter/* Print log messages and other information about RCS files. */ 29Sjkh 311894Speter/* Copyright 1982, 1988, 1989 Walter Tichy 411894Speter Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert 59Sjkh Distributed under license by the Free Software Foundation, Inc. 69Sjkh 79SjkhThis file is part of RCS. 89Sjkh 99SjkhRCS is free software; you can redistribute it and/or modify 109Sjkhit under the terms of the GNU General Public License as published by 119Sjkhthe Free Software Foundation; either version 2, or (at your option) 129Sjkhany later version. 139Sjkh 149SjkhRCS is distributed in the hope that it will be useful, 159Sjkhbut WITHOUT ANY WARRANTY; without even the implied warranty of 169SjkhMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 179SjkhGNU General Public License for more details. 189Sjkh 199SjkhYou should have received a copy of the GNU General Public License 2011894Speteralong with RCS; see the file COPYING. 2111894SpeterIf not, write to the Free Software Foundation, 2211894Speter59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 239Sjkh 249SjkhReport problems and direct all questions to: 259Sjkh 269Sjkh rcs-bugs@cs.purdue.edu 279Sjkh 289Sjkh*/ 299Sjkh 3011894Speter/* 3111894Speter * Revision 5.18 1995/06/16 06:19:24 eggert 3211894Speter * Update FSF address. 338858Srgrimes * 3411894Speter * Revision 5.17 1995/06/01 16:23:43 eggert 3511894Speter * (struct rcslockers): Renamed from `struct lockers'. 3611894Speter * (getnumericrev): Return error indication instead of ignoring errors. 3711894Speter * (main): Check it. Don't use dateform. 3811894Speter * (recentdate, extdate): cmpnum -> cmpdate 391487Sphk * 4011894Speter * Revision 5.16 1994/04/13 16:30:34 eggert 4111894Speter * Fix bug; `rlog -lxxx' inverted the sense of -l. 421486Sphk * 4311894Speter * Revision 5.15 1994/03/17 14:05:48 eggert 4411894Speter * -d'<DATE' now excludes DATE; the new syntax -d'<=DATE' includes it. 4511894Speter * Emulate -V4's white space generation more precisely. 4611894Speter * Work around SVR4 stdio performance bug. Remove lint. 471485Sphk * 4811894Speter * Revision 5.14 1993/11/09 17:40:15 eggert 4911894Speter * -V now prints version on stdout and exits. 50246Snate * 5111894Speter * Revision 5.13 1993/11/03 17:42:27 eggert 5211894Speter * Add -N, -z. Ignore -T. 5311894Speter * 5411894Speter * Revision 5.12 1992/07/28 16:12:44 eggert 5511894Speter * Don't miss B.0 when handling branch B. Diagnose missing `,' in -r. 5611894Speter * Add -V. Avoid `unsigned'. Statement macro names now end in _. 5711894Speter * 5811894Speter * Revision 5.11 1992/01/24 18:44:19 eggert 5911894Speter * Don't duplicate unexpected_EOF's function. lint -> RCS_lint 6011894Speter * 6111894Speter * Revision 5.10 1992/01/06 02:42:34 eggert 6211894Speter * Update usage string. 6311894Speter * while (E) ; -> while (E) continue; 6411894Speter * 659Sjkh * Revision 5.9 1991/09/17 19:07:40 eggert 669Sjkh * Getscript() didn't uncache partial lines. 679Sjkh * 689Sjkh * Revision 5.8 1991/08/19 03:13:55 eggert 699Sjkh * Revision separator is `:', not `-'. 709Sjkh * Check for missing and duplicate logs. Tune. 719Sjkh * Permit log messages that do not end in newline (including empty logs). 729Sjkh * 739Sjkh * Revision 5.7 1991/04/21 11:58:31 eggert 749Sjkh * Add -x, RCSINIT, MS-DOS support. 759Sjkh * 769Sjkh * Revision 5.6 1991/02/26 17:07:17 eggert 779Sjkh * Survive RCS files with missing logs. 789Sjkh * strsave -> str_save (DG/UX name clash) 799Sjkh * 809Sjkh * Revision 5.5 1990/11/01 05:03:55 eggert 819Sjkh * Permit arbitrary data in logs and comment leaders. 829Sjkh * 839Sjkh * Revision 5.4 1990/10/04 06:30:22 eggert 849Sjkh * Accumulate exit status across files. 859Sjkh * 869Sjkh * Revision 5.3 1990/09/11 02:41:16 eggert 879Sjkh * Plug memory leak. 889Sjkh * 899Sjkh * Revision 5.2 1990/09/04 08:02:33 eggert 909Sjkh * Count RCS lines better. 919Sjkh * 929Sjkh * Revision 5.0 1990/08/22 08:13:48 eggert 939Sjkh * Remove compile-time limits; use malloc instead. Add setuid support. 949Sjkh * Switch to GMT. 959Sjkh * Report dates in long form, to warn about dates past 1999/12/31. 969Sjkh * Change "added/del" message to make room for the longer dates. 979Sjkh * Don't generate trailing white space. Add -V. Ansify and Posixate. 989Sjkh * 999Sjkh * Revision 4.7 89/05/01 15:13:48 narten 1009Sjkh * changed copyright header to reflect current distribution rules 1018858Srgrimes * 1029Sjkh * Revision 4.6 88/08/09 19:13:28 eggert 1039Sjkh * Check for memory exhaustion; don't access freed storage. 1049Sjkh * Shrink stdio code size; remove lint. 1058858Srgrimes * 1069Sjkh * Revision 4.5 87/12/18 11:46:38 narten 1079Sjkh * more lint cleanups (Guy Harris) 1088858Srgrimes * 1099Sjkh * Revision 4.4 87/10/18 10:41:12 narten 1109Sjkh * Updating version numbers 1119Sjkh * Changes relative to 1.1 actually relative to 4.2 1128858Srgrimes * 1139Sjkh * Revision 1.3 87/09/24 14:01:10 narten 1148858Srgrimes * Sources now pass through lint (if you ignore printf/sprintf/fprintf 1159Sjkh * warnings) 1168858Srgrimes * 1179Sjkh * Revision 1.2 87/03/27 14:22:45 jenkins 1189Sjkh * Port to suns 1198858Srgrimes * 1209Sjkh * Revision 4.2 83/12/05 09:18:09 wft 1219Sjkh * changed rewriteflag to external. 1228858Srgrimes * 1239Sjkh * Revision 4.1 83/05/11 16:16:55 wft 1249Sjkh * Added -b, updated getnumericrev() accordingly. 1259Sjkh * Replaced getpwuid() with getcaller(). 1268858Srgrimes * 1279Sjkh * Revision 3.7 83/05/11 14:24:13 wft 1289Sjkh * Added options -L and -R; 1299Sjkh * Fixed selection bug with -l on multiple files. 1309Sjkh * Fixed error on dates of the form -d'>date' (rewrote getdatepair()). 1318858Srgrimes * 1329Sjkh * Revision 3.6 82/12/24 15:57:53 wft 1339Sjkh * shortened output format. 1349Sjkh * 1359Sjkh * Revision 3.5 82/12/08 21:45:26 wft 1369Sjkh * removed call to checkaccesslist(); used DATEFORM to format all dates; 1379Sjkh * removed unused variables. 1389Sjkh * 1399Sjkh * Revision 3.4 82/12/04 13:26:25 wft 1409Sjkh * Replaced getdelta() with gettree(); removed updating of field lockedby. 1419Sjkh * 1429Sjkh * Revision 3.3 82/12/03 14:08:20 wft 1439Sjkh * Replaced getlogin with getpwuid(), %02d with %.2d, fancydate with PRINTDATE. 1449Sjkh * Fixed printing of nil, removed printing of Suffix, 1459Sjkh * added shortcut if no revisions are printed, disambiguated struct members. 1469Sjkh * 1479Sjkh * Revision 3.2 82/10/18 21:09:06 wft 1489Sjkh * call to curdir replaced with getfullRCSname(), 1499Sjkh * fixed call to getlogin(), cosmetic changes on output, 1509Sjkh * changed conflicting long identifiers. 1519Sjkh * 1529Sjkh * Revision 3.1 82/10/13 16:07:56 wft 1539Sjkh * fixed type of variables receiving from getc() (char -> int). 1549Sjkh */ 1559Sjkh 1569Sjkh 1579Sjkh 1589Sjkh#include "rcsbase.h" 1599Sjkh 16011894Speterstruct rcslockers { /* lockers in locker option; stored */ 1619Sjkh char const * login; /* lockerlist */ 16211894Speter struct rcslockers * lockerlink; 1639Sjkh } ; 1649Sjkh 1659Sjkhstruct stateattri { /* states in state option; stored in */ 1669Sjkh char const * status; /* statelist */ 1679Sjkh struct stateattri * nextstate; 1689Sjkh } ; 1699Sjkh 1709Sjkhstruct authors { /* login names in author option; */ 1719Sjkh char const * login; /* stored in authorlist */ 1729Sjkh struct authors * nextauthor; 1739Sjkh } ; 1749Sjkh 1759Sjkhstruct Revpairs{ /* revision or branch range in -r */ 17611894Speter int numfld; /* option; stored in revlist */ 1779Sjkh char const * strtrev; 1789Sjkh char const * endrev; 1799Sjkh struct Revpairs * rnext; 1809Sjkh } ; 1819Sjkh 1829Sjkhstruct Datepairs{ /* date range in -d option; stored in */ 18311894Speter struct Datepairs *dnext; 1849Sjkh char strtdate[datesize]; /* duelst and datelist */ 1859Sjkh char enddate[datesize]; 18611894Speter char ne_date; /* datelist only; distinguishes < from <= */ 1879Sjkh }; 1889Sjkh 1899Sjkhstatic char extractdelta P((struct hshentry const*)); 1909Sjkhstatic int checkrevpair P((char const*,char const*)); 19111894Speterstatic int extdate P((struct hshentry*)); 19211894Speterstatic int getnumericrev P((void)); 1939Sjkhstatic struct hshentry const *readdeltalog P((void)); 1949Sjkhstatic void cleanup P((void)); 1959Sjkhstatic void exttree P((struct hshentry*)); 1969Sjkhstatic void getauthor P((char*)); 1979Sjkhstatic void getdatepair P((char*)); 1989Sjkhstatic void getlocker P((char*)); 1999Sjkhstatic void getrevpairs P((char*)); 2009Sjkhstatic void getscript P((struct hshentry*)); 2019Sjkhstatic void getstate P((char*)); 2029Sjkhstatic void putabranch P((struct hshentry const*)); 2039Sjkhstatic void putadelta P((struct hshentry const*,struct hshentry const*,int)); 2049Sjkhstatic void putforest P((struct branchhead const*)); 2059Sjkhstatic void putree P((struct hshentry const*)); 2069Sjkhstatic void putrunk P((void)); 2079Sjkhstatic void recentdate P((struct hshentry const*,struct Datepairs*)); 2089Sjkhstatic void trunclocks P((void)); 2099Sjkh 2109Sjkhstatic char const *insDelFormat; 2119Sjkhstatic int branchflag; /*set on -b */ 2129Sjkhstatic int exitstatus; 2139Sjkhstatic int lockflag; 2149Sjkhstatic struct Datepairs *datelist, *duelst; 2159Sjkhstatic struct Revpairs *revlist, *Revlst; 2169Sjkhstatic struct authors *authorlist; 21711894Speterstatic struct rcslockers *lockerlist; 2189Sjkhstatic struct stateattri *statelist; 2199Sjkh 2209Sjkh 22150472SpetermainProg(rlogId, "rlog", "$FreeBSD$") 2229Sjkh{ 2239Sjkh static char const cmdusage[] = 22411926Speter "\nrlog usage: rlog -{bhLNRt} -v[string] -ddates -l[lockers] -r[revs] -sstates -Vn -w[logins] -xsuff -zzone file ..."; 2259Sjkh 2269Sjkh register FILE *out; 2279Sjkh char *a, **newargv; 2289Sjkh struct Datepairs *currdate; 22911894Speter char const *accessListString, *accessFormat; 2309Sjkh char const *headFormat, *symbolFormat; 2319Sjkh struct access const *curaccess; 2329Sjkh struct assoc const *curassoc; 2339Sjkh struct hshentry const *delta; 23411894Speter struct rcslock const *currlock; 2359Sjkh int descflag, selectflag; 2369Sjkh int onlylockflag; /* print only files with locks */ 23711894Speter int onlyRCSflag; /* print only RCS pathname */ 23811894Speter int pre5; 23911894Speter int shownames; 24011894Speter int revno; 24111926Speter int versionlist; 24211926Speter char *vstring; 2439Sjkh 24411894Speter descflag = selectflag = shownames = true; 24511926Speter versionlist = onlylockflag = onlyRCSflag = false; 24611926Speter vstring=0; 2479Sjkh out = stdout; 2489Sjkh suffixes = X_DEFAULT; 2499Sjkh 2509Sjkh argc = getRCSINIT(argc, argv, &newargv); 2519Sjkh argv = newargv; 2529Sjkh while (a = *++argv, 0<--argc && *a++=='-') { 2539Sjkh switch (*a++) { 2549Sjkh 2559Sjkh case 'L': 2569Sjkh onlylockflag = true; 2579Sjkh break; 2589Sjkh 25911894Speter case 'N': 26011894Speter shownames = false; 26111894Speter break; 26211894Speter 2639Sjkh case 'R': 2649Sjkh onlyRCSflag =true; 2659Sjkh break; 2669Sjkh 2679Sjkh case 'l': 2689Sjkh lockflag = true; 2699Sjkh getlocker(a); 2709Sjkh break; 2719Sjkh 2729Sjkh case 'b': 2739Sjkh branchflag = true; 2749Sjkh break; 2759Sjkh 2769Sjkh case 'r': 2779Sjkh getrevpairs(a); 2789Sjkh break; 2799Sjkh 2809Sjkh case 'd': 2819Sjkh getdatepair(a); 2829Sjkh break; 2839Sjkh 2849Sjkh case 's': 2859Sjkh getstate(a); 2869Sjkh break; 2879Sjkh 2889Sjkh case 'w': 2899Sjkh getauthor(a); 2909Sjkh break; 2919Sjkh 2929Sjkh case 'h': 2939Sjkh descflag = false; 2949Sjkh break; 2959Sjkh 2969Sjkh case 't': 2979Sjkh selectflag = false; 2989Sjkh break; 2999Sjkh 3009Sjkh case 'q': 3019Sjkh /* This has no effect; it's here for consistency. */ 3029Sjkh quietflag = true; 3039Sjkh break; 3049Sjkh 3059Sjkh case 'x': 3069Sjkh suffixes = a; 3079Sjkh break; 3089Sjkh 30911894Speter case 'z': 31011894Speter zone_set(a); 31111894Speter break; 31211894Speter 31311894Speter case 'T': 31411894Speter /* Ignore -T, so that RCSINIT can contain -T. */ 31511894Speter if (*a) 31611894Speter goto unknown; 31711894Speter break; 31811894Speter 3199Sjkh case 'V': 3209Sjkh setRCSversion(*argv); 3219Sjkh break; 3229Sjkh 32311926Speter case 'v': 32411926Speter versionlist = true; 32511926Speter vstring = a; 32611926Speter break; 32711926Speter 3289Sjkh default: 32911894Speter unknown: 33011894Speter error("unknown option: %s%s", *argv, cmdusage); 3319Sjkh 3329Sjkh }; 3339Sjkh } /* end of option processing */ 3349Sjkh 3359Sjkh if (! (descflag|selectflag)) { 3369Sjkh warn("-t overrides -h."); 3379Sjkh descflag = true; 3389Sjkh } 3399Sjkh 34011894Speter pre5 = RCSversion < VERSION(5); 34111894Speter if (pre5) { 3429Sjkh accessListString = "\naccess list: "; 3439Sjkh accessFormat = " %s"; 34411894Speter headFormat = "RCS file: %s; Working file: %s\nhead: %s%s\nbranch: %s%s\nlocks: "; 34511894Speter insDelFormat = " lines added/del: %ld/%ld"; 3469Sjkh symbolFormat = " %s: %s;"; 3479Sjkh } else { 3489Sjkh accessListString = "\naccess list:"; 3499Sjkh accessFormat = "\n\t%s"; 35011894Speter headFormat = "RCS file: %s\nWorking file: %s\nhead:%s%s\nbranch:%s%s\nlocks:%s"; 35111894Speter insDelFormat = " lines: +%ld -%ld"; 3529Sjkh symbolFormat = "\n\t%s: %s"; 3539Sjkh } 3549Sjkh 35511894Speter /* Now handle all pathnames. */ 35611894Speter if (nerror) 35711894Speter cleanup(); 35811894Speter else if (argc < 1) 35911894Speter faterror("no input file%s", cmdusage); 36011894Speter else 36111894Speter for (; 0 < argc; cleanup(), ++argv, --argc) { 3629Sjkh ffree(); 3639Sjkh 36411894Speter if (pairnames(argc, argv, rcsreadopen, true, false) <= 0) 3659Sjkh continue; 3669Sjkh 36711894Speter /* 36811894Speter * RCSname contains the name of the RCS file, 36911894Speter * and finptr the file descriptor; 37011894Speter * workname contains the name of the working file. 3719Sjkh */ 3729Sjkh 3739Sjkh /* Keep only those locks given by -l. */ 3749Sjkh if (lockflag) 3759Sjkh trunclocks(); 3769Sjkh 3779Sjkh /* do nothing if -L is given and there are no locks*/ 3789Sjkh if (onlylockflag && !Locks) 3799Sjkh continue; 3809Sjkh 38111926Speter if ( versionlist ) { 38211926Speter gettree(); 38311926Speter aprintf(out, "%s%s %s\n", vstring, workname, tiprev()); 38411926Speter continue; 38511926Speter } 38611926Speter 38711894Speter if ( onlyRCSflag ) { 38811894Speter aprintf(out, "%s\n", RCSname); 3891485Sphk continue; 3901485Sphk } 3911485Sphk 39211894Speter gettree(); 39311894Speter 39411894Speter if (!getnumericrev()) 3959Sjkh continue; 39611894Speter 39711894Speter /* 39811894Speter * Output the first character with putc, not printf. 39911894Speter * Otherwise, an SVR4 stdio bug buffers output inefficiently. 40011894Speter */ 40111894Speter aputc_('\n', out) 40211894Speter 40311894Speter /* print RCS pathname, working pathname and optional 4049Sjkh administrative information */ 4059Sjkh /* could use getfullRCSname() here, but that is very slow */ 40611894Speter aprintf(out, headFormat, RCSname, workname, 4079Sjkh Head ? " " : "", Head ? Head->num : "", 4089Sjkh Dbranch ? " " : "", Dbranch ? Dbranch : "", 4099Sjkh StrictLocks ? " strict" : "" 4109Sjkh ); 4119Sjkh currlock = Locks; 4129Sjkh while( currlock ) { 4139Sjkh aprintf(out, symbolFormat, currlock->login, 4149Sjkh currlock->delta->num); 4159Sjkh currlock = currlock->nextlock; 4169Sjkh } 41711894Speter if (StrictLocks && pre5) 41811894Speter aputs(" ; strict" + (Locks?3:0), out); 4199Sjkh 4209Sjkh aputs(accessListString, out); /* print access list */ 4219Sjkh curaccess = AccessList; 4229Sjkh while(curaccess) { 4239Sjkh aprintf(out, accessFormat, curaccess->login); 4249Sjkh curaccess = curaccess->nextaccess; 4259Sjkh } 4269Sjkh 42711894Speter if (shownames) { 42811894Speter aputs("\nsymbolic names:", out); /* print symbolic names */ 42911894Speter for (curassoc=Symbols; curassoc; curassoc=curassoc->nextassoc) 43011894Speter aprintf(out, symbolFormat, curassoc->symbol, curassoc->num); 43111894Speter } 43211894Speter if (pre5) { 43311894Speter aputs("\ncomment leader: \"", out); 43411894Speter awrite(Comment.string, Comment.size, out); 43511894Speter afputc('\"', out); 43611894Speter } 43711894Speter if (!pre5 || Expand != KEYVAL_EXPAND) 43811894Speter aprintf(out, "\nkeyword substitution: %s", 4399Sjkh expand_names[Expand] 4409Sjkh ); 4419Sjkh 44211894Speter aprintf(out, "\ntotal revisions: %d", TotalDeltas); 4439Sjkh 4449Sjkh revno = 0; 4459Sjkh 4469Sjkh if (Head && selectflag & descflag) { 4479Sjkh 4489Sjkh exttree(Head); 4499Sjkh 4509Sjkh /* get most recently date of the dates pointed by duelst */ 4519Sjkh currdate = duelst; 4529Sjkh while( currdate) { 45311894Speter VOID strcpy(currdate->strtdate, "0.0.0.0.0.0"); 4549Sjkh recentdate(Head, currdate); 4559Sjkh currdate = currdate->dnext; 4569Sjkh } 4579Sjkh 4589Sjkh revno = extdate(Head); 4599Sjkh 46011894Speter aprintf(out, ";\tselected revisions: %d", revno); 4619Sjkh } 4629Sjkh 4639Sjkh afputc('\n',out); 4649Sjkh if (descflag) { 4659Sjkh aputs("description:\n", out); 4669Sjkh getdesc(true); 4679Sjkh } 4689Sjkh if (revno) { 4699Sjkh while (! (delta = readdeltalog())->selector || --revno) 47011894Speter continue; 4719Sjkh if (delta->next && countnumflds(delta->num)==2) 4729Sjkh /* Read through delta->next to get its insertlns. */ 4739Sjkh while (readdeltalog() != delta->next) 47411894Speter continue; 4759Sjkh putrunk(); 4769Sjkh putree(Head); 4779Sjkh } 47811925Speter aputs("----------------------------\n", out); 4799Sjkh aputs("=============================================================================\n",out); 48011894Speter } 4819Sjkh Ofclose(out); 4829Sjkh exitmain(exitstatus); 4839Sjkh} 4849Sjkh 4859Sjkh static void 4869Sjkhcleanup() 4879Sjkh{ 4889Sjkh if (nerror) exitstatus = EXIT_FAILURE; 4899Sjkh Izclose(&finptr); 4909Sjkh} 4919Sjkh 49211894Speter#if RCS_lint 4939Sjkh# define exiterr rlogExit 4949Sjkh#endif 49511894Speter void 4969Sjkhexiterr() 4979Sjkh{ 4989Sjkh _exit(EXIT_FAILURE); 4999Sjkh} 5009Sjkh 5019Sjkh 5029Sjkh 5039Sjkh static void 5049Sjkhputrunk() 5059Sjkh/* function: print revisions chosen, which are in trunk */ 5069Sjkh 5079Sjkh{ 5089Sjkh register struct hshentry const *ptr; 5099Sjkh 5109Sjkh for (ptr = Head; ptr; ptr = ptr->next) 5119Sjkh putadelta(ptr, ptr->next, true); 5129Sjkh} 5139Sjkh 5149Sjkh 5159Sjkh 5169Sjkh static void 5179Sjkhputree(root) 5189Sjkh struct hshentry const *root; 5199Sjkh/* function: print delta tree (not including trunk) in reverse 5209Sjkh order on each branch */ 5219Sjkh 5229Sjkh{ 52311894Speter if (!root) return; 5249Sjkh 5259Sjkh putree(root->next); 5269Sjkh 5279Sjkh putforest(root->branches); 5289Sjkh} 5299Sjkh 5309Sjkh 5319Sjkh 5329Sjkh 5339Sjkh static void 5349Sjkhputforest(branchroot) 5359Sjkh struct branchhead const *branchroot; 5369Sjkh/* function: print branches that has the same direct ancestor */ 5379Sjkh{ 53811894Speter if (!branchroot) return; 5399Sjkh 5409Sjkh putforest(branchroot->nextbranch); 5419Sjkh 5429Sjkh putabranch(branchroot->hsh); 5439Sjkh putree(branchroot->hsh); 5449Sjkh} 5459Sjkh 5469Sjkh 5479Sjkh 5489Sjkh 5499Sjkh static void 5509Sjkhputabranch(root) 5519Sjkh struct hshentry const *root; 5529Sjkh/* function : print one branch */ 5539Sjkh 5549Sjkh{ 55511894Speter if (!root) return; 5569Sjkh 5579Sjkh putabranch(root->next); 5589Sjkh 5599Sjkh putadelta(root, root, false); 5609Sjkh} 5619Sjkh 5629Sjkh 5639Sjkh 5649Sjkh 5659Sjkh 5669Sjkh static void 5679Sjkhputadelta(node,editscript,trunk) 5689Sjkh register struct hshentry const *node, *editscript; 5699Sjkh int trunk; 5709Sjkh/* function: Print delta node if node->selector is set. */ 5719Sjkh/* editscript indicates where the editscript is stored */ 5729Sjkh/* trunk indicated whether this node is in trunk */ 5739Sjkh{ 5749Sjkh static char emptych[] = EMPTYLOG; 5759Sjkh 5769Sjkh register FILE *out; 5779Sjkh char const *s; 5789Sjkh size_t n; 5799Sjkh struct branchhead const *newbranch; 5809Sjkh struct buf branchnum; 58111894Speter char datebuf[datesize + zonelenmax]; 58211894Speter int pre5 = RCSversion < VERSION(5); 5839Sjkh 5849Sjkh if (!node->selector) 5859Sjkh return; 5869Sjkh 5879Sjkh out = stdout; 5889Sjkh aprintf(out, 58911894Speter "----------------------------\nrevision %s%s", 59011894Speter node->num, pre5 ? " " : "" 5919Sjkh ); 5929Sjkh if ( node->lockedby ) 59311894Speter aprintf(out, pre5+"\tlocked by: %s;", node->lockedby); 5949Sjkh 5959Sjkh aprintf(out, "\ndate: %s; author: %s; state: %s;", 5969Sjkh date2str(node->date, datebuf), 5979Sjkh node->author, node->state 5989Sjkh ); 5999Sjkh 6009Sjkh if ( editscript ) 6019Sjkh if(trunk) 6029Sjkh aprintf(out, insDelFormat, 6039Sjkh editscript->deletelns, editscript->insertlns); 6049Sjkh else 6059Sjkh aprintf(out, insDelFormat, 6069Sjkh editscript->insertlns, editscript->deletelns); 6079Sjkh 6089Sjkh newbranch = node->branches; 6099Sjkh if ( newbranch ) { 6109Sjkh bufautobegin(&branchnum); 6119Sjkh aputs("\nbranches:", out); 6129Sjkh while( newbranch ) { 6139Sjkh getbranchno(newbranch->hsh->num, &branchnum); 6149Sjkh aprintf(out, " %s;", branchnum.string); 6159Sjkh newbranch = newbranch->nextbranch; 6169Sjkh } 6179Sjkh bufautoend(&branchnum); 6189Sjkh } 6199Sjkh 6209Sjkh afputc('\n', out); 6219Sjkh s = node->log.string; 6229Sjkh if (!(n = node->log.size)) { 6239Sjkh s = emptych; 6249Sjkh n = sizeof(emptych)-1; 6259Sjkh } 6269Sjkh awrite(s, n, out); 6279Sjkh if (s[n-1] != '\n') 6289Sjkh afputc('\n', out); 6299Sjkh} 6309Sjkh 6319Sjkh 6329Sjkh static struct hshentry const * 6339Sjkhreaddeltalog() 6349Sjkh/* Function : get the log message and skip the text of a deltatext node. 6359Sjkh * Return the delta found. 6369Sjkh * Assumes the current lexeme is not yet in nexttok; does not 6379Sjkh * advance nexttok. 6389Sjkh */ 6399Sjkh{ 6409Sjkh register struct hshentry * Delta; 6419Sjkh struct buf logbuf; 6429Sjkh struct cbuf cb; 6439Sjkh 6449Sjkh if (eoflex()) 6459Sjkh fatserror("missing delta log"); 6469Sjkh nextlex(); 6479Sjkh if (!(Delta = getnum())) 6489Sjkh fatserror("delta number corrupted"); 6499Sjkh getkeystring(Klog); 6509Sjkh if (Delta->log.string) 6519Sjkh fatserror("duplicate delta log"); 6529Sjkh bufautobegin(&logbuf); 6539Sjkh cb = savestring(&logbuf); 6549Sjkh Delta->log = bufremember(&logbuf, cb.size); 6559Sjkh 65611894Speter ignorephrases(Ktext); 6579Sjkh getkeystring(Ktext); 6589Sjkh Delta->insertlns = Delta->deletelns = 0; 6599Sjkh if ( Delta != Head) 6609Sjkh getscript(Delta); 6619Sjkh else 6629Sjkh readstring(); 6639Sjkh return Delta; 6649Sjkh} 6659Sjkh 6669Sjkh 6679Sjkh static void 6689Sjkhgetscript(Delta) 6699Sjkhstruct hshentry * Delta; 6709Sjkh/* function: read edit script of Delta and count how many lines added */ 6719Sjkh/* and deleted in the script */ 6729Sjkh 6739Sjkh{ 6749Sjkh int ed; /* editor command */ 6759Sjkh declarecache; 6769Sjkh register RILE *fin; 6779Sjkh register int c; 67811894Speter register long i; 6799Sjkh struct diffcmd dc; 6809Sjkh 6819Sjkh fin = finptr; 6829Sjkh setupcache(fin); 6839Sjkh initdiffcmd(&dc); 6849Sjkh while (0 <= (ed = getdiffcmd(fin,true,(FILE *)0,&dc))) 6859Sjkh if (!ed) 6869Sjkh Delta->deletelns += dc.nlines; 6879Sjkh else { 6889Sjkh /* skip scripted lines */ 6899Sjkh i = dc.nlines; 6909Sjkh Delta->insertlns += i; 6919Sjkh cache(fin); 6929Sjkh do { 6939Sjkh for (;;) { 69411894Speter cacheget_(c) 6959Sjkh switch (c) { 6969Sjkh default: 6979Sjkh continue; 6989Sjkh case SDELIM: 69911894Speter cacheget_(c) 7009Sjkh if (c == SDELIM) 7019Sjkh continue; 7029Sjkh if (--i) 70311894Speter unexpected_EOF(); 7049Sjkh nextc = c; 7059Sjkh uncache(fin); 7069Sjkh return; 7079Sjkh case '\n': 7089Sjkh break; 7099Sjkh } 7109Sjkh break; 7119Sjkh } 7129Sjkh ++rcsline; 7139Sjkh } while (--i); 7149Sjkh uncache(fin); 7159Sjkh } 7169Sjkh} 7179Sjkh 7189Sjkh 7199Sjkh 7209Sjkh 7219Sjkh 7229Sjkh 7239Sjkh 7249Sjkh static void 7259Sjkhexttree(root) 7269Sjkhstruct hshentry *root; 7279Sjkh/* function: select revisions , starting with root */ 7289Sjkh 7299Sjkh{ 7309Sjkh struct branchhead const *newbranch; 7319Sjkh 73211894Speter if (!root) return; 7339Sjkh 7349Sjkh root->selector = extractdelta(root); 73511894Speter root->log.string = 0; 7369Sjkh exttree(root->next); 7379Sjkh 7389Sjkh newbranch = root->branches; 7399Sjkh while( newbranch ) { 7409Sjkh exttree(newbranch->hsh); 7419Sjkh newbranch = newbranch->nextbranch; 7429Sjkh } 7439Sjkh} 7449Sjkh 7459Sjkh 7469Sjkh 7479Sjkh 7489Sjkh static void 7499Sjkhgetlocker(argv) 7509Sjkhchar * argv; 7519Sjkh/* function : get the login names of lockers from command line */ 7529Sjkh/* and store in lockerlist. */ 7539Sjkh 7549Sjkh{ 7559Sjkh register char c; 75611894Speter struct rcslockers *newlocker; 7579Sjkh argv--; 75811894Speter while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';') 75911894Speter continue; 7609Sjkh if ( c == '\0') { 76111894Speter lockerlist = 0; 7629Sjkh return; 7639Sjkh } 7649Sjkh 7659Sjkh while( c != '\0' ) { 76611894Speter newlocker = talloc(struct rcslockers); 7679Sjkh newlocker->lockerlink = lockerlist; 7689Sjkh newlocker->login = argv; 7699Sjkh lockerlist = newlocker; 77011894Speter while ((c = *++argv) && c!=',' && c!=' ' && c!='\t' && c!='\n' && c!=';') 77111894Speter continue; 7729Sjkh *argv = '\0'; 7739Sjkh if ( c == '\0' ) return; 77411894Speter while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';') 77511894Speter continue; 7769Sjkh } 7779Sjkh} 7789Sjkh 7799Sjkh 7809Sjkh 7819Sjkh static void 7829Sjkhgetauthor(argv) 7839Sjkhchar *argv; 7849Sjkh/* function: get the author's name from command line */ 7859Sjkh/* and store in authorlist */ 7869Sjkh 7879Sjkh{ 7889Sjkh register c; 7899Sjkh struct authors * newauthor; 7909Sjkh 7919Sjkh argv--; 79211894Speter while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';') 79311894Speter continue; 7949Sjkh if ( c == '\0' ) { 7959Sjkh authorlist = talloc(struct authors); 7969Sjkh authorlist->login = getusername(false); 79711894Speter authorlist->nextauthor = 0; 7989Sjkh return; 7999Sjkh } 8009Sjkh 8019Sjkh while( c != '\0' ) { 8029Sjkh newauthor = talloc(struct authors); 8039Sjkh newauthor->nextauthor = authorlist; 8049Sjkh newauthor->login = argv; 8059Sjkh authorlist = newauthor; 80611894Speter while ((c = *++argv) && c!=',' && c!=' ' && c!='\t' && c!='\n' && c!=';') 80711894Speter continue; 8089Sjkh * argv = '\0'; 8099Sjkh if ( c == '\0') return; 81011894Speter while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';') 81111894Speter continue; 8129Sjkh } 8139Sjkh} 8149Sjkh 8159Sjkh 8169Sjkh 8179Sjkh 8189Sjkh static void 8199Sjkhgetstate(argv) 8209Sjkhchar * argv; 8219Sjkh/* function : get the states of revisions from command line */ 8229Sjkh/* and store in statelist */ 8239Sjkh 8249Sjkh{ 8259Sjkh register char c; 8269Sjkh struct stateattri *newstate; 8279Sjkh 8289Sjkh argv--; 82911894Speter while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';') 83011894Speter continue; 8319Sjkh if ( c == '\0'){ 83211894Speter error("missing state attributes after -s options"); 8339Sjkh return; 8349Sjkh } 8359Sjkh 8369Sjkh while( c != '\0' ) { 8379Sjkh newstate = talloc(struct stateattri); 8389Sjkh newstate->nextstate = statelist; 8399Sjkh newstate->status = argv; 8409Sjkh statelist = newstate; 84111894Speter while ((c = *++argv) && c!=',' && c!=' ' && c!='\t' && c!='\n' && c!=';') 84211894Speter continue; 8439Sjkh *argv = '\0'; 8449Sjkh if ( c == '\0' ) return; 84511894Speter while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';') 84611894Speter continue; 8479Sjkh } 8489Sjkh} 8499Sjkh 8509Sjkh 8519Sjkh 8529Sjkh static void 8539Sjkhtrunclocks() 8549Sjkh/* Function: Truncate the list of locks to those that are held by the */ 8559Sjkh/* id's on lockerlist. Do not truncate if lockerlist empty. */ 8569Sjkh 8579Sjkh{ 85811894Speter struct rcslockers const *plocker; 85911894Speter struct rcslock *p, **pp; 8609Sjkh 86111894Speter if (!lockerlist) return; 8629Sjkh 8639Sjkh /* shorten Locks to those contained in lockerlist */ 86411894Speter for (pp = &Locks; (p = *pp); ) 86511894Speter for (plocker = lockerlist; ; ) 86611894Speter if (strcmp(plocker->login, p->login) == 0) { 86711894Speter pp = &p->nextlock; 86811894Speter break; 86911894Speter } else if (!(plocker = plocker->lockerlink)) { 87011894Speter *pp = p->nextlock; 87111894Speter break; 87211894Speter } 8739Sjkh} 8749Sjkh 8759Sjkh 8769Sjkh 8779Sjkh static void 8789Sjkhrecentdate(root, pd) 8799Sjkh struct hshentry const *root; 8809Sjkh struct Datepairs *pd; 8819Sjkh/* function: Finds the delta that is closest to the cutoff date given by */ 8829Sjkh/* pd among the revisions selected by exttree. */ 8839Sjkh/* Successively narrows down the interval given by pd, */ 8849Sjkh/* and sets the strtdate of pd to the date of the selected delta */ 8859Sjkh{ 8869Sjkh struct branchhead const *newbranch; 8879Sjkh 88811894Speter if (!root) return; 8899Sjkh if (root->selector) { 89011894Speter if ( cmpdate(root->date, pd->strtdate) >= 0 && 89111894Speter cmpdate(root->date, pd->enddate) <= 0) 8929Sjkh VOID strcpy(pd->strtdate, root->date); 8939Sjkh } 8949Sjkh 8959Sjkh recentdate(root->next, pd); 8969Sjkh newbranch = root->branches; 8979Sjkh while( newbranch) { 8989Sjkh recentdate(newbranch->hsh, pd); 8999Sjkh newbranch = newbranch->nextbranch; 9009Sjkh } 9019Sjkh} 9029Sjkh 9039Sjkh 9049Sjkh 9059Sjkh 9069Sjkh 9079Sjkh 90811894Speter static int 9099Sjkhextdate(root) 9109Sjkhstruct hshentry * root; 9119Sjkh/* function: select revisions which are in the date range specified */ 9129Sjkh/* in duelst and datelist, start at root */ 9139Sjkh/* Yield number of revisions selected, including those already selected. */ 9149Sjkh{ 9159Sjkh struct branchhead const *newbranch; 9169Sjkh struct Datepairs const *pdate; 91711894Speter int revno, ne; 9189Sjkh 9199Sjkh if (!root) 9209Sjkh return 0; 9219Sjkh 9229Sjkh if ( datelist || duelst) { 9239Sjkh pdate = datelist; 9249Sjkh while( pdate ) { 92511894Speter ne = pdate->ne_date; 92611894Speter if ( 92711894Speter (!pdate->strtdate[0] 92811894Speter || ne <= cmpdate(root->date, pdate->strtdate)) 92911894Speter && 93011894Speter (!pdate->enddate[0] 93111894Speter || ne <= cmpdate(pdate->enddate, root->date)) 93211894Speter ) 9339Sjkh break; 9349Sjkh pdate = pdate->dnext; 9359Sjkh } 93611894Speter if (!pdate) { 9379Sjkh pdate = duelst; 9389Sjkh for (;;) { 9399Sjkh if (!pdate) { 9409Sjkh root->selector = false; 9419Sjkh break; 9429Sjkh } 94311894Speter if (cmpdate(root->date, pdate->strtdate) == 0) 9449Sjkh break; 9459Sjkh pdate = pdate->dnext; 9469Sjkh } 9479Sjkh } 9489Sjkh } 9499Sjkh revno = root->selector + extdate(root->next); 9509Sjkh 9519Sjkh newbranch = root->branches; 9529Sjkh while( newbranch ) { 9539Sjkh revno += extdate(newbranch->hsh); 9549Sjkh newbranch = newbranch->nextbranch; 9559Sjkh } 9569Sjkh return revno; 9579Sjkh} 9589Sjkh 9599Sjkh 9609Sjkh 9619Sjkh static char 9629Sjkhextractdelta(pdelta) 9639Sjkh struct hshentry const *pdelta; 9649Sjkh/* function: compare information of pdelta to the authorlist, lockerlist,*/ 9659Sjkh/* statelist, revlist and yield true if pdelta is selected. */ 9669Sjkh 9679Sjkh{ 96811894Speter struct rcslock const *plock; 9699Sjkh struct stateattri const *pstate; 9709Sjkh struct authors const *pauthor; 9719Sjkh struct Revpairs const *prevision; 97211894Speter int length; 9739Sjkh 9749Sjkh if ((pauthor = authorlist)) /* only certain authors wanted */ 9759Sjkh while (strcmp(pauthor->login, pdelta->author) != 0) 9769Sjkh if (!(pauthor = pauthor->nextauthor)) 9779Sjkh return false; 9789Sjkh if ((pstate = statelist)) /* only certain states wanted */ 9799Sjkh while (strcmp(pstate->status, pdelta->state) != 0) 9809Sjkh if (!(pstate = pstate->nextstate)) 9819Sjkh return false; 9829Sjkh if (lockflag) /* only locked revisions wanted */ 9839Sjkh for (plock = Locks; ; plock = plock->nextlock) 9849Sjkh if (!plock) 9859Sjkh return false; 9869Sjkh else if (plock->delta == pdelta) 9879Sjkh break; 9889Sjkh if ((prevision = Revlst)) /* only certain revs or branches wanted */ 9899Sjkh for (;;) { 9909Sjkh length = prevision->numfld; 9919Sjkh if ( 9929Sjkh countnumflds(pdelta->num) == length+(length&1) && 9939Sjkh 0 <= compartial(pdelta->num, prevision->strtrev, length) && 9949Sjkh 0 <= compartial(prevision->endrev, pdelta->num, length) 9959Sjkh ) 9969Sjkh break; 9979Sjkh if (!(prevision = prevision->rnext)) 9989Sjkh return false; 9999Sjkh } 10009Sjkh return true; 10019Sjkh} 10029Sjkh 10039Sjkh 10049Sjkh 10059Sjkh static void 10069Sjkhgetdatepair(argv) 10079Sjkh char * argv; 10089Sjkh/* function: get time range from command line and store in datelist if */ 10099Sjkh/* a time range specified or in duelst if a time spot specified */ 10109Sjkh 10119Sjkh{ 10129Sjkh register char c; 10139Sjkh struct Datepairs * nextdate; 10149Sjkh char const * rawdate; 10159Sjkh int switchflag; 10169Sjkh 10179Sjkh argv--; 101811894Speter while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';') 101911894Speter continue; 10209Sjkh if ( c == '\0' ) { 102111894Speter error("missing date/time after -d"); 10229Sjkh return; 10239Sjkh } 10249Sjkh 10259Sjkh while( c != '\0' ) { 10269Sjkh switchflag = false; 10279Sjkh nextdate = talloc(struct Datepairs); 10289Sjkh if ( c == '<' ) { /* case: -d <date */ 10299Sjkh c = *++argv; 103011894Speter if (!(nextdate->ne_date = c!='=')) 103111894Speter c = *++argv; 10329Sjkh (nextdate->strtdate)[0] = '\0'; 10339Sjkh } else if (c == '>') { /* case: -d'>date' */ 10349Sjkh c = *++argv; 103511894Speter if (!(nextdate->ne_date = c!='=')) 103611894Speter c = *++argv; 10379Sjkh (nextdate->enddate)[0] = '\0'; 10389Sjkh switchflag = true; 10399Sjkh } else { 10409Sjkh rawdate = argv; 10419Sjkh while( c != '<' && c != '>' && c != ';' && c != '\0') 10429Sjkh c = *++argv; 10439Sjkh *argv = '\0'; 10449Sjkh if ( c == '>' ) switchflag=true; 10459Sjkh str2date(rawdate, 10469Sjkh switchflag ? nextdate->enddate : nextdate->strtdate); 10479Sjkh if ( c == ';' || c == '\0') { /* case: -d date */ 10489Sjkh VOID strcpy(nextdate->enddate,nextdate->strtdate); 10499Sjkh nextdate->dnext = duelst; 10509Sjkh duelst = nextdate; 10519Sjkh goto end; 10529Sjkh } else { 10539Sjkh /* case: -d date< or -d date>; see switchflag */ 105411894Speter int eq = argv[1]=='='; 105511894Speter nextdate->ne_date = !eq; 105611894Speter argv += eq; 105711894Speter while ((c = *++argv) == ' ' || c=='\t' || c=='\n') 105811894Speter continue; 10599Sjkh if ( c == ';' || c == '\0') { 10609Sjkh /* second date missing */ 10619Sjkh if (switchflag) 10629Sjkh *nextdate->strtdate= '\0'; 10639Sjkh else 10649Sjkh *nextdate->enddate= '\0'; 10659Sjkh nextdate->dnext = datelist; 10669Sjkh datelist = nextdate; 10679Sjkh goto end; 10689Sjkh } 10699Sjkh } 10709Sjkh } 10719Sjkh rawdate = argv; 10729Sjkh while( c != '>' && c != '<' && c != ';' && c != '\0') 10739Sjkh c = *++argv; 10749Sjkh *argv = '\0'; 10759Sjkh str2date(rawdate, 10769Sjkh switchflag ? nextdate->strtdate : nextdate->enddate); 10779Sjkh nextdate->dnext = datelist; 10789Sjkh datelist = nextdate; 10799Sjkh end: 108011894Speter if (RCSversion < VERSION(5)) 108111894Speter nextdate->ne_date = 0; 10829Sjkh if ( c == '\0') return; 108311894Speter while ((c = *++argv) == ';' || c == ' ' || c == '\t' || c =='\n') 108411894Speter continue; 10859Sjkh } 10869Sjkh} 10879Sjkh 10889Sjkh 10899Sjkh 109011894Speter static int 10919Sjkhgetnumericrev() 10929Sjkh/* function: get the numeric name of revisions which stored in revlist */ 10939Sjkh/* and then stored the numeric names in Revlst */ 10949Sjkh/* if branchflag, also add default branch */ 10959Sjkh 10969Sjkh{ 10979Sjkh struct Revpairs * ptr, *pt; 109811894Speter int n; 10999Sjkh struct buf s, e; 11009Sjkh char const *lrev; 11019Sjkh struct buf const *rstart, *rend; 11029Sjkh 110311894Speter Revlst = 0; 11049Sjkh ptr = revlist; 11059Sjkh bufautobegin(&s); 11069Sjkh bufautobegin(&e); 11079Sjkh while( ptr ) { 11089Sjkh n = 0; 11099Sjkh rstart = &s; 11109Sjkh rend = &e; 11119Sjkh 11129Sjkh switch (ptr->numfld) { 11139Sjkh 111411894Speter case 1: /* -rREV */ 111511894Speter if (!expandsym(ptr->strtrev, &s)) 111611894Speter goto freebufs; 111711894Speter rend = &s; 111811894Speter n = countnumflds(s.string); 111911894Speter if (!n && (lrev = tiprev())) { 112011894Speter bufscpy(&s, lrev); 112111894Speter n = countnumflds(lrev); 112211894Speter } 11239Sjkh break; 11249Sjkh 112511894Speter case 2: /* -rREV: */ 112611894Speter if (!expandsym(ptr->strtrev, &s)) 112711894Speter goto freebufs; 112811894Speter bufscpy(&e, s.string); 112911894Speter n = countnumflds(s.string); 113011894Speter (n<2 ? e.string : strrchr(e.string,'.'))[0] = 0; 11319Sjkh break; 11329Sjkh 113311894Speter case 3: /* -r:REV */ 113411894Speter if (!expandsym(ptr->endrev, &e)) 113511894Speter goto freebufs; 113611894Speter if ((n = countnumflds(e.string)) < 2) 113711894Speter bufscpy(&s, ".0"); 113811894Speter else { 113911894Speter bufscpy(&s, e.string); 114011894Speter VOID strcpy(strrchr(s.string,'.'), ".0"); 114111894Speter } 11429Sjkh break; 11439Sjkh 114411894Speter default: /* -rREV1:REV2 */ 114511894Speter if (!( 11469Sjkh expandsym(ptr->strtrev, &s) 11479Sjkh && expandsym(ptr->endrev, &e) 11489Sjkh && checkrevpair(s.string, e.string) 114911894Speter )) 115011894Speter goto freebufs; 115111894Speter n = countnumflds(s.string); 115211894Speter /* Swap if out of order. */ 115311894Speter if (compartial(s.string,e.string,n) > 0) { 115411894Speter rstart = &e; 115511894Speter rend = &s; 11569Sjkh } 11579Sjkh break; 11589Sjkh } 11599Sjkh 11609Sjkh if (n) { 11619Sjkh pt = ftalloc(struct Revpairs); 11629Sjkh pt->numfld = n; 11639Sjkh pt->strtrev = fstr_save(rstart->string); 11649Sjkh pt->endrev = fstr_save(rend->string); 11659Sjkh pt->rnext = Revlst; 11669Sjkh Revlst = pt; 11679Sjkh } 11689Sjkh ptr = ptr->rnext; 11699Sjkh } 11709Sjkh /* Now take care of branchflag */ 11719Sjkh if (branchflag && (Dbranch||Head)) { 11729Sjkh pt = ftalloc(struct Revpairs); 11739Sjkh pt->strtrev = pt->endrev = 11749Sjkh Dbranch ? Dbranch : fstr_save(partialno(&s,Head->num,1)); 11759Sjkh pt->rnext=Revlst; Revlst=pt; 11769Sjkh pt->numfld = countnumflds(pt->strtrev); 11779Sjkh } 117811894Speter 117911894Speter freebufs: 11809Sjkh bufautoend(&s); 11819Sjkh bufautoend(&e); 118211894Speter return !ptr; 11839Sjkh} 11849Sjkh 11859Sjkh 11869Sjkh 11879Sjkh static int 11889Sjkhcheckrevpair(num1,num2) 11899Sjkh char const *num1, *num2; 11909Sjkh/* function: check whether num1, num2 are legal pair,i.e. 11919Sjkh only the last field are different and have same number of 11929Sjkh fields( if length <= 2, may be different if first field) */ 11939Sjkh 11949Sjkh{ 119511894Speter int length = countnumflds(num1); 11969Sjkh 11979Sjkh if ( 11989Sjkh countnumflds(num2) != length 119911894Speter || (2 < length && compartial(num1, num2, length-1) != 0) 12009Sjkh ) { 120111894Speter rcserror("invalid branch or revision pair %s : %s", num1, num2); 12029Sjkh return false; 12039Sjkh } 12049Sjkh 12059Sjkh return true; 12069Sjkh} 12079Sjkh 12089Sjkh 12099Sjkh 12109Sjkh static void 12119Sjkhgetrevpairs(argv) 12129Sjkhregister char * argv; 12139Sjkh/* function: get revision or branch range from command line, and */ 12149Sjkh/* store in revlist */ 12159Sjkh 12169Sjkh{ 12179Sjkh register char c; 12189Sjkh struct Revpairs * nextrevpair; 12199Sjkh int separator; 12209Sjkh 12219Sjkh c = *argv; 12229Sjkh 12239Sjkh /* Support old ambiguous '-' syntax; this will go away. */ 12249Sjkh if (strchr(argv,':')) 12259Sjkh separator = ':'; 12269Sjkh else { 12279Sjkh if (strchr(argv,'-') && VERSION(5) <= RCSversion) 12289Sjkh warn("`-' is obsolete in `-r%s'; use `:' instead", argv); 12299Sjkh separator = '-'; 12309Sjkh } 12319Sjkh 12329Sjkh for (;;) { 12339Sjkh while (c==' ' || c=='\t' || c=='\n') 12349Sjkh c = *++argv; 12359Sjkh nextrevpair = talloc(struct Revpairs); 12369Sjkh nextrevpair->rnext = revlist; 12379Sjkh revlist = nextrevpair; 12389Sjkh nextrevpair->numfld = 1; 12399Sjkh nextrevpair->strtrev = argv; 12409Sjkh for (;; c = *++argv) { 12419Sjkh switch (c) { 12429Sjkh default: 12439Sjkh continue; 12449Sjkh case '\0': case ' ': case '\t': case '\n': 12459Sjkh case ',': case ';': 12469Sjkh break; 12479Sjkh case ':': case '-': 12489Sjkh if (c == separator) 12499Sjkh break; 12509Sjkh continue; 12519Sjkh } 12529Sjkh break; 12539Sjkh } 12549Sjkh *argv = '\0'; 12559Sjkh while (c==' ' || c=='\t' || c=='\n') 12569Sjkh c = *++argv; 12579Sjkh if (c == separator) { 125811894Speter while ((c = *++argv) == ' ' || c == '\t' || c =='\n') 125911894Speter continue; 12609Sjkh nextrevpair->endrev = argv; 12619Sjkh for (;; c = *++argv) { 12629Sjkh switch (c) { 12639Sjkh default: 12649Sjkh continue; 12659Sjkh case '\0': case ' ': case '\t': case '\n': 12669Sjkh case ',': case ';': 12679Sjkh break; 12689Sjkh case ':': case '-': 12699Sjkh if (c == separator) 127011894Speter break; 127111894Speter continue; 12729Sjkh } 12739Sjkh break; 12749Sjkh } 12759Sjkh *argv = '\0'; 12769Sjkh while (c==' ' || c=='\t' || c =='\n') 12779Sjkh c = *++argv; 12789Sjkh nextrevpair->numfld = 127911894Speter !nextrevpair->endrev[0] ? 2 /* -rREV: */ : 128011894Speter !nextrevpair->strtrev[0] ? 3 /* -r:REV */ : 128111894Speter 4 /* -rREV1:REV2 */; 12829Sjkh } 12839Sjkh if (!c) 12849Sjkh break; 128511894Speter else if (c==',' || c==';') 128611894Speter c = *++argv; 128711894Speter else 12889Sjkh error("missing `,' near `%c%s'", c, argv+1); 12899Sjkh } 12909Sjkh} 1291