|
|
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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.