No empty .Rs/.Re
[netbsd-mini2440.git] / usr.bin / rcs / src / rcsfnms.c
blob937cb76b4825fd591d53656cf8bb9c351ba9f2c8
1 /*
2 * RCS file name handling
3 */
4 #ifndef lint
5 static char
6 rcsid[]= "$Id: rcsfnms.c,v 1.1 1993/03/21 09:58:08 cgd 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 ****************************************************************************
16 /* Copyright (C) 1982, 1988, 1989 Walter Tichy
17 * All rights reserved.
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.
29 * Report all problems and direct all questions to:
30 * rcs-bugs@cs.purdue.edu
44 /* $Log: rcsfnms.c,v $
45 * Revision 3.12 89/08/15 21:38:10 bostic
46 * Version 4 from Tom Narten at Purdue
48 * Revision 4.8 89/05/01 15:09:41 narten
49 * changed getwd to not stat empty directories.
51 * Revision 4.7 88/11/08 12:01:22 narten
52 * changes from eggert@sm.unisys.com (Paul Eggert)
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.
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)
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
65 * Revision 1.3 87/03/27 14:22:21 jenkins
66 * Port to suns
68 * Revision 1.2 85/06/26 07:34:28 svb
69 * Comment leader '% ' for '*.tex' files added.
71 * Revision 1.1 84/01/23 14:50:24 kcs
72 * Initial revision
74 * Revision 4.3 83/12/15 12:26:48 wft
75 * Added check for KDELIM in file names to pairfilenames().
77 * Revision 4.2 83/12/02 22:47:45 wft
78 * Added csh, red, and sl file name suffixes.
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.
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.
90 * Revision 3.6 83/04/05 14:47:36 wft
91 * fixed Suffix in InitAdmin().
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.
98 * Revision 3.4 82/12/08 21:55:20 wft
99 * removed unused variable.
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 "./".
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.
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().
119 #include "rcsbase.h"
120 #include <sys/types.h>
121 #include <sys/stat.h>
122 #include <sys/dir.h>
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();
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 */
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[] */
146 struct compair {
147 char * suffix, * comlead;
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 */
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
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 */
199 ffclose(fptr)
200 FILE * fptr;
201 /* Function: checks ferror(fptr) and aborts the program if there were
202 * errors; otherwise closes fptr.
204 { if (ferror(fptr) || fclose(fptr)==EOF)
205 faterror("File read or write error; file system full?");
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.
218 register char * tp, *sp, *lp;
219 int fdesc;
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);
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*/
237 madesema = false;
238 if (access(semafilename, 0) == 0) {
239 error("RCS file %s is in use",RCSname);
240 return false;
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;
250 return true;
254 rmsema()
255 /* Function: delete the semaphore file if madeseam==true;
256 * sets madesema to false.
259 if (madesema) {
260 madesema=false;
261 if (unlink(semafilename) == -1) {
262 error("Can't find semaphore file %s",semafilename);
269 InitCleanup()
270 { freefilename = 0; /* initialize pointer */
274 cleanup()
275 /* Function: closes input file and rewrite file.
276 * Unlinks files in tfnames[], deletes semaphore file.
279 register int i;
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]);
286 InitCleanup();
287 rmsema();
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)
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++;
309 while (*tp++ = *filename++);
310 return (mktemp(tfnames[freefilename++]));
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.
322 { register char * r;
323 r = sp;
324 while (*sp) {
325 if (*sp++ == c) r=sp;
327 return r;
334 InitAdmin()
335 /* function: initializes an admin node */
336 { register char * Suffix;
337 register int i;
339 Head=Dbranch=nil; AccessList=nil; Symbols=nil; Locks=nil;
340 StrictLocks=STRICT_LOCKING;
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;
354 Lexinit(); /* Note: if finptr==NULL, reads nothing; only initializes*/
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.
367 register char * * next, * match;
368 register int count;
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;
378 return fname;
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.
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.
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.
403 * 0 is returned on all errors. Files that are directories are errors.
404 * Also calls InitCleanup();
407 register char * sp, * tp;
408 char * lastsep, * purefname, * pureRCSname;
409 int opened, returncode;
410 char * RCS1;
411 char prefdir[NCPPN];
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;
419 InitCleanup();
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;
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;
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;
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;
469 if (mustread) {
470 error("Can't find %s", RCSfilename);
471 return 0;
472 } else {
473 /* initialize if not mustread */
474 returncode = -1;
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 */
489 VOID strcat(sub1filename,RCSDIR);
490 VOID strcpy(prefdir,sub1filename); /* preferred directory for RCS file*/
491 VOID strcat(sub1filename,RCS1); VOID strcat(sub2filename,RCS1);
494 opened=(
495 ((finptr=fopen(RCSfilename=sub1filename, "r"))!=NULL) ||
496 ((finptr=fopen(RCSfilename=sub2filename,"r"))!=NULL) );
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;
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;
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;
525 Lexinit(); getadmin();
526 } else { /* returncode == -1; RCS file nonexisting */
527 haveRCSstat = -1;
528 InitAdmin();
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);
537 return returncode;
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 "./".
546 { static char pathbuf[NCPPN];
547 static char namebuf[NCPPN];
548 static int pathlength;
550 register char * realname, * lastpathchar;
551 register int dotdotcounter, realpathlength;
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. */
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;
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--;
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);
605 int trydiraccess(filename)
606 char * filename;
607 /* checks write permission in directory of filename and returns
608 * true if writable, false otherwise
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;
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;
638 #ifndef V4_2BSD
639 /* rename() and getwd() will be provided in bsd 4.2 */
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.
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));
655 #define dot "."
656 #define dotdot ".."
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.
668 FILE *file;
669 struct stat d, dd;
670 char buf[2]; /* to NUL-terminate dir.d_name */
671 struct direct dir;
673 int rdev, rino;
674 int off;
675 register i,j;
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;
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;
700 do {
701 if (fread((char *)&dir, sizeof(dir), 1, file) !=1)
702 goto fail;
703 } while (dir.d_ino != d.st_ino);
705 else do {
706 if(fread((char *)&dir, sizeof(dir), 1, file) != 1) {
707 goto fail;
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);
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 */
727 fail: VOID fclose(file);
728 return NULL;
732 #endif
735 #ifdef PAIRTEST
736 /* test program for pairfilenames() and getfullRCSname() */
737 char * workfilename, *RCSfilename;
738 extern int quietflag;
740 main(argc, argv)
741 int argc; char *argv[];
743 int result;
744 int initflag,tostdout;
745 quietflag=tostdout=initflag=false;
746 cmdid="pair";
748 while(--argc, ++argv, argc>=1 && ((*argv)[0] == '-')) {
749 switch ((*argv)[1]) {
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;
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());
769 switch (result) {
770 case 0: continue; /* already paired file */
772 case 1: if (initflag) {
773 error("RCS file %s exists already",RCSfilename);
774 } else {
775 diagnose("RCS file %s exists",RCSfilename);
777 VOID fclose(finptr);
778 break;
780 case -1:diagnose("RCS file does not exist");
781 break;
784 } while (++argv, --argc>=1);
787 #endif