1: /*
   2:  *                     RCS file name handling
   3:  */
   4:  static char rcsid[]=
   5:  "$Header: rcsfnms.c,v 3.9 86/05/15 02:24:55 lepreau Exp $ Purdue CS";
   6: /****************************************************************************
   7:  *                     creation and deletion of semaphorefile,
   8:  *                     creation of temporary filenames and cleanup()
   9:  *                     pairing of RCS file names and working file names.
  10:  *                     Testprogram: define PAIRTEST
  11:  ****************************************************************************
  12:  *
  13:  * Copyright (C) 1982 by Walter F. Tichy
  14:  *                       Purdue University
  15:  *                       Computer Science Department
  16:  *                       West Lafayette, IN 47907
  17:  *
  18:  * All rights reserved. No part of this software may be sold or distributed
  19:  * in any form or by any means without the prior written permission of the
  20:  * author.
  21:  * Report problems and direct all inquiries to Tichy@purdue (ARPA net).
  22:  */
  23: 
  24: 
  25: /* $Log:	rcsfnms.c,v $
  26:  * Revision 3.9  86/05/15  02:24:55  lepreau
  27:  * add suffix .el for gnulisp
  28:  *
  29:  * Revision 3.8  86/01/12  01:20:29  lepreau
  30:  * add suffixes csh,cl,sl,red for csh, common lisp,
  31:  * psl, and rlisp respectively.
  32:  *
  33:  * Revision 3.7  83/05/11  15:01:58  wft
  34:  * *** empty log message ***
  35:  *
  36:  * Revision 3.7  83/05/11  15:01:58  wft
  37:  * Added comtable[] which pairs file name suffixes with comment leaders;
  38:  * updated InitAdmin() accordingly.
  39:  *
  40:  * Revision 3.6  83/04/05  14:47:36  wft
  41:  * fixed Suffix in InitAdmin().
  42:  *
  43:  * Revision 3.5  83/01/17  18:01:04  wft
  44:  * Added getwd() and rename(); these can be removed by defining
  45:  * V4_2BSD, since they are not needed in 4.2 bsd.
  46:  * Changed sys/param.h to sys/types.h.
  47:  *
  48:  * Revision 3.4  82/12/08  21:55:20  wft
  49:  * removed unused variable.
  50:  *
  51:  * Revision 3.3  82/11/28  20:31:37  wft
  52:  * Changed mktempfile() to store the generated file names.
  53:  * Changed getfullRCSname() to store the file and pathname, and to
  54:  * delete leading "../" and "./".
  55:  *
  56:  * Revision 3.2  82/11/12  14:29:40  wft
  57:  * changed pairfilenames() to handle file.sfx,v; also deleted checkpathnosfx(),
  58:  * checksuffix(), checkfullpath(). Semaphore name generation updated.
  59:  * mktempfile() now checks for nil path; lastfilename initialized properly.
  60:  * Added Suffix .h to InitAdmin. Added testprogram PAIRTEST.
  61:  * Moved rmsema, trysema, trydiraccess, getfullRCSname from rcsutil.c to here.
  62:  *
  63:  * Revision 3.1  82/10/18  14:51:28  wft
  64:  * InitAdmin() now initializes StrictLocks=STRICT_LOCKING (def. in rcsbase.h).
  65:  * renamed checkpath() to checkfullpath().
  66:  */
  67: 
  68: 
  69: #include "rcsbase.h"
  70: extern char * rindex();
  71: extern char * mktemp();
  72: extern char * malloc();
  73: extern FILE * fopen();
  74: extern char * getwd();         /* get working directory; forward decl       */
  75: 
  76: extern FILE * finptr;          /* RCS input file descriptor                 */
  77: extern FILE * frewrite;        /* New RCS file descriptor                   */
  78: extern char * RCSfilename, * workfilename; /* filenames                     */
  79: 
  80: 
  81: 
  82: char tempfilename [NCPFN+10];  /* used for derived file names               */
  83: char subfilename  [NCPFN+14];  /* used for files RCS/file.sfx,v             */
  84: char semafilename [NCPPN];     /* name of semaphore file                    */
  85: int  madesema;                 /* indicates whether a semaphore file has been set */
  86: char * tfnames[10] =           /* temp. file names to be unlinked when finished   */
  87:        {nil,nil,nil,nil,nil,nil,nil,nil,nil,nil};
  88: int  lastfilename         = -1;/* index of last file name in tfnames[]      */
  89: 
  90: 
  91: struct compair {
  92:         char * suffix, * comlead;
  93: };
  94: 
  95: struct compair comtable[] = {
  96: /* comtable pairs each filename suffix with a comment leader. The comment   */
  97: /* leader is placed before each line generated by the $Log keyword. This    */
  98: /* table is used to guess the proper comment leader from the working file's */
  99: /* suffix during initial ci (see InitAdmin()). Comment leaders are needed   */
 100: /* for languages without multiline comments; for others they are optional.  */
 101:         "c",   " * ",   /* C           */
 102:         "h",   " * ",   /* C-header    */
 103:         "p",   " * ",   /* pascal      */
 104:         "sh",  "# ",    /* shell       */
 105:         "csh", "# ",    /* shell       */
 106:         "s",   "# ",    /* assembler   */
 107:         "sl",  "% ",    /* psl         */
 108:         "red", "% ",    /* psl/rlisp   */
 109:         "cl", ";;; ",    /* common lisp   */
 110:         "r",   "# ",    /* ratfor      */
 111:         "e",   "# ",    /* efl         */
 112:         "l",   " * ",   /* lex         NOTE: conflict between lex and franzlisp*/
 113:         "y",   " * ",   /* yacc        */
 114:         "yr",  " * ",   /* yacc-ratfor */
 115:         "ye",  " * ",   /* yacc-efl    */
 116:         "ml",  "; ",    /* mocklisp    */
 117:         "el",  "; ",    /* gnulisp     */
 118:         "mac", "; ",    /* macro       vms or dec-20 or pdp-11 macro */
 119:         "f",   "c ",    /* fortran     */
 120:         "ms",  "\\\" ", /* ms-macros   t/nroff*/
 121:         "me",  "\\\" ", /* me-macros   t/nroff*/
 122:         "",    "# ",    /* default for empty suffix */
 123:         nil,   ""       /* default for unknown suffix; must always be last */
 124: };
 125: 
 126: 
 127: 
 128: ffclose(fptr)
 129: FILE * fptr;
 130: /* Function: checks ferror(fptr) and aborts the program if there were
 131:  * errors; otherwise closes fptr.
 132:  */
 133: {       if (ferror(fptr) || fclose(fptr)==EOF)
 134:                 faterror("File read or write error; file system full?");
 135: }
 136: 
 137: 
 138: 
 139: int trysema(RCSfilename,makesema)
 140: char * RCSfilename; int makesema;
 141: /* Function: Checks whether a semaphore file exists for RCSfilename. If yes,
 142:  * returns false. If not, creates one if makesema==true and returns true
 143:  * if successful. If a semaphore file was created, madesema is set to true.
 144:  * The name of the semaphore file is put into variable semafilename.
 145:  */
 146: {
 147:         register char * tp, *sp, *lp;
 148:         int fdesc;
 149: 
 150:         sp=RCSfilename;
 151:         lp = rindex(sp,'/');
 152:         if (lp==0) {
 153:                 semafilename[0]='.'; semafilename[1]='/';
 154:                 tp= &semafilename[2];
 155:         } else {
 156:                 /* copy path */
 157:                 tp=semafilename;
 158:                 do *tp++ = *sp++; while (sp<=lp);
 159:         }
 160:         /*now insert `,' and append file name */
 161:         *tp++ = ',';
 162:         lp = rindex(sp, RCSSEP);
 163:         while (sp<lp) *tp++ = *sp++;
 164:         *tp++ = ','; *tp++ = '\0'; /* will be the same length as RCSfilename*/
 165: 
 166:         madesema = false;
 167:         if (access(semafilename, 0) == 0) {
 168:                 error("RCS file %s is in use",RCSfilename);
 169:                 return false;
 170:         }
 171:         if (makesema) {
 172:                 if ((fdesc=creat(semafilename, 000)) == -1) {
 173:                      error("Can't create semaphore file for RCS file %s",RCSfilename);
 174:                      return false;
 175:                 } else
 176:                      close(fdesc);
 177:                      madesema=true;
 178:         }
 179:         return true;
 180: }
 181: 
 182: 
 183: int rmsema()
 184: /* Function: delete the semaphore file if madeseam==true;
 185:  * sets madesema to false.
 186:  */
 187: {
 188:         if (madesema) {
 189:                 madesema=false;
 190:                 if (unlink(semafilename) == -1) {
 191:                         error("Can't find semaphore file %s",semafilename);
 192:                         return false;
 193:                 }
 194:         }
 195:         return true;
 196: }
 197: 
 198: 
 199: 
 200: InitCleanup()
 201: {       lastfilename =  -1;  /* initialize pointer */
 202: }
 203: 
 204: 
 205: cleanup()
 206: /* Function: closes input file and rewrite file.
 207:  * Unlinks files in tfnames[], deletes semaphore file.
 208:  */
 209: {
 210:         register int i;
 211: 
 212:         if (finptr!=NULL)   fclose(finptr);
 213:         if (frewrite!=NULL) fclose(frewrite);
 214:         for (i=0; i<=lastfilename; i++) {
 215:             if (tfnames[i][0]!='\0')  unlink(tfnames[i]);
 216:         }
 217:         InitCleanup();
 218:         return (rmsema());
 219: }
 220: 
 221: 
 222: char * mktempfile(fullpath,filename)
 223: register char * fullpath, * filename;
 224: /* Function: Creates a unique filename using the process id and stores it
 225:  * into a free slot in tfnames. The filename consists of the path contained
 226:  * in fullpath concatenated with filename. filename should end in "XXXXXX".
 227:  * Because of storage in tfnames, cleanup() can unlink the file later.
 228:  * lastfilename indicates the highest occupied slot in tfnames.
 229:  * Returns a pointer to the filename created.
 230:  * Example use: mktempfile("/tmp/", somefilename)
 231:  */
 232: {
 233:         register char * lastslash, *tp;
 234:         lastfilename++;
 235:         if ((tp=tfnames[lastfilename])==nil)
 236:               tp=tfnames[lastfilename] = malloc(NCPPN);
 237:         if (fullpath!=nil && (lastslash=rindex(fullpath,'/'))!=0) {
 238:                 /* copy path */
 239:                 while (fullpath<=lastslash) *tp++ = *fullpath++;
 240:         }
 241:         while (*tp++ = *filename++);
 242:         return (mktemp(tfnames[lastfilename]));
 243: }
 244: 
 245: 
 246: 
 247: 
 248: char * bindex(sp,c)
 249: register char * sp, c;
 250: /* Function: Finds the last occurrence of character c in string sp
 251:  * and returns a pointer to the character just beyond it. If the
 252:  * character doesn't occur in the string, sp is returned.
 253:  */
 254: {       register char * r;
 255:         r = sp;
 256:         while (*sp) {
 257:                 if (*sp++ == c) r=sp;
 258:         }
 259:         return r;
 260: }
 261: 
 262: 
 263: 
 264: InitAdmin()
 265: /* function: initializes an admin node */
 266: {       register char * Suffix;
 267:         register int i;
 268: 
 269:     Head=nil; AccessList=nil; Symbols=nil; Locks=nil;
 270:         StrictLocks=STRICT_LOCKING;
 271: 
 272:         /* guess the comment leader from the suffix*/
 273:         Suffix=bindex(workfilename, '.');
 274:         if (Suffix==workfilename) Suffix= ""; /* empty suffix; will get default*/
 275:         for (i=0;;i++) {
 276:                 if (comtable[i].suffix==nil) {
 277:                         Comment=comtable[i].comlead; /*default*/
 278:                         break;
 279:                 } elsif (strcmp(Suffix,comtable[i].suffix)==0) {
 280:                         Comment=comtable[i].comlead; /*default*/
 281:                         break;
 282:                 }
 283:         }
 284:         Lexinit(); /* Note: if finptr==NULL, reads nothing; only initializes*/
 285: }
 286: 
 287: 
 288: 
 289: 
 290: 
 291: 
 292: 
 293: char * findpairfile(argc, argv, fname)
 294: int argc; char * argv[], *fname;
 295: /* Function: Given a filename fname, findpairfile scans argv for a pathname
 296:  * ending in fname. If found, returns a pointer to the pathname, and sets
 297:  * the corresponding pointer in argv to nil. Otherwise returns fname.
 298:  * argc indicates the number of entries in argv. Some of them may be nil.
 299:  */
 300: {
 301:         register char * * next, * match;
 302:         register int count;
 303: 
 304:         for (next = argv, count = argc; count>0; next++,count--) {
 305:                 if ((*next != nil) && strcmp(bindex(*next,'/'),fname)==0) {
 306:                         /* bindex finds the beginning of the file name stem */
 307:                         match= *next;
 308:                         *next=nil;
 309:                         return match;
 310:                 }
 311:         }
 312:         return fname;
 313: }
 314: 
 315: 
 316: int pairfilenames(argc, argv, mustread, tostdout)
 317: int argc; char ** argv; int mustread, tostdout;
 318: /* Function: Pairs the filenames pointed to by argv; argc indicates
 319:  * how many there are.
 320:  * Places a pointer to the RCS filename into RCSfilename,
 321:  * and a pointer to the name of the working file into workfilename.
 322:  * If both the workfilename and the RCS filename are given, and tostdout
 323:  * is true, a warning is printed.
 324:  *
 325:  * If the RCS file exists, it is opened for reading, the file pointer
 326:  * is placed into finptr, and the admin-node is read in; returns 1.
 327:  * If the RCS file does not exist and mustread==true, an error is printed
 328:  * and 0 returned.
 329:  * If the RCS file does not exist and mustread==false, the admin node
 330:  * is initialized to empty (Head, AccessList, Locks, Symbols, StrictLocks),
 331:  * and -1 returned.
 332:  *
 333:  * 0 is returned on all errors.
 334:  * Also calls InitCleanup();
 335:  */
 336: {
 337:         register char * sp, * tp;
 338:         char * lastsep, * purefname, * pureRCSname;
 339:         int opened, returncode;
 340:         char * RCS1;
 341: 
 342:         if (*argv == nil) return 0; /* already paired filename */
 343: 
 344:         InitCleanup();
 345: 
 346:         /* first check suffix to see whether it is an RCS file or not */
 347:         purefname=bindex(*argv, '/'); /* skip path */
 348:         lastsep=rindex(purefname, RCSSEP);
 349:         if (lastsep!= 0 && *(lastsep+1)==RCSSUF && *(lastsep+2)=='\0') {
 350:                 /* RCS file name given*/
 351:                 RCS1=(*argv); pureRCSname=purefname;
 352:                 /* derive workfilename*/
 353:                 sp = purefname; tp=tempfilename;
 354:                 while (sp<lastsep) *tp++ = *sp++; *tp='\0';
 355:                 /* try to find workfile name among arguments */
 356:                 workfilename=findpairfile(argc-1,argv+1,tempfilename);
 357:                 if (strlen(pureRCSname)>NCPFN) {
 358:                         error("RCS file name %s too long",RCS1);
 359:                         return 0;
 360:                 }
 361:         } else {
 362:                 /* working file given; now try to find RCS file */
 363:                 workfilename= *argv;
 364:                 /* derive RCS file name*/
 365:                 sp=purefname; tp=tempfilename;
 366:                 while (*tp++ = *sp++);
 367:                 *(tp-1)=RCSSEP; *tp++=RCSSUF; *tp++='\0';
 368:                 /* Try to find RCS file name among arguments*/
 369:                 RCS1=findpairfile(argc-1,argv+1,tempfilename);
 370:                 pureRCSname=bindex(RCS1, '/');
 371:                 if (strlen(pureRCSname)>NCPFN) {
 372:                         error("working file name %s too long",workfilename);
 373:                         return 0;
 374:                 }
 375:         }
 376:         /* now we have a (tentative) RCS filename in RCS1 and workfilename  */
 377: 
 378:         if (pureRCSname!=RCS1) {
 379:                 /* a path for RCSfile is given; single RCS file to look for */
 380:                 finptr=fopen(RCSfilename=RCS1, "r");
 381:                 if (finptr!=NULL) {
 382:                     Lexinit(); getadmin();
 383:                     returncode=1;
 384:                 } else { /* could not open */
 385:                     if (access(RCSfilename,0)==0) {
 386:                         error("Can't open existing %s", RCSfilename);
 387:                         return 0;
 388:                     }
 389:                     if (mustread) {
 390:                         error("Can't find %s", RCSfilename);
 391:                         return 0;
 392:                     } else {
 393:                         /* initialize if not mustread */
 394:                         InitAdmin();
 395:                         returncode = -1;
 396:                     }
 397:                 }
 398:         } else {
 399:                 /* build second RCS file name by prefixing it with RCSDIR*/
 400:                 /* then try to open one of them */
 401:                 strcpy(subfilename,RCSDIR); strcat(subfilename,RCS1);
 402:                 opened=(
 403:                 ((finptr=fopen(RCSfilename=subfilename, "r"))!=NULL) ||
 404:                 ((finptr=fopen(RCSfilename=RCS1,"r"))!=NULL) );
 405: 
 406:                 if (opened) {
 407:                         /* open succeeded */
 408:                         Lexinit(); getadmin();
 409:                         returncode=1;
 410:                 } else {
 411:                         /* open failed; may be read protected */
 412:                         if ((access(RCSfilename=subfilename,0)==0) ||
 413:                             (access(RCSfilename=RCS1,0)==0)) {
 414:                                 error("Can't open existing %s",RCSfilename);
 415:                                 return 0;
 416:                         }
 417:                         if (mustread) {
 418:                                 error("Can't find %s nor %s",subfilename,RCS1);
 419:                                 return 0;
 420:                         } else {
 421:                                 /* initialize new file. Put into ./RCS if possible, strip off suffix*/
 422:                                 RCSfilename= (access(RCSDIR,0)==0)?subfilename:RCS1;
 423:                                 InitAdmin();
 424:                                 returncode= -1;
 425:                                 }
 426:                         }
 427:                 }
 428:                 if (tostdout&&
 429:                     !(RCS1==tempfilename||workfilename==tempfilename))
 430:                         /*The last term determines whether a pair of        */
 431:                         /* file names was given in the argument list        */
 432:                         warn("Option -p is set; ignoring output file %s",workfilename);
 433: 
 434:         return returncode;
 435: }
 436: 
 437: 
 438: char * getfullRCSname()
 439: /* Function: returns a pointer to the full path name of the RCS file.
 440:  * Calls getwd(), but only once.
 441:  * removes leading "../" and "./".
 442:  */
 443: {       static char pathbuf[NCPPN];
 444:         static char namebuf[NCPPN];
 445:         static int  pathlength =0;
 446: 
 447:         register char * realname, * lastpathchar;
 448:         register int  dotdotcounter, realpathlength;
 449: 
 450:         if (*RCSfilename=='/') {
 451:                 return(RCSfilename);
 452:         } else {
 453:                 if (pathlength==0) { /*call curdir for the first time*/
 454:                     if (getwd(pathbuf)==NULL)
 455:                         faterror("Can't build current directory path");
 456:                     pathlength=strlen(pathbuf);
 457:                     if (!((pathlength==1) && (pathbuf[0]=='/'))) {
 458:                         pathbuf[pathlength++]='/';
 459:                         /* Check needed because some getwd implementations */
 460:                         /* generate "/" for the root.                      */
 461:                     }
 462:                 }
 463:                 /*the following must be redone since RCSfilename may change*/
 464:                 /* find how many ../ to remvove from RCSfilename */
 465:                 dotdotcounter =0;
 466:                 realname = RCSfilename;
 467:                 while( realname[0]=='.' &&
 468:                       (realname[1]=='/'||(realname[1]=='.'&&realname[2]=='/'))){
 469:                         if (realname[1]=='/') {
 470:                             /* drop leading ./ */
 471:                             realname += 2;
 472:                         } else {
 473:                             /* drop leading ../ and remember */
 474:                             dotdotcounter++;
 475:                             realname += 3;
 476:                         }
 477:                 }
 478:                 /* now remove dotdotcounter trailing directories from pathbuf*/
 479:                 lastpathchar=pathbuf + pathlength-1;
 480:                 while (dotdotcounter>0 && lastpathchar>pathbuf) {
 481:                     /* move pointer backwards over trailing directory */
 482:                     lastpathchar--;
 483:                     if (*lastpathchar=='/') {
 484:                         dotdotcounter--;
 485:                     }
 486:                 }
 487:                 if (dotdotcounter>0) {
 488:                     error("Can't generate full path name for RCS file");
 489:                     return RCSfilename;
 490:                 } else {
 491:                     /* build full path name */
 492:                     realpathlength=lastpathchar-pathbuf+1;
 493:                     strncpy(namebuf,pathbuf,realpathlength);
 494:                     strcpy(&namebuf[realpathlength],realname);
 495:                     return(namebuf);
 496:                 }
 497:         }
 498: }
 499: 
 500: 
 501: 
 502: int trydiraccess(filename)
 503: char * filename;
 504: /* checks write permission in directory of filename and returns
 505:  * true if writable, false otherwise
 506:  */
 507: {
 508:         char pathname[NCPPN];
 509:         register char * tp, *sp, *lp;
 510:         lp = rindex(filename,'/');
 511:         if (lp==0) {
 512:                 /* check current directory */
 513:                 if (access(".",2)==0)
 514:                         return true;
 515:                 else {
 516:                         error("Current directory not writable");
 517:                         return false;
 518:                 }
 519:         }
 520:         /* copy path */
 521:         sp=filename;
 522:         tp=pathname;
 523:         do *tp++ = *sp++; while (sp<=lp);
 524:         *tp='\0';
 525:         if (access(pathname,2)==0)
 526:                 return true;
 527:         else {
 528:                 error("Directory %s not writable", pathname);
 529:                 return false;
 530:         }
 531: }
 532: 
 533: 
 534: 
 535: #ifndef V4_2BSD
 536: /* rename() and getwd() will be provided in bsd 4.2 */
 537: 
 538: 
 539: int rename(from, to)
 540: char * from, *to;
 541: /* Function: renames a file with the name given by from to the name given by to.
 542:  * unlinks the to-file if it already exists. returns -1 on error, 0 otherwise.
 543:  */
 544: {       unlink(to);      /* no need to check return code; will be caught by link*/
 545:                          /* no harm done if file "to" does not exist            */
 546:         if (link(from,to)<0) return -1;
 547:         return(unlink(from));
 548: }
 549: 
 550: 
 551: 
 552: #include        <sys/types.h>
 553: #include        <sys/stat.h>
 554: #include        <sys/dir.h>
 555: #define dot     "."
 556: #define dotdot  ".."
 557: 
 558: 
 559: 
 560: char * getwd(name)
 561: char * name;
 562: /* Function: places full pathname of current working directory into name and
 563:  * returns name on success, NULL on failure.
 564:  * getwd is an adaptation of pwd. May not return to the current directory on
 565:  * failure.
 566:  */
 567: {
 568:         FILE    *file;
 569:         struct  stat    d, dd;
 570:         char buf[2];    /* to NUL-terminate dir.d_name */
 571:         struct  direct  dir;
 572: 
 573:         int rdev, rino;
 574:         int off;
 575:         register i,j;
 576: 
 577:         name[off= 0] = '/';
 578:         name[1] = '\0';
 579:         buf[0] = '\0';
 580:         stat("/", &d);
 581:         rdev = d.st_dev;
 582:         rino = d.st_ino;
 583:         for (;;) {
 584:                 if (stat(dot, &d)<0) return NULL;
 585:                 if (d.st_ino==rino && d.st_dev==rdev) {
 586:                         if (name[off] == '/') name[off] = '\0';
 587:                         chdir(name); /*change back to current directory*/
 588:                         return name;
 589:                 }
 590:                 if ((file = fopen(dotdot,"r")) == NULL) return NULL;
 591:                 if (fstat(fileno(file), &dd)<0) goto fail;
 592:                 chdir(dotdot);
 593:                 if(d.st_dev == dd.st_dev) {
 594:                         if(d.st_ino == dd.st_ino) {
 595:                             if (name[off] == '/') name[off] = '\0';
 596:                             chdir(name); /*change back to current directory*/
 597:                             fclose(file);
 598:                             return name;
 599:                         }
 600:                         do {
 601:                             if (fread((char *)&dir, sizeof(dir), 1, file) !=1)
 602:                                 goto fail;
 603:                         } while (dir.d_ino != d.st_ino);
 604:                 }
 605:                 else do {
 606:                         if(fread((char *)&dir, sizeof(dir), 1, file) != 1) {
 607:                             goto fail;
 608:                         }
 609:                         stat(dir.d_name, &dd);
 610:                 } while(dd.st_ino != d.st_ino || dd.st_dev != d.st_dev);
 611:                 fclose(file);
 612: 
 613:                 /* concatenate file name */
 614:                 i = -1;
 615:                 while (dir.d_name[++i] != 0);
 616:                 for(j=off+1; j>0; --j)
 617:                         name[j+i+1] = name[j];
 618:                 off=i+off+1;
 619:                 name[i+1] = '/';
 620:                 for(--i; i>=0; --i)
 621:                         name[i+1] = dir.d_name[i];
 622:         } /* end for */
 623: 
 624: fail:   fclose(file);
 625:         return NULL;
 626: }
 627: 
 628: 
 629: #endif
 630: 
 631: 
 632: #ifdef PAIRTEST
 633: /* test program for pairfilenames() and getfullRCSname() */
 634: char * workfilename, *RCSfilename;
 635: 
 636: main(argc, argv)
 637: int argc; char *argv[];
 638: {
 639:         int result;
 640:         int initflag,tostdout;
 641:         tostdout=initflag=false;
 642:         cmdid="pair";
 643: 
 644:         while(--argc, ++argv, argc>=1 && ((*argv)[0] == '-')) {
 645:                 switch ((*argv)[1]) {
 646: 
 647:                 case 'p':       tostdout=true;
 648:                                 break;
 649:                 case 'i':       initflag=true;
 650:                                 break;
 651:                 }
 652:         }
 653: 
 654:         do {
 655:                 RCSfilename=workfilename=nil;
 656:                 result=pairfilenames(argc,argv,!initflag,tostdout);
 657:                 if (result!=0) {
 658:                      diagnose("RCSfile: %s; working file: %s",RCSfilename,workfilename);
 659:                      diagnose("Full RCS file name: %s", getfullRCSname());
 660:                 }
 661:                 switch (result) {
 662:                         case 0: continue; /* already paired file */
 663: 
 664:                         case 1: if (initflag) {
 665:                                     error("RCS file exists already");
 666:                                     continue;
 667:                                 } else {
 668:                                     diagnose("RCS file exists");
 669:                                 }
 670:                                 break;
 671: 
 672:                         case -1:diagnose("RCS file does not exist");
 673:                                 break;
 674:                 }
 675: 
 676:         } while (++argv, --argc>=1);
 677: 
 678: }
 679: #endif

Defined functions

InitAdmin defined in line 264; used 2 times
InitCleanup defined in line 200; used 2 times
bindex defined in line 248; used 7 times
findpairfile defined in line 293; used 2 times
getwd defined in line 560; used 2 times
main defined in line 636; never used
rename defined in line 539; used 5 times
rmsema defined in line 183; used 2 times

Defined variables

RCSfilename declared in line 78; defined in line 634; used 21 times
comtable defined in line 95; used 4 times
lastfilename defined in line 88; used 6 times
madesema defined in line 85; used 4 times
rcsid defined in line 4; never used
semafilename defined in line 84; used 8 times
subfilename defined in line 83; used 6 times
tempfilename defined in line 82; used 6 times
tfnames defined in line 86; used 5 times
workfilename declared in line 78; defined in line 634; used 9 times

Defined struct's

compair defined in line 91; used 2 times
  • in line 95(2)

Defined macros

dot defined in line 555; used 1 times
dotdot defined in line 556; used 2 times
Last modified: 1986-05-15
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2504
Valid CSS Valid XHTML 1.0 Strict