|
|
1.1 root 1: /*
2: * RLOG operation
3: */
4: #ifndef lint
5: static char rcsid[]=
6: "$Header: /usr/src/local/bin/rcs/src/RCS/rlog.c,v 4.7 89/05/01 15:13:48 narten Exp $ Purdue CS";
7: #endif
8: /*****************************************************************************
9: * print contents of RCS files
10: *****************************************************************************
11: */
12:
13: /* Copyright (C) 1982, 1988, 1989 Walter Tichy
14: * All rights reserved.
15: *
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.
25: *
26: * Report all problems and direct all questions to:
27: * [email protected]
28: *
29:
30:
31:
32:
33:
34:
35:
36: */
37:
38:
39:
40:
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
44: *
45: * Revision 4.6 88/11/08 11:59:40 narten
46: * changes from [email protected] (Paul Eggert)
47: *
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.
51: *
52: * Revision 4.5 87/12/18 11:46:38 narten
53: * more lint cleanups (Guy Harris)
54: *
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
58: *
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)
62: *
63: * Revision 1.2 87/03/27 14:22:45 jenkins
64: * Port to suns
65: *
66: * Revision 1.1 84/01/23 14:50:45 kcs
67: * Initial revision
68: *
69: * Revision 4.2 83/12/05 09:18:09 wft
70: * changed rewriteflag to external.
71: *
72: * Revision 4.1 83/05/11 16:16:55 wft
73: * Added -b, updated getnumericrev() accordingly.
74: * Replaced getpwuid() with getcaller().
75: *
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()).
80: *
81: * Revision 3.6 82/12/24 15:57:53 wft
82: * shortened output format.
83: *
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.
87: *
88: * Revision 3.4 82/12/04 13:26:25 wft
89: * Replaced getdelta() with gettree(); removed updating of field lockedby.
90: *
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.
95: *
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.
100: *
101: * Revision 3.1 82/10/13 16:07:56 wft
102: * fixed type of variables receiving from getc() (char -> int).
103: */
104:
105:
106:
107: #include "time.h"
108: #include "rcsbase.h"
109: #ifndef lint
110: static char rcsbaseid[] = RCSBASE;
111: #endif
112:
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 */
132:
133: char * RCSfilename, * workfilename;
134:
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 */
144:
145: struct lockers { /* lockers in locker option; stored */
146: char * login; /* lockerlist */
147: struct lockers * lockerlink;
148: } ;
149:
150: struct stateattri { /* states in state option; stored in */
151: char * status; /* statelist */
152: struct stateattri * nextstate;
153: } ;
154:
155: struct authors { /* login names in author option; */
156: char * login; /* stored in authorlist */
157: struct authors * nextauthor;
158: } ;
159:
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;
165: } ;
166:
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;
171: };
172:
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;
181:
182:
183:
184: main (argc, argv)
185: int argc;
186: char * argv[];
187: {
188: struct Datepairs * currdate;
189: struct assoc * curassoc;
190: struct access * curaccess;
191: struct lock * currlock;
192: char * cmdusage;
193:
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();
206:
207: while (--argc,++argv, argc>=1 && ((*argv)[0] == '-')) {
208: switch ((*argv)[1]) {
209:
210: case 'L':
211: onlylockflag = true;
212: break;
213:
214: case 'R':
215: onlyRCSflag =true;
216: break;
217:
218: case 'l':
219: selectop = true;
220: lockflag = true;
221: getlocker( (*argv)+2 );
222: break;
223:
224: case 'b':
225: selectop = true;
226: branchflag = true;
227: break;
228:
229: case 'r':
230: selectop = true;
231: getrevpairs( (*argv)+2 );
232: break;
233:
234: case 'd':
235: selectop = true;
236: getdatepair( (*argv)+2 );
237: break;
238:
239: case 's':
240: selectop = true;
241: getstate( (*argv)+2);
242: break;
243:
244: case 'w':
245: selectop = true;
246: getauthor( (*argv)+2);
247: break;
248:
249: case 'h':
250: if ( ! selectflag ) warn("option -t overrides -h");
251: else descflag = false;
252: break;
253:
254: case 't':
255: selectflag = false;
256: if ( ! descflag ) warn("option -t overrides -h");
257: descflag = true;
258: break;
259:
260: default:
261: faterror("unknown option: %s\n%s", *argv,cmdusage);
262:
263: };
264: } /* end of option processing */
265:
266: if (argc<1) faterror("No input file\n%s",cmdusage);
267:
268:
269: /* now handle all filenames */
270: do {
271: rewriteflag=false;
272: finptr=frewrite=nil;
273:
274:
275: if (!pairfilenames(argc, argv, true,false)) continue;
276:
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.
280: */
281:
282: if ( !trysema(RCSfilename, false)) goto loopend; /* give up */
283:
284: /* do nothing if -L is given and there are no locks*/
285: if ( onlylockflag && Locks == nil ) goto loopend;
286:
287: if ( onlyRCSflag ) {
288: VOID fprintf(stdout, "%s\n", RCSfilename);
289: goto loopend;
290: }
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);
298:
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;
305: }
306: if ( StrictLocks )
307: VOID fputs(Locks==nil?" ; strict":" strict",stdout);
308:
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;
315: }
316:
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;
323: }
324:
325: VOID fprintf(stdout,"\ncomment leader: \"%s\"\n",Comment);
326:
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;
335: }
336:
337:
338: /* keep only those locks given by -l */
339: if (lockflag)
340: trunclocks();
341: getnumericrev(); /* get numeric revision or branch names */
342: revno = 0;
343:
344: exttree(Head);
345:
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;
351: }
352:
353: extdate(Head);
354:
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;
360: }
361:
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");
373: }
374: VOID fputs("=============================================================================\n",stdout);
375: loopend:
376: VOID fclose(finptr);
377: } while( ++argv, --argc >= 1);
378: exit(nerror!=0);
379: }
380:
381:
382:
383: putrunk()
384: /* function: print revisions chosen, which are in trunk */
385:
386: {
387: struct hshentry * ptr, * pre;
388:
389: if (Head == nil) return; /* empty tree */
390:
391: pre = Head;
392: ptr = Head->next;
393: while( ptr ) {
394: putadelta(pre,ptr,true);
395: pre = ptr;
396: ptr = ptr->next;
397: }
398: putadelta(pre,ptr,true);
399: }
400:
401:
402:
403: putree(root)
404: struct hshentry *root;
405: /* function: print delta tree( not include trunck) in reversed calender
406: order on each branch */
407:
408: {
409: if ( root == nil ) return;
410:
411: putree(root->next);
412:
413: putforest(root->branches);
414: }
415:
416:
417:
418:
419: putforest(branchroot)
420: struct branchhead * branchroot;
421: /* function: print branches that has the same direct ancestor */
422: {
423:
424: if ( branchroot == nil ) return;
425:
426: putforest(branchroot->nextbranch);
427:
428: putabranch(branchroot->hsh);
429: putree(branchroot->hsh);
430: }
431:
432:
433:
434:
435: putabranch(root)
436: struct hshentry *root;
437: /* function : print one branch */
438:
439: {
440:
441: if ( root == nil) return;
442:
443: putabranch(root->next);
444:
445: putadelta(root, root, false);
446: }
447:
448:
449:
450:
451:
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 */
459: {
460: struct branchhead * newbranch;
461: char * branchnum, branch[40];
462:
463: if ( ( node == nil) || ( node->selector == 'u'))
464: return;
465:
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);
471:
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);
477:
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);
485:
486: VOID putc('\n', stdout);
487:
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;
496: }
497: VOID putc('\n', stdout);
498: }
499:
500: VOID fputs(node->log,stdout);
501: }
502:
503:
504:
505:
506:
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.
512: */
513: {
514: register struct hshentry * Delta;
515:
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;
531: }
532:
533:
534:
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 */
539:
540: {
541: int ed; /* editor command */
542: register FILE * fin;
543: register int c;
544: register int i;
545: int length;
546:
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;
557: }
558: while( '0' <= (c = getc(fin)) && c <= '9' ) ;
559:
560: while( c == ' ')c = getc(fin); /* skip blanks */
561: if ( !('0' <= c && c <= '9' ) ) {
562: faterror("Incorrect range in edit script");
563: break;
564: }
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;
573:
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++;
579: }
580: break;
581:
582: default:
583: faterror("Unknown command in edit script: %c", ed);
584: break;
585: }
586: }
587: nextc = getc(fin);
588: }
589:
590:
591:
592:
593:
594:
595:
596: exttree(root)
597: struct hshentry *root;
598: /* function: select revisions , starting with root */
599:
600: {
601: struct branchhead * newbranch;
602:
603: if (root == nil) return;
604:
605: extractdelta(root);
606: exttree(root->next);
607:
608: newbranch = root->branches;
609: while( newbranch ) {
610: exttree(newbranch->hsh);
611: newbranch = newbranch->nextbranch;
612: }
613: }
614:
615:
616:
617:
618: getlocker(argv)
619: char * argv;
620: /* function : get the login names of lockers from command line */
621: /* and store in lockerlist. */
622:
623: {
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;
632: }
633:
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 == ';') ;
645: }
646: }
647:
648:
649:
650: getauthor(argv)
651: char *argv;
652: /* function: get the author's name form command line */
653: /* and store in aauthorlist */
654:
655: {
656: register c;
657: struct authors * newauthor;
658:
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;
667: }
668:
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 == ';') ;
680: }
681: }
682:
683:
684:
685:
686: getstate(argv)
687: char * argv;
688: /* function : get the states of revisions from command line */
689: /* and store in statelist */
690:
691: {
692: register char c;
693: struct stateattri *newstate;
694:
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;
701: }
702:
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 == ';') ;
714: }
715: }
716:
717:
718:
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. */
722:
723: {
724: struct lockers * plocker;
725: struct lock * plocked, * nextlocked;
726:
727: if ( (lockerlist == nil) || (Locks == nil)) return;
728:
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;
740: }
741: plocked = nextlocked;
742: }
743: }
744:
745:
746:
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 */
754: {
755: struct branchhead * newbranch;
756:
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);
762: }
763:
764: recentdate(root->next, pd);
765: newbranch = root->branches;
766: while( newbranch) {
767: recentdate(newbranch->hsh, pd);
768: newbranch = newbranch->nextbranch;
769: }
770: }
771:
772:
773:
774:
775:
776:
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 */
781:
782: {
783: struct branchhead * newbranch;
784: struct Datepairs * pdate;
785:
786: if ( root == nil) return;
787:
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;
794: }
795: pdate = pdate->dnext;
796: }
797: if ( pdate == nil) {
798: pdate = duelst;
799: while(pdate) {
800: if ( cmpnum(root->date, pdate->strtdate) == 0)
801: break;
802: pdate = pdate->dnext;
803: }
804: }
805: if ( pdate == nil)
806: root->selector = 'u';
807: }
808: if (root->selector == 's') revno++;
809:
810: extdate(root->next);
811:
812: newbranch = root->branches;
813: while( newbranch ) {
814: extdate(newbranch->hsh);
815: newbranch = newbranch->nextbranch;
816: }
817: }
818:
819:
820:
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' */
826:
827: {
828: struct lock * plock;
829: struct stateattri * pstate;
830: struct authors * pauthor;
831: struct Revpairs * prevision;
832: int length;
833:
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;
842: }
843: }
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;
851: }
852: }
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;
860: }
861: }
862: if ( Revlst ) { /* revisions or branches selected */
863:
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;
872: }
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;
878: }
879: if (prevision == nil) {
880: pdelta->selector = 'u';
881: return;
882: }
883: }
884: }
885:
886:
887:
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.
893: */
894: {
895: long unixtime;
896: struct tm parseddate, *ftm;
897:
898: if ( partime(source, &parseddate) == 0) {
899: error("Can't parse date/time: %s", source);
900: *target= '\0';
901: return nil;
902: }
903: if ( (unixtime = maketime(&parseddate)) == 0L) {
904: error("Inconsistent date/time: %s", source);
905: *target='\0';
906: return nil;
907: }
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;
912: }
913:
914:
915:
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 */
920:
921: {
922: register char c;
923: struct Datepairs * nextdate;
924: char * rawdate;
925: int switchflag;
926:
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;
933: }
934:
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;
971: }
972: }
973: }
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:
983: /*
984: VOID printf("startdate: %s; enddate: %s;\n", nextdate->strtdate,nextdate->enddate);
985: */
986: if ( c == '\0') return;
987: while( (c = *++argv) == ';' || c == ' ' || c == '\t' || c =='\n');
988: }
989: }
990:
991:
992:
993:
994:
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 */
999:
1000: {
1001: struct Revpairs * ptr, *pt;
1002: int flag;
1003: char *temprev;
1004:
1005: /* free the previous numeric revision list */
1006: pt = Revlst;
1007: while( pt) {
1008: ptr = pt->rnext;
1009: free((char *)pt);
1010: pt = ptr;
1011: }
1012: Nextdotstring = &Dotstring[0]; /* reset buffer */
1013:
1014:
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' ) ;
1024: }
1025: }
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';
1034: }
1035: }
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';
1049: }
1050: }
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;
1065: }
1066: }
1067: }
1068: }
1069:
1070: if ( flag ){
1071: pt->rnext = Revlst;
1072: Revlst = pt;
1073: }
1074: else
1075: free((char *)pt);
1076: ptr = ptr->rnext;
1077: }
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);
1092: }
1093: }
1094:
1095: }
1096:
1097:
1098:
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) */
1104:
1105: {
1106: int length;
1107:
1108: if ( (length = countnumflds(num1)) != countnumflds(num2) ) {
1109: error(" Invalid branch or revision pair %s : %s", num1, num2);
1110: return false;
1111: }
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;
1116: }
1117:
1118: return true;
1119: }
1120:
1121:
1122:
1123: getrevpairs(argv)
1124: register char * argv;
1125: /* function: get revision or branch range from command line, and */
1126: /* store in revlist */
1127:
1128: {
1129: register char c;
1130: struct Revpairs * nextrevpair;
1131: int flag;
1132:
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;
1139: }
1140:
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') ;
1155: }
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;
1161:
1162: *argv = '\0';
1163:
1164: if ( c != '<' && c != '-') { /* case: rev */
1165: nextrevpair->numfld = 1;
1166: continue;
1167: }
1168:
1169: if ( (c =(*++argv)) == ',' || c == '\0' || c == ' '
1170: || c == '\t' || c == '\n' || c == ';') {/* case: rev_ */
1171: nextrevpair->numfld = 2;
1172: continue;
1173: }
1174: }
1175: nextrevpair->endrev = argv;
1176: while( c != ',' && c != ' ' && c != '\0' && c != '\t' && c != '<'
1177: && c != '\n' && c != '-' && c != ';') c = *++argv;
1178:
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;
1186: }
1187: else {
1188: if (flag) /* case: -rev */
1189: nextrevpair->numfld = 3;
1190:
1191: else /* rev1-rev2 appears */
1192: nextrevpair->numfld = 4;
1193: }
1194: }
1195: }
1196:
1197:
1198:
1199: choptail(strhead)
1200: char * strhead;
1201: /* function : chop off the last field of a branch or a revision number */
1202:
1203: {
1204: char *pt, *sp;
1205:
1206: for(pt = Nextdotstring-1; pt != strhead && *pt != '.'; pt--) ;
1207: for(sp = strhead; sp < pt; sp++) *Nextdotstring++ = *sp;
1208: }
1209:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.