HACK: pinfo->private_data points to smb_info again
[wireshark-wip.git] / epan / range.c
blobb546ceb463880c93784563a64056c215ac5cd673
1 /* range.c
2 * Range routines
4 * $Id$
6 * Dick Gooris <gooris@lucent.com>
7 * Ulf Lamping <ulf.lamping@web.de>
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
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.
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.
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.
28 #include "config.h"
30 #include <string.h>
31 #include <stdlib.h>
32 #include <ctype.h>
33 #include <errno.h>
35 #include <glib.h>
37 #include <epan/frame_data.h>
39 #include <epan/range.h>
40 #include <epan/emem.h>
41 #include <stdio.h>
44 * Size of the header of a range_t.
46 #define RANGE_HDR_SIZE (sizeof (range_t) - sizeof (range_admin_t))
48 /* Allocate an empty range. */
49 range_t *range_empty(void)
51 range_t *range;
53 range = (range_t *)g_malloc(RANGE_HDR_SIZE);
54 range->nranges = 0;
55 return range;
58 /******************** Range Entry Parser *********************************/
60 /* Converts a range string to a fast comparable array of ranges.
61 * The parameter 'es' points to the string to be converted.
62 * The parameter 'max_value' specifies the maximum value in a
63 * range.
65 * This function allocates a range_t large enough to hold the number
66 * of ranges specified, and fills the array range->ranges containing
67 * low and high values with the number of ranges being range->nranges.
68 * After having called this function, the function value_is_in_range()
69 * determines whether a given number is within the range or not.
71 * In case of a single number, we make a range where low is equal to high.
72 * We take care on wrongly entered ranges; opposite order will be taken
73 * care of.
75 * The following syntax is accepted :
77 * 1-20,30-40 Range from 1 to 20, and packets 30 to 40
78 * -20,30 Range from 1 to 20, and packet 30
79 * 20,30,40- 20, 30, and the range from 40 to the end
80 * 20-10,30-25 Range from 10 to 20, and from 25 to 30
81 * - All values
84 convert_ret_t
85 range_convert_str(range_t **rangep, const gchar *es, guint32 max_value)
87 return range_convert_str_work(rangep, es, max_value, TRUE);
90 /* This version of range_convert_str() allows the caller to specify whether
91 * values in excess of the range's specified maximum should cause an error or
92 * be silently lowered.
93 * XXX - both the function and the variable could probably use better names.
95 convert_ret_t
96 range_convert_str_work(range_t **rangep, const gchar *es, guint32 max_value,
97 gboolean err_on_max)
100 range_t *range;
101 guint nranges;
102 const gchar *p;
103 char *endp;
104 gchar c;
105 guint i;
106 guint32 tmp;
107 unsigned long val;
109 if ( (rangep == NULL) || (es == NULL) )
110 return CVT_SYNTAX_ERROR;
112 /* Allocate a range; this has room for one subrange. */
113 range = (range_t *)g_malloc(RANGE_HDR_SIZE + sizeof (range_admin_t));
114 range->nranges = 0;
115 nranges = 1;
117 /* Process the ranges separately until we get a comma or end of string.
119 * We build a structure array called ranges of high and low values. After the
120 * following loop, we have the nranges variable which tells how many ranges
121 * were found. The number of individual ranges is limited to 'MaxRanges'
124 p = es;
125 for (;;) {
126 /* Skip white space. */
127 while ((c = *p) == ' ' || c == '\t')
128 p++;
129 if (c == '\0')
130 break;
132 /* This must be a subrange. Make sure we have room for it. */
133 if (range->nranges >= nranges) {
134 /* Grow the structure.
135 * 4 is an arbitrarily chosen number.
136 * We start with 1, under the assumption that people
137 * will often give a single number or range, and then
138 * proceed to keep it a multiple of 4.
140 if (nranges == 1)
141 nranges = 4;
142 else
143 nranges += 4;
144 range = (range_t *)g_realloc(range, RANGE_HDR_SIZE +
145 nranges*sizeof (range_admin_t));
148 if (c == '-') {
149 /* Subrange starts with 1. */
150 range->ranges[range->nranges].low = 1;
151 } else if (isdigit((unsigned char)c)) {
152 /* Subrange starts with the specified number */
153 errno = 0;
154 val = strtoul(p, &endp, 10);
155 if (p == endp) {
156 /* That wasn't a valid number. */
157 g_free(range);
158 return CVT_SYNTAX_ERROR;
160 if (errno == ERANGE || val > max_value) {
161 /* That was valid, but it's too big. Return an error if requested
162 * (e.g., except when reading from the preferences file).
164 if (err_on_max) {
165 g_free(range);
166 return CVT_NUMBER_TOO_BIG;
167 } else {
168 /* Silently use the range's maximum value */
169 val = max_value;
172 p = endp;
173 range->ranges[range->nranges].low = (guint32)val;
175 /* Skip white space. */
176 while ((c = *p) == ' ' || c == '\t')
177 p++;
178 } else {
179 /* Neither empty nor a number. */
180 g_free(range);
181 return CVT_SYNTAX_ERROR;
184 if (c == '-') {
185 /* There's a hyphen in the range. Skip past it. */
186 p++;
188 /* Skip white space. */
189 while ((c = *p) == ' ' || c == '\t')
190 p++;
192 if (c == ',' || c == '\0') {
193 /* End of subrange string; that means the subrange ends
194 * with max_value.
196 range->ranges[range->nranges].high = max_value;
197 } else if (isdigit((unsigned char)c)) {
198 /* Subrange ends with the specified number. */
199 errno = 0;
200 val = strtoul(p, &endp, 10);
201 if (p == endp) {
202 /* That wasn't a valid number. */
203 g_free(range);
204 return CVT_SYNTAX_ERROR;
206 if (errno == ERANGE || val > max_value) {
207 /* That was valid, but it's too big. Return an error if requested
208 * (e.g., except when reading from the preferences file).
210 if (err_on_max) {
211 g_free(range);
212 return CVT_NUMBER_TOO_BIG;
213 } else {
214 /* Silently use the range's maximum value */
215 val = max_value;
218 p = endp;
219 range->ranges[range->nranges].high = (guint32)val;
221 /* Skip white space. */
222 while ((c = *p) == ' ' || c == '\t')
223 p++;
224 } else {
225 /* Neither empty nor a number. */
226 g_free(range);
227 return CVT_SYNTAX_ERROR;
229 } else if (c == ',' || c == '\0') {
230 /* End of subrange string; that means there's no hyphen
231 * in the subrange, so the start and the end are the same.
233 range->ranges[range->nranges].high = range->ranges[range->nranges].low;
234 } else {
235 /* Invalid character. */
236 g_free(range);
237 return CVT_SYNTAX_ERROR;
239 range->nranges++;
241 if (c == ',') {
242 /* Subrange is followed by a comma; skip it. */
243 p++;
247 /* Now we are going through the low and high values, and check
248 * whether they are in a proper order. Low should be equal or lower
249 * than high. So, go through the loop and swap if needed.
251 for (i=0; i < range->nranges; i++) {
252 if (range->ranges[i].low > range->ranges[i].high) {
253 tmp = range->ranges[i].low;
254 range->ranges[i].low = range->ranges[i].high;
255 range->ranges[i].high = tmp;
259 /* In case we want to know what the result ranges are :
261 * for (i=0; i < range->nranges; i++) {
262 * printf("Function : range_convert_str L=%u \t H=%u\n",range->ranges[i].low,range->ranges[i].high);
266 *rangep = range;
267 return CVT_NO_ERROR;
268 } /* range_convert_str */
270 /* This function returns TRUE if a given value is within one of the ranges
271 * stored in the ranges array.
273 gboolean
274 value_is_in_range(range_t *range, guint32 val)
276 guint i;
278 if (range) {
279 for (i=0; i < range->nranges; i++) {
280 if (val >= range->ranges[i].low && val <= range->ranges[i].high)
281 return TRUE;
284 return(FALSE);
287 /* This function returns TRUE if the two given range_t's are equal.
289 gboolean
290 ranges_are_equal(range_t *a, range_t *b)
292 guint i;
294 if ( (a == NULL) || (b == NULL) )
295 return FALSE;
297 if (a->nranges != b->nranges)
298 return FALSE;
300 for (i=0; i < a->nranges; i++) {
301 if (a->ranges[i].low != b->ranges[i].low)
302 return FALSE;
304 if (a->ranges[i].high != b->ranges[i].high)
305 return FALSE;
308 return TRUE;
312 /* This function calls the provided callback function for each value in
313 * in the range.
315 void
316 range_foreach(range_t *range, void (*callback)(guint32 val))
318 guint32 i, j;
320 if (range && callback) {
321 for (i=0; i < range->nranges; i++) {
322 for (j = range->ranges[i].low; j <= range->ranges[i].high; j++)
323 callback(j);
328 /* This function converts a range_t to a (ep_alloc()-allocated) string. */
329 char *
330 range_convert_range(range_t *range)
332 guint32 i;
333 gboolean prepend_comma = FALSE;
334 emem_strbuf_t *strbuf;
336 strbuf=ep_strbuf_new(NULL);
338 if (range) {
339 for (i=0; i < range->nranges; i++) {
340 if (range->ranges[i].low == range->ranges[i].high) {
341 ep_strbuf_append_printf(strbuf, "%s%u", prepend_comma?",":"", range->ranges[i].low);
342 } else {
343 ep_strbuf_append_printf(strbuf, "%s%u-%u", prepend_comma?",":"", range->ranges[i].low, range->ranges[i].high);
345 prepend_comma = TRUE;
348 return strbuf->str;
351 /* Create a copy of a range. */
352 range_t *
353 range_copy(range_t *src)
355 range_t *dst;
356 size_t range_size;
358 if (src == NULL)
359 return NULL;
361 range_size = RANGE_HDR_SIZE + src->nranges*sizeof (range_admin_t);
362 dst = (range_t *)g_malloc(range_size);
363 memcpy(dst, src, range_size);
364 return dst;
367 #if 0
368 /* This is a debug function to check the range functionality */
369 static void
370 value_is_in_range_check(range_t *range, guint32 val)
372 /* Print the result for a given value */
373 printf("Function : value_is_in_range_check Number %u\t",val);
375 if (value_is_in_range(range, val)) {
376 printf("is in range\n");
377 } else {
378 printf("is not in range\n");
381 #endif