BSD 4_2 development
authorCSRG <csrg@ucbvax.Berkeley.EDU>
Wed, 11 May 1983 08:13:27 +0000 (00:13 -0800)
committerCSRG <csrg@ucbvax.Berkeley.EDU>
Wed, 11 May 1983 08:13:27 +0000 (00:13 -0800)
Work on file usr/src/new/new/rcs/src/rcs/rlog.c

Synthesized-from: CSRG/cd1/4.2

usr/src/new/new/rcs/src/rcs/rlog.c [new file with mode: 0644]

diff --git a/usr/src/new/new/rcs/src/rcs/rlog.c b/usr/src/new/new/rcs/src/rcs/rlog.c
new file mode 100644 (file)
index 0000000..f5a9410
--- /dev/null
@@ -0,0 +1,1135 @@
+/*
+ *                       RLOG    operation
+ */
+static char rcsid[]=
+"$Header: /usr/wft/RCS/SRC/RCS/rlog.c,v 3.7 83/05/11 14:24:13 wft Exp $ Purdue CS";
+/*****************************************************************************
+ *                       print contents of RCS files
+ *****************************************************************************
+ *
+ * Copyright (C) 1982 by Walter Tichy
+ *                       Purdue University
+ *                       Computer Science Department
+ *                       West Lafayette, IN 47907
+ *
+ * All rights reserved. No part of this software may be sold or distributed
+ * in any form or by any means without the prior written permission of the
+ * author.
+ * Report problems and direct all inquiries to Tichy@purdue (ARPA net).
+ */
+
+
+/* $Log:       rlog.c,v $
+ * 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 <pwd.h>
+#include "time.h"
+#include "rcsbase.h"
+static char rcsbaseid[] = RCSBASE;
+
+
+extern FILE * fopen();
+extern struct passwd *getpwuid();
+extern char * malloc();
+extern        free();
+extern struct hshentry * genrevs(); /*generate delta numbers                */
+extern int    countnumflds();
+extern int    compartial();
+extern char * partialno();
+extern int    expandsym();          /*get numeric name of a revision        */
+extern char * getfullRCSname();     /*get full path name of RCS file        */
+extern int nextc;                   /*next input character                  */
+extern char * Klog;
+extern char * Ktext;
+extern int  partime();
+extern long maketime();             /*convert parsed time to unix time.     */
+extern struct tm * localtime();     /*convert unixtime into a tm-structure  */
+extern int  pairfilenames();
+extern struct hshentry  * getnum();
+extern FILE * finptr;               /* RCS input file                       */
+extern FILE * frewrite;             /* new RCS file                         */
+extern int    nerror;               /* error counter                        */
+
+char * RCSfilename, * workfilename;
+int    rewriteflag; /* indicates whether input should be echoed to frewrite */
+
+char * caller;                        /* caller's login;                    */
+
+char numericrev[revlength];           /* holds expanded revision number     */
+struct hshentry * gendeltas[hshsize]; /* stores deltas to be generated      */
+struct hshentry * targetdelta;        /* final delta to be generated        */
+int  descflag, selectflag, selectop;  /* option to print access list, symbolic  */
+                                      /* names, descriptive text, locks and */
+                                      /* Head                               */
+int  onlylockflag;                   /* option to print only files         */
+                                     /* with locks                         */
+int  onlyRCSflag;                     /* option to print only RCS file name */
+int  lockflag;                        /* whether locker option is set       */
+int  revno;                           /* number of revision chosen          */
+
+struct  lockers {                     /* lockers in locker option; stored   */
+     char               * login;      /* lockerlist                         */
+     struct     lockers * lockerlink;
+     }  ;
+
+struct  stateattri {                  /* states in state option; stored in  */
+     char               * status;     /* statelist                          */
+     struct  stateattri * nextstate;
+     }  ;
+
+struct  authors {                     /* login names in author option;      */
+     char               * login;      /* stored in authorlist               */
+     struct     authors * nextauthor;
+     }  ;
+
+struct Revpairs{                      /* revision or branch range in -r     */
+     int                  numfld;     /* option; stored in revlist          */
+     char               * strtrev;
+     char               * endrev;
+     struct  Revpairs   * rnext;
+     } ;
+
+struct Datepairs{                     /* date range in -d option; stored in */
+     char               strtdate[datelength];   /* duelst and datelist      */
+     char               enddate[datelength];
+     struct  Datepairs  * dnext;
+     };
+
+char   Dotstring[200];                /* string of numeric revision name    */
+char   * Nextdotstring;               /* next available place of Dotstring  */
+struct  Datepairs       * datelist,  * duelst;
+struct  Revpairs        * revlist, * Revlst;
+struct  lockers         * lockerlist;
+struct  stateattri      * statelist;
+struct  authors         * authorlist;
+
+
+
+main (argc, argv)
+int argc;
+char * argv[];
+{
+        struct  Datepairs       * currdate;
+        struct  assoc         * curassoc;
+        struct  access        * curaccess;
+        struct  lock          * currlock;
+        char * cmdusage;
+
+       cmdusage = "command format:\nrlog -L -R -h -t -ddates -l[lockers] -rrevisions -sstates -w[logins] file ...";
+        cmdid = "rlog";
+        descflag = selectflag = true;
+        lockflag = onlylockflag = selectop = false;
+       onlyRCSflag = false;
+        lockerlist = nil;
+        authorlist = nil;
+        statelist = nil;
+        Revlst = revlist = nil;
+        duelst = datelist = nil;
+        caller=getpwuid(getuid())->pw_name;
+
+        while (--argc,++argv, argc>=1 && ((*argv)[0] == '-')) {
+                switch ((*argv)[1]) {
+
+               case 'L':
+                       onlylockflag = true;
+                       break;
+
+               case 'R':
+                       onlyRCSflag =true;
+                       break;
+
+                case 'l':
+                        selectop = true;
+                        lockflag = true;
+                        getlocker( (*argv)+2 );
+                        break;
+
+                case 'r':
+                        selectop = true;
+                        getrevpairs( (*argv)+2 );
+                        break;
+
+                case 'd':
+                        selectop = true;
+                        getdatepair( (*argv)+2 );
+                        break;
+
+                case 's':
+                        selectop = true;
+                        getstate( (*argv)+2);
+                        break;
+
+                case 'w':
+                        selectop = true;
+                        getauthor( (*argv)+2);
+                        break;
+
+                case 'h':
+                        if ( ! selectflag ) warn("option -t overrides -h");
+                        else    descflag = false;
+                        break;
+
+                case 't':
+                        selectflag = false;
+                        if ( ! descflag ) warn("option -t overrides -h");
+                        descflag = true;
+                        break;
+
+                default:
+                        faterror("unknown option: %s\n%s", *argv,cmdusage);
+
+                };
+        } /* end of option processing */
+
+        if (argc<1) faterror("No input file\n%s",cmdusage);
+
+
+        /* now handle all filenames */
+        do {
+            rewriteflag=false;
+            finptr=frewrite=nil;
+
+
+            if (!pairfilenames(argc, argv, true,false)) continue;
+
+            /* now RCSfilename contains the name of the RCS file, and finptr
+             * the file descriptor. Workfilename contains the name of the
+             * working file.
+             */
+
+            if ( !trysema(RCSfilename, false)) goto loopend; /*  give up */
+
+            /* do nothing if -L is given and there are no locks*/
+           if ( onlylockflag && Locks == nil ) goto loopend;
+
+           if ( onlyRCSflag ) {
+               fprintf(stdout, "%s\n", RCSfilename);
+               goto loopend;
+           }
+            /*   print RCS filename , working filename and optional
+                 administrative information                         */
+            fprintf(stdout, "\nRCS file:        %s;   ",RCSfilename);
+            /* could use getfullRCSname() here, but that is very slow */
+            fprintf(stdout, "Working file:    %s\n", workfilename);
+            fprintf(stdout, "head:            %s\n", Head==nil?"":Head->num);
+
+            fputs("locks:         ", stdout);  /*  print locker list   */
+            currlock = Locks;
+            while( currlock ) {
+                fprintf(stdout,"  %s: %s;", currlock->login,
+                                currlock->delta->num);
+                currlock = currlock->nextlock;
+            }
+            if ( StrictLocks )
+                fputs(Locks==nil?"  ;  strict":"  strict",stdout);
+
+            fputs("\naccess list:   ", stdout);      /*  print access list  */
+            curaccess = AccessList;
+            while(curaccess) {
+                fputs("  ",stdout);
+                fputs(curaccess->login, stdout);
+                curaccess = curaccess->nextaccess;
+            }
+
+            fputs("\nsymbolic names:", stdout);   /*  print symbolic names   */
+            curassoc = Symbols;
+            while( curassoc ) {
+                fprintf(stdout, "  %s: %s;",curassoc->symbol,
+                           curassoc->delta->num);
+                curassoc = curassoc->nextassoc;
+            }
+
+            fprintf(stdout,"\ncomment leader:  \"%s\"\n",Comment);
+
+            gettree();
+            fprintf(stdout, "total revisions: %d;    ", TotalDeltas);
+            if ( Head == nil || !selectflag || !descflag) {
+                putc('\n',stdout);
+                if (descflag) fputs("description:\n", stdout);
+                getdesc(descflag);
+                fputs("=============================================================================\n",stdout);
+                goto loopend;
+            }
+
+
+            /*  keep only those locks given by -l */
+            if (lockflag)
+                trunclocks();
+            getnumericrev();    /* get numeric revision or branch names */
+            revno = 0;
+
+            exttree(Head);
+
+            /*  get most recently date of the dates pointed by duelst  */
+            currdate = duelst;
+            while( currdate) {
+                recentdate(Head, currdate);
+                currdate = currdate->dnext;
+           }
+
+            extdate(Head);
+
+            /*  reinitialize the date specification list   */
+            currdate = duelst;
+            while(currdate) {
+                sprintf(currdate->strtdate,DATEFORM,0,0,0,0,0,0);
+                currdate = currdate->dnext;
+            }
+
+            if ( selectop || ( selectflag && descflag) )
+                fprintf(stdout, "selected revisions: %d", revno);
+            putc('\n', stdout);
+            if (descflag) fputs("description:\n", stdout);
+            getdesc(descflag);
+            while( (nexttok != EOFILE) && readdeltalog());
+            if (selectflag && descflag && revno) {
+                putrunk();
+                putree(Head);
+                if (nextlex(), nexttok != EOFILE)
+                    fatserror("syntax error; expecting EOF");
+            }
+            fputs("=============================================================================\n",stdout);
+        loopend:
+            fclose(finptr);
+        } while( ++argv, --argc >= 1);
+        exit(nerror!=0);
+}
+
+
+
+putrunk()
+/*  function:  print revisions chosen, which are in trunk      */
+
+{
+        struct  hshentry        * ptr, * pre;
+
+        if (Head == nil) return;   /*  empty tree  */
+
+        pre = Head;
+        ptr = Head->next;
+        while( ptr ) {
+            putadelta(pre,ptr,true);
+            pre = ptr;
+            ptr = ptr->next;
+        }
+        putadelta(pre,ptr,true);
+}
+
+
+
+putree(root)
+struct  hshentry  *root;
+/*   function: print delta tree( not include trunck) in reversed calender
+               order on each branch                                        */
+
+{
+        if ( root == nil ) return;
+
+        putree(root->next);
+
+        putforest(root->branches);
+}
+
+
+
+
+putforest(branchroot)
+struct   branchhead     * branchroot;
+/*   function:  print branches that has the same direct ancestor    */
+{
+
+        if ( branchroot == nil ) return;
+
+        putforest(branchroot->nextbranch);
+
+        putabranch(branchroot->hsh);
+        putree(branchroot->hsh);
+}
+
+
+
+
+putabranch(root)
+struct      hshentry   *root;
+/*   function  :  print one branch     */
+
+{
+
+        if ( root == nil) return;
+
+        putabranch(root->next);
+
+        putadelta(root, root, false);
+}
+
+
+
+
+
+putadelta(node,editscript,trunk)
+register  struct   hshentry    * node;
+register  struct   hshentry    * editscript;
+int                              trunk;
+/*  function: print delta node if node->selector is 's'.        */
+/*      editscript indicates where the editscript is stored     */
+/*      trunk indicated whether this node is in trunk           */
+{
+        struct  branchhead      * newbranch;
+        char                    * branchnum,  branch[40];
+
+        if ( ( node == nil) || ( node->selector == 'u'))
+            return;
+
+        fprintf(stdout,"----------------------------\n");
+        fprintf(stdout, "revision %s        ",node->num);
+        if ( node->lockedby )
+           fprintf(stdout, "locked by: %s;       ", node->lockedby);
+        putc('\n', stdout);
+
+        fputs("date: ",stdout);
+        PRINTDATE(stdout,node->date); putc(' ',stdout);
+        PRINTTIME(stdout,node->date);
+        fprintf(stdout, ";  author: %s;  ", node->author);
+        fprintf(stdout, "state: %s;  ", node->state);
+
+        if ( editscript )
+           if(trunk)
+              fprintf(stdout,"lines added/del: %d/%d",
+                             editscript->deletelns, editscript->insertlns);
+           else
+              fprintf(stdout,"lines added/del: %d/%d",
+                             editscript->insertlns, editscript->deletelns);
+
+        putc('\n', stdout);
+
+        branchnum = & (branch[0]);
+        newbranch = node->branches;
+        if ( newbranch ) {
+           fputs("branches:  ", stdout);
+           while( newbranch ) {
+                getbranchno(newbranch->hsh->num, branchnum);
+                fprintf(stdout, "%s;  ", branchnum);
+                newbranch = newbranch->nextbranch;
+           }
+           putc('\n', stdout);
+        }
+
+        fputs(node->log,stdout);
+}
+
+
+
+
+
+readdeltalog()
+/*  Function : get the log message and skip the text of a deltatext node.
+ *             Return false if current block does not start with a number.
+ *             Assumes the current lexeme is not yet in nexttok; does not
+ *             advance nexttok.
+ */
+{
+        register struct  hshentry  * Delta;
+
+        nextlex();
+        if ( !(Delta = getnum() )) return(false);
+        if ( ! getkey(Klog) || ( nexttok != STRING ) )
+                fatserror("Missing log entry");
+        Delta->log = malloc(logsize);
+        savestring(Delta->log, logsize);
+        nextlex();
+        if ( ! getkey(Ktext) || (nexttok != STRING) )
+                fatserror("Missing delta text");
+        Delta->insertlns = Delta->deletelns = 0;
+        if ( Delta != Head)
+                getscript(Delta);
+        else
+                readstring();
+        return true;
+}
+
+
+
+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  */
+        register  int   c;
+        register  int   i;
+        int             length;
+
+        while( (ed = getc(finptr)) != EOF) {
+           /*  assume first none white character is command name  */
+            while( ed == '\n' || ed == ' ' || ed == '\t')
+                ed = getc(finptr);
+            if (ed == SDELIM) break;  /*  script text is ended   */
+            while( ( c = getc(finptr)) == ' ' );  /*  skip blank  */
+            if ( ! ('0' <= c && c <= '9')) {
+                faterror("Missing line number in edit script");
+                break;
+            }
+            while( '0' <= (c = getc(finptr)) && c <= '9' ) ;
+
+            while( c == ' ')c = getc(finptr);  /*  skip blanks  */
+            if ( !('0' <= c && c <= '9' ) ) {
+                faterror("Incorrect range in edit script");
+                break;
+            }
+            length = c - '0';
+            while( '0' <= (c = getc(finptr)) && c <= '9' )
+                length = length * 10 + c - '0';
+            while( c != '\n' && c != EOF) c = getc(finptr);
+            switch (ed) {
+            case 'd' :
+                 Delta->deletelns += length;
+                 break;
+
+            case 'a' :
+                 /*  skip scripted lines  */
+                 for ( i=length; i > 0 && c != EOF; i--){
+                     while( (c=getc(finptr)) != '\n' && c != EOF);
+                     Delta->insertlns++;
+                 }
+                 break;
+
+            default:
+                 faterror("Unknown command in edit script: %c", ed);
+                 break;
+            }
+        }
+        nextc = getc(finptr);
+}
+
+
+
+
+
+
+
+exttree(root)
+struct hshentry  *root;
+/*  function: select revisions , starting with root             */
+
+{
+        struct branchhead       * newbranch;
+
+        if (root == nil) return;
+
+        extractdelta(root);
+        exttree(root->next);
+
+        newbranch = root->branches;
+        while( newbranch ) {
+            exttree(newbranch->hsh);
+            newbranch = newbranch->nextbranch;
+        }
+}
+
+
+
+
+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 = ( struct lockers *)malloc( sizeof(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 == ';')  ;
+        }
+}
+
+
+
+getauthor(argv)
+char   *argv;
+/*   function:  get the author's name form command line   */
+/*              and store in aauthorlist                  */
+
+{
+        register    c;
+        struct     authors  * newauthor;
+
+        argv--;
+        while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' ||
+                 c == '\n' || c == ';')  ;
+        if ( c == '\0' ) {
+            authorlist = (struct authors *)malloc(sizeof(struct authors));
+            authorlist->login = caller;
+            authorlist->nextauthor  = nil;
+            return;
+        }
+
+        while( c != '\0' ) {
+            newauthor = (struct authors *)malloc(sizeof(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 == ';')  ;
+        }
+}
+
+
+
+
+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 = (struct stateattri *)malloc(sizeof(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 == ';')  ;
+        }
+}
+
+
+
+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  * 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;
+        }
+}
+
+
+
+recentdate(root, pd)
+struct         hshentry        * 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 interfal given by pd,           */
+/*             and sets the strtdate of pd to the date of the selected delta */
+{
+        struct  branchhead      * newbranch;
+
+       if ( root == nil) return;
+        if ( root->selector == 's') {
+             if ( cmpnum(root->date, pd->strtdate) >= 0 &&
+                  cmpnum(root->date, pd->enddate) <= 0)
+               strcpy(pd->strtdate, root->date);
+        }
+
+        recentdate(root->next, pd);
+        newbranch = root->branches;
+        while( newbranch) {
+           recentdate(newbranch->hsh, pd);
+           newbranch = newbranch->nextbranch;
+       }
+}
+
+
+
+
+
+
+extdate(root)
+struct  hshentry        * root;
+/*  function:  select revisions which are in the date range specified     */
+/*             in duelst  and datelist, start at root                     */
+
+{
+        struct  branchhead      * newbranch;
+        struct  Datepairs       * pdate;
+
+        if ( root == nil) return;
+
+        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;
+                while(pdate) {
+                   if ( cmpnum(root->date, pdate->strtdate) == 0)
+                      break;
+                   pdate = pdate->dnext;
+                }
+            }
+            if ( pdate == nil)
+                root->selector = 'u';
+        }
+        if (root->selector == 's') revno++;
+
+        extdate(root->next);
+
+        newbranch = root->branches;
+        while( newbranch ) {
+           extdate(newbranch->hsh);
+           newbranch = newbranch->nextbranch;
+        }
+}
+
+
+
+extractdelta(pdelta)
+struct  hshentry        * pdelta;
+/*  function:  compare information of pdelta to the authorlst, lockerlist, */
+/*             statelist, revlist and mark 's' on selector if pdelta is    */
+/*             selected; otherwise, mark 'u'                               */
+
+{
+        struct  lock            * plock;
+        struct  stateattri      * pstate;
+        struct  authors         * pauthor;
+        struct  Revpairs        * prevision;
+        int                       length;
+
+        pdelta->selector = 's';
+        if ( authorlist ) {  /*  certain author's revisions wanted only  */
+            pauthor = authorlist;
+            while((pauthor != nil) && ( strcmp(pauthor->login, pdelta->author)!=0))
+                pauthor = pauthor->nextauthor;
+            if ( pauthor == nil ) {
+                pdelta->selector = 'u';
+                return;
+            }
+        }
+        if ( statelist ) {   /* revisions with certain state wanted  */
+            pstate = statelist;
+            while((pstate != nil) && (strcmp(pstate->status, pdelta->state)!=0))
+                pstate = pstate->nextstate;
+            if ( pstate == nil ) {
+                pdelta->selector = 'u';
+                return;
+            }
+        }
+        if ( lockflag ) {    /*  locked revisions   */
+            plock = Locks;
+            while( plock && (plock->delta != pdelta))
+                plock = plock->nextlock;
+            if (plock == nil ) {
+                pdelta->selector = 'u';
+                return;
+            }
+        }
+        if ( Revlst ) {   /*  revisions or branches selected  */
+
+            prevision = Revlst;
+            while( prevision != nil ) {
+                length = prevision->numfld;
+                if ( length % 2 == 1) { /*  a branch number  */
+                     if ( countnumflds(pdelta->num) ==(length+1))
+                        if ( (compartial(pdelta->num, prevision->strtrev,length) >= 0)&&
+                             (compartial(prevision->endrev, pdelta->num, length) >= 0) )
+                             break;
+                }
+                else if ( countnumflds(pdelta->num ) == length)  /*  a revision */
+                    if ( (compartial(pdelta->num, prevision->strtrev, length) >= 0) &&
+                         (compartial(prevision->endrev, pdelta->num, length) >= 0) )
+                        break;
+                prevision = prevision->rnext;
+            }
+            if (prevision == nil)  {
+                pdelta->selector = 'u';
+                return;
+            }
+        }
+}
+
+
+
+char * procdate(target, source)
+char * target, * source;
+/* Function: Parses a free-format date in target, converts it
+ * into RCS internal format, and stores the result into source.
+ * Returns target on success, nil otherwise.
+ */
+{
+       long            unixtime;
+       struct     tm   parseddate,  *ftm;
+
+       if ( partime(source, &parseddate) == 0) {
+           error("Can't parse date/time: %s", source);
+           *target= '\0';
+           return nil;
+       }
+       if ( (unixtime = maketime(&parseddate)) == 0L) {
+           error("Inconsistent date/time: %s", source);
+           *target='\0';
+           return nil;
+       }
+       ftm = localtime(&unixtime);
+       sprintf(target,DATEFORM,
+       ftm->tm_year,ftm->tm_mon+1,ftm->tm_mday,ftm->tm_hour,ftm->tm_min,ftm->tm_sec);
+       return target;
+}
+
+
+
+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                    * 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 = (struct Datepairs *) malloc(sizeof(struct Datepairs));
+            if ( c == '<' ) {   /*   case: -d <date   */
+                c = *++argv;
+                (nextdate->strtdate)[0] = '\0';
+           } elsif (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;
+               if (procdate(switchflag?nextdate->enddate:nextdate->strtdate,
+                            rawdate)==nil) continue;
+               if ( c == ';' || c == '\0') {  /*  case: -d date  */
+                   strcpy(nextdate->enddate,nextdate->strtdate);
+                   sprintf(nextdate->strtdate,DATEFORM,0,0,0,0,0,0);
+                    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';
+           if (procdate(switchflag?nextdate->strtdate:nextdate->enddate,
+                        rawdate)==nil) continue;
+            nextdate->dnext = datelist;
+           datelist = nextdate;
+     end:
+/*
+           printf("startdate: %s; enddate: %s;\n", nextdate->strtdate,nextdate->enddate);
+*/
+           if ( c == '\0')  return;
+            while( (c = *++argv) == ';' || c == ' ' || c == '\t' || c =='\n');
+        }
+}
+
+
+
+
+
+getnumericrev()
+/*  function:  get the numeric name of revisions which stored in revlist  */
+/*             and then stored the numeric names in Revlst                */
+
+{
+        struct  Revpairs        * ptr, *pt;
+        int     flag;
+        char    *temprev;
+
+        /*  free the previous numeric revision list  */
+        pt = Revlst;
+        while( pt) {
+           free(pt);
+           pt = pt->rnext;
+        }
+        Nextdotstring = &Dotstring[0]; /* reset buffer */
+
+
+        Revlst = nil;
+        ptr = revlist;
+        while( ptr ) {
+            pt = (struct Revpairs *) malloc(sizeof(struct Revpairs));
+            if ( ptr->numfld == 1 ){ /*  case:  -r rev   */
+                if ( (flag = expandsym(ptr->strtrev, Nextdotstring)) == true ) {
+                    pt->numfld = countnumflds(Nextdotstring);
+                    pt->strtrev = pt->endrev = Nextdotstring;
+                    while( *Nextdotstring++ != '\0' )  ;
+                }
+            }
+            else if( ptr->numfld == 2){ /*  case: -r rev-   */
+                if ( (flag = expandsym(ptr->strtrev, Nextdotstring)) == true) {
+                    pt->numfld = countnumflds(Nextdotstring);
+                    pt->strtrev = Nextdotstring;
+                    while( *Nextdotstring++ != '\0' ) ;
+                    pt->endrev = Nextdotstring;
+                    if ( pt->numfld > 2) choptail(pt->strtrev);
+                    * Nextdotstring++ = '\0';
+                }
+             }
+             else if(ptr->numfld == 3)  { /*  case: -r -rev   */
+                if ( (flag = expandsym(ptr->endrev, Nextdotstring)) == true) {
+                    pt->endrev = Nextdotstring;
+                    while( *Nextdotstring++ != '\0' )  ;
+                    pt->numfld = countnumflds(pt->endrev);
+                    pt->strtrev = Nextdotstring;
+                    if ( pt->numfld == 2)
+                        *Nextdotstring++ = '1';
+                    else
+                        choptail(pt->endrev);
+                    *Nextdotstring++ = '.';
+                    *Nextdotstring++ = '1';
+                    *Nextdotstring++ = '\0';
+                }
+             }
+             else  {     /*   case:  -r rev1-rev2   */
+                if ( (flag = expandsym(ptr->strtrev, Nextdotstring)) == true ) {
+                    pt->strtrev = Nextdotstring;
+                    while( *Nextdotstring++ != '\0' )  ;
+                    if ( ( flag = expandsym(ptr->endrev, Nextdotstring)) == true)  {
+                        pt->numfld = countnumflds(pt->strtrev);
+                        pt->endrev = Nextdotstring;
+                        while( *Nextdotstring++ != '\0' ) ;
+                        if((flag = checkrevpair(pt->strtrev, pt->endrev)) == true)
+                           /*  switch pt->strtrev with pt->endrev, if pt->strtrev > pt->endre  */
+                            if (compartial(pt->strtrev, pt->endrev, pt->numfld) > 0 ) {
+                                temprev = pt->strtrev;
+                                pt->strtrev = pt->endrev;
+                                pt->endrev = temprev;
+                            }
+                     }
+                }
+             }
+
+             if ( flag ){
+                pt->rnext = Revlst;
+                Revlst = pt;
+             }
+             else
+                free(pt);
+             ptr = ptr->rnext;
+        }
+
+}
+
+
+
+checkrevpair(num1,num2)
+char    *num1,  *num2;
+/*  function:  check whether num1, num2 are legal pair,i.e.
+    only the last field are different and have same number of
+    feilds( if length <= 2, may be different if first field)   */
+
+{
+        int    length;
+
+        if ( (length = countnumflds(num1)) != countnumflds(num2) ) {
+            error(" Invalid branch or revision pair %s : %s", num1, num2);
+            return false;
+        }
+        if ( length > 2 )
+            if (compartial(num1, num2, length-1) != 0) {
+                error("Invalid branch or revision pair %s : %s", num1, num2);
+                return false;
+            }
+
+        return true;
+}
+
+
+
+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         flag;
+
+        argv--;
+        while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' ||
+                 c == '\n' || c == ';')  ;
+        if ( c == '\0' ) {
+            warn(" Missing revision or branch number after -r");
+            return;
+        }
+
+        while( c != '\0') {
+            while(  c  == ',' || c == ' ' || c == '\t' ||
+                     c == '\n' || c == ';') c = *++argv;
+            if (c == '\0')  return;
+            nextrevpair = (struct Revpairs *) malloc(sizeof(struct Revpairs));
+            nextrevpair->rnext = revlist;
+            revlist = nextrevpair;
+            nextrevpair->numfld  = nil;
+            nextrevpair->strtrev = nil;
+            nextrevpair->endrev  = nil;
+            flag = false;
+            if (  c == '<' || c == '-' ) {  /*  case: -r -rev  or -r <rev  */
+                flag = true;
+                while( (c =(*++argv)) == ' ' || c == '\t' || c =='\n') ;
+            }
+            else {
+                nextrevpair->strtrev = argv;
+                /*   get a revision or branch name  */
+                while( c != ',' && c != ';' && c != ' ' && c != '\0' && c != '-'
+                        && c != '\t' && c != '\n' && c != '<') c = *++argv;
+
+                *argv = '\0';
+
+                if ( c != '<' && c != '-') {    /*  case: rev  */
+                    nextrevpair->numfld = 1;
+                    continue;
+                }
+
+                if ( (c =(*++argv)) == ',' || c == '\0' || c == ' '
+                      || c == '\t' || c == '\n' || c == ';') {/*  case: rev_  */
+                    nextrevpair->numfld = 2;
+                    continue;
+                }
+            }
+            nextrevpair->endrev = argv;
+            while( c != ',' && c != ' ' && c != '\0' && c != '\t' && c != '<'
+                   && c != '\n' && c != '-' && c != ';')  c = *++argv;
+
+            * argv = '\0';
+            if ( c == '<'){
+                error("seperator expected near %s", nextrevpair->endrev);
+                while( (c = *++argv) != ',' && c != ' ' && c != '\0' &&
+                        c != '\t' && c != '\n' && c != ';' ) ;
+                revlist = nextrevpair->rnext;
+                continue;
+            }
+            else  {
+                if (flag)   /*  case:  -rev   */
+                    nextrevpair->numfld  = 3;
+
+                else     /*   rev1-rev2  appears  */
+                    nextrevpair->numfld = 4;
+            }
+        }
+}
+
+
+
+choptail(strhead)
+char     * strhead;
+/*   function : chop off the last field of a branch or a revision number  */
+
+{
+        char    *pt, *sp;
+
+        for(pt = Nextdotstring-1; pt != strhead && *pt != '.'; pt--) ;
+        for(sp = strhead; sp < pt; sp++) *Nextdotstring++ = *sp;
+}
+