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 * Revision 5.18 1995/06/16 06:19:24 eggert
34 * Revision 5.17 1995/06/01 16:23:43 eggert
35 * (struct rcslockers): Renamed from `struct lockers'.
36 * (getnumericrev): Return error indication instead of ignoring errors.
37 * (main): Check it. Don't use dateform.
38 * (recentdate, extdate): cmpnum -> cmpdate
40 * Revision 5.16 1994/04/13 16:30:34 eggert
41 * Fix bug; `rlog -lxxx' inverted the sense of -l.
43 * Revision 5.15 1994/03/17 14:05:48 eggert
44 * -d'<DATE' now excludes DATE; the new syntax -d'<=DATE' includes it.
45 * Emulate -V4's white space generation more precisely.
46 * Work around SVR4 stdio performance bug. Remove lint.
48 * Revision 5.14 1993/11/09 17:40:15 eggert
49 * -V now prints version on stdout and exits.
51 * Revision 5.13 1993/11/03 17:42:27 eggert
52 * Add -N, -z. Ignore -T.
54 * Revision 5.12 1992/07/28 16:12:44 eggert
55 * Don't miss B.0 when handling branch B. Diagnose missing `,' in -r.
56 * Add -V. Avoid `unsigned'. Statement macro names now end in _.
58 * Revision 5.11 1992/01/24 18:44:19 eggert
59 * Don't duplicate unexpected_EOF's function. lint -> RCS_lint
61 * Revision 5.10 1992/01/06 02:42:34 eggert
62 * Update usage string.
63 * while (E) ; -> while (E) continue;
65 * Revision 5.9 1991/09/17 19:07:40 eggert
66 * Getscript() didn't uncache partial lines.
68 * Revision 5.8 1991/08/19 03:13:55 eggert
69 * Revision separator is `:', not `-'.
70 * Check for missing and duplicate logs. Tune.
71 * Permit log messages that do not end in newline (including empty logs).
73 * Revision 5.7 1991/04/21 11:58:31 eggert
74 * Add -x, RCSINIT, MS-DOS support.
76 * Revision 5.6 1991/02/26 17:07:17 eggert
77 * Survive RCS files with missing logs.
78 * strsave -> str_save (DG/UX name clash)
80 * Revision 5.5 1990/11/01 05:03:55 eggert
81 * Permit arbitrary data in logs and comment leaders.
83 * Revision 5.4 1990/10/04 06:30:22 eggert
84 * Accumulate exit status across files.
86 * Revision 5.3 1990/09/11 02:41:16 eggert
89 * Revision 5.2 1990/09/04 08:02:33 eggert
90 * Count RCS lines better.
92 * Revision 5.0 1990/08/22 08:13:48 eggert
93 * Remove compile-time limits; use malloc instead. Add setuid support.
95 * Report dates in long form, to warn about dates past 1999/12/31.
96 * Change "added/del" message to make room for the longer dates.
97 * Don't generate trailing white space. Add -V. Ansify and Posixate.
99 * Revision 4.7 89/05/01 15:13:48 narten
100 * changed copyright header to reflect current distribution rules
102 * Revision 4.6 88/08/09 19:13:28 eggert
103 * Check for memory exhaustion; don't access freed storage.
104 * Shrink stdio code size; remove lint.
106 * Revision 4.5 87/12/18 11:46:38 narten
107 * more lint cleanups (Guy Harris)
109 * Revision 4.4 87/10/18 10:41:12 narten
110 * Updating version numbers
111 * Changes relative to 1.1 actually relative to 4.2
113 * Revision 1.3 87/09/24 14:01:10 narten
114 * Sources now pass through lint (if you ignore printf/sprintf/fprintf
117 * Revision 1.2 87/03/27 14:22:45 jenkins
120 * Revision 4.2 83/12/05 09:18:09 wft
121 * changed rewriteflag to external.
123 * Revision 4.1 83/05/11 16:16:55 wft
124 * Added -b, updated getnumericrev() accordingly.
125 * Replaced getpwuid() with getcaller().
127 * Revision 3.7 83/05/11 14:24:13 wft
128 * Added options -L and -R;
129 * Fixed selection bug with -l on multiple files.
130 * Fixed error on dates of the form -d'>date' (rewrote getdatepair()).
132 * Revision 3.6 82/12/24 15:57:53 wft
133 * shortened output format.
135 * Revision 3.5 82/12/08 21:45:26 wft
136 * removed call to checkaccesslist(); used DATEFORM to format all dates;
137 * removed unused variables.
139 * Revision 3.4 82/12/04 13:26:25 wft
140 * Replaced getdelta() with gettree(); removed updating of field lockedby.
142 * Revision 3.3 82/12/03 14:08:20 wft
143 * Replaced getlogin with getpwuid(), %02d with %.2d, fancydate with PRINTDATE.
144 * Fixed printing of nil, removed printing of Suffix,
145 * added shortcut if no revisions are printed, disambiguated struct members.
147 * Revision 3.2 82/10/18 21:09:06 wft
148 * call to curdir replaced with getfullRCSname(),
149 * fixed call to getlogin(), cosmetic changes on output,
150 * changed conflicting long identifiers.
152 * Revision 3.1 82/10/13 16:07:56 wft
153 * fixed type of variables receiving from getc() (char -> int).
160 struct rcslockers { /* lockers in locker option; stored */
161 char const * login; /* lockerlist */
162 struct rcslockers * lockerlink;
165 struct stateattri { /* states in state option; stored in */
166 char const * status; /* statelist */
167 struct stateattri * nextstate;
170 struct authors { /* login names in author option; */
171 char const * login; /* stored in authorlist */
172 struct authors * nextauthor;
175 struct Revpairs{ /* revision or branch range in -r */
176 int numfld; /* option; stored in revlist */
177 char const * strtrev;
179 struct Revpairs * rnext;
182 struct Datepairs{ /* date range in -d option; stored in */
183 struct Datepairs *dnext;
184 char strtdate[datesize]; /* duelst and datelist */
185 char enddate[datesize];
186 char ne_date; /* datelist only; distinguishes < from <= */
189 static char extractdelta P((struct hshentry const*));
190 static int checkrevpair P((char const*,char const*));
191 static int extdate P((struct hshentry*));
192 static int getnumericrev P((void));
193 static struct hshentry const *readdeltalog P((void));
194 static void cleanup P((void));
195 static void exttree P((struct hshentry*));
196 static void getauthor P((char*));
197 static void getdatepair P((char*));
198 static void getlocker P((char*));
199 static void getrevpairs P((char*));
200 static void getscript P((struct hshentry*));
201 static void getstate P((char*));
202 static void putabranch P((struct hshentry const*));
203 static void putadelta P((struct hshentry const*,struct hshentry const*,int));
204 static void putforest P((struct branchhead const*));
205 static void putree P((struct hshentry const*));
206 static void putrunk P((void));
207 static void recentdate P((struct hshentry const*,struct Datepairs*));
208 static void trunclocks P((void));
210 static char const *insDelFormat;
211 static int branchflag; /*set on -b */
212 static int exitstatus;
214 static struct Datepairs *datelist, *duelst;
215 static struct Revpairs *revlist, *Revlst;
216 static struct authors *authorlist;
217 static struct rcslockers *lockerlist;
218 static struct stateattri *statelist;
221 mainProg(rlogId, "rlog", "$FreeBSD$")
223 static char const cmdusage[] =
224 "\nrlog usage: rlog -{bhLNRt} -v[string] -ddates -l[lockers] -r[revs] -sstates -Vn -w[logins] -xsuff -zzone file ...";
228 struct Datepairs *currdate;
229 char const *accessListString, *accessFormat;
230 char const *headFormat, *symbolFormat;
231 struct access const *curaccess;
232 struct assoc const *curassoc;
233 struct hshentry const *delta;
234 struct rcslock const *currlock;
235 int descflag, selectflag;
236 int onlylockflag; /* print only files with locks */
237 int onlyRCSflag; /* print only RCS pathname */
244 descflag = selectflag = shownames = true;
245 versionlist = 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);
330 error("unknown option: %s%s", *argv, cmdusage);
333 } /* end of option processing */
335 if (! (descflag|selectflag)) {
336 warn("-t overrides -h.");
340 pre5 = RCSversion < VERSION(5);
342 accessListString = "\naccess list: ";
343 accessFormat = " %s";
344 headFormat = "RCS file: %s; Working file: %s\nhead: %s%s\nbranch: %s%s\nlocks: ";
345 insDelFormat = " lines added/del: %ld/%ld";
346 symbolFormat = " %s: %s;";
348 accessListString = "\naccess list:";
349 accessFormat = "\n\t%s";
350 headFormat = "RCS file: %s\nWorking file: %s\nhead:%s%s\nbranch:%s%s\nlocks:%s";
351 insDelFormat = " lines: +%ld -%ld";
352 symbolFormat = "\n\t%s: %s";
355 /* Now handle all pathnames. */
359 faterror("no input file%s", cmdusage);
361 for (; 0 < argc; cleanup(), ++argv, --argc) {
364 if (pairnames(argc, argv, rcsreadopen, true, false) <= 0)
368 * RCSname contains the name of the RCS file,
369 * and finptr the file descriptor;
370 * workname contains the name of the working file.
373 /* Keep only those locks given by -l. */
377 /* do nothing if -L is given and there are no locks*/
378 if (onlylockflag && !Locks)
383 aprintf(out, "%s%s %s\n", vstring, workname, tiprev());
388 aprintf(out, "%s\n", RCSname);
394 if (!getnumericrev())
398 * Output the first character with putc, not printf.
399 * Otherwise, an SVR4 stdio bug buffers output inefficiently.
403 /* print RCS pathname, working pathname and optional
404 administrative information */
405 /* could use getfullRCSname() here, but that is very slow */
406 aprintf(out, headFormat, RCSname, workname,
407 Head ? " " : "", Head ? Head->num : "",
408 Dbranch ? " " : "", Dbranch ? Dbranch : "",
409 StrictLocks ? " strict" : ""
413 aprintf(out, symbolFormat, currlock->login,
414 currlock->delta->num);
415 currlock = currlock->nextlock;
417 if (StrictLocks && pre5)
418 aputs(" ; strict" + (Locks?3:0), out);
420 aputs(accessListString, out); /* print access list */
421 curaccess = AccessList;
423 aprintf(out, accessFormat, curaccess->login);
424 curaccess = curaccess->nextaccess;
428 aputs("\nsymbolic names:", out); /* print symbolic names */
429 for (curassoc=Symbols; curassoc; curassoc=curassoc->nextassoc)
430 aprintf(out, symbolFormat, curassoc->symbol, curassoc->num);
433 aputs("\ncomment leader: \"", out);
434 awrite(Comment.string, Comment.size, out);
437 if (!pre5 || Expand != KEYVAL_EXPAND)
438 aprintf(out, "\nkeyword substitution: %s",
442 aprintf(out, "\ntotal revisions: %d", TotalDeltas);
446 if (Head && selectflag & descflag) {
450 /* get most recently date of the dates pointed by duelst */
453 VOID strcpy(currdate->strtdate, "0.0.0.0.0.0");
454 recentdate(Head, currdate);
455 currdate = currdate->dnext;
458 revno = extdate(Head);
460 aprintf(out, ";\tselected revisions: %d", revno);
465 aputs("description:\n", out);
469 while (! (delta = readdeltalog())->selector || --revno)
471 if (delta->next && countnumflds(delta->num)==2)
472 /* Read through delta->next to get its insertlns. */
473 while (readdeltalog() != delta->next)
478 aputs("----------------------------\n", out);
479 aputs("=============================================================================\n",out);
482 exitmain(exitstatus);
488 if (nerror) exitstatus = EXIT_FAILURE;
493 # define exiterr rlogExit
505 /* function: print revisions chosen, which are in trunk */
508 register struct hshentry const *ptr;
510 for (ptr = Head; ptr; ptr = ptr->next)
511 putadelta(ptr, ptr->next, true);
518 struct hshentry const *root;
519 /* function: print delta tree (not including trunk) in reverse
520 order on each branch */
527 putforest(root->branches);
534 putforest(branchroot)
535 struct branchhead const *branchroot;
536 /* function: print branches that has the same direct ancestor */
538 if (!branchroot) return;
540 putforest(branchroot->nextbranch);
542 putabranch(branchroot->hsh);
543 putree(branchroot->hsh);
551 struct hshentry const *root;
552 /* function : print one branch */
557 putabranch(root->next);
559 putadelta(root, root, false);
567 putadelta(node,editscript,trunk)
568 register struct hshentry const *node, *editscript;
570 /* function: Print delta node if node->selector is set. */
571 /* editscript indicates where the editscript is stored */
572 /* trunk indicated whether this node is in trunk */
574 static char emptych[] = EMPTYLOG;
579 struct branchhead const *newbranch;
580 struct buf branchnum;
581 char datebuf[datesize + zonelenmax];
582 int pre5 = RCSversion < VERSION(5);
589 "----------------------------\nrevision %s%s",
590 node->num, pre5 ? " " : ""
592 if ( node->lockedby )
593 aprintf(out, pre5+"\tlocked by: %s;", node->lockedby);
595 aprintf(out, "\ndate: %s; author: %s; state: %s;",
596 date2str(node->date, datebuf),
597 node->author, node->state
602 aprintf(out, insDelFormat,
603 editscript->deletelns, editscript->insertlns);
605 aprintf(out, insDelFormat,
606 editscript->insertlns, editscript->deletelns);
608 newbranch = node->branches;
610 bufautobegin(&branchnum);
611 aputs("\nbranches:", out);
613 getbranchno(newbranch->hsh->num, &branchnum);
614 aprintf(out, " %s;", branchnum.string);
615 newbranch = newbranch->nextbranch;
617 bufautoend(&branchnum);
621 s = node->log.string;
622 if (!(n = node->log.size)) {
624 n = sizeof(emptych)-1;
632 static struct hshentry const *
634 /* Function : get the log message and skip the text of a deltatext node.
635 * Return the delta found.
636 * Assumes the current lexeme is not yet in nexttok; does not
640 register struct hshentry * Delta;
645 fatserror("missing delta log");
647 if (!(Delta = getnum()))
648 fatserror("delta number corrupted");
650 if (Delta->log.string)
651 fatserror("duplicate delta log");
652 bufautobegin(&logbuf);
653 cb = savestring(&logbuf);
654 Delta->log = bufremember(&logbuf, cb.size);
656 ignorephrases(Ktext);
658 Delta->insertlns = Delta->deletelns = 0;
669 struct hshentry * Delta;
670 /* function: read edit script of Delta and count how many lines added */
671 /* and deleted in the script */
674 int ed; /* editor command */
684 while (0 <= (ed = getdiffcmd(fin,true,(FILE *)0,&dc)))
686 Delta->deletelns += dc.nlines;
688 /* skip scripted lines */
690 Delta->insertlns += i;
726 struct hshentry *root;
727 /* function: select revisions , starting with root */
730 struct branchhead const *newbranch;
734 root->selector = extractdelta(root);
735 root->log.string = 0;
738 newbranch = root->branches;
740 exttree(newbranch->hsh);
741 newbranch = newbranch->nextbranch;
751 /* function : get the login names of lockers from command line */
752 /* and store in lockerlist. */
756 struct rcslockers *newlocker;
758 while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';')
766 newlocker = talloc(struct rcslockers);
767 newlocker->lockerlink = lockerlist;
768 newlocker->login = argv;
769 lockerlist = newlocker;
770 while ((c = *++argv) && c!=',' && c!=' ' && c!='\t' && c!='\n' && c!=';')
773 if ( c == '\0' ) return;
774 while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';')
784 /* function: get the author's name from command line */
785 /* and store in authorlist */
789 struct authors * newauthor;
792 while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';')
795 authorlist = talloc(struct authors);
796 authorlist->login = getusername(false);
797 authorlist->nextauthor = 0;
802 newauthor = talloc(struct authors);
803 newauthor->nextauthor = authorlist;
804 newauthor->login = argv;
805 authorlist = newauthor;
806 while ((c = *++argv) && c!=',' && c!=' ' && c!='\t' && c!='\n' && c!=';')
809 if ( c == '\0') return;
810 while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';')
821 /* function : get the states of revisions from command line */
822 /* and store in statelist */
826 struct stateattri *newstate;
829 while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';')
832 error("missing state attributes after -s options");
837 newstate = talloc(struct stateattri);
838 newstate->nextstate = statelist;
839 newstate->status = argv;
840 statelist = newstate;
841 while ((c = *++argv) && c!=',' && c!=' ' && c!='\t' && c!='\n' && c!=';')
844 if ( c == '\0' ) return;
845 while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';')
854 /* Function: Truncate the list of locks to those that are held by the */
855 /* id's on lockerlist. Do not truncate if lockerlist empty. */
858 struct rcslockers const *plocker;
859 struct rcslock *p, **pp;
861 if (!lockerlist) return;
863 /* shorten Locks to those contained in lockerlist */
864 for (pp = &Locks; (p = *pp); )
865 for (plocker = lockerlist; ; )
866 if (strcmp(plocker->login, p->login) == 0) {
869 } else if (!(plocker = plocker->lockerlink)) {
879 struct hshentry const *root;
880 struct Datepairs *pd;
881 /* function: Finds the delta that is closest to the cutoff date given by */
882 /* pd among the revisions selected by exttree. */
883 /* Successively narrows down the interval given by pd, */
884 /* and sets the strtdate of pd to the date of the selected delta */
886 struct branchhead const *newbranch;
889 if (root->selector) {
890 if ( cmpdate(root->date, pd->strtdate) >= 0 &&
891 cmpdate(root->date, pd->enddate) <= 0)
892 VOID strcpy(pd->strtdate, root->date);
895 recentdate(root->next, pd);
896 newbranch = root->branches;
898 recentdate(newbranch->hsh, pd);
899 newbranch = newbranch->nextbranch;
910 struct hshentry * root;
911 /* function: select revisions which are in the date range specified */
912 /* in duelst and datelist, start at root */
913 /* Yield number of revisions selected, including those already selected. */
915 struct branchhead const *newbranch;
916 struct Datepairs const *pdate;
922 if ( datelist || duelst) {
928 || ne <= cmpdate(root->date, pdate->strtdate))
931 || ne <= cmpdate(pdate->enddate, root->date))
934 pdate = pdate->dnext;
940 root->selector = false;
943 if (cmpdate(root->date, pdate->strtdate) == 0)
945 pdate = pdate->dnext;
949 revno = root->selector + extdate(root->next);
951 newbranch = root->branches;
953 revno += extdate(newbranch->hsh);
954 newbranch = newbranch->nextbranch;
963 struct hshentry const *pdelta;
964 /* function: compare information of pdelta to the authorlist, lockerlist,*/
965 /* statelist, revlist and yield true if pdelta is selected. */
968 struct rcslock const *plock;
969 struct stateattri const *pstate;
970 struct authors const *pauthor;
971 struct Revpairs const *prevision;
974 if ((pauthor = authorlist)) /* only certain authors wanted */
975 while (strcmp(pauthor->login, pdelta->author) != 0)
976 if (!(pauthor = pauthor->nextauthor))
978 if ((pstate = statelist)) /* only certain states wanted */
979 while (strcmp(pstate->status, pdelta->state) != 0)
980 if (!(pstate = pstate->nextstate))
982 if (lockflag) /* only locked revisions wanted */
983 for (plock = Locks; ; plock = plock->nextlock)
986 else if (plock->delta == pdelta)
988 if ((prevision = Revlst)) /* only certain revs or branches wanted */
990 length = prevision->numfld;
992 countnumflds(pdelta->num) == length+(length&1) &&
993 0 <= compartial(pdelta->num, prevision->strtrev, length) &&
994 0 <= compartial(prevision->endrev, pdelta->num, length)
997 if (!(prevision = prevision->rnext))
1008 /* function: get time range from command line and store in datelist if */
1009 /* a time range specified or in duelst if a time spot specified */
1013 struct Datepairs * nextdate;
1014 char const * rawdate;
1018 while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';')
1021 error("missing date/time after -d");
1025 while( c != '\0' ) {
1027 nextdate = talloc(struct Datepairs);
1028 if ( c == '<' ) { /* case: -d <date */
1030 if (!(nextdate->ne_date = c!='='))
1032 (nextdate->strtdate)[0] = '\0';
1033 } else if (c == '>') { /* case: -d'>date' */
1035 if (!(nextdate->ne_date = c!='='))
1037 (nextdate->enddate)[0] = '\0';
1041 while( c != '<' && c != '>' && c != ';' && c != '\0')
1044 if ( c == '>' ) switchflag=true;
1046 switchflag ? nextdate->enddate : nextdate->strtdate);
1047 if ( c == ';' || c == '\0') { /* case: -d date */
1048 VOID strcpy(nextdate->enddate,nextdate->strtdate);
1049 nextdate->dnext = duelst;
1053 /* case: -d date< or -d date>; see switchflag */
1054 int eq = argv[1]=='=';
1055 nextdate->ne_date = !eq;
1057 while ((c = *++argv) == ' ' || c=='\t' || c=='\n')
1059 if ( c == ';' || c == '\0') {
1060 /* second date missing */
1062 *nextdate->strtdate= '\0';
1064 *nextdate->enddate= '\0';
1065 nextdate->dnext = datelist;
1066 datelist = nextdate;
1072 while( c != '>' && c != '<' && c != ';' && c != '\0')
1076 switchflag ? nextdate->strtdate : nextdate->enddate);
1077 nextdate->dnext = datelist;
1078 datelist = nextdate;
1080 if (RCSversion < VERSION(5))
1081 nextdate->ne_date = 0;
1082 if ( c == '\0') return;
1083 while ((c = *++argv) == ';' || c == ' ' || c == '\t' || c =='\n')
1092 /* function: get the numeric name of revisions which stored in revlist */
1093 /* and then stored the numeric names in Revlst */
1094 /* if branchflag, also add default branch */
1097 struct Revpairs * ptr, *pt;
1101 struct buf const *rstart, *rend;
1112 switch (ptr->numfld) {
1115 if (!expandsym(ptr->strtrev, &s))
1118 n = countnumflds(s.string);
1119 if (!n && (lrev = tiprev())) {
1121 n = countnumflds(lrev);
1125 case 2: /* -rREV: */
1126 if (!expandsym(ptr->strtrev, &s))
1128 bufscpy(&e, s.string);
1129 n = countnumflds(s.string);
1130 (n<2 ? e.string : strrchr(e.string,'.'))[0] = 0;
1133 case 3: /* -r:REV */
1134 if (!expandsym(ptr->endrev, &e))
1136 if ((n = countnumflds(e.string)) < 2)
1139 bufscpy(&s, e.string);
1140 VOID strcpy(strrchr(s.string,'.'), ".0");
1144 default: /* -rREV1:REV2 */
1146 expandsym(ptr->strtrev, &s)
1147 && expandsym(ptr->endrev, &e)
1148 && checkrevpair(s.string, e.string)
1151 n = countnumflds(s.string);
1152 /* Swap if out of order. */
1153 if (compartial(s.string,e.string,n) > 0) {
1161 pt = ftalloc(struct Revpairs);
1163 pt->strtrev = fstr_save(rstart->string);
1164 pt->endrev = fstr_save(rend->string);
1170 /* Now take care of branchflag */
1171 if (branchflag && (Dbranch||Head)) {
1172 pt = ftalloc(struct Revpairs);
1173 pt->strtrev = pt->endrev =
1174 Dbranch ? Dbranch : fstr_save(partialno(&s,Head->num,1));
1175 pt->rnext=Revlst; Revlst=pt;
1176 pt->numfld = countnumflds(pt->strtrev);
1188 checkrevpair(num1,num2)
1189 char const *num1, *num2;
1190 /* function: check whether num1, num2 are legal pair,i.e.
1191 only the last field are different and have same number of
1192 fields( if length <= 2, may be different if first field) */
1195 int length = countnumflds(num1);
1198 countnumflds(num2) != length
1199 || (2 < length && compartial(num1, num2, length-1) != 0)
1201 rcserror("invalid branch or revision pair %s : %s", num1, num2);
1212 register char * argv;
1213 /* function: get revision or branch range from command line, and */
1214 /* store in revlist */
1218 struct Revpairs * nextrevpair;
1223 /* Support old ambiguous '-' syntax; this will go away. */
1224 if (strchr(argv,':'))
1227 if (strchr(argv,'-') && VERSION(5) <= RCSversion)
1228 warn("`-' is obsolete in `-r%s'; use `:' instead", argv);
1233 while (c==' ' || c=='\t' || c=='\n')
1235 nextrevpair = talloc(struct Revpairs);
1236 nextrevpair->rnext = revlist;
1237 revlist = nextrevpair;
1238 nextrevpair->numfld = 1;
1239 nextrevpair->strtrev = argv;
1240 for (;; c = *++argv) {
1244 case '\0': case ' ': case '\t': case '\n':
1255 while (c==' ' || c=='\t' || c=='\n')
1257 if (c == separator) {
1258 while ((c = *++argv) == ' ' || c == '\t' || c =='\n')
1260 nextrevpair->endrev = argv;
1261 for (;; c = *++argv) {
1265 case '\0': case ' ': case '\t': case '\n':
1276 while (c==' ' || c=='\t' || c =='\n')
1278 nextrevpair->numfld =
1279 !nextrevpair->endrev[0] ? 2 /* -rREV: */ :
1280 !nextrevpair->strtrev[0] ? 3 /* -r:REV */ :
1281 4 /* -rREV1:REV2 */;
1285 else if (c==',' || c==';')
1288 error("missing `,' near `%c%s'", c, argv+1);