2 * Code for reading and writing the filters file.
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
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.
40 #include <epan/filesystem.h>
43 #include <wsutil/file_util.h>
46 * Old filter file name.
48 #define FILTER_FILE_NAME "filters"
51 * Capture filter file name.
53 #define CFILTER_FILE_NAME "cfilters"
56 * Display filter file name.
58 #define DFILTER_FILE_NAME "dfilters"
61 * List of capture filters - saved.
63 static GList *capture_filters = NULL;
66 * List of display filters - saved.
68 static GList *display_filters = NULL;
71 * List of capture filters - currently edited.
73 static GList *capture_edited_filters = NULL;
76 * List of display filters - currently edited.
78 static GList *display_edited_filters = NULL;
81 * Read in a list of filters.
83 * On success, "*pref_path_return" is set to NULL.
84 * On error, "*pref_path_return" is set to point to the pathname of
85 * the file we tried to read - it should be freed by our caller -
86 * and "*errno_return" is set to the error.
89 #define INIT_BUF_SIZE 128
92 add_filter_entry(GList *fl, const char *filt_name, const char *filt_expr)
96 filt = (filter_def *) g_malloc(sizeof(filter_def));
97 filt->name = g_strdup(filt_name);
98 filt->strval = g_strdup(filt_expr);
99 return g_list_append(fl, filt);
103 remove_filter_entry(GList *fl, GList *fl_entry)
107 filt = (filter_def *) fl_entry->data;
109 g_free(filt->strval);
111 return g_list_remove_link(fl, fl_entry);
115 read_filter_list(filter_list_type_t list_type, char **pref_path_return,
123 char *filt_name, *filt_expr;
124 int filt_name_len, filt_expr_len;
125 int filt_name_index, filt_expr_index;
128 *pref_path_return = NULL; /* assume no error */
133 ff_name = CFILTER_FILE_NAME;
134 flpp = &capture_filters;
138 ff_name = DFILTER_FILE_NAME;
139 flpp = &display_filters;
143 g_assert_not_reached();
147 /* try to open personal "cfilters"/"dfilters" file */
148 ff_path = get_persconffile_path(ff_name, TRUE, FALSE);
149 if ((ff = ws_fopen(ff_path, "r")) == NULL) {
151 * Did that fail because the file didn't exist?
153 if (errno != ENOENT) {
157 *pref_path_return = ff_path;
158 *errno_return = errno;
163 * Yes. See if there's an "old style" personal "filters" file; if so, read it.
164 * This means that a user will start out with their capture and
165 * display filter lists being identical; each list may contain
166 * filters that don't belong in that list. The user can edit
167 * the filter lists, and delete the ones that don't belong in
171 ff_path = get_persconffile_path(FILTER_FILE_NAME, FALSE, FALSE);
172 if ((ff = ws_fopen(ff_path, "r")) == NULL) {
174 * Did that fail because the file didn't exist?
176 if (errno != ENOENT) {
180 *pref_path_return = ff_path;
181 *errno_return = errno;
186 * Try to open the global "cfilters/dfilters" file */
188 ff_path = get_datafile_path(ff_name);
189 if ((ff = ws_fopen(ff_path, "r")) == NULL) {
192 * Well, that didn't work, either. Just give up.
193 * Return an error if the file existed but we couldn't open it.
195 if (errno != ENOENT) {
196 *pref_path_return = ff_path;
197 *errno_return = errno;
206 /* If we already have a list of filters, discard it. */
207 /* this should never happen - this function is called only once for each list! */
209 *flpp = remove_filter_entry(*flpp, g_list_first(*flpp));
212 /* Allocate the filter name buffer. */
213 filt_name_len = INIT_BUF_SIZE;
214 filt_name = (char *)g_malloc(filt_name_len + 1);
215 filt_expr_len = INIT_BUF_SIZE;
216 filt_expr = (char *)g_malloc(filt_expr_len + 1);
218 for (line = 1; ; line++) {
219 /* Lines in a filter file are of the form
223 where "name" is a name, in quotes - backslashes in the name
224 escape the next character, so quotes and backslashes can appear
225 in the name - and "expression" is a filter expression, not in
226 quotes, running to the end of the line. */
228 /* Skip over leading white space, if any. */
229 while ((c = getc(ff)) != EOF && isspace(c)) {
237 break; /* Nothing more to read */
239 /* "c" is the first non-white-space character.
240 If it's not a quote, it's an error. */
242 g_warning("'%s' line %d doesn't have a quoted filter name.", ff_path,
245 c = getc(ff); /* skip to the end of the line */
249 /* Get the name of the filter. */
253 if (c == EOF || c == '\n')
254 break; /* End of line - or end of file */
257 if (filt_name_index >= filt_name_len) {
258 /* Filter name buffer isn't long enough; double its length. */
260 filt_name = (char *)g_realloc(filt_name, filt_name_len + 1);
262 filt_name[filt_name_index] = '\0';
266 /* Next character is escaped */
268 if (c == EOF || c == '\n')
269 break; /* End of line - or end of file */
271 /* Add this character to the filter name string. */
272 if (filt_name_index >= filt_name_len) {
273 /* Filter name buffer isn't long enough; double its length. */
275 filt_name = (char *)g_realloc(filt_name, filt_name_len + 1);
277 filt_name[filt_name_index] = c;
283 /* EOF, not error; no newline seen before EOF */
284 g_warning("'%s' line %d doesn't have a newline.", ff_path,
287 break; /* nothing more to read */
291 /* No newline seen before end-of-line */
292 g_warning("'%s' line %d doesn't have a closing quote.", ff_path,
297 /* Skip over separating white space, if any. */
298 while ((c = getc(ff)) != EOF && isspace(c)) {
305 /* EOF, not error; no newline seen before EOF */
306 g_warning("'%s' line %d doesn't have a newline.", ff_path,
309 break; /* nothing more to read */
313 /* No filter expression */
314 g_warning("'%s' line %d doesn't have a filter expression.", ff_path,
319 /* "c" is the first non-white-space character; it's the first
320 character of the filter expression. */
323 /* Add this character to the filter expression string. */
324 if (filt_expr_index >= filt_expr_len) {
325 /* Filter expressioin buffer isn't long enough; double its length. */
327 filt_expr = (char *)g_realloc(filt_expr, filt_expr_len + 1);
329 filt_expr[filt_expr_index] = c;
332 /* Get the next character. */
334 if (c == EOF || c == '\n')
340 /* EOF, not error; no newline seen before EOF */
341 g_warning("'%s' line %d doesn't have a newline.", ff_path,
344 break; /* nothing more to read */
347 /* We saw the ending newline; terminate the filter expression string */
348 if (filt_expr_index >= filt_expr_len) {
349 /* Filter expressioin buffer isn't long enough; double its length. */
351 filt_expr = (char *)g_realloc(filt_expr, filt_expr_len + 1);
353 filt_expr[filt_expr_index] = '\0';
355 /* Add the new filter to the list of filters */
356 *flpp = add_filter_entry(*flpp, filt_name, filt_expr);
359 *pref_path_return = ff_path;
360 *errno_return = errno;
367 /* init the corresponding edited list */
370 copy_filter_list(CFILTER_EDITED_LIST, CFILTER_LIST);
373 copy_filter_list(DFILTER_EDITED_LIST, DFILTER_LIST);
376 g_assert_not_reached();
382 * Get a pointer to a list of filters.
385 get_filter_list(filter_list_type_t list_type)
392 flpp = &capture_filters;
396 flpp = &display_filters;
399 case CFILTER_EDITED_LIST:
400 flpp = &capture_edited_filters;
403 case DFILTER_EDITED_LIST:
404 flpp = &display_edited_filters;
408 g_assert_not_reached();
415 * Get a pointer to the first entry in a filter list.
418 get_filter_list_first(filter_list_type_t list_type)
422 flpp = get_filter_list(list_type);
423 return g_list_first(*flpp);
427 * Add a new filter to the end of a list.
428 * Returns a pointer to the newly-added entry.
431 add_to_filter_list(filter_list_type_t list_type, const char *name,
432 const char *expression)
436 flpp = get_filter_list(list_type);
437 *flpp = add_filter_entry(*flpp, name, expression);
439 return g_list_last(*flpp);
443 * Remove a filter from a list.
446 remove_from_filter_list(filter_list_type_t list_type, GList *fl_entry)
450 flpp = get_filter_list(list_type);
451 *flpp = remove_filter_entry(*flpp, fl_entry);
455 * Write out a list of filters.
457 * On success, "*pref_path_return" is set to NULL.
458 * On error, "*pref_path_return" is set to point to the pathname of
459 * the file we tried to read - it should be freed by our caller -
460 * and "*errno_return" is set to the error.
463 save_filter_list(filter_list_type_t list_type, char **pref_path_return,
466 const gchar *ff_name;
467 gchar *ff_path, *ff_path_new;
474 *pref_path_return = NULL; /* assume no error */
479 ff_name = CFILTER_FILE_NAME;
480 fl = capture_filters;
484 ff_name = DFILTER_FILE_NAME;
485 fl = display_filters;
489 g_assert_not_reached();
493 ff_path = get_persconffile_path(ff_name, TRUE, TRUE);
495 /* Write to "XXX.new", and rename if that succeeds.
496 That means we don't trash the file if we fail to write it out
498 ff_path_new = g_strdup_printf("%s.new", ff_path);
500 if ((ff = ws_fopen(ff_path_new, "w")) == NULL) {
501 *pref_path_return = ff_path;
502 *errno_return = errno;
506 flpp = g_list_first(fl);
508 filt = (filter_def *) flpp->data;
510 /* Write out the filter name as a quoted string; escape any quotes
513 for (p = (guchar *)filt->name; (c = *p) != '\0'; p++) {
514 if (c == '"' || c == '\\')
520 /* Separate the filter name and value with a space. */
523 /* Write out the filter expression and a newline. */
524 fprintf(ff, "%s\n", filt->strval);
526 *pref_path_return = ff_path;
527 *errno_return = errno;
529 ws_unlink(ff_path_new);
535 if (fclose(ff) == EOF) {
536 *pref_path_return = ff_path;
537 *errno_return = errno;
538 ws_unlink(ff_path_new);
544 /* ANSI C doesn't say whether "rename()" removes the target if it
545 exists; the Win32 call to rename files doesn't do so, which I
546 infer is the reason why the MSVC++ "rename()" doesn't do so.
547 We must therefore remove the target file first, on Windows. */
548 if (ws_remove(ff_path) < 0 && errno != ENOENT) {
549 /* It failed for some reason other than "it's not there"; if
550 it's not there, we don't need to remove it, so we just
552 *pref_path_return = ff_path;
553 *errno_return = errno;
554 ws_unlink(ff_path_new);
560 if (ws_rename(ff_path_new, ff_path) < 0) {
561 *pref_path_return = ff_path;
562 *errno_return = errno;
563 ws_unlink(ff_path_new);
572 * Copy a filter list into another.
574 void copy_filter_list(filter_list_type_t dest_type, filter_list_type_t src_type)
581 g_assert(dest_type != src_type);
583 flpp_dest = get_filter_list(dest_type);
584 flpp_src = get_filter_list(src_type);
587 /* throw away the "old" destination list - a NULL list is ok here */
589 *flpp_dest = remove_filter_entry(*flpp_dest, g_list_first(*flpp_dest));
591 g_assert(g_list_length(*flpp_dest) == 0);
593 /* copy the list entries */
595 filt = (filter_def *)(flp_src->data);
597 *flpp_dest = add_filter_entry(*flpp_dest, filt->name, filt->strval);
598 flp_src = g_list_next(flp_src);