# 2.11BSD#431 - /usr/src/new/rcs/src/rcsfnms.c

##### Functions

    InitAdmin         X
    InitCleanup       X
    bindex            X
    cleanup           X
    ffclose           X
    findpairfile      X
    getfullRCSname    X
    getwd             X
    main              X
    mktempfile        X
    pairfilenames     X
    rename            X
    rmsema            X
    trydiraccess      X
    trysema           X

##### Variables

    RCSfilename       X
    RCSstat           X
    comtable          X
    haveRCSstat       X
    haveworkstat      X
    lastfilename      X
    madesema          X
    semafilename      X
    sub1filename      X
    sub2filename      X
    tempfilename      X
    tfnames           X
    workfilename      X
    workstat          X

##### Macros

    dot               X
    dotdot            X

##### struct's

    compair           X

       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

- in line 506

InitCleanup defined in line 246; used 2 times

- in line 263, 397

bindex defined in line 294; used 13 times

- in line 321, 349, 400, 423
- in /usr/src/new/rcs/src/rcs.c line 115, 986
- in /usr/src/new/rcs/src/rcsedit.c line 100-105(2), 442, 457, 466
- in /usr/src/new/rcs/src/rcsutil.c line 88, 360

cleanup defined in line 251; used 14 times

- in /usr/src/new/rcs/src/ci.c line 486, 521
- in /usr/src/new/rcs/src/co.c line 368
- in /usr/src/new/rcs/src/rcs.c line 561, 578
- in /usr/src/new/rcs/src/rcsclean.c line 42, 161, 181
- in /usr/src/new/rcs/src/rcsdiff.c line 77, 236, 258
- in /usr/src/new/rcs/src/rcsmerge.c line 57, 161
- in /usr/src/new/rcs/src/rcsutil.c line 254

ffclose defined in line 174; used 13 times

- in /usr/src/new/rcs/src/ci.c line 441, 478, 801(2)
- in /usr/src/new/rcs/src/co.c line 330
- in /usr/src/new/rcs/src/rcs.c line 553, 1008, 1466-1471(2)
- in /usr/src/new/rcs/src/rcsedit.c line 171
- in /usr/src/new/rcs/src/rcsgen.c line 139, 156, 163

findpairfile defined in line 337; used 2 times

- in line 409, 422

getfullRCSname defined in line 519; used 7 times

- in line 742
- in /usr/src/new/rcs/src/rcs.c line 131, 987
- in /usr/src/new/rcs/src/rcsedit.c line 106, 443, 472
- in /usr/src/new/rcs/src/rlog.c line 95

getwd defined in line 638; used 2 times

- in line 102, 535

main defined in line 715; never used
mktempfile defined in line 268; used 24 times

- in /usr/src/new/rcs/src/ci.c line 131, 426, 443, 794
- in /usr/src/new/rcs/src/co.c line 113, 309, 582-583(2)
- in /usr/src/new/rcs/src/rcs.c line 132, 527, 981, 1454, 1474
- in /usr/src/new/rcs/src/rcsclean.c line 43, 127
- in /usr/src/new/rcs/src/rcsdiff.c line 78, 207, 219
- in /usr/src/new/rcs/src/rcsedit.c line 99, 126-127(2)
- in /usr/src/new/rcs/src/rcsmerge.c line 58, 134-135(2)

pairfilenames defined in line 360; used 11 times

- in line 739
- in /usr/src/new/rcs/src/ci.c line 332
- in /usr/src/new/rcs/src/co.c line 249
- in /usr/src/new/rcs/src/rcs.c line 274, 427, 436
- in /usr/src/new/rcs/src/rcsclean.c line 101
- in /usr/src/new/rcs/src/rcsdiff.c line 176
- in /usr/src/new/rcs/src/rcsmerge.c line 110
- in /usr/src/new/rcs/src/rlog.c line 102, 252

rename defined in line 620; used 7 times

- in /usr/src/new/rcs/src/ci.c line 118, 481, 509
- in /usr/src/new/rcs/src/co.c line 103, 332, 354
- in /usr/src/new/rcs/src/rcs.c line 556

rmsema defined in line 229; used 2 times

- in line 264
- in /usr/src/new/rcs/src/co.c line 350

trydiraccess defined in line 583; used 3 times

- in /usr/src/new/rcs/src/ci.c line 360
- in /usr/src/new/rcs/src/co.c line 259
- in /usr/src/new/rcs/src/rcs.c line 452

trysema defined in line 185; used 7 times

- in /usr/src/new/rcs/src/ci.c line 362
- in /usr/src/new/rcs/src/co.c line 261
- in /usr/src/new/rcs/src/rcs.c line 454
- in /usr/src/new/rcs/src/rcsclean.c line 112
- in /usr/src/new/rcs/src/rcsdiff.c line 184
- in /usr/src/new/rcs/src/rcsmerge.c line 118
- in /usr/src/new/rcs/src/rlog.c line 259

#### Defined variables

RCSfilename declared in line 107; defined in line 712; used 24 times

- in line 185-186(2), 196, 214-219(2), 439-448(4), 473-474(2), 481-483(3), 491, 500, 531-532(2), 547, 570, 738-741(2), 748-750(2)

RCSstat defined in line 108; used 8 times

- in line 498-499(2)
- in /usr/src/new/rcs/src/ci.c line 491, 587, 756
- in /usr/src/new/rcs/src/co.c line 340, 363
- in /usr/src/new/rcs/src/rcs.c line 568

comtable defined in line 126; used 4 times

- in line 324-328(4)

haveRCSstat defined in line 109; used 3 times

- in line 498-499(2), 505

haveworkstat defined in line 109; used 4 times

- in line 431-432(2)
- in /usr/src/new/rcs/src/co.c line 391
- in /usr/src/new/rcs/src/rcs.c line 569

lastfilename defined in line 119; used 6 times

- in line 247, 260, 280-282(3), 288

madesema defined in line 116; used 4 times

- in line 212, 223, 234-235(2)

rcsid defined in line 6; never used
semafilename defined in line 115; used 8 times

- in line 199-203(4), 213-218(2), 236-237(2)

sub1filename defined in line 113; used 10 times

- in line 459-473(7), 481, 487-491(2)

sub2filename defined in line 114; used 7 times

- in line 459, 465-474(3), 482-491(3)

tempfilename defined in line 112; used 7 times

- in line 406-409(2), 418-422(2), 460, 510(2)

tfnames defined in line 117; used 5 times

- in line 261(2), 281-282(2), 288

workfilename declared in line 107; defined in line 712; used 11 times

- in line 321-322(2), 409, 416, 425, 431-433(2), 510-513(2), 738-741(2)

workstat defined in line 108; used 5 times

- in line 431-432(2)
- in /usr/src/new/rcs/src/ci.c line 491
- in /usr/src/new/rcs/src/co.c line 394
- in /usr/src/new/rcs/src/rcs.c line 570

#### 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

- in line 662

dotdot defined in line 634; used 2 times

- in line 668-670(2)

Last modified: 1988-02-19 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 1873 |