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