4 * Dick Gooris <gooris@lucent.com>
5 * Ulf Lamping <ulf.lamping@web.de>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * SPDX-License-Identifier: GPL-2.0-or-later
23 #include <epan/frame_data.h>
25 #include <epan/range.h>
27 #include <wsutil/strtoi.h>
30 * Size of the header of a range_t.
32 #define RANGE_HDR_SIZE (sizeof (range_t))
34 /* Allocate an empty range. */
35 range_t
*range_empty(wmem_allocator_t
*scope
)
39 range
= (range_t
*)wmem_alloc(scope
, RANGE_HDR_SIZE
);
44 /******************** Range Entry Parser *********************************/
46 /* Converts a range string to a fast comparable array of ranges.
47 * The parameter 'es' points to the string to be converted.
48 * The parameter 'max_value' specifies the maximum value in a
51 * This function allocates a range_t large enough to hold the number
52 * of ranges specified, and fills the array range->ranges containing
53 * low and high values with the number of ranges being range->nranges.
54 * After having called this function, the function value_is_in_range()
55 * determines whether a given number is within the range or not.
57 * In case of a single number, we make a range where low is equal to high.
58 * We take care on wrongly entered ranges; opposite order will be taken
61 * The following syntax is accepted :
63 * 1-20,30-40 Range from 1 to 20, and packets 30 to 40
64 * -20,30 Range from 1 to 20, and packet 30
65 * 20,30,40- 20, 30, and the range from 40 to the end
66 * 20-10,30-25 Range from 10 to 20, and from 25 to 30
71 range_convert_str(wmem_allocator_t
*scope
, range_t
**rangep
, const char *es
, uint32_t max_value
)
73 return range_convert_str_work(scope
, rangep
, es
, max_value
, true);
76 /* This version of range_convert_str() allows the caller to specify whether
77 * values in excess of the range's specified maximum should cause an error or
78 * be silently lowered.
79 * XXX - both the function and the variable could probably use better names.
82 range_convert_str_work(wmem_allocator_t
*scope
, range_t
**rangep
, const char *es
, uint32_t max_value
,
95 if ( (rangep
== NULL
) || (es
== NULL
) )
96 return CVT_SYNTAX_ERROR
;
98 /* Allocate a range; this has room for one subrange. */
99 range
= (range_t
*)wmem_alloc(scope
, RANGE_HDR_SIZE
+ sizeof (range_admin_t
));
103 /* Process the ranges separately until we get a comma or end of string.
105 * We build a structure array called ranges of high and low values. After the
106 * following loop, we have the nranges variable which tells how many ranges
107 * were found. The number of individual ranges is limited to 'MaxRanges'
112 /* Skip white space. */
113 while ((c
= *p
) == ' ' || c
== '\t')
118 /* This must be a subrange. Make sure we have room for it. */
119 if (range
->nranges
>= nranges
) {
120 /* Grow the structure.
121 * 4 is an arbitrarily chosen number.
122 * We start with 1, under the assumption that people
123 * will often give a single number or range, and then
124 * proceed to keep it a multiple of 4.
130 range
= (range_t
*)wmem_realloc(scope
, range
, RANGE_HDR_SIZE
+
131 nranges
*sizeof (range_admin_t
));
135 /* Subrange starts with 1. */
136 range
->ranges
[range
->nranges
].low
= 1;
137 } else if (g_ascii_isdigit(c
)) {
138 /* Subrange starts with the specified number */
140 ws_basestrtou32(p
, &endp
, &val
, 0);
141 if (errno
== EINVAL
) {
142 /* That wasn't a valid number. */
143 wmem_free(scope
, range
);
144 return CVT_SYNTAX_ERROR
;
146 if (errno
== ERANGE
|| val
> max_value
) {
147 /* That was valid, but it's too big. Return an error if requested
148 * (e.g., except when reading from the preferences file).
151 wmem_free(scope
, range
);
152 return CVT_NUMBER_TOO_BIG
;
154 /* Silently use the range's maximum value */
159 range
->ranges
[range
->nranges
].low
= val
;
161 /* Skip white space. */
162 while ((c
= *p
) == ' ' || c
== '\t')
165 /* Neither empty nor a number. */
166 wmem_free(scope
, range
);
167 return CVT_SYNTAX_ERROR
;
171 /* There's a hyphen in the range. Skip past it. */
174 /* Skip white space. */
175 while ((c
= *p
) == ' ' || c
== '\t')
178 if (c
== ',' || c
== '\0') {
179 /* End of subrange string; that means the subrange ends
182 range
->ranges
[range
->nranges
].high
= max_value
;
183 } else if (g_ascii_isdigit(c
)) {
184 /* Subrange ends with the specified number. */
186 ws_basestrtou32(p
, &endp
, &val
, 0);
187 if (errno
== EINVAL
) {
188 /* That wasn't a valid number. */
189 wmem_free(scope
, range
);
190 return CVT_SYNTAX_ERROR
;
192 if (errno
== ERANGE
|| val
> max_value
) {
193 /* That was valid, but it's too big. Return an error if requested
194 * (e.g., except when reading from the preferences file).
197 wmem_free(scope
, range
);
198 return CVT_NUMBER_TOO_BIG
;
200 /* Silently use the range's maximum value */
205 range
->ranges
[range
->nranges
].high
= val
;
207 /* Skip white space. */
208 while ((c
= *p
) == ' ' || c
== '\t')
211 /* Neither empty nor a number. */
212 wmem_free(scope
, range
);
213 return CVT_SYNTAX_ERROR
;
215 } else if (c
== ',' || c
== '\0') {
216 /* End of subrange string; that means there's no hyphen
217 * in the subrange, so the start and the end are the same.
219 range
->ranges
[range
->nranges
].high
= range
->ranges
[range
->nranges
].low
;
221 /* Invalid character. */
222 wmem_free(scope
, range
);
223 return CVT_SYNTAX_ERROR
;
228 /* Subrange is followed by a comma; skip it. */
233 /* Now we are going through the low and high values, and check
234 * whether they are in a proper order. Low should be equal or lower
235 * than high. So, go through the loop and swap if needed.
237 for (i
=0; i
< range
->nranges
; i
++) {
238 if (range
->ranges
[i
].low
> range
->ranges
[i
].high
) {
239 tmp
= range
->ranges
[i
].low
;
240 range
->ranges
[i
].low
= range
->ranges
[i
].high
;
241 range
->ranges
[i
].high
= tmp
;
245 /* In case we want to know what the result ranges are :
247 * for (i=0; i < range->nranges; i++) {
248 * printf("Function : range_convert_str L=%u \t H=%u\n",range->ranges[i].low,range->ranges[i].high);
254 } /* range_convert_str */
256 /* This function returns true if a given value is within one of the ranges
257 * stored in the ranges array.
260 value_is_in_range(const range_t
*range
, uint32_t val
)
265 for (i
=0; i
< range
->nranges
; i
++) {
266 if (val
>= range
->ranges
[i
].low
&& val
<= range
->ranges
[i
].high
)
273 /* This function returns true if val has successfully been added to
274 * a range. This may extend an existing range or create a new one
277 range_add_value(wmem_allocator_t
*scope
, range_t
**range
, uint32_t val
)
281 if ((range
) && (*range
)) {
282 for (i
=0; i
< (*range
)->nranges
; i
++) {
283 if (val
>= (*range
)->ranges
[i
].low
&& val
<= (*range
)->ranges
[i
].high
)
286 if (val
== (*range
)->ranges
[i
].low
-1)
288 /* Sink to a new low */
289 (*range
)->ranges
[i
].low
= val
;
293 if (val
== (*range
)->ranges
[i
].high
+1)
295 /* Reach a new high */
296 (*range
)->ranges
[i
].high
= val
;
301 (*range
) = (range_t
*)wmem_realloc(scope
, (*range
), RANGE_HDR_SIZE
+
302 ((*range
)->nranges
+1)*sizeof (range_admin_t
));
304 (*range
)->ranges
[i
].low
= (*range
)->ranges
[i
].high
= val
;
310 /* This function returns true if val has successfully been removed from
311 * a range. This may delete an existing range
314 range_remove_value(wmem_allocator_t
*scope
, range_t
**range
, uint32_t val
)
316 unsigned i
, j
, new_j
;
319 if ((range
) && (*range
)) {
320 for (i
=0; i
< (*range
)->nranges
; i
++) {
322 /* value is in the middle of the range, so it can't really be removed */
323 if (val
> (*range
)->ranges
[i
].low
&& val
< (*range
)->ranges
[i
].high
)
326 if ((val
== (*range
)->ranges
[i
].low
) && (val
== (*range
)->ranges
[i
].high
))
328 /* Remove the range item entirely */
329 new_range
= (range_t
*)wmem_alloc(scope
, RANGE_HDR_SIZE
+ ((*range
)->nranges
-1)*sizeof (range_admin_t
));
330 new_range
->nranges
= (*range
)->nranges
-1;
331 for (j
=0, new_j
= 0; j
< (*range
)->nranges
; j
++) {
333 /* Skip the current range */
337 new_range
->ranges
[new_j
].low
= (*range
)->ranges
[j
].low
;
338 new_range
->ranges
[new_j
].high
= (*range
)->ranges
[j
].high
;
342 wmem_free(scope
, *range
);
347 if (val
== (*range
)->ranges
[i
].low
)
350 (*range
)->ranges
[i
].low
++;
354 if (val
== (*range
)->ranges
[i
].high
)
356 /* Reach a new high */
357 (*range
)->ranges
[i
].high
--;
366 /* This function returns true if the two given range_t's are equal.
369 ranges_are_equal(const range_t
*a
, const range_t
*b
)
373 if ( (a
== NULL
) || (b
== NULL
) )
376 if (a
->nranges
!= b
->nranges
)
379 for (i
=0; i
< a
->nranges
; i
++) {
380 if (a
->ranges
[i
].low
!= b
->ranges
[i
].low
)
383 if (a
->ranges
[i
].high
!= b
->ranges
[i
].high
)
391 /* This function calls the provided callback function for each value in
395 range_foreach(range_t
*range
, void (*callback
)(uint32_t val
, void *ptr
), void *ptr
)
399 if (range
&& callback
) {
400 for (i
=0; i
< range
->nranges
; i
++) {
401 for (j
= range
->ranges
[i
].low
; j
<= range
->ranges
[i
].high
; j
++)
407 /* This function converts a range_t to a (wmem-allocated) string. */
409 range_convert_range(wmem_allocator_t
*scope
, const range_t
*range
)
412 bool prepend_comma
= false;
413 wmem_strbuf_t
*strbuf
;
415 strbuf
=wmem_strbuf_new(scope
, "");
418 for (i
=0; i
< range
->nranges
; i
++) {
419 if (range
->ranges
[i
].low
== range
->ranges
[i
].high
) {
420 wmem_strbuf_append_printf(strbuf
, "%s%u", prepend_comma
?",":"", range
->ranges
[i
].low
);
422 wmem_strbuf_append_printf(strbuf
, "%s%u-%u", prepend_comma
?",":"", range
->ranges
[i
].low
, range
->ranges
[i
].high
);
424 prepend_comma
= true;
427 return wmem_strbuf_finalize(strbuf
);
430 /* Create a copy of a range. */
432 range_copy(wmem_allocator_t
*scope
, const range_t
*src
)
440 range_size
= RANGE_HDR_SIZE
+ src
->nranges
*sizeof (range_admin_t
);
441 dst
= (range_t
*)wmem_memdup(scope
, src
, range_size
);
446 /* This is a debug function to check the range functionality */
448 value_is_in_range_check(range_t
*range
, uint32_t val
)
450 /* Print the result for a given value */
451 printf("Function : value_is_in_range_check Number %u\t",val
);
453 if (value_is_in_range(range
, val
)) {
454 printf("is in range\n");
456 printf("is not in range\n");
462 * Editor modelines - https://www.wireshark.org/tools/modelines.html
467 * indent-tabs-mode: nil
470 * ex: set shiftwidth=3 tabstop=8 expandtab:
471 * :indentSize=3:tabSize=8:noTabs=true: