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

unix.superglobalmegacorp.com

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