1 /* $NetBSD: rlog.c,v 1.1.1.2 1996/10/13 21:57:27 veego Exp $ */
3 /* Print log messages and other information about RCS files. */
5 /* Copyright 1982, 1988, 1989 Walter Tichy
6 Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
7 Distributed under license by the Free Software Foundation, Inc.
9 This file is part of RCS.
11 RCS is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
16 RCS is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with RCS; see the file COPYING.
23 If not, write to the Free Software Foundation,
24 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 Report problems and direct all questions to:
28 rcs-bugs@cs.purdue.edu
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", "Id: rlog.c,v 5.18 1995/06/16 06:19:24 eggert Exp")
226 static char const cmdusage
[] =
227 "\nrlog usage: rlog -{bhLNRt} -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 */
245 descflag
= selectflag
= shownames
= true;
246 onlylockflag
= onlyRCSflag
= false;
248 suffixes
= X_DEFAULT
;
250 argc
= getRCSINIT(argc
, argv
, &newargv
);
252 while (a
= *++argv
, 0<--argc
&& *a
++=='-') {
301 /* This has no effect; it's here for consistency. */
314 /* Ignore -T, so that RCSINIT can contain -T. */
320 setRCSversion(*argv
);
325 error("unknown option: %s%s", *argv
, cmdusage
);
328 } /* end of option processing */
330 if (! (descflag
|selectflag
)) {
331 warn("-t overrides -h.");
335 pre5
= RCSversion
< VERSION(5);
337 accessListString
= "\naccess list: ";
338 accessFormat
= " %s";
339 headFormat
= "RCS file: %s; Working file: %s\nhead: %s%s\nbranch: %s%s\nlocks: ";
340 insDelFormat
= " lines added/del: %ld/%ld";
341 symbolFormat
= " %s: %s;";
343 accessListString
= "\naccess list:";
344 accessFormat
= "\n\t%s";
345 headFormat
= "RCS file: %s\nWorking file: %s\nhead:%s%s\nbranch:%s%s\nlocks:%s";
346 insDelFormat
= " lines: +%ld -%ld";
347 symbolFormat
= "\n\t%s: %s";
350 /* Now handle all pathnames. */
354 faterror("no input file%s", cmdusage
);
356 for (; 0 < argc
; cleanup(), ++argv
, --argc
) {
359 if (pairnames(argc
, argv
, rcsreadopen
, true, false) <= 0)
363 * RCSname contains the name of the RCS file,
364 * and finptr the file descriptor;
365 * workname contains the name of the working file.
368 /* Keep only those locks given by -l. */
372 /* do nothing if -L is given and there are no locks*/
373 if (onlylockflag
&& !Locks
)
377 aprintf(out
, "%s\n", RCSname
);
383 if (!getnumericrev())
387 * Output the first character with putc, not printf.
388 * Otherwise, an SVR4 stdio bug buffers output inefficiently.
392 /* print RCS pathname, working pathname and optional
393 administrative information */
394 /* could use getfullRCSname() here, but that is very slow */
395 aprintf(out
, headFormat
, RCSname
, workname
,
396 Head
? " " : "", Head
? Head
->num
: "",
397 Dbranch
? " " : "", Dbranch
? Dbranch
: "",
398 StrictLocks
? " strict" : ""
402 aprintf(out
, symbolFormat
, currlock
->login
,
403 currlock
->delta
->num
);
404 currlock
= currlock
->nextlock
;
406 if (StrictLocks
&& pre5
)
407 aputs(" ; strict" + (Locks
?3:0), out
);
409 aputs(accessListString
, out
); /* print access list */
410 curaccess
= AccessList
;
412 aprintf(out
, accessFormat
, curaccess
->login
);
413 curaccess
= curaccess
->nextaccess
;
417 aputs("\nsymbolic names:", out
); /* print symbolic names */
418 for (curassoc
=Symbols
; curassoc
; curassoc
=curassoc
->nextassoc
)
419 aprintf(out
, symbolFormat
, curassoc
->symbol
, curassoc
->num
);
422 aputs("\ncomment leader: \"", out
);
423 awrite(Comment
.string
, Comment
.size
, out
);
426 if (!pre5
|| Expand
!= KEYVAL_EXPAND
)
427 aprintf(out
, "\nkeyword substitution: %s",
431 aprintf(out
, "\ntotal revisions: %d", TotalDeltas
);
435 if (Head
&& selectflag
& descflag
) {
439 /* get most recently date of the dates pointed by duelst */
442 VOID
strcpy(currdate
->strtdate
, "0.0.0.0.0.0");
443 recentdate(Head
, currdate
);
444 currdate
= currdate
->dnext
;
447 revno
= extdate(Head
);
449 aprintf(out
, ";\tselected revisions: %d", revno
);
454 aputs("description:\n", out
);
458 while (! (delta
= readdeltalog())->selector
|| --revno
)
460 if (delta
->next
&& countnumflds(delta
->num
)==2)
461 /* Read through delta->next to get its insertlns. */
462 while (readdeltalog() != delta
->next
)
467 aputs("=============================================================================\n",out
);
470 exitmain(exitstatus
);
476 if (nerror
) exitstatus
= EXIT_FAILURE
;
481 # define exiterr rlogExit
493 /* function: print revisions chosen, which are in trunk */
496 register struct hshentry
const *ptr
;
498 for (ptr
= Head
; ptr
; ptr
= ptr
->next
)
499 putadelta(ptr
, ptr
->next
, true);
506 struct hshentry
const *root
;
507 /* function: print delta tree (not including trunk) in reverse
508 order on each branch */
515 putforest(root
->branches
);
522 putforest(branchroot
)
523 struct branchhead
const *branchroot
;
524 /* function: print branches that has the same direct ancestor */
526 if (!branchroot
) return;
528 putforest(branchroot
->nextbranch
);
530 putabranch(branchroot
->hsh
);
531 putree(branchroot
->hsh
);
539 struct hshentry
const *root
;
540 /* function : print one branch */
545 putabranch(root
->next
);
547 putadelta(root
, root
, false);
555 putadelta(node
,editscript
,trunk
)
556 register struct hshentry
const *node
, *editscript
;
558 /* function: Print delta node if node->selector is set. */
559 /* editscript indicates where the editscript is stored */
560 /* trunk indicated whether this node is in trunk */
562 static char emptych
[] = EMPTYLOG
;
567 struct branchhead
const *newbranch
;
568 struct buf branchnum
;
569 char datebuf
[datesize
+ zonelenmax
];
570 int pre5
= RCSversion
< VERSION(5);
577 "----------------------------\nrevision %s%s",
578 node
->num
, pre5
? " " : ""
580 if ( node
->lockedby
)
581 aprintf(out
, pre5
+"\tlocked by: %s;", node
->lockedby
);
583 aprintf(out
, "\ndate: %s; author: %s; state: %s;",
584 date2str(node
->date
, datebuf
),
585 node
->author
, node
->state
590 aprintf(out
, insDelFormat
,
591 editscript
->deletelns
, editscript
->insertlns
);
593 aprintf(out
, insDelFormat
,
594 editscript
->insertlns
, editscript
->deletelns
);
596 newbranch
= node
->branches
;
598 bufautobegin(&branchnum
);
599 aputs("\nbranches:", out
);
601 getbranchno(newbranch
->hsh
->num
, &branchnum
);
602 aprintf(out
, " %s;", branchnum
.string
);
603 newbranch
= newbranch
->nextbranch
;
605 bufautoend(&branchnum
);
609 s
= node
->log
.string
;
610 if (!(n
= node
->log
.size
)) {
612 n
= sizeof(emptych
)-1;
620 static struct hshentry
const *
622 /* Function : get the log message and skip the text of a deltatext node.
623 * Return the delta found.
624 * Assumes the current lexeme is not yet in nexttok; does not
628 register struct hshentry
* Delta
;
633 fatserror("missing delta log");
635 if (!(Delta
= getnum()))
636 fatserror("delta number corrupted");
638 if (Delta
->log
.string
)
639 fatserror("duplicate delta log");
640 bufautobegin(&logbuf
);
641 cb
= savestring(&logbuf
);
642 Delta
->log
= bufremember(&logbuf
, cb
.size
);
644 ignorephrases(Ktext
);
646 Delta
->insertlns
= Delta
->deletelns
= 0;
657 struct hshentry
* Delta
;
658 /* function: read edit script of Delta and count how many lines added */
659 /* and deleted in the script */
662 int ed
; /* editor command */
672 while (0 <= (ed
= getdiffcmd(fin
,true,(FILE *)0,&dc
)))
674 Delta
->deletelns
+= dc
.nlines
;
676 /* skip scripted lines */
678 Delta
->insertlns
+= i
;
714 struct hshentry
*root
;
715 /* function: select revisions , starting with root */
718 struct branchhead
const *newbranch
;
722 root
->selector
= extractdelta(root
);
723 root
->log
.string
= 0;
726 newbranch
= root
->branches
;
728 exttree(newbranch
->hsh
);
729 newbranch
= newbranch
->nextbranch
;
739 /* function : get the login names of lockers from command line */
740 /* and store in lockerlist. */
744 struct rcslockers
*newlocker
;
746 while ((c
= *++argv
)==',' || c
==' ' || c
=='\t' || c
=='\n' || c
==';')
754 newlocker
= talloc(struct rcslockers
);
755 newlocker
->lockerlink
= lockerlist
;
756 newlocker
->login
= argv
;
757 lockerlist
= newlocker
;
758 while ((c
= *++argv
) && c
!=',' && c
!=' ' && c
!='\t' && c
!='\n' && c
!=';')
761 if ( c
== '\0' ) return;
762 while ((c
= *++argv
)==',' || c
==' ' || c
=='\t' || c
=='\n' || c
==';')
772 /* function: get the author's name from command line */
773 /* and store in authorlist */
777 struct authors
* newauthor
;
780 while ((c
= *++argv
)==',' || c
==' ' || c
=='\t' || c
=='\n' || c
==';')
783 authorlist
= talloc(struct authors
);
784 authorlist
->login
= getusername(false);
785 authorlist
->nextauthor
= 0;
790 newauthor
= talloc(struct authors
);
791 newauthor
->nextauthor
= authorlist
;
792 newauthor
->login
= argv
;
793 authorlist
= newauthor
;
794 while ((c
= *++argv
) && c
!=',' && c
!=' ' && c
!='\t' && c
!='\n' && c
!=';')
797 if ( c
== '\0') return;
798 while ((c
= *++argv
)==',' || c
==' ' || c
=='\t' || c
=='\n' || c
==';')
809 /* function : get the states of revisions from command line */
810 /* and store in statelist */
814 struct stateattri
*newstate
;
817 while ((c
= *++argv
)==',' || c
==' ' || c
=='\t' || c
=='\n' || c
==';')
820 error("missing state attributes after -s options");
825 newstate
= talloc(struct stateattri
);
826 newstate
->nextstate
= statelist
;
827 newstate
->status
= argv
;
828 statelist
= newstate
;
829 while ((c
= *++argv
) && c
!=',' && c
!=' ' && c
!='\t' && c
!='\n' && c
!=';')
832 if ( c
== '\0' ) return;
833 while ((c
= *++argv
)==',' || c
==' ' || c
=='\t' || c
=='\n' || c
==';')
842 /* Function: Truncate the list of locks to those that are held by the */
843 /* id's on lockerlist. Do not truncate if lockerlist empty. */
846 struct rcslockers
const *plocker
;
847 struct rcslock
*p
, **pp
;
849 if (!lockerlist
) return;
851 /* shorten Locks to those contained in lockerlist */
852 for (pp
= &Locks
; (p
= *pp
); )
853 for (plocker
= lockerlist
; ; )
854 if (strcmp(plocker
->login
, p
->login
) == 0) {
857 } else if (!(plocker
= plocker
->lockerlink
)) {
867 struct hshentry
const *root
;
868 struct Datepairs
*pd
;
869 /* function: Finds the delta that is closest to the cutoff date given by */
870 /* pd among the revisions selected by exttree. */
871 /* Successively narrows down the interval given by pd, */
872 /* and sets the strtdate of pd to the date of the selected delta */
874 struct branchhead
const *newbranch
;
877 if (root
->selector
) {
878 if ( cmpdate(root
->date
, pd
->strtdate
) >= 0 &&
879 cmpdate(root
->date
, pd
->enddate
) <= 0)
880 VOID
strcpy(pd
->strtdate
, root
->date
);
883 recentdate(root
->next
, pd
);
884 newbranch
= root
->branches
;
886 recentdate(newbranch
->hsh
, pd
);
887 newbranch
= newbranch
->nextbranch
;
898 struct hshentry
* root
;
899 /* function: select revisions which are in the date range specified */
900 /* in duelst and datelist, start at root */
901 /* Yield number of revisions selected, including those already selected. */
903 struct branchhead
const *newbranch
;
904 struct Datepairs
const *pdate
;
910 if ( datelist
|| duelst
) {
916 || ne
<= cmpdate(root
->date
, pdate
->strtdate
))
919 || ne
<= cmpdate(pdate
->enddate
, root
->date
))
922 pdate
= pdate
->dnext
;
928 root
->selector
= false;
931 if (cmpdate(root
->date
, pdate
->strtdate
) == 0)
933 pdate
= pdate
->dnext
;
937 revno
= root
->selector
+ extdate(root
->next
);
939 newbranch
= root
->branches
;
941 revno
+= extdate(newbranch
->hsh
);
942 newbranch
= newbranch
->nextbranch
;
951 struct hshentry
const *pdelta
;
952 /* function: compare information of pdelta to the authorlist, lockerlist,*/
953 /* statelist, revlist and yield true if pdelta is selected. */
956 struct rcslock
const *plock
;
957 struct stateattri
const *pstate
;
958 struct authors
const *pauthor
;
959 struct Revpairs
const *prevision
;
962 if ((pauthor
= authorlist
)) /* only certain authors wanted */
963 while (strcmp(pauthor
->login
, pdelta
->author
) != 0)
964 if (!(pauthor
= pauthor
->nextauthor
))
966 if ((pstate
= statelist
)) /* only certain states wanted */
967 while (strcmp(pstate
->status
, pdelta
->state
) != 0)
968 if (!(pstate
= pstate
->nextstate
))
970 if (lockflag
) /* only locked revisions wanted */
971 for (plock
= Locks
; ; plock
= plock
->nextlock
)
974 else if (plock
->delta
== pdelta
)
976 if ((prevision
= Revlst
)) /* only certain revs or branches wanted */
978 length
= prevision
->numfld
;
980 countnumflds(pdelta
->num
) == length
+(length
&1) &&
981 0 <= compartial(pdelta
->num
, prevision
->strtrev
, length
) &&
982 0 <= compartial(prevision
->endrev
, pdelta
->num
, length
)
985 if (!(prevision
= prevision
->rnext
))
996 /* function: get time range from command line and store in datelist if */
997 /* a time range specified or in duelst if a time spot specified */
1001 struct Datepairs
* nextdate
;
1002 char const * rawdate
;
1006 while ((c
= *++argv
)==',' || c
==' ' || c
=='\t' || c
=='\n' || c
==';')
1009 error("missing date/time after -d");
1013 while( c
!= '\0' ) {
1015 nextdate
= talloc(struct Datepairs
);
1016 if ( c
== '<' ) { /* case: -d <date */
1018 if (!(nextdate
->ne_date
= c
!='='))
1020 (nextdate
->strtdate
)[0] = '\0';
1021 } else if (c
== '>') { /* case: -d'>date' */
1023 if (!(nextdate
->ne_date
= c
!='='))
1025 (nextdate
->enddate
)[0] = '\0';
1029 while( c
!= '<' && c
!= '>' && c
!= ';' && c
!= '\0')
1032 if ( c
== '>' ) switchflag
=true;
1034 switchflag
? nextdate
->enddate
: nextdate
->strtdate
);
1035 if ( c
== ';' || c
== '\0') { /* case: -d date */
1036 VOID
strcpy(nextdate
->enddate
,nextdate
->strtdate
);
1037 nextdate
->dnext
= duelst
;
1041 /* case: -d date< or -d date>; see switchflag */
1042 int eq
= argv
[1]=='=';
1043 nextdate
->ne_date
= !eq
;
1045 while ((c
= *++argv
) == ' ' || c
=='\t' || c
=='\n')
1047 if ( c
== ';' || c
== '\0') {
1048 /* second date missing */
1050 *nextdate
->strtdate
= '\0';
1052 *nextdate
->enddate
= '\0';
1053 nextdate
->dnext
= datelist
;
1054 datelist
= nextdate
;
1060 while( c
!= '>' && c
!= '<' && c
!= ';' && c
!= '\0')
1064 switchflag
? nextdate
->strtdate
: nextdate
->enddate
);
1065 nextdate
->dnext
= datelist
;
1066 datelist
= nextdate
;
1068 if (RCSversion
< VERSION(5))
1069 nextdate
->ne_date
= 0;
1070 if ( c
== '\0') return;
1071 while ((c
= *++argv
) == ';' || c
== ' ' || c
== '\t' || c
=='\n')
1080 /* function: get the numeric name of revisions which stored in revlist */
1081 /* and then stored the numeric names in Revlst */
1082 /* if branchflag, also add default branch */
1085 struct Revpairs
* ptr
, *pt
;
1089 struct buf
const *rstart
, *rend
;
1100 switch (ptr
->numfld
) {
1103 if (!expandsym(ptr
->strtrev
, &s
))
1106 n
= countnumflds(s
.string
);
1107 if (!n
&& (lrev
= tiprev())) {
1109 n
= countnumflds(lrev
);
1113 case 2: /* -rREV: */
1114 if (!expandsym(ptr
->strtrev
, &s
))
1116 bufscpy(&e
, s
.string
);
1117 n
= countnumflds(s
.string
);
1118 (n
<2 ? e
.string
: strrchr(e
.string
,'.'))[0] = 0;
1121 case 3: /* -r:REV */
1122 if (!expandsym(ptr
->endrev
, &e
))
1124 if ((n
= countnumflds(e
.string
)) < 2)
1127 bufscpy(&s
, e
.string
);
1128 VOID
strcpy(strrchr(s
.string
,'.'), ".0");
1132 default: /* -rREV1:REV2 */
1134 expandsym(ptr
->strtrev
, &s
)
1135 && expandsym(ptr
->endrev
, &e
)
1136 && checkrevpair(s
.string
, e
.string
)
1139 n
= countnumflds(s
.string
);
1140 /* Swap if out of order. */
1141 if (compartial(s
.string
,e
.string
,n
) > 0) {
1149 pt
= ftalloc(struct Revpairs
);
1151 pt
->strtrev
= fstr_save(rstart
->string
);
1152 pt
->endrev
= fstr_save(rend
->string
);
1158 /* Now take care of branchflag */
1159 if (branchflag
&& (Dbranch
||Head
)) {
1160 pt
= ftalloc(struct Revpairs
);
1161 pt
->strtrev
= pt
->endrev
=
1162 Dbranch
? Dbranch
: fstr_save(partialno(&s
,Head
->num
,1));
1163 pt
->rnext
=Revlst
; Revlst
=pt
;
1164 pt
->numfld
= countnumflds(pt
->strtrev
);
1176 checkrevpair(num1
,num2
)
1177 char const *num1
, *num2
;
1178 /* function: check whether num1, num2 are legal pair,i.e.
1179 only the last field are different and have same number of
1180 fields( if length <= 2, may be different if first field) */
1183 int length
= countnumflds(num1
);
1186 countnumflds(num2
) != length
1187 || (2 < length
&& compartial(num1
, num2
, length
-1) != 0)
1189 rcserror("invalid branch or revision pair %s : %s", num1
, num2
);
1200 register char * argv
;
1201 /* function: get revision or branch range from command line, and */
1202 /* store in revlist */
1206 struct Revpairs
* nextrevpair
;
1211 /* Support old ambiguous '-' syntax; this will go away. */
1212 if (strchr(argv
,':'))
1215 if (strchr(argv
,'-') && VERSION(5) <= RCSversion
)
1216 warn("`-' is obsolete in `-r%s'; use `:' instead", argv
);
1221 while (c
==' ' || c
=='\t' || c
=='\n')
1223 nextrevpair
= talloc(struct Revpairs
);
1224 nextrevpair
->rnext
= revlist
;
1225 revlist
= nextrevpair
;
1226 nextrevpair
->numfld
= 1;
1227 nextrevpair
->strtrev
= argv
;
1228 for (;; c
= *++argv
) {
1232 case '\0': case ' ': case '\t': case '\n':
1243 while (c
==' ' || c
=='\t' || c
=='\n')
1245 if (c
== separator
) {
1246 while ((c
= *++argv
) == ' ' || c
== '\t' || c
=='\n')
1248 nextrevpair
->endrev
= argv
;
1249 for (;; c
= *++argv
) {
1253 case '\0': case ' ': case '\t': case '\n':
1264 while (c
==' ' || c
=='\t' || c
=='\n')
1266 nextrevpair
->numfld
=
1267 !nextrevpair
->endrev
[0] ? 2 /* -rREV: */ :
1268 !nextrevpair
->strtrev
[0] ? 3 /* -r:REV */ :
1269 4 /* -rREV1:REV2 */;
1273 else if (c
==',' || c
==';')
1276 error("missing `,' near `%c%s'", c
, argv
+1);