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