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

Defined functions

checkrevpair defined in line 1073; used 1 times
choptail defined in line 1173; used 2 times
extdate defined in line 752; used 3 times
extractdelta defined in line 796; used 1 times
exttree defined in line 571; used 3 times
getauthor defined in line 625; used 1 times
getdatepair defined in line 891; used 1 times
getlocker defined in line 593; used 1 times
getnumericrev defined in line 970; used 1 times
getrevpairs defined in line 1097; used 1 times
getscript defined in line 512; used 1 times
getstate defined in line 661; used 1 times
main defined in line 161; never used
procdate defined in line 863; used 2 times
putabranch defined in line 412; used 2 times
putadelta defined in line 429; used 3 times
putforest defined in line 396; used 2 times
putree defined in line 380; used 3 times
putrunk defined in line 360; used 1 times
readdeltalog defined in line 484; used 1 times
recentdate defined in line 722; used 3 times
trunclocks defined in line 694; used 1 times

Defined variables

Dotstring defined in line 150; used 1 times
Nextdotstring defined in line 151; used 29 times
RCSfilename defined in line 110; used 31 times
Revlst defined in line 153; used 9 times
authorlist defined in line 157; used 8 times
branchflag defined in line 154; used 3 times
caller defined in line 112; used 2 times
datelist defined in line 152; used 7 times
descflag defined in line 113; used 11 times
duelst defined in line 152; used 7 times
lockerlist defined in line 155; used 6 times
lockflag defined in line 119; used 4 times
onlyRCSflag defined in line 118; used 3 times
onlylockflag defined in line 116; used 3 times
rcsbaseid defined in line 83; never used
rcsid defined in line 5; never used
revlist defined in line 153; used 5 times
revno defined in line 120; used 4 times
selectflag defined in line 113; used 6 times
selectop defined in line 113; used 8 times
statelist defined in line 156; used 5 times
workfilename defined in line 110; used 12 times

Defined struct's

Datepairs defined in line 144; used 16 times
Revpairs defined in line 137; used 22 times
authors defined in line 132; used 16 times
lockers defined in line 122; used 12 times
stateattri defined in line 127; used 12 times
Last modified: 1988-02-18
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2724
Valid CSS Valid XHTML 1.0 Strict