rcs: Fix gcc80 warnings (-Wdangling-else and -Wmisleading-indentation).
[dragonfly.git] / gnu / usr.bin / rcs / rlog / rlog.c
blob02e0d3ed748d2d626ab959c193889bdd80cd7e2d
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)
12 any later version.
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
35 * Update FSF address.
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
90 * Plug memory leak.
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.
97 * Switch to GMT.
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
118 * warnings)
120 * Revision 1.2 87/03/27 14:22:45 jenkins
121 * Port to suns
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).
161 #include "rcsbase.h"
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;
181 char const * endrev;
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;
216 static int lockflag;
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 ...";
229 register FILE *out;
230 char *a, **newargv;
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 */
241 int pre5;
242 int shownames;
243 int revno;
244 int versionlist;
245 char *vstring;
247 descflag = selectflag = shownames = true;
248 versionlist = onlylockflag = onlyRCSflag = false;
249 vstring=0;
250 out = stdout;
251 suffixes = X_DEFAULT;
253 argc = getRCSINIT(argc, argv, &newargv);
254 argv = newargv;
255 while (a = *++argv, 0<--argc && *a++=='-') {
256 switch (*a++) {
258 case 'L':
259 onlylockflag = true;
260 break;
262 case 'N':
263 shownames = false;
264 break;
266 case 'R':
267 onlyRCSflag =true;
268 break;
270 case 'l':
271 lockflag = true;
272 getlocker(a);
273 break;
275 case 'b':
276 branchflag = true;
277 break;
279 case 'r':
280 getrevpairs(a);
281 break;
283 case 'd':
284 getdatepair(a);
285 break;
287 case 's':
288 getstate(a);
289 break;
291 case 'w':
292 getauthor(a);
293 break;
295 case 'h':
296 descflag = false;
297 break;
299 case 't':
300 selectflag = false;
301 break;
303 case 'q':
304 /* This has no effect; it's here for consistency. */
305 quietflag = true;
306 break;
308 case 'x':
309 suffixes = a;
310 break;
312 case 'z':
313 zone_set(a);
314 break;
316 case 'T':
317 /* Ignore -T, so that RCSINIT can contain -T. */
318 if (*a)
319 goto unknown;
320 break;
322 case 'V':
323 setRCSversion(*argv);
324 break;
326 case 'v':
327 versionlist = true;
328 vstring = a;
329 break;
331 default:
332 unknown:
333 error("unknown option: %s%s", *argv, cmdusage);
336 } /* end of option processing */
338 if (! (descflag|selectflag)) {
339 warn("-t overrides -h.");
340 descflag = true;
343 pre5 = RCSversion < VERSION(5);
344 if (pre5) {
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;";
350 } else {
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. */
359 if (nerror)
360 cleanup();
361 else if (argc < 1)
362 faterror("no input file%s", cmdusage);
363 else
364 for (; 0 < argc; cleanup(), ++argv, --argc) {
365 ffree();
367 if (pairnames(argc, argv, rcsreadopen, true, false) <= 0)
368 continue;
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. */
377 if (lockflag)
378 trunclocks();
380 /* do nothing if -L is given and there are no locks*/
381 if (onlylockflag && !Locks)
382 continue;
384 if ( versionlist ) {
385 gettree();
386 aprintf(out, "%s%s %s\n", vstring, workname, tiprev());
387 continue;
390 if ( onlyRCSflag ) {
391 aprintf(out, "%s\n", RCSname);
392 continue;
395 gettree();
397 if (!getnumericrev())
398 continue;
401 * Output the first character with putc, not printf.
402 * Otherwise, an SVR4 stdio bug buffers output inefficiently.
404 aputc_('\n', out)
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" : ""
414 currlock = Locks;
415 while( currlock ) {
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;
425 while(curaccess) {
426 aprintf(out, accessFormat, curaccess->login);
427 curaccess = curaccess->nextaccess;
430 if (shownames) {
431 aputs("\nsymbolic names:", out); /* print symbolic names */
432 for (curassoc=Symbols; curassoc; curassoc=curassoc->nextassoc)
433 aprintf(out, symbolFormat, curassoc->symbol, curassoc->num);
435 if (pre5) {
436 aputs("\ncomment leader: \"", out);
437 awrite(Comment.string, Comment.size, out);
438 afputc('\"', out);
440 if (!pre5 || Expand != KEYVAL_EXPAND)
441 aprintf(out, "\nkeyword substitution: %s",
442 expand_names[Expand]
445 aprintf(out, "\ntotal revisions: %d", TotalDeltas);
447 revno = 0;
449 if (Head && selectflag & descflag) {
451 exttree(Head);
453 /* get most recently date of the dates pointed by duelst */
454 currdate = duelst;
455 while( currdate) {
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);
466 afputc('\n',out);
467 if (descflag) {
468 aputs("description:\n", out);
469 getdesc(true);
471 if (revno) {
472 while (! (delta = readdeltalog())->selector || --revno)
473 continue;
474 if (delta->next && countnumflds(delta->num)==2)
475 /* Read through delta->next to get its insertlns. */
476 while (readdeltalog() != delta->next)
477 continue;
478 putrunk();
479 putree(Head);
481 aputs("----------------------------\n", out);
482 aputs("=============================================================================\n",out);
484 Ofclose(out);
485 exitmain(exitstatus);
488 static void
489 cleanup()
491 if (nerror) exitstatus = EXIT_FAILURE;
492 Izclose(&finptr);
495 #if RCS_lint
496 # define exiterr rlogExit
497 #endif
498 void
499 exiterr()
501 _exit(EXIT_FAILURE);
506 static void
507 putrunk()
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);
519 static void
520 putree(root)
521 struct hshentry const *root;
522 /* function: print delta tree (not including trunk) in reverse
523 order on each branch */
526 if (!root) return;
528 putree(root->next);
530 putforest(root->branches);
536 static void
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);
552 static void
553 putabranch(root)
554 struct hshentry const *root;
555 /* function : print one branch */
558 if (!root) return;
560 putabranch(root->next);
562 putadelta(root, root, false);
569 static void
570 putadelta(node,editscript,trunk)
571 register struct hshentry const *node, *editscript;
572 int trunk;
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;
579 register FILE *out;
580 char const *s;
581 size_t n;
582 struct branchhead const *newbranch;
583 struct buf branchnum;
584 char datebuf[datesize + zonelenmax];
585 int pre5 = RCSversion < VERSION(5);
587 if (!node->selector)
588 return;
590 out = stdout;
591 aprintf(out,
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
603 if ( editscript ) {
604 if(trunk)
605 aprintf(out, insDelFormat,
606 editscript->deletelns, editscript->insertlns);
607 else
608 aprintf(out, insDelFormat,
609 editscript->insertlns, editscript->deletelns);
612 if ( node->commitid )
613 aprintf(out, "%s commitid: %s", (editscript) ? ";" : "",
614 node->commitid);
616 newbranch = node->branches;
617 if ( newbranch ) {
618 bufautobegin(&branchnum);
619 aputs("\nbranches:", out);
620 while( newbranch ) {
621 getbranchno(newbranch->hsh->num, &branchnum);
622 aprintf(out, " %s;", branchnum.string);
623 newbranch = newbranch->nextbranch;
625 bufautoend(&branchnum);
628 afputc('\n', out);
629 s = node->log.string;
630 if (!(n = node->log.size)) {
631 s = emptych;
632 n = sizeof(emptych)-1;
634 awrite(s, n, out);
635 if (s[n-1] != '\n')
636 afputc('\n', out);
640 static struct hshentry const *
641 readdeltalog()
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
645 * advance nexttok.
648 register struct hshentry * Delta;
649 struct buf logbuf;
650 struct cbuf cb;
652 if (eoflex())
653 fatserror("missing delta log");
654 nextlex();
655 if (!(Delta = getnum()))
656 fatserror("delta number corrupted");
657 getkeystring(Klog);
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);
665 getkeystring(Ktext);
666 Delta->insertlns = Delta->deletelns = 0;
667 if ( Delta != Head)
668 getscript(Delta);
669 else
670 readstring();
671 return Delta;
675 static void
676 getscript(Delta)
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 */
683 declarecache;
684 register RILE *fin;
685 register int c;
686 register long i;
687 struct diffcmd dc;
689 fin = finptr;
690 setupcache(fin);
691 initdiffcmd(&dc);
692 while (0 <= (ed = getdiffcmd(fin,true,(FILE *)0,&dc)))
693 if (!ed)
694 Delta->deletelns += dc.nlines;
695 else {
696 /* skip scripted lines */
697 i = dc.nlines;
698 Delta->insertlns += i;
699 cache(fin);
700 do {
701 for (;;) {
702 cacheget_(c)
703 switch (c) {
704 default:
705 continue;
706 case SDELIM:
707 cacheget_(c)
708 if (c == SDELIM)
709 continue;
710 if (--i)
711 unexpected_EOF();
712 nextc = c;
713 uncache(fin);
714 return;
715 case '\n':
716 break;
718 break;
720 ++rcsline;
721 } while (--i);
722 uncache(fin);
732 static void
733 exttree(root)
734 struct hshentry *root;
735 /* function: select revisions , starting with root */
738 struct branchhead const *newbranch;
740 if (!root) return;
742 root->selector = extractdelta(root);
743 root->log.string = 0;
744 exttree(root->next);
746 newbranch = root->branches;
747 while( newbranch ) {
748 exttree(newbranch->hsh);
749 newbranch = newbranch->nextbranch;
756 static void
757 getlocker(argv)
758 char * argv;
759 /* function : get the login names of lockers from command line */
760 /* and store in lockerlist. */
763 register char c;
764 struct rcslockers *newlocker;
765 argv--;
766 while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';')
767 continue;
768 if ( c == '\0') {
769 lockerlist = 0;
770 return;
773 while( c != '\0' ) {
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!=';')
779 continue;
780 *argv = '\0';
781 if ( c == '\0' ) return;
782 while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';')
783 continue;
789 static void
790 getauthor(argv)
791 char *argv;
792 /* function: get the author's name from command line */
793 /* and store in authorlist */
796 register int c;
797 struct authors * newauthor;
799 argv--;
800 while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';')
801 continue;
802 if ( c == '\0' ) {
803 authorlist = talloc(struct authors);
804 authorlist->login = getusername(false);
805 authorlist->nextauthor = 0;
806 return;
809 while( c != '\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!=';')
815 continue;
816 * argv = '\0';
817 if ( c == '\0') return;
818 while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';')
819 continue;
826 static void
827 getstate(argv)
828 char * argv;
829 /* function : get the states of revisions from command line */
830 /* and store in statelist */
833 register char c;
834 struct stateattri *newstate;
836 argv--;
837 while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';')
838 continue;
839 if ( c == '\0'){
840 error("missing state attributes after -s options");
841 return;
844 while( c != '\0' ) {
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!=';')
850 continue;
851 *argv = '\0';
852 if ( c == '\0' ) return;
853 while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';')
854 continue;
860 static void
861 trunclocks()
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) {
875 pp = &p->nextlock;
876 break;
877 } else if (!(plocker = plocker->lockerlink)) {
878 *pp = p->nextlock;
879 break;
885 static void
886 recentdate(root, pd)
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;
896 if (!root) return;
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;
905 while( newbranch) {
906 recentdate(newbranch->hsh, pd);
907 newbranch = newbranch->nextbranch;
916 static int
917 extdate(root)
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;
925 int revno, ne;
927 if (!root)
928 return 0;
930 if ( datelist || duelst) {
931 pdate = datelist;
932 while( pdate ) {
933 ne = pdate->ne_date;
934 if (
935 (!pdate->strtdate[0]
936 || ne <= cmpdate(root->date, pdate->strtdate))
938 (!pdate->enddate[0]
939 || ne <= cmpdate(pdate->enddate, root->date))
941 break;
942 pdate = pdate->dnext;
944 if (!pdate) {
945 pdate = duelst;
946 for (;;) {
947 if (!pdate) {
948 root->selector = false;
949 break;
951 if (cmpdate(root->date, pdate->strtdate) == 0)
952 break;
953 pdate = pdate->dnext;
957 revno = root->selector + extdate(root->next);
959 newbranch = root->branches;
960 while( newbranch ) {
961 revno += extdate(newbranch->hsh);
962 newbranch = newbranch->nextbranch;
964 return revno;
969 static char
970 extractdelta(pdelta)
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;
980 int length;
982 if ((pauthor = authorlist)) /* only certain authors wanted */
983 while (strcmp(pauthor->login, pdelta->author) != 0)
984 if (!(pauthor = pauthor->nextauthor))
985 return false;
986 if ((pstate = statelist)) /* only certain states wanted */
987 while (strcmp(pstate->status, pdelta->state) != 0)
988 if (!(pstate = pstate->nextstate))
989 return false;
990 if (lockflag) { /* only locked revisions wanted */
991 for (plock = Locks; ; plock = plock->nextlock) {
992 if (!plock)
993 return false;
994 else if (plock->delta == pdelta)
995 break;
998 if ((prevision = Revlst)) /* only certain revs or branches wanted */
999 for (;;) {
1000 length = prevision->numfld;
1001 if (
1002 countnumflds(pdelta->num) == length+(length&1) &&
1003 0 <= compartial(pdelta->num, prevision->strtrev, length) &&
1004 0 <= compartial(prevision->endrev, pdelta->num, length)
1006 break;
1007 if (!(prevision = prevision->rnext))
1008 return false;
1010 return true;
1015 static void
1016 getdatepair(argv)
1017 char * argv;
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 */
1022 register char c;
1023 struct Datepairs * nextdate;
1024 char const * rawdate;
1025 int switchflag;
1027 argv--;
1028 while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';')
1029 continue;
1030 if ( c == '\0' ) {
1031 error("missing date/time after -d");
1032 return;
1035 while( c != '\0' ) {
1036 switchflag = false;
1037 nextdate = talloc(struct Datepairs);
1038 if ( c == '<' ) { /* case: -d <date */
1039 c = *++argv;
1040 if (!(nextdate->ne_date = c!='='))
1041 c = *++argv;
1042 (nextdate->strtdate)[0] = '\0';
1043 } else if (c == '>') { /* case: -d'>date' */
1044 c = *++argv;
1045 if (!(nextdate->ne_date = c!='='))
1046 c = *++argv;
1047 (nextdate->enddate)[0] = '\0';
1048 switchflag = true;
1049 } else {
1050 rawdate = argv;
1051 while( c != '<' && c != '>' && c != ';' && c != '\0')
1052 c = *++argv;
1053 *argv = '\0';
1054 if ( c == '>' ) switchflag=true;
1055 str2date(rawdate,
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;
1060 duelst = nextdate;
1061 goto end;
1062 } else {
1063 /* case: -d date< or -d date>; see switchflag */
1064 int eq = argv[1]=='=';
1065 nextdate->ne_date = !eq;
1066 argv += eq;
1067 while ((c = *++argv) == ' ' || c=='\t' || c=='\n')
1068 continue;
1069 if ( c == ';' || c == '\0') {
1070 /* second date missing */
1071 if (switchflag)
1072 *nextdate->strtdate= '\0';
1073 else
1074 *nextdate->enddate= '\0';
1075 nextdate->dnext = datelist;
1076 datelist = nextdate;
1077 goto end;
1081 rawdate = argv;
1082 while( c != '>' && c != '<' && c != ';' && c != '\0')
1083 c = *++argv;
1084 *argv = '\0';
1085 str2date(rawdate,
1086 switchflag ? nextdate->strtdate : nextdate->enddate);
1087 nextdate->dnext = datelist;
1088 datelist = nextdate;
1089 end:
1090 if (RCSversion < VERSION(5))
1091 nextdate->ne_date = 0;
1092 if ( c == '\0') return;
1093 while ((c = *++argv) == ';' || c == ' ' || c == '\t' || c =='\n')
1094 continue;
1100 static int
1101 getnumericrev()
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;
1108 int n;
1109 struct buf s, e;
1110 char const *lrev;
1111 struct buf const *rstart, *rend;
1113 Revlst = 0;
1114 ptr = revlist;
1115 bufautobegin(&s);
1116 bufautobegin(&e);
1117 while( ptr ) {
1118 n = 0;
1119 rstart = &s;
1120 rend = &e;
1122 switch (ptr->numfld) {
1124 case 1: /* -rREV */
1125 if (!expandsym(ptr->strtrev, &s))
1126 goto freebufs;
1127 rend = &s;
1128 n = countnumflds(s.string);
1129 if (!n && (lrev = tiprev())) {
1130 bufscpy(&s, lrev);
1131 n = countnumflds(lrev);
1133 break;
1135 case 2: /* -rREV: */
1136 if (!expandsym(ptr->strtrev, &s))
1137 goto freebufs;
1138 bufscpy(&e, s.string);
1139 n = countnumflds(s.string);
1140 (n<2 ? e.string : strrchr(e.string,'.'))[0] = 0;
1141 break;
1143 case 3: /* -r:REV */
1144 if (!expandsym(ptr->endrev, &e))
1145 goto freebufs;
1146 if ((n = countnumflds(e.string)) < 2)
1147 bufscpy(&s, ".0");
1148 else {
1149 bufscpy(&s, e.string);
1150 VOID strcpy(strrchr(s.string,'.'), ".0");
1152 break;
1154 default: /* -rREV1:REV2 */
1155 if (!(
1156 expandsym(ptr->strtrev, &s)
1157 && expandsym(ptr->endrev, &e)
1158 && checkrevpair(s.string, e.string)
1160 goto freebufs;
1161 n = countnumflds(s.string);
1162 /* Swap if out of order. */
1163 if (compartial(s.string,e.string,n) > 0) {
1164 rstart = &e;
1165 rend = &s;
1167 break;
1170 if (n) {
1171 pt = ftalloc(struct Revpairs);
1172 pt->numfld = n;
1173 pt->strtrev = fstr_save(rstart->string);
1174 pt->endrev = fstr_save(rend->string);
1175 pt->rnext = Revlst;
1176 Revlst = pt;
1178 ptr = ptr->rnext;
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);
1189 freebufs:
1190 bufautoend(&s);
1191 bufautoend(&e);
1192 return !ptr;
1197 static int
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);
1207 if (
1208 countnumflds(num2) != length
1209 || (2 < length && compartial(num1, num2, length-1) != 0)
1211 rcserror("invalid branch or revision pair %s : %s", num1, num2);
1212 return false;
1215 return true;
1220 static void
1221 getrevpairs(argv)
1222 register char * argv;
1223 /* function: get revision or branch range from command line, and */
1224 /* store in revlist */
1227 register char c;
1228 struct Revpairs * nextrevpair;
1229 int separator;
1231 c = *argv;
1233 /* Support old ambiguous '-' syntax; this will go away. */
1234 if (strchr(argv,':'))
1235 separator = ':';
1236 else {
1237 if (strchr(argv,'-') && VERSION(5) <= RCSversion)
1238 warn("`-' is obsolete in `-r%s'; use `:' instead", argv);
1239 separator = '-';
1242 for (;;) {
1243 while (c==' ' || c=='\t' || c=='\n')
1244 c = *++argv;
1245 nextrevpair = talloc(struct Revpairs);
1246 nextrevpair->rnext = revlist;
1247 revlist = nextrevpair;
1248 nextrevpair->numfld = 1;
1249 nextrevpair->strtrev = argv;
1250 for (;; c = *++argv) {
1251 switch (c) {
1252 default:
1253 continue;
1254 case '\0': case ' ': case '\t': case '\n':
1255 case ',': case ';':
1256 break;
1257 case ':': case '-':
1258 if (c == separator)
1259 break;
1260 continue;
1262 break;
1264 *argv = '\0';
1265 while (c==' ' || c=='\t' || c=='\n')
1266 c = *++argv;
1267 if (c == separator) {
1268 while ((c = *++argv) == ' ' || c == '\t' || c =='\n')
1269 continue;
1270 nextrevpair->endrev = argv;
1271 for (;; c = *++argv) {
1272 switch (c) {
1273 default:
1274 continue;
1275 case '\0': case ' ': case '\t': case '\n':
1276 case ',': case ';':
1277 break;
1278 case ':': case '-':
1279 if (c == separator)
1280 break;
1281 continue;
1283 break;
1285 *argv = '\0';
1286 while (c==' ' || c=='\t' || c =='\n')
1287 c = *++argv;
1288 nextrevpair->numfld =
1289 !nextrevpair->endrev[0] ? 2 /* -rREV: */ :
1290 !nextrevpair->strtrev[0] ? 3 /* -r:REV */ :
1291 4 /* -rREV1:REV2 */;
1293 if (!c)
1294 break;
1295 else if (c==',' || c==';')
1296 c = *++argv;
1297 else
1298 error("missing `,' near `%c%s'", c, argv+1);