Annotation of 43BSDReno/contrib/rcs/src/rlog.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.