Refactor commandline arg helpers to not exit on failure

Have the clopts_common helpers return success/fail (true/false) and have the desired return value passed in as an argument.  This allows failures to be handled by the calling applications and have a "cleaner" exit on failure.
This commit is contained in:
Michael Mann 2025-04-18 13:10:42 -04:00
parent e2ac9079a9
commit 7b048f64a9
10 changed files with 235 additions and 124 deletions

View File

@ -5094,7 +5094,10 @@ set_80211_channel(const char *iface, const char *opt)
} }
if (options[0]) if (options[0])
freq = get_nonzero_uint32(options[0], "802.11 channel frequency"); if (!get_nonzero_uint32(options[0], "802.11 channel frequency", &freq)) {
ret = EINVAL;
goto out;
}
if (args >= 1 && options[1]) { if (args >= 1 && options[1]) {
type = ws80211_str_to_chan_type(options[1]); type = ws80211_str_to_chan_type(options[1]);
@ -5106,10 +5109,16 @@ set_80211_channel(const char *iface, const char *opt)
} }
if (args >= 2 && options[2]) if (args >= 2 && options[2])
center_freq1 = get_nonzero_uint32(options[2], "VHT center frequency"); if (!get_nonzero_uint32(options[2], "VHT center frequency", &center_freq1)) {
ret = EINVAL;
goto out;
}
if (args >= 3 && options[3]) if (args >= 3 && options[3])
center_freq2 = get_nonzero_uint32(options[3], "VHT center frequency 2"); if (!get_nonzero_uint32(options[3], "VHT center frequency 2", &center_freq2)) {
ret = EINVAL;
goto out;
}
ret = ws80211_set_freq(iface, freq, type, center_freq1, center_freq2); ret = ws80211_set_freq(iface, freq, type, center_freq1, center_freq2);
@ -5667,10 +5676,12 @@ main(int argc, char *argv[])
machine_readable = true; machine_readable = true;
break; break;
case 'C': case 'C':
pcap_queue_byte_limit = get_positive_int(ws_optarg, "byte_limit"); if (!get_positive_int64(ws_optarg, "byte_limit", &pcap_queue_byte_limit))
arg_error = true;
break; break;
case 'N': case 'N':
pcap_queue_packet_limit = get_positive_int(ws_optarg, "packet_limit"); if (!get_positive_int64(ws_optarg, "packet_limit", &pcap_queue_packet_limit))
arg_error = true;
break; break;
default: default:
/* wslog arguments are okay */ /* wslog arguments are okay */

View File

@ -302,7 +302,8 @@ add_selection(char *sel, uint64_t* max_selection)
fprintf(stderr, "Not inclusive ..."); fprintf(stderr, "Not inclusive ...");
selectfrm[max_selected].inclusive = false; selectfrm[max_selected].inclusive = false;
selectfrm[max_selected].first = get_uint64(sel, "packet number"); if (!get_uint64(sel, "packet number", &selectfrm[max_selected].first))
return false;
if (selectfrm[max_selected].first > *max_selection) if (selectfrm[max_selected].first > *max_selection)
*max_selection = selectfrm[max_selected].first; *max_selection = selectfrm[max_selected].first;
@ -315,8 +316,10 @@ add_selection(char *sel, uint64_t* max_selection)
*locn = '\0'; /* split the range */ *locn = '\0'; /* split the range */
next = locn + 1; next = locn + 1;
selectfrm[max_selected].inclusive = true; selectfrm[max_selected].inclusive = true;
selectfrm[max_selected].first = get_uint64(sel, "beginning of packet range"); if (!get_uint64(sel, "beginning of packet range", &selectfrm[max_selected].first))
selectfrm[max_selected].second = get_uint64(next, "end of packet range"); return false;
if (!get_uint64(next, "end of packet range", &selectfrm[max_selected].second))
return false;
if (selectfrm[max_selected].second == 0) if (selectfrm[max_selected].second == 0)
{ {
@ -1695,7 +1698,10 @@ main(int argc, char *argv[])
} }
case 'c': case 'c':
split_packet_count = get_nonzero_uint64(ws_optarg, "packet count"); if (!get_nonzero_uint64(ws_optarg, "packet count", &split_packet_count)) {
ret = WS_EXIT_INVALID_OPTION;
goto clean_exit;
}
break; break;
case 'C': case 'C':
@ -1743,7 +1749,10 @@ main(int argc, char *argv[])
case 'D': case 'D':
dup_detect = true; dup_detect = true;
dup_detect_by_time = false; dup_detect_by_time = false;
dup_window = get_uint32(ws_optarg, "duplicate window"); if (!get_uint32(ws_optarg, "duplicate window", &dup_window)) {
ret = WS_EXIT_INVALID_OPTION;
goto clean_exit;
}
if (dup_window > MAX_DUP_DEPTH) { if (dup_window > MAX_DUP_DEPTH) {
cmdarg_err("\"%d\" duplicate window value must be between 0 and %d inclusive.", cmdarg_err("\"%d\" duplicate window value must be between 0 and %d inclusive.",
dup_window, MAX_DUP_DEPTH); dup_window, MAX_DUP_DEPTH);
@ -1779,7 +1788,11 @@ main(int argc, char *argv[])
case 'i': /* break capture file based on time interval */ case 'i': /* break capture file based on time interval */
{ {
double spb = get_positive_double(ws_optarg, "time interval"); double spb;
if (!get_positive_double(ws_optarg, "time interval", &spb)) {
ret = WS_EXIT_INVALID_OPTION;
goto clean_exit;
}
if (spb == 0.0) { if (spb == 0.0) {
cmdarg_err("The specified interval is zero"); cmdarg_err("The specified interval is zero");
ret = WS_EXIT_INVALID_OPTION; ret = WS_EXIT_INVALID_OPTION;
@ -1794,7 +1807,10 @@ main(int argc, char *argv[])
break; break;
case 'I': /* ignored_bytes at the beginning of the frame for duplications removal */ case 'I': /* ignored_bytes at the beginning of the frame for duplications removal */
ignored_bytes = get_uint32(ws_optarg, "number of bytes to ignore"); if (!get_uint32(ws_optarg, "number of bytes to ignore", &ignored_bytes)) {
ret = WS_EXIT_INVALID_OPTION;
goto clean_exit;
}
break; break;
case 'L': case 'L':
@ -1802,7 +1818,10 @@ main(int argc, char *argv[])
break; break;
case 'o': case 'o':
change_offset = get_uint32(ws_optarg, "change offset"); if (!get_uint32(ws_optarg, "change offset", &change_offset)) {
ret = WS_EXIT_INVALID_OPTION;
goto clean_exit;
}
break; break;
case 'r': case 'r':
@ -1853,7 +1872,10 @@ main(int argc, char *argv[])
} }
case 's': case 's':
snaplen = get_nonzero_uint32(ws_optarg, "snapshot length"); if (!get_nonzero_uint32(ws_optarg, "snapshot length", &snaplen)) {
ret = WS_EXIT_INVALID_OPTION;
goto clean_exit;
}
break; break;
case 'S': case 'S':

View File

@ -281,7 +281,10 @@ main(int argc, char *argv[])
break; break;
case 's': case 's':
snaplen = get_nonzero_uint32(ws_optarg, "snapshot length"); if (!get_nonzero_uint32(ws_optarg, "snapshot length", &snaplen)) {
status = false;
goto clean_exit;
}
break; break;
case 'V': case 'V':

View File

@ -165,7 +165,10 @@ main(int argc, char *argv[])
while ((opt = ws_getopt_long(argc, argv, optstring, long_options, NULL)) != -1) { while ((opt = ws_getopt_long(argc, argv, optstring, long_options, NULL)) != -1) {
switch (opt) { switch (opt) {
case 'b': /* max bytes */ case 'b': /* max bytes */
produce_max_bytes = get_positive_int(ws_optarg, "max bytes"); if (!get_positive_int(ws_optarg, "max bytes", &produce_max_bytes)) {
ret = WS_EXIT_INVALID_OPTION;
goto clean_exit;
}
if (produce_max_bytes > 65536) { if (produce_max_bytes > 65536) {
cmdarg_err("max bytes is > 65536"); cmdarg_err("max bytes is > 65536");
ret = WS_EXIT_INVALID_OPTION; ret = WS_EXIT_INVALID_OPTION;
@ -174,7 +177,10 @@ main(int argc, char *argv[])
break; break;
case 'c': /* count */ case 'c': /* count */
produce_count = get_positive_int(ws_optarg, "count"); if (!get_positive_int(ws_optarg, "count", &produce_count)) {
ret = WS_EXIT_INVALID_OPTION;
goto clean_exit;
}
break; break;
case 'F': case 'F':

View File

@ -572,10 +572,9 @@ main(int argc, char *argv[])
break; break;
#if !defined(_WIN32) && defined(RLIMIT_AS) #if !defined(_WIN32) && defined(RLIMIT_AS)
case 'm': case 'm':
limit.rlim_cur = get_positive_int(ws_optarg, "memory limit"); if (!get_uint32(ws_optarg, "memory limit", (uint32_t*)(&limit.rlim_cur)) ||
limit.rlim_max = get_positive_int(ws_optarg, "memory limit"); !get_uint32(ws_optarg, "memory limit", (uint32_t*)(&limit.rlim_max)) ||
(setrlimit(RLIMIT_AS, &limit) != 0)) {
if(setrlimit(RLIMIT_AS, &limit) != 0) {
cmdarg_err("setrlimit(RLIMIT_AS) failed: %s", cmdarg_err("setrlimit(RLIMIT_AS) failed: %s",
g_strerror(errno)); g_strerror(errno));
ret = WS_EXIT_INVALID_OPTION; ret = WS_EXIT_INVALID_OPTION;

View File

@ -1079,7 +1079,7 @@ main(int argc, char *argv[])
char *err_str, *err_str_secondary; char *err_str, *err_str_secondary;
#else #else
bool capture_option_specified = false; bool capture_option_specified = false;
volatile int max_packet_count = 0; int max_packet_count = 0;
#endif #endif
volatile int out_file_type = WTAP_FILE_TYPE_SUBTYPE_UNKNOWN; volatile int out_file_type = WTAP_FILE_TYPE_SUBTYPE_UNKNOWN;
volatile bool out_file_name_res = false; volatile bool out_file_name_res = false;
@ -1428,7 +1428,9 @@ main(int argc, char *argv[])
cmdarg_err("-M does not support two-pass analysis."); cmdarg_err("-M does not support two-pass analysis.");
arg_error=true; arg_error=true;
} }
epan_auto_reset_count = get_positive_int(ws_optarg, "epan reset count"); if (!get_positive_int(ws_optarg, "epan reset count", &epan_auto_reset_count))
arg_error = true;
epan_auto_reset = true; epan_auto_reset = true;
break; break;
case 'a': /* autostop criteria */ case 'a': /* autostop criteria */
@ -1466,7 +1468,10 @@ main(int argc, char *argv[])
goto clean_exit; goto clean_exit;
} }
#else #else
max_packet_count = get_positive_int(ws_optarg, "packet count"); if (!get_positive_int(ws_optarg, "packet count", &max_packet_count)) {
exit_status = WS_EXIT_INVALID_OPTION;
goto clean_exit;
}
#endif #endif
break; break;
case 'w': /* Write to file x */ case 'w': /* Write to file x */

View File

@ -331,20 +331,25 @@ set_autostop_criterion(capture_options *capture_opts, const char *autostoparg)
} }
if (strcmp(autostoparg,"duration") == 0) { if (strcmp(autostoparg,"duration") == 0) {
capture_opts->has_autostop_duration = true; capture_opts->has_autostop_duration = true;
capture_opts->autostop_duration = get_positive_double(p,"autostop duration"); if (!get_positive_double(p,"autostop duration",&capture_opts->autostop_duration))
return false;
} else if (strcmp(autostoparg,"filesize") == 0) { } else if (strcmp(autostoparg,"filesize") == 0) {
capture_opts->has_autostop_filesize = true; capture_opts->has_autostop_filesize = true;
capture_opts->autostop_filesize = get_nonzero_uint32(p,"autostop filesize"); if (!get_nonzero_uint32(p,"autostop filesize",&capture_opts->autostop_filesize))
return false;
} else if (strcmp(autostoparg,"files") == 0) { } else if (strcmp(autostoparg,"files") == 0) {
capture_opts->multi_files_on = true; capture_opts->multi_files_on = true;
capture_opts->has_autostop_files = true; capture_opts->has_autostop_files = true;
capture_opts->autostop_files = get_positive_int(p,"autostop files"); if (!get_positive_int(p,"autostop files",&capture_opts->autostop_files))
return false;
} else if (strcmp(autostoparg,"packets") == 0) { } else if (strcmp(autostoparg,"packets") == 0) {
capture_opts->has_autostop_written_packets = true; capture_opts->has_autostop_written_packets = true;
capture_opts->autostop_written_packets = get_positive_int(p,"packet write count"); if (!get_positive_int(p,"packet write count",&capture_opts->autostop_written_packets))
return false;
} else if (strcmp(autostoparg,"events") == 0) { } else if (strcmp(autostoparg,"events") == 0) {
capture_opts->has_autostop_written_packets = true; capture_opts->has_autostop_written_packets = true;
capture_opts->autostop_written_packets = get_positive_int(p,"event write count"); if (!get_positive_int(p,"event write count",&capture_opts->autostop_written_packets))
return false;
} else { } else {
return false; return false;
} }
@ -468,25 +473,33 @@ get_ring_arguments(capture_options *capture_opts, const char *arg)
if (strcmp(arg,"files") == 0) { if (strcmp(arg,"files") == 0) {
capture_opts->has_ring_num_files = true; capture_opts->has_ring_num_files = true;
capture_opts->ring_num_files = get_nonzero_uint32(p, "number of ring buffer files"); if (!get_nonzero_uint32(p, "number of ring buffer files",&capture_opts->ring_num_files))
return false;
} else if (strcmp(arg,"filesize") == 0) { } else if (strcmp(arg,"filesize") == 0) {
capture_opts->has_autostop_filesize = true; capture_opts->has_autostop_filesize = true;
capture_opts->autostop_filesize = get_nonzero_uint32(p, "ring buffer filesize"); if (!get_nonzero_uint32(p, "ring buffer filesize",&capture_opts->autostop_filesize))
return false;
} else if (strcmp(arg,"duration") == 0) { } else if (strcmp(arg,"duration") == 0) {
capture_opts->has_file_duration = true; capture_opts->has_file_duration = true;
capture_opts->file_duration = get_positive_double(p, "ring buffer duration"); if (!get_positive_double(p, "ring buffer duration",&capture_opts->file_duration))
return false;
} else if (strcmp(arg,"interval") == 0) { } else if (strcmp(arg,"interval") == 0) {
capture_opts->has_file_interval = true; capture_opts->has_file_interval = true;
capture_opts->file_interval = get_positive_int(p, "ring buffer interval"); if (!get_positive_int(p, "ring buffer interval",&capture_opts->file_interval))
return false;
} else if (strcmp(arg,"nametimenum") == 0) { } else if (strcmp(arg,"nametimenum") == 0) {
int val = get_positive_int(p, "file name: time before num"); int val;
if (!get_positive_int(p, "file name: time before num", &val))
return false;
capture_opts->has_nametimenum = (val > 1); capture_opts->has_nametimenum = (val > 1);
} else if (strcmp(arg,"packets") == 0) { } else if (strcmp(arg,"packets") == 0) {
capture_opts->has_file_packets = true; capture_opts->has_file_packets = true;
capture_opts->file_packets = get_positive_int(p, "ring buffer packet count"); if (!get_positive_int(p, "ring buffer packet count",&capture_opts->file_packets))
return false;
} else if (strcmp(arg,"events") == 0) { } else if (strcmp(arg,"events") == 0) {
capture_opts->has_file_packets = true; capture_opts->has_file_packets = true;
capture_opts->file_packets = get_positive_int(p, "ring buffer event count"); if (!get_positive_int(p, "ring buffer event count",&capture_opts->file_packets))
return false;
} else if (strcmp(arg,"printname") == 0) { } else if (strcmp(arg,"printname") == 0) {
capture_opts->print_file_names = true; capture_opts->print_file_names = true;
capture_opts->print_name_to = g_strdup(p); capture_opts->print_name_to = g_strdup(p);
@ -530,10 +543,12 @@ get_sampling_arguments(capture_options *capture_opts, const char *arg)
interface_opts = &g_array_index(capture_opts->ifaces, interface_options, capture_opts->ifaces->len - 1); interface_opts = &g_array_index(capture_opts->ifaces, interface_options, capture_opts->ifaces->len - 1);
interface_opts->sampling_method = CAPTURE_SAMP_BY_COUNT; interface_opts->sampling_method = CAPTURE_SAMP_BY_COUNT;
interface_opts->sampling_param = get_positive_int(p, "sampling count"); if (!get_positive_int(p, "sampling count", &interface_opts->sampling_param))
return false;
} else { } else {
capture_opts->default_options.sampling_method = CAPTURE_SAMP_BY_COUNT; capture_opts->default_options.sampling_method = CAPTURE_SAMP_BY_COUNT;
capture_opts->default_options.sampling_param = get_positive_int(p, "sampling count"); if (!get_positive_int(p, "sampling count", &capture_opts->default_options.sampling_param))
return false;
} }
} else if (strcmp(arg, "timer") == 0) { } else if (strcmp(arg, "timer") == 0) {
if (capture_opts->ifaces->len > 0) { if (capture_opts->ifaces->len > 0) {
@ -541,10 +556,12 @@ get_sampling_arguments(capture_options *capture_opts, const char *arg)
interface_opts = &g_array_index(capture_opts->ifaces, interface_options, capture_opts->ifaces->len - 1); interface_opts = &g_array_index(capture_opts->ifaces, interface_options, capture_opts->ifaces->len - 1);
interface_opts->sampling_method = CAPTURE_SAMP_BY_TIMER; interface_opts->sampling_method = CAPTURE_SAMP_BY_TIMER;
interface_opts->sampling_param = get_positive_int(p, "sampling timer"); if (!get_positive_int(p, "sampling timer", &interface_opts->sampling_param))
return false;
} else { } else {
capture_opts->default_options.sampling_method = CAPTURE_SAMP_BY_TIMER; capture_opts->default_options.sampling_method = CAPTURE_SAMP_BY_TIMER;
capture_opts->default_options.sampling_param = get_positive_int(p, "sampling timer"); if (!get_positive_int(p, "sampling timer", &capture_opts->default_options.sampling_param))
return false;
} }
} }
*colonp = ':'; *colonp = ':';
@ -987,15 +1004,18 @@ capture_opts_add_opt(capture_options *capture_opts, int opt, const char *optarg_
interface_options *interface_opts; interface_options *interface_opts;
interface_opts = &g_array_index(capture_opts->ifaces, interface_options, capture_opts->ifaces->len - 1); interface_opts = &g_array_index(capture_opts->ifaces, interface_options, capture_opts->ifaces->len - 1);
interface_opts->buffer_size = get_positive_int(optarg_str_p, "buffer size"); if (!get_positive_int(optarg_str_p, "buffer size", &interface_opts->buffer_size))
return 1;
} else { } else {
capture_opts->default_options.buffer_size = get_positive_int(optarg_str_p, "buffer size"); if (!get_positive_int(optarg_str_p, "buffer size", &capture_opts->default_options.buffer_size))
return 1;
} }
break; break;
case 'c': /* Capture n packets */ case 'c': /* Capture n packets */
/* XXX Use set_autostop_criterion instead? */ /* XXX Use set_autostop_criterion instead? */
capture_opts->has_autostop_packets = true; capture_opts->has_autostop_packets = true;
capture_opts->autostop_packets = get_positive_int(optarg_str_p, "packet count"); if (!get_positive_int(optarg_str_p, "packet count", &capture_opts->autostop_packets))
return 1;
break; break;
case 'f': /* capture filter */ case 'f': /* capture filter */
get_filter_arguments(capture_opts, optarg_str_p); get_filter_arguments(capture_opts, optarg_str_p);
@ -1089,7 +1109,8 @@ capture_opts_add_opt(capture_options *capture_opts, int opt, const char *optarg_
#endif #endif
case 's': /* Set the snapshot (capture) length */ case 's': /* Set the snapshot (capture) length */
// XXX Should we error out if our flavor is Stratoshark? // XXX Should we error out if our flavor is Stratoshark?
snaplen = get_natural_int(optarg_str_p, "snapshot length"); if (!get_natural_int(optarg_str_p, "snapshot length", &snaplen))
return 1;
/* /*
* Make a snapshot length of 0 equivalent to the maximum packet * Make a snapshot length of 0 equivalent to the maximum packet
* length, mirroring what tcpdump does. * length, mirroring what tcpdump does.
@ -1195,7 +1216,8 @@ capture_opts_add_opt(capture_options *capture_opts, int opt, const char *optarg_
capture_opts->temp_dir = g_strdup(optarg_str_p); capture_opts->temp_dir = g_strdup(optarg_str_p);
break; break;
case LONGOPT_UPDATE_INTERVAL: /* capture update interval */ case LONGOPT_UPDATE_INTERVAL: /* capture update interval */
capture_opts->update_interval = get_natural_int(optarg_str_p, "update interval"); if (!get_natural_int(optarg_str_p, "update interval", &capture_opts->update_interval))
return false;
break; break;
default: default:
/* the caller is responsible to send us only the right opt's */ /* the caller is responsible to send us only the right opt's */

View File

@ -607,7 +607,8 @@ void commandline_other_options(int argc, char *argv[], bool opt_reset)
global_commandline_info.jump_backwards = SD_BACKWARD; global_commandline_info.jump_backwards = SD_BACKWARD;
break; break;
case 'g': /* Go to item with the given item number */ case 'g': /* Go to item with the given item number */
global_commandline_info.go_to_packet = get_nonzero_uint32(ws_optarg, "go to packet"); if (!get_nonzero_uint32(ws_optarg, "go to packet", &global_commandline_info.go_to_packet))
exit_application(WS_EXIT_INVALID_OPTION);
break; break;
case 'J': /* Jump to the first item which matches the filter criteria */ case 'J': /* Jump to the first item which matches the filter criteria */
global_commandline_info.jfilter = ws_optarg; global_commandline_info.jfilter = ws_optarg;

View File

@ -14,127 +14,155 @@
#include <stdlib.h> #include <stdlib.h>
#include <errno.h> #include <errno.h>
#include <ws_exit_codes.h>
#include <wsutil/strtoi.h> #include <wsutil/strtoi.h>
#include <wsutil/cmdarg_err.h> #include <wsutil/cmdarg_err.h>
int bool
get_natural_int(const char *string, const char *name) get_natural_int(const char *string, const char *name, int32_t* number)
{ {
int32_t number; if (!ws_strtoi32(string, NULL, number)) {
if (!ws_strtoi32(string, NULL, &number)) {
if (errno == EINVAL) { if (errno == EINVAL) {
cmdarg_err("The specified %s \"%s\" isn't a decimal number", name, string); cmdarg_err("The specified %s \"%s\" isn't a decimal number", name, string);
exit(1); return false;
} }
if (number < 0) { if (*number < 0) {
cmdarg_err("The specified %s \"%s\" is a negative number", name, string); cmdarg_err("The specified %s \"%s\" is a negative number", name, string);
exit(1); return false;
} }
cmdarg_err("The specified %s \"%s\" is too large (greater than %d)", cmdarg_err("The specified %s \"%s\" is too large (greater than %d)",
name, string, number); name, string, *number);
exit(1); return false;
} }
if (number < 0) { if (*number < 0) {
cmdarg_err("The specified %s \"%s\" is a negative number", name, string); cmdarg_err("The specified %s \"%s\" is a negative number", name, string);
exit(1); return false;
} }
return (int)number; return true;
} }
int bool
get_positive_int(const char *string, const char *name) get_positive_int(const char *string, const char *name, int32_t* number)
{ {
int number; if (!get_natural_int(string, name, number))
return false;
number = get_natural_int(string, name); if (*number == 0) {
if (number == 0) {
cmdarg_err("The specified %s is zero", name); cmdarg_err("The specified %s is zero", name);
exit(1); return false;
} }
return number; return true;
} }
uint32_t bool
get_uint32(const char *string, const char *name) get_natural_int64(const char* string, const char* name, int64_t* number)
{ {
uint32_t number; if (!ws_strtoi64(string, NULL, number)) {
if (errno == EINVAL) {
cmdarg_err("The specified %s \"%s\" isn't a decimal number", name, string);
return false;
}
if (*number < 0) {
cmdarg_err("The specified %s \"%s\" is a negative number", name, string);
return false;
}
cmdarg_err("The specified %s \"%s\" is too large (greater than %" PRId64 ")",
name, string, *number);
return false;
}
if (*number < 0) {
cmdarg_err("The specified %s \"%s\" is a negative number", name, string);
return false;
}
return true;
}
if (!ws_strtou32(string, NULL, &number)) { bool
get_positive_int64(const char* string, const char* name, int64_t* number)
{
if (!get_natural_int64(string, name, number))
return false;
if (*number == 0) {
cmdarg_err("The specified %s is zero", name);
return false;
}
return true;
}
bool
get_uint32(const char *string, const char *name, uint32_t* number)
{
if (!ws_strtou32(string, NULL, number)) {
if (errno == EINVAL) { if (errno == EINVAL) {
cmdarg_err("The specified %s \"%s\" isn't a decimal number", name, string); cmdarg_err("The specified %s \"%s\" isn't a decimal number", name, string);
exit(1); return false;
} }
cmdarg_err("The specified %s \"%s\" is too large (greater than %d)", cmdarg_err("The specified %s \"%s\" is too large (greater than %d)",
name, string, number); name, string, *number);
exit(1); return false;
} }
return number; return true;
} }
uint32_t bool
get_nonzero_uint32(const char *string, const char *name) get_nonzero_uint32(const char *string, const char *name, uint32_t* number)
{ {
uint32_t number; if (!get_uint32(string, name, number))
return false;
number = get_uint32(string, name); if (*number == 0) {
if (number == 0) {
cmdarg_err("The specified %s is zero", name); cmdarg_err("The specified %s is zero", name);
exit(1); return false;
} }
return number; return true;
} }
uint64_t bool
get_uint64(const char *string, const char *name) get_uint64(const char *string, const char *name, uint64_t* number)
{ {
uint64_t number; if (!ws_strtou64(string, NULL, number)) {
if (!ws_strtou64(string, NULL, &number)) {
if (errno == EINVAL) { if (errno == EINVAL) {
cmdarg_err("The specified %s \"%s\" isn't a decimal number", name, string); cmdarg_err("The specified %s \"%s\" isn't a decimal number", name, string);
exit(1); return false;
} }
cmdarg_err("The specified %s \"%s\" is too large (greater than %" PRIu64 ")", cmdarg_err("The specified %s \"%s\" is too large (greater than %" PRIu64 ")",
name, string, number); name, string, *number);
exit(1); return false;
} }
return number; return true;
} }
uint64_t bool
get_nonzero_uint64(const char *string, const char *name) get_nonzero_uint64(const char *string, const char *name, uint64_t* number)
{ {
uint64_t number; if (!get_uint64(string, name, number))
return false;
number = get_uint64(string, name); if (*number == 0) {
if (number == 0) {
cmdarg_err("The specified %s is zero", name); cmdarg_err("The specified %s is zero", name);
exit(1); return false;
} }
return number; return true;
} }
double bool
get_positive_double(const char *string, const char *name) get_positive_double(const char *string, const char *name, double* number)
{ {
double number = g_ascii_strtod(string, NULL); *number = g_ascii_strtod(string, NULL);
if (errno == EINVAL) { if (errno == EINVAL) {
cmdarg_err("The specified %s \"%s\" isn't a floating point number", name, string); cmdarg_err("The specified %s \"%s\" isn't a floating point number", name, string);
exit(1); return false;
} }
if (number < 0.0) { if (*number < 0.0) {
cmdarg_err("The specified %s \"%s\" is a negative number", name, string); cmdarg_err("The specified %s \"%s\" is a negative number", name, string);
exit(1); return false;
} }
return number; return true;
} }

View File

@ -40,34 +40,48 @@ extern "C" {
#define OPTSTRING_READ_CAPTURE_COMMON \ #define OPTSTRING_READ_CAPTURE_COMMON \
"r:" "r:"
WS_DLL_PUBLIC int WS_DLL_PUBLIC bool
get_natural_int(const char *string, const char *name); get_natural_int(const char *string, const char *name, int32_t* number);
WS_DLL_PUBLIC int WS_DLL_PUBLIC bool
get_positive_int(const char *string, const char *name); get_positive_int(const char *string, const char *name, int32_t* number);
WS_DLL_PUBLIC uint32_t WS_DLL_PUBLIC bool
get_uint32(const char *string, const char *name); get_natural_int64(const char* string, const char* name, int64_t* number);
WS_DLL_PUBLIC bool
get_positive_int64(const char* string, const char* name, int64_t* number);
WS_DLL_PUBLIC bool
get_uint32(const char *string, const char *name, uint32_t* number);
WS_DEPRECATED_X("Use get_uint32 instead") WS_DEPRECATED_X("Use get_uint32 instead")
static inline uint32_t static inline uint32_t
get_guint32(const char *string, const char *name) { return get_uint32(string, name); } get_guint32(const char *string, const char *name) {
uint32_t number = 0;
get_uint32(string, name, &number);
return number;
}
WS_DLL_PUBLIC uint32_t WS_DLL_PUBLIC bool
get_nonzero_uint32(const char *string, const char *name); get_nonzero_uint32(const char *string, const char *name, uint32_t* number);
WS_DEPRECATED_X("Use get_nonzero_uint32 instead") WS_DEPRECATED_X("Use get_nonzero_uint32 instead")
static inline uint32_t static inline uint32_t
get_nonzero_guint32(const char *string, const char *name) { return get_nonzero_uint32(string, name); } get_nonzero_guint32(const char *string, const char *name) {
uint32_t number = 0;
get_nonzero_uint32(string, name, &number);
return number;
}
WS_DLL_PUBLIC uint64_t WS_DLL_PUBLIC bool
get_uint64(const char *string, const char *name); get_uint64(const char *string, const char *name, uint64_t* number);
WS_DLL_PUBLIC uint64_t WS_DLL_PUBLIC bool
get_nonzero_uint64(const char *string, const char *name); get_nonzero_uint64(const char *string, const char *name, uint64_t* number);
WS_DLL_PUBLIC double WS_DLL_PUBLIC bool
get_positive_double(const char *string, const char *name); get_positive_double(const char *string, const char *name, double* number);
#ifdef __cplusplus #ifdef __cplusplus
} }