2 * Code for reading and writing the filters file.
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
13 * This program 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.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
31 #include <wsutil/file_util.h>
32 #include <wsutil/filesystem.h>
33 #include <wsutil/glib-compat.h>
35 #include "filter_files.h"
38 * Old filter file name.
40 #define FILTER_FILE_NAME "filters"
43 * Capture filter file name.
45 #define CFILTER_FILE_NAME "cfilters"
48 * Display filter file name.
50 #define DFILTER_FILE_NAME "dfilters"
53 * List of capture filters - saved.
55 static GList *capture_filters = NULL;
58 * List of display filters - saved.
60 static GList *display_filters = NULL;
63 * List of capture filters - currently edited.
65 static GList *capture_edited_filters = NULL;
68 * List of display filters - currently edited.
70 static GList *display_edited_filters = NULL;
73 * Read in a list of filters.
75 * On success, "*pref_path_return" is set to NULL.
76 * On error, "*pref_path_return" is set to point to the pathname of
77 * the file we tried to read - it should be freed by our caller -
78 * and "*errno_return" is set to the error.
81 #define INIT_BUF_SIZE 128
84 add_filter_entry(GList *fl, const char *filt_name, const char *filt_expr)
88 filt = (filter_def *) g_malloc(sizeof(filter_def));
89 filt->name = g_strdup(filt_name);
90 filt->strval = g_strdup(filt_expr);
91 return g_list_append(fl, filt);
95 free_filter_entry(gpointer data)
97 filter_def *filt = (filter_def*)data;
103 void free_filter_lists(void)
105 if (capture_filters) {
106 g_list_free_full(capture_filters, free_filter_entry);
107 capture_filters = NULL;
109 if (display_filters) {
110 g_list_free_full(display_filters, free_filter_entry);
111 display_filters = NULL;
113 if (capture_edited_filters) {
114 g_list_free_full(capture_edited_filters, free_filter_entry);
115 capture_edited_filters = NULL;
117 if (display_edited_filters) {
118 g_list_free_full(display_edited_filters, free_filter_entry);
119 display_edited_filters = NULL;
124 remove_filter_entry(GList *fl, GList *fl_entry)
128 filt = (filter_def *) fl_entry->data;
130 g_free(filt->strval);
132 return g_list_remove_link(fl, fl_entry);
136 skip_whitespace(FILE *ff)
140 while ((c = getc(ff)) != EOF && c != '\n' && g_ascii_isspace(c))
152 /* Treat CR-LF at the end of a line like LF, so that if we're reading
153 * a Windows-format file on UN*X, we handle it the same way we'd handle
154 * a UN*X-format file. */
156 if (c != EOF && c != '\n') {
157 /* Put back the character after the CR, and process the CR normally. */
166 read_filter_list(filter_list_type_t list_type, char **pref_path_return,
174 char *filt_name, *filt_expr;
175 int filt_name_len, filt_expr_len;
176 int filt_name_index, filt_expr_index;
179 *pref_path_return = NULL; /* assume no error */
184 ff_name = CFILTER_FILE_NAME;
185 flpp = &capture_filters;
189 ff_name = DFILTER_FILE_NAME;
190 flpp = &display_filters;
194 g_assert_not_reached();
198 /* try to open personal "cfilters"/"dfilters" file */
199 ff_path = get_persconffile_path(ff_name, TRUE);
200 if ((ff = ws_fopen(ff_path, "r")) == NULL) {
202 * Did that fail because the file didn't exist?
204 if (errno != ENOENT) {
208 *pref_path_return = ff_path;
209 *errno_return = errno;
214 * Yes. See if there's an "old style" personal "filters" file; if so, read it.
215 * This means that a user will start out with their capture and
216 * display filter lists being identical; each list may contain
217 * filters that don't belong in that list. The user can edit
218 * the filter lists, and delete the ones that don't belong in
222 ff_path = get_persconffile_path(FILTER_FILE_NAME, FALSE);
223 if ((ff = ws_fopen(ff_path, "r")) == NULL) {
225 * Did that fail because the file didn't exist?
227 if (errno != ENOENT) {
231 *pref_path_return = ff_path;
232 *errno_return = errno;
237 * Try to open the global "cfilters/dfilters" file */
239 ff_path = get_datafile_path(ff_name);
240 if ((ff = ws_fopen(ff_path, "r")) == NULL) {
243 * Well, that didn't work, either. Just give up.
244 * Return an error if the file existed but we couldn't open it.
246 if (errno != ENOENT) {
247 *pref_path_return = ff_path;
248 *errno_return = errno;
257 /* If we already have a list of filters, discard it. */
258 /* this should never happen - this function is called only once for each list! */
260 *flpp = remove_filter_entry(*flpp, g_list_first(*flpp));
263 /* Allocate the filter name buffer. */
264 filt_name_len = INIT_BUF_SIZE;
265 filt_name = (char *)g_malloc(filt_name_len + 1);
266 filt_expr_len = INIT_BUF_SIZE;
267 filt_expr = (char *)g_malloc(filt_expr_len + 1);
269 for (line = 1; ; line++) {
270 /* Lines in a filter file are of the form
274 where "name" is a name, in quotes - backslashes in the name
275 escape the next character, so quotes and backslashes can appear
276 in the name - and "expression" is a filter expression, not in
277 quotes, running to the end of the line. */
279 /* Skip over leading white space, if any. */
280 c = skip_whitespace(ff);
283 break; /* Nothing more to read */
285 continue; /* Blank line. */
287 /* "c" is the first non-white-space character.
288 If it's not a quote, it's an error. */
290 g_warning("'%s' line %d doesn't have a quoted filter name.", ff_path,
293 c = getc(ff); /* skip to the end of the line */
297 /* Get the name of the filter. */
301 if (c == EOF || c == '\n')
302 break; /* End of line - or end of file */
305 if (filt_name_index >= filt_name_len) {
306 /* Filter name buffer isn't long enough; double its length. */
308 filt_name = (char *)g_realloc(filt_name, filt_name_len + 1);
310 filt_name[filt_name_index] = '\0';
314 /* Next character is escaped */
316 if (c == EOF || c == '\n')
317 break; /* End of line - or end of file */
319 /* Add this character to the filter name string. */
320 if (filt_name_index >= filt_name_len) {
321 /* Filter name buffer isn't long enough; double its length. */
323 filt_name = (char *)g_realloc(filt_name, filt_name_len + 1);
325 filt_name[filt_name_index] = c;
331 /* EOF, not error; no newline seen before EOF */
332 g_warning("'%s' line %d doesn't have a newline.", ff_path,
335 break; /* nothing more to read */
339 /* No newline seen before end-of-line */
340 g_warning("'%s' line %d doesn't have a closing quote.", ff_path,
345 /* Skip over separating white space, if any. */
346 c = skip_whitespace(ff);
350 /* EOF, not error; no newline seen before EOF */
351 g_warning("'%s' line %d doesn't have a newline.", ff_path,
354 break; /* nothing more to read */
358 /* No filter expression */
359 g_warning("'%s' line %d doesn't have a filter expression.", ff_path,
364 /* "c" is the first non-white-space character; it's the first
365 character of the filter expression. */
368 /* Add this character to the filter expression string. */
369 if (filt_expr_index >= filt_expr_len) {
370 /* Filter expressioin buffer isn't long enough; double its length. */
372 filt_expr = (char *)g_realloc(filt_expr, filt_expr_len + 1);
374 filt_expr[filt_expr_index] = c;
377 /* Get the next character. */
379 if (c == EOF || c == '\n')
385 /* EOF, not error; no newline seen before EOF */
386 g_warning("'%s' line %d doesn't have a newline.", ff_path,
389 break; /* nothing more to read */
392 /* We saw the ending newline; terminate the filter expression string */
393 if (filt_expr_index >= filt_expr_len) {
394 /* Filter expressioin buffer isn't long enough; double its length. */
396 filt_expr = (char *)g_realloc(filt_expr, filt_expr_len + 1);
398 filt_expr[filt_expr_index] = '\0';
400 /* Add the new filter to the list of filters */
401 *flpp = add_filter_entry(*flpp, filt_name, filt_expr);
404 *pref_path_return = ff_path;
405 *errno_return = errno;
412 /* init the corresponding edited list */
415 copy_filter_list(CFILTER_EDITED_LIST, CFILTER_LIST);
418 copy_filter_list(DFILTER_EDITED_LIST, DFILTER_LIST);
421 g_assert_not_reached();
427 * Get a pointer to a list of filters.
430 get_filter_list(filter_list_type_t list_type)
437 flpp = &capture_filters;
441 flpp = &display_filters;
444 case CFILTER_EDITED_LIST:
445 flpp = &capture_edited_filters;
448 case DFILTER_EDITED_LIST:
449 flpp = &display_edited_filters;
453 g_assert_not_reached();
460 * Get a pointer to the first entry in a filter list.
463 get_filter_list_first(filter_list_type_t list_type)
467 flpp = get_filter_list(list_type);
468 return g_list_first(*flpp);
472 * Add a new filter to the end of a list.
473 * Returns a pointer to the newly-added entry.
476 add_to_filter_list(filter_list_type_t list_type, const char *name,
477 const char *expression)
481 flpp = get_filter_list(list_type);
482 *flpp = add_filter_entry(*flpp, name, expression);
484 return g_list_last(*flpp);
488 * Remove a filter from a list.
491 remove_from_filter_list(filter_list_type_t list_type, GList *fl_entry)
495 flpp = get_filter_list(list_type);
496 *flpp = remove_filter_entry(*flpp, fl_entry);
500 * Write out a list of filters.
502 * On success, "*pref_path_return" is set to NULL.
503 * On error, "*pref_path_return" is set to point to the pathname of
504 * the file we tried to read - it should be freed by our caller -
505 * and "*errno_return" is set to the error.
508 save_filter_list(filter_list_type_t list_type, char **pref_path_return,
511 const gchar *ff_name;
512 gchar *ff_path, *ff_path_new;
519 *pref_path_return = NULL; /* assume no error */
524 ff_name = CFILTER_FILE_NAME;
525 fl = capture_filters;
529 ff_name = DFILTER_FILE_NAME;
530 fl = display_filters;
534 g_assert_not_reached();
538 ff_path = get_persconffile_path(ff_name, TRUE);
540 /* Write to "XXX.new", and rename if that succeeds.
541 That means we don't trash the file if we fail to write it out
543 ff_path_new = g_strdup_printf("%s.new", ff_path);
545 if ((ff = ws_fopen(ff_path_new, "w")) == NULL) {
546 *pref_path_return = ff_path;
547 *errno_return = errno;
551 flpp = g_list_first(fl);
553 filt = (filter_def *) flpp->data;
555 /* Write out the filter name as a quoted string; escape any quotes
558 for (p = (guchar *)filt->name; (c = *p) != '\0'; p++) {
559 if (c == '"' || c == '\\')
565 /* Separate the filter name and value with a space. */
568 /* Write out the filter expression and a newline. */
569 fprintf(ff, "%s\n", filt->strval);
571 *pref_path_return = ff_path;
572 *errno_return = errno;
574 ws_unlink(ff_path_new);
580 if (fclose(ff) == EOF) {
581 *pref_path_return = ff_path;
582 *errno_return = errno;
583 ws_unlink(ff_path_new);
589 /* ANSI C doesn't say whether "rename()" removes the target if it
590 exists; the Win32 call to rename files doesn't do so, which I
591 infer is the reason why the MSVC++ "rename()" doesn't do so.
592 We must therefore remove the target file first, on Windows.
594 XXX - ws_rename() should be ws_stdio_rename() on Windows,
595 and ws_stdio_rename() uses MoveFileEx() with MOVEFILE_REPLACE_EXISTING,
596 so it should remove the target if it exists, so this stuff
597 shouldn't be necessary. Perhaps it dates back to when we were
598 calling rename(), with that being a wrapper around Microsoft's
599 _rename(), which didn't remove the target. */
600 if (ws_remove(ff_path) < 0 && errno != ENOENT) {
601 /* It failed for some reason other than "it's not there"; if
602 it's not there, we don't need to remove it, so we just
604 *pref_path_return = ff_path;
605 *errno_return = errno;
606 ws_unlink(ff_path_new);
612 if (ws_rename(ff_path_new, ff_path) < 0) {
613 *pref_path_return = ff_path;
614 *errno_return = errno;
615 ws_unlink(ff_path_new);
624 * Copy a filter list into another.
626 void copy_filter_list(filter_list_type_t dest_type, filter_list_type_t src_type)
633 g_assert(dest_type != src_type);
635 flpp_dest = get_filter_list(dest_type);
636 flpp_src = get_filter_list(src_type);
637 /* throw away the "old" destination list - a NULL list is ok here */
639 *flpp_dest = remove_filter_entry(*flpp_dest, g_list_first(*flpp_dest));
641 g_assert(g_list_length(*flpp_dest) == 0);
643 /* copy the list entries */
644 for(flp_src = g_list_first(*flpp_src); flp_src; flp_src = g_list_next(flp_src)) {
645 filt = (filter_def *)(flp_src->data);
647 *flpp_dest = add_filter_entry(*flpp_dest, filt->name, filt->strval);
652 * Editor modelines - http://www.wireshark.org/tools/modelines.html
657 * indent-tabs-mode: nil
660 * ex: set shiftwidth=2 tabstop=8 expandtab:
661 * :indentSize=2:tabSize=8:noTabs=true: