diff options
Diffstat (limited to 'gnu/usr.bin/rcs/rlog/rlog.c')
-rw-r--r-- | gnu/usr.bin/rcs/rlog/rlog.c | 1204 |
1 files changed, 1204 insertions, 0 deletions
diff --git a/gnu/usr.bin/rcs/rlog/rlog.c b/gnu/usr.bin/rcs/rlog/rlog.c new file mode 100644 index 0000000..b18b0c9 --- /dev/null +++ b/gnu/usr.bin/rcs/rlog/rlog.c @@ -0,0 +1,1204 @@ +/* + * RLOG operation + */ +/***************************************************************************** + * print contents of RCS files + ***************************************************************************** + */ + +/* Copyright (C) 1982, 1988, 1989 Walter Tichy + Copyright 1990, 1991 by Paul Eggert + Distributed under license by the Free Software Foundation, Inc. + +This file is part of RCS. + +RCS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +RCS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RCS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +Report problems and direct all questions to: + + rcs-bugs@cs.purdue.edu + +*/ + + + + +/* $Log: rlog.c,v $ + * Revision 5.9 1991/09/17 19:07:40 eggert + * Getscript() didn't uncache partial lines. + * + * Revision 5.8 1991/08/19 03:13:55 eggert + * Revision separator is `:', not `-'. + * Check for missing and duplicate logs. Tune. + * Permit log messages that do not end in newline (including empty logs). + * + * Revision 5.7 1991/04/21 11:58:31 eggert + * Add -x, RCSINIT, MS-DOS support. + * + * Revision 5.6 1991/02/26 17:07:17 eggert + * Survive RCS files with missing logs. + * strsave -> str_save (DG/UX name clash) + * + * Revision 5.5 1990/11/01 05:03:55 eggert + * Permit arbitrary data in logs and comment leaders. + * + * Revision 5.4 1990/10/04 06:30:22 eggert + * Accumulate exit status across files. + * + * Revision 5.3 1990/09/11 02:41:16 eggert + * Plug memory leak. + * + * Revision 5.2 1990/09/04 08:02:33 eggert + * Count RCS lines better. + * + * Revision 5.0 1990/08/22 08:13:48 eggert + * Remove compile-time limits; use malloc instead. Add setuid support. + * Switch to GMT. + * Report dates in long form, to warn about dates past 1999/12/31. + * Change "added/del" message to make room for the longer dates. + * Don't generate trailing white space. Add -V. Ansify and Posixate. + * + * Revision 4.7 89/05/01 15:13:48 narten + * changed copyright header to reflect current distribution rules + * + * Revision 4.6 88/08/09 19:13:28 eggert + * Check for memory exhaustion; don't access freed storage. + * Shrink stdio code size; remove lint. + * + * Revision 4.5 87/12/18 11:46:38 narten + * more lint cleanups (Guy Harris) + * + * Revision 4.4 87/10/18 10:41:12 narten + * Updating version numbers + * Changes relative to 1.1 actually relative to 4.2 + * + * Revision 1.3 87/09/24 14:01:10 narten + * Sources now pass through lint (if you ignore printf/sprintf/fprintf + * warnings) + * + * Revision 1.2 87/03/27 14:22:45 jenkins + * Port to suns + * + * Revision 4.2 83/12/05 09:18:09 wft + * changed rewriteflag to external. + * + * Revision 4.1 83/05/11 16:16:55 wft + * Added -b, updated getnumericrev() accordingly. + * Replaced getpwuid() with getcaller(). + * + * Revision 3.7 83/05/11 14:24:13 wft + * Added options -L and -R; + * Fixed selection bug with -l on multiple files. + * Fixed error on dates of the form -d'>date' (rewrote getdatepair()). + * + * Revision 3.6 82/12/24 15:57:53 wft + * shortened output format. + * + * Revision 3.5 82/12/08 21:45:26 wft + * removed call to checkaccesslist(); used DATEFORM to format all dates; + * removed unused variables. + * + * Revision 3.4 82/12/04 13:26:25 wft + * Replaced getdelta() with gettree(); removed updating of field lockedby. + * + * Revision 3.3 82/12/03 14:08:20 wft + * Replaced getlogin with getpwuid(), %02d with %.2d, fancydate with PRINTDATE. + * Fixed printing of nil, removed printing of Suffix, + * added shortcut if no revisions are printed, disambiguated struct members. + * + * Revision 3.2 82/10/18 21:09:06 wft + * call to curdir replaced with getfullRCSname(), + * fixed call to getlogin(), cosmetic changes on output, + * changed conflicting long identifiers. + * + * Revision 3.1 82/10/13 16:07:56 wft + * fixed type of variables receiving from getc() (char -> int). + */ + + + +#include "rcsbase.h" + +struct lockers { /* lockers in locker option; stored */ + char const * login; /* lockerlist */ + struct lockers * lockerlink; + } ; + +struct stateattri { /* states in state option; stored in */ + char const * status; /* statelist */ + struct stateattri * nextstate; + } ; + +struct authors { /* login names in author option; */ + char const * login; /* stored in authorlist */ + struct authors * nextauthor; + } ; + +struct Revpairs{ /* revision or branch range in -r */ + unsigned numfld; /* option; stored in revlist */ + char const * strtrev; + char const * endrev; + struct Revpairs * rnext; + } ; + +struct Datepairs{ /* date range in -d option; stored in */ + char strtdate[datesize]; /* duelst and datelist */ + char enddate[datesize]; + struct Datepairs * dnext; + }; + +static char extractdelta P((struct hshentry const*)); +static int checkrevpair P((char const*,char const*)); +static struct hshentry const *readdeltalog P((void)); +static unsigned extdate P((struct hshentry*)); +static void cleanup P((void)); +static void exttree P((struct hshentry*)); +static void getauthor P((char*)); +static void getdatepair P((char*)); +static void getlocker P((char*)); +static void getnumericrev P((void)); +static void getrevpairs P((char*)); +static void getscript P((struct hshentry*)); +static void getstate P((char*)); +static void putabranch P((struct hshentry const*)); +static void putadelta P((struct hshentry const*,struct hshentry const*,int)); +static void putforest P((struct branchhead const*)); +static void putree P((struct hshentry const*)); +static void putrunk P((void)); +static void recentdate P((struct hshentry const*,struct Datepairs*)); +static void trunclocks P((void)); + +static char const *insDelFormat; +static int branchflag; /*set on -b */ +static int exitstatus; +static int lockflag; +static struct Datepairs *datelist, *duelst; +static struct Revpairs *revlist, *Revlst; +static struct authors *authorlist; +static struct lockers *lockerlist; +static struct stateattri *statelist; + + +mainProg(rlogId, "rlog", "$Id: rlog.c,v 5.9 1991/09/17 19:07:40 eggert Exp $") +{ + static char const cmdusage[] = + "\nrlog usage: rlog -{bhLRt} -ddates -l[lockers] -rrevs -sstates -w[logins] -Vn file ..."; + + register FILE *out; + char *a, **newargv; + struct Datepairs *currdate; + char const *accessListString, *accessFormat, *commentFormat; + char const *headFormat, *symbolFormat; + struct access const *curaccess; + struct assoc const *curassoc; + struct hshentry const *delta; + struct lock const *currlock; + int descflag, selectflag; + int onlylockflag; /* print only files with locks */ + int onlyRCSflag; /* print only RCS file name */ + unsigned revno; + + descflag = selectflag = true; + onlylockflag = onlyRCSflag = false; + out = stdout; + suffixes = X_DEFAULT; + + argc = getRCSINIT(argc, argv, &newargv); + argv = newargv; + while (a = *++argv, 0<--argc && *a++=='-') { + switch (*a++) { + + case 'L': + onlylockflag = true; + break; + + case 'R': + onlyRCSflag =true; + break; + + case 'l': + lockflag = true; + getlocker(a); + break; + + case 'b': + branchflag = true; + break; + + case 'r': + getrevpairs(a); + break; + + case 'd': + getdatepair(a); + break; + + case 's': + getstate(a); + break; + + case 'w': + getauthor(a); + break; + + case 'h': + descflag = false; + break; + + case 't': + selectflag = false; + break; + + case 'q': + /* This has no effect; it's here for consistency. */ + quietflag = true; + break; + + case 'x': + suffixes = a; + break; + + case 'V': + setRCSversion(*argv); + break; + + default: + faterror("unknown option: %s%s", *argv, cmdusage); + + }; + } /* end of option processing */ + + if (argc<1) faterror("no input file%s", cmdusage); + + if (! (descflag|selectflag)) { + warn("-t overrides -h."); + descflag = true; + } + + if (RCSversion < VERSION(5)) { + accessListString = "\naccess list: "; + accessFormat = " %s"; + commentFormat = "\ncomment leader: \""; + headFormat = "\nRCS file: %s; Working file: %s\nhead: %s%s\nbranch: %s%s\nlocks: "; + insDelFormat = " lines added/del: %lu/%lu"; + symbolFormat = " %s: %s;"; + } else { + accessListString = "\naccess list:"; + accessFormat = "\n\t%s"; + commentFormat = "\ncomment leader: \""; + headFormat = "\nRCS file: %s\nWorking file: %s\nhead:%s%s\nbranch:%s%s\nlocks:%s"; + insDelFormat = " lines: +%lu -%lu"; + symbolFormat = "\n\t%s: %s"; + } + + /* now handle all filenames */ + do { + ffree(); + + if (pairfilenames(argc, argv, rcsreadopen, true, false) <= 0) + continue; + + /* now RCSfilename contains the name of the RCS file, and finptr + * the file descriptor. Workfilename contains the name of the + * working file. + */ + + /* Keep only those locks given by -l. */ + if (lockflag) + trunclocks(); + + /* do nothing if -L is given and there are no locks*/ + if (onlylockflag && !Locks) + continue; + + if ( onlyRCSflag ) { + aprintf(out, "%s\n", RCSfilename); + continue; + } + /* print RCS filename , working filename and optional + administrative information */ + /* could use getfullRCSname() here, but that is very slow */ + aprintf(out, headFormat, RCSfilename, workfilename, + Head ? " " : "", Head ? Head->num : "", + Dbranch ? " " : "", Dbranch ? Dbranch : "", + StrictLocks ? " strict" : "" + ); + currlock = Locks; + while( currlock ) { + aprintf(out, symbolFormat, currlock->login, + currlock->delta->num); + currlock = currlock->nextlock; + } + if (StrictLocks && RCSversion<VERSION(5)) + aputs(" strict", out); + + aputs(accessListString, out); /* print access list */ + curaccess = AccessList; + while(curaccess) { + aprintf(out, accessFormat, curaccess->login); + curaccess = curaccess->nextaccess; + } + + aputs("\nsymbolic names:", out); /* print symbolic names */ + for (curassoc=Symbols; curassoc; curassoc=curassoc->nextassoc) + aprintf(out, symbolFormat, curassoc->symbol, curassoc->num); + aputs(commentFormat, out); + awrite(Comment.string, Comment.size, out); + aputs("\"\n", out); + if (VERSION(5)<=RCSversion || Expand != KEYVAL_EXPAND) + aprintf(out, "keyword substitution: %s\n", + expand_names[Expand] + ); + + gettree(); + + aprintf(out, "total revisions: %u", TotalDeltas); + + revno = 0; + + if (Head && selectflag & descflag) { + + getnumericrev(); /* get numeric revision or branch names */ + + exttree(Head); + + /* get most recently date of the dates pointed by duelst */ + currdate = duelst; + while( currdate) { + VOID sprintf(currdate->strtdate,DATEFORM,0,0,0,0,0,0); + recentdate(Head, currdate); + currdate = currdate->dnext; + } + + revno = extdate(Head); + + aprintf(out, ";\tselected revisions: %u", revno); + } + + afputc('\n',out); + if (descflag) { + aputs("description:\n", out); + getdesc(true); + } + if (revno) { + while (! (delta = readdeltalog())->selector || --revno) + ; + if (delta->next && countnumflds(delta->num)==2) + /* Read through delta->next to get its insertlns. */ + while (readdeltalog() != delta->next) + ; + putrunk(); + putree(Head); + } + aputs("=============================================================================\n",out); + } while (cleanup(), + ++argv, --argc >= 1); + Ofclose(out); + exitmain(exitstatus); +} + + static void +cleanup() +{ + if (nerror) exitstatus = EXIT_FAILURE; + Izclose(&finptr); +} + +#if lint +# define exiterr rlogExit +#endif + exiting void +exiterr() +{ + _exit(EXIT_FAILURE); +} + + + + static void +putrunk() +/* function: print revisions chosen, which are in trunk */ + +{ + register struct hshentry const *ptr; + + for (ptr = Head; ptr; ptr = ptr->next) + putadelta(ptr, ptr->next, true); +} + + + + static void +putree(root) + struct hshentry const *root; +/* function: print delta tree (not including trunk) in reverse + order on each branch */ + +{ + if ( root == nil ) return; + + putree(root->next); + + putforest(root->branches); +} + + + + + static void +putforest(branchroot) + struct branchhead const *branchroot; +/* function: print branches that has the same direct ancestor */ +{ + + if ( branchroot == nil ) return; + + putforest(branchroot->nextbranch); + + putabranch(branchroot->hsh); + putree(branchroot->hsh); +} + + + + + static void +putabranch(root) + struct hshentry const *root; +/* function : print one branch */ + +{ + + if ( root == nil) return; + + putabranch(root->next); + + putadelta(root, root, false); +} + + + + + + static void +putadelta(node,editscript,trunk) + register struct hshentry const *node, *editscript; + int trunk; +/* function: Print delta node if node->selector is set. */ +/* editscript indicates where the editscript is stored */ +/* trunk indicated whether this node is in trunk */ +{ + static char emptych[] = EMPTYLOG; + + register FILE *out; + char const *s; + size_t n; + struct branchhead const *newbranch; + struct buf branchnum; + char datebuf[datesize]; + + if (!node->selector) + return; + + out = stdout; + aprintf(out, + "----------------------------\nrevision %s", node->num + ); + if ( node->lockedby ) + aprintf(out, "\tlocked by: %s;", node->lockedby); + + aprintf(out, "\ndate: %s; author: %s; state: %s;", + date2str(node->date, datebuf), + node->author, node->state + ); + + if ( editscript ) + if(trunk) + aprintf(out, insDelFormat, + editscript->deletelns, editscript->insertlns); + else + aprintf(out, insDelFormat, + editscript->insertlns, editscript->deletelns); + + newbranch = node->branches; + if ( newbranch ) { + bufautobegin(&branchnum); + aputs("\nbranches:", out); + while( newbranch ) { + getbranchno(newbranch->hsh->num, &branchnum); + aprintf(out, " %s;", branchnum.string); + newbranch = newbranch->nextbranch; + } + bufautoend(&branchnum); + } + + afputc('\n', out); + s = node->log.string; + if (!(n = node->log.size)) { + s = emptych; + n = sizeof(emptych)-1; + } + awrite(s, n, out); + if (s[n-1] != '\n') + afputc('\n', out); +} + + + + + + static struct hshentry const * +readdeltalog() +/* Function : get the log message and skip the text of a deltatext node. + * Return the delta found. + * Assumes the current lexeme is not yet in nexttok; does not + * advance nexttok. + */ +{ + register struct hshentry * Delta; + struct buf logbuf; + struct cbuf cb; + + if (eoflex()) + fatserror("missing delta log"); + nextlex(); + if (!(Delta = getnum())) + fatserror("delta number corrupted"); + getkeystring(Klog); + if (Delta->log.string) + fatserror("duplicate delta log"); + bufautobegin(&logbuf); + cb = savestring(&logbuf); + Delta->log = bufremember(&logbuf, cb.size); + + nextlex(); + while (nexttok==ID && strcmp(NextString,Ktext)!=0) + ignorephrase(); + getkeystring(Ktext); + Delta->insertlns = Delta->deletelns = 0; + if ( Delta != Head) + getscript(Delta); + else + readstring(); + return Delta; +} + + + static void +getscript(Delta) +struct hshentry * Delta; +/* function: read edit script of Delta and count how many lines added */ +/* and deleted in the script */ + +{ + int ed; /* editor command */ + declarecache; + register RILE *fin; + register int c; + register unsigned long i; + struct diffcmd dc; + + fin = finptr; + setupcache(fin); + initdiffcmd(&dc); + while (0 <= (ed = getdiffcmd(fin,true,(FILE *)0,&dc))) + if (!ed) + Delta->deletelns += dc.nlines; + else { + /* skip scripted lines */ + i = dc.nlines; + Delta->insertlns += i; + cache(fin); + do { + for (;;) { + cacheget(c); + switch (c) { + default: + continue; + case SDELIM: + cacheget(c); + if (c == SDELIM) + continue; + if (--i) + fatserror("unexpected end to edit script"); + nextc = c; + uncache(fin); + return; + case '\n': + break; + } + break; + } + ++rcsline; + } while (--i); + uncache(fin); + } +} + + + + + + + + static void +exttree(root) +struct hshentry *root; +/* function: select revisions , starting with root */ + +{ + struct branchhead const *newbranch; + + if (root == nil) return; + + root->selector = extractdelta(root); + root->log.string = nil; + exttree(root->next); + + newbranch = root->branches; + while( newbranch ) { + exttree(newbranch->hsh); + newbranch = newbranch->nextbranch; + } +} + + + + + static void +getlocker(argv) +char * argv; +/* function : get the login names of lockers from command line */ +/* and store in lockerlist. */ + +{ + register char c; + struct lockers * newlocker; + argv--; + while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' || + c == '\n' || c == ';') ; + if ( c == '\0') { + lockerlist=nil; + return; + } + + while( c != '\0' ) { + newlocker = talloc(struct lockers); + newlocker->lockerlink = lockerlist; + newlocker->login = argv; + lockerlist = newlocker; + while ( ( c = (*++argv)) != ',' && c != '\0' && c != ' ' + && c != '\t' && c != '\n' && c != ';') ; + *argv = '\0'; + if ( c == '\0' ) return; + while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' || + c == '\n' || c == ';') ; + } +} + + + + static void +getauthor(argv) +char *argv; +/* function: get the author's name from command line */ +/* and store in authorlist */ + +{ + register c; + struct authors * newauthor; + + argv--; + while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' || + c == '\n' || c == ';') ; + if ( c == '\0' ) { + authorlist = talloc(struct authors); + authorlist->login = getusername(false); + authorlist->nextauthor = nil; + return; + } + + while( c != '\0' ) { + newauthor = talloc(struct authors); + newauthor->nextauthor = authorlist; + newauthor->login = argv; + authorlist = newauthor; + while( ( c = *++argv) != ',' && c != '\0' && c != ' ' + && c != '\t' && c != '\n' && c != ';') ; + * argv = '\0'; + if ( c == '\0') return; + while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' || + c == '\n' || c == ';') ; + } +} + + + + + static void +getstate(argv) +char * argv; +/* function : get the states of revisions from command line */ +/* and store in statelist */ + +{ + register char c; + struct stateattri *newstate; + + argv--; + while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' || + c == '\n' || c == ';') ; + if ( c == '\0'){ + warn("missing state attributes after -s options"); + return; + } + + while( c != '\0' ) { + newstate = talloc(struct stateattri); + newstate->nextstate = statelist; + newstate->status = argv; + statelist = newstate; + while( (c = (*++argv)) != ',' && c != '\0' && c != ' ' + && c != '\t' && c != '\n' && c != ';') ; + *argv = '\0'; + if ( c == '\0' ) return; + while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' || + c == '\n' || c == ';') ; + } +} + + + + static void +trunclocks() +/* Function: Truncate the list of locks to those that are held by the */ +/* id's on lockerlist. Do not truncate if lockerlist empty. */ + +{ + struct lockers const *plocker; + struct lock * plocked, * nextlocked; + + if ( (lockerlist == nil) || (Locks == nil)) return; + + /* shorten Locks to those contained in lockerlist */ + plocked = Locks; + Locks = nil; + while( plocked != nil) { + plocker = lockerlist; + while((plocker != nil) && ( strcmp(plocker->login, plocked->login)!=0)) + plocker = plocker->lockerlink; + nextlocked = plocked->nextlock; + if ( plocker != nil) { + plocked->nextlock = Locks; + Locks = plocked; + } + plocked = nextlocked; + } +} + + + + static void +recentdate(root, pd) + struct hshentry const *root; + struct Datepairs *pd; +/* function: Finds the delta that is closest to the cutoff date given by */ +/* pd among the revisions selected by exttree. */ +/* Successively narrows down the interval given by pd, */ +/* and sets the strtdate of pd to the date of the selected delta */ +{ + struct branchhead const *newbranch; + + if ( root == nil) return; + if (root->selector) { + if ( cmpnum(root->date, pd->strtdate) >= 0 && + cmpnum(root->date, pd->enddate) <= 0) + VOID strcpy(pd->strtdate, root->date); + } + + recentdate(root->next, pd); + newbranch = root->branches; + while( newbranch) { + recentdate(newbranch->hsh, pd); + newbranch = newbranch->nextbranch; + } +} + + + + + + + static unsigned +extdate(root) +struct hshentry * root; +/* function: select revisions which are in the date range specified */ +/* in duelst and datelist, start at root */ +/* Yield number of revisions selected, including those already selected. */ +{ + struct branchhead const *newbranch; + struct Datepairs const *pdate; + unsigned revno; + + if (!root) + return 0; + + if ( datelist || duelst) { + pdate = datelist; + while( pdate ) { + if ( (pdate->strtdate)[0] == '\0' || cmpnum(root->date,pdate->strtdate) >= 0){ + if ((pdate->enddate)[0] == '\0' || cmpnum(pdate->enddate,root->date) >= 0) + break; + } + pdate = pdate->dnext; + } + if ( pdate == nil) { + pdate = duelst; + for (;;) { + if (!pdate) { + root->selector = false; + break; + } + if ( cmpnum(root->date, pdate->strtdate) == 0) + break; + pdate = pdate->dnext; + } + } + } + revno = root->selector + extdate(root->next); + + newbranch = root->branches; + while( newbranch ) { + revno += extdate(newbranch->hsh); + newbranch = newbranch->nextbranch; + } + return revno; +} + + + + static char +extractdelta(pdelta) + struct hshentry const *pdelta; +/* function: compare information of pdelta to the authorlist, lockerlist,*/ +/* statelist, revlist and yield true if pdelta is selected. */ + +{ + struct lock const *plock; + struct stateattri const *pstate; + struct authors const *pauthor; + struct Revpairs const *prevision; + unsigned length; + + if ((pauthor = authorlist)) /* only certain authors wanted */ + while (strcmp(pauthor->login, pdelta->author) != 0) + if (!(pauthor = pauthor->nextauthor)) + return false; + if ((pstate = statelist)) /* only certain states wanted */ + while (strcmp(pstate->status, pdelta->state) != 0) + if (!(pstate = pstate->nextstate)) + return false; + if (lockflag) /* only locked revisions wanted */ + for (plock = Locks; ; plock = plock->nextlock) + if (!plock) + return false; + else if (plock->delta == pdelta) + break; + if ((prevision = Revlst)) /* only certain revs or branches wanted */ + for (;;) { + length = prevision->numfld; + if ( + countnumflds(pdelta->num) == length+(length&1) && + 0 <= compartial(pdelta->num, prevision->strtrev, length) && + 0 <= compartial(prevision->endrev, pdelta->num, length) + ) + break; + if (!(prevision = prevision->rnext)) + return false; + } + return true; +} + + + + static void +getdatepair(argv) + char * argv; +/* function: get time range from command line and store in datelist if */ +/* a time range specified or in duelst if a time spot specified */ + +{ + register char c; + struct Datepairs * nextdate; + char const * rawdate; + int switchflag; + + argv--; + while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' || + c == '\n' || c == ';') ; + if ( c == '\0' ) { + warn("missing date/time after -d"); + return; + } + + while( c != '\0' ) { + switchflag = false; + nextdate = talloc(struct Datepairs); + if ( c == '<' ) { /* case: -d <date */ + c = *++argv; + (nextdate->strtdate)[0] = '\0'; + } else if (c == '>') { /* case: -d'>date' */ + c = *++argv; + (nextdate->enddate)[0] = '\0'; + switchflag = true; + } else { + rawdate = argv; + while( c != '<' && c != '>' && c != ';' && c != '\0') + c = *++argv; + *argv = '\0'; + if ( c == '>' ) switchflag=true; + str2date(rawdate, + switchflag ? nextdate->enddate : nextdate->strtdate); + if ( c == ';' || c == '\0') { /* case: -d date */ + VOID strcpy(nextdate->enddate,nextdate->strtdate); + nextdate->dnext = duelst; + duelst = nextdate; + goto end; + } else { + /* case: -d date< or -d date>; see switchflag */ + while ( (c= *++argv) == ' ' || c=='\t' || c=='\n'); + if ( c == ';' || c == '\0') { + /* second date missing */ + if (switchflag) + *nextdate->strtdate= '\0'; + else + *nextdate->enddate= '\0'; + nextdate->dnext = datelist; + datelist = nextdate; + goto end; + } + } + } + rawdate = argv; + while( c != '>' && c != '<' && c != ';' && c != '\0') + c = *++argv; + *argv = '\0'; + str2date(rawdate, + switchflag ? nextdate->strtdate : nextdate->enddate); + nextdate->dnext = datelist; + datelist = nextdate; + end: + if ( c == '\0') return; + while( (c = *++argv) == ';' || c == ' ' || c == '\t' || c =='\n'); + } +} + + + + static void +getnumericrev() +/* function: get the numeric name of revisions which stored in revlist */ +/* and then stored the numeric names in Revlst */ +/* if branchflag, also add default branch */ + +{ + struct Revpairs * ptr, *pt; + unsigned n; + struct buf s, e; + char const *lrev; + struct buf const *rstart, *rend; + + Revlst = nil; + ptr = revlist; + bufautobegin(&s); + bufautobegin(&e); + while( ptr ) { + n = 0; + rstart = &s; + rend = &e; + + switch (ptr->numfld) { + + case 1: /* -r rev */ + if (expandsym(ptr->strtrev, &s)) { + rend = &s; + n = countnumflds(s.string); + if (!n && (lrev = tiprev())) { + bufscpy(&s, lrev); + n = countnumflds(lrev); + } + } + break; + + case 2: /* -r rev- */ + if (expandsym(ptr->strtrev, &s)) { + bufscpy(&e, s.string); + n = countnumflds(s.string); + (n<2 ? e.string : strrchr(e.string,'.'))[0] = 0; + } + break; + + case 3: /* -r -rev */ + if (expandsym(ptr->endrev, &e)) { + if ((n = countnumflds(e.string)) < 2) + bufscpy(&s, ".1"); + else { + bufscpy(&s, e.string); + VOID strcpy(strrchr(s.string,'.'), ".1"); + } + } + break; + + default: /* -r rev1-rev2 */ + if ( + expandsym(ptr->strtrev, &s) + && expandsym(ptr->endrev, &e) + && checkrevpair(s.string, e.string) + ) { + n = countnumflds(s.string); + /* Swap if out of order. */ + if (compartial(s.string,e.string,n) > 0) { + rstart = &e; + rend = &s; + } + } + break; + } + + if (n) { + pt = ftalloc(struct Revpairs); + pt->numfld = n; + pt->strtrev = fstr_save(rstart->string); + pt->endrev = fstr_save(rend->string); + pt->rnext = Revlst; + Revlst = pt; + } + ptr = ptr->rnext; + } + /* Now take care of branchflag */ + if (branchflag && (Dbranch||Head)) { + pt = ftalloc(struct Revpairs); + pt->strtrev = pt->endrev = + Dbranch ? Dbranch : fstr_save(partialno(&s,Head->num,1)); + pt->rnext=Revlst; Revlst=pt; + pt->numfld = countnumflds(pt->strtrev); + } + bufautoend(&s); + bufautoend(&e); +} + + + + static int +checkrevpair(num1,num2) + char const *num1, *num2; +/* function: check whether num1, num2 are legal pair,i.e. + only the last field are different and have same number of + fields( if length <= 2, may be different if first field) */ + +{ + unsigned length = countnumflds(num1); + + if ( + countnumflds(num2) != length + || 2 < length && compartial(num1, num2, length-1) != 0 + ) { + error("invalid branch or revision pair %s : %s", num1, num2); + return false; + } + + return true; +} + + + + static void +getrevpairs(argv) +register char * argv; +/* function: get revision or branch range from command line, and */ +/* store in revlist */ + +{ + register char c; + struct Revpairs * nextrevpair; + int separator; + + c = *argv; + + /* Support old ambiguous '-' syntax; this will go away. */ + if (strchr(argv,':')) + separator = ':'; + else { + if (strchr(argv,'-') && VERSION(5) <= RCSversion) + warn("`-' is obsolete in `-r%s'; use `:' instead", argv); + separator = '-'; + } + + for (;;) { + while (c==' ' || c=='\t' || c=='\n') + c = *++argv; + nextrevpair = talloc(struct Revpairs); + nextrevpair->rnext = revlist; + revlist = nextrevpair; + nextrevpair->numfld = 1; + nextrevpair->strtrev = argv; + for (;; c = *++argv) { + switch (c) { + default: + continue; + case '\0': case ' ': case '\t': case '\n': + case ',': case ';': + break; + case ':': case '-': + if (c == separator) + break; + continue; + } + break; + } + *argv = '\0'; + while (c==' ' || c=='\t' || c=='\n') + c = *++argv; + if (c == separator) { + while( (c =(*++argv)) == ' ' || c == '\t' || c =='\n') ; + nextrevpair->endrev = argv; + for (;; c = *++argv) { + switch (c) { + default: + continue; + case '\0': case ' ': case '\t': case '\n': + case ',': case ';': + break; + case ':': case '-': + if (c == separator) + continue; + break; + } + break; + } + *argv = '\0'; + while (c==' ' || c=='\t' || c =='\n') + c = *++argv; + nextrevpair->numfld = + !nextrevpair->endrev[0] ? 2 /* -rrev- */ : + !nextrevpair->strtrev[0] ? 3 /* -r-rev */ : + 4 /* -rrev1-rev2 */; + } + if (!c) + break; + if (c!=',' && c!=';') + error("missing `,' near `%c%s'", c, argv+1); + } +} |