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

Defined functions

InitAdmin defined in line 312; used 1 times
InitCleanup defined in line 246; used 2 times
bindex defined in line 294; used 13 times
findpairfile defined in line 337; used 2 times
getwd defined in line 638; used 2 times
main defined in line 715; never used
rmsema defined in line 229; used 2 times

Defined variables

RCSfilename declared in line 107; defined in line 712; used 24 times
RCSstat defined in line 108; used 8 times
comtable defined in line 126; used 4 times
haveRCSstat defined in line 109; used 3 times
haveworkstat defined in line 109; used 4 times
lastfilename defined in line 119; used 6 times
madesema defined in line 116; used 4 times
rcsid defined in line 6; never used
semafilename defined in line 115; used 8 times
sub1filename defined in line 113; used 10 times
sub2filename defined in line 114; used 7 times
tempfilename defined in line 112; used 7 times
tfnames defined in line 117; used 5 times
workfilename declared in line 107; defined in line 712; used 11 times
workstat defined in line 108; used 5 times

Defined struct's

compair defined in line 122; used 2 times
  • in line 126(2)

Defined macros

dot defined in line 633; used 1 times
dotdot defined in line 634; used 2 times
Last modified: 1988-02-19
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 112
Valid CSS Valid XHTML 1.0 Strict