Witness: add pidl output
[wireshark-wip.git] / filters.c
blob5fb5ac4991a51d5872bc87a7638ee63bb557ff1e
1 /* filters.c
2 * Code for reading and writing the filters file.
4 * $Id$
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include "config.h"
27 #include <stdio.h>
28 #include <string.h>
29 #include <ctype.h>
30 #include <errno.h>
32 #ifdef HAVE_UNISTD_H
33 #include <unistd.h>
34 #endif
36 #include <glib.h>
38 #include <epan/filesystem.h>
40 #include "filters.h"
41 #include <wsutil/file_util.h>
44 * Old filter file name.
46 #define FILTER_FILE_NAME "filters"
49 * Capture filter file name.
51 #define CFILTER_FILE_NAME "cfilters"
54 * Display filter file name.
56 #define DFILTER_FILE_NAME "dfilters"
59 * List of capture filters - saved.
61 static GList *capture_filters = NULL;
64 * List of display filters - saved.
66 static GList *display_filters = NULL;
69 * List of capture filters - currently edited.
71 static GList *capture_edited_filters = NULL;
74 * List of display filters - currently edited.
76 static GList *display_edited_filters = NULL;
79 * Read in a list of filters.
81 * On success, "*pref_path_return" is set to NULL.
82 * On error, "*pref_path_return" is set to point to the pathname of
83 * the file we tried to read - it should be freed by our caller -
84 * and "*errno_return" is set to the error.
87 #define INIT_BUF_SIZE 128
89 static GList *
90 add_filter_entry(GList *fl, const char *filt_name, const char *filt_expr)
92 filter_def *filt;
94 filt = (filter_def *) g_malloc(sizeof(filter_def));
95 filt->name = g_strdup(filt_name);
96 filt->strval = g_strdup(filt_expr);
97 return g_list_append(fl, filt);
100 static GList *
101 remove_filter_entry(GList *fl, GList *fl_entry)
103 filter_def *filt;
105 filt = (filter_def *) fl_entry->data;
106 g_free(filt->name);
107 g_free(filt->strval);
108 g_free(filt);
109 return g_list_remove_link(fl, fl_entry);
112 void
113 read_filter_list(filter_list_type_t list_type, char **pref_path_return,
114 int *errno_return)
116 const char *ff_name;
117 char *ff_path;
118 FILE *ff;
119 GList **flpp;
120 int c;
121 char *filt_name, *filt_expr;
122 int filt_name_len, filt_expr_len;
123 int filt_name_index, filt_expr_index;
124 int line = 1;
126 *pref_path_return = NULL; /* assume no error */
128 switch (list_type) {
130 case CFILTER_LIST:
131 ff_name = CFILTER_FILE_NAME;
132 flpp = &capture_filters;
133 break;
135 case DFILTER_LIST:
136 ff_name = DFILTER_FILE_NAME;
137 flpp = &display_filters;
138 break;
140 default:
141 g_assert_not_reached();
142 return;
145 /* try to open personal "cfilters"/"dfilters" file */
146 ff_path = get_persconffile_path(ff_name, TRUE);
147 if ((ff = ws_fopen(ff_path, "r")) == NULL) {
149 * Did that fail because the file didn't exist?
151 if (errno != ENOENT) {
153 * No. Just give up.
155 *pref_path_return = ff_path;
156 *errno_return = errno;
157 return;
161 * Yes. See if there's an "old style" personal "filters" file; if so, read it.
162 * This means that a user will start out with their capture and
163 * display filter lists being identical; each list may contain
164 * filters that don't belong in that list. The user can edit
165 * the filter lists, and delete the ones that don't belong in
166 * a particular list.
168 g_free(ff_path);
169 ff_path = get_persconffile_path(FILTER_FILE_NAME, FALSE);
170 if ((ff = ws_fopen(ff_path, "r")) == NULL) {
172 * Did that fail because the file didn't exist?
174 if (errno != ENOENT) {
176 * No. Just give up.
178 *pref_path_return = ff_path;
179 *errno_return = errno;
180 return;
184 * Try to open the global "cfilters/dfilters" file */
185 g_free(ff_path);
186 ff_path = get_datafile_path(ff_name);
187 if ((ff = ws_fopen(ff_path, "r")) == NULL) {
190 * Well, that didn't work, either. Just give up.
191 * Return an error if the file existed but we couldn't open it.
193 if (errno != ENOENT) {
194 *pref_path_return = ff_path;
195 *errno_return = errno;
196 } else {
197 g_free(ff_path);
199 return;
204 /* If we already have a list of filters, discard it. */
205 /* this should never happen - this function is called only once for each list! */
206 while(*flpp) {
207 *flpp = remove_filter_entry(*flpp, g_list_first(*flpp));
210 /* Allocate the filter name buffer. */
211 filt_name_len = INIT_BUF_SIZE;
212 filt_name = (char *)g_malloc(filt_name_len + 1);
213 filt_expr_len = INIT_BUF_SIZE;
214 filt_expr = (char *)g_malloc(filt_expr_len + 1);
216 for (line = 1; ; line++) {
217 /* Lines in a filter file are of the form
219 "name" expression
221 where "name" is a name, in quotes - backslashes in the name
222 escape the next character, so quotes and backslashes can appear
223 in the name - and "expression" is a filter expression, not in
224 quotes, running to the end of the line. */
226 /* Skip over leading white space, if any. */
227 while ((c = getc(ff)) != EOF && isspace(c)) {
228 if (c == '\n') {
229 /* Blank line. */
230 continue;
234 if (c == EOF)
235 break; /* Nothing more to read */
237 /* "c" is the first non-white-space character.
238 If it's not a quote, it's an error. */
239 if (c != '"') {
240 g_warning("'%s' line %d doesn't have a quoted filter name.", ff_path,
241 line);
242 while (c != '\n')
243 c = getc(ff); /* skip to the end of the line */
244 continue;
247 /* Get the name of the filter. */
248 filt_name_index = 0;
249 for (;;) {
250 c = getc(ff);
251 if (c == EOF || c == '\n')
252 break; /* End of line - or end of file */
253 if (c == '"') {
254 /* Closing quote. */
255 if (filt_name_index >= filt_name_len) {
256 /* Filter name buffer isn't long enough; double its length. */
257 filt_name_len *= 2;
258 filt_name = (char *)g_realloc(filt_name, filt_name_len + 1);
260 filt_name[filt_name_index] = '\0';
261 break;
263 if (c == '\\') {
264 /* Next character is escaped */
265 c = getc(ff);
266 if (c == EOF || c == '\n')
267 break; /* End of line - or end of file */
269 /* Add this character to the filter name string. */
270 if (filt_name_index >= filt_name_len) {
271 /* Filter name buffer isn't long enough; double its length. */
272 filt_name_len *= 2;
273 filt_name = (char *)g_realloc(filt_name, filt_name_len + 1);
275 filt_name[filt_name_index] = c;
276 filt_name_index++;
279 if (c == EOF) {
280 if (!ferror(ff)) {
281 /* EOF, not error; no newline seen before EOF */
282 g_warning("'%s' line %d doesn't have a newline.", ff_path,
283 line);
285 break; /* nothing more to read */
288 if (c != '"') {
289 /* No newline seen before end-of-line */
290 g_warning("'%s' line %d doesn't have a closing quote.", ff_path,
291 line);
292 continue;
295 /* Skip over separating white space, if any. */
296 while ((c = getc(ff)) != EOF && isspace(c)) {
297 if (c == '\n')
298 break;
301 if (c == EOF) {
302 if (!ferror(ff)) {
303 /* EOF, not error; no newline seen before EOF */
304 g_warning("'%s' line %d doesn't have a newline.", ff_path,
305 line);
307 break; /* nothing more to read */
310 if (c == '\n') {
311 /* No filter expression */
312 g_warning("'%s' line %d doesn't have a filter expression.", ff_path,
313 line);
314 continue;
317 /* "c" is the first non-white-space character; it's the first
318 character of the filter expression. */
319 filt_expr_index = 0;
320 for (;;) {
321 /* Add this character to the filter expression string. */
322 if (filt_expr_index >= filt_expr_len) {
323 /* Filter expressioin buffer isn't long enough; double its length. */
324 filt_expr_len *= 2;
325 filt_expr = (char *)g_realloc(filt_expr, filt_expr_len + 1);
327 filt_expr[filt_expr_index] = c;
328 filt_expr_index++;
330 /* Get the next character. */
331 c = getc(ff);
332 if (c == EOF || c == '\n')
333 break;
336 if (c == EOF) {
337 if (!ferror(ff)) {
338 /* EOF, not error; no newline seen before EOF */
339 g_warning("'%s' line %d doesn't have a newline.", ff_path,
340 line);
342 break; /* nothing more to read */
345 /* We saw the ending newline; terminate the filter expression string */
346 if (filt_expr_index >= filt_expr_len) {
347 /* Filter expressioin buffer isn't long enough; double its length. */
348 filt_expr_len *= 2;
349 filt_expr = (char *)g_realloc(filt_expr, filt_expr_len + 1);
351 filt_expr[filt_expr_index] = '\0';
353 /* Add the new filter to the list of filters */
354 *flpp = add_filter_entry(*flpp, filt_name, filt_expr);
356 if (ferror(ff)) {
357 *pref_path_return = ff_path;
358 *errno_return = errno;
359 } else
360 g_free(ff_path);
361 fclose(ff);
362 g_free(filt_name);
363 g_free(filt_expr);
365 /* init the corresponding edited list */
366 switch (list_type) {
367 case CFILTER_LIST:
368 copy_filter_list(CFILTER_EDITED_LIST, CFILTER_LIST);
369 break;
370 case DFILTER_LIST:
371 copy_filter_list(DFILTER_EDITED_LIST, DFILTER_LIST);
372 break;
373 default:
374 g_assert_not_reached();
375 return;
380 * Get a pointer to a list of filters.
382 static GList **
383 get_filter_list(filter_list_type_t list_type)
385 GList **flpp;
387 switch (list_type) {
389 case CFILTER_LIST:
390 flpp = &capture_filters;
391 break;
393 case DFILTER_LIST:
394 flpp = &display_filters;
395 break;
397 case CFILTER_EDITED_LIST:
398 flpp = &capture_edited_filters;
399 break;
401 case DFILTER_EDITED_LIST:
402 flpp = &display_edited_filters;
403 break;
405 default:
406 g_assert_not_reached();
407 flpp = NULL;
409 return flpp;
413 * Get a pointer to the first entry in a filter list.
415 GList *
416 get_filter_list_first(filter_list_type_t list_type)
418 GList **flpp;
420 flpp = get_filter_list(list_type);
421 return g_list_first(*flpp);
425 * Add a new filter to the end of a list.
426 * Returns a pointer to the newly-added entry.
428 GList *
429 add_to_filter_list(filter_list_type_t list_type, const char *name,
430 const char *expression)
432 GList **flpp;
434 flpp = get_filter_list(list_type);
435 *flpp = add_filter_entry(*flpp, name, expression);
437 return g_list_last(*flpp);
441 * Remove a filter from a list.
443 void
444 remove_from_filter_list(filter_list_type_t list_type, GList *fl_entry)
446 GList **flpp;
448 flpp = get_filter_list(list_type);
449 *flpp = remove_filter_entry(*flpp, fl_entry);
453 * Write out a list of filters.
455 * On success, "*pref_path_return" is set to NULL.
456 * On error, "*pref_path_return" is set to point to the pathname of
457 * the file we tried to read - it should be freed by our caller -
458 * and "*errno_return" is set to the error.
460 void
461 save_filter_list(filter_list_type_t list_type, char **pref_path_return,
462 int *errno_return)
464 const gchar *ff_name;
465 gchar *ff_path, *ff_path_new;
466 GList *fl;
467 GList *flpp;
468 filter_def *filt;
469 FILE *ff;
470 guchar *p, c;
472 *pref_path_return = NULL; /* assume no error */
474 switch (list_type) {
476 case CFILTER_LIST:
477 ff_name = CFILTER_FILE_NAME;
478 fl = capture_filters;
479 break;
481 case DFILTER_LIST:
482 ff_name = DFILTER_FILE_NAME;
483 fl = display_filters;
484 break;
486 default:
487 g_assert_not_reached();
488 return;
491 ff_path = get_persconffile_path(ff_name, TRUE);
493 /* Write to "XXX.new", and rename if that succeeds.
494 That means we don't trash the file if we fail to write it out
495 completely. */
496 ff_path_new = g_strdup_printf("%s.new", ff_path);
498 if ((ff = ws_fopen(ff_path_new, "w")) == NULL) {
499 *pref_path_return = ff_path;
500 *errno_return = errno;
501 g_free(ff_path_new);
502 return;
504 flpp = g_list_first(fl);
505 while (flpp) {
506 filt = (filter_def *) flpp->data;
508 /* Write out the filter name as a quoted string; escape any quotes
509 or backslashes. */
510 putc('"', ff);
511 for (p = (guchar *)filt->name; (c = *p) != '\0'; p++) {
512 if (c == '"' || c == '\\')
513 putc('\\', ff);
514 putc(c, ff);
516 putc('"', ff);
518 /* Separate the filter name and value with a space. */
519 putc(' ', ff);
521 /* Write out the filter expression and a newline. */
522 fprintf(ff, "%s\n", filt->strval);
523 if (ferror(ff)) {
524 *pref_path_return = ff_path;
525 *errno_return = errno;
526 fclose(ff);
527 ws_unlink(ff_path_new);
528 g_free(ff_path_new);
529 return;
531 flpp = flpp->next;
533 if (fclose(ff) == EOF) {
534 *pref_path_return = ff_path;
535 *errno_return = errno;
536 ws_unlink(ff_path_new);
537 g_free(ff_path_new);
538 return;
541 #ifdef _WIN32
542 /* ANSI C doesn't say whether "rename()" removes the target if it
543 exists; the Win32 call to rename files doesn't do so, which I
544 infer is the reason why the MSVC++ "rename()" doesn't do so.
545 We must therefore remove the target file first, on Windows.
547 XXX - ws_rename() should be ws_stdio_rename() on Windows,
548 and ws_stdio_rename() uses MoveFileEx() with MOVEFILE_REPLACE_EXISTING,
549 so it should remove the target if it exists, so this stuff
550 shouldn't be necessary. Perhaps it dates back to when we were
551 calling rename(), with that being a wrapper around Microsoft's
552 _rename(), which didn't remove the target. */
553 if (ws_remove(ff_path) < 0 && errno != ENOENT) {
554 /* It failed for some reason other than "it's not there"; if
555 it's not there, we don't need to remove it, so we just
556 drive on. */
557 *pref_path_return = ff_path;
558 *errno_return = errno;
559 ws_unlink(ff_path_new);
560 g_free(ff_path_new);
561 return;
563 #endif
565 if (ws_rename(ff_path_new, ff_path) < 0) {
566 *pref_path_return = ff_path;
567 *errno_return = errno;
568 ws_unlink(ff_path_new);
569 g_free(ff_path_new);
570 return;
572 g_free(ff_path_new);
573 g_free(ff_path);
577 * Copy a filter list into another.
579 void copy_filter_list(filter_list_type_t dest_type, filter_list_type_t src_type)
581 GList **flpp_dest;
582 GList **flpp_src;
583 GList *flp_src;
584 filter_def *filt;
586 g_assert(dest_type != src_type);
588 flpp_dest = get_filter_list(dest_type);
589 flpp_src = get_filter_list(src_type);
590 /* throw away the "old" destination list - a NULL list is ok here */
591 while(*flpp_dest) {
592 *flpp_dest = remove_filter_entry(*flpp_dest, g_list_first(*flpp_dest));
594 g_assert(g_list_length(*flpp_dest) == 0);
596 /* copy the list entries */
597 for(flp_src = g_list_first(*flpp_src); flp_src; flp_src = g_list_next(flp_src)) {
598 filt = (filter_def *)(flp_src->data);
600 *flpp_dest = add_filter_entry(*flpp_dest, filt->name, filt->strval);