No empty .Rs/.Re
[netbsd-mini2440.git] / gnu / usr.bin / rcs / rcsclean / rcsclean.c
blob5045785f9095b3cd69ef7dcdb860c3b94245efad
1 /* $NetBSD: rcsclean.c,v 1.4 1996/10/15 07:00:38 veego Exp $ */
3 /* Clean up working files. */
5 /* Copyright 1991, 1992, 1993, 1994, 1995 Paul Eggert
6 Distributed under license by the Free Software Foundation, Inc.
8 This file is part of RCS.
10 RCS is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2, or (at your option)
13 any later version.
15 RCS is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with RCS; see the file COPYING.
22 If not, write to the Free Software Foundation,
23 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 Report problems and direct all questions to:
27 rcs-bugs@cs.purdue.edu
31 #include "rcsbase.h"
33 #if has_dirent
34 static int get_directory P((char const*,char***));
35 #endif
37 static int unlock P((struct hshentry *));
38 static void cleanup P((void));
40 static RILE *workptr;
41 static int exitstatus;
43 mainProg(rcscleanId, "rcsclean", "Id: rcsclean.c,v 5.9 1995/06/16 06:19:24 eggert Exp")
45 static char const usage[] =
46 "\nrcsclean: usage: rcsclean -ksubst -{nqru}[rev] -T -Vn -xsuff -zzone file ...";
48 static struct buf revision;
50 char *a, **newargv;
51 char const *rev, *p;
52 int dounlock, expmode, perform, unlocked, unlockflag, waslocked;
53 int Ttimeflag;
54 struct hshentries *deltas;
55 struct hshentry *delta;
56 struct stat workstat;
58 setrid();
60 expmode = -1;
61 rev = 0;
62 suffixes = X_DEFAULT;
63 perform = true;
64 unlockflag = false;
65 Ttimeflag = false;
67 argc = getRCSINIT(argc, argv, &newargv);
68 argv = newargv;
69 for (;;) {
70 if (--argc < 1) {
71 # if has_dirent
72 argc = get_directory(".", &newargv);
73 argv = newargv;
74 break;
75 # else
76 faterror("no pathnames specified");
77 # endif
79 a = *++argv;
80 if (!*a || *a++ != '-')
81 break;
82 switch (*a++) {
83 case 'k':
84 if (0 <= expmode)
85 redefined('k');
86 if ((expmode = str2expmode(a)) < 0)
87 goto unknown;
88 break;
90 case 'n':
91 perform = false;
92 goto handle_revision;
94 case 'q':
95 quietflag = true;
96 /* fall into */
97 case 'r':
98 handle_revision:
99 if (*a) {
100 if (rev)
101 warn("redefinition of revision number");
102 rev = a;
104 break;
106 case 'T':
107 if (*a)
108 goto unknown;
109 Ttimeflag = true;
110 break;
112 case 'u':
113 unlockflag = true;
114 goto handle_revision;
116 case 'V':
117 setRCSversion(*argv);
118 break;
120 case 'x':
121 suffixes = a;
122 break;
124 case 'z':
125 zone_set(a);
126 break;
128 default:
129 unknown:
130 error("unknown option: %s%s", *argv, usage);
134 dounlock = perform & unlockflag;
136 if (nerror)
137 cleanup();
138 else
139 for (; 0 < argc; cleanup(), ++argv, --argc) {
141 ffree();
143 if (!(
144 0 < pairnames(
145 argc, argv,
146 dounlock ? rcswriteopen : rcsreadopen,
147 true, true
148 ) &&
149 (workptr = Iopen(workname, FOPEN_R_WORK, &workstat))
151 continue;
153 if (same_file(RCSstat, workstat, 0)) {
154 rcserror("RCS file is the same as working file %s.",
155 workname
157 continue;
160 gettree();
162 p = 0;
163 if (rev) {
164 if (!fexpandsym(rev, &revision, workptr))
165 continue;
166 p = revision.string;
167 } else if (Head)
168 switch (unlockflag ? findlock(false,&delta) : 0) {
169 default:
170 continue;
171 case 0:
172 p = Dbranch ? Dbranch : "";
173 break;
174 case 1:
175 p = delta->num;
176 break;
178 delta = 0;
179 deltas = 0; /* Keep lint happy. */
180 if (p && !(delta = genrevs(p,(char*)0,(char*)0,(char*)0,&deltas)))
181 continue;
183 waslocked = delta && delta->lockedby;
184 locker_expansion = unlock(delta);
185 unlocked = locker_expansion & unlockflag;
186 if (unlocked<waslocked && workstat.st_mode&(S_IWUSR|S_IWGRP|S_IWOTH))
187 continue;
189 if (unlocked && !checkaccesslist())
190 continue;
192 if (dorewrite(dounlock, unlocked) != 0)
193 continue;
195 if (0 <= expmode)
196 Expand = expmode;
197 else if (
198 waslocked &&
199 Expand == KEYVAL_EXPAND &&
200 WORKMODE(RCSstat.st_mode,true) == workstat.st_mode
202 Expand = KEYVALLOCK_EXPAND;
204 getdesc(false);
206 if (
207 !delta ? workstat.st_size!=0 :
208 0 < rcsfcmp(
209 workptr, &workstat,
210 buildrevision(deltas, delta, (FILE*)0, false),
211 delta
214 continue;
216 if (quietflag < unlocked)
217 aprintf(stdout, "rcs -u%s %s\n", delta->num, RCSname);
219 if (perform & unlocked) {
220 if_advise_access(deltas->first != delta, finptr, MADV_SEQUENTIAL);
221 if (donerewrite(true,
222 Ttimeflag ? RCSstat.st_mtime : (time_t)-1
223 ) != 0)
224 continue;
227 if (!quietflag)
228 aprintf(stdout, "rm -f %s\n", workname);
229 Izclose(&workptr);
230 if (perform && un_link(workname) != 0)
231 eerror(workname);
235 tempunlink();
236 if (!quietflag)
237 Ofclose(stdout);
238 exitmain(exitstatus);
241 static void
242 cleanup()
244 if (nerror) exitstatus = EXIT_FAILURE;
245 Izclose(&finptr);
246 Izclose(&workptr);
247 Ozclose(&fcopy);
248 ORCSclose();
249 dirtempunlink();
252 #if RCS_lint
253 # define exiterr rcscleanExit
254 #endif
255 void
256 exiterr()
258 ORCSerror();
259 dirtempunlink();
260 tempunlink();
261 _exit(EXIT_FAILURE);
264 static int
265 unlock(delta)
266 struct hshentry *delta;
268 register struct rcslock **al, *l;
270 if (delta && delta->lockedby && strcmp(getcaller(),delta->lockedby)==0)
271 for (al = &Locks; (l = *al); al = &l->nextlock)
272 if (l->delta == delta) {
273 *al = l->nextlock;
274 delta->lockedby = 0;
275 return true;
277 return false;
280 #if has_dirent
281 static int
282 get_directory(dirname, aargv)
283 char const *dirname;
284 char ***aargv;
286 * Put a vector of all DIRNAME's directory entries names into *AARGV.
287 * Ignore names of RCS files.
288 * Yield the number of entries found. Terminate the vector with 0.
289 * Allocate the storage for the vector and entry names.
290 * Do not sort the names. Do not include '.' and '..'.
293 int i, entries = 0, entries_max = 64;
294 size_t chars = 0, chars_max = 1024;
295 size_t *offset = tnalloc(size_t, entries_max);
296 char *a = tnalloc(char, chars_max), **p;
297 DIR *d;
298 struct dirent *e;
300 if (!(d = opendir(dirname)))
301 efaterror(dirname);
302 while ((errno = 0, e = readdir(d))) {
303 char const *en = e->d_name;
304 size_t s = strlen(en) + 1;
305 if (en[0]=='.' && (!en[1] || (en[1]=='.' && !en[2])))
306 continue;
307 if (rcssuffix(en))
308 continue;
309 while (chars_max < s + chars)
310 a = trealloc(char, a, chars_max<<=1);
311 if (entries == entries_max)
312 offset = trealloc(size_t, offset, entries_max<<=1);
313 offset[entries++] = chars;
314 VOID strcpy(a+chars, en);
315 chars += s;
317 # if void_closedir
318 # define close_directory(d) (closedir(d), 0)
319 # else
320 # define close_directory(d) closedir(d)
321 # endif
322 if (errno || close_directory(d) != 0)
323 efaterror(dirname);
324 if (chars)
325 a = trealloc(char, a, chars);
326 else {
327 tfree(a);
328 a = NULL;
330 *aargv = p = tnalloc(char*, entries+1);
331 if (a)
332 for (i=0; i<entries; i++)
333 *p++ = a + offset[i];
334 *p = 0;
335 tfree(offset);
336 return entries;
338 #endif