1 /* Print log messages and other information about RCS files. */
3 /* Copyright 1982, 1988, 1989 Walter Tichy
4 Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
5 Distributed under license by the Free Software Foundation, Inc.
7 This file is part of RCS.
9 RCS is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
14 RCS is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with RCS; see the file COPYING.
21 If not, write to the Free Software Foundation,
22 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 Report problems and direct all questions to:
26 rcs-bugs@cs.purdue.edu
31 * $FreeBSD: src/gnu/usr.bin/rcs/rlog/rlog.c,v 1.13 1999/08/27 23:36:59 peter Exp $
32 * $DragonFly: src/gnu/usr.bin/rcs/rlog/rlog.c,v 1.3 2007/01/17 17:56:24 y0netan1 Exp $
34 * Revision 5.18 1995/06/16 06:19:24 eggert
37 * Revision 5.17 1995/06/01 16:23:43 eggert
38 * (struct rcslockers): Renamed from `struct lockers'.
39 * (getnumericrev): Return error indication instead of ignoring errors.
40 * (main): Check it. Don't use dateform.
41 * (recentdate, extdate): cmpnum -> cmpdate
43 * Revision 5.16 1994/04/13 16:30:34 eggert
44 * Fix bug; `rlog -lxxx' inverted the sense of -l.
46 * Revision 5.15 1994/03/17 14:05:48 eggert
47 * -d'<DATE' now excludes DATE; the new syntax -d'<=DATE' includes it.
48 * Emulate -V4's white space generation more precisely.
49 * Work around SVR4 stdio performance bug. Remove lint.
51 * Revision 5.14 1993/11/09 17:40:15 eggert
52 * -V now prints version on stdout and exits.
54 * Revision 5.13 1993/11/03 17:42:27 eggert
55 * Add -N, -z. Ignore -T.
57 * Revision 5.12 1992/07/28 16:12:44 eggert
58 * Don't miss B.0 when handling branch B. Diagnose missing `,' in -r.
59 * Add -V. Avoid `unsigned'. Statement macro names now end in _.
61 * Revision 5.11 1992/01/24 18:44:19 eggert
62 * Don't duplicate unexpected_EOF's function. lint -> RCS_lint
64 * Revision 5.10 1992/01/06 02:42:34 eggert
65 * Update usage string.
66 * while (E) ; -> while (E) continue;
68 * Revision 5.9 1991/09/17 19:07:40 eggert
69 * Getscript() didn't uncache partial lines.
71 * Revision 5.8 1991/08/19 03:13:55 eggert
72 * Revision separator is `:', not `-'.
73 * Check for missing and duplicate logs. Tune.
74 * Permit log messages that do not end in newline (including empty logs).
76 * Revision 5.7 1991/04/21 11:58:31 eggert
77 * Add -x, RCSINIT, MS-DOS support.
79 * Revision 5.6 1991/02/26 17:07:17 eggert
80 * Survive RCS files with missing logs.
81 * strsave -> str_save (DG/UX name clash)
83 * Revision 5.5 1990/11/01 05:03:55 eggert
84 * Permit arbitrary data in logs and comment leaders.
86 * Revision 5.4 1990/10/04 06:30:22 eggert
87 * Accumulate exit status across files.
89 * Revision 5.3 1990/09/11 02:41:16 eggert
92 * Revision 5.2 1990/09/04 08:02:33 eggert
93 * Count RCS lines better.
95 * Revision 5.0 1990/08/22 08:13:48 eggert
96 * Remove compile-time limits; use malloc instead. Add setuid support.
98 * Report dates in long form, to warn about dates past 1999/12/31.
99 * Change "added/del" message to make room for the longer dates.
100 * Don't generate trailing white space. Add -V. Ansify and Posixate.
102 * Revision 4.7 89/05/01 15:13:48 narten
103 * changed copyright header to reflect current distribution rules
105 * Revision 4.6 88/08/09 19:13:28 eggert
106 * Check for memory exhaustion; don't access freed storage.
107 * Shrink stdio code size; remove lint.
109 * Revision 4.5 87/12/18 11:46:38 narten
110 * more lint cleanups (Guy Harris)
112 * Revision 4.4 87/10/18 10:41:12 narten
113 * Updating version numbers
114 * Changes relative to 1.1 actually relative to 4.2
116 * Revision 1.3 87/09/24 14:01:10 narten
117 * Sources now pass through lint (if you ignore printf/sprintf/fprintf
120 * Revision 1.2 87/03/27 14:22:45 jenkins
123 * Revision 4.2 83/12/05 09:18:09 wft
124 * changed rewriteflag to external.
126 * Revision 4.1 83/05/11 16:16:55 wft
127 * Added -b, updated getnumericrev() accordingly.
128 * Replaced getpwuid() with getcaller().
130 * Revision 3.7 83/05/11 14:24:13 wft
131 * Added options -L and -R;
132 * Fixed selection bug with -l on multiple files.
133 * Fixed error on dates of the form -d'>date' (rewrote getdatepair()).
135 * Revision 3.6 82/12/24 15:57:53 wft
136 * shortened output format.
138 * Revision 3.5 82/12/08 21:45:26 wft
139 * removed call to checkaccesslist(); used DATEFORM to format all dates;
140 * removed unused variables.
142 * Revision 3.4 82/12/04 13:26:25 wft
143 * Replaced getdelta() with gettree(); removed updating of field lockedby.
145 * Revision 3.3 82/12/03 14:08:20 wft
146 * Replaced getlogin with getpwuid(), %02d with %.2d, fancydate with PRINTDATE.
147 * Fixed printing of nil, removed printing of Suffix,
148 * added shortcut if no revisions are printed, disambiguated struct members.
150 * Revision 3.2 82/10/18 21:09:06 wft
151 * call to curdir replaced with getfullRCSname(),
152 * fixed call to getlogin(), cosmetic changes on output,
153 * changed conflicting long identifiers.
155 * Revision 3.1 82/10/13 16:07:56 wft
156 * fixed type of variables receiving from getc() (char -> int).
163 struct rcslockers
{ /* lockers in locker option; stored */
164 char const * login
; /* lockerlist */
165 struct rcslockers
* lockerlink
;
168 struct stateattri
{ /* states in state option; stored in */
169 char const * status
; /* statelist */
170 struct stateattri
* nextstate
;
173 struct authors
{ /* login names in author option; */
174 char const * login
; /* stored in authorlist */
175 struct authors
* nextauthor
;
178 struct Revpairs
{ /* revision or branch range in -r */
179 int numfld
; /* option; stored in revlist */
180 char const * strtrev
;
182 struct Revpairs
* rnext
;
185 struct Datepairs
{ /* date range in -d option; stored in */
186 struct Datepairs
*dnext
;
187 char strtdate
[datesize
]; /* duelst and datelist */
188 char enddate
[datesize
];
189 char ne_date
; /* datelist only; distinguishes < from <= */
192 static char extractdelta
P((struct hshentry
const*));
193 static int checkrevpair
P((char const*,char const*));
194 static int extdate
P((struct hshentry
*));
195 static int getnumericrev
P((void));
196 static struct hshentry
const *readdeltalog
P((void));
197 static void cleanup
P((void));
198 static void exttree
P((struct hshentry
*));
199 static void getauthor
P((char*));
200 static void getdatepair
P((char*));
201 static void getlocker
P((char*));
202 static void getrevpairs
P((char*));
203 static void getscript
P((struct hshentry
*));
204 static void getstate
P((char*));
205 static void putabranch
P((struct hshentry
const*));
206 static void putadelta
P((struct hshentry
const*,struct hshentry
const*,int));
207 static void putforest
P((struct branchhead
const*));
208 static void putree
P((struct hshentry
const*));
209 static void putrunk
P((void));
210 static void recentdate
P((struct hshentry
const*,struct Datepairs
*));
211 static void trunclocks
P((void));
213 static char const *insDelFormat
;
214 static int branchflag
; /*set on -b */
215 static int exitstatus
;
217 static struct Datepairs
*datelist
, *duelst
;
218 static struct Revpairs
*revlist
, *Revlst
;
219 static struct authors
*authorlist
;
220 static struct rcslockers
*lockerlist
;
221 static struct stateattri
*statelist
;
224 mainProg(rlogId
, "rlog", "$DragonFly: src/gnu/usr.bin/rcs/rlog/rlog.c,v 1.3 2007/01/17 17:56:24 y0netan1 Exp $")
226 static char const cmdusage
[] =
227 "\nrlog usage: rlog -{bhLNRt} -v[string] -ddates -l[lockers] -r[revs] -sstates -Vn -w[logins] -xsuff -zzone file ...";
231 struct Datepairs
*currdate
;
232 char const *accessListString
, *accessFormat
;
233 char const *headFormat
, *symbolFormat
;
234 struct access
const *curaccess
;
235 struct assoc
const *curassoc
;
236 struct hshentry
const *delta
;
237 struct rcslock
const *currlock
;
238 int descflag
, selectflag
;
239 int onlylockflag
; /* print only files with locks */
240 int onlyRCSflag
; /* print only RCS pathname */
247 descflag
= selectflag
= shownames
= true;
248 versionlist
= onlylockflag
= onlyRCSflag
= false;
251 suffixes
= X_DEFAULT
;
253 argc
= getRCSINIT(argc
, argv
, &newargv
);
255 while (a
= *++argv
, 0<--argc
&& *a
++=='-') {
304 /* This has no effect; it's here for consistency. */
317 /* Ignore -T, so that RCSINIT can contain -T. */
323 setRCSversion(*argv
);
333 error("unknown option: %s%s", *argv
, cmdusage
);
336 } /* end of option processing */
338 if (! (descflag
|selectflag
)) {
339 warn("-t overrides -h.");
343 pre5
= RCSversion
< VERSION(5);
345 accessListString
= "\naccess list: ";
346 accessFormat
= " %s";
347 headFormat
= "RCS file: %s; Working file: %s\nhead: %s%s\nbranch: %s%s\nlocks: ";
348 insDelFormat
= " lines added/del: %ld/%ld";
349 symbolFormat
= " %s: %s;";
351 accessListString
= "\naccess list:";
352 accessFormat
= "\n\t%s";
353 headFormat
= "RCS file: %s\nWorking file: %s\nhead:%s%s\nbranch:%s%s\nlocks:%s";
354 insDelFormat
= " lines: +%ld -%ld";
355 symbolFormat
= "\n\t%s: %s";
358 /* Now handle all pathnames. */
362 faterror("no input file%s", cmdusage
);
364 for (; 0 < argc
; cleanup(), ++argv
, --argc
) {
367 if (pairnames(argc
, argv
, rcsreadopen
, true, false) <= 0)
371 * RCSname contains the name of the RCS file,
372 * and finptr the file descriptor;
373 * workname contains the name of the working file.
376 /* Keep only those locks given by -l. */
380 /* do nothing if -L is given and there are no locks*/
381 if (onlylockflag
&& !Locks
)
386 aprintf(out
, "%s%s %s\n", vstring
, workname
, tiprev());
391 aprintf(out
, "%s\n", RCSname
);
397 if (!getnumericrev())
401 * Output the first character with putc, not printf.
402 * Otherwise, an SVR4 stdio bug buffers output inefficiently.
406 /* print RCS pathname, working pathname and optional
407 administrative information */
408 /* could use getfullRCSname() here, but that is very slow */
409 aprintf(out
, headFormat
, RCSname
, workname
,
410 Head
? " " : "", Head
? Head
->num
: "",
411 Dbranch
? " " : "", Dbranch
? Dbranch
: "",
412 StrictLocks
? " strict" : ""
416 aprintf(out
, symbolFormat
, currlock
->login
,
417 currlock
->delta
->num
);
418 currlock
= currlock
->nextlock
;
420 if (StrictLocks
&& pre5
)
421 aputs(" ; strict" + (Locks
?3:0), out
);
423 aputs(accessListString
, out
); /* print access list */
424 curaccess
= AccessList
;
426 aprintf(out
, accessFormat
, curaccess
->login
);
427 curaccess
= curaccess
->nextaccess
;
431 aputs("\nsymbolic names:", out
); /* print symbolic names */
432 for (curassoc
=Symbols
; curassoc
; curassoc
=curassoc
->nextassoc
)
433 aprintf(out
, symbolFormat
, curassoc
->symbol
, curassoc
->num
);
436 aputs("\ncomment leader: \"", out
);
437 awrite(Comment
.string
, Comment
.size
, out
);
440 if (!pre5
|| Expand
!= KEYVAL_EXPAND
)
441 aprintf(out
, "\nkeyword substitution: %s",
445 aprintf(out
, "\ntotal revisions: %d", TotalDeltas
);
449 if (Head
&& selectflag
& descflag
) {
453 /* get most recently date of the dates pointed by duelst */
456 VOID
strcpy(currdate
->strtdate
, "0.0.0.0.0.0");
457 recentdate(Head
, currdate
);
458 currdate
= currdate
->dnext
;
461 revno
= extdate(Head
);
463 aprintf(out
, ";\tselected revisions: %d", revno
);
468 aputs("description:\n", out
);
472 while (! (delta
= readdeltalog())->selector
|| --revno
)
474 if (delta
->next
&& countnumflds(delta
->num
)==2)
475 /* Read through delta->next to get its insertlns. */
476 while (readdeltalog() != delta
->next
)
481 aputs("----------------------------\n", out
);
482 aputs("=============================================================================\n",out
);
485 exitmain(exitstatus
);
491 if (nerror
) exitstatus
= EXIT_FAILURE
;
496 # define exiterr rlogExit
508 /* function: print revisions chosen, which are in trunk */
511 register struct hshentry
const *ptr
;
513 for (ptr
= Head
; ptr
; ptr
= ptr
->next
)
514 putadelta(ptr
, ptr
->next
, true);
521 struct hshentry
const *root
;
522 /* function: print delta tree (not including trunk) in reverse
523 order on each branch */
530 putforest(root
->branches
);
537 putforest(branchroot
)
538 struct branchhead
const *branchroot
;
539 /* function: print branches that has the same direct ancestor */
541 if (!branchroot
) return;
543 putforest(branchroot
->nextbranch
);
545 putabranch(branchroot
->hsh
);
546 putree(branchroot
->hsh
);
554 struct hshentry
const *root
;
555 /* function : print one branch */
560 putabranch(root
->next
);
562 putadelta(root
, root
, false);
570 putadelta(node
,editscript
,trunk
)
571 register struct hshentry
const *node
, *editscript
;
573 /* function: Print delta node if node->selector is set. */
574 /* editscript indicates where the editscript is stored */
575 /* trunk indicated whether this node is in trunk */
577 static char emptych
[] = EMPTYLOG
;
582 struct branchhead
const *newbranch
;
583 struct buf branchnum
;
584 char datebuf
[datesize
+ zonelenmax
];
585 int pre5
= RCSversion
< VERSION(5);
592 "----------------------------\nrevision %s%s",
593 node
->num
, pre5
? " " : ""
595 if ( node
->lockedby
)
596 aprintf(out
, pre5
+"\tlocked by: %s;", node
->lockedby
);
598 aprintf(out
, "\ndate: %s; author: %s; state: %s;",
599 date2str(node
->date
, datebuf
),
600 node
->author
, node
->state
605 aprintf(out
, insDelFormat
,
606 editscript
->deletelns
, editscript
->insertlns
);
608 aprintf(out
, insDelFormat
,
609 editscript
->insertlns
, editscript
->deletelns
);
612 if ( node
->commitid
)
613 aprintf(out
, "%s commitid: %s", (editscript
) ? ";" : "",
616 newbranch
= node
->branches
;
618 bufautobegin(&branchnum
);
619 aputs("\nbranches:", out
);
621 getbranchno(newbranch
->hsh
->num
, &branchnum
);
622 aprintf(out
, " %s;", branchnum
.string
);
623 newbranch
= newbranch
->nextbranch
;
625 bufautoend(&branchnum
);
629 s
= node
->log
.string
;
630 if (!(n
= node
->log
.size
)) {
632 n
= sizeof(emptych
)-1;
640 static struct hshentry
const *
642 /* Function : get the log message and skip the text of a deltatext node.
643 * Return the delta found.
644 * Assumes the current lexeme is not yet in nexttok; does not
648 register struct hshentry
* Delta
;
653 fatserror("missing delta log");
655 if (!(Delta
= getnum()))
656 fatserror("delta number corrupted");
658 if (Delta
->log
.string
)
659 fatserror("duplicate delta log");
660 bufautobegin(&logbuf
);
661 cb
= savestring(&logbuf
);
662 Delta
->log
= bufremember(&logbuf
, cb
.size
);
664 ignorephrases(Ktext
);
666 Delta
->insertlns
= Delta
->deletelns
= 0;
677 struct hshentry
* Delta
;
678 /* function: read edit script of Delta and count how many lines added */
679 /* and deleted in the script */
682 int ed
; /* editor command */
692 while (0 <= (ed
= getdiffcmd(fin
,true,(FILE *)0,&dc
)))
694 Delta
->deletelns
+= dc
.nlines
;
696 /* skip scripted lines */
698 Delta
->insertlns
+= i
;
734 struct hshentry
*root
;
735 /* function: select revisions , starting with root */
738 struct branchhead
const *newbranch
;
742 root
->selector
= extractdelta(root
);
743 root
->log
.string
= 0;
746 newbranch
= root
->branches
;
748 exttree(newbranch
->hsh
);
749 newbranch
= newbranch
->nextbranch
;
759 /* function : get the login names of lockers from command line */
760 /* and store in lockerlist. */
764 struct rcslockers
*newlocker
;
766 while ((c
= *++argv
)==',' || c
==' ' || c
=='\t' || c
=='\n' || c
==';')
774 newlocker
= talloc(struct rcslockers
);
775 newlocker
->lockerlink
= lockerlist
;
776 newlocker
->login
= argv
;
777 lockerlist
= newlocker
;
778 while ((c
= *++argv
) && c
!=',' && c
!=' ' && c
!='\t' && c
!='\n' && c
!=';')
781 if ( c
== '\0' ) return;
782 while ((c
= *++argv
)==',' || c
==' ' || c
=='\t' || c
=='\n' || c
==';')
792 /* function: get the author's name from command line */
793 /* and store in authorlist */
797 struct authors
* newauthor
;
800 while ((c
= *++argv
)==',' || c
==' ' || c
=='\t' || c
=='\n' || c
==';')
803 authorlist
= talloc(struct authors
);
804 authorlist
->login
= getusername(false);
805 authorlist
->nextauthor
= 0;
810 newauthor
= talloc(struct authors
);
811 newauthor
->nextauthor
= authorlist
;
812 newauthor
->login
= argv
;
813 authorlist
= newauthor
;
814 while ((c
= *++argv
) && c
!=',' && c
!=' ' && c
!='\t' && c
!='\n' && c
!=';')
817 if ( c
== '\0') return;
818 while ((c
= *++argv
)==',' || c
==' ' || c
=='\t' || c
=='\n' || c
==';')
829 /* function : get the states of revisions from command line */
830 /* and store in statelist */
834 struct stateattri
*newstate
;
837 while ((c
= *++argv
)==',' || c
==' ' || c
=='\t' || c
=='\n' || c
==';')
840 error("missing state attributes after -s options");
845 newstate
= talloc(struct stateattri
);
846 newstate
->nextstate
= statelist
;
847 newstate
->status
= argv
;
848 statelist
= newstate
;
849 while ((c
= *++argv
) && c
!=',' && c
!=' ' && c
!='\t' && c
!='\n' && c
!=';')
852 if ( c
== '\0' ) return;
853 while ((c
= *++argv
)==',' || c
==' ' || c
=='\t' || c
=='\n' || c
==';')
862 /* Function: Truncate the list of locks to those that are held by the */
863 /* id's on lockerlist. Do not truncate if lockerlist empty. */
866 struct rcslockers
const *plocker
;
867 struct rcslock
*p
, **pp
;
869 if (!lockerlist
) return;
871 /* shorten Locks to those contained in lockerlist */
872 for (pp
= &Locks
; (p
= *pp
); )
873 for (plocker
= lockerlist
; ; )
874 if (strcmp(plocker
->login
, p
->login
) == 0) {
877 } else if (!(plocker
= plocker
->lockerlink
)) {
887 struct hshentry
const *root
;
888 struct Datepairs
*pd
;
889 /* function: Finds the delta that is closest to the cutoff date given by */
890 /* pd among the revisions selected by exttree. */
891 /* Successively narrows down the interval given by pd, */
892 /* and sets the strtdate of pd to the date of the selected delta */
894 struct branchhead
const *newbranch
;
897 if (root
->selector
) {
898 if ( cmpdate(root
->date
, pd
->strtdate
) >= 0 &&
899 cmpdate(root
->date
, pd
->enddate
) <= 0)
900 VOID
strcpy(pd
->strtdate
, root
->date
);
903 recentdate(root
->next
, pd
);
904 newbranch
= root
->branches
;
906 recentdate(newbranch
->hsh
, pd
);
907 newbranch
= newbranch
->nextbranch
;
918 struct hshentry
* root
;
919 /* function: select revisions which are in the date range specified */
920 /* in duelst and datelist, start at root */
921 /* Yield number of revisions selected, including those already selected. */
923 struct branchhead
const *newbranch
;
924 struct Datepairs
const *pdate
;
930 if ( datelist
|| duelst
) {
936 || ne
<= cmpdate(root
->date
, pdate
->strtdate
))
939 || ne
<= cmpdate(pdate
->enddate
, root
->date
))
942 pdate
= pdate
->dnext
;
948 root
->selector
= false;
951 if (cmpdate(root
->date
, pdate
->strtdate
) == 0)
953 pdate
= pdate
->dnext
;
957 revno
= root
->selector
+ extdate(root
->next
);
959 newbranch
= root
->branches
;
961 revno
+= extdate(newbranch
->hsh
);
962 newbranch
= newbranch
->nextbranch
;
971 struct hshentry
const *pdelta
;
972 /* function: compare information of pdelta to the authorlist, lockerlist,*/
973 /* statelist, revlist and yield true if pdelta is selected. */
976 struct rcslock
const *plock
;
977 struct stateattri
const *pstate
;
978 struct authors
const *pauthor
;
979 struct Revpairs
const *prevision
;
982 if ((pauthor
= authorlist
)) /* only certain authors wanted */
983 while (strcmp(pauthor
->login
, pdelta
->author
) != 0)
984 if (!(pauthor
= pauthor
->nextauthor
))
986 if ((pstate
= statelist
)) /* only certain states wanted */
987 while (strcmp(pstate
->status
, pdelta
->state
) != 0)
988 if (!(pstate
= pstate
->nextstate
))
990 if (lockflag
) { /* only locked revisions wanted */
991 for (plock
= Locks
; ; plock
= plock
->nextlock
) {
994 else if (plock
->delta
== pdelta
)
998 if ((prevision
= Revlst
)) /* only certain revs or branches wanted */
1000 length
= prevision
->numfld
;
1002 countnumflds(pdelta
->num
) == length
+(length
&1) &&
1003 0 <= compartial(pdelta
->num
, prevision
->strtrev
, length
) &&
1004 0 <= compartial(prevision
->endrev
, pdelta
->num
, length
)
1007 if (!(prevision
= prevision
->rnext
))
1018 /* function: get time range from command line and store in datelist if */
1019 /* a time range specified or in duelst if a time spot specified */
1023 struct Datepairs
* nextdate
;
1024 char const * rawdate
;
1028 while ((c
= *++argv
)==',' || c
==' ' || c
=='\t' || c
=='\n' || c
==';')
1031 error("missing date/time after -d");
1035 while( c
!= '\0' ) {
1037 nextdate
= talloc(struct Datepairs
);
1038 if ( c
== '<' ) { /* case: -d <date */
1040 if (!(nextdate
->ne_date
= c
!='='))
1042 (nextdate
->strtdate
)[0] = '\0';
1043 } else if (c
== '>') { /* case: -d'>date' */
1045 if (!(nextdate
->ne_date
= c
!='='))
1047 (nextdate
->enddate
)[0] = '\0';
1051 while( c
!= '<' && c
!= '>' && c
!= ';' && c
!= '\0')
1054 if ( c
== '>' ) switchflag
=true;
1056 switchflag
? nextdate
->enddate
: nextdate
->strtdate
);
1057 if ( c
== ';' || c
== '\0') { /* case: -d date */
1058 VOID
strcpy(nextdate
->enddate
,nextdate
->strtdate
);
1059 nextdate
->dnext
= duelst
;
1063 /* case: -d date< or -d date>; see switchflag */
1064 int eq
= argv
[1]=='=';
1065 nextdate
->ne_date
= !eq
;
1067 while ((c
= *++argv
) == ' ' || c
=='\t' || c
=='\n')
1069 if ( c
== ';' || c
== '\0') {
1070 /* second date missing */
1072 *nextdate
->strtdate
= '\0';
1074 *nextdate
->enddate
= '\0';
1075 nextdate
->dnext
= datelist
;
1076 datelist
= nextdate
;
1082 while( c
!= '>' && c
!= '<' && c
!= ';' && c
!= '\0')
1086 switchflag
? nextdate
->strtdate
: nextdate
->enddate
);
1087 nextdate
->dnext
= datelist
;
1088 datelist
= nextdate
;
1090 if (RCSversion
< VERSION(5))
1091 nextdate
->ne_date
= 0;
1092 if ( c
== '\0') return;
1093 while ((c
= *++argv
) == ';' || c
== ' ' || c
== '\t' || c
=='\n')
1102 /* function: get the numeric name of revisions which stored in revlist */
1103 /* and then stored the numeric names in Revlst */
1104 /* if branchflag, also add default branch */
1107 struct Revpairs
* ptr
, *pt
;
1111 struct buf
const *rstart
, *rend
;
1122 switch (ptr
->numfld
) {
1125 if (!expandsym(ptr
->strtrev
, &s
))
1128 n
= countnumflds(s
.string
);
1129 if (!n
&& (lrev
= tiprev())) {
1131 n
= countnumflds(lrev
);
1135 case 2: /* -rREV: */
1136 if (!expandsym(ptr
->strtrev
, &s
))
1138 bufscpy(&e
, s
.string
);
1139 n
= countnumflds(s
.string
);
1140 (n
<2 ? e
.string
: strrchr(e
.string
,'.'))[0] = 0;
1143 case 3: /* -r:REV */
1144 if (!expandsym(ptr
->endrev
, &e
))
1146 if ((n
= countnumflds(e
.string
)) < 2)
1149 bufscpy(&s
, e
.string
);
1150 VOID
strcpy(strrchr(s
.string
,'.'), ".0");
1154 default: /* -rREV1:REV2 */
1156 expandsym(ptr
->strtrev
, &s
)
1157 && expandsym(ptr
->endrev
, &e
)
1158 && checkrevpair(s
.string
, e
.string
)
1161 n
= countnumflds(s
.string
);
1162 /* Swap if out of order. */
1163 if (compartial(s
.string
,e
.string
,n
) > 0) {
1171 pt
= ftalloc(struct Revpairs
);
1173 pt
->strtrev
= fstr_save(rstart
->string
);
1174 pt
->endrev
= fstr_save(rend
->string
);
1180 /* Now take care of branchflag */
1181 if (branchflag
&& (Dbranch
||Head
)) {
1182 pt
= ftalloc(struct Revpairs
);
1183 pt
->strtrev
= pt
->endrev
=
1184 Dbranch
? Dbranch
: fstr_save(partialno(&s
,Head
->num
,1));
1185 pt
->rnext
=Revlst
; Revlst
=pt
;
1186 pt
->numfld
= countnumflds(pt
->strtrev
);
1198 checkrevpair(num1
,num2
)
1199 char const *num1
, *num2
;
1200 /* function: check whether num1, num2 are legal pair,i.e.
1201 only the last field are different and have same number of
1202 fields( if length <= 2, may be different if first field) */
1205 int length
= countnumflds(num1
);
1208 countnumflds(num2
) != length
1209 || (2 < length
&& compartial(num1
, num2
, length
-1) != 0)
1211 rcserror("invalid branch or revision pair %s : %s", num1
, num2
);
1222 register char * argv
;
1223 /* function: get revision or branch range from command line, and */
1224 /* store in revlist */
1228 struct Revpairs
* nextrevpair
;
1233 /* Support old ambiguous '-' syntax; this will go away. */
1234 if (strchr(argv
,':'))
1237 if (strchr(argv
,'-') && VERSION(5) <= RCSversion
)
1238 warn("`-' is obsolete in `-r%s'; use `:' instead", argv
);
1243 while (c
==' ' || c
=='\t' || c
=='\n')
1245 nextrevpair
= talloc(struct Revpairs
);
1246 nextrevpair
->rnext
= revlist
;
1247 revlist
= nextrevpair
;
1248 nextrevpair
->numfld
= 1;
1249 nextrevpair
->strtrev
= argv
;
1250 for (;; c
= *++argv
) {
1254 case '\0': case ' ': case '\t': case '\n':
1265 while (c
==' ' || c
=='\t' || c
=='\n')
1267 if (c
== separator
) {
1268 while ((c
= *++argv
) == ' ' || c
== '\t' || c
=='\n')
1270 nextrevpair
->endrev
= argv
;
1271 for (;; c
= *++argv
) {
1275 case '\0': case ' ': case '\t': case '\n':
1286 while (c
==' ' || c
=='\t' || c
=='\n')
1288 nextrevpair
->numfld
=
1289 !nextrevpair
->endrev
[0] ? 2 /* -rREV: */ :
1290 !nextrevpair
->strtrev
[0] ? 3 /* -r:REV */ :
1291 4 /* -rREV1:REV2 */;
1295 else if (c
==',' || c
==';')
1298 error("missing `,' near `%c%s'", c
, argv
+1);