No empty .Rs/.Re
[netbsd-mini2440.git] / usr.bin / rcs / src / rlog.c
blob17c9424d1e0adcfc3e62de376b01489fca4a7305
1 /*
2 * RLOG operation
3 */
4 #ifndef lint
5 static char rcsid[]=
6 "$Header: /pub/NetBSD/misc/repositories/cvsroot/src/usr.bin/rcs/src/Attic/rlog.c,v 1.1 1993/03/21 09:58:09 cgd Exp $ Purdue CS";
7 #endif
8 /*****************************************************************************
9 * print contents of RCS files
10 *****************************************************************************
13 /* Copyright (C) 1982, 1988, 1989 Walter Tichy
14 * All rights reserved.
16 * Redistribution and use in source and binary forms are permitted
17 * provided that the above copyright notice and this paragraph are
18 * duplicated in all such forms and that any documentation,
19 * advertising materials, and other materials related to such
20 * distribution and use acknowledge that the software was developed
21 * by Walter Tichy.
22 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
26 * Report all problems and direct all questions to:
27 * rcs-bugs@cs.purdue.edu
41 /* $Log: rlog.c,v $
42 * Revision 4.7 89/05/01 15:13:48 narten
43 * changed copyright header to reflect current distribution rules
45 * Revision 4.6 88/11/08 11:59:40 narten
46 * changes from eggert@sm.unisys.com (Paul Eggert)
48 * Revision 4.6 88/08/09 19:13:28 eggert
49 * Check for memory exhaustion; don't access freed storage.
50 * Shrink stdio code size; remove lint.
52 * Revision 4.5 87/12/18 11:46:38 narten
53 * more lint cleanups (Guy Harris)
55 * Revision 4.4 87/10/18 10:41:12 narten
56 * Updating version numbers
57 * Changes relative to 1.1 actually relative to 4.2
59 * Revision 1.3 87/09/24 14:01:10 narten
60 * Sources now pass through lint (if you ignore printf/sprintf/fprintf
61 * warnings)
63 * Revision 1.2 87/03/27 14:22:45 jenkins
64 * Port to suns
66 * Revision 1.1 84/01/23 14:50:45 kcs
67 * Initial revision
69 * Revision 4.2 83/12/05 09:18:09 wft
70 * changed rewriteflag to external.
72 * Revision 4.1 83/05/11 16:16:55 wft
73 * Added -b, updated getnumericrev() accordingly.
74 * Replaced getpwuid() with getcaller().
76 * Revision 3.7 83/05/11 14:24:13 wft
77 * Added options -L and -R;
78 * Fixed selection bug with -l on multiple files.
79 * Fixed error on dates of the form -d'>date' (rewrote getdatepair()).
81 * Revision 3.6 82/12/24 15:57:53 wft
82 * shortened output format.
84 * Revision 3.5 82/12/08 21:45:26 wft
85 * removed call to checkaccesslist(); used DATEFORM to format all dates;
86 * removed unused variables.
88 * Revision 3.4 82/12/04 13:26:25 wft
89 * Replaced getdelta() with gettree(); removed updating of field lockedby.
91 * Revision 3.3 82/12/03 14:08:20 wft
92 * Replaced getlogin with getpwuid(), %02d with %.2d, fancydate with PRINTDATE.
93 * Fixed printing of nil, removed printing of Suffix,
94 * added shortcut if no revisions are printed, disambiguated struct members.
96 * Revision 3.2 82/10/18 21:09:06 wft
97 * call to curdir replaced with getfullRCSname(),
98 * fixed call to getlogin(), cosmetic changes on output,
99 * changed conflicting long identifiers.
101 * Revision 3.1 82/10/13 16:07:56 wft
102 * fixed type of variables receiving from getc() (char -> int).
107 #include "time.h"
108 #include "rcsbase.h"
109 #ifndef lint
110 static char rcsbaseid[] = RCSBASE;
111 #endif
113 extern char * partialno();
114 extern char * getcaller(); /*get login of caller */
115 extern free();
116 extern int countnumflds();
117 extern int compartial();
118 extern int expandsym(); /*get numeric name of a revision */
119 extern int nextc; /*next input character */
120 extern char Klog[];
121 extern char Ktext[];
122 extern int partime();
123 extern long maketime(); /*convert parsed time to unix time. */
124 extern struct tm * localtime(); /*convert unixtime into a tm-structure */
125 extern int pairfilenames();
126 extern struct hshentry * getnum();
127 extern FILE * finptr; /* RCS input file */
128 extern FILE * frewrite; /* new RCS file */
129 extern int rewriteflag; /* indicates whether input should be */
130 /* echoed to frewrite */
131 extern int nerror; /* error counter */
133 char * RCSfilename, * workfilename;
135 char * caller; /* caller's login; */
136 int descflag, selectflag, selectop; /* option to print access list, symbolic */
137 /* names, descriptive text, locks and */
138 /* Head */
139 int onlylockflag; /* option to print only files */
140 /* with locks */
141 int onlyRCSflag; /* option to print only RCS file name */
142 int lockflag; /* whether locker option is set */
143 int revno; /* number of revision chosen */
145 struct lockers { /* lockers in locker option; stored */
146 char * login; /* lockerlist */
147 struct lockers * lockerlink;
150 struct stateattri { /* states in state option; stored in */
151 char * status; /* statelist */
152 struct stateattri * nextstate;
155 struct authors { /* login names in author option; */
156 char * login; /* stored in authorlist */
157 struct authors * nextauthor;
160 struct Revpairs{ /* revision or branch range in -r */
161 int numfld; /* option; stored in revlist */
162 char * strtrev;
163 char * endrev;
164 struct Revpairs * rnext;
167 struct Datepairs{ /* date range in -d option; stored in */
168 char strtdate[datelength]; /* duelst and datelist */
169 char enddate[datelength];
170 struct Datepairs * dnext;
173 char Dotstring[200]; /* string of numeric revision name */
174 char * Nextdotstring; /* next available place of Dotstring */
175 struct Datepairs * datelist, * duelst;
176 struct Revpairs * revlist, * Revlst;
177 int branchflag; /* set on -b */
178 struct lockers * lockerlist;
179 struct stateattri * statelist;
180 struct authors * authorlist;
184 main (argc, argv)
185 int argc;
186 char * argv[];
188 struct Datepairs * currdate;
189 struct assoc * curassoc;
190 struct access * curaccess;
191 struct lock * currlock;
192 char * cmdusage;
194 cmdusage = "command format:\nrlog -L -R -h -t -b -ddates -l[lockers] -rrevisions -sstates -w[logins] file ...";
195 cmdid = "rlog";
196 descflag = selectflag = true;
197 lockflag = onlylockflag = selectop = false;
198 onlyRCSflag = false;
199 lockerlist = nil;
200 authorlist = nil;
201 statelist = nil;
202 Revlst = revlist = nil;
203 branchflag= false;
204 duelst = datelist = nil;
205 caller=getcaller();
207 while (--argc,++argv, argc>=1 && ((*argv)[0] == '-')) {
208 switch ((*argv)[1]) {
210 case 'L':
211 onlylockflag = true;
212 break;
214 case 'R':
215 onlyRCSflag =true;
216 break;
218 case 'l':
219 selectop = true;
220 lockflag = true;
221 getlocker( (*argv)+2 );
222 break;
224 case 'b':
225 selectop = true;
226 branchflag = true;
227 break;
229 case 'r':
230 selectop = true;
231 getrevpairs( (*argv)+2 );
232 break;
234 case 'd':
235 selectop = true;
236 getdatepair( (*argv)+2 );
237 break;
239 case 's':
240 selectop = true;
241 getstate( (*argv)+2);
242 break;
244 case 'w':
245 selectop = true;
246 getauthor( (*argv)+2);
247 break;
249 case 'h':
250 if ( ! selectflag ) warn("option -t overrides -h");
251 else descflag = false;
252 break;
254 case 't':
255 selectflag = false;
256 if ( ! descflag ) warn("option -t overrides -h");
257 descflag = true;
258 break;
260 default:
261 faterror("unknown option: %s\n%s", *argv,cmdusage);
264 } /* end of option processing */
266 if (argc<1) faterror("No input file\n%s",cmdusage);
269 /* now handle all filenames */
270 do {
271 rewriteflag=false;
272 finptr=frewrite=nil;
275 if (!pairfilenames(argc, argv, true,false)) continue;
277 /* now RCSfilename contains the name of the RCS file, and finptr
278 * the file descriptor. Workfilename contains the name of the
279 * working file.
282 if ( !trysema(RCSfilename, false)) goto loopend; /* give up */
284 /* do nothing if -L is given and there are no locks*/
285 if ( onlylockflag && Locks == nil ) goto loopend;
287 if ( onlyRCSflag ) {
288 VOID fprintf(stdout, "%s\n", RCSfilename);
289 goto loopend;
291 /* print RCS filename , working filename and optional
292 administrative information */
293 VOID fprintf(stdout, "\nRCS file: %s; ",RCSfilename);
294 /* could use getfullRCSname() here, but that is very slow */
295 VOID fprintf(stdout, "Working file: %s\n", workfilename);
296 VOID fprintf(stdout, "head: %s\n", Head==nil?"":Head->num);
297 VOID fprintf(stdout, "branch: %s\n", Dbranch==nil?"":Dbranch->num);
299 VOID fputs("locks: ", stdout); /* print locker list */
300 currlock = Locks;
301 while( currlock ) {
302 VOID fprintf(stdout," %s: %s;", currlock->login,
303 currlock->delta->num);
304 currlock = currlock->nextlock;
306 if ( StrictLocks )
307 VOID fputs(Locks==nil?" ; strict":" strict",stdout);
309 VOID fputs("\naccess list: ", stdout); /* print access list */
310 curaccess = AccessList;
311 while(curaccess) {
312 VOID fputs(" ",stdout);
313 VOID fputs(curaccess->login, stdout);
314 curaccess = curaccess->nextaccess;
317 VOID fputs("\nsymbolic names:", stdout); /* print symbolic names */
318 curassoc = Symbols;
319 while( curassoc ) {
320 VOID fprintf(stdout, " %s: %s;",curassoc->symbol,
321 curassoc->delta->num);
322 curassoc = curassoc->nextassoc;
325 VOID fprintf(stdout,"\ncomment leader: \"%s\"\n",Comment);
327 gettree();
328 VOID fprintf(stdout, "total revisions: %d; ", TotalDeltas);
329 if ( Head == nil || !selectflag || !descflag) {
330 VOID putc('\n',stdout);
331 if (descflag) VOID fputs("description:\n", stdout);
332 getdesc(descflag);
333 VOID fputs("=============================================================================\n",stdout);
334 goto loopend;
338 /* keep only those locks given by -l */
339 if (lockflag)
340 trunclocks();
341 getnumericrev(); /* get numeric revision or branch names */
342 revno = 0;
344 exttree(Head);
346 /* get most recently date of the dates pointed by duelst */
347 currdate = duelst;
348 while( currdate) {
349 recentdate(Head, currdate);
350 currdate = currdate->dnext;
353 extdate(Head);
355 /* reinitialize the date specification list */
356 currdate = duelst;
357 while(currdate) {
358 VOID sprintf(currdate->strtdate,DATEFORM,0,0,0,0,0,0);
359 currdate = currdate->dnext;
362 if ( selectop || ( selectflag && descflag) )
363 VOID fprintf(stdout, "selected revisions: %d", revno);
364 VOID putc('\n', stdout);
365 if (descflag) VOID fputs("description:\n", stdout);
366 getdesc(descflag);
367 while( (nexttok != EOFILE) && readdeltalog());
368 if (selectflag && descflag && revno) {
369 putrunk();
370 putree(Head);
371 if (nextlex(), nexttok != EOFILE)
372 fatserror("syntax error; expecting EOF");
374 VOID fputs("=============================================================================\n",stdout);
375 loopend:
376 VOID fclose(finptr);
377 } while( ++argv, --argc >= 1);
378 exit(nerror!=0);
383 putrunk()
384 /* function: print revisions chosen, which are in trunk */
387 struct hshentry * ptr, * pre;
389 if (Head == nil) return; /* empty tree */
391 pre = Head;
392 ptr = Head->next;
393 while( ptr ) {
394 putadelta(pre,ptr,true);
395 pre = ptr;
396 ptr = ptr->next;
398 putadelta(pre,ptr,true);
403 putree(root)
404 struct hshentry *root;
405 /* function: print delta tree( not include trunck) in reversed calender
406 order on each branch */
409 if ( root == nil ) return;
411 putree(root->next);
413 putforest(root->branches);
419 putforest(branchroot)
420 struct branchhead * branchroot;
421 /* function: print branches that has the same direct ancestor */
424 if ( branchroot == nil ) return;
426 putforest(branchroot->nextbranch);
428 putabranch(branchroot->hsh);
429 putree(branchroot->hsh);
435 putabranch(root)
436 struct hshentry *root;
437 /* function : print one branch */
441 if ( root == nil) return;
443 putabranch(root->next);
445 putadelta(root, root, false);
452 putadelta(node,editscript,trunk)
453 register struct hshentry * node;
454 register struct hshentry * editscript;
455 int trunk;
456 /* function: print delta node if node->selector is 's'. */
457 /* editscript indicates where the editscript is stored */
458 /* trunk indicated whether this node is in trunk */
460 struct branchhead * newbranch;
461 char * branchnum, branch[40];
463 if ( ( node == nil) || ( node->selector == 'u'))
464 return;
466 VOID fprintf(stdout,"----------------------------\n");
467 VOID fprintf(stdout, "revision %s ",node->num);
468 if ( node->lockedby )
469 VOID fprintf(stdout, "locked by: %s; ", node->lockedby);
470 VOID putc('\n', stdout);
472 VOID fputs("date: ",stdout);
473 VOID PRINTDATE(stdout,node->date); VOID putc(' ',stdout);
474 VOID PRINTTIME(stdout,node->date);
475 VOID fprintf(stdout, "; author: %s; ", node->author);
476 VOID fprintf(stdout, "state: %s; ", node->state);
478 if ( editscript )
479 if(trunk)
480 VOID fprintf(stdout,"lines added/del: %d/%d",
481 editscript->deletelns, editscript->insertlns);
482 else
483 VOID fprintf(stdout,"lines added/del: %d/%d",
484 editscript->insertlns, editscript->deletelns);
486 VOID putc('\n', stdout);
488 branchnum = & (branch[0]);
489 newbranch = node->branches;
490 if ( newbranch ) {
491 VOID fputs("branches: ", stdout);
492 while( newbranch ) {
493 getbranchno(newbranch->hsh->num, branchnum);
494 VOID fprintf(stdout, "%s; ", branchnum);
495 newbranch = newbranch->nextbranch;
497 VOID putc('\n', stdout);
500 VOID fputs(node->log,stdout);
507 readdeltalog()
508 /* Function : get the log message and skip the text of a deltatext node.
509 * Return false if current block does not start with a number.
510 * Assumes the current lexeme is not yet in nexttok; does not
511 * advance nexttok.
514 register struct hshentry * Delta;
516 nextlex();
517 if ( !(Delta = getnum() )) return(false);
518 if ( ! getkey(Klog) || ( nexttok != STRING ) )
519 fatserror("Missing log entry");
520 Delta->log = talloc(logsize);
521 VOID savestring(Delta->log, logsize);
522 nextlex();
523 if ( ! getkey(Ktext) || (nexttok != STRING) )
524 fatserror("Missing delta text");
525 Delta->insertlns = Delta->deletelns = 0;
526 if ( Delta != Head)
527 getscript(Delta);
528 else
529 readstring();
530 return true;
535 getscript(Delta)
536 struct hshentry * Delta;
537 /* function: read edit script of Delta and count how many lines added */
538 /* and deleted in the script */
541 int ed; /* editor command */
542 register FILE * fin;
543 register int c;
544 register int i;
545 int length;
547 fin = finptr;
548 while( (ed = getc(fin)) != EOF) {
549 /* assume first none white character is command name */
550 while( ed == '\n' || ed == ' ' || ed == '\t')
551 ed = getc(fin);
552 if (ed == SDELIM) break; /* script text is ended */
553 while( ( c = getc(fin)) == ' ' ); /* skip blank */
554 if ( ! ('0' <= c && c <= '9')) {
555 faterror("Missing line number in edit script");
556 break;
558 while( '0' <= (c = getc(fin)) && c <= '9' ) ;
560 while( c == ' ')c = getc(fin); /* skip blanks */
561 if ( !('0' <= c && c <= '9' ) ) {
562 faterror("Incorrect range in edit script");
563 break;
565 length = c - '0';
566 while( '0' <= (c = getc(fin)) && c <= '9' )
567 length = length * 10 + c - '0';
568 while( c != '\n' && c != EOF) c = getc(fin);
569 switch (ed) {
570 case 'd' :
571 Delta->deletelns += length;
572 break;
574 case 'a' :
575 /* skip scripted lines */
576 for ( i=length; i > 0 && c != EOF; i--){
577 while( (c=getc(fin)) != '\n' && c != EOF);
578 Delta->insertlns++;
580 break;
582 default:
583 faterror("Unknown command in edit script: %c", ed);
584 break;
587 nextc = getc(fin);
596 exttree(root)
597 struct hshentry *root;
598 /* function: select revisions , starting with root */
601 struct branchhead * newbranch;
603 if (root == nil) return;
605 extractdelta(root);
606 exttree(root->next);
608 newbranch = root->branches;
609 while( newbranch ) {
610 exttree(newbranch->hsh);
611 newbranch = newbranch->nextbranch;
618 getlocker(argv)
619 char * argv;
620 /* function : get the login names of lockers from command line */
621 /* and store in lockerlist. */
624 register char c;
625 struct lockers * newlocker;
626 argv--;
627 while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' ||
628 c == '\n' || c == ';') ;
629 if ( c == '\0') {
630 lockerlist=nil;
631 return;
634 while( c != '\0' ) {
635 newlocker = ( struct lockers *)talloc( sizeof(struct lockers) );
636 newlocker->lockerlink = lockerlist;
637 newlocker->login = argv;
638 lockerlist = newlocker;
639 while ( ( c = (*++argv)) != ',' && c != '\0' && c != ' '
640 && c != '\t' && c != '\n' && c != ';') ;
641 *argv = '\0';
642 if ( c == '\0' ) return;
643 while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' ||
644 c == '\n' || c == ';') ;
650 getauthor(argv)
651 char *argv;
652 /* function: get the author's name form command line */
653 /* and store in aauthorlist */
656 register c;
657 struct authors * newauthor;
659 argv--;
660 while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' ||
661 c == '\n' || c == ';') ;
662 if ( c == '\0' ) {
663 authorlist = (struct authors *)talloc(sizeof(struct authors));
664 authorlist->login = caller;
665 authorlist->nextauthor = nil;
666 return;
669 while( c != '\0' ) {
670 newauthor = (struct authors *)talloc(sizeof(struct authors));
671 newauthor->nextauthor = authorlist;
672 newauthor->login = argv;
673 authorlist = newauthor;
674 while( ( c = *++argv) != ',' && c != '\0' && c != ' '
675 && c != '\t' && c != '\n' && c != ';') ;
676 * argv = '\0';
677 if ( c == '\0') return;
678 while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' ||
679 c == '\n' || c == ';') ;
686 getstate(argv)
687 char * argv;
688 /* function : get the states of revisions from command line */
689 /* and store in statelist */
692 register char c;
693 struct stateattri *newstate;
695 argv--;
696 while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' ||
697 c == '\n' || c == ';') ;
698 if ( c == '\0'){
699 warn(" Missing state attributes after -s options");
700 return;
703 while( c != '\0' ) {
704 newstate = (struct stateattri *)talloc(sizeof(struct stateattri));
705 newstate->nextstate = statelist;
706 newstate->status = argv;
707 statelist = newstate;
708 while( (c = (*++argv)) != ',' && c != '\0' && c != ' '
709 && c != '\t' && c != '\n' && c != ';') ;
710 *argv = '\0';
711 if ( c == '\0' ) return;
712 while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' ||
713 c == '\n' || c == ';') ;
719 trunclocks()
720 /* Function: Truncate the list of locks to those that are held by the */
721 /* id's on lockerlist. Do not truncate if lockerlist empty. */
724 struct lockers * plocker;
725 struct lock * plocked, * nextlocked;
727 if ( (lockerlist == nil) || (Locks == nil)) return;
729 /* shorten Locks to those contained in lockerlist */
730 plocked = Locks;
731 Locks = nil;
732 while( plocked != nil) {
733 plocker = lockerlist;
734 while((plocker != nil) && ( strcmp(plocker->login, plocked->login)!=0))
735 plocker = plocker->lockerlink;
736 nextlocked = plocked->nextlock;
737 if ( plocker != nil) {
738 plocked->nextlock = Locks;
739 Locks = plocked;
741 plocked = nextlocked;
747 recentdate(root, pd)
748 struct hshentry * root;
749 struct Datepairs * pd;
750 /* function: Finds the delta that is closest to the cutoff date given by */
751 /* pd among the revisions selected by exttree. */
752 /* Successively narrows down the interfal given by pd, */
753 /* and sets the strtdate of pd to the date of the selected delta */
755 struct branchhead * newbranch;
757 if ( root == nil) return;
758 if ( root->selector == 's') {
759 if ( cmpnum(root->date, pd->strtdate) >= 0 &&
760 cmpnum(root->date, pd->enddate) <= 0)
761 VOID strcpy(pd->strtdate, root->date);
764 recentdate(root->next, pd);
765 newbranch = root->branches;
766 while( newbranch) {
767 recentdate(newbranch->hsh, pd);
768 newbranch = newbranch->nextbranch;
777 extdate(root)
778 struct hshentry * root;
779 /* function: select revisions which are in the date range specified */
780 /* in duelst and datelist, start at root */
783 struct branchhead * newbranch;
784 struct Datepairs * pdate;
786 if ( root == nil) return;
788 if ( datelist || duelst) {
789 pdate = datelist;
790 while( pdate ) {
791 if ( (pdate->strtdate)[0] == '\0' || cmpnum(root->date,pdate->strtdate) >= 0){
792 if ((pdate->enddate)[0] == '\0' || cmpnum(pdate->enddate,root->date) >= 0)
793 break;
795 pdate = pdate->dnext;
797 if ( pdate == nil) {
798 pdate = duelst;
799 while(pdate) {
800 if ( cmpnum(root->date, pdate->strtdate) == 0)
801 break;
802 pdate = pdate->dnext;
805 if ( pdate == nil)
806 root->selector = 'u';
808 if (root->selector == 's') revno++;
810 extdate(root->next);
812 newbranch = root->branches;
813 while( newbranch ) {
814 extdate(newbranch->hsh);
815 newbranch = newbranch->nextbranch;
821 extractdelta(pdelta)
822 struct hshentry * pdelta;
823 /* function: compare information of pdelta to the authorlst, lockerlist, */
824 /* statelist, revlist and mark 's' on selector if pdelta is */
825 /* selected; otherwise, mark 'u' */
828 struct lock * plock;
829 struct stateattri * pstate;
830 struct authors * pauthor;
831 struct Revpairs * prevision;
832 int length;
834 pdelta->selector = 's';
835 if ( authorlist ) { /* certain author's revisions wanted only */
836 pauthor = authorlist;
837 while((pauthor != nil) && ( strcmp(pauthor->login, pdelta->author)!=0))
838 pauthor = pauthor->nextauthor;
839 if ( pauthor == nil ) {
840 pdelta->selector = 'u';
841 return;
844 if ( statelist ) { /* revisions with certain state wanted */
845 pstate = statelist;
846 while((pstate != nil) && (strcmp(pstate->status, pdelta->state)!=0))
847 pstate = pstate->nextstate;
848 if ( pstate == nil ) {
849 pdelta->selector = 'u';
850 return;
853 if ( lockflag ) { /* locked revisions */
854 plock = Locks;
855 while( plock && (plock->delta != pdelta))
856 plock = plock->nextlock;
857 if (plock == nil ) {
858 pdelta->selector = 'u';
859 return;
862 if ( Revlst ) { /* revisions or branches selected */
864 prevision = Revlst;
865 while( prevision != nil ) {
866 length = prevision->numfld;
867 if ( length % 2 == 1) { /* a branch number */
868 if ( countnumflds(pdelta->num) ==(length+1))
869 if ( (compartial(pdelta->num, prevision->strtrev,length) >= 0)&&
870 (compartial(prevision->endrev, pdelta->num, length) >= 0) )
871 break;
873 else if ( countnumflds(pdelta->num ) == length) /* a revision */
874 if ( (compartial(pdelta->num, prevision->strtrev, length) >= 0) &&
875 (compartial(prevision->endrev, pdelta->num, length) >= 0) )
876 break;
877 prevision = prevision->rnext;
879 if (prevision == nil) {
880 pdelta->selector = 'u';
881 return;
888 char * procdate(target, source)
889 char * target, * source;
890 /* Function: Parses a free-format date in target, converts it
891 * into RCS internal format, and stores the result into source.
892 * Returns target on success, nil otherwise.
895 long unixtime;
896 struct tm parseddate, *ftm;
898 if ( partime(source, &parseddate) == 0) {
899 error("Can't parse date/time: %s", source);
900 *target= '\0';
901 return nil;
903 if ( (unixtime = maketime(&parseddate)) == 0L) {
904 error("Inconsistent date/time: %s", source);
905 *target='\0';
906 return nil;
908 ftm = localtime(&unixtime);
909 VOID sprintf(target,DATEFORM,
910 ftm->tm_year,ftm->tm_mon+1,ftm->tm_mday,ftm->tm_hour,ftm->tm_min,ftm->tm_sec);
911 return target;
916 getdatepair(argv)
917 char * argv;
918 /* function: get time range from command line and store in datelist if */
919 /* a time range specified or in duelst if a time spot specified */
922 register char c;
923 struct Datepairs * nextdate;
924 char * rawdate;
925 int switchflag;
927 argv--;
928 while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' ||
929 c == '\n' || c == ';') ;
930 if ( c == '\0' ) {
931 warn("Missing date/time after -d");
932 return;
935 while( c != '\0' ) {
936 switchflag = false;
937 nextdate = (struct Datepairs *) talloc(sizeof(struct Datepairs));
938 if ( c == '<' ) { /* case: -d <date */
939 c = *++argv;
940 (nextdate->strtdate)[0] = '\0';
941 } elsif (c == '>') { /* case: -d >date */
942 c = *++argv;
943 (nextdate->enddate)[0] = '\0';
944 switchflag = true;
945 } else {
946 rawdate = argv;
947 while( c != '<' && c != '>' && c != ';' && c != '\0')
948 c = *++argv;
949 *argv = '\0';
950 if ( c == '>' ) switchflag=true;
951 if (procdate(switchflag?nextdate->enddate:nextdate->strtdate,
952 rawdate)==nil) continue;
953 if ( c == ';' || c == '\0') { /* case: -d date */
954 VOID strcpy(nextdate->enddate,nextdate->strtdate);
955 VOID sprintf(nextdate->strtdate,DATEFORM,0,0,0,0,0,0);
956 nextdate->dnext = duelst;
957 duelst = nextdate;
958 goto end;
959 } else {
960 /* case: -d date< or -d date>; see switchflag */
961 while ( (c= *++argv) == ' ' || c=='\t' || c=='\n');
962 if ( c == ';' || c == '\0') {
963 /* second date missing */
964 if (switchflag)
965 *nextdate->strtdate= '\0';
966 else
967 *nextdate->enddate= '\0';
968 nextdate->dnext = datelist;
969 datelist = nextdate;
970 goto end;
974 rawdate = argv;
975 while( c != '>' && c != '<' && c != ';' && c != '\0')
976 c = *++argv;
977 *argv = '\0';
978 if (procdate(switchflag?nextdate->strtdate:nextdate->enddate,
979 rawdate)==nil) continue;
980 nextdate->dnext = datelist;
981 datelist = nextdate;
982 end:
984 VOID printf("startdate: %s; enddate: %s;\n", nextdate->strtdate,nextdate->enddate);
986 if ( c == '\0') return;
987 while( (c = *++argv) == ';' || c == ' ' || c == '\t' || c =='\n');
995 getnumericrev()
996 /* function: get the numeric name of revisions which stored in revlist */
997 /* and then stored the numeric names in Revlst */
998 /* if branchflag, also add default branch */
1001 struct Revpairs * ptr, *pt;
1002 int flag;
1003 char *temprev;
1005 /* free the previous numeric revision list */
1006 pt = Revlst;
1007 while( pt) {
1008 ptr = pt->rnext;
1009 free((char *)pt);
1010 pt = ptr;
1012 Nextdotstring = &Dotstring[0]; /* reset buffer */
1015 Revlst = nil;
1016 ptr = revlist;
1017 while( ptr ) {
1018 pt = (struct Revpairs *) talloc(sizeof(struct Revpairs));
1019 if ( ptr->numfld == 1 ){ /* case: -r rev */
1020 if ( (flag = expandsym(ptr->strtrev, Nextdotstring)) == true ) {
1021 pt->numfld = countnumflds(Nextdotstring);
1022 pt->strtrev = pt->endrev = Nextdotstring;
1023 while( *Nextdotstring++ != '\0' ) ;
1026 else if( ptr->numfld == 2){ /* case: -r rev- */
1027 if ( (flag = expandsym(ptr->strtrev, Nextdotstring)) == true) {
1028 pt->numfld = countnumflds(Nextdotstring);
1029 pt->strtrev = Nextdotstring;
1030 while( *Nextdotstring++ != '\0' ) ;
1031 pt->endrev = Nextdotstring;
1032 if ( pt->numfld > 2) choptail(pt->strtrev);
1033 * Nextdotstring++ = '\0';
1036 else if(ptr->numfld == 3) { /* case: -r -rev */
1037 if ( (flag = expandsym(ptr->endrev, Nextdotstring)) == true) {
1038 pt->endrev = Nextdotstring;
1039 while( *Nextdotstring++ != '\0' ) ;
1040 pt->numfld = countnumflds(pt->endrev);
1041 pt->strtrev = Nextdotstring;
1042 if ( pt->numfld == 2)
1043 *Nextdotstring++ = '1';
1044 else
1045 choptail(pt->endrev);
1046 *Nextdotstring++ = '.';
1047 *Nextdotstring++ = '1';
1048 *Nextdotstring++ = '\0';
1051 else { /* case: -r rev1-rev2 */
1052 if ( (flag = expandsym(ptr->strtrev, Nextdotstring)) == true ) {
1053 pt->strtrev = Nextdotstring;
1054 while( *Nextdotstring++ != '\0' ) ;
1055 if ( ( flag = expandsym(ptr->endrev, Nextdotstring)) == true) {
1056 pt->numfld = countnumflds(pt->strtrev);
1057 pt->endrev = Nextdotstring;
1058 while( *Nextdotstring++ != '\0' ) ;
1059 if((flag = checkrevpair(pt->strtrev, pt->endrev)) == true)
1060 /* switch pt->strtrev with pt->endrev, if pt->strtrev > pt->endre */
1061 if (compartial(pt->strtrev, pt->endrev, pt->numfld) > 0 ) {
1062 temprev = pt->strtrev;
1063 pt->strtrev = pt->endrev;
1064 pt->endrev = temprev;
1070 if ( flag ){
1071 pt->rnext = Revlst;
1072 Revlst = pt;
1074 else
1075 free((char *)pt);
1076 ptr = ptr->rnext;
1078 /* Now take care of branchflag */
1079 if (branchflag) {
1080 flag =true;
1081 pt = (struct Revpairs *) talloc(sizeof(struct Revpairs));
1082 if (Dbranch) {
1083 pt->strtrev = pt->endrev = Dbranch->num;
1084 } elsif (Head!=nil) {
1085 pt->strtrev = pt->endrev = /* branch number of head */
1086 partialno(Nextdotstring,Head->num,1);
1087 while( *Nextdotstring++ != '\0' ) ;
1088 } else flag = false;
1089 if (flag) { /* prepend new node */
1090 pt->rnext=Revlst; Revlst=pt;
1091 pt->numfld = countnumflds(pt->strtrev);
1099 checkrevpair(num1,num2)
1100 char *num1, *num2;
1101 /* function: check whether num1, num2 are legal pair,i.e.
1102 only the last field are different and have same number of
1103 feilds( if length <= 2, may be different if first field) */
1106 int length;
1108 if ( (length = countnumflds(num1)) != countnumflds(num2) ) {
1109 error(" Invalid branch or revision pair %s : %s", num1, num2);
1110 return false;
1112 if ( length > 2 )
1113 if (compartial(num1, num2, length-1) != 0) {
1114 error("Invalid branch or revision pair %s : %s", num1, num2);
1115 return false;
1118 return true;
1123 getrevpairs(argv)
1124 register char * argv;
1125 /* function: get revision or branch range from command line, and */
1126 /* store in revlist */
1129 register char c;
1130 struct Revpairs * nextrevpair;
1131 int flag;
1133 argv--;
1134 while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' ||
1135 c == '\n' || c == ';') ;
1136 if ( c == '\0' ) {
1137 warn(" Missing revision or branch number after -r");
1138 return;
1141 while( c != '\0') {
1142 while( c == ',' || c == ' ' || c == '\t' ||
1143 c == '\n' || c == ';') c = *++argv;
1144 if (c == '\0') return;
1145 nextrevpair = (struct Revpairs *) talloc(sizeof(struct Revpairs));
1146 nextrevpair->rnext = revlist;
1147 revlist = nextrevpair;
1148 nextrevpair->numfld = nil;
1149 nextrevpair->strtrev = nil;
1150 nextrevpair->endrev = nil;
1151 flag = false;
1152 if ( c == '<' || c == '-' ) { /* case: -r -rev or -r <rev */
1153 flag = true;
1154 while( (c =(*++argv)) == ' ' || c == '\t' || c =='\n') ;
1156 else {
1157 nextrevpair->strtrev = argv;
1158 /* get a revision or branch name */
1159 while( c != ',' && c != ';' && c != ' ' && c != '\0' && c != '-'
1160 && c != '\t' && c != '\n' && c != '<') c = *++argv;
1162 *argv = '\0';
1164 if ( c != '<' && c != '-') { /* case: rev */
1165 nextrevpair->numfld = 1;
1166 continue;
1169 if ( (c =(*++argv)) == ',' || c == '\0' || c == ' '
1170 || c == '\t' || c == '\n' || c == ';') {/* case: rev_ */
1171 nextrevpair->numfld = 2;
1172 continue;
1175 nextrevpair->endrev = argv;
1176 while( c != ',' && c != ' ' && c != '\0' && c != '\t' && c != '<'
1177 && c != '\n' && c != '-' && c != ';') c = *++argv;
1179 * argv = '\0';
1180 if ( c == '<'){
1181 error("separator expected near %s", nextrevpair->endrev);
1182 while( (c = *++argv) != ',' && c != ' ' && c != '\0' &&
1183 c != '\t' && c != '\n' && c != ';' ) ;
1184 revlist = nextrevpair->rnext;
1185 continue;
1187 else {
1188 if (flag) /* case: -rev */
1189 nextrevpair->numfld = 3;
1191 else /* rev1-rev2 appears */
1192 nextrevpair->numfld = 4;
1199 choptail(strhead)
1200 char * strhead;
1201 /* function : chop off the last field of a branch or a revision number */
1204 char *pt, *sp;
1206 for(pt = Nextdotstring-1; pt != strhead && *pt != '.'; pt--) ;
1207 for(sp = strhead; sp < pt; sp++) *Nextdotstring++ = *sp;