Annotation of 43BSDTahoe/new/rcs/src/rcsfnms.c, revision 1.1.1.1

1.1       root        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

unix.superglobalmegacorp.com

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