1*86d7f5d3SJohn Marino /* RCS filename and pathname handling */
2*86d7f5d3SJohn Marino
3*86d7f5d3SJohn Marino /****************************************************************************
4*86d7f5d3SJohn Marino * creation and deletion of /tmp temporaries
5*86d7f5d3SJohn Marino * pairing of RCS pathnames and working pathnames.
6*86d7f5d3SJohn Marino * Testprogram: define PAIRTEST
7*86d7f5d3SJohn Marino ****************************************************************************
8*86d7f5d3SJohn Marino */
9*86d7f5d3SJohn Marino
10*86d7f5d3SJohn Marino /* Copyright 1982, 1988, 1989 Walter Tichy
11*86d7f5d3SJohn Marino Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
12*86d7f5d3SJohn Marino Distributed under license by the Free Software Foundation, Inc.
13*86d7f5d3SJohn Marino
14*86d7f5d3SJohn Marino This file is part of RCS.
15*86d7f5d3SJohn Marino
16*86d7f5d3SJohn Marino RCS is free software; you can redistribute it and/or modify
17*86d7f5d3SJohn Marino it under the terms of the GNU General Public License as published by
18*86d7f5d3SJohn Marino the Free Software Foundation; either version 2, or (at your option)
19*86d7f5d3SJohn Marino any later version.
20*86d7f5d3SJohn Marino
21*86d7f5d3SJohn Marino RCS is distributed in the hope that it will be useful,
22*86d7f5d3SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
23*86d7f5d3SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24*86d7f5d3SJohn Marino GNU General Public License for more details.
25*86d7f5d3SJohn Marino
26*86d7f5d3SJohn Marino You should have received a copy of the GNU General Public License
27*86d7f5d3SJohn Marino along with RCS; see the file COPYING.
28*86d7f5d3SJohn Marino If not, write to the Free Software Foundation,
29*86d7f5d3SJohn Marino 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30*86d7f5d3SJohn Marino
31*86d7f5d3SJohn Marino Report problems and direct all questions to:
32*86d7f5d3SJohn Marino
33*86d7f5d3SJohn Marino rcs-bugs@cs.purdue.edu
34*86d7f5d3SJohn Marino
35*86d7f5d3SJohn Marino */
36*86d7f5d3SJohn Marino
37*86d7f5d3SJohn Marino
38*86d7f5d3SJohn Marino
39*86d7f5d3SJohn Marino
40*86d7f5d3SJohn Marino /*
41*86d7f5d3SJohn Marino * $FreeBSD: src/gnu/usr.bin/rcs/lib/rcsfnms.c,v 1.10.2.1 2001/05/12 10:29:43 kris Exp $
42*86d7f5d3SJohn Marino * $DragonFly: src/gnu/usr.bin/rcs/lib/rcsfnms.c,v 1.2 2003/06/17 04:25:47 dillon Exp $
43*86d7f5d3SJohn Marino *
44*86d7f5d3SJohn Marino * Revision 5.16 1995/06/16 06:19:24 eggert
45*86d7f5d3SJohn Marino * Update FSF address.
46*86d7f5d3SJohn Marino *
47*86d7f5d3SJohn Marino * Revision 5.15 1995/06/01 16:23:43 eggert
48*86d7f5d3SJohn Marino * (basefilename): Renamed from basename to avoid collisions.
49*86d7f5d3SJohn Marino * (dirlen): Remove (for similar reasons).
50*86d7f5d3SJohn Marino * (rcsreadopen): Open with FOPEN_RB.
51*86d7f5d3SJohn Marino * (SLASHSLASH_is_SLASH): Default is 0.
52*86d7f5d3SJohn Marino * (getcwd): Work around bad_wait_if_SIGCHLD_ignored bug.
53*86d7f5d3SJohn Marino *
54*86d7f5d3SJohn Marino * Revision 5.14 1994/03/17 14:05:48 eggert
55*86d7f5d3SJohn Marino * Strip trailing SLASHes from TMPDIR; some systems need this. Remove lint.
56*86d7f5d3SJohn Marino *
57*86d7f5d3SJohn Marino * Revision 5.13 1993/11/03 17:42:27 eggert
58*86d7f5d3SJohn Marino * Determine whether a file name is too long indirectly,
59*86d7f5d3SJohn Marino * by examining inode numbers, instead of trying to use operating system
60*86d7f5d3SJohn Marino * primitives like pathconf, which are not trustworthy in general.
61*86d7f5d3SJohn Marino * File names may now hold white space or $.
62*86d7f5d3SJohn Marino * Do not flatten ../X in pathnames; that may yield wrong answer for symlinks.
63*86d7f5d3SJohn Marino * Add getabsname hook. Improve quality of diagnostics.
64*86d7f5d3SJohn Marino *
65*86d7f5d3SJohn Marino * Revision 5.12 1992/07/28 16:12:44 eggert
66*86d7f5d3SJohn Marino * Add .sty. .pl now implies Perl, not Prolog. Fix fdlock initialization bug.
67*86d7f5d3SJohn Marino * Check that $PWD is really ".". Be consistent about pathnames vs filenames.
68*86d7f5d3SJohn Marino *
69*86d7f5d3SJohn Marino * Revision 5.11 1992/02/17 23:02:25 eggert
70*86d7f5d3SJohn Marino * `a/RCS/b/c' is now an RCS file with an empty extension, not just `a/b/RCS/c'.
71*86d7f5d3SJohn Marino *
72*86d7f5d3SJohn Marino * Revision 5.10 1992/01/24 18:44:19 eggert
73*86d7f5d3SJohn Marino * Fix bug: Expand and Ignored weren't reinitialized.
74*86d7f5d3SJohn Marino * Avoid `char const c=ch;' compiler bug.
75*86d7f5d3SJohn Marino * Add support for bad_creat0.
76*86d7f5d3SJohn Marino *
77*86d7f5d3SJohn Marino * Revision 5.9 1992/01/06 02:42:34 eggert
78*86d7f5d3SJohn Marino * Shorten long (>31 chars) name.
79*86d7f5d3SJohn Marino * while (E) ; -> while (E) continue;
80*86d7f5d3SJohn Marino *
81*86d7f5d3SJohn Marino * Revision 5.8 1991/09/24 00:28:40 eggert
82*86d7f5d3SJohn Marino * Don't export bindex().
83*86d7f5d3SJohn Marino *
84*86d7f5d3SJohn Marino * Revision 5.7 1991/08/19 03:13:55 eggert
85*86d7f5d3SJohn Marino * Fix messages when rcswriteopen fails.
86*86d7f5d3SJohn Marino * Look in $TMP and $TEMP if $TMPDIR isn't set. Tune.
87*86d7f5d3SJohn Marino *
88*86d7f5d3SJohn Marino * Revision 5.6 1991/04/21 11:58:23 eggert
89*86d7f5d3SJohn Marino * Fix errno bugs. Add -x, RCSINIT, MS-DOS support.
90*86d7f5d3SJohn Marino *
91*86d7f5d3SJohn Marino * Revision 5.5 1991/02/26 17:48:38 eggert
92*86d7f5d3SJohn Marino * Fix setuid bug. Support new link behavior.
93*86d7f5d3SJohn Marino * Define more portable getcwd().
94*86d7f5d3SJohn Marino *
95*86d7f5d3SJohn Marino * Revision 5.4 1990/11/01 05:03:43 eggert
96*86d7f5d3SJohn Marino * Permit arbitrary data in comment leaders.
97*86d7f5d3SJohn Marino *
98*86d7f5d3SJohn Marino * Revision 5.3 1990/09/14 22:56:16 hammer
99*86d7f5d3SJohn Marino * added more filename extensions and their comment leaders
100*86d7f5d3SJohn Marino *
101*86d7f5d3SJohn Marino * Revision 5.2 1990/09/04 08:02:23 eggert
102*86d7f5d3SJohn Marino * Fix typo when !RCSSEP.
103*86d7f5d3SJohn Marino *
104*86d7f5d3SJohn Marino * Revision 5.1 1990/08/29 07:13:59 eggert
105*86d7f5d3SJohn Marino * Work around buggy compilers with defective argument promotion.
106*86d7f5d3SJohn Marino *
107*86d7f5d3SJohn Marino * Revision 5.0 1990/08/22 08:12:50 eggert
108*86d7f5d3SJohn Marino * Ignore signals when manipulating the semaphore file.
109*86d7f5d3SJohn Marino * Modernize list of filename extensions.
110*86d7f5d3SJohn Marino * Permit paths of arbitrary length. Beware filenames beginning with "-".
111*86d7f5d3SJohn Marino * Remove compile-time limits; use malloc instead.
112*86d7f5d3SJohn Marino * Permit dates past 1999/12/31. Make lock and temp files faster and safer.
113*86d7f5d3SJohn Marino * Ansify and Posixate.
114*86d7f5d3SJohn Marino * Don't use access(). Fix test for non-regular files. Tune.
115*86d7f5d3SJohn Marino *
116*86d7f5d3SJohn Marino * Revision 4.8 89/05/01 15:09:41 narten
117*86d7f5d3SJohn Marino * changed getwd to not stat empty directories.
118*86d7f5d3SJohn Marino *
119*86d7f5d3SJohn Marino * Revision 4.7 88/08/09 19:12:53 eggert
120*86d7f5d3SJohn Marino * Fix troff macro comment leader bug; add Prolog; allow cc -R; remove lint.
121*86d7f5d3SJohn Marino *
122*86d7f5d3SJohn Marino * Revision 4.6 87/12/18 11:40:23 narten
123*86d7f5d3SJohn Marino * additional file types added from 4.3 BSD version, and SPARC assembler
124*86d7f5d3SJohn Marino * comment character added. Also, more lint cleanups. (Guy Harris)
125*86d7f5d3SJohn Marino *
126*86d7f5d3SJohn Marino * Revision 4.5 87/10/18 10:34:16 narten
127*86d7f5d3SJohn Marino * Updating version numbers. Changes relative to 1.1 actually relative
128*86d7f5d3SJohn Marino * to verion 4.3
129*86d7f5d3SJohn Marino *
130*86d7f5d3SJohn Marino * Revision 1.3 87/03/27 14:22:21 jenkins
131*86d7f5d3SJohn Marino * Port to suns
132*86d7f5d3SJohn Marino *
133*86d7f5d3SJohn Marino * Revision 1.2 85/06/26 07:34:28 svb
134*86d7f5d3SJohn Marino * Comment leader '% ' for '*.tex' files added.
135*86d7f5d3SJohn Marino *
136*86d7f5d3SJohn Marino * Revision 4.3 83/12/15 12:26:48 wft
137*86d7f5d3SJohn Marino * Added check for KDELIM in filenames to pairfilenames().
138*86d7f5d3SJohn Marino *
139*86d7f5d3SJohn Marino * Revision 4.2 83/12/02 22:47:45 wft
140*86d7f5d3SJohn Marino * Added csh, red, and sl filename suffixes.
141*86d7f5d3SJohn Marino *
142*86d7f5d3SJohn Marino * Revision 4.1 83/05/11 16:23:39 wft
143*86d7f5d3SJohn Marino * Added initialization of Dbranch to InitAdmin(). Canged pairfilenames():
144*86d7f5d3SJohn Marino * 1. added copying of path from workfile to RCS file, if RCS file is omitted;
145*86d7f5d3SJohn Marino * 2. added getting the file status of RCS and working files;
146*86d7f5d3SJohn Marino * 3. added ignoring of directories.
147*86d7f5d3SJohn Marino *
148*86d7f5d3SJohn Marino * Revision 3.7 83/05/11 15:01:58 wft
149*86d7f5d3SJohn Marino * Added comtable[] which pairs filename suffixes with comment leaders;
150*86d7f5d3SJohn Marino * updated InitAdmin() accordingly.
151*86d7f5d3SJohn Marino *
152*86d7f5d3SJohn Marino * Revision 3.6 83/04/05 14:47:36 wft
153*86d7f5d3SJohn Marino * fixed Suffix in InitAdmin().
154*86d7f5d3SJohn Marino *
155*86d7f5d3SJohn Marino * Revision 3.5 83/01/17 18:01:04 wft
156*86d7f5d3SJohn Marino * Added getwd() and rename(); these can be removed by defining
157*86d7f5d3SJohn Marino * V4_2BSD, since they are not needed in 4.2 bsd.
158*86d7f5d3SJohn Marino * Changed sys/param.h to sys/types.h.
159*86d7f5d3SJohn Marino *
160*86d7f5d3SJohn Marino * Revision 3.4 82/12/08 21:55:20 wft
161*86d7f5d3SJohn Marino * removed unused variable.
162*86d7f5d3SJohn Marino *
163*86d7f5d3SJohn Marino * Revision 3.3 82/11/28 20:31:37 wft
164*86d7f5d3SJohn Marino * Changed mktempfile() to store the generated filenames.
165*86d7f5d3SJohn Marino * Changed getfullRCSname() to store the file and pathname, and to
166*86d7f5d3SJohn Marino * delete leading "../" and "./".
167*86d7f5d3SJohn Marino *
168*86d7f5d3SJohn Marino * Revision 3.2 82/11/12 14:29:40 wft
169*86d7f5d3SJohn Marino * changed pairfilenames() to handle file.sfx,v; also deleted checkpathnosfx(),
170*86d7f5d3SJohn Marino * checksuffix(), checkfullpath(). Semaphore name generation updated.
171*86d7f5d3SJohn Marino * mktempfile() now checks for nil path; freefilename initialized properly.
172*86d7f5d3SJohn Marino * Added Suffix .h to InitAdmin. Added testprogram PAIRTEST.
173*86d7f5d3SJohn Marino * Moved rmsema, trysema, trydiraccess, getfullRCSname from rcsutil.c to here.
174*86d7f5d3SJohn Marino *
175*86d7f5d3SJohn Marino * Revision 3.1 82/10/18 14:51:28 wft
176*86d7f5d3SJohn Marino * InitAdmin() now initializes StrictLocks=STRICT_LOCKING (def. in rcsbase.h).
177*86d7f5d3SJohn Marino * renamed checkpath() to checkfullpath().
178*86d7f5d3SJohn Marino */
179*86d7f5d3SJohn Marino
180*86d7f5d3SJohn Marino
181*86d7f5d3SJohn Marino #include "rcsbase.h"
182*86d7f5d3SJohn Marino
183*86d7f5d3SJohn Marino libId(fnmsId, "$DragonFly: src/gnu/usr.bin/rcs/lib/rcsfnms.c,v 1.2 2003/06/17 04:25:47 dillon Exp $")
184*86d7f5d3SJohn Marino
185*86d7f5d3SJohn Marino static char const *bindex P((char const*,int));
186*86d7f5d3SJohn Marino static int fin2open P((char const*, size_t, char const*, size_t, char const*, size_t, RILE*(*)P((struct buf*,struct stat*,int)), int));
187*86d7f5d3SJohn Marino static int finopen P((RILE*(*)P((struct buf*,struct stat*,int)), int));
188*86d7f5d3SJohn Marino static int suffix_matches P((char const*,char const*));
189*86d7f5d3SJohn Marino static size_t dir_useful_len P((char const*));
190*86d7f5d3SJohn Marino static size_t suffixlen P((char const*));
191*86d7f5d3SJohn Marino static void InitAdmin P((void));
192*86d7f5d3SJohn Marino
193*86d7f5d3SJohn Marino char const *RCSname;
194*86d7f5d3SJohn Marino char *workname;
195*86d7f5d3SJohn Marino int fdlock;
196*86d7f5d3SJohn Marino FILE *workstdout;
197*86d7f5d3SJohn Marino struct stat RCSstat;
198*86d7f5d3SJohn Marino char const *suffixes;
199*86d7f5d3SJohn Marino
200*86d7f5d3SJohn Marino static char const rcsdir[] = "RCS";
201*86d7f5d3SJohn Marino #define rcslen (sizeof(rcsdir)-1)
202*86d7f5d3SJohn Marino
203*86d7f5d3SJohn Marino static struct buf RCSbuf, RCSb;
204*86d7f5d3SJohn Marino static int RCSerrno;
205*86d7f5d3SJohn Marino
206*86d7f5d3SJohn Marino
207*86d7f5d3SJohn Marino /* Temp names to be unlinked when done, if they are not 0. */
208*86d7f5d3SJohn Marino #define TEMPNAMES 5 /* must be at least DIRTEMPNAMES (see rcsedit.c) */
209*86d7f5d3SJohn Marino static char *volatile tpnames[TEMPNAMES];
210*86d7f5d3SJohn Marino
211*86d7f5d3SJohn Marino
212*86d7f5d3SJohn Marino struct compair {
213*86d7f5d3SJohn Marino char const *suffix, *comlead;
214*86d7f5d3SJohn Marino };
215*86d7f5d3SJohn Marino
216*86d7f5d3SJohn Marino /*
217*86d7f5d3SJohn Marino * This table is present only for backwards compatibility.
218*86d7f5d3SJohn Marino * Normally we ignore this table, and use the prefix of the `$Log' line instead.
219*86d7f5d3SJohn Marino */
220*86d7f5d3SJohn Marino static struct compair const comtable[] = {
221*86d7f5d3SJohn Marino { "a" , "-- " }, /* Ada */
222*86d7f5d3SJohn Marino { "ada" , "-- " },
223*86d7f5d3SJohn Marino { "adb" , "-- " },
224*86d7f5d3SJohn Marino { "ads" , "-- " },
225*86d7f5d3SJohn Marino { "asm" , ";; " }, /* assembler (MS-DOS) */
226*86d7f5d3SJohn Marino { "bat" , ":: " }, /* batch (MS-DOS) */
227*86d7f5d3SJohn Marino { "body", "-- " }, /* Ada */
228*86d7f5d3SJohn Marino { "c" , " * " }, /* C */
229*86d7f5d3SJohn Marino { "c++" , "// " }, /* C++ in all its infinite guises */
230*86d7f5d3SJohn Marino { "cc" , "// " },
231*86d7f5d3SJohn Marino { "cpp" , "// " },
232*86d7f5d3SJohn Marino { "cxx" , "// " },
233*86d7f5d3SJohn Marino { "cl" , ";;; "}, /* Common Lisp */
234*86d7f5d3SJohn Marino { "cmd" , ":: " }, /* command (OS/2) */
235*86d7f5d3SJohn Marino { "cmf" , "c " }, /* CM Fortran */
236*86d7f5d3SJohn Marino { "cs" , " * " }, /* C* */
237*86d7f5d3SJohn Marino { "el" , "; " }, /* Emacs Lisp */
238*86d7f5d3SJohn Marino { "f" , "c " }, /* Fortran */
239*86d7f5d3SJohn Marino { "for" , "c " },
240*86d7f5d3SJohn Marino { "h" , " * " }, /* C-header */
241*86d7f5d3SJohn Marino { "hpp" , "// " }, /* C++ header */
242*86d7f5d3SJohn Marino { "hxx" , "// " },
243*86d7f5d3SJohn Marino { "l" , " * " }, /* lex (NOTE: franzlisp disagrees) */
244*86d7f5d3SJohn Marino { "lisp", ";;; "}, /* Lucid Lisp */
245*86d7f5d3SJohn Marino { "lsp" , ";; " }, /* Microsoft Lisp */
246*86d7f5d3SJohn Marino { "m" , "// " }, /* Objective C */
247*86d7f5d3SJohn Marino { "mac" , ";; " }, /* macro (DEC-10, MS-DOS, PDP-11, VMS, etc) */
248*86d7f5d3SJohn Marino { "me" , ".\\\" "}, /* troff -me */
249*86d7f5d3SJohn Marino { "ml" , "; " }, /* mocklisp */
250*86d7f5d3SJohn Marino { "mm" , ".\\\" "}, /* troff -mm */
251*86d7f5d3SJohn Marino { "ms" , ".\\\" "}, /* troff -ms */
252*86d7f5d3SJohn Marino { "p" , " * " }, /* Pascal */
253*86d7f5d3SJohn Marino { "pas" , " * " },
254*86d7f5d3SJohn Marino { "ps" , "% " }, /* PostScript */
255*86d7f5d3SJohn Marino { "spec", "-- " }, /* Ada */
256*86d7f5d3SJohn Marino { "sty" , "% " }, /* LaTeX style */
257*86d7f5d3SJohn Marino { "tex" , "% " }, /* TeX */
258*86d7f5d3SJohn Marino { "y" , " * " }, /* yacc */
259*86d7f5d3SJohn Marino { 0 , "# " } /* default for unknown suffix; must be last */
260*86d7f5d3SJohn Marino };
261*86d7f5d3SJohn Marino
262*86d7f5d3SJohn Marino #if has_mktemp
263*86d7f5d3SJohn Marino static char const *tmp P((void));
264*86d7f5d3SJohn Marino static char const *
tmp()265*86d7f5d3SJohn Marino tmp()
266*86d7f5d3SJohn Marino /* Yield the name of the tmp directory. */
267*86d7f5d3SJohn Marino {
268*86d7f5d3SJohn Marino static char const *s;
269*86d7f5d3SJohn Marino if (!s
270*86d7f5d3SJohn Marino && !(s = cgetenv("TMPDIR")) /* Unix tradition */
271*86d7f5d3SJohn Marino && !(s = cgetenv("TMP")) /* DOS tradition */
272*86d7f5d3SJohn Marino && !(s = cgetenv("TEMP")) /* another DOS tradition */
273*86d7f5d3SJohn Marino )
274*86d7f5d3SJohn Marino s = TMPDIR;
275*86d7f5d3SJohn Marino return s;
276*86d7f5d3SJohn Marino }
277*86d7f5d3SJohn Marino #endif
278*86d7f5d3SJohn Marino
279*86d7f5d3SJohn Marino char const *
maketemp(n)280*86d7f5d3SJohn Marino maketemp(n)
281*86d7f5d3SJohn Marino int n;
282*86d7f5d3SJohn Marino /* Create a unique pathname using n and the process id and store it
283*86d7f5d3SJohn Marino * into the nth slot in tpnames.
284*86d7f5d3SJohn Marino * Because of storage in tpnames, tempunlink() can unlink the file later.
285*86d7f5d3SJohn Marino * Return a pointer to the pathname created.
286*86d7f5d3SJohn Marino */
287*86d7f5d3SJohn Marino {
288*86d7f5d3SJohn Marino char *p;
289*86d7f5d3SJohn Marino char const *t = tpnames[n];
290*86d7f5d3SJohn Marino # if has_mktemp
291*86d7f5d3SJohn Marino int fd;
292*86d7f5d3SJohn Marino # endif
293*86d7f5d3SJohn Marino
294*86d7f5d3SJohn Marino if (t)
295*86d7f5d3SJohn Marino return t;
296*86d7f5d3SJohn Marino
297*86d7f5d3SJohn Marino catchints();
298*86d7f5d3SJohn Marino {
299*86d7f5d3SJohn Marino # if has_mktemp
300*86d7f5d3SJohn Marino char const *tp = tmp();
301*86d7f5d3SJohn Marino size_t tplen = dir_useful_len(tp);
302*86d7f5d3SJohn Marino p = testalloc(tplen + 10);
303*86d7f5d3SJohn Marino VOID sprintf(p, "%.*s%cT%cXXXXXX", (int)tplen, tp, SLASH, '0'+n);
304*86d7f5d3SJohn Marino fd = mkstemp(p);
305*86d7f5d3SJohn Marino if (fd < 0 || !*p)
306*86d7f5d3SJohn Marino faterror("can't make temporary pathname `%.*s%cT%cXXXXXX'",
307*86d7f5d3SJohn Marino (int)tplen, tp, SLASH, '0'+n
308*86d7f5d3SJohn Marino );
309*86d7f5d3SJohn Marino close(fd);
310*86d7f5d3SJohn Marino # else
311*86d7f5d3SJohn Marino static char tpnamebuf[TEMPNAMES][L_tmpnam];
312*86d7f5d3SJohn Marino p = tpnamebuf[n];
313*86d7f5d3SJohn Marino if (!tmpnam(p) || !*p)
314*86d7f5d3SJohn Marino # ifdef P_tmpdir
315*86d7f5d3SJohn Marino faterror("can't make temporary pathname `%s...'",P_tmpdir);
316*86d7f5d3SJohn Marino # else
317*86d7f5d3SJohn Marino faterror("can't make temporary pathname");
318*86d7f5d3SJohn Marino # endif
319*86d7f5d3SJohn Marino # endif
320*86d7f5d3SJohn Marino }
321*86d7f5d3SJohn Marino
322*86d7f5d3SJohn Marino tpnames[n] = p;
323*86d7f5d3SJohn Marino return p;
324*86d7f5d3SJohn Marino }
325*86d7f5d3SJohn Marino
326*86d7f5d3SJohn Marino void
tempunlink()327*86d7f5d3SJohn Marino tempunlink()
328*86d7f5d3SJohn Marino /* Clean up maketemp() files. May be invoked by signal handler.
329*86d7f5d3SJohn Marino */
330*86d7f5d3SJohn Marino {
331*86d7f5d3SJohn Marino register int i;
332*86d7f5d3SJohn Marino register char *p;
333*86d7f5d3SJohn Marino
334*86d7f5d3SJohn Marino for (i = TEMPNAMES; 0 <= --i; )
335*86d7f5d3SJohn Marino if ((p = tpnames[i])) {
336*86d7f5d3SJohn Marino VOID unlink(p);
337*86d7f5d3SJohn Marino /*
338*86d7f5d3SJohn Marino * We would tfree(p) here,
339*86d7f5d3SJohn Marino * but this might dump core if we're handing a signal.
340*86d7f5d3SJohn Marino * We're about to exit anyway, so we won't bother.
341*86d7f5d3SJohn Marino */
342*86d7f5d3SJohn Marino tpnames[i] = 0;
343*86d7f5d3SJohn Marino }
344*86d7f5d3SJohn Marino }
345*86d7f5d3SJohn Marino
346*86d7f5d3SJohn Marino
347*86d7f5d3SJohn Marino static char const *
bindex(sp,c)348*86d7f5d3SJohn Marino bindex(sp, c)
349*86d7f5d3SJohn Marino register char const *sp;
350*86d7f5d3SJohn Marino register int c;
351*86d7f5d3SJohn Marino /* Function: Finds the last occurrence of character c in string sp
352*86d7f5d3SJohn Marino * and returns a pointer to the character just beyond it. If the
353*86d7f5d3SJohn Marino * character doesn't occur in the string, sp is returned.
354*86d7f5d3SJohn Marino */
355*86d7f5d3SJohn Marino {
356*86d7f5d3SJohn Marino register char const *r;
357*86d7f5d3SJohn Marino r = sp;
358*86d7f5d3SJohn Marino while (*sp) {
359*86d7f5d3SJohn Marino if (*sp++ == c) r=sp;
360*86d7f5d3SJohn Marino }
361*86d7f5d3SJohn Marino return r;
362*86d7f5d3SJohn Marino }
363*86d7f5d3SJohn Marino
364*86d7f5d3SJohn Marino
365*86d7f5d3SJohn Marino
366*86d7f5d3SJohn Marino static int
suffix_matches(suffix,pattern)367*86d7f5d3SJohn Marino suffix_matches(suffix, pattern)
368*86d7f5d3SJohn Marino register char const *suffix, *pattern;
369*86d7f5d3SJohn Marino {
370*86d7f5d3SJohn Marino register int c;
371*86d7f5d3SJohn Marino if (!pattern)
372*86d7f5d3SJohn Marino return true;
373*86d7f5d3SJohn Marino for (;;)
374*86d7f5d3SJohn Marino switch (*suffix++ - (c = *pattern++)) {
375*86d7f5d3SJohn Marino case 0:
376*86d7f5d3SJohn Marino if (!c)
377*86d7f5d3SJohn Marino return true;
378*86d7f5d3SJohn Marino break;
379*86d7f5d3SJohn Marino
380*86d7f5d3SJohn Marino case 'A'-'a':
381*86d7f5d3SJohn Marino if (ctab[c] == Letter)
382*86d7f5d3SJohn Marino break;
383*86d7f5d3SJohn Marino /* fall into */
384*86d7f5d3SJohn Marino default:
385*86d7f5d3SJohn Marino return false;
386*86d7f5d3SJohn Marino }
387*86d7f5d3SJohn Marino }
388*86d7f5d3SJohn Marino
389*86d7f5d3SJohn Marino
390*86d7f5d3SJohn Marino static void
InitAdmin()391*86d7f5d3SJohn Marino InitAdmin()
392*86d7f5d3SJohn Marino /* function: initializes an admin node */
393*86d7f5d3SJohn Marino {
394*86d7f5d3SJohn Marino register char const *Suffix;
395*86d7f5d3SJohn Marino register int i;
396*86d7f5d3SJohn Marino
397*86d7f5d3SJohn Marino Head=0; Dbranch=0; AccessList=0; Symbols=0; Locks=0;
398*86d7f5d3SJohn Marino StrictLocks=STRICT_LOCKING;
399*86d7f5d3SJohn Marino
400*86d7f5d3SJohn Marino /* guess the comment leader from the suffix*/
401*86d7f5d3SJohn Marino Suffix = bindex(workname, '.');
402*86d7f5d3SJohn Marino if (Suffix==workname) Suffix= ""; /* empty suffix; will get default*/
403*86d7f5d3SJohn Marino for (i=0; !suffix_matches(Suffix,comtable[i].suffix); i++)
404*86d7f5d3SJohn Marino continue;
405*86d7f5d3SJohn Marino Comment.string = comtable[i].comlead;
406*86d7f5d3SJohn Marino Comment.size = strlen(comtable[i].comlead);
407*86d7f5d3SJohn Marino Expand = KEYVAL_EXPAND;
408*86d7f5d3SJohn Marino clear_buf(&Ignored);
409*86d7f5d3SJohn Marino Lexinit(); /* note: if !finptr, reads nothing; only initializes */
410*86d7f5d3SJohn Marino }
411*86d7f5d3SJohn Marino
412*86d7f5d3SJohn Marino
413*86d7f5d3SJohn Marino
414*86d7f5d3SJohn Marino void
bufalloc(b,size)415*86d7f5d3SJohn Marino bufalloc(b, size)
416*86d7f5d3SJohn Marino register struct buf *b;
417*86d7f5d3SJohn Marino size_t size;
418*86d7f5d3SJohn Marino /* Ensure *B is a name buffer of at least SIZE bytes.
419*86d7f5d3SJohn Marino * *B's old contents can be freed; *B's new contents are undefined.
420*86d7f5d3SJohn Marino */
421*86d7f5d3SJohn Marino {
422*86d7f5d3SJohn Marino if (b->size < size) {
423*86d7f5d3SJohn Marino if (b->size)
424*86d7f5d3SJohn Marino tfree(b->string);
425*86d7f5d3SJohn Marino else
426*86d7f5d3SJohn Marino b->size = sizeof(malloc_type);
427*86d7f5d3SJohn Marino while (b->size < size)
428*86d7f5d3SJohn Marino b->size <<= 1;
429*86d7f5d3SJohn Marino b->string = tnalloc(char, b->size);
430*86d7f5d3SJohn Marino }
431*86d7f5d3SJohn Marino }
432*86d7f5d3SJohn Marino
433*86d7f5d3SJohn Marino void
bufrealloc(b,size)434*86d7f5d3SJohn Marino bufrealloc(b, size)
435*86d7f5d3SJohn Marino register struct buf *b;
436*86d7f5d3SJohn Marino size_t size;
437*86d7f5d3SJohn Marino /* like bufalloc, except *B's old contents, if any, are preserved */
438*86d7f5d3SJohn Marino {
439*86d7f5d3SJohn Marino if (b->size < size) {
440*86d7f5d3SJohn Marino if (!b->size)
441*86d7f5d3SJohn Marino bufalloc(b, size);
442*86d7f5d3SJohn Marino else {
443*86d7f5d3SJohn Marino while ((b->size <<= 1) < size)
444*86d7f5d3SJohn Marino continue;
445*86d7f5d3SJohn Marino b->string = trealloc(char, b->string, b->size);
446*86d7f5d3SJohn Marino }
447*86d7f5d3SJohn Marino }
448*86d7f5d3SJohn Marino }
449*86d7f5d3SJohn Marino
450*86d7f5d3SJohn Marino void
bufautoend(b)451*86d7f5d3SJohn Marino bufautoend(b)
452*86d7f5d3SJohn Marino struct buf *b;
453*86d7f5d3SJohn Marino /* Free an auto buffer at block exit. */
454*86d7f5d3SJohn Marino {
455*86d7f5d3SJohn Marino if (b->size)
456*86d7f5d3SJohn Marino tfree(b->string);
457*86d7f5d3SJohn Marino }
458*86d7f5d3SJohn Marino
459*86d7f5d3SJohn Marino struct cbuf
bufremember(b,s)460*86d7f5d3SJohn Marino bufremember(b, s)
461*86d7f5d3SJohn Marino struct buf *b;
462*86d7f5d3SJohn Marino size_t s;
463*86d7f5d3SJohn Marino /*
464*86d7f5d3SJohn Marino * Free the buffer B with used size S.
465*86d7f5d3SJohn Marino * Yield a cbuf with identical contents.
466*86d7f5d3SJohn Marino * The cbuf will be reclaimed when this input file is finished.
467*86d7f5d3SJohn Marino */
468*86d7f5d3SJohn Marino {
469*86d7f5d3SJohn Marino struct cbuf cb;
470*86d7f5d3SJohn Marino
471*86d7f5d3SJohn Marino if ((cb.size = s))
472*86d7f5d3SJohn Marino cb.string = fremember(trealloc(char, b->string, s));
473*86d7f5d3SJohn Marino else {
474*86d7f5d3SJohn Marino bufautoend(b); /* not really auto */
475*86d7f5d3SJohn Marino cb.string = "";
476*86d7f5d3SJohn Marino }
477*86d7f5d3SJohn Marino return cb;
478*86d7f5d3SJohn Marino }
479*86d7f5d3SJohn Marino
480*86d7f5d3SJohn Marino char *
bufenlarge(b,alim)481*86d7f5d3SJohn Marino bufenlarge(b, alim)
482*86d7f5d3SJohn Marino register struct buf *b;
483*86d7f5d3SJohn Marino char const **alim;
484*86d7f5d3SJohn Marino /* Make *B larger. Set *ALIM to its new limit, and yield the relocated value
485*86d7f5d3SJohn Marino * of its old limit.
486*86d7f5d3SJohn Marino */
487*86d7f5d3SJohn Marino {
488*86d7f5d3SJohn Marino size_t s = b->size;
489*86d7f5d3SJohn Marino bufrealloc(b, s + 1);
490*86d7f5d3SJohn Marino *alim = b->string + b->size;
491*86d7f5d3SJohn Marino return b->string + s;
492*86d7f5d3SJohn Marino }
493*86d7f5d3SJohn Marino
494*86d7f5d3SJohn Marino void
bufscat(b,s)495*86d7f5d3SJohn Marino bufscat(b, s)
496*86d7f5d3SJohn Marino struct buf *b;
497*86d7f5d3SJohn Marino char const *s;
498*86d7f5d3SJohn Marino /* Concatenate S to B's end. */
499*86d7f5d3SJohn Marino {
500*86d7f5d3SJohn Marino size_t blen = b->string ? strlen(b->string) : 0;
501*86d7f5d3SJohn Marino bufrealloc(b, blen+strlen(s)+1);
502*86d7f5d3SJohn Marino VOID strcpy(b->string+blen, s);
503*86d7f5d3SJohn Marino }
504*86d7f5d3SJohn Marino
505*86d7f5d3SJohn Marino void
bufscpy(b,s)506*86d7f5d3SJohn Marino bufscpy(b, s)
507*86d7f5d3SJohn Marino struct buf *b;
508*86d7f5d3SJohn Marino char const *s;
509*86d7f5d3SJohn Marino /* Copy S into B. */
510*86d7f5d3SJohn Marino {
511*86d7f5d3SJohn Marino bufalloc(b, strlen(s)+1);
512*86d7f5d3SJohn Marino VOID strcpy(b->string, s);
513*86d7f5d3SJohn Marino }
514*86d7f5d3SJohn Marino
515*86d7f5d3SJohn Marino
516*86d7f5d3SJohn Marino char const *
basefilename(p)517*86d7f5d3SJohn Marino basefilename(p)
518*86d7f5d3SJohn Marino char const *p;
519*86d7f5d3SJohn Marino /* Yield the address of the base filename of the pathname P. */
520*86d7f5d3SJohn Marino {
521*86d7f5d3SJohn Marino register char const *b = p, *q = p;
522*86d7f5d3SJohn Marino for (;;)
523*86d7f5d3SJohn Marino switch (*q++) {
524*86d7f5d3SJohn Marino case SLASHes: b = q; break;
525*86d7f5d3SJohn Marino case 0: return b;
526*86d7f5d3SJohn Marino }
527*86d7f5d3SJohn Marino }
528*86d7f5d3SJohn Marino
529*86d7f5d3SJohn Marino
530*86d7f5d3SJohn Marino static size_t
suffixlen(x)531*86d7f5d3SJohn Marino suffixlen(x)
532*86d7f5d3SJohn Marino char const *x;
533*86d7f5d3SJohn Marino /* Yield the length of X, an RCS pathname suffix. */
534*86d7f5d3SJohn Marino {
535*86d7f5d3SJohn Marino register char const *p;
536*86d7f5d3SJohn Marino
537*86d7f5d3SJohn Marino p = x;
538*86d7f5d3SJohn Marino for (;;)
539*86d7f5d3SJohn Marino switch (*p) {
540*86d7f5d3SJohn Marino case 0: case SLASHes:
541*86d7f5d3SJohn Marino return p - x;
542*86d7f5d3SJohn Marino
543*86d7f5d3SJohn Marino default:
544*86d7f5d3SJohn Marino ++p;
545*86d7f5d3SJohn Marino continue;
546*86d7f5d3SJohn Marino }
547*86d7f5d3SJohn Marino }
548*86d7f5d3SJohn Marino
549*86d7f5d3SJohn Marino char const *
rcssuffix(name)550*86d7f5d3SJohn Marino rcssuffix(name)
551*86d7f5d3SJohn Marino char const *name;
552*86d7f5d3SJohn Marino /* Yield the suffix of NAME if it is an RCS pathname, 0 otherwise. */
553*86d7f5d3SJohn Marino {
554*86d7f5d3SJohn Marino char const *x, *p, *nz;
555*86d7f5d3SJohn Marino size_t nl, xl;
556*86d7f5d3SJohn Marino
557*86d7f5d3SJohn Marino nl = strlen(name);
558*86d7f5d3SJohn Marino nz = name + nl;
559*86d7f5d3SJohn Marino x = suffixes;
560*86d7f5d3SJohn Marino do {
561*86d7f5d3SJohn Marino if ((xl = suffixlen(x))) {
562*86d7f5d3SJohn Marino if (xl <= nl && memcmp(p = nz-xl, x, xl) == 0)
563*86d7f5d3SJohn Marino return p;
564*86d7f5d3SJohn Marino } else
565*86d7f5d3SJohn Marino for (p = name; p < nz - rcslen; p++)
566*86d7f5d3SJohn Marino if (
567*86d7f5d3SJohn Marino isSLASH(p[rcslen])
568*86d7f5d3SJohn Marino && (p==name || isSLASH(p[-1]))
569*86d7f5d3SJohn Marino && memcmp(p, rcsdir, rcslen) == 0
570*86d7f5d3SJohn Marino )
571*86d7f5d3SJohn Marino return nz;
572*86d7f5d3SJohn Marino x += xl;
573*86d7f5d3SJohn Marino } while (*x++);
574*86d7f5d3SJohn Marino return 0;
575*86d7f5d3SJohn Marino }
576*86d7f5d3SJohn Marino
577*86d7f5d3SJohn Marino /*ARGSUSED*/ RILE *
rcsreadopen(RCSpath,status,mustread)578*86d7f5d3SJohn Marino rcsreadopen(RCSpath, status, mustread)
579*86d7f5d3SJohn Marino struct buf *RCSpath;
580*86d7f5d3SJohn Marino struct stat *status;
581*86d7f5d3SJohn Marino int mustread;
582*86d7f5d3SJohn Marino /* Open RCSPATH for reading and yield its FILE* descriptor.
583*86d7f5d3SJohn Marino * If successful, set *STATUS to its status.
584*86d7f5d3SJohn Marino * Pass this routine to pairnames() for read-only access to the file. */
585*86d7f5d3SJohn Marino {
586*86d7f5d3SJohn Marino return Iopen(RCSpath->string, FOPEN_RB, status);
587*86d7f5d3SJohn Marino }
588*86d7f5d3SJohn Marino
589*86d7f5d3SJohn Marino static int
590*86d7f5d3SJohn Marino finopen(rcsopen, mustread)
591*86d7f5d3SJohn Marino RILE *(*rcsopen)P((struct buf*,struct stat*,int));
592*86d7f5d3SJohn Marino int mustread;
593*86d7f5d3SJohn Marino /*
594*86d7f5d3SJohn Marino * Use RCSOPEN to open an RCS file; MUSTREAD is set if the file must be read.
595*86d7f5d3SJohn Marino * Set finptr to the result and yield true if successful.
596*86d7f5d3SJohn Marino * RCSb holds the file's name.
597*86d7f5d3SJohn Marino * Set RCSbuf to the best RCS name found so far, and RCSerrno to its errno.
598*86d7f5d3SJohn Marino * Yield true if successful or if an unusual failure.
599*86d7f5d3SJohn Marino */
600*86d7f5d3SJohn Marino {
601*86d7f5d3SJohn Marino int interesting, preferold;
602*86d7f5d3SJohn Marino
603*86d7f5d3SJohn Marino /*
604*86d7f5d3SJohn Marino * We prefer an old name to that of a nonexisting new RCS file,
605*86d7f5d3SJohn Marino * unless we tried locking the old name and failed.
606*86d7f5d3SJohn Marino */
607*86d7f5d3SJohn Marino preferold = RCSbuf.string[0] && (mustread||0<=fdlock);
608*86d7f5d3SJohn Marino
609*86d7f5d3SJohn Marino finptr = (*rcsopen)(&RCSb, &RCSstat, mustread);
610*86d7f5d3SJohn Marino interesting = finptr || errno!=ENOENT;
611*86d7f5d3SJohn Marino if (interesting || !preferold) {
612*86d7f5d3SJohn Marino /* Use the new name. */
613*86d7f5d3SJohn Marino RCSerrno = errno;
614*86d7f5d3SJohn Marino bufscpy(&RCSbuf, RCSb.string);
615*86d7f5d3SJohn Marino }
616*86d7f5d3SJohn Marino return interesting;
617*86d7f5d3SJohn Marino }
618*86d7f5d3SJohn Marino
619*86d7f5d3SJohn Marino static int
fin2open(d,dlen,base,baselen,x,xlen,rcsopen,mustread)620*86d7f5d3SJohn Marino fin2open(d, dlen, base, baselen, x, xlen, rcsopen, mustread)
621*86d7f5d3SJohn Marino char const *d, *base, *x;
622*86d7f5d3SJohn Marino size_t dlen, baselen, xlen;
623*86d7f5d3SJohn Marino RILE *(*rcsopen)P((struct buf*,struct stat*,int));
624*86d7f5d3SJohn Marino int mustread;
625*86d7f5d3SJohn Marino /*
626*86d7f5d3SJohn Marino * D is a directory name with length DLEN (including trailing slash).
627*86d7f5d3SJohn Marino * BASE is a filename with length BASELEN.
628*86d7f5d3SJohn Marino * X is an RCS pathname suffix with length XLEN.
629*86d7f5d3SJohn Marino * Use RCSOPEN to open an RCS file; MUSTREAD is set if the file must be read.
630*86d7f5d3SJohn Marino * Yield true if successful.
631*86d7f5d3SJohn Marino * Try dRCS/basex first; if that fails and x is nonempty, try dbasex.
632*86d7f5d3SJohn Marino * Put these potential names in RCSb.
633*86d7f5d3SJohn Marino * Set RCSbuf to the best RCS name found so far, and RCSerrno to its errno.
634*86d7f5d3SJohn Marino * Yield true if successful or if an unusual failure.
635*86d7f5d3SJohn Marino */
636*86d7f5d3SJohn Marino {
637*86d7f5d3SJohn Marino register char *p;
638*86d7f5d3SJohn Marino
639*86d7f5d3SJohn Marino bufalloc(&RCSb, dlen + rcslen + 1 + baselen + xlen + 1);
640*86d7f5d3SJohn Marino
641*86d7f5d3SJohn Marino /* Try dRCS/basex. */
642*86d7f5d3SJohn Marino VOID memcpy(p = RCSb.string, d, dlen);
643*86d7f5d3SJohn Marino VOID memcpy(p += dlen, rcsdir, rcslen);
644*86d7f5d3SJohn Marino p += rcslen;
645*86d7f5d3SJohn Marino *p++ = SLASH;
646*86d7f5d3SJohn Marino VOID memcpy(p, base, baselen);
647*86d7f5d3SJohn Marino VOID memcpy(p += baselen, x, xlen);
648*86d7f5d3SJohn Marino p[xlen] = 0;
649*86d7f5d3SJohn Marino if (xlen) {
650*86d7f5d3SJohn Marino if (finopen(rcsopen, mustread))
651*86d7f5d3SJohn Marino return true;
652*86d7f5d3SJohn Marino
653*86d7f5d3SJohn Marino /* Try dbasex. */
654*86d7f5d3SJohn Marino /* Start from scratch, because finopen() may have changed RCSb. */
655*86d7f5d3SJohn Marino VOID memcpy(p = RCSb.string, d, dlen);
656*86d7f5d3SJohn Marino VOID memcpy(p += dlen, base, baselen);
657*86d7f5d3SJohn Marino VOID memcpy(p += baselen, x, xlen);
658*86d7f5d3SJohn Marino p[xlen] = 0;
659*86d7f5d3SJohn Marino }
660*86d7f5d3SJohn Marino return finopen(rcsopen, mustread);
661*86d7f5d3SJohn Marino }
662*86d7f5d3SJohn Marino
663*86d7f5d3SJohn Marino int
pairnames(argc,argv,rcsopen,mustread,quiet)664*86d7f5d3SJohn Marino pairnames(argc, argv, rcsopen, mustread, quiet)
665*86d7f5d3SJohn Marino int argc;
666*86d7f5d3SJohn Marino char **argv;
667*86d7f5d3SJohn Marino RILE *(*rcsopen)P((struct buf*,struct stat*,int));
668*86d7f5d3SJohn Marino int mustread, quiet;
669*86d7f5d3SJohn Marino /*
670*86d7f5d3SJohn Marino * Pair the pathnames pointed to by argv; argc indicates
671*86d7f5d3SJohn Marino * how many there are.
672*86d7f5d3SJohn Marino * Place a pointer to the RCS pathname into RCSname,
673*86d7f5d3SJohn Marino * and a pointer to the pathname of the working file into workname.
674*86d7f5d3SJohn Marino * If both are given, and workstdout
675*86d7f5d3SJohn Marino * is set, a warning is printed.
676*86d7f5d3SJohn Marino *
677*86d7f5d3SJohn Marino * If the RCS file exists, places its status into RCSstat.
678*86d7f5d3SJohn Marino *
679*86d7f5d3SJohn Marino * If the RCS file exists, it is RCSOPENed for reading, the file pointer
680*86d7f5d3SJohn Marino * is placed into finptr, and the admin-node is read in; returns 1.
681*86d7f5d3SJohn Marino * If the RCS file does not exist and MUSTREAD,
682*86d7f5d3SJohn Marino * print an error unless QUIET and return 0.
683*86d7f5d3SJohn Marino * Otherwise, initialize the admin node and return -1.
684*86d7f5d3SJohn Marino *
685*86d7f5d3SJohn Marino * 0 is returned on all errors, e.g. files that are not regular files.
686*86d7f5d3SJohn Marino */
687*86d7f5d3SJohn Marino {
688*86d7f5d3SJohn Marino static struct buf tempbuf;
689*86d7f5d3SJohn Marino
690*86d7f5d3SJohn Marino register char *p, *arg, *RCS1;
691*86d7f5d3SJohn Marino char const *base, *RCSbase, *x;
692*86d7f5d3SJohn Marino int paired;
693*86d7f5d3SJohn Marino size_t arglen, dlen, baselen, xlen;
694*86d7f5d3SJohn Marino
695*86d7f5d3SJohn Marino fdlock = -1;
696*86d7f5d3SJohn Marino
697*86d7f5d3SJohn Marino if (!(arg = *argv)) return 0; /* already paired pathname */
698*86d7f5d3SJohn Marino if (*arg == '-') {
699*86d7f5d3SJohn Marino error("%s option is ignored after pathnames", arg);
700*86d7f5d3SJohn Marino return 0;
701*86d7f5d3SJohn Marino }
702*86d7f5d3SJohn Marino
703*86d7f5d3SJohn Marino base = basefilename(arg);
704*86d7f5d3SJohn Marino paired = false;
705*86d7f5d3SJohn Marino
706*86d7f5d3SJohn Marino /* first check suffix to see whether it is an RCS file or not */
707*86d7f5d3SJohn Marino if ((x = rcssuffix(arg)))
708*86d7f5d3SJohn Marino {
709*86d7f5d3SJohn Marino /* RCS pathname given */
710*86d7f5d3SJohn Marino RCS1 = arg;
711*86d7f5d3SJohn Marino RCSbase = base;
712*86d7f5d3SJohn Marino baselen = x - base;
713*86d7f5d3SJohn Marino if (
714*86d7f5d3SJohn Marino 1 < argc &&
715*86d7f5d3SJohn Marino !rcssuffix(workname = p = argv[1]) &&
716*86d7f5d3SJohn Marino baselen <= (arglen = strlen(p)) &&
717*86d7f5d3SJohn Marino ((p+=arglen-baselen) == workname || isSLASH(p[-1])) &&
718*86d7f5d3SJohn Marino memcmp(base, p, baselen) == 0
719*86d7f5d3SJohn Marino ) {
720*86d7f5d3SJohn Marino argv[1] = 0;
721*86d7f5d3SJohn Marino paired = true;
722*86d7f5d3SJohn Marino } else {
723*86d7f5d3SJohn Marino bufscpy(&tempbuf, base);
724*86d7f5d3SJohn Marino workname = p = tempbuf.string;
725*86d7f5d3SJohn Marino p[baselen] = 0;
726*86d7f5d3SJohn Marino }
727*86d7f5d3SJohn Marino } else {
728*86d7f5d3SJohn Marino /* working file given; now try to find RCS file */
729*86d7f5d3SJohn Marino workname = arg;
730*86d7f5d3SJohn Marino baselen = strlen(base);
731*86d7f5d3SJohn Marino /* Derive RCS pathname. */
732*86d7f5d3SJohn Marino if (
733*86d7f5d3SJohn Marino 1 < argc &&
734*86d7f5d3SJohn Marino (x = rcssuffix(RCS1 = argv[1])) &&
735*86d7f5d3SJohn Marino baselen <= x - RCS1 &&
736*86d7f5d3SJohn Marino ((RCSbase=x-baselen)==RCS1 || isSLASH(RCSbase[-1])) &&
737*86d7f5d3SJohn Marino memcmp(base, RCSbase, baselen) == 0
738*86d7f5d3SJohn Marino ) {
739*86d7f5d3SJohn Marino argv[1] = 0;
740*86d7f5d3SJohn Marino paired = true;
741*86d7f5d3SJohn Marino } else
742*86d7f5d3SJohn Marino RCSbase = RCS1 = 0;
743*86d7f5d3SJohn Marino }
744*86d7f5d3SJohn Marino /* Now we have a (tentative) RCS pathname in RCS1 and workname. */
745*86d7f5d3SJohn Marino /* Second, try to find the right RCS file */
746*86d7f5d3SJohn Marino if (RCSbase!=RCS1) {
747*86d7f5d3SJohn Marino /* a path for RCSfile is given; single RCS file to look for */
748*86d7f5d3SJohn Marino bufscpy(&RCSbuf, RCS1);
749*86d7f5d3SJohn Marino finptr = (*rcsopen)(&RCSbuf, &RCSstat, mustread);
750*86d7f5d3SJohn Marino RCSerrno = errno;
751*86d7f5d3SJohn Marino } else {
752*86d7f5d3SJohn Marino bufscpy(&RCSbuf, "");
753*86d7f5d3SJohn Marino if (RCS1)
754*86d7f5d3SJohn Marino /* RCS filename was given without path. */
755*86d7f5d3SJohn Marino VOID fin2open(arg, (size_t)0, RCSbase, baselen,
756*86d7f5d3SJohn Marino x, strlen(x), rcsopen, mustread
757*86d7f5d3SJohn Marino );
758*86d7f5d3SJohn Marino else {
759*86d7f5d3SJohn Marino /* No RCS pathname was given. */
760*86d7f5d3SJohn Marino /* Try each suffix in turn. */
761*86d7f5d3SJohn Marino dlen = base-arg;
762*86d7f5d3SJohn Marino x = suffixes;
763*86d7f5d3SJohn Marino while (! fin2open(arg, dlen, base, baselen,
764*86d7f5d3SJohn Marino x, xlen=suffixlen(x), rcsopen, mustread
765*86d7f5d3SJohn Marino )) {
766*86d7f5d3SJohn Marino x += xlen;
767*86d7f5d3SJohn Marino if (!*x++)
768*86d7f5d3SJohn Marino break;
769*86d7f5d3SJohn Marino }
770*86d7f5d3SJohn Marino }
771*86d7f5d3SJohn Marino }
772*86d7f5d3SJohn Marino RCSname = p = RCSbuf.string;
773*86d7f5d3SJohn Marino if (finptr) {
774*86d7f5d3SJohn Marino if (!S_ISREG(RCSstat.st_mode)) {
775*86d7f5d3SJohn Marino error("%s isn't a regular file -- ignored", p);
776*86d7f5d3SJohn Marino return 0;
777*86d7f5d3SJohn Marino }
778*86d7f5d3SJohn Marino Lexinit(); getadmin();
779*86d7f5d3SJohn Marino } else {
780*86d7f5d3SJohn Marino if (RCSerrno!=ENOENT || mustread || fdlock<0) {
781*86d7f5d3SJohn Marino if (RCSerrno == EEXIST)
782*86d7f5d3SJohn Marino error("RCS file %s is in use", p);
783*86d7f5d3SJohn Marino else if (!quiet || RCSerrno!=ENOENT)
784*86d7f5d3SJohn Marino enerror(RCSerrno, p);
785*86d7f5d3SJohn Marino return 0;
786*86d7f5d3SJohn Marino }
787*86d7f5d3SJohn Marino InitAdmin();
788*86d7f5d3SJohn Marino };
789*86d7f5d3SJohn Marino
790*86d7f5d3SJohn Marino if (paired && workstdout)
791*86d7f5d3SJohn Marino workwarn("Working file ignored due to -p option");
792*86d7f5d3SJohn Marino
793*86d7f5d3SJohn Marino prevkeys = false;
794*86d7f5d3SJohn Marino return finptr ? 1 : -1;
795*86d7f5d3SJohn Marino }
796*86d7f5d3SJohn Marino
797*86d7f5d3SJohn Marino
798*86d7f5d3SJohn Marino char const *
getfullRCSname()799*86d7f5d3SJohn Marino getfullRCSname()
800*86d7f5d3SJohn Marino /*
801*86d7f5d3SJohn Marino * Return a pointer to the full pathname of the RCS file.
802*86d7f5d3SJohn Marino * Remove leading `./'.
803*86d7f5d3SJohn Marino */
804*86d7f5d3SJohn Marino {
805*86d7f5d3SJohn Marino if (ROOTPATH(RCSname)) {
806*86d7f5d3SJohn Marino return RCSname;
807*86d7f5d3SJohn Marino } else {
808*86d7f5d3SJohn Marino static struct buf rcsbuf;
809*86d7f5d3SJohn Marino # if needs_getabsname
810*86d7f5d3SJohn Marino bufalloc(&rcsbuf, SIZEABLE_PATH + 1);
811*86d7f5d3SJohn Marino while (getabsname(RCSname, rcsbuf.string, rcsbuf.size) != 0)
812*86d7f5d3SJohn Marino if (errno == ERANGE)
813*86d7f5d3SJohn Marino bufalloc(&rcsbuf, rcsbuf.size<<1);
814*86d7f5d3SJohn Marino else
815*86d7f5d3SJohn Marino efaterror("getabsname");
816*86d7f5d3SJohn Marino # else
817*86d7f5d3SJohn Marino static char const *wdptr;
818*86d7f5d3SJohn Marino static struct buf wdbuf;
819*86d7f5d3SJohn Marino static size_t wdlen;
820*86d7f5d3SJohn Marino
821*86d7f5d3SJohn Marino register char const *r;
822*86d7f5d3SJohn Marino register size_t dlen;
823*86d7f5d3SJohn Marino register char *d;
824*86d7f5d3SJohn Marino register char const *wd;
825*86d7f5d3SJohn Marino
826*86d7f5d3SJohn Marino if (!(wd = wdptr)) {
827*86d7f5d3SJohn Marino /* Get working directory for the first time. */
828*86d7f5d3SJohn Marino char *PWD = cgetenv("PWD");
829*86d7f5d3SJohn Marino struct stat PWDstat, dotstat;
830*86d7f5d3SJohn Marino if (! (
831*86d7f5d3SJohn Marino (d = PWD) &&
832*86d7f5d3SJohn Marino ROOTPATH(PWD) &&
833*86d7f5d3SJohn Marino stat(PWD, &PWDstat) == 0 &&
834*86d7f5d3SJohn Marino stat(".", &dotstat) == 0 &&
835*86d7f5d3SJohn Marino same_file(PWDstat, dotstat, 1)
836*86d7f5d3SJohn Marino )) {
837*86d7f5d3SJohn Marino bufalloc(&wdbuf, SIZEABLE_PATH + 1);
838*86d7f5d3SJohn Marino # if has_getcwd || !has_getwd
839*86d7f5d3SJohn Marino while (!(d = getcwd(wdbuf.string, wdbuf.size)))
840*86d7f5d3SJohn Marino if (errno == ERANGE)
841*86d7f5d3SJohn Marino bufalloc(&wdbuf, wdbuf.size<<1);
842*86d7f5d3SJohn Marino else if ((d = PWD))
843*86d7f5d3SJohn Marino break;
844*86d7f5d3SJohn Marino else
845*86d7f5d3SJohn Marino efaterror("getcwd");
846*86d7f5d3SJohn Marino # else
847*86d7f5d3SJohn Marino d = getwd(wdbuf.string);
848*86d7f5d3SJohn Marino if (!d && !(d = PWD))
849*86d7f5d3SJohn Marino efaterror("getwd");
850*86d7f5d3SJohn Marino # endif
851*86d7f5d3SJohn Marino }
852*86d7f5d3SJohn Marino wdlen = dir_useful_len(d);
853*86d7f5d3SJohn Marino d[wdlen] = 0;
854*86d7f5d3SJohn Marino wdptr = wd = d;
855*86d7f5d3SJohn Marino }
856*86d7f5d3SJohn Marino /*
857*86d7f5d3SJohn Marino * Remove leading `./'s from RCSname.
858*86d7f5d3SJohn Marino * Do not try to handle `../', since removing it may yield
859*86d7f5d3SJohn Marino * the wrong answer in the presence of symbolic links.
860*86d7f5d3SJohn Marino */
861*86d7f5d3SJohn Marino for (r = RCSname; r[0]=='.' && isSLASH(r[1]); r += 2)
862*86d7f5d3SJohn Marino /* `.////' is equivalent to `./'. */
863*86d7f5d3SJohn Marino while (isSLASH(r[2]))
864*86d7f5d3SJohn Marino r++;
865*86d7f5d3SJohn Marino /* Build full pathname. */
866*86d7f5d3SJohn Marino dlen = wdlen;
867*86d7f5d3SJohn Marino bufalloc(&rcsbuf, dlen + strlen(r) + 2);
868*86d7f5d3SJohn Marino d = rcsbuf.string;
869*86d7f5d3SJohn Marino VOID memcpy(d, wd, dlen);
870*86d7f5d3SJohn Marino d += dlen;
871*86d7f5d3SJohn Marino *d++ = SLASH;
872*86d7f5d3SJohn Marino VOID strcpy(d, r);
873*86d7f5d3SJohn Marino # endif
874*86d7f5d3SJohn Marino return rcsbuf.string;
875*86d7f5d3SJohn Marino }
876*86d7f5d3SJohn Marino }
877*86d7f5d3SJohn Marino
878*86d7f5d3SJohn Marino /* Derived from code from the XFree86 project */
879*86d7f5d3SJohn Marino char const *
getfullCVSname()880*86d7f5d3SJohn Marino getfullCVSname()
881*86d7f5d3SJohn Marino /* Function: returns a pointer to the path name of the RCS file with the
882*86d7f5d3SJohn Marino * CVSROOT part stripped off, and with 'Attic/' stripped off (if present).
883*86d7f5d3SJohn Marino */
884*86d7f5d3SJohn Marino {
885*86d7f5d3SJohn Marino
886*86d7f5d3SJohn Marino #define ATTICDIR "/Attic"
887*86d7f5d3SJohn Marino
888*86d7f5d3SJohn Marino char const *namebuf = getfullRCSname();
889*86d7f5d3SJohn Marino char *cvsroot = cgetenv("CVSROOT");
890*86d7f5d3SJohn Marino int cvsrootlen;
891*86d7f5d3SJohn Marino char *c = NULL;
892*86d7f5d3SJohn Marino int alen = strlen(ATTICDIR);
893*86d7f5d3SJohn Marino
894*86d7f5d3SJohn Marino if ((c = strrchr(namebuf, '/')) != NULL) {
895*86d7f5d3SJohn Marino if (namebuf - c >= alen) {
896*86d7f5d3SJohn Marino if (!strncmp(c - alen, ATTICDIR, alen)) {
897*86d7f5d3SJohn Marino while(*c != '\0') {
898*86d7f5d3SJohn Marino *(c - alen) = *c;
899*86d7f5d3SJohn Marino c++;
900*86d7f5d3SJohn Marino }
901*86d7f5d3SJohn Marino *(c - alen) = '\0';
902*86d7f5d3SJohn Marino }
903*86d7f5d3SJohn Marino }
904*86d7f5d3SJohn Marino }
905*86d7f5d3SJohn Marino
906*86d7f5d3SJohn Marino if (!cvsroot)
907*86d7f5d3SJohn Marino return(namebuf);
908*86d7f5d3SJohn Marino else
909*86d7f5d3SJohn Marino {
910*86d7f5d3SJohn Marino cvsrootlen = strlen(cvsroot);
911*86d7f5d3SJohn Marino if (!strncmp(namebuf, cvsroot, cvsrootlen) &&
912*86d7f5d3SJohn Marino namebuf[cvsrootlen] == '/')
913*86d7f5d3SJohn Marino return(namebuf + cvsrootlen + 1);
914*86d7f5d3SJohn Marino else
915*86d7f5d3SJohn Marino return(namebuf);
916*86d7f5d3SJohn Marino }
917*86d7f5d3SJohn Marino }
918*86d7f5d3SJohn Marino
919*86d7f5d3SJohn Marino static size_t
dir_useful_len(d)920*86d7f5d3SJohn Marino dir_useful_len(d)
921*86d7f5d3SJohn Marino char const *d;
922*86d7f5d3SJohn Marino /*
923*86d7f5d3SJohn Marino * D names a directory; yield the number of characters of D's useful part.
924*86d7f5d3SJohn Marino * To create a file in D, append a SLASH and a file name to D's useful part.
925*86d7f5d3SJohn Marino * Ignore trailing slashes if possible; not only are they ugly,
926*86d7f5d3SJohn Marino * but some non-Posix systems misbehave unless the slashes are omitted.
927*86d7f5d3SJohn Marino */
928*86d7f5d3SJohn Marino {
929*86d7f5d3SJohn Marino # ifndef SLASHSLASH_is_SLASH
930*86d7f5d3SJohn Marino # define SLASHSLASH_is_SLASH 0
931*86d7f5d3SJohn Marino # endif
932*86d7f5d3SJohn Marino size_t dlen = strlen(d);
933*86d7f5d3SJohn Marino if (!SLASHSLASH_is_SLASH && dlen==2 && isSLASH(d[0]) && isSLASH(d[1]))
934*86d7f5d3SJohn Marino --dlen;
935*86d7f5d3SJohn Marino else
936*86d7f5d3SJohn Marino while (dlen && isSLASH(d[dlen-1]))
937*86d7f5d3SJohn Marino --dlen;
938*86d7f5d3SJohn Marino return dlen;
939*86d7f5d3SJohn Marino }
940*86d7f5d3SJohn Marino
941*86d7f5d3SJohn Marino #ifndef isSLASH
942*86d7f5d3SJohn Marino int
isSLASH(c)943*86d7f5d3SJohn Marino isSLASH(c)
944*86d7f5d3SJohn Marino int c;
945*86d7f5d3SJohn Marino {
946*86d7f5d3SJohn Marino switch (c) {
947*86d7f5d3SJohn Marino case SLASHes:
948*86d7f5d3SJohn Marino return true;
949*86d7f5d3SJohn Marino default:
950*86d7f5d3SJohn Marino return false;
951*86d7f5d3SJohn Marino }
952*86d7f5d3SJohn Marino }
953*86d7f5d3SJohn Marino #endif
954*86d7f5d3SJohn Marino
955*86d7f5d3SJohn Marino
956*86d7f5d3SJohn Marino #if !has_getcwd && !has_getwd
957*86d7f5d3SJohn Marino
958*86d7f5d3SJohn Marino char *
getcwd(path,size)959*86d7f5d3SJohn Marino getcwd(path, size)
960*86d7f5d3SJohn Marino char *path;
961*86d7f5d3SJohn Marino size_t size;
962*86d7f5d3SJohn Marino {
963*86d7f5d3SJohn Marino static char const usrbinpwd[] = "/usr/bin/pwd";
964*86d7f5d3SJohn Marino # define binpwd (usrbinpwd+4)
965*86d7f5d3SJohn Marino
966*86d7f5d3SJohn Marino register FILE *fp;
967*86d7f5d3SJohn Marino register int c;
968*86d7f5d3SJohn Marino register char *p, *lim;
969*86d7f5d3SJohn Marino int closeerrno, closeerror, e, fd[2], readerror, toolong, wstatus;
970*86d7f5d3SJohn Marino pid_t child;
971*86d7f5d3SJohn Marino
972*86d7f5d3SJohn Marino if (!size) {
973*86d7f5d3SJohn Marino errno = EINVAL;
974*86d7f5d3SJohn Marino return 0;
975*86d7f5d3SJohn Marino }
976*86d7f5d3SJohn Marino if (pipe(fd) != 0)
977*86d7f5d3SJohn Marino return 0;
978*86d7f5d3SJohn Marino # if bad_wait_if_SIGCHLD_ignored
979*86d7f5d3SJohn Marino # ifndef SIGCHLD
980*86d7f5d3SJohn Marino # define SIGCHLD SIGCLD
981*86d7f5d3SJohn Marino # endif
982*86d7f5d3SJohn Marino VOID signal(SIGCHLD, SIG_DFL);
983*86d7f5d3SJohn Marino # endif
984*86d7f5d3SJohn Marino if (!(child = vfork())) {
985*86d7f5d3SJohn Marino if (
986*86d7f5d3SJohn Marino close(fd[0]) == 0 &&
987*86d7f5d3SJohn Marino (fd[1] == STDOUT_FILENO ||
988*86d7f5d3SJohn Marino # ifdef F_DUPFD
989*86d7f5d3SJohn Marino (VOID close(STDOUT_FILENO),
990*86d7f5d3SJohn Marino fcntl(fd[1], F_DUPFD, STDOUT_FILENO))
991*86d7f5d3SJohn Marino # else
992*86d7f5d3SJohn Marino dup2(fd[1], STDOUT_FILENO)
993*86d7f5d3SJohn Marino # endif
994*86d7f5d3SJohn Marino == STDOUT_FILENO &&
995*86d7f5d3SJohn Marino close(fd[1]) == 0
996*86d7f5d3SJohn Marino )
997*86d7f5d3SJohn Marino ) {
998*86d7f5d3SJohn Marino VOID close(STDERR_FILENO);
999*86d7f5d3SJohn Marino VOID execl(binpwd, binpwd, (char *)0);
1000*86d7f5d3SJohn Marino VOID execl(usrbinpwd, usrbinpwd, (char *)0);
1001*86d7f5d3SJohn Marino }
1002*86d7f5d3SJohn Marino _exit(EXIT_FAILURE);
1003*86d7f5d3SJohn Marino }
1004*86d7f5d3SJohn Marino e = errno;
1005*86d7f5d3SJohn Marino closeerror = close(fd[1]);
1006*86d7f5d3SJohn Marino closeerrno = errno;
1007*86d7f5d3SJohn Marino fp = 0;
1008*86d7f5d3SJohn Marino readerror = toolong = wstatus = 0;
1009*86d7f5d3SJohn Marino p = path;
1010*86d7f5d3SJohn Marino if (0 <= child) {
1011*86d7f5d3SJohn Marino fp = fdopen(fd[0], "r");
1012*86d7f5d3SJohn Marino e = errno;
1013*86d7f5d3SJohn Marino if (fp) {
1014*86d7f5d3SJohn Marino lim = p + size;
1015*86d7f5d3SJohn Marino for (p = path; ; *p++ = c) {
1016*86d7f5d3SJohn Marino if ((c=getc(fp)) < 0) {
1017*86d7f5d3SJohn Marino if (feof(fp))
1018*86d7f5d3SJohn Marino break;
1019*86d7f5d3SJohn Marino if (ferror(fp)) {
1020*86d7f5d3SJohn Marino readerror = 1;
1021*86d7f5d3SJohn Marino e = errno;
1022*86d7f5d3SJohn Marino break;
1023*86d7f5d3SJohn Marino }
1024*86d7f5d3SJohn Marino }
1025*86d7f5d3SJohn Marino if (p == lim) {
1026*86d7f5d3SJohn Marino toolong = 1;
1027*86d7f5d3SJohn Marino break;
1028*86d7f5d3SJohn Marino }
1029*86d7f5d3SJohn Marino }
1030*86d7f5d3SJohn Marino }
1031*86d7f5d3SJohn Marino # if has_waitpid
1032*86d7f5d3SJohn Marino if (waitpid(child, &wstatus, 0) < 0)
1033*86d7f5d3SJohn Marino wstatus = 1;
1034*86d7f5d3SJohn Marino # else
1035*86d7f5d3SJohn Marino {
1036*86d7f5d3SJohn Marino pid_t w;
1037*86d7f5d3SJohn Marino do {
1038*86d7f5d3SJohn Marino if ((w = wait(&wstatus)) < 0) {
1039*86d7f5d3SJohn Marino wstatus = 1;
1040*86d7f5d3SJohn Marino break;
1041*86d7f5d3SJohn Marino }
1042*86d7f5d3SJohn Marino } while (w != child);
1043*86d7f5d3SJohn Marino }
1044*86d7f5d3SJohn Marino # endif
1045*86d7f5d3SJohn Marino }
1046*86d7f5d3SJohn Marino if (!fp) {
1047*86d7f5d3SJohn Marino VOID close(fd[0]);
1048*86d7f5d3SJohn Marino errno = e;
1049*86d7f5d3SJohn Marino return 0;
1050*86d7f5d3SJohn Marino }
1051*86d7f5d3SJohn Marino if (fclose(fp) != 0)
1052*86d7f5d3SJohn Marino return 0;
1053*86d7f5d3SJohn Marino if (readerror) {
1054*86d7f5d3SJohn Marino errno = e;
1055*86d7f5d3SJohn Marino return 0;
1056*86d7f5d3SJohn Marino }
1057*86d7f5d3SJohn Marino if (closeerror) {
1058*86d7f5d3SJohn Marino errno = closeerrno;
1059*86d7f5d3SJohn Marino return 0;
1060*86d7f5d3SJohn Marino }
1061*86d7f5d3SJohn Marino if (toolong) {
1062*86d7f5d3SJohn Marino errno = ERANGE;
1063*86d7f5d3SJohn Marino return 0;
1064*86d7f5d3SJohn Marino }
1065*86d7f5d3SJohn Marino if (wstatus || p == path || *--p != '\n') {
1066*86d7f5d3SJohn Marino errno = EACCES;
1067*86d7f5d3SJohn Marino return 0;
1068*86d7f5d3SJohn Marino }
1069*86d7f5d3SJohn Marino *p = '\0';
1070*86d7f5d3SJohn Marino return path;
1071*86d7f5d3SJohn Marino }
1072*86d7f5d3SJohn Marino #endif
1073*86d7f5d3SJohn Marino
1074*86d7f5d3SJohn Marino
1075*86d7f5d3SJohn Marino #ifdef PAIRTEST
1076*86d7f5d3SJohn Marino /* test program for pairnames() and getfullRCSname() */
1077*86d7f5d3SJohn Marino
1078*86d7f5d3SJohn Marino char const cmdid[] = "pair";
1079*86d7f5d3SJohn Marino
main(argc,argv)1080*86d7f5d3SJohn Marino main(argc, argv)
1081*86d7f5d3SJohn Marino int argc; char *argv[];
1082*86d7f5d3SJohn Marino {
1083*86d7f5d3SJohn Marino int result;
1084*86d7f5d3SJohn Marino int initflag;
1085*86d7f5d3SJohn Marino quietflag = initflag = false;
1086*86d7f5d3SJohn Marino
1087*86d7f5d3SJohn Marino while(--argc, ++argv, argc>=1 && ((*argv)[0] == '-')) {
1088*86d7f5d3SJohn Marino switch ((*argv)[1]) {
1089*86d7f5d3SJohn Marino
1090*86d7f5d3SJohn Marino case 'p': workstdout = stdout;
1091*86d7f5d3SJohn Marino break;
1092*86d7f5d3SJohn Marino case 'i': initflag=true;
1093*86d7f5d3SJohn Marino break;
1094*86d7f5d3SJohn Marino case 'q': quietflag=true;
1095*86d7f5d3SJohn Marino break;
1096*86d7f5d3SJohn Marino default: error("unknown option: %s", *argv);
1097*86d7f5d3SJohn Marino break;
1098*86d7f5d3SJohn Marino }
1099*86d7f5d3SJohn Marino }
1100*86d7f5d3SJohn Marino
1101*86d7f5d3SJohn Marino do {
1102*86d7f5d3SJohn Marino RCSname = workname = 0;
1103*86d7f5d3SJohn Marino result = pairnames(argc,argv,rcsreadopen,!initflag,quietflag);
1104*86d7f5d3SJohn Marino if (result!=0) {
1105*86d7f5d3SJohn Marino diagnose("RCS pathname: %s; working pathname: %s\nFull RCS pathname: %s\n",
1106*86d7f5d3SJohn Marino RCSname, workname, getfullRCSname()
1107*86d7f5d3SJohn Marino );
1108*86d7f5d3SJohn Marino }
1109*86d7f5d3SJohn Marino switch (result) {
1110*86d7f5d3SJohn Marino case 0: continue; /* already paired file */
1111*86d7f5d3SJohn Marino
1112*86d7f5d3SJohn Marino case 1: if (initflag) {
1113*86d7f5d3SJohn Marino rcserror("already exists");
1114*86d7f5d3SJohn Marino } else {
1115*86d7f5d3SJohn Marino diagnose("RCS file %s exists\n", RCSname);
1116*86d7f5d3SJohn Marino }
1117*86d7f5d3SJohn Marino Ifclose(finptr);
1118*86d7f5d3SJohn Marino break;
1119*86d7f5d3SJohn Marino
1120*86d7f5d3SJohn Marino case -1:diagnose("RCS file doesn't exist\n");
1121*86d7f5d3SJohn Marino break;
1122*86d7f5d3SJohn Marino }
1123*86d7f5d3SJohn Marino
1124*86d7f5d3SJohn Marino } while (++argv, --argc>=1);
1125*86d7f5d3SJohn Marino
1126*86d7f5d3SJohn Marino }
1127*86d7f5d3SJohn Marino
1128*86d7f5d3SJohn Marino void
exiterr()1129*86d7f5d3SJohn Marino exiterr()
1130*86d7f5d3SJohn Marino {
1131*86d7f5d3SJohn Marino dirtempunlink();
1132*86d7f5d3SJohn Marino tempunlink();
1133*86d7f5d3SJohn Marino _exit(EXIT_FAILURE);
1134*86d7f5d3SJohn Marino }
1135*86d7f5d3SJohn Marino #endif
1136