2 * Code for reading and writing the filters file.
4 * $Id: filters.c,v 1.11 2001/10/22 22:59:23 guy Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program 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 this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
34 #ifdef HAVE_SYS_STAT_H
43 #include <direct.h> /* to declare "mkdir()" on Windows */
48 #include <filesystem.h>
53 * Old filter file name.
55 #define FILTER_FILE_NAME "filters"
58 * Capture filter file name.
60 #define CFILTER_FILE_NAME "cfilters"
63 * Display filter file name.
65 #define DFILTER_FILE_NAME "dfilters"
68 * List of capture filters.
70 static GList *capture_filters = NULL;
73 * List of display filters.
75 static GList *display_filters = NULL;
78 * Read in a list of filters.
80 * On success, "*pref_path_return" is set to NULL.
81 * On error, "*pref_path_return" is set to point to the pathname of
82 * the file we tried to read - it should be freed by our caller -
83 * and "*errno_return" is set to the error.
86 #define INIT_BUF_SIZE 128
89 read_filter_list(filter_list_type_t list, char **pref_path_return,
92 const char *pf_dir_path;
93 char *ff_path, *ff_name;
99 char *filt_name, *filt_expr;
100 int filt_name_len, filt_expr_len;
101 int filt_name_index, filt_expr_index;
104 *pref_path_return = NULL; /* assume no error */
109 ff_name = CFILTER_FILE_NAME;
110 flp = &capture_filters;
114 ff_name = DFILTER_FILE_NAME;
115 flp = &display_filters;
119 g_assert_not_reached();
123 /* To do: generalize this */
124 pf_dir_path = get_persconffile_dir();
125 ff_path = (gchar *) g_malloc(strlen(pf_dir_path) + strlen(ff_name) + 2);
126 sprintf(ff_path, "%s" G_DIR_SEPARATOR_S "%s", pf_dir_path, ff_name);
128 if ((ff = fopen(ff_path, "r")) == NULL) {
130 * Did that fail because we the file didn't exist?
132 if (errno != ENOENT) {
136 *pref_path_return = ff_path;
137 *errno_return = errno;
142 * Yes. See if there's a "filters" file; if so, read it.
143 * This means that a user will start out with their capture and
144 * display filter lists being identical; each list may contain
145 * filters that don't belong in that list. The user can edit
146 * the filter lists, and delete the ones that don't belong in
149 sprintf(ff_path, "%s" G_DIR_SEPARATOR_S "%s", pf_dir_path,
151 if ((ff = fopen(ff_path, "r")) == NULL) {
153 * Well, that didn't work, either. Just give up.
154 * Return an error if the file existed but we couldn't open it.
156 if (errno != ENOENT) {
157 *pref_path_return = ff_path;
158 *errno_return = errno;
164 /* If we already have a list of filters, discard it. */
166 fl_ent = g_list_first(*flp);
167 while (fl_ent != NULL) {
168 filt = (filter_def *) fl_ent->data;
170 g_free(filt->strval);
172 fl_ent = fl_ent->next;
178 /* Allocate the filter name buffer. */
179 filt_name_len = INIT_BUF_SIZE;
180 filt_name = g_malloc(filt_name_len + 1);
181 filt_expr_len = INIT_BUF_SIZE;
182 filt_expr = g_malloc(filt_expr_len + 1);
184 for (line = 1; ; line++) {
185 /* Lines in a filter file are of the form
189 where "name" is a name, in quotes - backslashes in the name
190 escape the next character, so quotes and backslashes can appear
191 in the name - and "expression" is a filter expression, not in
192 quotes, running to the end of the line. */
194 /* Skip over leading white space, if any. */
195 while ((c = getc(ff)) != EOF && isspace(c)) {
203 break; /* Nothing more to read */
205 /* "c" is the first non-white-space character.
206 If it's not a quote, it's an error. */
208 g_warning("'%s' line %d doesn't have a quoted filter name.", ff_path,
211 c = getc(ff); /* skip to the end of the line */
215 /* Get the name of the filter. */
219 if (c == EOF || c == '\n')
220 break; /* End of line - or end of file */
223 if (filt_name_index >= filt_name_len) {
224 /* Filter name buffer isn't long enough; double its length. */
226 filt_name = g_realloc(filt_name, filt_name_len + 1);
228 filt_name[filt_name_index] = '\0';
232 /* Next character is escaped */
234 if (c == EOF || c == '\n')
235 break; /* End of line - or end of file */
237 /* Add this character to the filter name string. */
238 if (filt_name_index >= filt_name_len) {
239 /* Filter name buffer isn't long enough; double its length. */
241 filt_name = g_realloc(filt_name, filt_name_len + 1);
243 filt_name[filt_name_index] = c;
249 /* EOF, not error; no newline seen before EOF */
250 g_warning("'%s' line %d doesn't have a newline.", ff_path,
253 break; /* nothing more to read */
257 /* No newline seen before end-of-line */
258 g_warning("'%s' line %d doesn't have a closing quote.", ff_path,
263 /* Skip over separating white space, if any. */
264 while ((c = getc(ff)) != EOF && isspace(c)) {
271 /* EOF, not error; no newline seen before EOF */
272 g_warning("'%s' line %d doesn't have a newline.", ff_path,
275 break; /* nothing more to read */
279 /* No filter expression */
280 g_warning("'%s' line %d doesn't have a filter expression.", ff_path,
285 /* "c" is the first non-white-space character; it's the first
286 character of the filter expression. */
289 /* Add this character to the filter expression string. */
290 if (filt_expr_index >= filt_expr_len) {
291 /* Filter expressioin buffer isn't long enough; double its length. */
293 filt_expr = g_realloc(filt_expr, filt_expr_len + 1);
295 filt_expr[filt_expr_index] = c;
298 /* Get the next character. */
300 if (c == EOF || c == '\n')
306 /* EOF, not error; no newline seen before EOF */
307 g_warning("'%s' line %d doesn't have a newline.", ff_path,
310 break; /* nothing more to read */
313 /* We saw the ending newline; terminate the filter expression string */
314 if (filt_expr_index >= filt_expr_len) {
315 /* Filter expressioin buffer isn't long enough; double its length. */
317 filt_expr = g_realloc(filt_expr, filt_expr_len + 1);
319 filt_expr[filt_expr_index] = '\0';
321 /* Add the new filter to the list of filters */
322 filt = (filter_def *) g_malloc(sizeof(filter_def));
323 filt->name = g_strdup(filt_name);
324 filt->strval = g_strdup(filt_expr);
325 *flp = g_list_append(*flp, filt);
328 *pref_path_return = ff_path;
329 *errno_return = errno;
338 * Get a pointer to a list of filters.
341 get_filter_list(filter_list_type_t list)
348 flp = &capture_filters;
352 flp = &display_filters;
356 g_assert_not_reached();
363 * Get a pointer to the first entry in a filter list.
366 get_filter_list_first(filter_list_type_t list)
370 flp = get_filter_list(list);
371 return g_list_first(*flp);
375 * Add a new filter to the end of a list.
376 * Returns a pointer to the newly-added entry.
379 add_to_filter_list(filter_list_type_t list, char *name, char *expression)
384 flp = get_filter_list(list);
385 filt = (filter_def *) g_malloc(sizeof(filter_def));
386 filt->name = g_strdup(name);
387 filt->strval = g_strdup(expression);
388 *flp = g_list_append(*flp, filt);
389 return g_list_last(*flp);
393 * Remove a filter from a list.
396 remove_from_filter_list(filter_list_type_t list, GList *fl_entry)
401 flp = get_filter_list(list);
402 filt = (filter_def *) fl_entry->data;
404 g_free(filt->strval);
406 *flp = g_list_remove_link(*flp, fl_entry);
410 * Write out a list of filters.
412 * On success, "*pref_path_return" is set to NULL.
413 * On error, "*pref_path_return" is set to point to the pathname of
414 * the file we tried to read - it should be freed by our caller -
415 * and "*errno_return" is set to the error.
418 save_filter_list(filter_list_type_t list, char **pref_path_return,
421 const char *pf_dir_path;
422 gchar *ff_path, *ff_path_new, *ff_name;
431 *pref_path_return = NULL; /* assume no error */
436 ff_name = CFILTER_FILE_NAME;
437 fl = capture_filters;
441 ff_name = DFILTER_FILE_NAME;
442 fl = display_filters;
446 g_assert_not_reached();
450 pf_dir_path = get_persconffile_dir();
451 if (stat(pf_dir_path, &s_buf) != 0)
455 mkdir(pf_dir_path, 0755);
458 path_length = strlen(pf_dir_path) + strlen(ff_name) + 2;
459 ff_path = (gchar *) g_malloc(path_length);
460 sprintf(ff_path, "%s" G_DIR_SEPARATOR_S "%s", pf_dir_path, ff_name);
462 /* Write to "XXX.new", and rename if that succeeds.
463 That means we don't trash the file if we fail to write it out
465 ff_path_new = (gchar *) g_malloc(path_length + 4);
466 sprintf(ff_path_new, "%s.new", ff_path);
468 if ((ff = fopen(ff_path_new, "w")) == NULL) {
469 *pref_path_return = ff_path;
470 *errno_return = errno;
474 flp = g_list_first(fl);
476 filt = (filter_def *) flp->data;
478 /* Write out the filter name as a quoted string; escape any quotes
481 for (p = (guchar *)filt->name; (c = *p) != '\0'; p++) {
482 if (c == '"' || c == '\\')
488 /* Separate the filter name and value with a space. */
491 /* Write out the filter expression and a newline. */
492 fprintf(ff, "%s\n", filt->strval);
494 *pref_path_return = ff_path;
495 *errno_return = errno;
503 if (fclose(ff) == EOF) {
504 *pref_path_return = ff_path;
505 *errno_return = errno;
512 /* ANSI C doesn't say whether "rename()" removes the target if it
513 exists; the Win32 call to rename files doesn't do so, which I
514 infer is the reason why the MSVC++ "rename()" doesn't do so.
515 We must therefore remove the target file first, on Windows. */
516 if (remove(ff_path) < 0 && errno != ENOENT) {
517 /* It failed for some reason other than "it's not there"; if
518 it's not there, we don't need to remove it, so we just
520 *pref_path_return = ff_path;
521 *errno_return = errno;
528 if (rename(ff_path_new, ff_path) < 0) {
529 *pref_path_return = ff_path;
530 *errno_return = errno;