/* * RLOG operation */ static char rcsid[]= "$Header: /usr/wft/RCS/SRC/RCS/rlog.c,v 3.7 83/05/11 14:24:13 wft Exp $ Purdue CS"; /***************************************************************************** * print contents of RCS files ***************************************************************************** * * Copyright (C) 1982 by Walter Tichy * Purdue University * Computer Science Department * West Lafayette, IN 47907 * * All rights reserved. No part of this software may be sold or distributed * in any form or by any means without the prior written permission of the * author. * Report problems and direct all inquiries to Tichy@purdue (ARPA net). */ /* $Log: rlog.c,v $ * Revision 3.7 83/05/11 14:24:13 wft * Added options -L and -R; * Fixed selection bug with -l on multiple files. * Fixed error on dates of the form -d'>date' (rewrote getdatepair()). * * Revision 3.6 82/12/24 15:57:53 wft * shortened output format. * * Revision 3.5 82/12/08 21:45:26 wft * removed call to checkaccesslist(); used DATEFORM to format all dates; * removed unused variables. * * Revision 3.4 82/12/04 13:26:25 wft * Replaced getdelta() with gettree(); removed updating of field lockedby. * * Revision 3.3 82/12/03 14:08:20 wft * Replaced getlogin with getpwuid(), %02d with %.2d, fancydate with PRINTDATE. * Fixed printing of nil, removed printing of Suffix, * added shortcut if no revisions are printed, disambiguated struct members. * * Revision 3.2 82/10/18 21:09:06 wft * call to curdir replaced with getfullRCSname(), * fixed call to getlogin(), cosmetic changes on output, * changed conflicting long identifiers. * * Revision 3.1 82/10/13 16:07:56 wft * fixed type of variables receiving from getc() (char -> int). */ #include #include "time.h" #include "rcsbase.h" static char rcsbaseid[] = RCSBASE; extern FILE * fopen(); extern struct passwd *getpwuid(); extern char * malloc(); extern free(); extern struct hshentry * genrevs(); /*generate delta numbers */ extern int countnumflds(); extern int compartial(); extern char * partialno(); extern int expandsym(); /*get numeric name of a revision */ extern char * getfullRCSname(); /*get full path name of RCS file */ extern int nextc; /*next input character */ extern char * Klog; extern char * Ktext; extern int partime(); extern long maketime(); /*convert parsed time to unix time. */ extern struct tm * localtime(); /*convert unixtime into a tm-structure */ extern int pairfilenames(); extern struct hshentry * getnum(); extern FILE * finptr; /* RCS input file */ extern FILE * frewrite; /* new RCS file */ extern int nerror; /* error counter */ char * RCSfilename, * workfilename; int rewriteflag; /* indicates whether input should be echoed to frewrite */ char * caller; /* caller's login; */ char numericrev[revlength]; /* holds expanded revision number */ struct hshentry * gendeltas[hshsize]; /* stores deltas to be generated */ struct hshentry * targetdelta; /* final delta to be generated */ int descflag, selectflag, selectop; /* option to print access list, symbolic */ /* names, descriptive text, locks and */ /* Head */ int onlylockflag; /* option to print only files */ /* with locks */ int onlyRCSflag; /* option to print only RCS file name */ int lockflag; /* whether locker option is set */ int revno; /* number of revision chosen */ struct lockers { /* lockers in locker option; stored */ char * login; /* lockerlist */ struct lockers * lockerlink; } ; struct stateattri { /* states in state option; stored in */ char * status; /* statelist */ struct stateattri * nextstate; } ; struct authors { /* login names in author option; */ char * login; /* stored in authorlist */ struct authors * nextauthor; } ; struct Revpairs{ /* revision or branch range in -r */ int numfld; /* option; stored in revlist */ char * strtrev; char * endrev; struct Revpairs * rnext; } ; struct Datepairs{ /* date range in -d option; stored in */ char strtdate[datelength]; /* duelst and datelist */ char enddate[datelength]; struct Datepairs * dnext; }; char Dotstring[200]; /* string of numeric revision name */ char * Nextdotstring; /* next available place of Dotstring */ struct Datepairs * datelist, * duelst; struct Revpairs * revlist, * Revlst; struct lockers * lockerlist; struct stateattri * statelist; struct authors * authorlist; main (argc, argv) int argc; char * argv[]; { struct Datepairs * currdate; struct assoc * curassoc; struct access * curaccess; struct lock * currlock; char * cmdusage; cmdusage = "command format:\nrlog -L -R -h -t -ddates -l[lockers] -rrevisions -sstates -w[logins] file ..."; cmdid = "rlog"; descflag = selectflag = true; lockflag = onlylockflag = selectop = false; onlyRCSflag = false; lockerlist = nil; authorlist = nil; statelist = nil; Revlst = revlist = nil; duelst = datelist = nil; caller=getpwuid(getuid())->pw_name; while (--argc,++argv, argc>=1 && ((*argv)[0] == '-')) { switch ((*argv)[1]) { case 'L': onlylockflag = true; break; case 'R': onlyRCSflag =true; break; case 'l': selectop = true; lockflag = true; getlocker( (*argv)+2 ); break; case 'r': selectop = true; getrevpairs( (*argv)+2 ); break; case 'd': selectop = true; getdatepair( (*argv)+2 ); break; case 's': selectop = true; getstate( (*argv)+2); break; case 'w': selectop = true; getauthor( (*argv)+2); break; case 'h': if ( ! selectflag ) warn("option -t overrides -h"); else descflag = false; break; case 't': selectflag = false; if ( ! descflag ) warn("option -t overrides -h"); descflag = true; break; default: faterror("unknown option: %s\n%s", *argv,cmdusage); }; } /* end of option processing */ if (argc<1) faterror("No input file\n%s",cmdusage); /* now handle all filenames */ do { rewriteflag=false; finptr=frewrite=nil; if (!pairfilenames(argc, argv, true,false)) continue; /* now RCSfilename contains the name of the RCS file, and finptr * the file descriptor. Workfilename contains the name of the * working file. */ if ( !trysema(RCSfilename, false)) goto loopend; /* give up */ /* do nothing if -L is given and there are no locks*/ if ( onlylockflag && Locks == nil ) goto loopend; if ( onlyRCSflag ) { fprintf(stdout, "%s\n", RCSfilename); goto loopend; } /* print RCS filename , working filename and optional administrative information */ fprintf(stdout, "\nRCS file: %s; ",RCSfilename); /* could use getfullRCSname() here, but that is very slow */ fprintf(stdout, "Working file: %s\n", workfilename); fprintf(stdout, "head: %s\n", Head==nil?"":Head->num); fputs("locks: ", stdout); /* print locker list */ currlock = Locks; while( currlock ) { fprintf(stdout," %s: %s;", currlock->login, currlock->delta->num); currlock = currlock->nextlock; } if ( StrictLocks ) fputs(Locks==nil?" ; strict":" strict",stdout); fputs("\naccess list: ", stdout); /* print access list */ curaccess = AccessList; while(curaccess) { fputs(" ",stdout); fputs(curaccess->login, stdout); curaccess = curaccess->nextaccess; } fputs("\nsymbolic names:", stdout); /* print symbolic names */ curassoc = Symbols; while( curassoc ) { fprintf(stdout, " %s: %s;",curassoc->symbol, curassoc->delta->num); curassoc = curassoc->nextassoc; } fprintf(stdout,"\ncomment leader: \"%s\"\n",Comment); gettree(); fprintf(stdout, "total revisions: %d; ", TotalDeltas); if ( Head == nil || !selectflag || !descflag) { putc('\n',stdout); if (descflag) fputs("description:\n", stdout); getdesc(descflag); fputs("=============================================================================\n",stdout); goto loopend; } /* keep only those locks given by -l */ if (lockflag) trunclocks(); getnumericrev(); /* get numeric revision or branch names */ revno = 0; exttree(Head); /* get most recently date of the dates pointed by duelst */ currdate = duelst; while( currdate) { recentdate(Head, currdate); currdate = currdate->dnext; } extdate(Head); /* reinitialize the date specification list */ currdate = duelst; while(currdate) { sprintf(currdate->strtdate,DATEFORM,0,0,0,0,0,0); currdate = currdate->dnext; } if ( selectop || ( selectflag && descflag) ) fprintf(stdout, "selected revisions: %d", revno); putc('\n', stdout); if (descflag) fputs("description:\n", stdout); getdesc(descflag); while( (nexttok != EOFILE) && readdeltalog()); if (selectflag && descflag && revno) { putrunk(); putree(Head); if (nextlex(), nexttok != EOFILE) fatserror("syntax error; expecting EOF"); } fputs("=============================================================================\n",stdout); loopend: fclose(finptr); } while( ++argv, --argc >= 1); exit(nerror!=0); } putrunk() /* function: print revisions chosen, which are in trunk */ { struct hshentry * ptr, * pre; if (Head == nil) return; /* empty tree */ pre = Head; ptr = Head->next; while( ptr ) { putadelta(pre,ptr,true); pre = ptr; ptr = ptr->next; } putadelta(pre,ptr,true); } putree(root) struct hshentry *root; /* function: print delta tree( not include trunck) in reversed calender order on each branch */ { if ( root == nil ) return; putree(root->next); putforest(root->branches); } putforest(branchroot) struct branchhead * branchroot; /* function: print branches that has the same direct ancestor */ { if ( branchroot == nil ) return; putforest(branchroot->nextbranch); putabranch(branchroot->hsh); putree(branchroot->hsh); } putabranch(root) struct hshentry *root; /* function : print one branch */ { if ( root == nil) return; putabranch(root->next); putadelta(root, root, false); } putadelta(node,editscript,trunk) register struct hshentry * node; register struct hshentry * editscript; int trunk; /* function: print delta node if node->selector is 's'. */ /* editscript indicates where the editscript is stored */ /* trunk indicated whether this node is in trunk */ { struct branchhead * newbranch; char * branchnum, branch[40]; if ( ( node == nil) || ( node->selector == 'u')) return; fprintf(stdout,"----------------------------\n"); fprintf(stdout, "revision %s ",node->num); if ( node->lockedby ) fprintf(stdout, "locked by: %s; ", node->lockedby); putc('\n', stdout); fputs("date: ",stdout); PRINTDATE(stdout,node->date); putc(' ',stdout); PRINTTIME(stdout,node->date); fprintf(stdout, "; author: %s; ", node->author); fprintf(stdout, "state: %s; ", node->state); if ( editscript ) if(trunk) fprintf(stdout,"lines added/del: %d/%d", editscript->deletelns, editscript->insertlns); else fprintf(stdout,"lines added/del: %d/%d", editscript->insertlns, editscript->deletelns); putc('\n', stdout); branchnum = & (branch[0]); newbranch = node->branches; if ( newbranch ) { fputs("branches: ", stdout); while( newbranch ) { getbranchno(newbranch->hsh->num, branchnum); fprintf(stdout, "%s; ", branchnum); newbranch = newbranch->nextbranch; } putc('\n', stdout); } fputs(node->log,stdout); } readdeltalog() /* Function : get the log message and skip the text of a deltatext node. * Return false if current block does not start with a number. * Assumes the current lexeme is not yet in nexttok; does not * advance nexttok. */ { register struct hshentry * Delta; nextlex(); if ( !(Delta = getnum() )) return(false); if ( ! getkey(Klog) || ( nexttok != STRING ) ) fatserror("Missing log entry"); Delta->log = malloc(logsize); savestring(Delta->log, logsize); nextlex(); if ( ! getkey(Ktext) || (nexttok != STRING) ) fatserror("Missing delta text"); Delta->insertlns = Delta->deletelns = 0; if ( Delta != Head) getscript(Delta); else readstring(); return true; } getscript(Delta) struct hshentry * Delta; /* function: read edit script of Delta and count how many lines added */ /* and deleted in the script */ { int ed; /* editor command */ register int c; register int i; int length; while( (ed = getc(finptr)) != EOF) { /* assume first none white character is command name */ while( ed == '\n' || ed == ' ' || ed == '\t') ed = getc(finptr); if (ed == SDELIM) break; /* script text is ended */ while( ( c = getc(finptr)) == ' ' ); /* skip blank */ if ( ! ('0' <= c && c <= '9')) { faterror("Missing line number in edit script"); break; } while( '0' <= (c = getc(finptr)) && c <= '9' ) ; while( c == ' ')c = getc(finptr); /* skip blanks */ if ( !('0' <= c && c <= '9' ) ) { faterror("Incorrect range in edit script"); break; } length = c - '0'; while( '0' <= (c = getc(finptr)) && c <= '9' ) length = length * 10 + c - '0'; while( c != '\n' && c != EOF) c = getc(finptr); switch (ed) { case 'd' : Delta->deletelns += length; break; case 'a' : /* skip scripted lines */ for ( i=length; i > 0 && c != EOF; i--){ while( (c=getc(finptr)) != '\n' && c != EOF); Delta->insertlns++; } break; default: faterror("Unknown command in edit script: %c", ed); break; } } nextc = getc(finptr); } exttree(root) struct hshentry *root; /* function: select revisions , starting with root */ { struct branchhead * newbranch; if (root == nil) return; extractdelta(root); exttree(root->next); newbranch = root->branches; while( newbranch ) { exttree(newbranch->hsh); newbranch = newbranch->nextbranch; } } getlocker(argv) char * argv; /* function : get the login names of lockers from command line */ /* and store in lockerlist. */ { register char c; struct lockers * newlocker; argv--; while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' || c == '\n' || c == ';') ; if ( c == '\0') { lockerlist=nil; return; } while( c != '\0' ) { newlocker = ( struct lockers *)malloc( sizeof(struct lockers) ); newlocker->lockerlink = lockerlist; newlocker->login = argv; lockerlist = newlocker; while ( ( c = (*++argv)) != ',' && c != '\0' && c != ' ' && c != '\t' && c != '\n' && c != ';') ; *argv = '\0'; if ( c == '\0' ) return; while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' || c == '\n' || c == ';') ; } } getauthor(argv) char *argv; /* function: get the author's name form command line */ /* and store in aauthorlist */ { register c; struct authors * newauthor; argv--; while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' || c == '\n' || c == ';') ; if ( c == '\0' ) { authorlist = (struct authors *)malloc(sizeof(struct authors)); authorlist->login = caller; authorlist->nextauthor = nil; return; } while( c != '\0' ) { newauthor = (struct authors *)malloc(sizeof(struct authors)); newauthor->nextauthor = authorlist; newauthor->login = argv; authorlist = newauthor; while( ( c = *++argv) != ',' && c != '\0' && c != ' ' && c != '\t' && c != '\n' && c != ';') ; * argv = '\0'; if ( c == '\0') return; while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' || c == '\n' || c == ';') ; } } getstate(argv) char * argv; /* function : get the states of revisions from command line */ /* and store in statelist */ { register char c; struct stateattri *newstate; argv--; while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' || c == '\n' || c == ';') ; if ( c == '\0'){ warn(" Missing state attributes after -s options"); return; } while( c != '\0' ) { newstate = (struct stateattri *)malloc(sizeof(struct stateattri)); newstate->nextstate = statelist; newstate->status = argv; statelist = newstate; while( (c = (*++argv)) != ',' && c != '\0' && c != ' ' && c != '\t' && c != '\n' && c != ';') ; *argv = '\0'; if ( c == '\0' ) return; while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' || c == '\n' || c == ';') ; } } trunclocks() /* Function: Truncate the list of locks to those that are held by the */ /* id's on lockerlist. Do not truncate if lockerlist empty. */ { struct lockers * plocker; struct lock * plocked, * nextlocked; if ( (lockerlist == nil) || (Locks == nil)) return; /* shorten Locks to those contained in lockerlist */ plocked = Locks; Locks = nil; while( plocked != nil) { plocker = lockerlist; while((plocker != nil) && ( strcmp(plocker->login, plocked->login)!=0)) plocker = plocker->lockerlink; nextlocked = plocked->nextlock; if ( plocker != nil) { plocked->nextlock = Locks; Locks = plocked; } plocked = nextlocked; } } recentdate(root, pd) struct hshentry * root; struct Datepairs * pd; /* function: Finds the delta that is closest to the cutoff date given by */ /* pd among the revisions selected by exttree. */ /* Successively narrows down the interfal given by pd, */ /* and sets the strtdate of pd to the date of the selected delta */ { struct branchhead * newbranch; if ( root == nil) return; if ( root->selector == 's') { if ( cmpnum(root->date, pd->strtdate) >= 0 && cmpnum(root->date, pd->enddate) <= 0) strcpy(pd->strtdate, root->date); } recentdate(root->next, pd); newbranch = root->branches; while( newbranch) { recentdate(newbranch->hsh, pd); newbranch = newbranch->nextbranch; } } extdate(root) struct hshentry * root; /* function: select revisions which are in the date range specified */ /* in duelst and datelist, start at root */ { struct branchhead * newbranch; struct Datepairs * pdate; if ( root == nil) return; if ( datelist || duelst) { pdate = datelist; while( pdate ) { if ( (pdate->strtdate)[0] == '\0' || cmpnum(root->date,pdate->strtdate) >= 0){ if ((pdate->enddate)[0] == '\0' || cmpnum(pdate->enddate,root->date) >= 0) break; } pdate = pdate->dnext; } if ( pdate == nil) { pdate = duelst; while(pdate) { if ( cmpnum(root->date, pdate->strtdate) == 0) break; pdate = pdate->dnext; } } if ( pdate == nil) root->selector = 'u'; } if (root->selector == 's') revno++; extdate(root->next); newbranch = root->branches; while( newbranch ) { extdate(newbranch->hsh); newbranch = newbranch->nextbranch; } } extractdelta(pdelta) struct hshentry * pdelta; /* function: compare information of pdelta to the authorlst, lockerlist, */ /* statelist, revlist and mark 's' on selector if pdelta is */ /* selected; otherwise, mark 'u' */ { struct lock * plock; struct stateattri * pstate; struct authors * pauthor; struct Revpairs * prevision; int length; pdelta->selector = 's'; if ( authorlist ) { /* certain author's revisions wanted only */ pauthor = authorlist; while((pauthor != nil) && ( strcmp(pauthor->login, pdelta->author)!=0)) pauthor = pauthor->nextauthor; if ( pauthor == nil ) { pdelta->selector = 'u'; return; } } if ( statelist ) { /* revisions with certain state wanted */ pstate = statelist; while((pstate != nil) && (strcmp(pstate->status, pdelta->state)!=0)) pstate = pstate->nextstate; if ( pstate == nil ) { pdelta->selector = 'u'; return; } } if ( lockflag ) { /* locked revisions */ plock = Locks; while( plock && (plock->delta != pdelta)) plock = plock->nextlock; if (plock == nil ) { pdelta->selector = 'u'; return; } } if ( Revlst ) { /* revisions or branches selected */ prevision = Revlst; while( prevision != nil ) { length = prevision->numfld; if ( length % 2 == 1) { /* a branch number */ if ( countnumflds(pdelta->num) ==(length+1)) if ( (compartial(pdelta->num, prevision->strtrev,length) >= 0)&& (compartial(prevision->endrev, pdelta->num, length) >= 0) ) break; } else if ( countnumflds(pdelta->num ) == length) /* a revision */ if ( (compartial(pdelta->num, prevision->strtrev, length) >= 0) && (compartial(prevision->endrev, pdelta->num, length) >= 0) ) break; prevision = prevision->rnext; } if (prevision == nil) { pdelta->selector = 'u'; return; } } } char * procdate(target, source) char * target, * source; /* Function: Parses a free-format date in target, converts it * into RCS internal format, and stores the result into source. * Returns target on success, nil otherwise. */ { long unixtime; struct tm parseddate, *ftm; if ( partime(source, &parseddate) == 0) { error("Can't parse date/time: %s", source); *target= '\0'; return nil; } if ( (unixtime = maketime(&parseddate)) == 0L) { error("Inconsistent date/time: %s", source); *target='\0'; return nil; } ftm = localtime(&unixtime); sprintf(target,DATEFORM, ftm->tm_year,ftm->tm_mon+1,ftm->tm_mday,ftm->tm_hour,ftm->tm_min,ftm->tm_sec); return target; } getdatepair(argv) char * argv; /* function: get time range from command line and store in datelist if */ /* a time range specified or in duelst if a time spot specified */ { register char c; struct Datepairs * nextdate; char * rawdate; int switchflag; argv--; while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' || c == '\n' || c == ';') ; if ( c == '\0' ) { warn("Missing date/time after -d"); return; } while( c != '\0' ) { switchflag = false; nextdate = (struct Datepairs *) malloc(sizeof(struct Datepairs)); if ( c == '<' ) { /* case: -d strtdate)[0] = '\0'; } elsif (c == '>') { /* case: -d >date */ c = *++argv; (nextdate->enddate)[0] = '\0'; switchflag = true; } else { rawdate = argv; while( c != '<' && c != '>' && c != ';' && c != '\0') c = *++argv; *argv = '\0'; if ( c == '>' ) switchflag=true; if (procdate(switchflag?nextdate->enddate:nextdate->strtdate, rawdate)==nil) continue; if ( c == ';' || c == '\0') { /* case: -d date */ strcpy(nextdate->enddate,nextdate->strtdate); sprintf(nextdate->strtdate,DATEFORM,0,0,0,0,0,0); nextdate->dnext = duelst; duelst = nextdate; goto end; } else { /* case: -d date< or -d date>; see switchflag */ while ( (c= *++argv) == ' ' || c=='\t' || c=='\n'); if ( c == ';' || c == '\0') { /* second date missing */ if (switchflag) *nextdate->strtdate= '\0'; else *nextdate->enddate= '\0'; nextdate->dnext = datelist; datelist = nextdate; goto end; } } } rawdate = argv; while( c != '>' && c != '<' && c != ';' && c != '\0') c = *++argv; *argv = '\0'; if (procdate(switchflag?nextdate->strtdate:nextdate->enddate, rawdate)==nil) continue; nextdate->dnext = datelist; datelist = nextdate; end: /* printf("startdate: %s; enddate: %s;\n", nextdate->strtdate,nextdate->enddate); */ if ( c == '\0') return; while( (c = *++argv) == ';' || c == ' ' || c == '\t' || c =='\n'); } } getnumericrev() /* function: get the numeric name of revisions which stored in revlist */ /* and then stored the numeric names in Revlst */ { struct Revpairs * ptr, *pt; int flag; char *temprev; /* free the previous numeric revision list */ pt = Revlst; while( pt) { free(pt); pt = pt->rnext; } Nextdotstring = &Dotstring[0]; /* reset buffer */ Revlst = nil; ptr = revlist; while( ptr ) { pt = (struct Revpairs *) malloc(sizeof(struct Revpairs)); if ( ptr->numfld == 1 ){ /* case: -r rev */ if ( (flag = expandsym(ptr->strtrev, Nextdotstring)) == true ) { pt->numfld = countnumflds(Nextdotstring); pt->strtrev = pt->endrev = Nextdotstring; while( *Nextdotstring++ != '\0' ) ; } } else if( ptr->numfld == 2){ /* case: -r rev- */ if ( (flag = expandsym(ptr->strtrev, Nextdotstring)) == true) { pt->numfld = countnumflds(Nextdotstring); pt->strtrev = Nextdotstring; while( *Nextdotstring++ != '\0' ) ; pt->endrev = Nextdotstring; if ( pt->numfld > 2) choptail(pt->strtrev); * Nextdotstring++ = '\0'; } } else if(ptr->numfld == 3) { /* case: -r -rev */ if ( (flag = expandsym(ptr->endrev, Nextdotstring)) == true) { pt->endrev = Nextdotstring; while( *Nextdotstring++ != '\0' ) ; pt->numfld = countnumflds(pt->endrev); pt->strtrev = Nextdotstring; if ( pt->numfld == 2) *Nextdotstring++ = '1'; else choptail(pt->endrev); *Nextdotstring++ = '.'; *Nextdotstring++ = '1'; *Nextdotstring++ = '\0'; } } else { /* case: -r rev1-rev2 */ if ( (flag = expandsym(ptr->strtrev, Nextdotstring)) == true ) { pt->strtrev = Nextdotstring; while( *Nextdotstring++ != '\0' ) ; if ( ( flag = expandsym(ptr->endrev, Nextdotstring)) == true) { pt->numfld = countnumflds(pt->strtrev); pt->endrev = Nextdotstring; while( *Nextdotstring++ != '\0' ) ; if((flag = checkrevpair(pt->strtrev, pt->endrev)) == true) /* switch pt->strtrev with pt->endrev, if pt->strtrev > pt->endre */ if (compartial(pt->strtrev, pt->endrev, pt->numfld) > 0 ) { temprev = pt->strtrev; pt->strtrev = pt->endrev; pt->endrev = temprev; } } } } if ( flag ){ pt->rnext = Revlst; Revlst = pt; } else free(pt); ptr = ptr->rnext; } } checkrevpair(num1,num2) char *num1, *num2; /* function: check whether num1, num2 are legal pair,i.e. only the last field are different and have same number of feilds( if length <= 2, may be different if first field) */ { int length; if ( (length = countnumflds(num1)) != countnumflds(num2) ) { error(" Invalid branch or revision pair %s : %s", num1, num2); return false; } if ( length > 2 ) if (compartial(num1, num2, length-1) != 0) { error("Invalid branch or revision pair %s : %s", num1, num2); return false; } return true; } getrevpairs(argv) register char * argv; /* function: get revision or branch range from command line, and */ /* store in revlist */ { register char c; struct Revpairs * nextrevpair; int flag; argv--; while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' || c == '\n' || c == ';') ; if ( c == '\0' ) { warn(" Missing revision or branch number after -r"); return; } while( c != '\0') { while( c == ',' || c == ' ' || c == '\t' || c == '\n' || c == ';') c = *++argv; if (c == '\0') return; nextrevpair = (struct Revpairs *) malloc(sizeof(struct Revpairs)); nextrevpair->rnext = revlist; revlist = nextrevpair; nextrevpair->numfld = nil; nextrevpair->strtrev = nil; nextrevpair->endrev = nil; flag = false; if ( c == '<' || c == '-' ) { /* case: -r -rev or -r strtrev = argv; /* get a revision or branch name */ while( c != ',' && c != ';' && c != ' ' && c != '\0' && c != '-' && c != '\t' && c != '\n' && c != '<') c = *++argv; *argv = '\0'; if ( c != '<' && c != '-') { /* case: rev */ nextrevpair->numfld = 1; continue; } if ( (c =(*++argv)) == ',' || c == '\0' || c == ' ' || c == '\t' || c == '\n' || c == ';') {/* case: rev_ */ nextrevpair->numfld = 2; continue; } } nextrevpair->endrev = argv; while( c != ',' && c != ' ' && c != '\0' && c != '\t' && c != '<' && c != '\n' && c != '-' && c != ';') c = *++argv; * argv = '\0'; if ( c == '<'){ error("seperator expected near %s", nextrevpair->endrev); while( (c = *++argv) != ',' && c != ' ' && c != '\0' && c != '\t' && c != '\n' && c != ';' ) ; revlist = nextrevpair->rnext; continue; } else { if (flag) /* case: -rev */ nextrevpair->numfld = 3; else /* rev1-rev2 appears */ nextrevpair->numfld = 4; } } } choptail(strhead) char * strhead; /* function : chop off the last field of a branch or a revision number */ { char *pt, *sp; for(pt = Nextdotstring-1; pt != strhead && *pt != '.'; pt--) ; for(sp = strhead; sp < pt; sp++) *Nextdotstring++ = *sp; }