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