]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - gnu/usr.bin/rcs/rcsclean/rcsclean.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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 #include "rcsbase.h"
30
31 #if has_dirent
32         static int get_directory P((char const*,char***));
33 #endif
34
35 static int unlock P((struct hshentry *));
36 static void cleanup P((void));
37
38 static RILE *workptr;
39 static int exitstatus;
40
41 mainProg(rcscleanId, "rcsclean", "$FreeBSD$")
42 {
43         static char const usage[] =
44                 "\nrcsclean: usage: rcsclean -ksubst -{nqru}[rev] -T -Vn -xsuff -zzone file ...";
45
46         static struct buf revision;
47
48         char *a, **newargv;
49         char const *rev, *p;
50         int dounlock, expmode, perform, unlocked, unlockflag, waslocked;
51         int Ttimeflag;
52         struct hshentries *deltas;
53         struct hshentry *delta;
54         struct stat workstat;
55
56         setrid();
57
58         expmode = -1;
59         rev = 0;
60         suffixes = X_DEFAULT;
61         perform = true;
62         unlockflag = false;
63         Ttimeflag = false;
64
65         argc = getRCSINIT(argc, argv, &newargv);
66         argv = newargv;
67         for (;;) {
68                 if (--argc < 1) {
69 #                       if has_dirent
70                                 argc = get_directory(".", &newargv);
71                                 argv = newargv;
72                                 break;
73 #                       else
74                                 faterror("no pathnames specified");
75 #                       endif
76                 }
77                 a = *++argv;
78                 if (!*a  ||  *a++ != '-')
79                         break;
80                 switch (*a++) {
81                         case 'k':
82                                 if (0 <= expmode)
83                                         redefined('k');
84                                 if ((expmode = str2expmode(a))  <  0)
85                                         goto unknown;
86                                 break;
87
88                         case 'n':
89                                 perform = false;
90                                 goto handle_revision;
91
92                         case 'q':
93                                 quietflag = true;
94                                 /* fall into */
95                         case 'r':
96                         handle_revision:
97                                 if (*a) {
98                                         if (rev)
99                                                 warn("redefinition of revision number");
100                                         rev = a;
101                                 }
102                                 break;
103
104                         case 'T':
105                                 if (*a)
106                                         goto unknown;
107                                 Ttimeflag = true;
108                                 break;
109
110                         case 'u':
111                                 unlockflag = true;
112                                 goto handle_revision;
113
114                         case 'V':
115                                 setRCSversion(*argv);
116                                 break;
117
118                         case 'x':
119                                 suffixes = a;
120                                 break;
121
122                         case 'z':
123                                 zone_set(a);
124                                 break;
125
126                         default:
127                         unknown:
128                                 error("unknown option: %s%s", *argv, usage);
129                 }
130         }
131
132         dounlock = perform & unlockflag;
133
134         if (nerror)
135           cleanup();
136         else
137           for (;  0 < argc;  cleanup(), ++argv, --argc) {
138
139                 ffree();
140
141                 if (!(
142                         0 < pairnames(
143                                 argc, argv,
144                                 dounlock ? rcswriteopen : rcsreadopen,
145                                 true, true
146                         ) &&
147                         (workptr = Iopen(workname, FOPEN_R_WORK, &workstat))
148                 ))
149                         continue;
150
151                 if (same_file(RCSstat, workstat, 0)) {
152                         rcserror("RCS file is the same as working file %s.",
153                                 workname
154                         );
155                         continue;
156                 }
157
158                 gettree();
159
160                 p = 0;
161                 if (rev) {
162                         if (!fexpandsym(rev, &revision, workptr))
163                                 continue;
164                         p = revision.string;
165                 } else if (Head)
166                         switch (unlockflag ? findlock(false,&delta) : 0) {
167                                 default:
168                                         continue;
169                                 case 0:
170                                         p = Dbranch ? Dbranch : "";
171                                         break;
172                                 case 1:
173                                         p = delta->num;
174                                         break;
175                         }
176                 delta = 0;
177                 deltas = 0;  /* Keep lint happy.  */
178                 if (p  &&  !(delta = genrevs(p,(char*)0,(char*)0,(char*)0,&deltas)))
179                         continue;
180
181                 waslocked = delta && delta->lockedby;
182                 locker_expansion = unlock(delta);
183                 unlocked = locker_expansion & unlockflag;
184                 if (unlocked<waslocked  &&  workstat.st_mode&(S_IWUSR|S_IWGRP|S_IWOTH))
185                         continue;
186
187                 if (unlocked && !checkaccesslist())
188                         continue;
189
190                 if (dorewrite(dounlock, unlocked) != 0)
191                         continue;
192
193                 if (0 <= expmode)
194                         Expand = expmode;
195                 else if (
196                         waslocked  &&
197                         Expand == KEYVAL_EXPAND  &&
198                         WORKMODE(RCSstat.st_mode,true) == workstat.st_mode
199                 )
200                         Expand = KEYVALLOCK_EXPAND;
201
202                 getdesc(false);
203
204                 if (
205                         !delta ? workstat.st_size!=0 :
206                         0 < rcsfcmp(
207                                 workptr, &workstat,
208                                 buildrevision(deltas, delta, (FILE*)0, false),
209                                 delta
210                         )
211                 )
212                         continue;
213
214                 if (quietflag < unlocked)
215                         aprintf(stdout, "rcs -u%s %s\n", delta->num, RCSname);
216
217                 if (perform & unlocked) {
218                         if_advise_access(deltas->first != delta, finptr, MADV_SEQUENTIAL);
219                         if (donerewrite(true,
220                                 Ttimeflag ? RCSstat.st_mtime : (time_t)-1
221                         ) != 0)
222                                 continue;
223                 }
224
225                 if (!quietflag)
226                         aprintf(stdout, "rm -f %s\n", workname);
227                 Izclose(&workptr);
228                 if (perform  &&  un_link(workname) != 0)
229                         eerror(workname);
230
231           }
232
233         tempunlink();
234         if (!quietflag)
235                 Ofclose(stdout);
236         exitmain(exitstatus);
237 }
238
239         static void
240 cleanup()
241 {
242         if (nerror) exitstatus = EXIT_FAILURE;
243         Izclose(&finptr);
244         Izclose(&workptr);
245         Ozclose(&fcopy);
246         ORCSclose();
247         dirtempunlink();
248 }
249
250 #if RCS_lint
251 #       define exiterr rcscleanExit
252 #endif
253         void
254 exiterr()
255 {
256         ORCSerror();
257         dirtempunlink();
258         tempunlink();
259         _exit(EXIT_FAILURE);
260 }
261
262         static int
263 unlock(delta)
264         struct hshentry *delta;
265 {
266         register struct rcslock **al, *l;
267
268         if (delta && delta->lockedby && strcmp(getcaller(),delta->lockedby)==0)
269                 for (al = &Locks;  (l = *al);  al = &l->nextlock)
270                         if (l->delta == delta) {
271                                 *al = l->nextlock;
272                                 delta->lockedby = 0;
273                                 return true;
274                         }
275         return false;
276 }
277
278 #if has_dirent
279         static int
280 get_directory(dirname, aargv)
281         char const *dirname;
282         char ***aargv;
283 /*
284  * Put a vector of all DIRNAME's directory entries names into *AARGV.
285  * Ignore names of RCS files.
286  * Yield the number of entries found.  Terminate the vector with 0.
287  * Allocate the storage for the vector and entry names.
288  * Do not sort the names.  Do not include '.' and '..'.
289  */
290 {
291         int i, entries = 0, entries_max = 64;
292         size_t chars = 0, chars_max = 1024;
293         size_t *offset = tnalloc(size_t, entries_max);
294         char *a = tnalloc(char, chars_max), **p;
295         DIR *d;
296         struct dirent *e;
297
298         if (!(d = opendir(dirname)))
299                 efaterror(dirname);
300         while ((errno = 0,  e = readdir(d))) {
301                 char const *en = e->d_name;
302                 size_t s = strlen(en) + 1;
303                 if (en[0]=='.'   &&   (!en[1]  ||  (en[1]=='.' && !en[2])))
304                         continue;
305                 if (rcssuffix(en))
306                         continue;
307                 while (chars_max < s + chars)
308                         a = trealloc(char, a, chars_max<<=1);
309                 if (entries == entries_max)
310                         offset = trealloc(size_t, offset, entries_max<<=1);
311                 offset[entries++] = chars;
312                 VOID strcpy(a+chars, en);
313                 chars += s;
314         }
315 #       if void_closedir
316 #               define close_directory(d) (closedir(d), 0)
317 #       else
318 #               define close_directory(d) closedir(d)
319 #       endif
320         if (errno  ||  close_directory(d) != 0)
321                 efaterror(dirname);
322         if (chars)
323                 a = trealloc(char, a, chars);
324         else
325                 tfree(a);
326         *aargv = p = tnalloc(char*, entries+1);
327         for (i=0; i<entries; i++)
328                 *p++ = a + offset[i];
329         *p = 0;
330         tfree(offset);
331         return entries;
332 }
333 #endif