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.2 2003/06/17 04:25:48 dillon 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.2 2003/06/17 04:25:48 dillon 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);
611 newbranch = node->branches;
613 bufautobegin(&branchnum);
614 aputs("\nbranches:", out);
616 getbranchno(newbranch->hsh->num, &branchnum);
617 aprintf(out, " %s;", branchnum.string);
618 newbranch = newbranch->nextbranch;
620 bufautoend(&branchnum);
624 s = node->log.string;
625 if (!(n = node->log.size)) {
627 n = sizeof(emptych)-1;
635 static struct hshentry const *
637 /* Function : get the log message and skip the text of a deltatext node.
638 * Return the delta found.
639 * Assumes the current lexeme is not yet in nexttok; does not
643 register struct hshentry * Delta;
648 fatserror("missing delta log");
650 if (!(Delta = getnum()))
651 fatserror("delta number corrupted");
653 if (Delta->log.string)
654 fatserror("duplicate delta log");
655 bufautobegin(&logbuf);
656 cb = savestring(&logbuf);
657 Delta->log = bufremember(&logbuf, cb.size);
659 ignorephrases(Ktext);
661 Delta->insertlns = Delta->deletelns = 0;
672 struct hshentry * Delta;
673 /* function: read edit script of Delta and count how many lines added */
674 /* and deleted in the script */
677 int ed; /* editor command */
687 while (0 <= (ed = getdiffcmd(fin,true,(FILE *)0,&dc)))
689 Delta->deletelns += dc.nlines;
691 /* skip scripted lines */
693 Delta->insertlns += i;
729 struct hshentry *root;
730 /* function: select revisions , starting with root */
733 struct branchhead const *newbranch;
737 root->selector = extractdelta(root);
738 root->log.string = 0;
741 newbranch = root->branches;
743 exttree(newbranch->hsh);
744 newbranch = newbranch->nextbranch;
754 /* function : get the login names of lockers from command line */
755 /* and store in lockerlist. */
759 struct rcslockers *newlocker;
761 while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';')
769 newlocker = talloc(struct rcslockers);
770 newlocker->lockerlink = lockerlist;
771 newlocker->login = argv;
772 lockerlist = newlocker;
773 while ((c = *++argv) && c!=',' && c!=' ' && c!='\t' && c!='\n' && c!=';')
776 if ( c == '\0' ) return;
777 while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';')
787 /* function: get the author's name from command line */
788 /* and store in authorlist */
792 struct authors * newauthor;
795 while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';')
798 authorlist = talloc(struct authors);
799 authorlist->login = getusername(false);
800 authorlist->nextauthor = 0;
805 newauthor = talloc(struct authors);
806 newauthor->nextauthor = authorlist;
807 newauthor->login = argv;
808 authorlist = newauthor;
809 while ((c = *++argv) && c!=',' && c!=' ' && c!='\t' && c!='\n' && c!=';')
812 if ( c == '\0') return;
813 while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';')
824 /* function : get the states of revisions from command line */
825 /* and store in statelist */
829 struct stateattri *newstate;
832 while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';')
835 error("missing state attributes after -s options");
840 newstate = talloc(struct stateattri);
841 newstate->nextstate = statelist;
842 newstate->status = argv;
843 statelist = newstate;
844 while ((c = *++argv) && c!=',' && c!=' ' && c!='\t' && c!='\n' && c!=';')
847 if ( c == '\0' ) return;
848 while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';')
857 /* Function: Truncate the list of locks to those that are held by the */
858 /* id's on lockerlist. Do not truncate if lockerlist empty. */
861 struct rcslockers const *plocker;
862 struct rcslock *p, **pp;
864 if (!lockerlist) return;
866 /* shorten Locks to those contained in lockerlist */
867 for (pp = &Locks; (p = *pp); )
868 for (plocker = lockerlist; ; )
869 if (strcmp(plocker->login, p->login) == 0) {
872 } else if (!(plocker = plocker->lockerlink)) {
882 struct hshentry const *root;
883 struct Datepairs *pd;
884 /* function: Finds the delta that is closest to the cutoff date given by */
885 /* pd among the revisions selected by exttree. */
886 /* Successively narrows down the interval given by pd, */
887 /* and sets the strtdate of pd to the date of the selected delta */
889 struct branchhead const *newbranch;
892 if (root->selector) {
893 if ( cmpdate(root->date, pd->strtdate) >= 0 &&
894 cmpdate(root->date, pd->enddate) <= 0)
895 VOID strcpy(pd->strtdate, root->date);
898 recentdate(root->next, pd);
899 newbranch = root->branches;
901 recentdate(newbranch->hsh, pd);
902 newbranch = newbranch->nextbranch;
913 struct hshentry * root;
914 /* function: select revisions which are in the date range specified */
915 /* in duelst and datelist, start at root */
916 /* Yield number of revisions selected, including those already selected. */
918 struct branchhead const *newbranch;
919 struct Datepairs const *pdate;
925 if ( datelist || duelst) {
931 || ne <= cmpdate(root->date, pdate->strtdate))
934 || ne <= cmpdate(pdate->enddate, root->date))
937 pdate = pdate->dnext;
943 root->selector = false;
946 if (cmpdate(root->date, pdate->strtdate) == 0)
948 pdate = pdate->dnext;
952 revno = root->selector + extdate(root->next);
954 newbranch = root->branches;
956 revno += extdate(newbranch->hsh);
957 newbranch = newbranch->nextbranch;
966 struct hshentry const *pdelta;
967 /* function: compare information of pdelta to the authorlist, lockerlist,*/
968 /* statelist, revlist and yield true if pdelta is selected. */
971 struct rcslock const *plock;
972 struct stateattri const *pstate;
973 struct authors const *pauthor;
974 struct Revpairs const *prevision;
977 if ((pauthor = authorlist)) /* only certain authors wanted */
978 while (strcmp(pauthor->login, pdelta->author) != 0)
979 if (!(pauthor = pauthor->nextauthor))
981 if ((pstate = statelist)) /* only certain states wanted */
982 while (strcmp(pstate->status, pdelta->state) != 0)
983 if (!(pstate = pstate->nextstate))
985 if (lockflag) /* only locked revisions wanted */
986 for (plock = Locks; ; plock = plock->nextlock)
989 else if (plock->delta == pdelta)
991 if ((prevision = Revlst)) /* only certain revs or branches wanted */
993 length = prevision->numfld;
995 countnumflds(pdelta->num) == length+(length&1) &&
996 0 <= compartial(pdelta->num, prevision->strtrev, length) &&
997 0 <= compartial(prevision->endrev, pdelta->num, length)
1000 if (!(prevision = prevision->rnext))
1011 /* function: get time range from command line and store in datelist if */
1012 /* a time range specified or in duelst if a time spot specified */
1016 struct Datepairs * nextdate;
1017 char const * rawdate;
1021 while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';')
1024 error("missing date/time after -d");
1028 while( c != '\0' ) {
1030 nextdate = talloc(struct Datepairs);
1031 if ( c == '<' ) { /* case: -d <date */
1033 if (!(nextdate->ne_date = c!='='))
1035 (nextdate->strtdate)[0] = '\0';
1036 } else if (c == '>') { /* case: -d'>date' */
1038 if (!(nextdate->ne_date = c!='='))
1040 (nextdate->enddate)[0] = '\0';
1044 while( c != '<' && c != '>' && c != ';' && c != '\0')
1047 if ( c == '>' ) switchflag=true;
1049 switchflag ? nextdate->enddate : nextdate->strtdate);
1050 if ( c == ';' || c == '\0') { /* case: -d date */
1051 VOID strcpy(nextdate->enddate,nextdate->strtdate);
1052 nextdate->dnext = duelst;
1056 /* case: -d date< or -d date>; see switchflag */
1057 int eq = argv[1]=='=';
1058 nextdate->ne_date = !eq;
1060 while ((c = *++argv) == ' ' || c=='\t' || c=='\n')
1062 if ( c == ';' || c == '\0') {
1063 /* second date missing */
1065 *nextdate->strtdate= '\0';
1067 *nextdate->enddate= '\0';
1068 nextdate->dnext = datelist;
1069 datelist = nextdate;
1075 while( c != '>' && c != '<' && c != ';' && c != '\0')
1079 switchflag ? nextdate->strtdate : nextdate->enddate);
1080 nextdate->dnext = datelist;
1081 datelist = nextdate;
1083 if (RCSversion < VERSION(5))
1084 nextdate->ne_date = 0;
1085 if ( c == '\0') return;
1086 while ((c = *++argv) == ';' || c == ' ' || c == '\t' || c =='\n')
1095 /* function: get the numeric name of revisions which stored in revlist */
1096 /* and then stored the numeric names in Revlst */
1097 /* if branchflag, also add default branch */
1100 struct Revpairs * ptr, *pt;
1104 struct buf const *rstart, *rend;
1115 switch (ptr->numfld) {
1118 if (!expandsym(ptr->strtrev, &s))
1121 n = countnumflds(s.string);
1122 if (!n && (lrev = tiprev())) {
1124 n = countnumflds(lrev);
1128 case 2: /* -rREV: */
1129 if (!expandsym(ptr->strtrev, &s))
1131 bufscpy(&e, s.string);
1132 n = countnumflds(s.string);
1133 (n<2 ? e.string : strrchr(e.string,'.'))[0] = 0;
1136 case 3: /* -r:REV */
1137 if (!expandsym(ptr->endrev, &e))
1139 if ((n = countnumflds(e.string)) < 2)
1142 bufscpy(&s, e.string);
1143 VOID strcpy(strrchr(s.string,'.'), ".0");
1147 default: /* -rREV1:REV2 */
1149 expandsym(ptr->strtrev, &s)
1150 && expandsym(ptr->endrev, &e)
1151 && checkrevpair(s.string, e.string)
1154 n = countnumflds(s.string);
1155 /* Swap if out of order. */
1156 if (compartial(s.string,e.string,n) > 0) {
1164 pt = ftalloc(struct Revpairs);
1166 pt->strtrev = fstr_save(rstart->string);
1167 pt->endrev = fstr_save(rend->string);
1173 /* Now take care of branchflag */
1174 if (branchflag && (Dbranch||Head)) {
1175 pt = ftalloc(struct Revpairs);
1176 pt->strtrev = pt->endrev =
1177 Dbranch ? Dbranch : fstr_save(partialno(&s,Head->num,1));
1178 pt->rnext=Revlst; Revlst=pt;
1179 pt->numfld = countnumflds(pt->strtrev);
1191 checkrevpair(num1,num2)
1192 char const *num1, *num2;
1193 /* function: check whether num1, num2 are legal pair,i.e.
1194 only the last field are different and have same number of
1195 fields( if length <= 2, may be different if first field) */
1198 int length = countnumflds(num1);
1201 countnumflds(num2) != length
1202 || (2 < length && compartial(num1, num2, length-1) != 0)
1204 rcserror("invalid branch or revision pair %s : %s", num1, num2);
1215 register char * argv;
1216 /* function: get revision or branch range from command line, and */
1217 /* store in revlist */
1221 struct Revpairs * nextrevpair;
1226 /* Support old ambiguous '-' syntax; this will go away. */
1227 if (strchr(argv,':'))
1230 if (strchr(argv,'-') && VERSION(5) <= RCSversion)
1231 warn("`-' is obsolete in `-r%s'; use `:' instead", argv);
1236 while (c==' ' || c=='\t' || c=='\n')
1238 nextrevpair = talloc(struct Revpairs);
1239 nextrevpair->rnext = revlist;
1240 revlist = nextrevpair;
1241 nextrevpair->numfld = 1;
1242 nextrevpair->strtrev = argv;
1243 for (;; c = *++argv) {
1247 case '\0': case ' ': case '\t': case '\n':
1258 while (c==' ' || c=='\t' || c=='\n')
1260 if (c == separator) {
1261 while ((c = *++argv) == ' ' || c == '\t' || c =='\n')
1263 nextrevpair->endrev = argv;
1264 for (;; c = *++argv) {
1268 case '\0': case ' ': case '\t': case '\n':
1279 while (c==' ' || c=='\t' || c =='\n')
1281 nextrevpair->numfld =
1282 !nextrevpair->endrev[0] ? 2 /* -rREV: */ :
1283 !nextrevpair->strtrev[0] ? 3 /* -r:REV */ :
1284 4 /* -rREV1:REV2 */;
1288 else if (c==',' || c==';')
1291 error("missing `,' near `%c%s'", c, argv+1);