X-Git-Url: https://sigrok.org/gitweb/?p=sigrok-cli.git;a=blobdiff_plain;f=options.c;h=2573bd4c17b6cb861be37239070ff6e7bc8e07ef;hp=b26ca4bee9a29f0270f7f013be0155bc300d7680;hb=HEAD;hpb=cd62e027c0a3a8d97a6689d042b92699d8b619f3 diff --git a/options.c b/options.c index b26ca4b..e47b680 100644 --- a/options.c +++ b/options.c @@ -17,91 +17,161 @@ * along with this program. If not, see . */ -#include "sigrok-cli.h" +#include #include +#include "sigrok-cli.h" gboolean opt_version = FALSE; +gboolean opt_list_supported = FALSE; +gboolean opt_list_supported_wiki = FALSE; gint opt_loglevel = SR_LOG_WARN; /* Show errors+warnings by default. */ gboolean opt_scan_devs = FALSE; +gboolean opt_dont_scan = FALSE; gboolean opt_wait_trigger = FALSE; gchar *opt_input_file = NULL; gchar *opt_output_file = NULL; gchar *opt_drv = NULL; -gchar *opt_config = NULL; +gchar **opt_configs = NULL; gchar *opt_channels = NULL; gchar *opt_channel_group = NULL; gchar *opt_triggers = NULL; -gchar *opt_pds = NULL; +gchar **opt_pds = NULL; #ifdef HAVE_SRD -gchar *opt_pd_stack = NULL; gchar *opt_pd_annotations = NULL; gchar *opt_pd_meta = NULL; gchar *opt_pd_binary = NULL; +gboolean opt_pd_ann_class = FALSE; +gboolean opt_pd_samplenum = FALSE; +gboolean opt_pd_jsontrace = FALSE; #endif gchar *opt_input_format = NULL; gchar *opt_output_format = NULL; -gchar *opt_show = NULL; +gchar *opt_transform_module = NULL; +gboolean opt_show = FALSE; gchar *opt_time = NULL; gchar *opt_samples = NULL; gchar *opt_frames = NULL; -gchar *opt_continuous = NULL; -gchar *opt_set = NULL; +gboolean opt_continuous = FALSE; +gchar **opt_gets = NULL; +gboolean opt_set = FALSE; +gboolean opt_list_serial = FALSE; + +/* + * Defines a callback function that generates an error if an + * option occurs twice. + */ +#define CHECK_ONCE(option) \ +static gboolean check_ ## option \ + (const gchar *option_name, const gchar *value, \ + gpointer data, GError **error) \ +{ \ + (void)data; \ + \ + static gboolean seen = FALSE; \ + if (seen) { \ + g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, \ + "superfluous option \"%s\"", option_name); \ + return FALSE; \ + } \ + \ + option = g_strdup(value); \ + seen = TRUE; \ + return TRUE; \ +} + +CHECK_ONCE(opt_drv) +CHECK_ONCE(opt_input_format) +CHECK_ONCE(opt_output_format) +CHECK_ONCE(opt_transform_module) +CHECK_ONCE(opt_channels) +CHECK_ONCE(opt_channel_group) +CHECK_ONCE(opt_triggers) +#ifdef HAVE_SRD +CHECK_ONCE(opt_pd_annotations) +CHECK_ONCE(opt_pd_meta) +CHECK_ONCE(opt_pd_binary) +#endif +CHECK_ONCE(opt_time) +CHECK_ONCE(opt_samples) +CHECK_ONCE(opt_frames) + +#undef CHECK_STR_ONCE + +static gchar **input_file_array = NULL; +static gchar **output_file_array = NULL; static const GOptionEntry optargs[] = { {"version", 'V', 0, G_OPTION_ARG_NONE, &opt_version, - "Show version and support list", NULL}, + "Show version", NULL}, + {"list-supported", 'L', 0, G_OPTION_ARG_NONE, &opt_list_supported, + "List supported devices/modules/decoders", NULL}, + {"list-supported-wiki", 0, 0, G_OPTION_ARG_NONE, &opt_list_supported_wiki, + "List supported decoders (MediaWiki)", NULL}, {"loglevel", 'l', 0, G_OPTION_ARG_INT, &opt_loglevel, "Set loglevel (5 is most verbose)", NULL}, - {"driver", 'd', 0, G_OPTION_ARG_STRING, &opt_drv, + {"driver", 'd', 0, G_OPTION_ARG_CALLBACK, &check_opt_drv, "The driver to use", NULL}, - {"config", 'c', 0, G_OPTION_ARG_STRING, &opt_config, + {"config", 'c', 0, G_OPTION_ARG_STRING_ARRAY, &opt_configs, "Specify device configuration options", NULL}, - {"input-file", 'i', 0, G_OPTION_ARG_FILENAME, &opt_input_file, + {"input-file", 'i', 0, G_OPTION_ARG_FILENAME_ARRAY, &input_file_array, "Load input from file", NULL}, - {"input-format", 'I', 0, G_OPTION_ARG_STRING, &opt_input_format, + {"input-format", 'I', 0, G_OPTION_ARG_CALLBACK, &check_opt_input_format, "Input format", NULL}, - {"output-file", 'o', 0, G_OPTION_ARG_FILENAME, &opt_output_file, + {"output-file", 'o', 0, G_OPTION_ARG_FILENAME_ARRAY, &output_file_array, "Save output to file", NULL}, - {"output-format", 'O', 0, G_OPTION_ARG_STRING, &opt_output_format, + {"output-format", 'O', 0, G_OPTION_ARG_CALLBACK, &check_opt_output_format, "Output format", NULL}, - {"channels", 'C', 0, G_OPTION_ARG_STRING, &opt_channels, + {"transform-module", 'T', 0, G_OPTION_ARG_CALLBACK, &check_opt_transform_module, + "Transform module", NULL}, + {"channels", 'C', 0, G_OPTION_ARG_CALLBACK, &check_opt_channels, "Channels to use", NULL}, - {"channel-group", 'g', 0, G_OPTION_ARG_STRING, &opt_channel_group, + {"channel-group", 'g', 0, G_OPTION_ARG_CALLBACK, &check_opt_channel_group, "Channel groups", NULL}, - {"triggers", 't', 0, G_OPTION_ARG_STRING, &opt_triggers, + {"triggers", 't', 0, G_OPTION_ARG_CALLBACK, &check_opt_triggers, "Trigger configuration", NULL}, {"wait-trigger", 'w', 0, G_OPTION_ARG_NONE, &opt_wait_trigger, "Wait for trigger", NULL}, #ifdef HAVE_SRD - {"protocol-decoders", 'P', 0, G_OPTION_ARG_STRING, &opt_pds, + {"protocol-decoders", 'P', 0, G_OPTION_ARG_STRING_ARRAY, &opt_pds, "Protocol decoders to run", NULL}, - {"protocol-decoder-stack", 'S', 0, G_OPTION_ARG_STRING, &opt_pd_stack, - "Protocol decoder stack", NULL}, - {"protocol-decoder-annotations", 'A', 0, G_OPTION_ARG_STRING, &opt_pd_annotations, + {"protocol-decoder-annotations", 'A', 0, G_OPTION_ARG_CALLBACK, &check_opt_pd_annotations, "Protocol decoder annotation(s) to show", NULL}, - {"protocol-decoder-meta", 'M', 0, G_OPTION_ARG_STRING, &opt_pd_meta, + {"protocol-decoder-meta", 'M', 0, G_OPTION_ARG_CALLBACK, &check_opt_pd_meta, "Protocol decoder meta output to show", NULL}, - {"protocol-decoder-binary", 'B', 0, G_OPTION_ARG_STRING, &opt_pd_binary, + {"protocol-decoder-binary", 'B', 0, G_OPTION_ARG_CALLBACK, &check_opt_pd_binary, "Protocol decoder binary output to show", NULL}, + {"protocol-decoder-ann-class", 0, 0, G_OPTION_ARG_NONE, &opt_pd_ann_class, + "Show annotation class in decoder output", NULL}, + {"protocol-decoder-samplenum", 0, 0, G_OPTION_ARG_NONE, &opt_pd_samplenum, + "Show sample numbers in decoder output", NULL}, + {"protocol-decoder-jsontrace", 0, 0, G_OPTION_ARG_NONE, &opt_pd_jsontrace, + "Output in Google Trace Event format (JSON)", NULL}, #endif {"scan", 0, 0, G_OPTION_ARG_NONE, &opt_scan_devs, "Scan for devices", NULL}, + {"dont-scan", 'D', 0, G_OPTION_ARG_NONE, &opt_dont_scan, + "Don't auto-scan (use -d spec only)", NULL}, {"show", 0, 0, G_OPTION_ARG_NONE, &opt_show, - "Show device detail", NULL}, - {"time", 0, 0, G_OPTION_ARG_STRING, &opt_time, + "Show device/format/decoder details", NULL}, + {"time", 0, 0, G_OPTION_ARG_CALLBACK, &check_opt_time, "How long to sample (ms)", NULL}, - {"samples", 0, 0, G_OPTION_ARG_STRING, &opt_samples, + {"samples", 0, 0, G_OPTION_ARG_CALLBACK, &check_opt_samples, "Number of samples to acquire", NULL}, - {"frames", 0, 0, G_OPTION_ARG_STRING, &opt_frames, + {"frames", 0, 0, G_OPTION_ARG_CALLBACK, &check_opt_frames, "Number of frames to acquire", NULL}, {"continuous", 0, 0, G_OPTION_ARG_NONE, &opt_continuous, "Sample continuously", NULL}, + {"get", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_gets, + "Get device options only", NULL}, {"set", 0, 0, G_OPTION_ARG_NONE, &opt_set, "Set device options only", NULL}, + {"list-serial", 0, 0, G_OPTION_ARG_NONE, &opt_list_serial, "List available serial/HID/BT/BLE ports", NULL}, {NULL, 0, 0, 0, NULL, NULL, NULL} }; -/* Parses the command line and sets all the 'opt_...' variables. - Returns zero on success, non-zero otherwise. */ +/* + * Parses the command line and sets all the 'opt_...' variables. + * Returns zero on success, non-zero otherwise. + */ int parse_options(int argc, char **argv) { GError *error = NULL; @@ -115,10 +185,41 @@ int parse_options(int argc, char **argv) goto done; } + /* + * Because of encoding issues with filenames (mentioned in the glib + * documentation), we don't check them with a callback function, but + * collect them into arrays and then check if the arrays contain at + * most one element. + */ + if (NULL != input_file_array) { + if (NULL != input_file_array[0] && NULL != input_file_array[1]) { + g_critical("option \"--input-file/-i\" only allowed once"); + goto done; + } + opt_input_file = g_strdup(input_file_array[0]); + } + + if (NULL != output_file_array) { + if (NULL != output_file_array[0] && NULL != output_file_array[1]) { + g_critical("option \"--output-file/-o\" only allowed once"); + goto done; + } + opt_output_file = g_strdup(output_file_array[0]); + } + + if (1 != argc) { + g_critical("superfluous command line argument \"%s\"", argv[1]); + goto done; + } + ret = 0; done: g_option_context_free(context); + g_strfreev(input_file_array); + g_strfreev(output_file_array); + input_file_array = NULL; + output_file_array = NULL; return ret; } @@ -133,4 +234,16 @@ void show_help(void) g_free(help); g_option_context_free(context); + +#ifdef HAVE_SRD +#define SHOW_DECODER_TEXT "| -P " +#else +#define SHOW_DECODER_TEXT "" +#endif + printf("Example use, typical options:\n"); + printf(" -d --scan\n"); + printf(" -d { --samples N | --frames N | --time T | --continuous }\n"); + printf(" { -d | -I | -O %s} --show\n", SHOW_DECODER_TEXT); + printf(" See the manpage or the wiki for more details.\n"); + printf(" Note: --samples/--frames/--time/--continuous is required for acquisition.\n"); }