Handle an error message that includes single quotes.
[metze/wireshark/wip.git] / packet-range.c
1 /* packet-range.c
2  * Packet range routines (save, print, ...)
3  *
4  * $Id$
5  *
6  * Dick Gooris <gooris@lucent.com>
7  * Ulf Lamping <ulf.lamping@web.de>
8  *
9  * Wireshark - Network traffic analyzer
10  * By Gerald Combs <gerald@wireshark.org>
11  * Copyright 1998 Gerald Combs
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26  */
27
28 #include "config.h"
29
30 #include <stdio.h>
31 #include <string.h>
32 #include <ctype.h>
33
34 #include <glib.h>
35
36 #include <epan/frame_data.h>
37
38 #include "packet-range.h"
39
40 /* (re-)calculate the packet counts (except the user specified range) */
41 static void packet_range_calc(packet_range_t *range) {
42     guint32       framenum;
43     guint32       mark_low;
44     guint32       mark_high;
45     guint32       displayed_mark_low;
46     guint32       displayed_mark_high;
47     frame_data    *packet;
48
49
50     range->selected_packet        = 0L;
51
52     mark_low                      = 0L;
53     mark_high                     = 0L;
54     range->mark_range_cnt         = 0L;
55     range->ignored_cnt            = 0L;
56     range->ignored_marked_cnt     = 0L;
57     range->ignored_mark_range_cnt = 0L;
58     range->ignored_user_range_cnt = 0L;
59
60     displayed_mark_low            = 0L;
61     displayed_mark_high           = 0L;
62     range->displayed_cnt          = 0L;
63     range->displayed_marked_cnt   = 0L;
64     range->displayed_mark_range_cnt=0L;
65     range->displayed_plus_dependents_cnt    = 0L;
66     range->displayed_ignored_cnt            = 0L;
67     range->displayed_ignored_marked_cnt     = 0L;
68     range->displayed_ignored_mark_range_cnt = 0L;
69     range->displayed_ignored_user_range_cnt = 0L;
70
71     g_assert(range->cf != NULL);
72
73     /* XXX - this doesn't work unless you have a full set of frame_data
74      * structures for all packets in the capture, which is not,
75      * for example, the case when TShark is doing a one-pass
76      * read of a file or a live capture.
77      *
78      * It's also horribly slow on large captures, causing it to
79      * take a long time for the Save As dialog to pop up, for
80      * example.  We should really keep these statistics in
81      * the capture_file structure, updating them whenever we
82      * filter the display, etc..
83      */
84     if (range->cf->frames != NULL) {
85         /* The next for-loop is used to obtain the amount of packets
86          * to be processed and is used to present the information in
87          * the Save/Print As widget.
88          * We have different types of ranges: All the packets, the number
89          * of packets of a marked range, a single packet, and a user specified
90          * packet range. The last one is not calculated here since this
91          * data must be entered in the widget by the user.
92          */
93
94         for(framenum = 1; framenum <= range->cf->count; framenum++) {
95             packet = frame_data_sequence_find(range->cf->frames, framenum);
96
97             if (range->cf->current_frame == packet) {
98                 range->selected_packet = framenum;
99             }
100             if (packet->flags.passed_dfilter) {
101                 range->displayed_cnt++;
102             }
103             if (packet->flags.passed_dfilter ||
104                 packet->flags.dependent_of_displayed) {
105                 range->displayed_plus_dependents_cnt++;
106             }
107             if (packet->flags.marked) {
108                 if (packet->flags.ignored) {
109                     range->ignored_marked_cnt++;
110                 }
111                 if (packet->flags.passed_dfilter) {
112                     range->displayed_marked_cnt++;
113                     if (packet->flags.ignored) {
114                         range->displayed_ignored_marked_cnt++;
115                     }
116                     if (displayed_mark_low == 0) {
117                        displayed_mark_low = framenum;
118                     }
119                     if (framenum > displayed_mark_high) {
120                        displayed_mark_high = framenum;
121                     }
122                 }
123
124                 if (mark_low == 0) {
125                    mark_low = framenum;
126                 }
127                 if (framenum > mark_high) {
128                    mark_high = framenum;
129                 }
130             }
131             if (packet->flags.ignored) {
132                 range->ignored_cnt++;
133                 if (packet->flags.passed_dfilter) {
134                     range->displayed_ignored_cnt++;
135                 }
136             }
137         }
138
139         for(framenum = 1; framenum <= range->cf->count; framenum++) {
140             packet = frame_data_sequence_find(range->cf->frames, framenum);
141
142             if (framenum >= mark_low &&
143                 framenum <= mark_high)
144             {
145                 range->mark_range_cnt++;
146                 if (packet->flags.ignored) {
147                     range->ignored_mark_range_cnt++;
148                 }
149             }
150
151             if (framenum >= displayed_mark_low &&
152                 framenum <= displayed_mark_high)
153             {
154                 if (packet->flags.passed_dfilter) {
155                     range->displayed_mark_range_cnt++;
156                     if (packet->flags.ignored) {
157                         range->displayed_ignored_mark_range_cnt++;
158                     }
159                 }
160             }
161         }
162
163 #if 0
164         /* in case we marked just one packet, we add 1. */
165         if (range->cf->marked_count != 0) {
166             range->mark_range = mark_high - mark_low + 1;
167         }
168
169         /* in case we marked just one packet, we add 1. */
170         if (range->displayed_marked_cnt != 0) {
171             range->displayed_mark_range = displayed_mark_high - displayed_mark_low + 1;
172         }
173 #endif
174     }
175 }
176
177
178 /* (re-)calculate the user specified packet range counts */
179 static void packet_range_calc_user(packet_range_t *range) {
180     guint32       framenum;
181     frame_data    *packet;
182
183     range->user_range_cnt             = 0L;
184     range->ignored_user_range_cnt     = 0L;
185     range->displayed_user_range_cnt   = 0L;
186     range->displayed_ignored_user_range_cnt = 0L;
187
188     g_assert(range->cf != NULL);
189
190     /* XXX - this doesn't work unless you have a full set of frame_data
191      * structures for all packets in the capture, which is not,
192      * for example, the case when TShark is doing a one-pass
193      * read of a file or a live capture.
194      *
195      * It's also horribly slow on large captures, causing it to
196      * take a long time for the Save As dialog to pop up, for
197      * example.  This obviously can't be kept in the capture_file
198      * structure and recalculated whenever we filter the display
199      * or mark frames as ignored, as the results of this depend
200      * on what the user specifies.  In some cases, limiting the
201      * frame_data structures at which we look to the ones specified
202      * by the user might help, but if most of the frames are in
203      * the range, that won't help.  In that case, if we could
204      * examine the *complement* of the range, and *subtract* them
205      * from the statistics for the capture as a whole, that might
206      * help, but if the user specified about *half* the packets in
207      * the range, that won't help, either.
208      */
209     if (range->cf->frames != NULL) {
210         for(framenum = 1; framenum <= range->cf->count; framenum++) {
211             packet = frame_data_sequence_find(range->cf->frames, framenum);
212
213             if (value_is_in_range(range->user_range, framenum)) {
214                 range->user_range_cnt++;
215                 if (packet->flags.ignored) {
216                     range->ignored_user_range_cnt++;
217                 }
218                 if (packet->flags.passed_dfilter) {
219                     range->displayed_user_range_cnt++;
220                     if (packet->flags.ignored) {
221                         range->displayed_ignored_user_range_cnt++;
222                     }
223                 }
224             }
225         }
226     }
227 }
228
229
230 /* init the range struct */
231 void packet_range_init(packet_range_t *range, capture_file *cf) {
232
233     memset(range, 0, sizeof(packet_range_t));
234     range->process    = range_process_all;
235     range->user_range = range_empty();
236     range->cf         = cf;
237
238     /* calculate all packet range counters */
239     packet_range_calc(range);
240     packet_range_calc_user(range);
241 }
242
243 /* check whether the packet range is OK */
244 convert_ret_t packet_range_check(packet_range_t *range) {
245     if (range->process == range_process_user_range && range->user_range == NULL) {
246         /* Not valid - return the error. */
247         return range->user_range_status;
248     }
249     return CVT_NO_ERROR;
250 }
251
252 /* init the processing run */
253 void packet_range_process_init(packet_range_t *range) {
254     /* Check that, if an explicit range was selected, it's valid. */
255     /* "enumeration" values */
256     range->marked_range_active    = FALSE;
257     range->selected_done          = FALSE;
258
259     if (range->process_filtered == FALSE) {
260         range->marked_range_left = range->mark_range_cnt;
261     } else {
262         range->marked_range_left = range->displayed_mark_range_cnt;
263     }
264 }
265
266 /* do we have to process all packets? */
267 gboolean packet_range_process_all(packet_range_t *range) {
268     return range->process == range_process_all && !range->process_filtered && !range->remove_ignored;
269 }
270
271 /* do we have to process this packet? */
272 range_process_e packet_range_process_packet(packet_range_t *range, frame_data *fdata) {
273
274     if (range->remove_ignored && fdata->flags.ignored) {
275         return range_process_next;
276     }
277
278     g_assert(range->cf != NULL);
279
280     switch(range->process) {
281     case(range_process_all):
282         break;
283     case(range_process_selected):
284         if (range->selected_done) {
285           return range_processing_finished;
286         }
287         if (fdata->num != range->cf->current_frame->num) {
288           return range_process_next;
289         }
290         range->selected_done = TRUE;
291         break;
292     case(range_process_marked):
293         if (fdata->flags.marked == FALSE) {
294           return range_process_next;
295         }
296         break;
297     case(range_process_marked_range):
298         if (range->marked_range_left == 0) {
299           return range_processing_finished;
300         }
301         if (fdata->flags.marked == TRUE) {
302           range->marked_range_active = TRUE;
303         }
304         if (range->marked_range_active == FALSE ) {
305           return range_process_next;
306         }
307         if (!range->process_filtered ||
308           (range->process_filtered && fdata->flags.passed_dfilter == TRUE))
309         {
310           range->marked_range_left--;
311         }
312         break;
313     case(range_process_user_range):
314         if (value_is_in_range(range->user_range, fdata->num) == FALSE) {
315           return range_process_next;
316         }
317         break;
318     default:
319         g_assert_not_reached();
320     }
321
322     /* This packet has to pass the display filter but didn't?
323      * Try next, but only if we're not including dependent packets and this
324      * packet happens to be a dependency on something that is displayed.
325      */
326     if ((range->process_filtered && fdata->flags.passed_dfilter == FALSE) &&
327         !(range->include_dependents && fdata->flags.dependent_of_displayed)) {
328         return range_process_next;
329     }
330
331     /* We fell through the conditions above, so we accept this packet */
332     return range_process_this;
333 }
334
335
336 /******************** Range Entry Parser *********************************/
337
338 /* Converts a range string to a user range.
339  * The parameter 'es' points to the string to be converted, and is defined in
340  * the Save/Print-As widget.
341  */
342
343 void packet_range_convert_str(packet_range_t *range, const gchar *es)
344 {
345     range_t *new_range;
346     convert_ret_t ret;
347
348     if (range->user_range != NULL)
349         g_free(range->user_range);
350
351     g_assert(range->cf != NULL);
352
353     ret = range_convert_str(&new_range, es, range->cf->count);
354     if (ret != CVT_NO_ERROR) {
355         /* range isn't valid */
356         range->user_range                 = NULL;
357         range->user_range_status          = ret;
358         range->user_range_cnt             = 0L;
359         range->ignored_user_range_cnt     = 0L;
360         range->displayed_user_range_cnt   = 0L;
361         range->displayed_ignored_user_range_cnt = 0L;
362         return;
363     }
364     range->user_range = new_range;
365
366     /* calculate new user specified packet range counts */
367     packet_range_calc_user(range);
368 } /* packet_range_convert_str */