1: /*
   2:  *                       RLOG    operation
   3:  */
   4: static char rcsid[]=
   5: "$Header: /usr/wft/RCS/SRC/RCS/rlog.c,v 3.7 83/05/11 14:24:13 wft Exp $ Purdue CS";
   6: /*****************************************************************************
   7:  *                       print contents of RCS files
   8:  *****************************************************************************
   9:  *
  10:  * Copyright (C) 1982 by Walter Tichy
  11:  *                       Purdue University
  12:  *                       Computer Science Department
  13:  *                       West Lafayette, IN 47907
  14:  *
  15:  * All rights reserved. No part of this software may be sold or distributed
  16:  * in any form or by any means without the prior written permission of the
  17:  * author.
  18:  * Report problems and direct all inquiries to Tichy@purdue (ARPA net).
  19:  */
  20: 
  21: 
  22: /* $Log:	rlog.c,v $
  23:  * Revision 3.7  83/05/11  14:24:13  wft
  24:  * Added options -L and -R;
  25:  * Fixed selection bug with -l on multiple files.
  26:  * Fixed error on dates of the form -d'>date' (rewrote getdatepair()).
  27:  *
  28:  * Revision 3.6  82/12/24  15:57:53  wft
  29:  * shortened output format.
  30:  *
  31:  * Revision 3.5  82/12/08  21:45:26  wft
  32:  * removed call to checkaccesslist(); used DATEFORM to format all dates;
  33:  * removed unused variables.
  34:  *
  35:  * Revision 3.4  82/12/04  13:26:25  wft
  36:  * Replaced getdelta() with gettree(); removed updating of field lockedby.
  37:  *
  38:  * Revision 3.3  82/12/03  14:08:20  wft
  39:  * Replaced getlogin with getpwuid(), %02d with %.2d, fancydate with PRINTDATE.
  40:  * Fixed printing of nil, removed printing of Suffix,
  41:  * added shortcut if no revisions are printed, disambiguated struct members.
  42:  *
  43:  * Revision 3.2  82/10/18  21:09:06  wft
  44:  * call to curdir replaced with getfullRCSname(),
  45:  * fixed call to getlogin(), cosmetic changes on output,
  46:  * changed conflicting long identifiers.
  47:  *
  48:  * Revision 3.1  82/10/13  16:07:56  wft
  49:  * fixed type of variables receiving from getc() (char -> int).
  50:  */
  51: 
  52: 
  53: 
  54: #include <pwd.h>
  55: #include "time.h"
  56: #include "rcsbase.h"
  57: static char rcsbaseid[] = RCSBASE;
  58: 
  59: 
  60: extern FILE * fopen();
  61: extern struct passwd *getpwuid();
  62: extern char * malloc();
  63: extern        free();
  64: extern struct hshentry * genrevs(); /*generate delta numbers                */
  65: extern int    countnumflds();
  66: extern int    compartial();
  67: extern char * partialno();
  68: extern int    expandsym();          /*get numeric name of a revision        */
  69: extern char * getfullRCSname();     /*get full path name of RCS file        */
  70: extern int nextc;                   /*next input character                  */
  71: extern char * Klog;
  72: extern char * Ktext;
  73: extern int  partime();
  74: extern long maketime();             /*convert parsed time to unix time.     */
  75: extern struct tm * localtime();     /*convert unixtime into a tm-structure  */
  76: extern int  pairfilenames();
  77: extern struct hshentry  * getnum();
  78: extern FILE * finptr;               /* RCS input file                       */
  79: extern FILE * frewrite;             /* new RCS file                         */
  80: extern int    nerror;               /* error counter                        */
  81: 
  82: char * RCSfilename, * workfilename;
  83: int    rewriteflag; /* indicates whether input should be echoed to frewrite */
  84: 
  85: char * caller;                        /* caller's login;                    */
  86: 
  87: char numericrev[revlength];           /* holds expanded revision number     */
  88: struct hshentry * gendeltas[hshsize]; /* stores deltas to be generated      */
  89: struct hshentry * targetdelta;        /* final delta to be generated        */
  90: int  descflag, selectflag, selectop;  /* option to print access list, symbolic  */
  91:                                       /* names, descriptive text, locks and */
  92:                                       /* Head                               */
  93: int  onlylockflag;            /* option to print only files         */
  94:                       /* with locks			    */
  95: int  onlyRCSflag;                     /* option to print only RCS file name */
  96: int  lockflag;                        /* whether locker option is set       */
  97: int  revno;                           /* number of revision chosen          */
  98: 
  99: struct  lockers {                     /* lockers in locker option; stored   */
 100:      char               * login;      /* lockerlist                         */
 101:      struct     lockers * lockerlink;
 102:      }  ;
 103: 
 104: struct  stateattri {                  /* states in state option; stored in  */
 105:      char               * status;     /* statelist                          */
 106:      struct  stateattri * nextstate;
 107:      }  ;
 108: 
 109: struct  authors {                     /* login names in author option;      */
 110:      char               * login;      /* stored in authorlist               */
 111:      struct     authors * nextauthor;
 112:      }  ;
 113: 
 114: struct Revpairs{                      /* revision or branch range in -r     */
 115:      int                  numfld;     /* option; stored in revlist          */
 116:      char               * strtrev;
 117:      char               * endrev;
 118:      struct  Revpairs   * rnext;
 119:      } ;
 120: 
 121: struct Datepairs{                     /* date range in -d option; stored in */
 122:      char               strtdate[datelength];   /* duelst and datelist      */
 123:      char               enddate[datelength];
 124:      struct  Datepairs  * dnext;
 125:      };
 126: 
 127: char   Dotstring[200];                /* string of numeric revision name    */
 128: char   * Nextdotstring;               /* next available place of Dotstring  */
 129: struct  Datepairs       * datelist,  * duelst;
 130: struct  Revpairs        * revlist, * Revlst;
 131: struct  lockers         * lockerlist;
 132: struct  stateattri      * statelist;
 133: struct  authors         * authorlist;
 134: 
 135: 
 136: 
 137: main (argc, argv)
 138: int argc;
 139: char * argv[];
 140: {
 141:         struct  Datepairs       * currdate;
 142:         struct  assoc         * curassoc;
 143:         struct  access        * curaccess;
 144:         struct  lock          * currlock;
 145:         char * cmdusage;
 146: 
 147:     cmdusage = "command format:\nrlog -L -R -h -t -ddates -l[lockers] -rrevisions -sstates -w[logins] file ...";
 148:         cmdid = "rlog";
 149:         descflag = selectflag = true;
 150:         lockflag = onlylockflag = selectop = false;
 151:     onlyRCSflag = false;
 152:         lockerlist = nil;
 153:         authorlist = nil;
 154:         statelist = nil;
 155:         Revlst = revlist = nil;
 156:         duelst = datelist = nil;
 157:         caller=getpwuid(getuid())->pw_name;
 158: 
 159:         while (--argc,++argv, argc>=1 && ((*argv)[0] == '-')) {
 160:                 switch ((*argv)[1]) {
 161: 
 162:         case 'L':
 163:             onlylockflag = true;
 164:             break;
 165: 
 166:         case 'R':
 167:             onlyRCSflag =true;
 168:             break;
 169: 
 170:                 case 'l':
 171:                         selectop = true;
 172:                         lockflag = true;
 173:                         getlocker( (*argv)+2 );
 174:                         break;
 175: 
 176:                 case 'r':
 177:                         selectop = true;
 178:                         getrevpairs( (*argv)+2 );
 179:                         break;
 180: 
 181:                 case 'd':
 182:                         selectop = true;
 183:                         getdatepair( (*argv)+2 );
 184:                         break;
 185: 
 186:                 case 's':
 187:                         selectop = true;
 188:                         getstate( (*argv)+2);
 189:                         break;
 190: 
 191:                 case 'w':
 192:                         selectop = true;
 193:                         getauthor( (*argv)+2);
 194:                         break;
 195: 
 196:                 case 'h':
 197:                         if ( ! selectflag ) warn("option -t overrides -h");
 198:                         else    descflag = false;
 199:                         break;
 200: 
 201:                 case 't':
 202:                         selectflag = false;
 203:                         if ( ! descflag ) warn("option -t overrides -h");
 204:                         descflag = true;
 205:                         break;
 206: 
 207:                 default:
 208:                         faterror("unknown option: %s\n%s", *argv,cmdusage);
 209: 
 210:                 };
 211:         } /* end of option processing */
 212: 
 213:         if (argc<1) faterror("No input file\n%s",cmdusage);
 214: 
 215: 
 216:         /* now handle all filenames */
 217:         do {
 218:             rewriteflag=false;
 219:             finptr=frewrite=nil;
 220: 
 221: 
 222:             if (!pairfilenames(argc, argv, true,false)) continue;
 223: 
 224:             /* now RCSfilename contains the name of the RCS file, and finptr
 225:              * the file descriptor. Workfilename contains the name of the
 226:              * working file.
 227:              */
 228: 
 229:             if ( !trysema(RCSfilename, false)) goto loopend; /*  give up */
 230: 
 231:             /* do nothing if -L is given and there are no locks*/
 232:         if ( onlylockflag && Locks == nil ) goto loopend;
 233: 
 234:         if ( onlyRCSflag ) {
 235:         fprintf(stdout, "%s\n", RCSfilename);
 236:         goto loopend;
 237:         }
 238:             /*   print RCS filename , working filename and optional
 239:                  administrative information                         */
 240:             fprintf(stdout, "\nRCS file:        %s;   ",RCSfilename);
 241:             /* could use getfullRCSname() here, but that is very slow */
 242:             fprintf(stdout, "Working file:    %s\n", workfilename);
 243:             fprintf(stdout, "head:            %s\n", Head==nil?"":Head->num);
 244: 
 245:             fputs("locks:         ", stdout);  /*  print locker list   */
 246:             currlock = Locks;
 247:             while( currlock ) {
 248:                 fprintf(stdout,"  %s: %s;", currlock->login,
 249:                                 currlock->delta->num);
 250:                 currlock = currlock->nextlock;
 251:             }
 252:             if ( StrictLocks )
 253:                 fputs(Locks==nil?"  ;  strict":"  strict",stdout);
 254: 
 255:             fputs("\naccess list:   ", stdout);      /*  print access list  */
 256:             curaccess = AccessList;
 257:             while(curaccess) {
 258:                 fputs("  ",stdout);
 259:                 fputs(curaccess->login, stdout);
 260:                 curaccess = curaccess->nextaccess;
 261:             }
 262: 
 263:             fputs("\nsymbolic names:", stdout);   /*  print symbolic names   */
 264:             curassoc = Symbols;
 265:             while( curassoc ) {
 266:                 fprintf(stdout, "  %s: %s;",curassoc->symbol,
 267:                            curassoc->delta->num);
 268:                 curassoc = curassoc->nextassoc;
 269:             }
 270: 
 271:             fprintf(stdout,"\ncomment leader:  \"%s\"\n",Comment);
 272: 
 273:             gettree();
 274:             fprintf(stdout, "total revisions: %d;    ", TotalDeltas);
 275:             if ( Head == nil || !selectflag || !descflag) {
 276:                 putc('\n',stdout);
 277:                 if (descflag) fputs("description:\n", stdout);
 278:                 getdesc(descflag);
 279:                 fputs("=============================================================================\n",stdout);
 280:                 goto loopend;
 281:             }
 282: 
 283: 
 284:             /*  keep only those locks given by -l */
 285:             if (lockflag)
 286:                 trunclocks();
 287:             getnumericrev();    /* get numeric revision or branch names */
 288:             revno = 0;
 289: 
 290:             exttree(Head);
 291: 
 292:             /*  get most recently date of the dates pointed by duelst  */
 293:             currdate = duelst;
 294:             while( currdate) {
 295:                 recentdate(Head, currdate);
 296:                 currdate = currdate->dnext;
 297:         }
 298: 
 299:             extdate(Head);
 300: 
 301:             /*  reinitialize the date specification list   */
 302:             currdate = duelst;
 303:             while(currdate) {
 304:                 sprintf(currdate->strtdate,DATEFORM,0,0,0,0,0,0);
 305:                 currdate = currdate->dnext;
 306:             }
 307: 
 308:             if ( selectop || ( selectflag && descflag) )
 309:                 fprintf(stdout, "selected revisions: %d", revno);
 310:             putc('\n', stdout);
 311:             if (descflag) fputs("description:\n", stdout);
 312:             getdesc(descflag);
 313:             while( (nexttok != EOFILE) && readdeltalog());
 314:             if (selectflag && descflag && revno) {
 315:                 putrunk();
 316:                 putree(Head);
 317:                 if (nextlex(), nexttok != EOFILE)
 318:                     fatserror("syntax error; expecting EOF");
 319:             }
 320:             fputs("=============================================================================\n",stdout);
 321:         loopend:
 322:             fclose(finptr);
 323:         } while( ++argv, --argc >= 1);
 324:         exit(nerror!=0);
 325: }
 326: 
 327: 
 328: 
 329: putrunk()
 330: /*  function:  print revisions chosen, which are in trunk      */
 331: 
 332: {
 333:         struct  hshentry        * ptr, * pre;
 334: 
 335:         if (Head == nil) return;   /*  empty tree  */
 336: 
 337:         pre = Head;
 338:         ptr = Head->next;
 339:         while( ptr ) {
 340:             putadelta(pre,ptr,true);
 341:             pre = ptr;
 342:             ptr = ptr->next;
 343:         }
 344:         putadelta(pre,ptr,true);
 345: }
 346: 
 347: 
 348: 
 349: putree(root)
 350: struct  hshentry  *root;
 351: /*   function: print delta tree( not include trunck) in reversed calender
 352:                order on each branch                                        */
 353: 
 354: {
 355:         if ( root == nil ) return;
 356: 
 357:         putree(root->next);
 358: 
 359:         putforest(root->branches);
 360: }
 361: 
 362: 
 363: 
 364: 
 365: putforest(branchroot)
 366: struct   branchhead     * branchroot;
 367: /*   function:  print branches that has the same direct ancestor    */
 368: {
 369: 
 370:         if ( branchroot == nil ) return;
 371: 
 372:         putforest(branchroot->nextbranch);
 373: 
 374:         putabranch(branchroot->hsh);
 375:         putree(branchroot->hsh);
 376: }
 377: 
 378: 
 379: 
 380: 
 381: putabranch(root)
 382: struct      hshentry   *root;
 383: /*   function  :  print one branch     */
 384: 
 385: {
 386: 
 387:         if ( root == nil) return;
 388: 
 389:         putabranch(root->next);
 390: 
 391:         putadelta(root, root, false);
 392: }
 393: 
 394: 
 395: 
 396: 
 397: 
 398: putadelta(node,editscript,trunk)
 399: register  struct   hshentry    * node;
 400: register  struct   hshentry    * editscript;
 401: int                              trunk;
 402: /*  function: print delta node if node->selector is 's'.        */
 403: /*      editscript indicates where the editscript is stored     */
 404: /*      trunk indicated whether this node is in trunk           */
 405: {
 406:         struct  branchhead      * newbranch;
 407:         char                    * branchnum,  branch[40];
 408: 
 409:         if ( ( node == nil) || ( node->selector == 'u'))
 410:             return;
 411: 
 412:         fprintf(stdout,"----------------------------\n");
 413:         fprintf(stdout, "revision %s        ",node->num);
 414:         if ( node->lockedby )
 415:            fprintf(stdout, "locked by: %s;       ", node->lockedby);
 416:         putc('\n', stdout);
 417: 
 418:         fputs("date: ",stdout);
 419:         PRINTDATE(stdout,node->date); putc(' ',stdout);
 420:         PRINTTIME(stdout,node->date);
 421:         fprintf(stdout, ";  author: %s;  ", node->author);
 422:         fprintf(stdout, "state: %s;  ", node->state);
 423: 
 424:         if ( editscript )
 425:            if(trunk)
 426:               fprintf(stdout,"lines added/del: %d/%d",
 427:                              editscript->deletelns, editscript->insertlns);
 428:            else
 429:               fprintf(stdout,"lines added/del: %d/%d",
 430:                              editscript->insertlns, editscript->deletelns);
 431: 
 432:         putc('\n', stdout);
 433: 
 434:         branchnum = & (branch[0]);
 435:         newbranch = node->branches;
 436:         if ( newbranch ) {
 437:            fputs("branches:  ", stdout);
 438:            while( newbranch ) {
 439:                 getbranchno(newbranch->hsh->num, branchnum);
 440:                 fprintf(stdout, "%s;  ", branchnum);
 441:                 newbranch = newbranch->nextbranch;
 442:            }
 443:            putc('\n', stdout);
 444:         }
 445: 
 446:         fputs(node->log,stdout);
 447: }
 448: 
 449: 
 450: 
 451: 
 452: 
 453: readdeltalog()
 454: /*  Function : get the log message and skip the text of a deltatext node.
 455:  *             Return false if current block does not start with a number.
 456:  *             Assumes the current lexeme is not yet in nexttok; does not
 457:  *             advance nexttok.
 458:  */
 459: {
 460:         register struct  hshentry  * Delta;
 461: 
 462:         nextlex();
 463:         if ( !(Delta = getnum() )) return(false);
 464:         if ( ! getkey(Klog) || ( nexttok != STRING ) )
 465:                 fatserror("Missing log entry");
 466:         Delta->log = malloc(logsize);
 467:         savestring(Delta->log, logsize);
 468:         nextlex();
 469:         if ( ! getkey(Ktext) || (nexttok != STRING) )
 470:                 fatserror("Missing delta text");
 471:         Delta->insertlns = Delta->deletelns = 0;
 472:         if ( Delta != Head)
 473:                 getscript(Delta);
 474:         else
 475:                 readstring();
 476:         return true;
 477: }
 478: 
 479: 
 480: 
 481: getscript(Delta)
 482: struct    hshentry   * Delta;
 483: /*   function:  read edit script of Delta and count how many lines added  */
 484: /*              and deleted in the script                                 */
 485: 
 486: {
 487:         int ed;   /*  editor command  */
 488:         register  int   c;
 489:         register  int   i;
 490:         int             length;
 491: 
 492:         while( (ed = getc(finptr)) != EOF) {
 493:            /*  assume first none white character is command name  */
 494:             while( ed == '\n' || ed == ' ' || ed == '\t')
 495:                 ed = getc(finptr);
 496:             if (ed == SDELIM) break;  /*  script text is ended   */
 497:             while( ( c = getc(finptr)) == ' ' );  /*  skip blank  */
 498:             if ( ! ('0' <= c && c <= '9')) {
 499:                 faterror("Missing line number in edit script");
 500:                 break;
 501:             }
 502:             while( '0' <= (c = getc(finptr)) && c <= '9' ) ;
 503: 
 504:             while( c == ' ')c = getc(finptr);  /*  skip blanks  */
 505:             if ( !('0' <= c && c <= '9' ) ) {
 506:                 faterror("Incorrect range in edit script");
 507:                 break;
 508:             }
 509:             length = c - '0';
 510:             while( '0' <= (c = getc(finptr)) && c <= '9' )
 511:                 length = length * 10 + c - '0';
 512:             while( c != '\n' && c != EOF) c = getc(finptr);
 513:             switch (ed) {
 514:             case 'd' :
 515:                  Delta->deletelns += length;
 516:                  break;
 517: 
 518:             case 'a' :
 519:                  /*  skip scripted lines  */
 520:                  for ( i=length; i > 0 && c != EOF; i--){
 521:                      while( (c=getc(finptr)) != '\n' && c != EOF);
 522:                      Delta->insertlns++;
 523:                  }
 524:                  break;
 525: 
 526:             default:
 527:                  faterror("Unknown command in edit script: %c", ed);
 528:                  break;
 529:             }
 530:         }
 531:         nextc = getc(finptr);
 532: }
 533: 
 534: 
 535: 
 536: 
 537: 
 538: 
 539: 
 540: exttree(root)
 541: struct hshentry  *root;
 542: /*  function: select revisions , starting with root             */
 543: 
 544: {
 545:         struct branchhead       * newbranch;
 546: 
 547:         if (root == nil) return;
 548: 
 549:         extractdelta(root);
 550:         exttree(root->next);
 551: 
 552:         newbranch = root->branches;
 553:         while( newbranch ) {
 554:             exttree(newbranch->hsh);
 555:             newbranch = newbranch->nextbranch;
 556:         }
 557: }
 558: 
 559: 
 560: 
 561: 
 562: getlocker(argv)
 563: char    * argv;
 564: /*   function : get the login names of lockers from command line   */
 565: /*              and store in lockerlist.                           */
 566: 
 567: {
 568:         register char c;
 569:         struct   lockers   * newlocker;
 570:         argv--;
 571:         while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' ||
 572:                  c == '\n' || c == ';')  ;
 573:         if (  c == '\0') {
 574:             lockerlist=nil;
 575:             return;
 576:         }
 577: 
 578:         while( c != '\0' ) {
 579:             newlocker = ( struct lockers *)malloc( sizeof(struct lockers) );
 580:             newlocker->lockerlink = lockerlist;
 581:             newlocker->login = argv;
 582:             lockerlist = newlocker;
 583:             while ( ( c = (*++argv)) != ',' && c != '\0' && c != ' '
 584:                        && c != '\t' && c != '\n' && c != ';') ;
 585:             *argv = '\0';
 586:             if ( c == '\0' ) return;
 587:             while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' ||
 588:                      c == '\n' || c == ';')  ;
 589:         }
 590: }
 591: 
 592: 
 593: 
 594: getauthor(argv)
 595: char   *argv;
 596: /*   function:  get the author's name form command line   */
 597: /*              and store in aauthorlist                  */
 598: 
 599: {
 600:         register    c;
 601:         struct     authors  * newauthor;
 602: 
 603:         argv--;
 604:         while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' ||
 605:                  c == '\n' || c == ';')  ;
 606:         if ( c == '\0' ) {
 607:             authorlist = (struct authors *)malloc(sizeof(struct authors));
 608:             authorlist->login = caller;
 609:             authorlist->nextauthor  = nil;
 610:             return;
 611:         }
 612: 
 613:         while( c != '\0' ) {
 614:             newauthor = (struct authors *)malloc(sizeof(struct authors));
 615:             newauthor->nextauthor = authorlist;
 616:             newauthor->login = argv;
 617:             authorlist = newauthor;
 618:             while( ( c = *++argv) != ',' && c != '\0' && c != ' '
 619:                      && c != '\t' && c != '\n' && c != ';') ;
 620:             * argv = '\0';
 621:             if ( c == '\0') return;
 622:             while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' ||
 623:                      c == '\n' || c == ';')  ;
 624:         }
 625: }
 626: 
 627: 
 628: 
 629: 
 630: getstate(argv)
 631: char   * argv;
 632: /*   function :  get the states of revisions from command line  */
 633: /*               and store in statelist                         */
 634: 
 635: {
 636:         register  char  c;
 637:         struct    stateattri    *newstate;
 638: 
 639:         argv--;
 640:         while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' ||
 641:                  c == '\n' || c == ';')  ;
 642:         if ( c == '\0'){
 643:             warn(" Missing state attributes after -s options");
 644:             return;
 645:         }
 646: 
 647:         while( c != '\0' ) {
 648:             newstate = (struct stateattri *)malloc(sizeof(struct stateattri));
 649:             newstate->nextstate = statelist;
 650:             newstate->status = argv;
 651:             statelist = newstate;
 652:             while( (c = (*++argv)) != ',' && c != '\0' && c != ' '
 653:                     && c != '\t' && c != '\n' && c != ';')  ;
 654:             *argv = '\0';
 655:             if ( c == '\0' ) return;
 656:             while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' ||
 657:                      c == '\n' || c == ';')  ;
 658:         }
 659: }
 660: 
 661: 
 662: 
 663: trunclocks()
 664: /*  Function:  Truncate the list of locks to those that are held by the  */
 665: /*             id's on lockerlist. Do not truncate if lockerlist empty.  */
 666: 
 667: {
 668:         struct lockers  * plocker;
 669:         struct lock     * plocked,  * nextlocked;
 670: 
 671:         if ( (lockerlist == nil) || (Locks == nil)) return;
 672: 
 673:         /* shorten Locks to those contained in lockerlist */
 674:         plocked = Locks;
 675:         Locks = nil;
 676:         while( plocked != nil) {
 677:             plocker = lockerlist;
 678:             while((plocker != nil) && ( strcmp(plocker->login, plocked->login)!=0))
 679:                 plocker = plocker->lockerlink;
 680:             nextlocked = plocked->nextlock;
 681:             if ( plocker != nil) {
 682:                 plocked->nextlock = Locks;
 683:                 Locks = plocked;
 684:             }
 685:             plocked = nextlocked;
 686:         }
 687: }
 688: 
 689: 
 690: 
 691: recentdate(root, pd)
 692: struct  hshentry    * root;
 693: struct  Datepairs   * pd;
 694: /*  function:  Finds the delta that is closest to the cutoff date given by   */
 695: /*             pd among the revisions selected by exttree.                   */
 696: /*             Successively narrows down the interfal given by pd,           */
 697: /*             and sets the strtdate of pd to the date of the selected delta */
 698: {
 699:         struct  branchhead      * newbranch;
 700: 
 701:     if ( root == nil) return;
 702:         if ( root->selector == 's') {
 703:              if ( cmpnum(root->date, pd->strtdate) >= 0 &&
 704:                   cmpnum(root->date, pd->enddate) <= 0)
 705:         strcpy(pd->strtdate, root->date);
 706:         }
 707: 
 708:         recentdate(root->next, pd);
 709:         newbranch = root->branches;
 710:         while( newbranch) {
 711:            recentdate(newbranch->hsh, pd);
 712:            newbranch = newbranch->nextbranch;
 713:     }
 714: }
 715: 
 716: 
 717: 
 718: 
 719: 
 720: 
 721: extdate(root)
 722: struct  hshentry        * root;
 723: /*  function:  select revisions which are in the date range specified     */
 724: /*             in duelst  and datelist, start at root                     */
 725: 
 726: {
 727:         struct  branchhead      * newbranch;
 728:         struct  Datepairs       * pdate;
 729: 
 730:         if ( root == nil) return;
 731: 
 732:         if ( datelist || duelst) {
 733:             pdate = datelist;
 734:             while( pdate ) {
 735:                 if ( (pdate->strtdate)[0] == '\0' || cmpnum(root->date,pdate->strtdate) >= 0){
 736:                    if ((pdate->enddate)[0] == '\0' || cmpnum(pdate->enddate,root->date) >= 0)
 737:                         break;
 738:                 }
 739:                 pdate = pdate->dnext;
 740:             }
 741:             if ( pdate == nil) {
 742:                 pdate = duelst;
 743:                 while(pdate) {
 744:                    if ( cmpnum(root->date, pdate->strtdate) == 0)
 745:                       break;
 746:                    pdate = pdate->dnext;
 747:                 }
 748:             }
 749:             if ( pdate == nil)
 750:                 root->selector = 'u';
 751:         }
 752:         if (root->selector == 's') revno++;
 753: 
 754:         extdate(root->next);
 755: 
 756:         newbranch = root->branches;
 757:         while( newbranch ) {
 758:            extdate(newbranch->hsh);
 759:            newbranch = newbranch->nextbranch;
 760:         }
 761: }
 762: 
 763: 
 764: 
 765: extractdelta(pdelta)
 766: struct  hshentry        * pdelta;
 767: /*  function:  compare information of pdelta to the authorlst, lockerlist, */
 768: /*             statelist, revlist and mark 's' on selector if pdelta is    */
 769: /*             selected; otherwise, mark 'u'                               */
 770: 
 771: {
 772:         struct  lock            * plock;
 773:         struct  stateattri      * pstate;
 774:         struct  authors         * pauthor;
 775:         struct  Revpairs        * prevision;
 776:         int                       length;
 777: 
 778:         pdelta->selector = 's';
 779:         if ( authorlist ) {  /*  certain author's revisions wanted only  */
 780:             pauthor = authorlist;
 781:             while((pauthor != nil) && ( strcmp(pauthor->login, pdelta->author)!=0))
 782:                 pauthor = pauthor->nextauthor;
 783:             if ( pauthor == nil ) {
 784:                 pdelta->selector = 'u';
 785:                 return;
 786:             }
 787:         }
 788:         if ( statelist ) {   /* revisions with certain state wanted  */
 789:             pstate = statelist;
 790:             while((pstate != nil) && (strcmp(pstate->status, pdelta->state)!=0))
 791:                 pstate = pstate->nextstate;
 792:             if ( pstate == nil ) {
 793:                 pdelta->selector = 'u';
 794:                 return;
 795:             }
 796:         }
 797:         if ( lockflag ) {    /*  locked revisions   */
 798:             plock = Locks;
 799:             while( plock && (plock->delta != pdelta))
 800:                 plock = plock->nextlock;
 801:             if (plock == nil ) {
 802:                 pdelta->selector = 'u';
 803:                 return;
 804:             }
 805:         }
 806:         if ( Revlst ) {   /*  revisions or branches selected  */
 807: 
 808:             prevision = Revlst;
 809:             while( prevision != nil ) {
 810:                 length = prevision->numfld;
 811:                 if ( length % 2 == 1) { /*  a branch number  */
 812:                      if ( countnumflds(pdelta->num) ==(length+1))
 813:                         if ( (compartial(pdelta->num, prevision->strtrev,length) >= 0)&&
 814:                              (compartial(prevision->endrev, pdelta->num, length) >= 0) )
 815:                              break;
 816:                 }
 817:                 else if ( countnumflds(pdelta->num ) == length)  /*  a revision */
 818:                     if ( (compartial(pdelta->num, prevision->strtrev, length) >= 0) &&
 819:                          (compartial(prevision->endrev, pdelta->num, length) >= 0) )
 820:                         break;
 821:                 prevision = prevision->rnext;
 822:             }
 823:             if (prevision == nil)  {
 824:                 pdelta->selector = 'u';
 825:                 return;
 826:             }
 827:         }
 828: }
 829: 
 830: 
 831: 
 832: char * procdate(target, source)
 833: char * target, * source;
 834: /* Function: Parses a free-format date in target, converts it
 835:  * into RCS internal format, and stores the result into source.
 836:  * Returns target on success, nil otherwise.
 837:  */
 838: {
 839:     long            unixtime;
 840:     struct     tm   parseddate,  *ftm;
 841: 
 842:     if ( partime(source, &parseddate) == 0) {
 843:         error("Can't parse date/time: %s", source);
 844:         *target= '\0';
 845:         return nil;
 846:     }
 847:     if ( (unixtime = maketime(&parseddate)) == 0L) {
 848:         error("Inconsistent date/time: %s", source);
 849:         *target='\0';
 850:         return nil;
 851:     }
 852:     ftm = localtime(&unixtime);
 853:     sprintf(target,DATEFORM,
 854:     ftm->tm_year,ftm->tm_mon+1,ftm->tm_mday,ftm->tm_hour,ftm->tm_min,ftm->tm_sec);
 855:     return target;
 856: }
 857: 
 858: 
 859: 
 860: getdatepair(argv)
 861:    char   * argv;
 862: /*  function:  get time range from command line and store in datelist if    */
 863: /*             a time range specified or in duelst if a time spot specified */
 864: 
 865: {
 866:         register   char         c;
 867:         struct     Datepairs    * nextdate;
 868:         char                    * rawdate;
 869:     int                     switchflag;
 870: 
 871:         argv--;
 872:         while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' ||
 873:                  c == '\n' || c == ';')  ;
 874:         if ( c == '\0' ) {
 875:             warn("Missing date/time after -d");
 876:             return;
 877:         }
 878: 
 879:         while( c != '\0' )  {
 880:         switchflag = false;
 881:         nextdate = (struct Datepairs *) malloc(sizeof(struct Datepairs));
 882:             if ( c == '<' ) {   /*   case: -d <date   */
 883:                 c = *++argv;
 884:                 (nextdate->strtdate)[0] = '\0';
 885:         } elsif (c == '>') {        /*  case:  -d >date     */
 886:         c = *++argv;
 887:         (nextdate->enddate)[0] = '\0';
 888:         switchflag = true;
 889:         } else {
 890:                 rawdate = argv;
 891:         while( c != '<' && c != '>' && c != ';' && c != '\0')
 892:              c = *++argv;
 893:                 *argv = '\0';
 894:         if ( c == '>' ) switchflag=true;
 895:         if (procdate(switchflag?nextdate->enddate:nextdate->strtdate,
 896:                  rawdate)==nil) continue;
 897:         if ( c == ';' || c == '\0') {  /*  case: -d date  */
 898:             strcpy(nextdate->enddate,nextdate->strtdate);
 899:             sprintf(nextdate->strtdate,DATEFORM,0,0,0,0,0,0);
 900:                     nextdate->dnext = duelst;
 901:                     duelst = nextdate;
 902:             goto end;
 903:         } else {
 904:             /*   case:   -d date<  or -d  date>; see switchflag */
 905:             while ( (c= *++argv) == ' ' || c=='\t' || c=='\n');
 906:             if ( c == ';' || c == '\0') {
 907:             /* second date missing */
 908:             if (switchflag)
 909:                 *nextdate->strtdate= '\0';
 910:             else
 911:                 *nextdate->enddate= '\0';
 912:             nextdate->dnext = datelist;
 913:             datelist = nextdate;
 914:             goto end;
 915:             }
 916:                 }
 917:             }
 918:             rawdate = argv;
 919:         while( c != '>' && c != '<' && c != ';' && c != '\0')
 920:         c = *++argv;
 921:             *argv = '\0';
 922:         if (procdate(switchflag?nextdate->strtdate:nextdate->enddate,
 923:              rawdate)==nil) continue;
 924:             nextdate->dnext = datelist;
 925:         datelist = nextdate;
 926:      end:
 927: /*
 928: 	    printf("startdate: %s; enddate: %s;\n", nextdate->strtdate,nextdate->enddate);
 929: */
 930:         if ( c == '\0')  return;
 931:             while( (c = *++argv) == ';' || c == ' ' || c == '\t' || c =='\n');
 932:         }
 933: }
 934: 
 935: 
 936: 
 937: 
 938: 
 939: getnumericrev()
 940: /*  function:  get the numeric name of revisions which stored in revlist  */
 941: /*             and then stored the numeric names in Revlst                */
 942: 
 943: {
 944:         struct  Revpairs        * ptr, *pt;
 945:         int     flag;
 946:         char    *temprev;
 947: 
 948:         /*  free the previous numeric revision list  */
 949:         pt = Revlst;
 950:         while( pt) {
 951:            free(pt);
 952:            pt = pt->rnext;
 953:         }
 954:         Nextdotstring = &Dotstring[0]; /* reset buffer */
 955: 
 956: 
 957:         Revlst = nil;
 958:         ptr = revlist;
 959:         while( ptr ) {
 960:             pt = (struct Revpairs *) malloc(sizeof(struct Revpairs));
 961:             if ( ptr->numfld == 1 ){ /*  case:  -r rev   */
 962:                 if ( (flag = expandsym(ptr->strtrev, Nextdotstring)) == true ) {
 963:                     pt->numfld = countnumflds(Nextdotstring);
 964:                     pt->strtrev = pt->endrev = Nextdotstring;
 965:                     while( *Nextdotstring++ != '\0' )  ;
 966:                 }
 967:             }
 968:             else if( ptr->numfld == 2){ /*  case: -r rev-   */
 969:                 if ( (flag = expandsym(ptr->strtrev, Nextdotstring)) == true) {
 970:                     pt->numfld = countnumflds(Nextdotstring);
 971:                     pt->strtrev = Nextdotstring;
 972:                     while( *Nextdotstring++ != '\0' ) ;
 973:                     pt->endrev = Nextdotstring;
 974:                     if ( pt->numfld > 2) choptail(pt->strtrev);
 975:                     * Nextdotstring++ = '\0';
 976:                 }
 977:              }
 978:              else if(ptr->numfld == 3)  { /*  case: -r -rev   */
 979:                 if ( (flag = expandsym(ptr->endrev, Nextdotstring)) == true) {
 980:                     pt->endrev = Nextdotstring;
 981:                     while( *Nextdotstring++ != '\0' )  ;
 982:                     pt->numfld = countnumflds(pt->endrev);
 983:                     pt->strtrev = Nextdotstring;
 984:                     if ( pt->numfld == 2)
 985:                         *Nextdotstring++ = '1';
 986:                     else
 987:                         choptail(pt->endrev);
 988:                     *Nextdotstring++ = '.';
 989:                     *Nextdotstring++ = '1';
 990:                     *Nextdotstring++ = '\0';
 991:                 }
 992:              }
 993:              else  {     /*   case:  -r rev1-rev2   */
 994:                 if ( (flag = expandsym(ptr->strtrev, Nextdotstring)) == true ) {
 995:                     pt->strtrev = Nextdotstring;
 996:                     while( *Nextdotstring++ != '\0' )  ;
 997:                     if ( ( flag = expandsym(ptr->endrev, Nextdotstring)) == true)  {
 998:                         pt->numfld = countnumflds(pt->strtrev);
 999:                         pt->endrev = Nextdotstring;
1000:                         while( *Nextdotstring++ != '\0' ) ;
1001:                         if((flag = checkrevpair(pt->strtrev, pt->endrev)) == true)
1002:                            /*  switch pt->strtrev with pt->endrev, if pt->strtrev > pt->endre  */
1003:                             if (compartial(pt->strtrev, pt->endrev, pt->numfld) > 0 ) {
1004:                                 temprev = pt->strtrev;
1005:                                 pt->strtrev = pt->endrev;
1006:                                 pt->endrev = temprev;
1007:                             }
1008:                      }
1009:                 }
1010:              }
1011: 
1012:              if ( flag ){
1013:                 pt->rnext = Revlst;
1014:                 Revlst = pt;
1015:              }
1016:              else
1017:                 free(pt);
1018:              ptr = ptr->rnext;
1019:         }
1020: 
1021: }
1022: 
1023: 
1024: 
1025: checkrevpair(num1,num2)
1026: char    *num1,  *num2;
1027: /*  function:  check whether num1, num2 are legal pair,i.e.
1028:     only the last field are different and have same number of
1029:     feilds( if length <= 2, may be different if first field)   */
1030: 
1031: {
1032:         int    length;
1033: 
1034:         if ( (length = countnumflds(num1)) != countnumflds(num2) ) {
1035:             error(" Invalid branch or revision pair %s : %s", num1, num2);
1036:             return false;
1037:         }
1038:         if ( length > 2 )
1039:             if (compartial(num1, num2, length-1) != 0) {
1040:                 error("Invalid branch or revision pair %s : %s", num1, num2);
1041:                 return false;
1042:             }
1043: 
1044:         return true;
1045: }
1046: 
1047: 
1048: 
1049: getrevpairs(argv)
1050: register     char    * argv;
1051: /*  function:  get revision or branch range from command line, and   */
1052: /*             store in revlist                                      */
1053: 
1054: {
1055:         register    char    c;
1056:         struct      Revpairs  * nextrevpair;
1057:         int         flag;
1058: 
1059:         argv--;
1060:         while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' ||
1061:                  c == '\n' || c == ';')  ;
1062:         if ( c == '\0' ) {
1063:             warn(" Missing revision or branch number after -r");
1064:             return;
1065:         }
1066: 
1067:         while( c != '\0') {
1068:             while(  c  == ',' || c == ' ' || c == '\t' ||
1069:                      c == '\n' || c == ';') c = *++argv;
1070:             if (c == '\0')  return;
1071:             nextrevpair = (struct Revpairs *) malloc(sizeof(struct Revpairs));
1072:             nextrevpair->rnext = revlist;
1073:             revlist = nextrevpair;
1074:             nextrevpair->numfld  = nil;
1075:             nextrevpair->strtrev = nil;
1076:             nextrevpair->endrev  = nil;
1077:             flag = false;
1078:             if (  c == '<' || c == '-' ) {  /*  case: -r -rev  or -r <rev  */
1079:                 flag = true;
1080:                 while( (c =(*++argv)) == ' ' || c == '\t' || c =='\n') ;
1081:             }
1082:             else {
1083:                 nextrevpair->strtrev = argv;
1084:                 /*   get a revision or branch name  */
1085:                 while( c != ',' && c != ';' && c != ' ' && c != '\0' && c != '-'
1086:                         && c != '\t' && c != '\n' && c != '<') c = *++argv;
1087: 
1088:                 *argv = '\0';
1089: 
1090:                 if ( c != '<' && c != '-') {    /*  case: rev  */
1091:                     nextrevpair->numfld = 1;
1092:                     continue;
1093:                 }
1094: 
1095:                 if ( (c =(*++argv)) == ',' || c == '\0' || c == ' '
1096:                       || c == '\t' || c == '\n' || c == ';') {/*  case: rev_  */
1097:                     nextrevpair->numfld = 2;
1098:                     continue;
1099:                 }
1100:             }
1101:             nextrevpair->endrev = argv;
1102:             while( c != ',' && c != ' ' && c != '\0' && c != '\t' && c != '<'
1103:                    && c != '\n' && c != '-' && c != ';')  c = *++argv;
1104: 
1105:             * argv = '\0';
1106:             if ( c == '<'){
1107:                 error("seperator expected near %s", nextrevpair->endrev);
1108:                 while( (c = *++argv) != ',' && c != ' ' && c != '\0' &&
1109:                         c != '\t' && c != '\n' && c != ';' ) ;
1110:                 revlist = nextrevpair->rnext;
1111:                 continue;
1112:             }
1113:             else  {
1114:                 if (flag)   /*  case:  -rev   */
1115:                     nextrevpair->numfld  = 3;
1116: 
1117:                 else     /*   rev1-rev2  appears  */
1118:                     nextrevpair->numfld = 4;
1119:             }
1120:         }
1121: }
1122: 
1123: 
1124: 
1125: choptail(strhead)
1126: char     * strhead;
1127: /*   function : chop off the last field of a branch or a revision number  */
1128: 
1129: {
1130:         char    *pt, *sp;
1131: 
1132:         for(pt = Nextdotstring-1; pt != strhead && *pt != '.'; pt--) ;
1133:         for(sp = strhead; sp < pt; sp++) *Nextdotstring++ = *sp;
1134: }

Defined functions

checkrevpair defined in line 1025; used 1 times
choptail defined in line 1125; used 2 times
extdate defined in line 721; used 3 times
extractdelta defined in line 765; used 1 times
exttree defined in line 540; used 3 times
getauthor defined in line 594; used 1 times
getdatepair defined in line 860; used 1 times
getlocker defined in line 562; used 1 times
getnumericrev defined in line 939; used 1 times
getrevpairs defined in line 1049; used 1 times
getscript defined in line 481; used 1 times
getstate defined in line 630; used 1 times
main defined in line 137; never used
procdate defined in line 832; used 2 times
putabranch defined in line 381; used 2 times
putadelta defined in line 398; used 3 times
putforest defined in line 365; used 2 times
putree defined in line 349; used 3 times
putrunk defined in line 329; used 1 times
readdeltalog defined in line 453; used 1 times
recentdate defined in line 691; used 3 times
trunclocks defined in line 663; used 1 times

Defined variables

Dotstring defined in line 127; used 1 times
Nextdotstring defined in line 128; used 27 times
RCSfilename defined in line 82; used 26 times
Revlst defined in line 130; used 7 times
authorlist defined in line 133; used 8 times
caller defined in line 85; used 2 times
datelist defined in line 129; used 7 times
descflag defined in line 90; used 11 times
duelst defined in line 129; used 7 times
gendeltas defined in line 88; never used
lockerlist defined in line 131; used 6 times
lockflag defined in line 96; used 4 times
numericrev defined in line 87; never used
onlyRCSflag defined in line 95; used 3 times
onlylockflag defined in line 93; used 3 times
rcsbaseid defined in line 57; never used
rcsid defined in line 4; never used
revlist defined in line 130; used 5 times
revno defined in line 97; used 4 times
rewriteflag defined in line 83; used 6 times
selectflag defined in line 90; used 6 times
selectop defined in line 90; used 7 times
statelist defined in line 132; used 5 times
targetdelta defined in line 89; never used
workfilename defined in line 82; used 10 times

Defined struct's

Datepairs defined in line 121; used 16 times
Revpairs defined in line 114; used 18 times
authors defined in line 109; used 16 times
lockers defined in line 99; used 12 times
stateattri defined in line 104; used 12 times
Last modified: 1983-05-12
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2505
Valid CSS Valid XHTML 1.0 Strict