1: /*
   2:  *                     RCS revision number handling
   3:  */
   4: #ifndef lint
   5: static char rcsid[]= "$Id: rcsrev.c,v 4.3 87/10/18 10:38:42 narten Exp $ Purdue CS";
   6: #endif
   7: /*********************************************************************************
   8:  *********************************************************************************
   9:  *
  10:  * Copyright (C) 1982 by Walter F. 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:	rcsrev.c,v $
  23:  * Revision 4.3  87/10/18  10:38:42  narten
  24:  * Updating version numbers. Changes relative to version 1.1 actually
  25:  * relative to 4.1
  26:  *
  27:  * Revision 1.3  87/09/24  14:00:37  narten
  28:  * Sources now pass through lint (if you ignore printf/sprintf/fprintf
  29:  * warnings)
  30:  *
  31:  * Revision 1.2  87/03/27  14:22:37  jenkins
  32:  * Port to suns
  33:  *
  34:  * Revision 1.1  84/01/23  14:50:37  kcs
  35:  * Initial revision
  36:  *
  37:  * Revision 4.1  83/03/25  21:10:45  wft
  38:  * Only changed $Header to $Id.
  39:  *
  40:  * Revision 3.4  82/12/04  13:24:08  wft
  41:  * Replaced getdelta() with gettree().
  42:  *
  43:  * Revision 3.3  82/11/28  21:33:15  wft
  44:  * fixed compartial() and compnum() for nil-parameters; fixed nils
  45:  * in error messages. Testprogram output shortenend.
  46:  *
  47:  * Revision 3.2  82/10/18  21:19:47  wft
  48:  * renamed compnum->cmpnum, compnumfld->cmpnumfld,
  49:  * numericrevno->numricrevno.
  50:  *
  51:  * Revision 3.1  82/10/11  19:46:09  wft
  52:  * changed expandsym() to check for source==nil; returns zero length string
  53:  * in that case.
  54:  */
  55: 
  56: 
  57: 
  58: /*
  59: #define REVTEST
  60: /* version REVTEST is for testing the routines that generate a sequence
  61:  * of delta numbers needed to regenerate a given delta.
  62:  */
  63: 
  64: #include "rcsbase.h"
  65: 
  66: extern FILE * finptr;   /* RCS input file */
  67: extern char * getid();
  68: extern struct hshentry * getnum();
  69: extern int    getkey();
  70: extern int    getlex();
  71: 
  72: extern char * getkeyval();
  73: extern int delta(), deltatext();
  74: struct hshentry * genbranch(); /* forward */
  75: 
  76: 
  77: 
  78: int countnumflds(s)
  79: char * s;
  80: /* Given a pointer s to a dotted number (date or revision number),
  81:  * countnumflds returns the number of digitfields in s.
  82:  */
  83: {       register char * sp;
  84:         register int    count;
  85:         if ((sp=s)==nil) return(0);
  86:         if (*sp == '\0') return(0);
  87:         count = 1;
  88:         while (*sp) {
  89:                 if (*sp++ == '.') count++;
  90:         }
  91:         if (*(--sp) == '.') count--; /*trailing periods don't count*/
  92:         return(count);
  93: }
  94: 
  95: getbranchno(revno,branchno)
  96: char * revno, * branchno;
  97: /* Given a non-nil revision number revno, getbranchno copies the number of the branch
  98:  * on which revno is into branchnumber. If revno itself is a branch number,
  99:  * it is copied unchanged.
 100:  */
 101: {
 102:         register int i, numflds;
 103:         register char * tp, * sp;
 104: 
 105:         numflds=countnumflds(revno);
 106:         if (numflds%2 == 1)
 107:                 VOID strcpy(branchno,revno);
 108:         else {
 109:                 sp=revno; tp=branchno;
 110:                 for (i=1;i<numflds;i++) {
 111:                         while(*sp!='.') *tp++ = *sp++;
 112:                         *tp++ = *sp++;
 113:                 }
 114:                 *(tp-1)='\0';
 115:         }
 116: }
 117: 
 118: 
 119: 
 120: int cmpnum(num1, num2)
 121: char * num1, * num2;
 122: /* compares the two dotted numbers num1 and num2 lexicographically
 123:  * by field. Individual fields are compared numerically.
 124:  * returns <0, 0, >0 if num1<num2, num1==num2, and num1>num2, resp.
 125:  * omitted fields are assumed to be higher than the existing ones.
 126: */
 127: {
 128:         register char * s1, *s2;
 129:         register int n1, n2;
 130: 
 131:         s1=num1==nil?"":num1;
 132:         s2=num2==nil?"":num2;
 133: 
 134:         do {
 135:                 n1 = 0;
 136:                 while (('0' <= *s1) && (*s1 <= '9')) {
 137:                         n1 = n1*10 + (*s1 - '0');
 138:                         s1++;
 139:                 }
 140:                 /* skip '.' */
 141:                 if (*s1=='.') s1++;
 142: 
 143:                 n2 = 0;
 144:                 while (('0' <= *s2) && (*s2 <= '9')) {
 145:                         n2 = n2*10 + (*s2 - '0');
 146:                         s2++;
 147:                 }
 148:                 /* skip '.' */
 149:                 if (*s2=='.') s2++;
 150: 
 151:         } while ((n1==n2) && (*s1!='\0') && (*s2!='\0'));
 152: 
 153:         if (((*s1=='\0') && (*s2=='\0')) || (n1!=n2))
 154:                 return (n1 - n2);
 155:         /*now n1==n2 and one of s1 or s2 is shorter*/
 156:         /*give precedence to shorter one*/
 157:         if (*s1=='\0') return 1;
 158:         else           return -1;
 159: 
 160: }
 161: 
 162: 
 163: 
 164: int cmpnumfld(num1, num2, fld)
 165: char * num1, * num2; int fld;
 166: /* compares the two dotted numbers at field fld and returns
 167:  * num1[fld]-num2[fld]. Assumes that num1 and num2 have at least fld fields.
 168: */
 169: {
 170:         register char * s1, *s2;
 171:         register int n1, n2;
 172: 
 173:         s1=num1; n1=fld-1;
 174:         /* skip fld-1 fields */
 175:         while (n1) {
 176:                 while(*s1 != '.') s1++;
 177:                 n1--; s1++;
 178:         }
 179:         s2 = num2; n2=fld-1;
 180:         while (n2) {
 181:                 while(*s2 != '.') s2++;
 182:                 n2--; s2++;
 183:         }
 184:         /* Don't put the above into a single loop! */
 185:         /* Now s1 and s2 point to the beginning of the respective fields */
 186:         /* compute numerical value and compare */
 187:         n1 = 0;
 188:         while (('0' <= *s1) && (*s1 <= '9')) {
 189:                 n1 = n1*10 + (*s1 - '0');
 190:                 s1++;
 191:         }
 192:         n2 = 0;
 193:         while (('0' <= *s2) && (*s2 <= '9')) {
 194:                 n2 = n2*10 + (*s2 - '0');
 195:                 s2++;
 196:         }
 197:         return (n1 - n2);
 198: }
 199: 
 200: 
 201: int compartial(num1, num2, length)
 202: char    * num1;
 203: char    * num2;
 204: int     length;
 205: 
 206: /*   compare the first "length" fields of two dot numbers;
 207:      the omitted field is considered to be larger than any number  */
 208: /*   restriction:  at least one number has length or more fields   */
 209: 
 210: {
 211:         register        char    *s1, *s2;
 212:         register        int     n1, n2;
 213: 
 214: 
 215:         s1 = num1;      s2 = num2;
 216:         if ( s1==nil || *s1 == '\0' ) return 1;
 217:         if ( s2==nil || *s2 == '\0' ) return -1;
 218: 
 219:         do {
 220:             n1 = 0;
 221:             while( ('0' <= *s1) && (*s1 <= '9') ) {
 222:                 n1 = n1 * 10 + (*s1 - '0') ;
 223:                 s1++;
 224:             }
 225:             if ( *s1 == '.' ) s1++;    /*  skip .   */
 226: 
 227:             n2 = 0;
 228:             while( ( '0' <= *s2) && ( *s2 <= '9' ) ) {
 229:                    n2 = n2 * 10 + ( *s2 - '0' ) ;
 230:                 s2++;
 231:             }
 232:             if (*s2 == '.') s2++;
 233:         }   while(  ( n1 == n2) && ((--length) != 0) &&
 234:                     ( *s1 != '\0') && (*s2 != '\0')  );
 235: 
 236:         if ( (n1 != n2) || (length == 0) ){
 237:                 return(n1-n2);   }
 238: 
 239:         if ( *s1 == '\0' ) return 1;
 240:         if ( *s2 == '\0' ) return -1;
 241:     fprintf(stderr, "RCS Internal error, routine: compartial\n");
 242:     return(0);
 243: /*NOTREACHED*/
 244: }
 245: 
 246: 
 247: 
 248: incnum(onum,nnum)
 249: char * onum, *nnum;
 250: /* increments the last field of revision number onum by one and
 251:  * places the result into nnum
 252:  */
 253: {
 254:         register char * sp, *tp;
 255:         register int i;
 256: 
 257:         sp = onum; tp = nnum;
 258:         for (i=countnumflds(onum)-1; i>0; i--) {
 259:                 while (*sp != '.') *tp++ = *sp++;
 260:                 *tp++ = *sp++;  /* copy dot also */
 261:         }
 262:         VOID sprintf(tp,"%d",atoi(sp)+1);
 263: }
 264: 
 265: 
 266: char * partialno(rev1,rev2,length)
 267: char * rev1, * rev2; register int length;
 268: /* Function: Copies length fields of revision number rev2 into rev1.
 269:  * returns rev1.
 270:  */
 271: {       register char * r1,* r2;
 272: 
 273:         r1=rev1; r2=rev2;
 274:         while (length) {
 275:                 while(*r2 != '.' && *r2!='\0') *r1++ = *r2++;
 276:                 *r1++ = *r2++;
 277:                 length--;
 278:         }
 279:         /* eliminate last '.'*/
 280:         *(r1-1)='\0';
 281:         return rev1;
 282: }
 283: 
 284: 
 285: 
 286: char * getancestor(r1, r2, r3)
 287: char * r1, *r2, *r3;
 288: /* function: finds the common ancestor of r1 and r2 and
 289:  * places it into r3.
 290:  * returns r3 if successful, false otherwise.
 291:  * works reliably only if r1 and r2 are not branch numbers.
 292:  */
 293: {       int l1, l2, l3;
 294:         char t1[revlength], t2[revlength];
 295: 
 296:         l1=countnumflds(r1); l2=countnumflds(r2);
 297:         if ((l1<=2 && l2<=2)||(cmpnum(r1,r2)==0)) {
 298:                 /* on main trunk or identical */
 299:                 error("Common ancestor of %s and %s undefined.", r1, r2);
 300:                 return false;
 301:         }
 302: 
 303:         l3=0;
 304:         while ((cmpnumfld(r1, r2, l3+1)==0) && (cmpnumfld(r1, r2, l3+2)==0)){
 305:                 l3=l3+2;
 306:         }
 307:         /* This will terminate since r1 and r2 are not the same; see above*/
 308:         if (l3==0) {
 309:                 /* no common prefix. Common ancestor on main trunk. */
 310:                 VOID partialno(t1,r1,l1>2?2:l1); VOID partialno(t2,r2,l2>2?2:l2);
 311:                 if (cmpnum(t1,t2)<0)
 312:                         VOID strcpy(r3,t1);
 313:                 else    VOID strcpy(r3,t2);
 314:                 if ((cmpnum(r3,r1)==0)||(cmpnum(r3,r2)==0)) {
 315:                         error("Ancestor for %s and %s undefined.",r1,r2);
 316:                         return false;
 317:                 }
 318:                 return r3;
 319:         } else {
 320:                if (cmpnumfld(r1,r2,l3+1)==0) {
 321:                         error("Ancestor for %s and %s undefined.",r1,r2);
 322:                         return false;
 323:                 }
 324:                 return(partialno(r3,r1,l3));
 325:         }
 326: }
 327: 
 328: 
 329: 
 330: 
 331: struct hshentry * genrevs(revno,date,author,state,store)
 332: char * revno, * date, * author, * state;
 333: struct hshentry * * store;
 334: /* Function: finds the deltas needed for reconstructing the
 335:  * revision given by revno, date, author, and state, and stores pointers
 336:  * to these deltas into an array whose starting address is given by store.
 337:  * The last pointer stored is nil. The last delta (target delta) is returned.
 338:  * If the proper delta could not be found, nil is returned.
 339:  */
 340: {
 341:         int length;
 342:         register struct hshentry * next;
 343:         int result;
 344:         char * branchnum;
 345:         char t[revlength];
 346: 
 347:         if (Head == nil) {
 348:                 error("RCSfile empty.");
 349:                 return nil;
 350:         }
 351: 
 352:         length = countnumflds(revno);
 353:         next=Head;
 354: 
 355:         if (length >= 1) {
 356:                 /* at least one field; find branch exactly */
 357:                 while ((next!=nil) &&
 358:                        ((result=cmpnumfld(revno,next->num,1))<0)) {
 359:                         /*puts(next->num);*/
 360:                         *store++ = next;
 361:                         next = next->next;
 362:                 }
 363: 
 364:                 if (next==nil) {error("Branch number %s too low.",partialno(t,revno,1));return nil;}
 365:                 if (result>0)  {error("Branch number %s not present.",partialno(t,revno,1));return nil;}
 366:         }
 367:         if (length<=1){
 368:                 /* pick latest one on given branch */
 369:                 branchnum = next->num; /* works even for empty revno*/
 370:                 while ((next!=nil) &&
 371:                        (cmpnumfld(branchnum,next->num,1)==0) &&
 372:                        !(
 373:                         (date==nil?1:(cmpnum(date,next->date)>=0)) &&
 374:                         (author==nil?1:(strcmp(author,next->author)==0)) &&
 375:                         (state ==nil?1:(strcmp(state, next->state) ==0))
 376:                         )
 377:                        )
 378:                 {       /*puts(next->num);*/
 379:                         *store ++ = next;
 380:                         next=next->next;
 381:                 }
 382:                 if ((next==nil) ||
 383:                     (cmpnumfld(branchnum,next->num,1)!=0))/*overshot*/ {
 384:                         error("Cannot find revision on branch %s with a date before %s, author %s, and state %s.",
 385:                                 length==0?partialno(t,branchnum,1):revno,date==nil?"<now>":date,
 386:                                 author==nil?"<any>":author, state==nil?"<any>":state);
 387:                         return nil;
 388:                 } else {
 389:                         /*puts(next->num);*/
 390:                         *store++ = next;
 391:                 }
 392:                 *store = nil;
 393:                 return next;
 394:         }
 395: 
 396:         /* length >=2 */
 397:         /* find revision; may go low if length==2*/
 398:         while ((next!=nil) &&
 399:                ((result =cmpnumfld(revno,next->num,2)) <0) &&
 400:                (cmpnumfld(revno,next->num,1)==0) ) {
 401:                 /*puts(next->num);*/
 402:                 *store++ = next;
 403:                 next = next->next;
 404:         }
 405: 
 406:         if ((next==nil) || (cmpnumfld(revno,next->num,1)!=0)) {
 407:                 error("Revision number %s too low.",partialno(t,revno,2));
 408:                 return nil;
 409:         }
 410:         if ((length>2) && (result!=0)) {
 411:                 error("Revision %s not present.",partialno(t,revno,2));
 412:                 return nil;
 413:         }
 414: 
 415:         /* print last one */
 416:         /*puts(next->num);*/
 417:         *store++ = next;
 418: 
 419:         if (length>2)
 420:                 return genbranch(next,revno,length,date,author,state,store);
 421:         else { /* length == 2*/
 422:                 if ((date!=nil) && (cmpnum(date,next->date)<0)){
 423:                         error("Revision %s has date %s.",next->num, next->date);
 424:                         return nil;
 425:                 }
 426:                 if ((author!=nil)&&(strcmp(author,next->author)!=0)) {
 427:                         error("Revision %s has author %s.",next->num,next->author);
 428:                         return nil;
 429:                 }
 430:                 if ((state!=nil)&&(strcmp(state,next->state)!=0)) {
 431:                         error("Revision %s has state %s.",next->num,
 432:                                next->state==nil?"<empty>":next->state);
 433:                         return nil;
 434:                 }
 435:                 *store=nil;
 436:                 return next;
 437:         }
 438: }
 439: 
 440: 
 441: 
 442: 
 443: struct hshentry * genbranch(bpoint, revno, length,date,author,state,store)
 444: struct hshentry * bpoint;
 445: char * revno; int length;
 446: char * date, * author, * state;
 447: struct hshentry ** store;
 448: /* Function: given a branchpoint, a revision number, date, author, and state,
 449:  * genbranch finds the deltas necessary to reconstruct the given revision
 450:  * from the branch point on.
 451:  * Pointers to the found deltas are stored in an array beginning with store.
 452:  * revno must be on a side branch.
 453:  * return nil on error
 454:  */
 455: {
 456:         int field;
 457:         register struct hshentry * next, * trail;
 458:         register struct branchhead * bhead;
 459:         int result;
 460:         char t[revlength];
 461: 
 462:         bhead = bpoint->branches;
 463: 
 464:         for (field=3; field<=length; field=field+2) {
 465: 
 466:                 if (bhead==nil) {error("No side branches present for %s.",partialno(t,revno,field-1));return nil;}
 467: 
 468:                 /*find branch head*/
 469:                 /*branches are arranged in increasing order*/
 470:                 while ((bhead!=nil) &&
 471:                        ((result=cmpnumfld(revno,bhead->hsh->num,field))>0)) {
 472:                         bhead = bhead->nextbranch;
 473:                 }
 474: 
 475:                 if (bhead==nil) {error("Branch number %s too high.",partialno(t,revno,field));return nil;}
 476:                 if (result<0)   {error("Branch number %s not present.",partialno(t,revno,field));return nil;}
 477: 
 478:                 next = bhead->hsh;
 479:                 if (length==field) {
 480:                         /* pick latest one on that branch */
 481:                         trail=nil;
 482:                         do { if ((date==nil?1:(cmpnum(date,next->date)>=0)) &&
 483:                                  (author==nil?1:(strcmp(author,next->author)==0)) &&
 484:                                  (state ==nil?1:(strcmp(state, next->state) ==0))
 485:                              ) trail = next;
 486:                              next=next->next;
 487:                         } while (next!=nil);
 488: 
 489:                         if (trail==nil) {
 490:                              error("Cannot find revision on branch %s with a date before %s, author %s, and state %s.",
 491:                                         revno, date==nil?"<now>":date,
 492:                                         author==nil?"<any>":author, state==nil?"<any>":state);
 493:                              return nil;
 494:                         } else { /* print up to last one suitable */
 495:                              next = bhead->hsh;
 496:                              while (next!=trail) {
 497:                                   /*puts(next->num);*/
 498:                                   *store++ = next;
 499:                                   next=next->next;
 500:                              }
 501:                              /*puts(next->num);*/
 502:                              *store++ = next;
 503:                         }
 504:                         *store = nil;
 505:                         return next;
 506:                 }
 507: 
 508:                 /* length > field */
 509:                 /* find revision */
 510:                 /* check low */
 511:                 if (cmpnumfld(revno,next->num,field+1)<0) {
 512:                         error("Revision number %s too low.",partialno(t,revno,field+1));
 513:                         return(nil);
 514:                 }
 515:                 do {    /*puts(next->num);*/
 516:                         *store++ = next;
 517:                         trail = next;
 518:                         next = next->next;
 519:                 } while ((next!=nil) &&
 520:                        (cmpnumfld(revno,next->num,field+1) >=0));
 521: 
 522:                 if ((length>field+1) &&  /*need exact hit */
 523:                     (cmpnumfld(revno,trail->num,field+1) !=0)){
 524:                         error("Revision %s not present.",partialno(t,revno,field+1));
 525:                         return(nil);
 526:                 }
 527:                 if (length == field+1) {
 528:                         if ((date!=nil) && (cmpnum(date,trail->date)<0)){
 529:                                 error("Revision %s has date %s.",trail->num, trail->date);
 530:                                 return nil;
 531:                         }
 532:                         if ((author!=nil)&&(strcmp(author,trail->author)!=0)) {
 533:                                 error("Revision %s has author %s.",trail->num,trail->author);
 534:                                 return nil;
 535:                         }
 536:                         if ((state!=nil)&&(strcmp(state,trail->state)!=0)) {
 537:                                 error("Revision %s has state %s.",trail->num,
 538:                                        trail->state==nil?"<empty>":trail->state);
 539:                                 return nil;
 540:                         }
 541:                 }
 542:                 bhead = trail->branches;
 543: 
 544:         }
 545:         * store = nil;
 546:         return trail;
 547: }
 548: 
 549: 
 550: char * lookupsym(id)
 551: char * id;
 552: /* Function: looks up id in the list of symbolic names starting
 553:  * with pointer SYMBOLS, and returns a pointer to the corresponding
 554:  * revision number. Returns nil if not present.
 555:  */
 556: {
 557:         register struct assoc * next;
 558:         next = Symbols;
 559:         while (next!=nil) {
 560:                 if (strcmp(id, next->symbol)==0)
 561:                         return(next->delta->num);
 562:                 else    next=next->nextassoc;
 563:         }
 564:         return nil;
 565: }
 566: 
 567: int expandsym(source, target)
 568: char * source, * target;
 569: /* Function: Source points to a revision number. Expandsym copies
 570:  * the number to target, but replaces all symbolic fields in the
 571:  * source number with their numeric values.
 572:  * A trailing '.' is omitted; leading zeroes are compressed.
 573:  * returns false on error;
 574:  */
 575: {       register char * sp, * tp, *bp;
 576:         char symbuf[30];
 577:         register enum tokens d;
 578: 
 579:         sp = source; tp=target;
 580:         if (sp == nil) { /*accept nil pointer as a legal value*/
 581:                 *tp='\0';
 582:                 return true;
 583:         }
 584: 
 585:         while (*sp != '\0') {
 586:                 if (ctab[*sp] == DIGIT) {
 587:                         if (*sp=='0') {
 588:                                 /* skip leading zeroes */
 589:                                 sp++;
 590:                                 while(*sp == '0') sp++;
 591:                                 if (*sp=='\0' || *sp=='.') *tp++ = '0'; /*single zero*/
 592:                         }
 593:                         while(ctab[*sp] == DIGIT) *tp++ = *sp++;
 594:                         if ((*sp == '\0') || ((*sp=='.')&&(*(sp+1)=='\0'))) {
 595:                                 *tp='\0'; return true;
 596:                         }
 597:                         if (*sp == '.') *tp++ = *sp++;
 598:                         else {
 599:                             error("Improper revision number: %s",source);
 600:                             *tp = '\0';
 601:                             return false;
 602:                         }
 603:                 } elsif (ctab[*sp] == LETTER) {
 604:                         bp = symbuf;
 605:                         do {    *bp++ = *sp++;
 606:                         } while(((d=ctab[*sp])==LETTER) || (d==DIGIT) ||
 607:                               (d==IDCHAR));
 608:                         *bp= '\0';
 609:                         bp=lookupsym(symbuf);
 610:                         if (bp==nil) {
 611:                                 error("Symbolic number %s is undefined.",symbuf);
 612:                                 *tp='\0';
 613:                                 return false;
 614:                         } else { /* copy number */
 615:                                 while (*tp++ = *bp++); /* copies the trailing \0*/
 616:                         }
 617:                         if ((*sp == '\0') || ((*sp=='.')&&(*(sp+1)=='\0')))
 618:                                 return true;
 619:                         if (*sp == '.')  {
 620:                                 *(tp-1) = *sp++;
 621:                         } else {
 622:                                 error("Improper revision number: %s",source);
 623:                                 return false;
 624:                         }
 625:                 }else {
 626:                         error("Improper revision number: %s", source);
 627:                         *tp = '\0';
 628:                         return false;
 629:                 }
 630:         }
 631:         *tp = '\0';
 632:         return true;
 633: }
 634: 
 635: 
 636: 
 637: #ifdef REVTEST
 638: 
 639: main(argc,argv)
 640: int argc; char * argv[];
 641: {
 642:         char symrevno[revlength];       /* used for input of revision numbers */
 643:         char numricrevno[revlength];
 644:         char author[20];
 645:         char state[20];
 646:         char date[20];
 647:         struct hshentry * gendeltas[hshsize/2];
 648:         struct hshentry * target;
 649:         int i;
 650: 
 651:         cmdid = "revtest";
 652:         if (argc<2) {
 653:                 VOID fputs("No input file\n",stderr);
 654:                 exit(-1);
 655:         }
 656:         if ((finptr=fopen(argv[1], "r")) == NULL) {
 657:                 faterror("Can't open input file %s\n",argv[1]);
 658:         }
 659:         Lexinit();
 660:         getadmin();
 661: 
 662:         gettree();
 663: 
 664:         getdesc(false);
 665: 
 666:         do {
 667:                 /* all output goes to stderr, to have diagnostics and       */
 668:                 /* errors in sequence.                                      */
 669:                 VOID fprintf(stderr,"\nEnter revision number or <return> or '.': ");
 670:                 if(gets(symrevno)==NULL) break;
 671:                 if (*symrevno == '.') break;
 672:                 VOID fprintf(stderr,"%s;\n",symrevno);
 673:                 expandsym(symrevno,numricrevno);
 674:                 VOID fprintf(stderr,"expanded number: %s; ",numricrevno);
 675:                 VOID fprintf(stderr,"Date: ");
 676:                 gets(date); VOID fprintf(stderr,"%s; ",date);
 677:                 VOID fprintf(stderr,"Author: ");
 678:                 gets(author);VOID fprintf(stderr,"%s; ",author);
 679:                 VOID fprintf(stderr,"State: ");
 680:                 gets(state); VOID fprintf(stderr, "%s;\n", state);
 681:                 target=genrevs(numricrevno,*date=='\0'?(char *)nil:date, *author=='\0'?(char *)nil:author,
 682:                               *state=='\0'?(char *)nil:state,gendeltas);
 683:                 if (target!=nil) {
 684:                         i=0;
 685:                         while (gendeltas[i]!=nil) {
 686:                                 VOID fprintf(stderr,"%s\n",gendeltas[i++]->num);
 687:                         }
 688:                 }
 689:         } while (true);
 690:         VOID fprintf(stderr,"done\n");
 691: 
 692: }
 693: 
 694: cleanup(){}
 695: /*dummy*/
 696: 
 697: #endif REVTEST

Defined functions

cleanup defined in line 694; never used
cmpnum defined in line 120; used 30 times
cmpnumfld defined in line 164; used 16 times
compartial defined in line 201; used 9 times
genbranch defined in line 443; used 2 times
getancestor defined in line 286; used 2 times
incnum defined in line 248; used 6 times
lookupsym defined in line 550; used 1 times
main defined in line 639; never used
partialno defined in line 266; used 15 times

Defined variables

rcsid defined in line 5; never used
Last modified: 1988-02-19
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3824
Valid CSS Valid XHTML 1.0 Strict