1 /* parse_rc.c--rcfile parser for niftyclean
2 *
3 * Written by Jay Laefer and Mike Darweesh
4 * (C) Copyright 1989 by Jay Laefer and Mike Darweesh
5 * All Rights Reserved.
6 * Permission is granted to copy, modify, and use this as long
7 * as this notice remains intact. This is a nifty program.
8 * (C) Copyright 1991- by Charles Swiger
9 */
10
11 #include "niftyclean.h"
12 #include <stdlib.h>
13
14 static struct globtype *globlist = NULL;
15 static struct batchtype *batchlist = NULL;
16 static struct excl_dirtype *excl_dirlist = NULL;
17
18 /* Here is the default list of regex's to terminate; should move this to a
19 * system-wide config file and not hardcode it within the binary.
20 */
21
22 char *defaults[] = {
23 "core",
24 "*~",
25 ".*~",
26 "*.BAK",
27 ".*.BAK",
28 "*.CKP",
29 ".*.CKP",
30 "*.NEW",
31 ".*.NEW",
32 "#*#",
33 ".emacs_[0-9]*",
34 "dead.letter",
35 "*.otl",
36 ".*.otl",
37 "*.backup",
38 ".*.backup",
39 NULL
40 };
41
42 char *def_excl_dirs[] = {
43 ".MESSAGES",
44 NULL
45 };
46
47 char *objects[] = {
48 "*.o",
49 "*.pyc",
50 "*.pyo",
51 NULL
52 };
53
54 /* do_default_rc() goes through the array of default globs and adds each item
55 * to the global list of patterns. It then goes through the array of default
56 * directories and adds them to the list of directories to be excluded.
57 */
58 static void
do_default_rc(void)59 do_default_rc(void)
60 {
61 char **def_ptr;
62
63 if (!(flag & NOGLOB)) {
64 def_ptr = defaults;
65 while (*def_ptr) {
66 add_glob(*def_ptr++);
67 }
68 }
69
70 if (!(flag & NOEXCL)) {
71 def_ptr = def_excl_dirs;
72 while (*def_ptr) {
73 add_glob(*def_ptr++);
74 }
75 }
76 }
77
78 void
do_rc(void)79 do_rc(void)
80 {
81 FILE *fp;
82 char *home, rcfile[MAXPATHLEN], line[1024], **def_ptr;
83 int noglob, noexcl;
84
85 noglob = flag & NOGLOB;
86 noexcl = flag & NOEXCL;
87
88 if (flag & OBJECTS) {
89 def_ptr = objects;
90 printf("in objects, def_ptr = %s\n", *def_ptr);
91 while (*def_ptr) {
92 add_glob(*def_ptr++);
93 }
94 }
95
96 /* return if we don't want the defaults */
97 if(noglob && noexcl)
98 return;
99
100 /* get home directory */
101 home = getenv("HOME");
102 if (home == NULL) {
103 do_default_rc();
104 return;
105 }
106
107 if ((strlen(home) + strlen(RCFILE)) > MAXPATHLEN)
108 errorh(FATAL,"Pathlength to ~/.cleanrc too long");
109
110 strcpy(rcfile, home);
111 strcat(rcfile, "/");
112 strcat(rcfile, RCFILE);
113
114 /* open .cleanrc */
115 if ((fp = fopen(rcfile, "r")) == NULL) {
116 do_default_rc();
117 return;
118 }
119
120 /* read patterns from file */
121 while (fgets(line, MAXPATHLEN, fp) != NULL) {
122 int len, c;
123
124 len = strlen(line) - 1;
125 if (line[len] == '\n')
126 line[len] = '\0';
127 else
128 while (((c = getc(fp)) != EOF) && (c != '\n'));
129
130 /* check for comment or blank line */
131 if ((line[0] != '#') && (line[0] != '\0')) {
132 if (line[0] == '!') {
133 if (!noexcl)
134 add_excl_dir(line + 1);
135 } else if (!noglob) {
136 if ((line[0] == '\\') &&
137 ((line[1] == '#') || (line[1] == '!') || (line[1] == '\\')))
138 add_glob(line + 1);
139 else
140 add_glob(line);
141 }
142 }
143 }
144
145 if (fclose(fp))
146 errorh(WARNING,"Problem closing ~/.cleanrc");
147 }
148
149 /* find_match() takes a string and goes through the list of patterns until it
150 * either finds a match or runs out of patterns.
151 */
152 static int
find_match(char * file)153 find_match (char *file)
154 {
155 struct globtype *temp;
156
157 temp = globlist;
158 while (temp) {
159 if (match(file, temp->glob))
160 return 1;
161 temp = temp->next;
162 }
163 return 0;
164 }
165
166 /* dofile() takes a directory and a filename and acts based on whether FORCE,
167 * BATCH, or INTERACTIVE mode is on.
168 */
169 int
dofile(char * dir,char * file)170 dofile (char *dir, char *file)
171 {
172 char unlinkerr[MAXPATHLEN + 100], c;
173
174 if (find_match(file)) { /* if the file matches a pattern */
175 char fullpath[MAXPATHLEN];
176
177 strcpy(fullpath, dir);
178 strcat(fullpath, "/");
179 strcat(fullpath, file);
180
181 if (flag & FORCE)
182 (void)unlink(fullpath);
183 else if (flag & BATCH)
184 add_batch(fullpath);
185 else {
186 fputs("Remove ", stdout);
187 fputs(fullpath, stdout);
188 fputs(" y/n/s [y]: ", stdout);
189 c = getfirstchar(stdin);
190 /* kill file if user wants it killed */
191 switch (c) {
192 case 'y':
193 case 'Y':
194 case '\n':
195 if (unlink(fullpath)) {
196 strcpy(unlinkerr, "Could not remove: ");
197 strcat(unlinkerr, fullpath);
198 errorh(WARNING, unlinkerr);
199 } else {
200 fputs("Removed: ", stdout);
201 puts(fullpath);
202 }
203 break;
204 case 's':
205 case 'S':
206 skip = 1;
207 puts("Skipping this directory...");
208 break;
209 }
210 }
211 return 1;
212 } else
213 return 0;
214 }
215
216 /* add_batch() takes the full pathname to a file that is slated for deletion.
217 * It then adds that to the globab linked list of such files.
218 */
219 void
add_batch(char * path)220 add_batch (char *path)
221 {
222 struct batchtype *batchptr;
223 batchptr = (struct batchtype *) malloc((sizeof (struct batchtype)
224 + strlen(path)));
225 if (batchptr == NULL)
226 errorh(FATAL, "Malloc failed in add_batch()");
227
228 strcpy(batchptr->path, path);
229 batchptr->next = batchlist;
230 batchlist = batchptr;
231 }
232
233 /* dobatch() runs through the list of files slated for deletion and asks the
234 * user if he wants to delete them.
235 */
236 void
dobatch(void)237 dobatch (void)
238 {
239 struct batchtype *temp;
240 char unlinkerr[MAXPATHLEN + 100];
241 int c;
242
243 if (!batchlist) {
244 puts("No non-nifty files found.");
245 return;
246 }
247
248 puts("\nThe following are non-nifty files:");
249 for (temp = batchlist; temp; temp = temp->next)
250 puts(temp->path);
251
252 fputs("Delete them y/n [y]: ", stdout);
253 c = getfirstchar(stdin);
254
255 if ((c = ((c == 'y') || (c == 'Y') || (c == '\n'))))
256 puts("Deleting files...");
257 else
258 puts("Files not deleted.");
259
260 /* delete the files and free the memory */
261 while (batchlist) {
262 if (c && unlink(batchlist->path)) {
263 strcpy(unlinkerr, "Could not remove: ");
264 strcat(unlinkerr, batchlist->path);
265 errorh(WARNING,unlinkerr);
266 }
267 temp = batchlist;
268 batchlist = batchlist->next;
269 free(temp);
270 }
271 }
272
273 /* add_glob() takes a word, malloc's space for a structure, and adds it to the
274 * front of the list of patterns to be matched.
275 */
276 void
add_glob(char * word)277 add_glob (char *word)
278 {
279 struct globtype *globptr;
280
281 if (0)
282 printf("add_glob(): word = %s\n", word);
283
284 globptr = (struct globtype *)malloc((sizeof (struct globtype)) + strlen(word));
285 if (globptr == NULL)
286 errorh(FATAL, "Malloc failed in add_glob()");
287
288 strcpy(globptr->glob, word);
289
290 globptr->next = globlist;
291
292 globlist = globptr;
293 }
294
295 /* add_excl_dir() takes a word, malloc's space for a structure, and adds it to
296 * the front of the list of directories to be excluded from the traversal.
297 */
298 void
add_excl_dir(char * word)299 add_excl_dir (char *word)
300 {
301 struct excl_dirtype *excl_dirptr;
302 if ((excl_dirptr = (struct excl_dirtype *)malloc((sizeof (struct excl_dirtype)) + strlen(word))) == NULL)
303 errorh(FATAL, "Malloc failed in add_excl_dir()");
304
305 strcpy(excl_dirptr->excl_dir, word);
306
307 excl_dirptr->next = excl_dirlist;
308
309 excl_dirlist = excl_dirptr;
310 }
311
312 /* check_excl_list() takes a directory name and checks to see if it is on the
313 * list of directories to be excluded. If so, a 0 is returned. Otherwise,
314 * return 1.
315 */
316 int
check_excl_list(char * dir)317 check_excl_list (char *dir)
318 {
319 struct excl_dirtype *temp;
320
321 /* Move down the linked list that starts with excl_dirlist */
322 for (temp = excl_dirlist; temp; temp = temp->next)
323 if (!strcmp(temp->excl_dir, dir))
324 return 0; /* Found */
325
326 return 1;
327 }
328