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>
34 #include "filter_files.h"
37 * Old filter file name.
39 #define FILTER_FILE_NAME "filters"
42 * Capture filter file name.
44 #define CFILTER_FILE_NAME "cfilters"
47 * Display filter file name.
49 #define DFILTER_FILE_NAME "dfilters"
52 * List of capture filters - saved.
54 static GList *capture_filters = NULL;
57 * List of display filters - saved.
59 static GList *display_filters = NULL;
62 * List of capture filters - currently edited.
64 static GList *capture_edited_filters = NULL;
67 * List of display filters - currently edited.
69 static GList *display_edited_filters = NULL;
72 * Read in a list of filters.
74 * On success, "*pref_path_return" is set to NULL.
75 * On error, "*pref_path_return" is set to point to the pathname of
76 * the file we tried to read - it should be freed by our caller -
77 * and "*errno_return" is set to the error.
80 #define INIT_BUF_SIZE 128
83 add_filter_entry(GList *fl, const char *filt_name, const char *filt_expr)
87 filt = (filter_def *) g_malloc(sizeof(filter_def));
88 filt->name = g_strdup(filt_name);
89 filt->strval = g_strdup(filt_expr);
90 return g_list_append(fl, filt);
94 remove_filter_entry(GList *fl, GList *fl_entry)
98 filt = (filter_def *) fl_entry->data;
100 g_free(filt->strval);
102 return g_list_remove_link(fl, fl_entry);
106 skip_whitespace(FILE *ff)
110 while ((c = getc(ff)) != EOF && c != '\n' && g_ascii_isspace(c))
122 /* Treat CR-LF at the end of a line like LF, so that if we're reading
123 * a Windows-format file on UN*X, we handle it the same way we'd handle
124 * a UN*X-format file. */
126 if (c != EOF && c != '\n') {
127 /* Put back the character after the CR, and process the CR normally. */
136 read_filter_list(filter_list_type_t list_type, char **pref_path_return,
144 char *filt_name, *filt_expr;
145 int filt_name_len, filt_expr_len;
146 int filt_name_index, filt_expr_index;
149 *pref_path_return = NULL; /* assume no error */
154 ff_name = CFILTER_FILE_NAME;
155 flpp = &capture_filters;
159 ff_name = DFILTER_FILE_NAME;
160 flpp = &display_filters;
164 g_assert_not_reached();
168 /* try to open personal "cfilters"/"dfilters" file */
169 ff_path = get_persconffile_path(ff_name, TRUE);
170 if ((ff = ws_fopen(ff_path, "r")) == NULL) {
172 * Did that fail because the file didn't exist?
174 if (errno != ENOENT) {
178 *pref_path_return = ff_path;
179 *errno_return = errno;
184 * Yes. See if there's an "old style" personal "filters" file; if so, read it.
185 * This means that a user will start out with their capture and
186 * display filter lists being identical; each list may contain
187 * filters that don't belong in that list. The user can edit
188 * the filter lists, and delete the ones that don't belong in
192 ff_path = get_persconffile_path(FILTER_FILE_NAME, FALSE);
193 if ((ff = ws_fopen(ff_path, "r")) == NULL) {
195 * Did that fail because the file didn't exist?
197 if (errno != ENOENT) {
201 *pref_path_return = ff_path;
202 *errno_return = errno;
207 * Try to open the global "cfilters/dfilters" file */
209 ff_path = get_datafile_path(ff_name);
210 if ((ff = ws_fopen(ff_path, "r")) == NULL) {
213 * Well, that didn't work, either. Just give up.
214 * Return an error if the file existed but we couldn't open it.
216 if (errno != ENOENT) {
217 *pref_path_return = ff_path;
218 *errno_return = errno;
227 /* If we already have a list of filters, discard it. */
228 /* this should never happen - this function is called only once for each list! */
230 *flpp = remove_filter_entry(*flpp, g_list_first(*flpp));
233 /* Allocate the filter name buffer. */
234 filt_name_len = INIT_BUF_SIZE;
235 filt_name = (char *)g_malloc(filt_name_len + 1);
236 filt_expr_len = INIT_BUF_SIZE;
237 filt_expr = (char *)g_malloc(filt_expr_len + 1);
239 for (line = 1; ; line++) {
240 /* Lines in a filter file are of the form
244 where "name" is a name, in quotes - backslashes in the name
245 escape the next character, so quotes and backslashes can appear
246 in the name - and "expression" is a filter expression, not in
247 quotes, running to the end of the line. */
249 /* Skip over leading white space, if any. */
250 c = skip_whitespace(ff);
253 break; /* Nothing more to read */
255 continue; /* Blank line. */
257 /* "c" is the first non-white-space character.
258 If it's not a quote, it's an error. */
260 g_warning("'%s' line %d doesn't have a quoted filter name.", ff_path,
263 c = getc(ff); /* skip to the end of the line */
267 /* Get the name of the filter. */
271 if (c == EOF || c == '\n')
272 break; /* End of line - or end of file */
275 if (filt_name_index >= filt_name_len) {
276 /* Filter name buffer isn't long enough; double its length. */
278 filt_name = (char *)g_realloc(filt_name, filt_name_len + 1);
280 filt_name[filt_name_index] = '\0';
284 /* Next character is escaped */
286 if (c == EOF || c == '\n')
287 break; /* End of line - or end of file */
289 /* Add this character to the filter name string. */
290 if (filt_name_index >= filt_name_len) {
291 /* Filter name buffer isn't long enough; double its length. */
293 filt_name = (char *)g_realloc(filt_name, filt_name_len + 1);
295 filt_name[filt_name_index] = c;
301 /* EOF, not error; no newline seen before EOF */
302 g_warning("'%s' line %d doesn't have a newline.", ff_path,
305 break; /* nothing more to read */
309 /* No newline seen before end-of-line */
310 g_warning("'%s' line %d doesn't have a closing quote.", ff_path,
315 /* Skip over separating white space, if any. */
316 c = skip_whitespace(ff);
320 /* EOF, not error; no newline seen before EOF */
321 g_warning("'%s' line %d doesn't have a newline.", ff_path,
324 break; /* nothing more to read */
328 /* No filter expression */
329 g_warning("'%s' line %d doesn't have a filter expression.", ff_path,
334 /* "c" is the first non-white-space character; it's the first
335 character of the filter expression. */
338 /* Add this character to the filter expression string. */
339 if (filt_expr_index >= filt_expr_len) {
340 /* Filter expressioin buffer isn't long enough; double its length. */
342 filt_expr = (char *)g_realloc(filt_expr, filt_expr_len + 1);
344 filt_expr[filt_expr_index] = c;
347 /* Get the next character. */
349 if (c == EOF || c == '\n')
355 /* EOF, not error; no newline seen before EOF */
356 g_warning("'%s' line %d doesn't have a newline.", ff_path,
359 break; /* nothing more to read */
362 /* We saw the ending newline; terminate the filter expression string */
363 if (filt_expr_index >= filt_expr_len) {
364 /* Filter expressioin buffer isn't long enough; double its length. */
366 filt_expr = (char *)g_realloc(filt_expr, filt_expr_len + 1);
368 filt_expr[filt_expr_index] = '\0';
370 /* Add the new filter to the list of filters */
371 *flpp = add_filter_entry(*flpp, filt_name, filt_expr);
374 *pref_path_return = ff_path;
375 *errno_return = errno;
382 /* init the corresponding edited list */
385 copy_filter_list(CFILTER_EDITED_LIST, CFILTER_LIST);
388 copy_filter_list(DFILTER_EDITED_LIST, DFILTER_LIST);
391 g_assert_not_reached();
397 * Get a pointer to a list of filters.
400 get_filter_list(filter_list_type_t list_type)
407 flpp = &capture_filters;
411 flpp = &display_filters;
414 case CFILTER_EDITED_LIST:
415 flpp = &capture_edited_filters;
418 case DFILTER_EDITED_LIST:
419 flpp = &display_edited_filters;
423 g_assert_not_reached();
430 * Get a pointer to the first entry in a filter list.
433 get_filter_list_first(filter_list_type_t list_type)
437 flpp = get_filter_list(list_type);
438 return g_list_first(*flpp);
442 * Add a new filter to the end of a list.
443 * Returns a pointer to the newly-added entry.
446 add_to_filter_list(filter_list_type_t list_type, const char *name,
447 const char *expression)
451 flpp = get_filter_list(list_type);
452 *flpp = add_filter_entry(*flpp, name, expression);
454 return g_list_last(*flpp);
458 * Remove a filter from a list.
461 remove_from_filter_list(filter_list_type_t list_type, GList *fl_entry)
465 flpp = get_filter_list(list_type);
466 *flpp = remove_filter_entry(*flpp, fl_entry);
470 * Write out a list of filters.
472 * On success, "*pref_path_return" is set to NULL.
473 * On error, "*pref_path_return" is set to point to the pathname of
474 * the file we tried to read - it should be freed by our caller -
475 * and "*errno_return" is set to the error.
478 save_filter_list(filter_list_type_t list_type, char **pref_path_return,
481 const gchar *ff_name;
482 gchar *ff_path, *ff_path_new;
489 *pref_path_return = NULL; /* assume no error */
494 ff_name = CFILTER_FILE_NAME;
495 fl = capture_filters;
499 ff_name = DFILTER_FILE_NAME;
500 fl = display_filters;
504 g_assert_not_reached();
508 ff_path = get_persconffile_path(ff_name, TRUE);
510 /* Write to "XXX.new", and rename if that succeeds.
511 That means we don't trash the file if we fail to write it out
513 ff_path_new = g_strdup_printf("%s.new", ff_path);
515 if ((ff = ws_fopen(ff_path_new, "w")) == NULL) {
516 *pref_path_return = ff_path;
517 *errno_return = errno;
521 flpp = g_list_first(fl);
523 filt = (filter_def *) flpp->data;
525 /* Write out the filter name as a quoted string; escape any quotes
528 for (p = (guchar *)filt->name; (c = *p) != '\0'; p++) {
529 if (c == '"' || c == '\\')
535 /* Separate the filter name and value with a space. */
538 /* Write out the filter expression and a newline. */
539 fprintf(ff, "%s\n", filt->strval);
541 *pref_path_return = ff_path;
542 *errno_return = errno;
544 ws_unlink(ff_path_new);
550 if (fclose(ff) == EOF) {
551 *pref_path_return = ff_path;
552 *errno_return = errno;
553 ws_unlink(ff_path_new);
559 /* ANSI C doesn't say whether "rename()" removes the target if it
560 exists; the Win32 call to rename files doesn't do so, which I
561 infer is the reason why the MSVC++ "rename()" doesn't do so.
562 We must therefore remove the target file first, on Windows.
564 XXX - ws_rename() should be ws_stdio_rename() on Windows,
565 and ws_stdio_rename() uses MoveFileEx() with MOVEFILE_REPLACE_EXISTING,
566 so it should remove the target if it exists, so this stuff
567 shouldn't be necessary. Perhaps it dates back to when we were
568 calling rename(), with that being a wrapper around Microsoft's
569 _rename(), which didn't remove the target. */
570 if (ws_remove(ff_path) < 0 && errno != ENOENT) {
571 /* It failed for some reason other than "it's not there"; if
572 it's not there, we don't need to remove it, so we just
574 *pref_path_return = ff_path;
575 *errno_return = errno;
576 ws_unlink(ff_path_new);
582 if (ws_rename(ff_path_new, ff_path) < 0) {
583 *pref_path_return = ff_path;
584 *errno_return = errno;
585 ws_unlink(ff_path_new);
594 * Copy a filter list into another.
596 void copy_filter_list(filter_list_type_t dest_type, filter_list_type_t src_type)
603 g_assert(dest_type != src_type);
605 flpp_dest = get_filter_list(dest_type);
606 flpp_src = get_filter_list(src_type);
607 /* throw away the "old" destination list - a NULL list is ok here */
609 *flpp_dest = remove_filter_entry(*flpp_dest, g_list_first(*flpp_dest));
611 g_assert(g_list_length(*flpp_dest) == 0);
613 /* copy the list entries */
614 for(flp_src = g_list_first(*flpp_src); flp_src; flp_src = g_list_next(flp_src)) {
615 filt = (filter_def *)(flp_src->data);
617 *flpp_dest = add_filter_entry(*flpp_dest, filt->name, filt->strval);
622 * Editor modelines - http://www.wireshark.org/tools/modelines.html
627 * indent-tabs-mode: nil
630 * ex: set shiftwidth=2 tabstop=8 expandtab:
631 * :indentSize=2:tabSize=8:noTabs=true: