summaryrefslogtreecommitdiffstats
path: root/gnu/usr.bin/rcs/rlog/rlog.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/usr.bin/rcs/rlog/rlog.c')
-rw-r--r--gnu/usr.bin/rcs/rlog/rlog.c1290
1 files changed, 1290 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..f8872fe
--- /dev/null
+++ b/gnu/usr.bin/rcs/rlog/rlog.c
@@ -0,0 +1,1290 @@
+/* Print log messages and other information about RCS files. */
+
+/* Copyright 1982, 1988, 1989 Walter Tichy
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995 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,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+Report problems and direct all questions to:
+
+ rcs-bugs@cs.purdue.edu
+
+*/
+
+/*
+ * Revision 5.18 1995/06/16 06:19:24 eggert
+ * Update FSF address.
+ *
+ * Revision 5.17 1995/06/01 16:23:43 eggert
+ * (struct rcslockers): Renamed from `struct lockers'.
+ * (getnumericrev): Return error indication instead of ignoring errors.
+ * (main): Check it. Don't use dateform.
+ * (recentdate, extdate): cmpnum -> cmpdate
+ *
+ * Revision 5.16 1994/04/13 16:30:34 eggert
+ * Fix bug; `rlog -lxxx' inverted the sense of -l.
+ *
+ * Revision 5.15 1994/03/17 14:05:48 eggert
+ * -d'<DATE' now excludes DATE; the new syntax -d'<=DATE' includes it.
+ * Emulate -V4's white space generation more precisely.
+ * Work around SVR4 stdio performance bug. Remove lint.
+ *
+ * Revision 5.14 1993/11/09 17:40:15 eggert
+ * -V now prints version on stdout and exits.
+ *
+ * Revision 5.13 1993/11/03 17:42:27 eggert
+ * Add -N, -z. Ignore -T.
+ *
+ * Revision 5.12 1992/07/28 16:12:44 eggert
+ * Don't miss B.0 when handling branch B. Diagnose missing `,' in -r.
+ * Add -V. Avoid `unsigned'. Statement macro names now end in _.
+ *
+ * Revision 5.11 1992/01/24 18:44:19 eggert
+ * Don't duplicate unexpected_EOF's function. lint -> RCS_lint
+ *
+ * Revision 5.10 1992/01/06 02:42:34 eggert
+ * Update usage string.
+ * while (E) ; -> while (E) continue;
+ *
+ * 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 rcslockers { /* lockers in locker option; stored */
+ char const * login; /* lockerlist */
+ struct rcslockers * 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 */
+ int numfld; /* option; stored in revlist */
+ char const * strtrev;
+ char const * endrev;
+ struct Revpairs * rnext;
+ } ;
+
+struct Datepairs{ /* date range in -d option; stored in */
+ struct Datepairs *dnext;
+ char strtdate[datesize]; /* duelst and datelist */
+ char enddate[datesize];
+ char ne_date; /* datelist only; distinguishes < from <= */
+ };
+
+static char extractdelta P((struct hshentry const*));
+static int checkrevpair P((char const*,char const*));
+static int extdate P((struct hshentry*));
+static int getnumericrev P((void));
+static struct hshentry const *readdeltalog P((void));
+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 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 rcslockers *lockerlist;
+static struct stateattri *statelist;
+
+
+mainProg(rlogId, "rlog", "$FreeBSD$")
+{
+ static char const cmdusage[] =
+ "\nrlog usage: rlog -{bhLNRt} -v[string] -ddates -l[lockers] -r[revs] -sstates -Vn -w[logins] -xsuff -zzone file ...";
+
+ register FILE *out;
+ char *a, **newargv;
+ struct Datepairs *currdate;
+ char const *accessListString, *accessFormat;
+ char const *headFormat, *symbolFormat;
+ struct access const *curaccess;
+ struct assoc const *curassoc;
+ struct hshentry const *delta;
+ struct rcslock const *currlock;
+ int descflag, selectflag;
+ int onlylockflag; /* print only files with locks */
+ int onlyRCSflag; /* print only RCS pathname */
+ int pre5;
+ int shownames;
+ int revno;
+ int versionlist;
+ char *vstring;
+
+ descflag = selectflag = shownames = true;
+ versionlist = onlylockflag = onlyRCSflag = false;
+ vstring=0;
+ 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 'N':
+ shownames = false;
+ 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 'z':
+ zone_set(a);
+ break;
+
+ case 'T':
+ /* Ignore -T, so that RCSINIT can contain -T. */
+ if (*a)
+ goto unknown;
+ break;
+
+ case 'V':
+ setRCSversion(*argv);
+ break;
+
+ case 'v':
+ versionlist = true;
+ vstring = a;
+ break;
+
+ default:
+ unknown:
+ error("unknown option: %s%s", *argv, cmdusage);
+
+ };
+ } /* end of option processing */
+
+ if (! (descflag|selectflag)) {
+ warn("-t overrides -h.");
+ descflag = true;
+ }
+
+ pre5 = RCSversion < VERSION(5);
+ if (pre5) {
+ accessListString = "\naccess list: ";
+ accessFormat = " %s";
+ headFormat = "RCS file: %s; Working file: %s\nhead: %s%s\nbranch: %s%s\nlocks: ";
+ insDelFormat = " lines added/del: %ld/%ld";
+ symbolFormat = " %s: %s;";
+ } else {
+ accessListString = "\naccess list:";
+ accessFormat = "\n\t%s";
+ headFormat = "RCS file: %s\nWorking file: %s\nhead:%s%s\nbranch:%s%s\nlocks:%s";
+ insDelFormat = " lines: +%ld -%ld";
+ symbolFormat = "\n\t%s: %s";
+ }
+
+ /* Now handle all pathnames. */
+ if (nerror)
+ cleanup();
+ else if (argc < 1)
+ faterror("no input file%s", cmdusage);
+ else
+ for (; 0 < argc; cleanup(), ++argv, --argc) {
+ ffree();
+
+ if (pairnames(argc, argv, rcsreadopen, true, false) <= 0)
+ continue;
+
+ /*
+ * RCSname contains the name of the RCS file,
+ * and finptr the file descriptor;
+ * workname 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 ( versionlist ) {
+ gettree();
+ aprintf(out, "%s%s %s\n", vstring, workname, tiprev());
+ continue;
+ }
+
+ if ( onlyRCSflag ) {
+ aprintf(out, "%s\n", RCSname);
+ continue;
+ }
+
+ gettree();
+
+ if (!getnumericrev())
+ continue;
+
+ /*
+ * Output the first character with putc, not printf.
+ * Otherwise, an SVR4 stdio bug buffers output inefficiently.
+ */
+ aputc_('\n', out)
+
+ /* print RCS pathname, working pathname and optional
+ administrative information */
+ /* could use getfullRCSname() here, but that is very slow */
+ aprintf(out, headFormat, RCSname, workname,
+ 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 && pre5)
+ aputs(" ; strict" + (Locks?3:0), out);
+
+ aputs(accessListString, out); /* print access list */
+ curaccess = AccessList;
+ while(curaccess) {
+ aprintf(out, accessFormat, curaccess->login);
+ curaccess = curaccess->nextaccess;
+ }
+
+ if (shownames) {
+ aputs("\nsymbolic names:", out); /* print symbolic names */
+ for (curassoc=Symbols; curassoc; curassoc=curassoc->nextassoc)
+ aprintf(out, symbolFormat, curassoc->symbol, curassoc->num);
+ }
+ if (pre5) {
+ aputs("\ncomment leader: \"", out);
+ awrite(Comment.string, Comment.size, out);
+ afputc('\"', out);
+ }
+ if (!pre5 || Expand != KEYVAL_EXPAND)
+ aprintf(out, "\nkeyword substitution: %s",
+ expand_names[Expand]
+ );
+
+ aprintf(out, "\ntotal revisions: %d", TotalDeltas);
+
+ revno = 0;
+
+ if (Head && selectflag & descflag) {
+
+ exttree(Head);
+
+ /* get most recently date of the dates pointed by duelst */
+ currdate = duelst;
+ while( currdate) {
+ VOID strcpy(currdate->strtdate, "0.0.0.0.0.0");
+ recentdate(Head, currdate);
+ currdate = currdate->dnext;
+ }
+
+ revno = extdate(Head);
+
+ aprintf(out, ";\tselected revisions: %d", revno);
+ }
+
+ afputc('\n',out);
+ if (descflag) {
+ aputs("description:\n", out);
+ getdesc(true);
+ }
+ if (revno) {
+ while (! (delta = readdeltalog())->selector || --revno)
+ continue;
+ if (delta->next && countnumflds(delta->num)==2)
+ /* Read through delta->next to get its insertlns. */
+ while (readdeltalog() != delta->next)
+ continue;
+ putrunk();
+ putree(Head);
+ }
+ aputs("----------------------------\n", out);
+ aputs("=============================================================================\n",out);
+ }
+ Ofclose(out);
+ exitmain(exitstatus);
+}
+
+ static void
+cleanup()
+{
+ if (nerror) exitstatus = EXIT_FAILURE;
+ Izclose(&finptr);
+}
+
+#if RCS_lint
+# define exiterr rlogExit
+#endif
+ 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) 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) return;
+
+ putforest(branchroot->nextbranch);
+
+ putabranch(branchroot->hsh);
+ putree(branchroot->hsh);
+}
+
+
+
+
+ static void
+putabranch(root)
+ struct hshentry const *root;
+/* function : print one branch */
+
+{
+ if (!root) 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 + zonelenmax];
+ int pre5 = RCSversion < VERSION(5);
+
+ if (!node->selector)
+ return;
+
+ out = stdout;
+ aprintf(out,
+ "----------------------------\nrevision %s%s",
+ node->num, pre5 ? " " : ""
+ );
+ if ( node->lockedby )
+ aprintf(out, pre5+"\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);
+
+ ignorephrases(Ktext);
+ 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 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)
+ unexpected_EOF();
+ 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) return;
+
+ root->selector = extractdelta(root);
+ root->log.string = 0;
+ 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 rcslockers *newlocker;
+ argv--;
+ while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';')
+ continue;
+ if ( c == '\0') {
+ lockerlist = 0;
+ return;
+ }
+
+ while( c != '\0' ) {
+ newlocker = talloc(struct rcslockers);
+ newlocker->lockerlink = lockerlist;
+ newlocker->login = argv;
+ lockerlist = newlocker;
+ while ((c = *++argv) && c!=',' && c!=' ' && c!='\t' && c!='\n' && c!=';')
+ continue;
+ *argv = '\0';
+ if ( c == '\0' ) return;
+ while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';')
+ continue;
+ }
+}
+
+
+
+ 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==';')
+ continue;
+ if ( c == '\0' ) {
+ authorlist = talloc(struct authors);
+ authorlist->login = getusername(false);
+ authorlist->nextauthor = 0;
+ return;
+ }
+
+ while( c != '\0' ) {
+ newauthor = talloc(struct authors);
+ newauthor->nextauthor = authorlist;
+ newauthor->login = argv;
+ authorlist = newauthor;
+ while ((c = *++argv) && c!=',' && c!=' ' && c!='\t' && c!='\n' && c!=';')
+ continue;
+ * argv = '\0';
+ if ( c == '\0') return;
+ while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';')
+ continue;
+ }
+}
+
+
+
+
+ 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==';')
+ continue;
+ if ( c == '\0'){
+ error("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!=',' && c!=' ' && c!='\t' && c!='\n' && c!=';')
+ continue;
+ *argv = '\0';
+ if ( c == '\0' ) return;
+ while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';')
+ continue;
+ }
+}
+
+
+
+ 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 rcslockers const *plocker;
+ struct rcslock *p, **pp;
+
+ if (!lockerlist) return;
+
+ /* shorten Locks to those contained in lockerlist */
+ for (pp = &Locks; (p = *pp); )
+ for (plocker = lockerlist; ; )
+ if (strcmp(plocker->login, p->login) == 0) {
+ pp = &p->nextlock;
+ break;
+ } else if (!(plocker = plocker->lockerlink)) {
+ *pp = p->nextlock;
+ break;
+ }
+}
+
+
+
+ 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) return;
+ if (root->selector) {
+ if ( cmpdate(root->date, pd->strtdate) >= 0 &&
+ cmpdate(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 int
+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;
+ int revno, ne;
+
+ if (!root)
+ return 0;
+
+ if ( datelist || duelst) {
+ pdate = datelist;
+ while( pdate ) {
+ ne = pdate->ne_date;
+ if (
+ (!pdate->strtdate[0]
+ || ne <= cmpdate(root->date, pdate->strtdate))
+ &&
+ (!pdate->enddate[0]
+ || ne <= cmpdate(pdate->enddate, root->date))
+ )
+ break;
+ pdate = pdate->dnext;
+ }
+ if (!pdate) {
+ pdate = duelst;
+ for (;;) {
+ if (!pdate) {
+ root->selector = false;
+ break;
+ }
+ if (cmpdate(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 rcslock const *plock;
+ struct stateattri const *pstate;
+ struct authors const *pauthor;
+ struct Revpairs const *prevision;
+ int 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==';')
+ continue;
+ if ( c == '\0' ) {
+ error("missing date/time after -d");
+ return;
+ }
+
+ while( c != '\0' ) {
+ switchflag = false;
+ nextdate = talloc(struct Datepairs);
+ if ( c == '<' ) { /* case: -d <date */
+ c = *++argv;
+ if (!(nextdate->ne_date = c!='='))
+ c = *++argv;
+ (nextdate->strtdate)[0] = '\0';
+ } else if (c == '>') { /* case: -d'>date' */
+ c = *++argv;
+ if (!(nextdate->ne_date = c!='='))
+ 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 */
+ int eq = argv[1]=='=';
+ nextdate->ne_date = !eq;
+ argv += eq;
+ while ((c = *++argv) == ' ' || c=='\t' || c=='\n')
+ continue;
+ 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 (RCSversion < VERSION(5))
+ nextdate->ne_date = 0;
+ if ( c == '\0') return;
+ while ((c = *++argv) == ';' || c == ' ' || c == '\t' || c =='\n')
+ continue;
+ }
+}
+
+
+
+ static int
+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;
+ int n;
+ struct buf s, e;
+ char const *lrev;
+ struct buf const *rstart, *rend;
+
+ Revlst = 0;
+ ptr = revlist;
+ bufautobegin(&s);
+ bufautobegin(&e);
+ while( ptr ) {
+ n = 0;
+ rstart = &s;
+ rend = &e;
+
+ switch (ptr->numfld) {
+
+ case 1: /* -rREV */
+ if (!expandsym(ptr->strtrev, &s))
+ goto freebufs;
+ rend = &s;
+ n = countnumflds(s.string);
+ if (!n && (lrev = tiprev())) {
+ bufscpy(&s, lrev);
+ n = countnumflds(lrev);
+ }
+ break;
+
+ case 2: /* -rREV: */
+ if (!expandsym(ptr->strtrev, &s))
+ goto freebufs;
+ 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))
+ goto freebufs;
+ if ((n = countnumflds(e.string)) < 2)
+ bufscpy(&s, ".0");
+ else {
+ bufscpy(&s, e.string);
+ VOID strcpy(strrchr(s.string,'.'), ".0");
+ }
+ break;
+
+ default: /* -rREV1:REV2 */
+ if (!(
+ expandsym(ptr->strtrev, &s)
+ && expandsym(ptr->endrev, &e)
+ && checkrevpair(s.string, e.string)
+ ))
+ goto freebufs;
+ 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);
+ }
+
+ freebufs:
+ bufautoend(&s);
+ bufautoend(&e);
+ return !ptr;
+}
+
+
+
+ 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) */
+
+{
+ int length = countnumflds(num1);
+
+ if (
+ countnumflds(num2) != length
+ || (2 < length && compartial(num1, num2, length-1) != 0)
+ ) {
+ rcserror("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')
+ continue;
+ 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)
+ break;
+ continue;
+ }
+ 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;
+ else if (c==',' || c==';')
+ c = *++argv;
+ else
+ error("missing `,' near `%c%s'", c, argv+1);
+ }
+}
OpenPOWER on IntegriCloud