diff options
author | Andreas Eversberg <jolly@eversberg.eu> | 2018-05-19 10:56:43 +0200 |
---|---|---|
committer | Andreas Eversberg <jolly@eversberg.eu> | 2018-05-21 19:39:09 +0200 |
commit | 3b8100721032397f507b93c059d3dec0365c7eb0 (patch) | |
tree | 10d2ce93dc2bd57f33ac3e6fefa86e23d162a08c | |
parent | 6ba1b8acab77520e29ba6ba6d7e18583297a4e41 (diff) |
Refactoring command line option handling
* Use own function to define and parse command line options
* Command line options can be defined by config file also
* --limesdr allows to auto-set required SDR option for LimeSDR
37 files changed, 1426 insertions, 1436 deletions
@@ -20,6 +20,7 @@ compile .libs .dirstamp m4 +src/liboptions/liboptions.a src/libdebug/libdebug.a src/libmobile/libmobile.a src/libdisplay/libdisplay.a diff --git a/configure.ac b/configure.ac index aa34386..c93de4a 100644 --- a/configure.ac +++ b/configure.ac @@ -49,6 +49,7 @@ AS_IF([test "x$with_imagemagick" == "xyes"],[AC_MSG_NOTICE( Compiling with Image AS_IF([test "x$with_alsa" != "xyes" -a "x$with_sdr" != "xyes"],[AC_MSG_FAILURE( Without sound nor SDR support this project does not make sense. Please support sound card for analog transceivers or better SDR!" )],[]) AC_OUTPUT( + src/liboptions/Makefile src/libdebug/Makefile src/libmobile/Makefile src/libdisplay/Makefile diff --git a/docs/sdr.html b/docs/sdr.html index c4b3bf5..09bded1 100644 --- a/docs/sdr.html +++ b/docs/sdr.html @@ -67,7 +67,7 @@ LimeSDR </p> <p> -If you have this device, you need to install the SoapySDR, then the LimeSuit and finally run configure with Osmocom Analog, compile and install. +If you have this device, you need to install the SoapySDR, then the LimeSuite and finally run configure with Osmocom Analog, compile and install. Run Osmocom Analog with --help again, and you should see a bunch of option for SDR. In case of B-Netz, I use the following parameters: </p> @@ -75,8 +75,9 @@ In case of B-Netz, I use the following parameters: <pre> # bnetz --sdr-soapy \ - --sdr-tx-gain 50 \ + --sdr-rx-antenna LNAL \ --sdr-rx-gain 30 \ + --sdr-tx-gain 30 \ --sdr-samplerate 5000000 \ -s 100000 \ -k 17 @@ -84,6 +85,12 @@ In case of B-Netz, I use the following parameters: </pre> <p> +Be sure to select the right RX antenna input. +The frequencies we use require the low frequency filter network, so I suggest to connect your antenna to RX_1_L and select "--sdr-rx-antenna LNAL". +Different versions of LimeSuite have different default antenna inputs, so be sure to set your RX antenna. +</p> + +<p> In order to change from analog sound card to SDR, you need <b>--sdr-soapy</b> option. In my setup I use antennas directly connected to the SDR. Being about 1-10 meters away, I use the <b>gain</b> as defined above. @@ -170,7 +177,8 @@ Because C-Netz uses only odd channel numbers for 10 KHz spacing, we use channel <pre> # cnetz --sdr-soapy \ - --sdr-rx-gain 50 \ + --sdr-rx-antenna LNAL \ + --sdr-rx-gain 30 \ --sdr-tx-gain 30 \ --sdr-samplerate 5000000 \ -s 100000 \ diff --git a/src/Makefile.am b/src/Makefile.am index aa068e1..4f1751f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,7 @@ AUTOMAKE_OPTIONS = foreign SUBDIRS = \ + liboptions \ libdebug \ libmobile \ libdisplay \ diff --git a/src/amps/Makefile.am b/src/amps/Makefile.am index 9bc972f..73118e2 100644 --- a/src/amps/Makefile.am +++ b/src/amps/Makefile.am @@ -26,6 +26,7 @@ amps_SOURCES = \ amps_LDADD = \ $(COMMON_LA) \ libamps.a \ + $(top_builddir)/src/liboptions/liboptions.a \ $(top_builddir)/src/libdebug/libdebug.a \ $(top_builddir)/src/libmobile/libmobile.a \ $(top_builddir)/src/libdisplay/libdisplay.a \ diff --git a/src/amps/amps_tacs_main.c b/src/amps/amps_tacs_main.c index 9601b10..df1dca0 100644 --- a/src/amps/amps_tacs_main.c +++ b/src/amps/amps_tacs_main.c @@ -19,13 +19,14 @@ #include <stdio.h> #include <stdint.h> -#include <getopt.h> #include <stdlib.h> #include <string.h> +#include <errno.h> #include "../libsample/sample.h" #include "../libmobile/main_mobile.h" #include "../libdebug/debug.h" #include "../libmobile/call.h" +#include "../liboptions/options.h" #include "amps.h" #include "dsp.h" #include "frame.h" @@ -103,152 +104,132 @@ void print_help(const char *arg0) main_mobile_print_hotkeys(); } -static int handle_options(int argc, char **argv) +static void add_options(void) +{ + main_mobile_add_options(); + option_add('T', "channel-type", 1); + option_add('F', "flip-polarity", 1); + option_add('P', "ms-power", 1); + option_add('D', "dtx", 1); + option_add('S', "sysinfo", 1); + option_add('O', "tolerant", 0); +} + +static int handle_options(int short_option, int argi, char **argv) { const char *p; - int skip_args = 0; int rc; - static struct option long_options_special[] = { - {"channel-type", 1, 0, 'T'}, - {"flip-polarity", 1, 0, 'F'}, - {"ms-power", 1, 0, 'P'}, - {"dtx", 1, 0, 'D'}, - {"sysinfo", 1, 0, 'S'}, - {"tolerant", 0, 0, 'O'}, - {0, 0, 0, 0} - }; - - main_mobile_set_options("T:F:P:D:S:O", long_options_special); - - while (1) { - int option_index = 0, c; - - c = getopt_long(argc, argv, optstring, long_options, &option_index); - - if (c == -1) - break; - - switch (c) { - case 'T': - if (!strcmp(optarg, "list")) { - amps_channel_list(); - exit(0); - } - rc = amps_channel_by_short_name(optarg); - if (rc < 0) { - fprintf(stderr, "Error, channel type '%s' unknown. Please use '-t list' to get a list. I suggest to use the default.\n", optarg); - exit(0); - } - OPT_ARRAY(num_chan_type, chan_type, rc) - skip_args += 2; - break; - case 'F': - if (!strcasecmp(optarg, "no")) - flip_polarity = "no"; - else if (!strcasecmp(optarg, "yes")) - flip_polarity = "yes"; - else { - fprintf(stderr, "Given polarity '%s' is illegal, see help!\n", optarg); - exit(0); - } - skip_args += 2; - break; - case 'P': - ms_power = atoi(optarg); - if (ms_power > 7) - ms_power = 7; - if (ms_power < 0) - ms_power = 0; - skip_args += 2; - break; - case 'D': - dtx = atoi(optarg); - if (dtx > 3) - dtx = 3; - if (dtx < 0) - dtx = 0; - skip_args += 2; - break; - case 'S': - p = strchr(optarg, '='); - if (!p) { - fprintf(stderr, "Given sysinfo parameter '%s' requires '=' character to set value, see help!\n", optarg); - exit(0); - } - p++; - if (!strncasecmp(optarg, "sid=", p - optarg) - || !strncasecmp(optarg, "aid=", p - optarg)) { - if (!strcasecmp(p, "list")) { - list_stations(); - exit(0); - } - sid = atoi(p); - if (sid > 32767) - sid = 32767; - if (sid < 0) - sid = 0; - } else - if (!strncasecmp(optarg, "dcc=", p - optarg)) { - dcc = atoi(p); - if (dcc > 3) - dcc = 3; - if (dcc < 0) - dcc = 0; - } else - if (!strncasecmp(optarg, "scc=", p - optarg)) { - scc = atoi(p); - if (scc > 2) - scc = 2; - if (scc < 0) - scc = 0; - } else - if (!strncasecmp(optarg, "regincr=", p - optarg)) { - regincr = atoi(p); - } else - if (!strncasecmp(optarg, "pureg=", p - optarg)) { - pureg = atoi(p) & 1; - } else - if (!strncasecmp(optarg, "pdreg=", p - optarg)) { - pdreg = atoi(p) & 1; - } else - if (!strncasecmp(optarg, "locaid=", p - optarg)) { - locaid = atoi(p); - if (locaid > 4095) - locaid = 4095; - } else - if (!strncasecmp(optarg, "regh=", p - optarg)) { - regh = atoi(p) & 1; - } else - if (!strncasecmp(optarg, "regr=", p - optarg)) { - regr = atoi(p) & 1; - } else - if (!strncasecmp(optarg, "bis=", p - optarg)) { - bis = atoi(p) & 1; - } else { - fprintf(stderr, "Given sysinfo parameter '%s' unknown, see help!\n", optarg); - exit(0); + switch (short_option) { + case 'T': + if (!strcmp(argv[argi], "list")) { + amps_channel_list(); + return 0; + } + rc = amps_channel_by_short_name(argv[argi]); + if (rc < 0) { + fprintf(stderr, "Error, channel type '%s' unknown. Please use '-t list' to get a list. I suggest to use the default.\n", argv[argi]); + return -EINVAL; + } + OPT_ARRAY(num_chan_type, chan_type, rc) + break; + case 'F': + if (!strcasecmp(argv[argi], "no")) + flip_polarity = "no"; + else if (!strcasecmp(argv[argi], "yes")) + flip_polarity = "yes"; + else { + fprintf(stderr, "Given polarity '%s' is illegal, use '-h' for help!\n", argv[argi]); + return -EINVAL; + } + break; + case 'P': + ms_power = atoi(argv[argi]); + if (ms_power > 7) + ms_power = 7; + if (ms_power < 0) + ms_power = 0; + break; + case 'D': + dtx = atoi(argv[argi]); + if (dtx > 3) + dtx = 3; + if (dtx < 0) + dtx = 0; + break; + case 'S': + p = strchr(argv[argi], '='); + if (!p) { + fprintf(stderr, "Given sysinfo parameter '%s' requires '=' character to set value, use '-h' for help!\n", argv[argi]); + return -EINVAL; + } + p++; + if (!strncasecmp(argv[argi], "sid=", p - argv[argi]) + || !strncasecmp(argv[argi], "aid=", p - argv[argi])) { + if (!strcasecmp(p, "list")) { + list_stations(); + return 0; } - skip_args += 2; - break; - case 'O': - tolerant = 1; - skip_args += 1; - break; - default: - main_mobile_opt_switch(c, argv[0], &skip_args); + sid = atoi(p); + if (sid > 32767) + sid = 32767; + if (sid < 0) + sid = 0; + } else + if (!strncasecmp(argv[argi], "dcc=", p - argv[argi])) { + dcc = atoi(p); + if (dcc > 3) + dcc = 3; + if (dcc < 0) + dcc = 0; + } else + if (!strncasecmp(argv[argi], "scc=", p - argv[argi])) { + scc = atoi(p); + if (scc > 2) + scc = 2; + if (scc < 0) + scc = 0; + } else + if (!strncasecmp(argv[argi], "regincr=", p - argv[argi])) { + regincr = atoi(p); + } else + if (!strncasecmp(argv[argi], "pureg=", p - argv[argi])) { + pureg = atoi(p) & 1; + } else + if (!strncasecmp(argv[argi], "pdreg=", p - argv[argi])) { + pdreg = atoi(p) & 1; + } else + if (!strncasecmp(argv[argi], "locaid=", p - argv[argi])) { + locaid = atoi(p); + if (locaid > 4095) + locaid = 4095; + } else + if (!strncasecmp(argv[argi], "regh=", p - argv[argi])) { + regh = atoi(p) & 1; + } else + if (!strncasecmp(argv[argi], "regr=", p - argv[argi])) { + regr = atoi(p) & 1; + } else + if (!strncasecmp(argv[argi], "bis=", p - argv[argi])) { + bis = atoi(p) & 1; + } else { + fprintf(stderr, "Given sysinfo parameter '%s' unknown, use '-h' for help!\n", argv[argi]); + return -EINVAL; } + break; + case 'O': + tolerant = 1; + break; + default: + return main_mobile_handle_options(short_option, argi, argv); } - free(long_options); - - return skip_args; + return 1; } int main_amps_tacs(int argc, char *argv[]) { - int rc; - int skip_args; + int rc, argi; const char *station_id = ""; int polarity; int i; @@ -258,12 +239,24 @@ int main_amps_tacs(int argc, char *argv[]) main_mobile_init(); - skip_args = handle_options(argc, argv); - argc -= skip_args; - argv += skip_args; + /* handle options / config file */ + add_options(); + if (!tacs) { + rc = options_config_file("~/.osmocom/analog/amps.conf", handle_options); + } else if (!jtacs) { + rc = options_config_file("~/.osmocom/analog/tacs.conf", handle_options); + } else { + rc = options_config_file("~/.osmocom/analog/jtacs.conf", handle_options); + } + if (rc < 0) + return 0; + argi = options_command_line(argc, argv, handle_options); + if (argi <= 0) + return argi; + - if (argc > 1) { - station_id = argv[1]; + if (argi < argc) { + station_id = argv[argi]; if (strlen(station_id) != 10) { printf("Given station ID '%s' does not have 10 digits\n", station_id); return 0; @@ -272,7 +265,7 @@ int main_amps_tacs(int argc, char *argv[]) if (!num_kanal) { printf("No channel (\"Kanal\") is specified, I suggest channel %d.\n\n", (!tacs) ? 334 : 323); - print_help(argv[-skip_args]); + print_help(argv[0]); return 0; } if (use_sdr) { @@ -380,7 +373,7 @@ int main_amps_tacs(int argc, char *argv[]) else if (use_sdr) polarity = 1; /* SDR is always positive */ else { - fprintf(stderr, "You must define, if the the TX deviation polarity has to be flipped. (-F yes | no) See help.\n"); + fprintf(stderr, "You must define, if the the TX deviation polarity has to be flipped. (-F yes | no) use '-h' for help.\n"); exit(0); } diff --git a/src/anetz/Makefile.am b/src/anetz/Makefile.am index 175404d..eba47db 100644 --- a/src/anetz/Makefile.am +++ b/src/anetz/Makefile.am @@ -18,6 +18,7 @@ anetz_SOURCES = \ anetz_LDADD = \ $(COMMON_LA) \ libgermanton.a \ + $(top_builddir)/src/liboptions/liboptions.a \ $(top_builddir)/src/libdebug/libdebug.a \ $(top_builddir)/src/libmobile/libmobile.a \ $(top_builddir)/src/libdisplay/libdisplay.a \ diff --git a/src/anetz/main.c b/src/anetz/main.c index 617bd88..35fc036 100644 --- a/src/anetz/main.c +++ b/src/anetz/main.c @@ -19,15 +19,16 @@ #include <stdio.h> #include <stdint.h> -#include <getopt.h> #include <stdlib.h> #include <string.h> +#include <errno.h> #include <math.h> #include "../libsample/sample.h" #include "../libmobile/main_mobile.h" #include "../libdebug/debug.h" #include "../libtimer/timer.h" #include "../libmobile/call.h" +#include "../liboptions/options.h" #include "freiton.h" #include "besetztton.h" #include "anetz.h" @@ -69,79 +70,60 @@ void print_help(const char *arg0) main_mobile_print_hotkeys(); } -static int handle_options(int argc, char **argv) +static void add_options(void) +{ + main_mobile_add_options(); + option_add('O', "operator", 1); + option_add('G', "geo", 1); + option_add('V', "page-gain", 1); + option_add('P', "page-sequence", 1); + option_add('S', "squelch", 1); +} + +static int handle_options(int short_option, int argi, char **argv) { - int skip_args = 0; char *p; double gain_db; - static struct option long_options_special[] = { - {"operator", 1, 0, 'O'}, - {"geo", 1, 0, 'G'}, - {"page-gain", 1, 0, 'V'}, - {"page-sequence", 1, 0, 'P'}, - {"squelch", 1, 0, 'S'}, - {0, 0, 0, 0} - }; - - main_mobile_set_options("O:G:V:P:S:", long_options_special); - - while (1) { - int option_index = 0, c; - - c = getopt_long(argc, argv, optstring, long_options, &option_index); - - if (c == -1) - break; - - switch (c) { - case 'O': - strncpy(operator, optarg, sizeof(operator) - 1); - operator[sizeof(operator) - 1] = '\0'; - skip_args += 2; - break; - case 'G': - if (!strcasecmp(optarg, "list")) { - station_list(); - exit(0); - } - if ((p = strchr(optarg, ','))) { - get_station_by_coordinates(atof(optarg), atof(p + 1)); - exit(0); - } - fprintf(stderr, "Invalid geo parameter\n"); - exit(0); - break; - case 'V': - gain_db = atof(optarg); - page_gain = pow(10, gain_db / 20.0); - skip_args += 2; - break; - case 'P': - page_sequence = atoi(optarg); - skip_args += 2; - break; - case 'S': - if (!strcasecmp(optarg, "auto")) - squelch_db = 0.0; - else - squelch_db = atof(optarg); - skip_args += 2; - break; - default: - main_mobile_opt_switch(c, argv[0], &skip_args); + switch (short_option) { + case 'O': + strncpy(operator, argv[argi], sizeof(operator) - 1); + operator[sizeof(operator) - 1] = '\0'; + break; + case 'G': + if (!strcasecmp(argv[argi], "list")) { + station_list(); + return 0; } + if ((p = strchr(argv[argi], ','))) { + get_station_by_coordinates(atof(argv[argi]), atof(p + 1)); + return 0; + } + fprintf(stderr, "Invalid geo parameter\n"); + return -EINVAL; + case 'V': + gain_db = atof(argv[argi]); + page_gain = pow(10, gain_db / 20.0); + break; + case 'P': + page_sequence = atoi(argv[argi]); + break; + case 'S': + if (!strcasecmp(argv[argi], "auto")) + squelch_db = 0.0; + else + squelch_db = atof(argv[argi]); + break; + default: + return main_mobile_handle_options(short_option, argi, argv); } - free(long_options); - - return skip_args; + return 1; } int main(int argc, char *argv[]) { - int rc; - int skip_args; + int rc, argi; const char *station_id = ""; int i; @@ -154,12 +136,17 @@ int main(int argc, char *argv[]) main_mobile_init(); - skip_args = handle_options(argc, argv); - argc -= skip_args; - argv += skip_args; + /* handle options / config file */ + add_options(); + rc = options_config_file("~/.osmocom/analog/anetz.conf", handle_options); + if (rc < 0) + return 0; + argi = options_command_line(argc, argv, handle_options); + if (argi <= 0) + return argi; - if (argc > 1) { - station_id = argv[1]; + if (argi < argc) { + station_id = argv[argi]; if (strlen(station_id) != 5 && strlen(station_id) != 7) { printf("Given station ID '%s' does not have 7 or (the last) 5 digits\n", station_id); return 0; @@ -170,7 +157,7 @@ int main(int argc, char *argv[]) if (!num_kanal) { printf("No channel (\"Kanal\") is specified, I suggest channel 30.\n\n"); - print_help(argv[-skip_args]); + print_help(argv[0]); return 0; } if (use_sdr) { diff --git a/src/bnetz/Makefile.am b/src/bnetz/Makefile.am index bc562e9..ecb611e 100644 --- a/src/bnetz/Makefile.am +++ b/src/bnetz/Makefile.am @@ -15,6 +15,7 @@ bnetz_SOURCES = \ bnetz_LDADD = \ $(COMMON_LA) \ ../anetz/libgermanton.a \ + $(top_builddir)/src/liboptions/liboptions.a \ $(top_builddir)/src/libdebug/libdebug.a \ $(top_builddir)/src/libmobile/libmobile.a \ $(top_builddir)/src/libdisplay/libdisplay.a \ @@ -36,6 +37,7 @@ bnetz_dialer_SOURCES = \ dialer.c bnetz_dialer_LDADD = \ $(COMMON_LA) \ + $(top_builddir)/src/liboptions/liboptions.a \ $(top_builddir)/src/libdebug/libdebug.a \ $(top_builddir)/src/libfsk/libfsk.a \ $(top_builddir)/src/libfm/libfm.a \ diff --git a/src/bnetz/dialer.c b/src/bnetz/dialer.c index a3a292d..05195e3 100644 --- a/src/bnetz/dialer.c +++ b/src/bnetz/dialer.c @@ -19,10 +19,10 @@ #include <stdio.h> #include <stdint.h> -#include <getopt.h> #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <errno.h> #include "../libsample/sample.h" #include "../libfsk/fsk.h" #include "../libwave/wave.h" @@ -30,6 +30,7 @@ #ifdef HAVE_ALSA #include "../libsound/sound.h" #endif +#include "../liboptions/options.h" #include "telegramm.h" #define MAX_PAUSE 0.5 /* pause before and after dialing sequence */ @@ -92,7 +93,6 @@ static void print_help(const char *arg0) printf(" -a --audio-device hw:<card>,<device>\n"); printf(" Sound card and device number (default = '%s')\n", audiodev); #endif - printf(" Don't set it for SDR!\n"); printf(" -s --samplerate <rate>\n"); printf(" Sample rate of sound device (default = '%d')\n", samplerate); printf(" -w --write-tx-wave <file>\n"); @@ -106,70 +106,50 @@ static void print_help(const char *arg0) printf(" Indicate to base station that we are a pay phone. ('Muenztelefon')\n"); } -static int handle_options(int argc, char **argv) +static void add_options(void) { - const char *optstring; - int skip_args = 0; - - static struct option long_options[] = { - {"help", 0, 0, 'h'}, - {"station-id", 1, 0, 'i'}, - {"audio-device", 1, 0, 'a'}, - {"samplerate", 1, 0, 's'}, - {"write-tx-wave", 1, 0, 'w'}, - {"gebuehrenimpuls", 0, 0, 'g'}, - {"metering", 0, 0, OPT_METERING}, - {"muenztelefon", 0, 0, 'm'}, - {"coin-box", 0, 0, OPT_COIN_BOX}, - {0, 0, 0, 0}, - }; - - optstring = "hi:a:s:w:gm"; - - while (1) { - int option_index = 0, c; - - c = getopt_long(argc, argv, optstring, long_options, &option_index); - - if (c == -1) - break; + option_add('h', "help", 0); + option_add('i', "station-id", 1); + option_add('a', "audio-device", 1); + option_add('s', "samplerate", 1); + option_add('w', "write-tx-wave", 1); + option_add('g', "gebuehrenimpuls", 0); + option_add(OPT_METERING, "metering", 0); + option_add('m', "muenztelefon", 0); + option_add(OPT_COIN_BOX, "coin-box", 0); +} - switch (c) { - case 'h': - print_help(argv[0]); - exit(0); - case 'i': - station_id = strdup(optarg); - skip_args += 2; - break; - case 'a': - audiodev = strdup(optarg); - skip_args += 2; - break; - case 's': - samplerate = atoi(optarg); - skip_args += 2; - break; - case 'w': - write_tx_wave = strdup(optarg); - skip_args += 2; - break; - case 'g': - case OPT_METERING: - start_digit = 'S'; - skip_args += 1; - break; - case 'm': - case OPT_COIN_BOX: - start_digit = 'M'; - skip_args += 1; - break; - default: - break; - } +static int handle_options(int short_option, int __attribute__((unused)) argi, char **argv) +{ + switch (short_option) { + case 'h': + print_help(argv[0]); + return 0; + case 'i': + station_id = strdup(argv[argi]); + break; + case 'a': + audiodev = strdup(argv[argi]); + break; + case 's': + samplerate = atoi(argv[argi]); + break; + case 'w': + write_tx_wave = strdup(argv[argi]); + break; + case 'g': + case OPT_METERING: + start_digit = 'S'; + break; + case 'm': + case OPT_COIN_BOX: + start_digit = 'M'; + break; + default: + return -EINVAL; } - return skip_args; + return 1; } @@ -301,10 +281,8 @@ static void process_signal(void) int main(int argc, char *argv[]) { - const char *arg0 = argv[0]; - int skip_args; int i; - int rc; + int rc, argi; /* init */ bnetz_init_telegramm(); @@ -313,13 +291,15 @@ int main(int argc, char *argv[]) /* latency of send buffer in samples */ latspl = samplerate * latency / 1000; - skip_args = handle_options(argc, argv); - argc -= skip_args; - argv += skip_args; + /* handle options / config file */ + add_options(); + argi = options_command_line(argc, argv, handle_options); + if (argi <= 0) + return argi; - if (argc <= 1) { + if (argi >= argc) { printf("No phone number given!\n\n"); - print_help(arg0); + print_help(argv[0]); goto exit; } @@ -336,7 +316,7 @@ int main(int argc, char *argv[]) } /* check for valid phone number */ - dialing = argv[1]; + dialing = argv[argi]; if (strlen(dialing) < 4) { printf("Given phone number '%s' has too few digits! (less than minimum of 4 digits)\n", dialing); goto exit; diff --git a/src/bnetz/main.c b/src/bnetz/main.c index d287e14..d60ba88 100644 --- a/src/bnetz/main.c +++ b/src/bnetz/main.c @@ -19,9 +19,9 @@ #include <stdio.h> #include <stdint.h> -#include <getopt.h> #include <stdlib.h> #include <string.h> +#include <errno.h> #include <math.h> #include "../libsample/sample.h" #include "../libdebug/debug.h" @@ -29,6 +29,7 @@ #include "../libmobile/main_mobile.h" #include "../anetz/freiton.h" #include "../anetz/besetztton.h" +#include "../liboptions/options.h" #include "bnetz.h" #include "dsp.h" #include "stations.h" @@ -79,70 +80,54 @@ void print_help(const char *arg0) main_mobile_print_hotkeys(); } -static int handle_options(int argc, char **argv) +static void add_options(void) +{ + main_mobile_add_options(); + option_add('G', "gfs", 1); + option_add('M', "gebuehrenimpuls", 1); + option_add('P', "paging", 1); + option_add('S', "squelch", 1); +} + +static int handle_options(int short_option, int argi, char **argv) { - int skip_args = 0; char *p; - static struct option long_options_special[] = { - {"gfs", 1, 0, 'G'}, - {"gebuehrenimpuls", 1, 0, 'M'}, - {"paging", 1, 0, 'P'}, - {"squelch", 1, 0, 'S'}, - {0, 0, 0, 0}, - }; - - main_mobile_set_options("G:M:P:S:", long_options_special); - - while (1) { - int option_index = 0, c; - - c = getopt_long(argc, argv, optstring, long_options, &option_index); - - if (c == -1) - break; - - switch (c) { - case 'G': - if (!strcasecmp(optarg, "list")) { - station_list(); - exit(0); - } - if ((p = strchr(optarg, ','))) { - gfs = get_station_by_coordinates(atof(optarg), atof(p + 1)); - if (gfs == 0) - exit(0); - } else - gfs = atoi(optarg); - skip_args += 2; - break; - case 'M': - metering = atoi(optarg); - skip_args += 2; - break; - case 'P': - paging = strdup(optarg); - skip_args += 2; - break; - case 'S': - if (!strcasecmp(optarg, "auto")) - squelch_db = 0.0; - else - squelch_db = atof(optarg); - skip_args += 2; - break; - default: - main_mobile_opt_switch(c, argv[0], &skip_args); + switch (short_option) { + case 'G': + if (!strcasecmp(argv[argi], "list")) { + station_list(); + return 0; } + if ((p = strchr(argv[argi], ','))) { + gfs = get_station_by_coordinates(atof(argv[argi]), atof(p + 1)); + if (gfs == 0) + return -EINVAL; + } else + gfs = atoi(argv[argi]); + break; + case 'M': + metering = atoi(argv[argi]); + break; + case 'P': + paging = strdup(argv[argi]); + break; + case 'S': + if (!strcasecmp(argv[argi], "auto")) + squelch_db = 0.0; + else + squelch_db = atof(argv[argi]); + break; + default: + return main_mobile_handle_options(short_option, argi, argv); } - return skip_args; + return 1; } int main(int argc, char *argv[]) { - int rc; - int skip_args; + int rc, argi; const char *station_id = ""; int i; @@ -153,12 +138,17 @@ int main(int argc, char *argv[]) main_mobile_init(); - skip_args = handle_options(argc, argv); - argc -= skip_args; - argv += skip_args; + /* handle options / config file */ + add_options(); + rc = options_config_file("~/.osmocom/analog/bnetz.conf", handle_options); + if (rc < 0) + return 0; + argi = options_command_line(argc, argv, handle_options); + if (argi <= 0) + return argi; - if (argc > 1) { - station_id = argv[1]; + if (argi < argc) { + station_id = argv[argi]; if (strlen(station_id) != 5) { printf("Given station ID '%s' does not have 5 digits\n", station_id); return 0; @@ -167,7 +157,7 @@ int main(int argc, char *argv[]) if (!num_kanal) { printf("No channel (\"Kanal\") is specified, I suggest channel 1 (sound card) or 17 (SDR).\n\n"); - print_help(argv[-skip_args]); + print_help(argv[0]); return 0; } if (use_sdr) { diff --git a/src/cnetz/Makefile.am b/src/cnetz/Makefile.am index ab7cf09..5823467 100644 --- a/src/cnetz/Makefile.am +++ b/src/cnetz/Makefile.am @@ -17,6 +17,7 @@ cnetz_SOURCES = \ cnetz_LDADD = \ $(COMMON_LA) \ ../anetz/libgermanton.a \ + $(top_builddir)/src/liboptions/liboptions.a \ $(top_builddir)/src/libdebug/libdebug.a \ $(top_builddir)/src/libmobile/libmobile.a \ $(top_builddir)/src/libdisplay/libdisplay.a \ diff --git a/src/cnetz/main.c b/src/cnetz/main.c index 8d31cd5..c5dd916 100644 --- a/src/cnetz/main.c +++ b/src/cnetz/main.c @@ -19,15 +19,16 @@ #include <stdio.h> #include <stdint.h> -#include <getopt.h> #include <stdlib.h> #include <string.h> +#include <errno.h> #include "../libsample/sample.h" #include "../libmobile/main_mobile.h" #include "../libdebug/debug.h" #include "../libmobile/call.h" #include "../anetz/freiton.h" #include "../anetz/besetztton.h" +#include "../liboptions/options.h" #include "cnetz.h" #include "database.h" #include "sysinfo.h" @@ -216,198 +217,174 @@ static int atoi_limit(const char *p, int l1, int l2) #define OPT_WARTESCHLANGE 256 -static int handle_options(int argc, char **argv) +static void add_options(void) +{ + main_mobile_add_options(); + option_add('T', "channel-type", 1); + option_add('M', "measure-speed", 0); + option_add('C', "clock-speed", 1); + option_add('F', "flip-polarity", 1); + option_add('P', "ms-power", 1); + option_add('A', "authentication", 0); + option_add('Q', "queue", 1); + option_add(OPT_WARTESCHLANGE, "warteschlange", 1); + option_add('G', "gebuehren", 1); + option_add('S', "sysinfo", 1); + option_add('D', "demod", 1); +} + +static int handle_options(int short_option, int argi, char **argv) { - int skip_args = 0; int rc; const char *p; - static struct option long_options_special[] = { - {"channel-type", 1, 0, 'T'}, - {"measure-speed", 0, 0, 'M'}, - {"clock-speed", 1, 0, 'C'}, - {"flip-polarity", 1, 0, 'F'}, - {"ms-power", 1, 0, 'P'}, - {"authentication", 0, 0, 'A'}, - {"queue", 1, 0, 'Q'}, - {"warteschlange", 1, 0, OPT_WARTESCHLANGE}, - {"gebuehren", 1, 0, 'G'}, - {"sysinfo", 1, 0, 'S'}, - {"demod", 1, 0, 'D'}, - {0, 0, 0, 0} - }; - - main_mobile_set_options("T:MC:F:P:AQ:G:S:D:", long_options_special); - - while (1) { - int option_index = 0, c; - - c = getopt_long(argc, argv, optstring, long_options, &option_index); - - if (c == -1) - break; - - switch (c) { - case 'T': - if (!strcmp(optarg, "list")) { - cnetz_channel_list(); - exit(0); - } - rc = cnetz_channel_by_short_name(optarg); - if (rc < 0) { - fprintf(stderr, "Error, channel type '%s' unknown. Please use '-t list' to get a list. I suggest to use the default.\n", optarg); - exit(0); - } - OPT_ARRAY(num_chan_type, chan_type, rc) - skip_args += 2; - break; - case 'M': - measure_speed = 1; - skip_args++; - break; - case 'C': - p = strchr(optarg, ','); - if (!p) { - fprintf(stderr, "Illegal clock speed, use two values, seperated by comma and no spaces!\n"); - exit(0); - } - clock_speed[0] = strtold(optarg, NULL); - clock_speed[1] = strtold(p + 1, NULL); - set_clock_speed = 1; - skip_args += 2; - break; - case 'F': - if (!strcasecmp(optarg, "no")) - flip_polarity = "no"; - else if (!strcasecmp(optarg, "yes")) - flip_polarity = "yes"; - else if (!strcasecmp(optarg, "auto")) - flip_polarity = "auto"; - else { - fprintf(stderr, "Given polarity '%s' is illegal, see help!\n", optarg); - exit(0); - } - skip_args += 2; - break; - case 'P': - ms_power = atoi_limit(optarg, 0, 3); - skip_args += 2; - break; - case 'A': - auth = 1; - skip_args += 1; - break; - case 'Q': - case OPT_WARTESCHLANGE: - warteschlange = atoi_limit(optarg, 0, 1);; - skip_args += 2; - break; - case 'G': - metering = atoi(optarg); - skip_args += 2; - break; - case 'S': - p = strchr(optarg, '='); - if (!p) { - fprintf(stderr, "Given sysinfo parameter '%s' requires '=' character to set value, see help!\n", optarg); - exit(0); - } - p++; - if (!strncasecmp(optarg, "fuz-nat=", p - optarg)) { - fuz_nat = atoi_limit(p, 0, 7); - } else - if (!strncasecmp(optarg, "fuz-fuvst=", p - optarg)) { - fuz_fuvst = atoi_limit(p, 0, 32); - } else - if (!strncasecmp(optarg, "fuz-rest=", p - optarg)) { - fuz_rest = atoi_limit(p, 0, 255); - } else - if (!strncasecmp(optarg, "kennung-fufst=", p - optarg)) { - kennung_fufst = atoi_limit(p, 0, 3); - } else - if (!strncasecmp(optarg, "ws-kennung=", p - optarg)) { - ws_kennung = atoi_limit(p, 0, 3); - } else - if (!strncasecmp(optarg, "fuvst-sperren=", p - optarg)) { - fuvst_sperren = atoi_limit(p, 0, 3); - } else - if (!strncasecmp(optarg, "grenz-einbuchen=", p - optarg)) { - grenz_einbuchen = atoi_limit(p, 0, 7); - } else - if (!strncasecmp(optarg, "grenz-umschalten=", p - optarg)) { - grenz_umschalten = atoi_limit(p, 0, 15); - } else - if (!strncasecmp(optarg, "grenz-ausloesen=", p - optarg)) { - grenz_ausloesen = atoi_limit(p, 0, 15); - } else - if (!strncasecmp(optarg, "mittel-umschalten=", p - optarg)) { - mittel_umschalten = atoi_limit(p, 0, 5); - } else - if (!strncasecmp(optarg, "mittel-ausloesen=", p - optarg)) { - mittel_ausloesen = atoi_limit(p, 0, 5); - } else - if (!strncasecmp(optarg, "genauigkeit=", p - optarg)) { - genauigkeit = atoi_limit(p, 0, 1); - } else - if (!strncasecmp(optarg, "bewertung=", p - optarg)) { - bewertung = atoi_limit(p, 0, 1); - } else - if (!strncasecmp(optarg, "entfernung=", p - optarg)) { - entfernung = atoi_limit(p, 0, 15); - } else - if (!strncasecmp(optarg, "nachbar-prio=", p - optarg)) { - nachbar_prio = atoi_limit(p, 0, 1); - } else - if (!strncasecmp(optarg, "futln-sperre=", p - optarg)) { - char value[128], *v, *q; - strncpy(value, p, sizeof(value) - 1); - value[sizeof(value) - 1] = '\0'; - v = value; - q = strchr(value, '-'); - if (q) - *q++ = '\0'; - if (strlen(v) > 5) - v += strlen(v) - 5; - futln_sperre_start = atoi(v) & 0xf; - if (q) { - if (strlen(q) > 5) - q += strlen(q) - 5; - futln_sperre_end = atoi(q) & 0xf; - } - } else - { - fprintf(stderr, "Given sysinfo parameter '%s' unknown, see help!\n", optarg); - exit(0); - } - skip_args += 2; - break; - case 'D': - if (!strcasecmp(optarg, "auto")) - demod = FSK_DEMOD_AUTO; - else if (!strcasecmp(optarg, "slope")) - demod = FSK_DEMOD_SLOPE; - else if (!strcasecmp(optarg, "level")) - demod = FSK_DEMOD_LEVEL; - else { - fprintf(stderr, "Given demodulation type '%s' is illegal, see help!\n", optarg); - exit(0); + switch (short_option) { + case 'T': + if (!strcmp(argv[argi], "list")) { + cnetz_channel_list(); + return 0; + } + rc = cnetz_channel_by_short_name(argv[argi]); + if (rc < 0) { + fprintf(stderr, "Error, channel type '%s' unknown. Please use '-t list' to get a list. I suggest to use the default.\n", argv[argi]); + return -EINVAL; + } + OPT_ARRAY(num_chan_type, chan_type, rc) + break; + case 'M': + measure_speed = 1; + break; + case 'C': + p = strchr(argv[argi], ','); + if (!p) { + fprintf(stderr, "Illegal clock speed, use two values, seperated by comma and no spaces!\n"); + return -EINVAL; + } + clock_speed[0] = strtold(argv[argi], NULL); + clock_speed[1] = strtold(p + 1, NULL); + set_clock_speed = 1; + break; + case 'F': + if (!strcasecmp(argv[argi], "no")) + flip_polarity = "no"; + else if (!strcasecmp(argv[argi], "yes")) + flip_polarity = "yes"; + else if (!strcasecmp(argv[argi], "auto")) + flip_polarity = "auto"; + else { + fprintf(stderr, "Given polarity '%s' is illegal, use '-h' for help!\n", argv[argi]); + return -EINVAL; + } + break; + case 'P': + ms_power = atoi_limit(argv[argi], 0, 3); + break; + case 'A': + auth = 1; + break; + case 'Q': + case OPT_WARTESCHLANGE: + warteschlange = atoi_limit(argv[argi], 0, 1);; + break; + case 'G': + metering = atoi(argv[argi]); + break; + case 'S': + p = strchr(argv[argi], '='); + if (!p) { + fprintf(stderr, "Given sysinfo parameter '%s' requires '=' character to set value, use '-h' for help!\n", argv[argi]); + return -EINVAL; + } + p++; + if (!strncasecmp(argv[argi], "fuz-nat=", p - argv[argi])) { + fuz_nat = atoi_limit(p, 0, 7); + } else + if (!strncasecmp(argv[argi], "fuz-fuvst=", p - argv[argi])) { + fuz_fuvst = atoi_limit(p, 0, 32); + } else + if (!strncasecmp(argv[argi], "fuz-rest=", p - argv[argi])) { + fuz_rest = atoi_limit(p, 0, 255); + } else + if (!strncasecmp(argv[argi], "kennung-fufst=", p - argv[argi])) { + kennung_fufst = atoi_limit(p, 0, 3); + } else + if (!strncasecmp(argv[argi], "ws-kennung=", p - argv[argi])) { + ws_kennung = atoi_limit(p, 0, 3); + } else + if (!strncasecmp(argv[argi], "fuvst-sperren=", p - argv[argi])) { + fuvst_sperren = atoi_limit(p, 0, 3); + } else + if (!strncasecmp(argv[argi], "grenz-einbuchen=", p - argv[argi])) { + grenz_einbuchen = atoi_limit(p, 0, 7); + } else + if (!strncasecmp(argv[argi], "grenz-umschalten=", p - argv[argi])) { + grenz_umschalten = atoi_limit(p, 0, 15); + } else + if (!strncasecmp(argv[argi], "grenz-ausloesen=", p - argv[argi])) { + grenz_ausloesen = atoi_limit(p, 0, 15); + } else + if (!strncasecmp(argv[argi], "mittel-umschalten=", p - argv[argi])) { + mittel_umschalten = atoi_limit(p, 0, 5); + } else + if (!strncasecmp(argv[argi], "mittel-ausloesen=", p - argv[argi])) { + mittel_ausloesen = atoi_limit(p, 0, 5); + } else + if (!strncasecmp(argv[argi], "genauigkeit=", p - argv[argi])) { + genauigkeit = atoi_limit(p, 0, 1); + } else + if (!strncasecmp(argv[argi], "bewertung=", p - argv[argi])) { + bewertung = atoi_limit(p, 0, 1); + } else + if (!strncasecmp(argv[argi], "entfernung=", p - argv[argi])) { + entfernung = atoi_limit(p, 0, 15); + } else + if (!strncasecmp(argv[argi], "nachbar-prio=", p - argv[argi])) { + nachbar_prio = atoi_limit(p, 0, 1); + } else + if (!strncasecmp(argv[argi], "futln-sperre=", p - argv[argi])) { + char value[128], *v, *q; + strncpy(value, p, sizeof(value) - 1); + value[sizeof(value) - 1] = '\0'; + v = value; + q = strchr(value, '-'); + if (q) + *q++ = '\0'; + if (strlen(v) > 5) + v += strlen(v) - 5; + futln_sperre_start = atoi(v) & 0xf; + if (q) { + if (strlen(q) > 5) + q += strlen(q) - 5; + futln_sperre_end = atoi(q) & 0xf; } - skip_args += 2; - break; - default: - main_mobile_opt_switch(c, argv[0], &skip_args); + } else + { + fprintf(stderr, "Given sysinfo parameter '%s' unknown, use '-h' for help!\n", argv[argi]); + return -EINVAL; } + break; + case 'D': + if (!strcasecmp(argv[argi], "auto")) + demod = FSK_DEMOD_AUTO; + else if (!strcasecmp(argv[argi], "slope")) + demod = FSK_DEMOD_SLOPE; + else if (!strcasecmp(argv[argi], "level")) + demod = FSK_DEMOD_LEVEL; + else { + fprintf(stderr, "Given demodulation type '%s' is illegal, use '-h' for help!\n", argv[argi]); + return -EINVAL; + } + break; + default: + return main_mobile_handle_options(short_option, argi, argv); } - free(long_options); - - return skip_args; + return 1; } int main(int argc, char *argv[]) { - int rc; - int skip_args; + int rc, argi; const char *station_id = ""; int mandatory = 0; int polarity; @@ -422,12 +399,17 @@ int main(int argc, char *argv[]) main_mobile_init(); - skip_args = handle_options(argc, argv); - argc -= skip_args; - argv += skip_args; + /* handle options / config file */ + add_options(); + rc = options_config_file("~/.osmocom/analog/cnetz.conf", handle_options); + if (rc < 0) + return 0; + argi = options_command_line(argc, argv, handle_options); + if (argi <= 0) + return argi; - if (argc > 1) { - station_id = argv[1]; + if (argi < argc) { + station_id = argv[argi]; if (strlen(station_id) != 7) { printf("Given station ID '%s' does not have 7 digits\n", station_id); return 0; @@ -470,7 +452,7 @@ int main(int argc, char *argv[]) } if (mandatory) { - print_help(argv[-skip_args]); + print_help(argv[0]); return 0; } diff --git a/src/jolly/Makefile.am b/src/jolly/Makefile.am index e36515f..85d5fc5 100644 --- a/src/jolly/Makefile.am +++ b/src/jolly/Makefile.am @@ -11,6 +11,7 @@ jollycom_SOURCES = \ jollycom_LDADD = \ $(COMMON_LA) \ ../anetz/libgermanton.a \ + $(top_builddir)/src/liboptions/liboptions.a \ $(top_builddir)/src/libdebug/libdebug.a \ $(top_builddir)/src/libmobile/libmobile.a \ $(top_builddir)/src/libdisplay/libdisplay.a \ diff --git a/src/jolly/main.c b/src/jolly/main.c index 218ebfc..424b091 100644 --- a/src/jolly/main.c +++ b/src/jolly/main.c @@ -1,4 +1,4 @@ -/* main +/* JollyCom main * * (C) 2017 by Andreas Eversberg <jolly@eversberg.eu> * All Rights Reserved @@ -19,11 +19,11 @@ #include <stdio.h> #include <stdint.h> -#include <getopt.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> +#include <errno.h> #include <math.h> #include <sys/types.h> #include <sys/stat.h> @@ -34,6 +34,7 @@ #include "../libmncc/mncc_sock.h" #include "../anetz/freiton.h" #include "../anetz/besetztton.h" +#include "../liboptions/options.h" #include "jolly.h" #include "dsp.h" #include "voice.h" @@ -70,73 +71,55 @@ void print_help(const char *arg0) main_mobile_print_hotkeys(); } -static int handle_options(int argc, char **argv) +static void add_options(void) { - int skip_args = 0; - - static struct option long_options_special[] = { - {"frequency", 1, 0, 'F'}, - {"squelch", 1, 0, 'S'}, - {"nbfm", 0, 0, 'N'}, - {"repeater", 0, 0, 'R'}, - {0, 0, 0, 0} - }; - - main_mobile_set_options("F:S:NR", long_options_special); - - while (1) { - int option_index = 0, c; - char *string, *string_dl, *string_ul, *string_step; - - c = getopt_long(argc, argv, optstring, long_options, &option_index); - - if (c == -1) - break; - - switch (c) { - case 'F': - string = strdup(optarg); - string_dl = strsep(&string, ","); - string_ul = strsep(&string, ","); - string_step = strsep(&string, ","); - if (!string_dl || !string_ul || !string_step) { - fprintf(stderr, "Please give 3 values for --frequency, seperated by comma and no space!\n"); - exit(0); - } - dl_freq = atof(string_dl); - ul_freq = atof(string_ul); - step = atof(string_step); - skip_args += 2; - break; - case 'S': - if (!strcasecmp(optarg, "auto")) - squelch_db = 0.0; - else - squelch_db = atof(optarg); - skip_args += 2; - break; - case 'N': - nbfm = 1; - skip_args += 1; - break; - case 'R': - repeater = 1; - skip_args += 1; - break; - default: - main_mobile_opt_switch(c, argv[0], &skip_args); + main_mobile_add_options(); + option_add('F', "frequency", 1); + option_add('S', "squelch", 1); + option_add('N', "nbfm", 0); + option_add('R', "repeater", 0); +} + +static int handle_options(int short_option, int argi, char **argv) +{ + char *string, *string_dl, *string_ul, *string_step; + + switch (short_option) { + case 'F': + string = strdup(argv[argi]); + string_dl = strsep(&string, ","); + string_ul = strsep(&string, ","); + string_step = strsep(&string, ","); + if (!string_dl || !string_ul || !string_step) { + fprintf(stderr, "Please give 3 values for --frequency, seperated by comma and no space!\n"); + exit(0); } + dl_freq = atof(string_dl); + ul_freq = atof(string_ul); + step = atof(string_step); + break; + case 'S': + if (!strcasecmp(argv[argi], "auto")) + squelch_db = 0.0; + else + squelch_db = atof(argv[argi]); + break; + case 'N': + nbfm = 1; + break; + case 'R': + repeater = 1; + break; + default: + return main_mobile_handle_options(short_option, argi, argv); } - free(long_options); - - return skip_args; + return 1; } int main(int argc, char *argv[]) { - int rc; - int skip_args; + int rc, argi; const char *station_id = ""; int mandatory = 0; int i; @@ -148,12 +131,17 @@ int main(int argc, char *argv[]) main_mobile_init(); - skip_args = handle_options(argc, argv); - argc -= skip_args; - argv += skip_args; + /* handle options / config file */ + add_options(); + rc = options_config_file("~/.osmocom/analog/jollycom.conf", handle_options); + if (rc < 0) + return 0; + argi = options_command_line(argc, argv, handle_options); + if (argi <= 0) + return argi; - if (argc > 1) { - station_id = argv[1]; + if (argi < argc) { + station_id = argv[argi]; if (strlen(station_id) != 4) { printf("Given station ID '%s' does not have 4 digits\n", station_id); return 0; @@ -178,7 +166,7 @@ int main(int argc, char *argv[]) } if (mandatory) { - print_help(argv[-skip_args]); + print_help(argv[0]); return 0; } diff --git a/src/jtacs/Makefile.am b/src/jtacs/Makefile.am index f2b051b..b5a8bb4 100644 --- a/src/jtacs/Makefile.am +++ b/src/jtacs/Makefile.am @@ -12,6 +12,7 @@ jtacs_SOURCES = \ jtacs_LDADD = \ $(COMMON_LA) \ ../amps/libamps.a \ + $(top_builddir)/src/liboptions/liboptions.a \ $(top_builddir)/src/libdebug/libdebug.a \ $(top_builddir)/src/libmobile/libmobile.a \ $(top_builddir)/src/libdisplay/libdisplay.a \ diff --git a/src/libdebug/debug.c b/src/libdebug/debug.c index fd891ec..934294b 100644 --- a/src/libdebug/debug.c +++ b/src/libdebug/debug.c @@ -41,6 +41,7 @@ struct debug_cat { const char *name; const char *color; } debug_cat[] = { + { "options", "\033[1;37m" }, { "sender", "\033[1;33m" }, { "sound", "\033[0;35m" }, { "dsp", "\033[0;31m" }, diff --git a/src/libdebug/debug.h b/src/libdebug/debug.h index 8a76d45..cfc420a 100644 --- a/src/libdebug/debug.h +++ b/src/libdebug/debug.h @@ -4,28 +4,29 @@ #define DEBUG_NOTICE 2 /* something unexpected happens */ #define DEBUG_ERROR 3 /* there is an error with this software */ -#define DSENDER 0 -#define DSOUND 1 -#define DDSP 2 -#define DANETZ 3 -#define DBNETZ 4 -#define DCNETZ 5 -#define DNMT 6 -#define DAMPS 7 -#define DR2000 8 -#define DJOLLY 9 -#define DFRAME 10 -#define DCALL 11 -#define DMNCC 12 -#define DDB 13 -#define DTRANS 14 -#define DDMS 15 -#define DSMS 16 -#define DSDR 17 -#define DUHD 18 -#define DSOAPY 19 -#define DWAVE 20 -#define DRADIO 21 +#define DOPTIONS 0 +#define DSENDER 1 +#define DSOUND 2 +#define DDSP 3 +#define DANETZ 4 +#define DBNETZ 5 +#define DCNETZ 6 +#define DNMT 7 +#define DAMPS 8 +#define DR2000 9 +#define DJOLLY 10 +#define DFRAME 11 +#define DCALL 12 +#define DMNCC 13 +#define DDB 14 +#define DTRANS 15 +#define DDMS 16 +#define DSMS 17 +#define DSDR 18 +#define DUHD 19 +#define DSOAPY 20 +#define DWAVE 21 +#define DRADIO 22 void get_win_size(int *w, int *h); diff --git a/src/libmobile/main_mobile.c b/src/libmobile/main_mobile.c index a66e038..3eee1d4 100644 --- a/src/libmobile/main_mobile.c +++ b/src/libmobile/main_mobile.c @@ -19,7 +19,6 @@ #include <stdio.h> #include <stdint.h> -#include <getopt.h> #include <stdlib.h> #include <string.h> #include <signal.h> @@ -28,7 +27,6 @@ #include <math.h> #include <termios.h> #include <errno.h> -#include <getopt.h> #include "../libsample/sample.h" #include "main_mobile.h" #include "../libdebug/debug.h" @@ -42,6 +40,7 @@ #include "../libsdr/sdr.h" #include "../libsdr/sdr_config.h" #endif +#include "../liboptions/options.h" #define DEFAULT_LO_OFFSET -1000000.0 @@ -153,6 +152,8 @@ void main_mobile_print_help(const char *arg0, const char *ext_usage) printf(" --read-tx-wave <file>\n"); printf(" Replace transmitted audio by given wave file.\n"); #ifdef HAVE_SDR + printf(" --limesdr\n"); + printf(" Auto-select several required options for LimeSDR\n"); sdr_config_print_help(); #endif printf("\nNetwork specific options:\n"); @@ -178,214 +179,167 @@ void main_mobile_print_hotkeys(void) #define OPT_READ_TX_WAVE 1004 #define OPT_CALL_SAMPLERATE 1005 #define OPT_MNCC_NAME 1006 +#define OPT_LIMESDR 1100 -static struct option main_mobile_long_options[] = { - {"help", 0, 0, 'h'}, - {"debug", 1, 0, 'v'}, - {"kanal", 1, 0, 'k'}, - {"channel", 1, 0, OPT_CHANNEL}, - {"audio-device", 1, 0, 'a'}, - {"samplerate", 1, 0, 's'}, - {"interval", 1, 0, 'i'}, - {"buffer", 1, 0, 'b'}, - {"pre-emphasis", 0, 0, 'p'}, - {"de-emphasis", 0, 0, 'd'}, - {"rx-gain", 1, 0, 'g'}, - {"echo-test", 0, 0, 'e'}, - {"mncc-cross", 0, 0, 'x'}, - {"mncc-sock", 0, 0, 'm'}, - {"mncc-name", 1, 0, OPT_MNCC_NAME}, - {"call-device", 1, 0, 'c'}, - {"call-samplerate", 1, 0, OPT_CALL_SAMPLERATE}, - {"tones", 0, 0, 't'}, - {"loopback", 1, 0, 'l'}, - {"realtime", 1, 0, 'r'}, - {"write-rx-wave", 1, 0, OPT_WRITE_RX_WAVE}, - {"write-tx-wave", 1, 0, OPT_WRITE_TX_WAVE}, - {"read-rx-wave", 1, 0, OPT_READ_RX_WAVE}, - {"read-tx-wave", 1, 0, OPT_READ_TX_WAVE}, - {0, 0, 0, 0} -}; - -static const char *main_mobile_optstring = "hv:k:a:s:i:b:pdg:exmc:t:l:r:"; - -struct option *long_options; -char *optstring; - -static void check_duplicate_option(int num, struct option *option) -{ - int i; - - for (i = 0; i < num; i++) { - if (long_options[i].val == option->val) { - fprintf(stderr, "Duplicate option %d. Please fix!\n", option->val); - abort(); - } - } -} - -void main_mobile_set_options(const char *optstring_special, struct option *long_options_special) +void main_mobile_add_options(void) { - int i = 0, j; - - long_options = calloc(sizeof(*long_options), 256); - for (j = 0; main_mobile_long_options[j].name; i++, j++) { - check_duplicate_option(i, &main_mobile_long_options[j]); - memcpy(&long_options[i], &main_mobile_long_options[j], sizeof(*long_options)); - } + option_add('h', "help", 0); + option_add('v', "debug", 1); + option_add('k', "kanal", 1); + option_add(OPT_CHANNEL, "channel", 1); + option_add('a', "audio-device", 1); + option_add('s', "samplerate", 1); + option_add('i', "interval", 1); + option_add('b', "buffer", 1); + option_add('p', "pre-emphasis", 0); + option_add('d', "de-emphasis", 0); + option_add('g', "rx-gain", 1); + option_add('e', "echo-test", 0); + option_add('x', "mncc-cross", 0); + option_add('m', "mncc-sock", 0); + option_add(OPT_MNCC_NAME, "mncc-name", 1); + option_add('c', "call-device", 1); + option_add(OPT_CALL_SAMPLERATE, "call-samplerate", 1); + option_add('t', "tones", 0); + option_add('l', "loopback", 1); + option_add('r', "realtime", 1); + option_add(OPT_WRITE_RX_WAVE, "write-rx-wave", 1); + option_add(OPT_WRITE_TX_WAVE, "write-tx-wave", 1); + option_add(OPT_READ_RX_WAVE, "read-rx-wave", 1); + option_add(OPT_READ_TX_WAVE, "read-tx-wave", 1); #ifdef HAVE_SDR - for (j = 0; sdr_config_long_options[j].name; i++, j++) { - check_duplicate_option(i, &sdr_config_long_options[j]); - memcpy(&long_options[i], &sdr_config_long_options[j], sizeof(*long_options)); - } + option_add(OPT_LIMESDR, "limesdr", 0); + sdr_config_add_options(); #endif - for (; long_options_special->name; i++) { - check_duplicate_option(i, long_options_special); - memcpy(&long_options[i], long_options_special++, sizeof(*long_options)); - } - - optstring = calloc(256, 2); - strcpy(optstring, main_mobile_optstring); -#ifdef HAVE_SDR - strcat(optstring, sdr_config_optstring); -#endif - strcat(optstring, optstring_special); -} +}; void print_help(const char *arg0); -void main_mobile_opt_switch(int c, char *arg0, int *skip_args) +int main_mobile_handle_options(int short_option, int argi, char **argv) { double gain_db; -#ifdef HAVE_SDR int rc; -#endif - switch (c) { + switch (short_option) { case 'h': - print_help(arg0); - exit(0); + print_help(argv[0]); + return 0; case 'v': - if (!strcasecmp(optarg, "list")) { + if (!strcasecmp(argv[argi], "list")) { debug_list_cat(); - exit(0); + return 0; } - if (parse_debug_opt(optarg)) { + rc = parse_debug_opt(argv[argi]); + if (rc < 0) { fprintf(stderr, "Failed to parse debug option, please use -h for help.\n"); - exit(0); + return rc; } - *skip_args += 2; break; case 'k': case OPT_CHANNEL: - OPT_ARRAY(num_kanal, kanal, atoi(optarg)) - *skip_args += 2; + OPT_ARRAY(num_kanal, kanal, atoi(argv[argi])) break; case 'a': - OPT_ARRAY(num_audiodev, audiodev, strdup(optarg)) - *skip_args += 2; + OPT_ARRAY(num_audiodev, audiodev, strdup(argv[argi])) break; case 's': - samplerate = atoi(optarg); - *skip_args += 2; + samplerate = atoi(argv[argi]); break; case 'i': - interval = atoi(optarg); - *skip_args += 2; + interval = atoi(argv[argi]); if (interval < 1) interval = 1; if (interval > 25) interval = 25; break; case 'b': - latency = atoi(optarg); - *skip_args += 2; + latency = atoi(argv[argi]); break; case 'p': if (!uses_emphasis) { no_emph: fprintf(stderr, "This network does not use emphasis, please do not enable pre- or de-emphasis! Disable emphasis on transceiver, if possible.\n"); - exit(0); + return -EINVAL; } do_pre_emphasis = 1; - *skip_args += 1; break; case 'd': if (!uses_emphasis) goto no_emph; do_de_emphasis = 1; - *skip_args += 1; break; case 'g': - gain_db = atof(optarg); + gain_db = atof(argv[argi]); if (gain_db < 0.0) { fprintf(stderr, "Given gain is below 0. To reduce RX signal, use sound card's mixer (or resistor net)!\n"); - exit(0); + return -EINVAL; } rx_gain = pow(10, gain_db / 20.0); - *skip_args += 2; break; case 'e': echo_test = 1; - *skip_args += 1; break; case 'x': use_mncc_cross = 1; - *skip_args += 1; break; case 'm': use_mncc_sock = 1; - *skip_args += 1; break; case OPT_MNCC_NAME: - mncc_name = strdup(optarg); - *skip_args += 2; + mncc_name = strdup(argv[argi]); break; case 'c': - call_audiodev = strdup(optarg); - *skip_args += 2; + call_audiodev = strdup(argv[argi]); break; case OPT_CALL_SAMPLERATE: - call_samplerate = atoi(optarg); - *skip_args += 2; + call_samplerate = atoi(argv[argi]); break; case 't': - send_patterns = atoi(optarg); - *skip_args += 2; + send_patterns = atoi(argv[argi]); break; case 'l': - loopback = atoi(optarg); - *skip_args += 2; + loopback = atoi(argv[argi]); break; case 'r': - rt_prio = atoi(optarg); - *skip_args += 2; + rt_prio = atoi(argv[argi]); break; case OPT_WRITE_RX_WAVE: - write_rx_wave = strdup(optarg); - *skip_args += 2; + write_rx_wave = strdup(argv[argi]); break; case OPT_WRITE_TX_WAVE: - write_tx_wave = strdup(optarg); - *skip_args += 2; + write_tx_wave = strdup(argv[argi]); break; case OPT_READ_RX_WAVE: - read_rx_wave = strdup(optarg); - *skip_args += 2; + read_rx_wave = strdup(argv[argi]); break; case OPT_READ_TX_WAVE: - read_tx_wave = strdup(optarg); - *skip_args += 2; + read_tx_wave = strdup(argv[argi]); break; +#ifdef HAVE_SDR + case OPT_LIMESDR: + { + char *argv_lime[] = { argv[0], + "--sdr-soapy", + "--sdr-rx-antenna", "LNAL", + "--sdr-rx-gain", "30", + "--sdr-tx-gain", "30", + "--sdr-samplerate", "5000000", + "--sdr-bandwidth", "15000000", + "-s", "200000", + }; + int argc_lime = sizeof(argv_lime) / sizeof (*argv_lime); + return options_command_line(argc_lime, argv_lime, main_mobile_handle_options); + } +#endif default: #ifdef HAVE_SDR - rc = sdr_config_opt_switch(c, skip_args); - if (rc < 0) - exit (0); - + return sdr_config_handle_options(short_option, argi, argv); +#else + return -EINVAL; #endif - break; } + + return 1; } /* global variable to quit main loop */ diff --git a/src/libmobile/main_mobile.h b/src/libmobile/main_mobile.h index e958f2c..4d5dffc 100644 --- a/src/libmobile/main_mobile.h +++ b/src/libmobile/main_mobile.h @@ -22,10 +22,8 @@ extern const char *read_tx_wave; void main_mobile_init(void); void main_mobile_print_help(const char *arg0, const char *ext_usage); void main_mobile_print_hotkeys(void); -extern struct option *long_options; -extern char *optstring; -void main_mobile_set_options(const char *optstring_special, struct option *long_options_special); -void main_mobile_opt_switch(int c, char *arg0, int *skip_args); +void main_mobile_add_options(void); +int main_mobile_handle_options(int short_option, int argi, char **argv); #define OPT_ARRAY(num_name, name, value) \ { \ diff --git a/src/liboptions/Makefile.am b/src/liboptions/Makefile.am new file mode 100644 index 0000000..0d10fa7 --- /dev/null +++ b/src/liboptions/Makefile.am @@ -0,0 +1,7 @@ +AM_CPPFLAGS = -Wall -Wextra -g $(all_includes) + +noinst_LIBRARIES = liboptions.a + +liboptions_a_SOURCES = \ + options.c + diff --git a/src/liboptions/options.c b/src/liboptions/options.c new file mode 100644 index 0000000..e9cc25b --- /dev/null +++ b/src/liboptions/options.c @@ -0,0 +1,221 @@ +/* command line options and config file parsing + * + * (C) 2018 by Andreas Eversberg <jolly@eversberg.eu> + * All Rights Reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include "options.h" +#include "../libdebug/debug.h" + +typedef struct option { + struct option *next; + int short_option; + const char *long_option; + int parameter_count; +} option_t; + +static option_t *option_head = NULL; +static option_t **option_tailp = &option_head; +static int first_option = 1; + +void option_add(int short_option, const char *long_option, int parameter_count) +{ + option_t *option; + + /* check if option already exists */ + for (option = option_head; option; option = option->next) { + if (option->short_option == short_option + || !strcmp(option->long_option, long_option)) { + PDEBUG(DOPTIONS, DEBUG_ERROR, "Option '%s' added twice, please fix!\n", option->long_option); + abort(); + } + } + + option = calloc(1, sizeof(*option)); + if (!option) { + PDEBUG(DOPTIONS, DEBUG_ERROR, "No mem!\n"); + abort(); + } + + option->short_option = short_option; + option->long_option = long_option; + option->parameter_count = parameter_count; + *option_tailp = option; + option_tailp = &(option->next); +} + +// FIXME: support more than one option */ +int options_config_file(const char *config_file, int (*handle_options)(int short_option, int argi, char *argv[])) +{ + static const char *home; + char config[256]; + FILE *fp; + char buffer[256], opt[256], param[256], *p, *argv[1]; + int line; + int rc = 1; + int i; + option_t *option; + + /* open config file */ + home = getenv("HOME"); + if (home == NULL) + return 1; + sprintf(config, "%s/%s", home, config_file + 2); + + fp = fopen(config, "r"); + if (!fp) { + PDEBUG(DOPTIONS, DEBUG_INFO, "Config file '%s' seems not to exist, using command line options only.\n", config); + return 1; + } + + /* parse config file */ + line = 0; + while((fgets(buffer, sizeof(buffer), fp))) { + line++; + /* prevent buffer overflow */ + buffer[sizeof(buffer) - 1] = '\0'; + /* cut away new-line and white spaces */ + while (buffer[0] && buffer[strlen(buffer) - 1] <= ' ') + buffer[strlen(buffer) - 1] = '\0'; + p = buffer; + /* remove white spaces in front of first keyword */ + while (*p > '\0' && *p <= ' ') + p++; + /* ignore '#' lines */ + if (*p == '#') + continue; + /* get option form line */ + i = 0; + while (*p > ' ') + opt[i++] = *p++; + opt[i] = '\0'; + if (opt[0] == '\0') + continue; + /* skip white spaces behind option */ + while (*p > '\0' && *p <= ' ') + p++; + /* get param from line */ + i = 0; + while (*p > ' ') + param[i++] = *p++; + param[i] = '\0'; + /* search option */ + for (option = option_head; option; option = option->next) { + if (opt[0] == option->short_option && opt[1] == '\0') { + PDEBUG(DOPTIONS, DEBUG_INFO, "Config file option '%s' ('%s'), parameter '%s'\n", opt, option->long_option, param); + break; + } + if (!strcmp(opt, option->long_option)) { + PDEBUG(DOPTIONS, DEBUG_INFO, "Config file option '%s', parameter '%s'\n", opt, param); + break; + } + } + if (!option) { + PDEBUG(DOPTIONS, DEBUG_ERROR, "Given option '%s' in config file '%s' at line %d is not a valid option, use '-h' for help!\n", opt, config_file, line); + rc = -EINVAL; + goto done; + } + if (option->parameter_count && !param[0]) { + PDEBUG(DOPTIONS, DEBUG_ERROR, "Given option '%s' in config file '%s' at line %d requires %d parameter(s), use '-h' for help!\n", opt, config_file, line, option->parameter_count); + return -EINVAL; + } + argv[0] = param; + rc = handle_options(option->short_option, 0, argv); + if (rc <= 0) + goto done; + first_option = 0; + } + +done: + /* close config file */ + fclose(fp); + + return rc; +} + +int options_command_line(int argc, char *argv[], int (*handle_options)(int short_option, int argi, char *argv[])) +{ + option_t *option; + int argi, i; + int rc; + + for (argi = 1; argi < argc; argi++) { + if (argv[argi][0] == '-') { + if (argv[argi][1] != '-') { + if (strlen(argv[argi]) != 2) { + PDEBUG(DOPTIONS, DEBUG_ERROR, "Given command line option '%s' exceeds one character, use '-h' for help!\n", argv[argi]); + return -EINVAL; + } + /* -x */ + for (option = option_head; option; option = option->next) { + if (argv[argi][1] == option->short_option) { + if (option->parameter_count && argi + option->parameter_count < argc) + PDEBUG(DOPTIONS, DEBUG_INFO, "Command line option '%s' ('--%s'), parameter '%s'\n", argv[argi], option->long_option, argv[argi + 1]); + else + PDEBUG(DOPTIONS, DEBUG_INFO, "Command line option '%s' ('--%s')\n", argv[argi], option->long_option); + break; + } + } + } else { + /* --xxxxxx */ + for (option = option_head; option; option = option->next) { + if (!strcmp(argv[argi] + 2, option->long_option)) { + if (option->parameter_count && argi + option->parameter_count < argc) + PDEBUG(DOPTIONS, DEBUG_INFO, "Command line option '%s', parameter '%s'\n", argv[argi], argv[argi + 1]); + else + PDEBUG(DOPTIONS, DEBUG_INFO, "Command line option '%s'\n", argv[argi]); + break; + } + } + } + if (!option) { + PDEBUG(DOPTIONS, DEBUG_ERROR, "Given command line option '%s' is not a valid option, use '-h' for help!\n", argv[argi]); + return -EINVAL; + } + if (argi + option->parameter_count >= argc) { + PDEBUG(DOPTIONS, DEBUG_ERROR, "Given command line option '%s' requires %d parameter(s), use '-h' for help!\n", argv[argi], option->parameter_count); + return -EINVAL; + } + rc = handle_options(option->short_option, argi + 1, argv); + if (rc <= 0) + return rc; + first_option = 0; + argi += option->parameter_count; + } else + break; + } + + /* no more options, so we check if there is an option after a non-option parameter */ + for (i = argi; i < argc; i++) { + if (argv[i][0] == '-') { + PDEBUG(DOPTIONS, DEBUG_ERROR, "Given command line option '%s' behind command line parameter '%s' not allowed! Please put all command line options before command line parameter(s).\n", argv[i], argv[argi]); + return -EINVAL; + } + } + + return argi; +} + +int option_is_first(void) +{ + return first_option; +} + diff --git a/src/liboptions/options.h b/src/liboptions/options.h new file mode 100644 index 0000000..6f7e41a --- /dev/null +++ b/src/liboptions/options.h @@ -0,0 +1,6 @@ + +void option_add(int short_option, const char *long_option, int parameter_count); +int options_config_file(const char *config_file, int (*handle_options)(int short_option, int argi, char *argv[])); +int options_command_line(int argc, char *argv[], int (*handle_options)(int short_option, int argi, char *argv[])); +int option_is_first(void); + diff --git a/src/libsdr/sdr.c b/src/libsdr/sdr.c index dec6ab6..0bcdf9a 100644 --- a/src/libsdr/sdr.c +++ b/src/libsdr/sdr.c @@ -25,7 +25,6 @@ enum paging_signal; #include <string.h> #include <errno.h> #include <math.h> -#include <getopt.h> #define __USE_GNU #include <pthread.h> #include <unistd.h> diff --git a/src/libsdr/sdr_config.c b/src/libsdr/sdr_config.c index 8fbb87c..dfbada7 100644 --- a/src/libsdr/sdr_config.c +++ b/src/libsdr/sdr_config.c @@ -23,8 +23,9 @@ enum paging_signal; #include <stdlib.h> #include <string.h> #include <stdint.h> -#include <getopt.h> +#include <errno.h> #include "../libsample/sample.h" +#include "../liboptions/options.h" #include "sdr.h" #include "sdr_config.h" @@ -122,43 +123,40 @@ void sdr_config_print_hotkeys(void) #define OPT_SDR_SWAP_LINKS 1517 #define OPT_SDR_UHD_TX_TS 1518 -struct option sdr_config_long_options[] = { - {"sdr-uhd", 0, 0, OPT_SDR_UHD}, - {"sdr-soapy", 0, 0, OPT_SDR_SOAPY}, - {"sdr-channel", 1, 0, OPT_SDR_CHANNEL}, - {"sdr-device-args", 1, 0, OPT_SDR_DEVICE_ARGS}, - {"sdr-stream-args", 1, 0, OPT_SDR_STREAM_ARGS}, - {"sdr-tune-args", 1, 0, OPT_SDR_TUNE_ARGS}, - {"sdr-samplerate", 1, 0, OPT_SDR_SAMPLERATE}, - {"sdr-lo-offset", 1, 0, OPT_SDR_LO_OFFSET}, - {"sdr-bandwidth", 1, 0, OPT_SDR_BANDWIDTH}, - {"sdr-rx-antenna", 1, 0, OPT_SDR_RX_ANTENNA}, - {"sdr-tx-antenna", 1, 0, OPT_SDR_TX_ANTENNA}, - {"sdr-rx-gain", 1, 0, OPT_SDR_RX_GAIN}, - {"sdr-tx-gain", 1, 0, OPT_SDR_TX_GAIN}, - {"write-iq-rx-wave", 1, 0, OPT_WRITE_IQ_RX_WAVE}, - {"write-iq-tx-wave", 1, 0, OPT_WRITE_IQ_TX_WAVE}, - {"read-iq-rx-wave", 1, 0, OPT_READ_IQ_RX_WAVE}, - {"read-iq-tx-wave", 1, 0, OPT_READ_IQ_TX_WAVE}, - {"sdr-swap-links", 0, 0, OPT_SDR_SWAP_LINKS}, - {"sdr-uhd-tx-timestamps", 0, 0, OPT_SDR_UHD_TX_TS}, - {0, 0, 0, 0} -}; - -const char *sdr_config_optstring = ""; +void sdr_config_add_options(void) +{ + option_add(OPT_SDR_UHD, "sdr-uhd", 0); + option_add(OPT_SDR_SOAPY, "sdr-soapy", 0); + option_add(OPT_SDR_CHANNEL, "sdr-channel", 1); + option_add(OPT_SDR_DEVICE_ARGS, "sdr-device-args", 1); + option_add(OPT_SDR_STREAM_ARGS, "sdr-stream-args", 1); + option_add(OPT_SDR_TUNE_ARGS, "sdr-tune-args", 1); + option_add(OPT_SDR_SAMPLERATE, "sdr-samplerate", 1); + option_add(OPT_SDR_LO_OFFSET, "sdr-lo-offset", 1); + option_add(OPT_SDR_BANDWIDTH, "sdr-bandwidth", 1); + option_add(OPT_SDR_RX_ANTENNA, "sdr-rx-antenna", 1); + option_add(OPT_SDR_TX_ANTENNA, "sdr-tx-antenna", 1); + option_add(OPT_SDR_RX_GAIN, "sdr-rx-gain", 1); + option_add(OPT_SDR_TX_GAIN, "sdr-tx-gain", 1); + option_add(OPT_WRITE_IQ_RX_WAVE, "write-iq-rx-wave", 1); + option_add(OPT_WRITE_IQ_TX_WAVE, "write-iq-tx-wave", 1); + option_add(OPT_READ_IQ_RX_WAVE, "read-iq-rx-wave", 1); + option_add(OPT_READ_IQ_TX_WAVE, "read-iq-tx-wave", 1); + option_add(OPT_SDR_SWAP_LINKS, "sdr-swap-links", 0); + option_add(OPT_SDR_UHD_TX_TS, "sdr-uhd-tx-timestamps", 0); +} -int sdr_config_opt_switch(int c, int *skip_args) +int sdr_config_handle_options(int short_option, int argi, char **argv) { - switch (c) { + switch (short_option) { case OPT_SDR_UHD: #ifdef HAVE_UHD sdr_config->uhd = 1; use_sdr = 1; #else fprintf(stderr, "UHD SDR support not compiled in!\n"); - exit(0); + return -EINVAL; #endif - *skip_args += 1; break; case OPT_SDR_SOAPY: #ifdef HAVE_SOAPY @@ -166,83 +164,65 @@ int sdr_config_opt_switch(int c, int *skip_args) use_sdr = 1; #else fprintf(stderr, "SoapySDR support not compiled in!\n"); - exit(0); + return -EINVAL; #endif - *skip_args += 1; break; case OPT_SDR_CHANNEL: - sdr_config->channel = atoi(optarg); - *skip_args += 2; + sdr_config->channel = atoi(argv[argi]); break; case OPT_SDR_DEVICE_ARGS: - sdr_config->device_args = strdup(optarg); - *skip_args += 2; + sdr_config->device_args = strdup(argv[argi]); break; case OPT_SDR_STREAM_ARGS: - sdr_config->stream_args = strdup(optarg); - *skip_args += 2; + sdr_config->stream_args = strdup(argv[argi]); break; case OPT_SDR_TUNE_ARGS: - sdr_config->tune_args = strdup(optarg); - *skip_args += 2; + sdr_config->tune_args = strdup(argv[argi]); break; case OPT_SDR_SAMPLERATE: - sdr_config->samplerate = atoi(optarg); - *skip_args += 2; + sdr_config->samplerate = atoi(argv[argi]); break; case OPT_SDR_LO_OFFSET: - sdr_config->lo_offset = atof(optarg); - *skip_args += 2; + sdr_config->lo_offset = atof(argv[argi]); break; case OPT_SDR_BANDWIDTH: - sdr_config->bandwidth = atof(optarg); - *skip_args += 2; + sdr_config->bandwidth = atof(argv[argi]); break; case OPT_SDR_RX_ANTENNA: - sdr_config->rx_antenna = strdup(optarg); - *skip_args += 2; + sdr_config->rx_antenna = strdup(argv[argi]); break; case OPT_SDR_TX_ANTENNA: - sdr_config->tx_antenna = strdup(optarg); - *skip_args += 2; + sdr_config->tx_antenna = strdup(argv[argi]); break; case OPT_SDR_RX_GAIN: - sdr_config->rx_gain = atof(optarg); - *skip_args += 2; + sdr_config->rx_gain = atof(argv[argi]); break; case OPT_SDR_TX_GAIN: - sdr_config->tx_gain = atof(optarg); - *skip_args += 2; + sdr_config->tx_gain = atof(argv[argi]); break; case OPT_WRITE_IQ_RX_WAVE: - sdr_config->write_iq_rx_wave = strdup(optarg); - *skip_args += 2; + sdr_config->write_iq_rx_wave = strdup(argv[argi]); break; case OPT_WRITE_IQ_TX_WAVE: - sdr_config->write_iq_tx_wave = strdup(optarg); - *skip_args += 2; + sdr_config->write_iq_tx_wave = strdup(argv[argi]); break; case OPT_READ_IQ_RX_WAVE: - sdr_config->read_iq_rx_wave = strdup(optarg); - *skip_args += 2; + sdr_config->read_iq_rx_wave = strdup(argv[argi]); break; case OPT_READ_IQ_TX_WAVE: - sdr_config->read_iq_tx_wave = strdup(optarg); - *skip_args += 2; + sdr_config->read_iq_tx_wave = strdup(argv[argi]); break; case OPT_SDR_SWAP_LINKS: sdr_config->swap_links = 1; - *skip_args += 1; break; case OPT_SDR_UHD_TX_TS: sdr_config->uhd_tx_timestamps = 1; - *skip_args += 1; break; default: - return -1; + return -EINVAL; } - return 0; + return 1; } int sdr_configure(int samplerate) diff --git a/src/libsdr/sdr_config.h b/src/libsdr/sdr_config.h index 9bfba1f..1feb323 100644 --- a/src/libsdr/sdr_config.h +++ b/src/libsdr/sdr_config.h @@ -26,8 +26,7 @@ extern sdr_config_t *sdr_config; void sdr_config_init(double lo_offset); void sdr_config_print_help(void); void sdr_config_print_hotkeys(void); -extern struct option sdr_config_long_options[]; -extern const char *sdr_config_optstring; -int sdr_config_opt_switch(int c, int *skip_args); +void sdr_config_add_options(void); +int sdr_config_handle_options(int short_option, int argi, char **argv); int sdr_configure(int samplerate); diff --git a/src/nmt/Makefile.am b/src/nmt/Makefile.am index cee6953..5f15ff4 100644 --- a/src/nmt/Makefile.am +++ b/src/nmt/Makefile.am @@ -22,6 +22,7 @@ nmt_SOURCES = \ nmt_LDADD = \ $(COMMON_LA) \ libdmssms.a \ + $(top_builddir)/src/liboptions/liboptions.a \ $(top_builddir)/src/libdebug/libdebug.a \ $(top_builddir)/src/libmobile/libmobile.a \ $(top_builddir)/src/libdisplay/libdisplay.a \ diff --git a/src/nmt/main.c b/src/nmt/main.c index ad8eb56..1d3eb2c 100644 --- a/src/nmt/main.c +++ b/src/nmt/main.c @@ -19,16 +19,17 @@ #include <stdio.h> #include <stdint.h> -#include <getopt.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> +#include <errno.h> #include <sys/types.h> #include <sys/stat.h> #include "../libsample/sample.h" #include "../libmobile/main_mobile.h" #include "../libdebug/debug.h" +#include "../liboptions/options.h" #include "nmt.h" #include "frame.h" #include "dsp.h" @@ -97,141 +98,118 @@ void print_help(const char *arg0) main_mobile_print_hotkeys(); } -static int handle_options(int argc, char **argv) +static void add_options(void) { + main_mobile_add_options(); + option_add('N', "nmt-system", 1); + option_add('T', "channel-type", 1); + option_add('P', "ms-power", 1); + option_add('Y', "traffic-area", 1); + option_add('A', "area-number", 1); + option_add('C', "compandor", 1); + option_add('0', "supervisory", 1); + option_add('S', "smsc-number", 1); + option_add('I', "caller-id", 1); +} + +static int handle_options(int short_option, int argi, char **argv) +{ + int rc; char *p; int super; - int skip_args = 0; - - static struct option long_options_special[] = { - {"nmt-system", 1, 0, 'N'}, - {"channel-type", 1, 0, 'T'}, - {"ms-power", 1, 0, 'P'}, - {"traffic-area", 1, 0, 'Y'}, - {"area-number", 1, 0, 'A'}, - {"compandor", 1, 0, 'C'}, - {"supervisory", 1, 0, '0'}, - {"smsc-number", 1, 0, 'S'}, - {"caller-id", 1, 0, 'I'}, - {0, 0, 0, 0} - }; - - main_mobile_set_options("N:T:P:Y:A:C:0:S:I:", long_options_special); - - while (1) { - int option_index = 0, c, rc; - static int first_option = 1; - - c = getopt_long(argc, argv, optstring, long_options, &option_index); - - if (c == -1) - break; - - switch (c) { - case 'N': - nmt_system = atoi(optarg); - if (nmt_system != 450 && nmt_system != 900) { - fprintf(stderr, "Error, NMT system type '%s' unknown. Please use '-N 450' for NMT-450 or '-N 900' for NMT-900.\n", optarg); - exit(0); - } - if (nmt_system == 900) - ms_power = 0; - if (!first_option) { - fprintf(stderr, "Please specify the NMT system (-N) as first command line option!\n"); - exit(0); - } - skip_args += 2; - break; - case 'T': - if (!strcmp(optarg, "list")) { - nmt_channel_list(nmt_system); - exit(0); - } - rc = nmt_channel_by_short_name(nmt_system, optarg); - if (rc < 0) { - fprintf(stderr, "Error, channel type '%s' unknown. Please use '-t list' to get a list. I suggest to use the default.\n", optarg); - exit(0); - } - OPT_ARRAY(num_chan_type, chan_type, rc) - skip_args += 2; - break; - case 'P': - ms_power = atoi(optarg); - if (ms_power > 3) - ms_power = 3; - if (ms_power < 0) - ms_power = 0; - skip_args += 2; - break; - case 'Y': - - if (!strcmp(optarg, "list")) { - nmt_country_list(nmt_system); - exit(0); - } - /* digits */ - strncpy(country, optarg, sizeof(country) - 1); - country[sizeof(country) - 1] = '\0'; - p = strchr(country, ','); - if (!p) { - fprintf(stderr, "Illegal traffic area '%s', see '-h' for help\n", optarg); - exit(0); - } - *p++ = '\0'; - rc = nmt_country_by_short_name(nmt_system, country); - if (rc < 0) { + + switch (short_option) { + case 'N': + nmt_system = atoi(argv[argi]); + if (nmt_system != 450 && nmt_system != 900) { + fprintf(stderr, "Error, NMT system type '%s' unknown. Please use '-N 450' for NMT-450 or '-N 900' for NMT-900.\n", argv[argi]); + return -EINVAL; + } + if (nmt_system == 900) + ms_power = 0; + if (!option_is_first()) { + fprintf(stderr, "Please specify the NMT system (-N) as first command line option!\n"); + return -EINVAL; + } + break; + case 'T': + if (!strcmp(argv[argi], "list")) { + nmt_channel_list(nmt_system); + return 0; + } + rc = nmt_channel_by_short_name(nmt_system, argv[argi]); + if (rc < 0) { + fprintf(stderr, "Error, channel type '%s' unknown. Please use '-t list' to get a list. I suggest to use the default.\n", argv[argi]); + return -EINVAL; + } + OPT_ARRAY(num_chan_type, chan_type, rc) + break; + case 'P': + ms_power = atoi(argv[argi]); + if (ms_power > 3) + ms_power = 3; + if (ms_power < 0) + ms_power = 0; + break; + case 'Y': + + if (!strcmp(argv[argi], "list")) { + nmt_country_list(nmt_system); + return 0; + } + /* digits */ + strncpy(country, argv[argi], sizeof(country) - 1); + country[sizeof(country) - 1] = '\0'; + p = strchr(country, ','); + if (!p) { + fprintf(stderr, "Illegal traffic area '%s', see '-h' for help\n", argv[argi]); + return -EINVAL; + } + *p++ = '\0'; + rc = nmt_country_by_short_name(nmt_system, country); + if (rc < 0) { error_ta: - fprintf(stderr, "Invalid traffic area '%s', use '-Y list' for a list of valid areas\n", optarg); - exit(0); - } - traffic_area[0] = rc + '0'; - if (p[strlen(p) - 1] != '!') { - rc = nmt_ta_by_short_name(nmt_system, country, atoi(p)); - if (rc < 0) - goto error_ta; - } - nmt_value2digits(atoi(p), traffic_area + 1, 1); - traffic_area[2] = '\0'; - skip_args += 2; - break; - case 'A': - area_no = optarg[0] - '0'; - if (area_no > 4) { - fprintf(stderr, "Area number '%s' out of range, please use 1..4 or 0 for no area\n", optarg); - exit(0); - } - skip_args += 2; - break; - case 'C': - compandor = atoi(optarg); - skip_args += 2; - break; - case '0': - super = atoi(optarg); - if (super < 0 || super > 4) { - fprintf(stderr, "Given supervisory signal is wrong, use '-h' for help!\n"); - exit(0); - } - OPT_ARRAY(num_supervisory, supervisory, super) - skip_args += 2; - break; - case 'S': - smsc_number = strdup(optarg); - skip_args += 2; - break; - case 'I': - send_callerid = atoi(optarg); - skip_args += 2; - break; - default: - main_mobile_opt_switch(c, argv[0], &skip_args); + fprintf(stderr, "Invalid traffic area '%s', use '-Y list' for a list of valid areas\n", argv[argi]); + return -EINVAL; + } + traffic_area[0] = rc + '0'; + if (p[strlen(p) - 1] != '!') { + rc = nmt_ta_by_short_name(nmt_system, country, atoi(p)); + if (rc < 0) + goto error_ta; + } + nmt_value2digits(atoi(p), traffic_area + 1, 1); + traffic_area[2] = '\0'; + break; + case 'A': + area_no = argv[argi][0] - '0'; + if (area_no > 4) { + fprintf(stderr, "Area number '%s' out of range, please use 1..4 or 0 for no area\n", argv[argi]); + return -EINVAL; + } + break; + case 'C': + compandor = atoi(argv[argi]); + break; + case '0': + super = atoi(argv[argi]); + if (super < 0 || super > 4) { + fprintf(stderr, "Given supervisory signal is wrong, use '-h' for help!\n"); + return -EINVAL; } - first_option = 0; + OPT_ARRAY(num_supervisory, supervisory, super) + break; + case 'S': + smsc_number = strdup(argv[argi]); + break; + case 'I': + send_callerid = atoi(argv[argi]); + break; + default: + return main_mobile_handle_options(short_option, argi, argv); } - free(long_options); - - return skip_args; + return 1; } static void myhandler(void) @@ -280,8 +258,7 @@ int submit_sms(const char *sms) int main(int argc, char *argv[]) { - int rc; - int skip_args; + int rc, argi; const char *station_id = ""; int mandatory = 0; int i; @@ -292,12 +269,17 @@ int main(int argc, char *argv[]) main_mobile_init(); - skip_args = handle_options(argc, argv); - argc -= skip_args; - argv += skip_args; + /* handle options / config file */ + add_options(); + rc = options_config_file("~/.osmocom/analog/nmt.conf", handle_options); + if (rc < 0) + return 0; + argi = options_command_line(argc, argv, handle_options); + if (argi <= 0) + return argi; - if (argc > 1) { - station_id = argv[1]; + if (argi < argc) { + station_id = argv[argi]; if (strlen(station_id) != 7) { printf("Given station ID '%s' does not have 7 digits\n", station_id); return 0; @@ -338,7 +320,7 @@ int main(int argc, char *argv[]) num_audiodev = 1; /* use default */ if (num_kanal != num_audiodev) { fprintf(stderr, "You need to specify as many sound devices as you have channels.\n"); - exit(0); + return -EINVAL; } if (num_kanal == 1 && num_chan_type == 0) { num_chan_type = 1; /* use default */ @@ -347,14 +329,14 @@ int main(int argc, char *argv[]) } if (num_kanal != num_chan_type) { fprintf(stderr, "You need to specify as many channel types as you have channels.\n"); - exit(0); + return -EINVAL; } if (num_kanal == 1 && num_supervisory == 0) num_supervisory = 1; /* use default */ if (num_kanal != num_supervisory) { fprintf(stderr, "You need to specify as many supervisory signals as you have channels.\n"); fprintf(stderr, "They shall be different at channels that are close to each other.\n"); - exit(0); + return -EINVAL; } if (num_kanal) { uint8_t super[5] = { 0, 0, 0, 0, 0 }; @@ -378,7 +360,7 @@ int main(int argc, char *argv[]) } if (mandatory) { - print_help(argv[-skip_args]); + print_help(argv[0]); return 0; } diff --git a/src/r2000/Makefile.am b/src/r2000/Makefile.am index 9500a2c..120221b 100644 --- a/src/r2000/Makefile.am +++ b/src/r2000/Makefile.am @@ -12,6 +12,7 @@ radiocom2000_SOURCES = \ main.c radiocom2000_LDADD = \ $(COMMON_LA) \ + $(top_builddir)/src/liboptions/liboptions.a \ $(top_builddir)/src/libdebug/libdebug.a \ $(top_builddir)/src/libmobile/libmobile.a \ $(top_builddir)/src/libdisplay/libdisplay.a \ diff --git a/src/r2000/main.c b/src/r2000/main.c index c772d75..bf4e98f 100644 --- a/src/r2000/main.c +++ b/src/r2000/main.c @@ -19,16 +19,17 @@ #include <stdio.h> #include <stdint.h> -#include <getopt.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> +#include <errno.h> #include <sys/types.h> #include <sys/stat.h> #include "../libsample/sample.h" #include "../libmobile/main_mobile.h" #include "../libdebug/debug.h" +#include "../liboptions/options.h" #include "r2000.h" #include "dsp.h" #include "frame.h" @@ -102,179 +103,154 @@ void print_help(const char *arg0) #define OPT_TAXE 258 #define OPT_DESTRUCTION 259 -static int handle_options(int argc, char **argv) +static void add_options(void) { - int skip_args = 0; - - static struct option long_options_special[] = { - {"band", 1, 0, 'B'}, - {"bande", 1, 0, OPT_BANDE}, - {"channel-type", 1, 0, 'T'}, - {"relais", 1, 0, 'R'}, - {"deport", 1, 0, OPT_DEPORT}, - {"agi", 1, 0, 'I'}, - {"sm-power", 1, 0, 'P'}, - {"taxe", 1, 0, OPT_TAXE}, - {"crins", 1, 0, 'C'}, - {"destruction", 1, 0, OPT_DESTRUCTION}, - {"nconv", 1, 0, 'N'}, - {"recall", 1, 0, 'S'}, - {0, 0, 0, 0} - }; - - main_mobile_set_options("B:T:R:I:P:C:N:S", long_options_special); - - while (1) { - int option_index = 0, c, rc; - - c = getopt_long(argc, argv, optstring, long_options, &option_index); - - if (c == -1) - break; + main_mobile_add_options(); + option_add('B', "band", 1); + option_add(OPT_BANDE, "bande", 1); + option_add('T', "channel-type", 1); + option_add('R', "relais", 1); + option_add(OPT_DEPORT, "deport", 1); + option_add('I', "agi", 1); + option_add('P', "sm-power", 1); + option_add(OPT_TAXE, "taxe", 1); + option_add('C', "crins", 1); + option_add(OPT_DESTRUCTION, "destruction", 1); + option_add('N', "nconv", 1); + option_add('S', "recall", 1); +} - switch (c) { - case 'B': - case OPT_BANDE: - if (!strcmp(optarg, "list")) { - r2000_band_list(); - exit(0); - } - band = atoi(optarg); - skip_args += 2; - break; - case 'T': - if (!strcmp(optarg, "list")) { - r2000_channel_list(); - exit(0); - } - rc = r2000_channel_by_short_name(optarg); - if (rc < 0) { - fprintf(stderr, "Error, channel type '%s' unknown. Please use '-t list' to get a list. I suggest to use the default.\n", optarg); - exit(0); - } - OPT_ARRAY(num_chan_type, chan_type, rc) - skip_args += 2; - break; - case 'R': - relais = atoi(optarg); - if (relais > 511) - relais = 511; - if (relais < 1) - relais = 1; - skip_args += 2; - break; - case OPT_DEPORT: - deport = atoi(optarg); - if (deport > 7) - deport = 7; - if (deport < 0) - deport = 0; - skip_args += 2; - break; - case 'I': - if (!strcmp(optarg, "list")) { - int i; +static int handle_options(int short_option, int argi, char **argv) +{ + int rc; - printf("\nList of possible AGI (inscription permission) codes:\n\n"); - printf("Value\tDescription\n"); - printf("------------------------------------------------------------------------\n"); - for (i = 0; i < 8; i++) - printf("%d\t%s\n", i, param_agi(i)); - exit(0); - } - agi = atoi(optarg); - if (agi < 0 || agi > 7) { - fprintf(stderr, "Error, given inscription permission (AGI) %d is invalid, use 'list' to get a list of values!\n", agi); - exit(0); - } - skip_args += 2; - break; - case 'P': - sm_power = atoi(optarg); - if (sm_power > 1) - sm_power = 1; - if (sm_power < 0) - sm_power = 0; - skip_args += 2; - break; - case OPT_TAXE: - taxe = atoi(optarg); - if (taxe > 1) - taxe = 1; - if (taxe < 0) - taxe = 0; - skip_args += 2; - break; + switch (short_option) { + case 'B': + case OPT_BANDE: + if (!strcmp(argv[argi], "list")) { + r2000_band_list(); + return 0; + } + band = atoi(argv[argi]); + break; + case 'T': + if (!strcmp(argv[argi], "list")) { + r2000_channel_list(); + return 0; + } + rc = r2000_channel_by_short_name(argv[argi]); + if (rc < 0) { + fprintf(stderr, "Error, channel type '%s' unknown. Please use '-t list' to get a list. I suggest to use the default.\n", argv[argi]); + return -EINVAL; + } + OPT_ARRAY(num_chan_type, chan_type, rc) + break; + case 'R': + relais = atoi(argv[argi]); + if (relais > 511) + relais = 511; + if (relais < 1) + relais = 1; + break; + case OPT_DEPORT: + deport = atoi(argv[argi]); + if (deport > 7) + deport = 7; + if (deport < 0) + deport = 0; + break; + case 'I': + if (!strcmp(argv[argi], "list")) { + int i; + + printf("\nList of possible AGI (inscription permission) codes:\n\n"); + printf("Value\tDescription\n"); + printf("------------------------------------------------------------------------\n"); + for (i = 0; i < 8; i++) + printf("%d\t%s\n", i, param_agi(i)); + return 0; + } + agi = atoi(argv[argi]); + if (agi < 0 || agi > 7) { + fprintf(stderr, "Error, given inscription permission (AGI) %d is invalid, use 'list' to get a list of values!\n", agi); + return -EINVAL; + } + break; + case 'P': + sm_power = atoi(argv[argi]); + if (sm_power > 1) + sm_power = 1; + if (sm_power < 0) + sm_power = 0; + break; + case OPT_TAXE: + taxe = atoi(argv[argi]); + if (taxe > 1) + taxe = 1; + if (taxe < 0) + taxe = 0; + break; #if 0 - case 'A': - if (!strcmp(optarg, "list")) { - int i; - - printf("\nList of possible AGA (call permission) codes:\n\n"); - printf("Value\tDescription\n"); - printf("------------------------------------------------------------------------\n"); - for (i = 0; i < 4; i++) - printf("%d\t%s\n", i, param_aga(i)); - exit(0); - } - aga = atoi(optarg); - if (aga < 0 || aga > 3) { - fprintf(stderr, "Error, given call permission (AGA) %d is invalid, use 'list' to get a list of values!\n", aga); - exit(0); - } - skip_args += 2; - break; + case 'A': + if (!strcmp(argv[argi], "list")) { + int i; + + printf("\nList of possible AGA (call permission) codes:\n\n"); + printf("Value\tDescription\n"); + printf("------------------------------------------------------------------------\n"); + for (i = 0; i < 4; i++) + printf("%d\t%s\n", i, param_aga(i)); + return 0; + } + aga = atoi(argv[argi]); + if (aga < 0 || aga > 3) { + fprintf(stderr, "Error, given call permission (AGA) %d is invalid, use 'list' to get a list of values!\n", aga); + return -EINVAL; + } + break; #endif - case 'C': - if (!strcmp(optarg, "list")) { - int i; - - printf("\nList of possible CRINS (inscription response) codes:\n\n"); - printf("Value\tDescription\n"); - printf("------------------------------------------------------------------------\n"); - for (i = 0; i < 8; i++) - printf("%d\t%s\n", i, param_crins(i)); - exit(0); - } - crins = atoi(optarg); - if (crins < 0 || crins > 7) { - fprintf(stderr, "Error, given inscription response (CRINS) %d is invalid, use 'list' to get a list of values!\n", crins); - exit(0); - } - skip_args += 2; - break; - case OPT_DESTRUCTION: - if (!strcmp(optarg, "YES")) { - destruction = 2342; - } - skip_args += 2; - break; - case 'N': - nconv = atoi(optarg); - if (nconv > 7) - nconv = 7; - if (nconv < 0) - nconv = 0; - skip_args += 2; - break; - case 'S': - recall = 1; - skip_args += 1; - break; - default: - main_mobile_opt_switch(c, argv[0], &skip_args); + case 'C': + if (!strcmp(argv[argi], "list")) { + int i; + + printf("\nList of possible CRINS (inscription response) codes:\n\n"); + printf("Value\tDescription\n"); + printf("------------------------------------------------------------------------\n"); + for (i = 0; i < 8; i++) + printf("%d\t%s\n", i, param_crins(i)); + return 0; + } + crins = atoi(argv[argi]); + if (crins < 0 || crins > 7) { + fprintf(stderr, "Error, given inscription response (CRINS) %d is invalid, use 'list' to get a list of values!\n", crins); + return -EINVAL; + } + break; + case OPT_DESTRUCTION: + if (!strcmp(argv[argi], "YES")) { + destruction = 2342; } + break; + case 'N': + nconv = atoi(argv[argi]); + if (nconv > 7) + nconv = 7; + if (nconv < 0) + nconv = 0; + break; + case 'S': + recall = 1; + break; + default: + return main_mobile_handle_options(short_option, argi, argv); } - free(long_options); - - return skip_args; + return 1; } int main(int argc, char *argv[]) { - int rc; - int skip_args; + int rc, argi; const char *station_id = ""; int mandatory = 0; int i; @@ -284,12 +260,17 @@ int main(int argc, char *argv[]) main_mobile_init(); - skip_args = handle_options(argc, argv); - argc -= skip_args; - argv += skip_args; + /* handle options / config file */ + add_options(); + rc = options_config_file("~/.osmocom/analog/radiocom2000.conf", handle_options); + if (rc < 0) + return 0; + argi = options_command_line(argc, argv, handle_options); + if (argi <= 0) + return argi; - if (argc > 1) { - station_id = argv[1]; + if (argi < argc) { + station_id = argv[argi]; if (strlen(station_id) != 9) { printf("Given station ID '%s' does not have 9 digits\n", station_id); return 0; @@ -328,7 +309,7 @@ int main(int argc, char *argv[]) } if (mandatory) { - print_help(argv[-skip_args]); + print_help(argv[0]); return 0; } diff --git a/src/radio/Makefile.am b/src/radio/Makefile.am index 24c65da..a96e3bb 100644 --- a/src/radio/Makefile.am +++ b/src/radio/Makefile.am @@ -10,6 +10,7 @@ osmoradio_SOURCES = \ main.c osmoradio_LDADD = \ $(COMMON_LA) \ + $(top_builddir)/src/liboptions/liboptions.a \ $(top_builddir)/src/libdebug/libdebug.a \ $(top_builddir)/src/libwave/libwave.a \ $(top_builddir)/src/libsample/libsample.a \ diff --git a/src/radio/main.c b/src/radio/main.c index d576ffe..77c415b 100644 --- a/src/radio/main.c +++ b/src/radio/main.c @@ -1,4 +1,4 @@ -/* main function +/* Radio main function * * (C) 2018 by Andreas Eversberg <jolly@eversberg.eu> * All Rights Reserved @@ -24,8 +24,8 @@ enum paging_signal; #include <string.h> #include <unistd.h> #include <stdlib.h> -#include <getopt.h> #include <signal.h> +#include <errno.h> #include <math.h> #include <termios.h> #include <unistd.h> @@ -34,6 +34,7 @@ enum paging_signal; #include "../libsdr/sdr_config.h" #include "../libsdr/sdr.h" #include "../libdisplay/display.h" +#include "../liboptions/options.h" #include "radio.h" #define DEFAULT_LO_OFFSET -1000000.0 @@ -137,170 +138,121 @@ void print_help(const char *arg0) printf(" -S --stereo\n"); printf(" Enables stereo carrier for frequency modulated UHF broadcast.\n"); printf(" It uses the 'Pilot-tone' system.\n"); + printf(" --limesdr\n"); + printf(" Auto-select several required options for LimeSDR\n"); sdr_config_print_help(); } -static struct option long_options_common[] = { - {"help", 0, 0, 'h'}, - {"frequency", 1, 0, 'f'}, - {"samplerate", 1, 0, 's'}, - {"tx-wave-file", 1, 0, 'r'}, - {"rx-wave-file", 1, 0, 'w'}, - {"audio-device", 1, 0, 'a'}, - {"modulation", 1, 0, 'M'}, - {"rx", 0, 0, 'R'}, - {"tx", 0, 0, 'T'}, - {"bandwidth", 1, 0, 'B'}, - {"deviation", 1, 0, 'D'}, - {"modulation-index", 1, 0, 'I'}, - {"emphasis", 1, 0, 'E'}, - {"stereo", 0, 0, 'S'}, - {0, 0, 0, 0} -}; - -static const char *optstring_common = "hf:s:r:w:a:M:RTB:D:I:E:S"; - -struct option *long_options; -char *optstring; - -static void check_duplicate_option(int num, struct option *option) -{ - int i; +#define OPT_LIMESDR 1100 - for (i = 0; i < num; i++) { - if (long_options[i].val == option->val) { - fprintf(stderr, "Duplicate option %d. Please fix!\n", option->val); - abort(); - } - } -} - -void set_options_common(void) +static void add_options(void) { - int i = 0, j; - - long_options = calloc(sizeof(*long_options), 256); - for (j = 0; long_options_common[i].name; i++, j++) { - check_duplicate_option(i, &long_options_common[j]); - memcpy(&long_options[i], &long_options_common[j], sizeof(*long_options)); - } - for (j = 0; sdr_config_long_options[j].name; i++, j++) { - check_duplicate_option(i, &sdr_config_long_options[j]); - memcpy(&long_options[i], &sdr_config_long_options[j], sizeof(*long_options)); - } - - optstring = calloc(256, 2); - strcpy(optstring, optstring_common); - strcat(optstring, sdr_config_optstring); + option_add('h', "help", 0); + option_add('f', "frequency", 1); + option_add('s', "samplerate", 1); + option_add('r', "tx-wave-file", 1); + option_add('w', "rx-wave-file", 1); + option_add('a', "audio-device", 1); + option_add('M', "modulation", 1); + option_add('R', "rx", 0); + option_add('T', "tx", 0); + option_add('B', "bandwidth", 1); + option_add('D', "deviation", 1); + option_add('I', "modulation-index", 1); + option_add('E', "emphasis", 1); + option_add('S', "stereo", 0); + option_add(OPT_LIMESDR, "limesdr", 0); + sdr_config_add_options(); } -static int handle_options(int argc, char **argv) +static int handle_options(int short_option, int argi, char **argv) { - int skip_args = 0; - int rc; - - set_options_common(); - - while (1) { - int option_index = 0, c; - - c = getopt_long(argc, argv, optstring, long_options, &option_index); - - if (c == -1) - break; - - switch (c) { - case 'h': - print_help(argv[0]); - exit(0); - case 'f': - frequency = atof(optarg); - skip_args += 2; - break; - case 's': - samplerate = atof(optarg); - skip_args += 2; - break; - case 'r': - tx_wave_file = strdup(optarg); - skip_args += 2; - break; - case 'w': - rx_wave_file = strdup(optarg); - skip_args += 2; - break; - case 'a': - tx_audiodev = strdup(optarg); - rx_audiodev = strdup(optarg); - skip_args += 2; - break; - case 'M': - if (!strcasecmp(optarg, "fm")) - modulation = MODULATION_FM; - else - if (!strcasecmp(optarg, "am")) - modulation = MODULATION_AM_DSB; - else - if (!strcasecmp(optarg, "usb")) - modulation = MODULATION_AM_USB; - else - if (!strcasecmp(optarg, "lsb")) - modulation = MODULATION_AM_LSB; - else - { - fprintf(stderr, "Invalid modulation option, see help!\n"); - exit(0); - } - skip_args += 2; - break; - case 'R': - rx = 1; - skip_args += 1; - break; - case 'T': - tx = 1; - skip_args += 1; - break; - case 'B': - bandwidth = atof(optarg); - skip_args += 2; - break; - case 'D': - deviation = atof(optarg); - skip_args += 2; - break; - case 'I': - modulation_index = atof(optarg); - if (modulation_index < 0.0 || modulation_index > 1.0) { - fprintf(stderr, "Invalid modulation index, see help!\n"); - exit(0); - } - skip_args += 2; - break; - case 'E': - time_constant_us = atof(optarg); - skip_args += 2; - break; - case 'S': - stereo = 1; - skip_args += 1; - break; - default: - rc = sdr_config_opt_switch(c, &skip_args); - if (rc < 0) - exit(0); - break; + switch (short_option) { + case 'h': + print_help(argv[0]); + return 0; + case 'f': + frequency = atof(argv[argi]); + break; + case 's': + samplerate = atof(argv[argi]); + break; + case 'r': + tx_wave_file = strdup(argv[argi]); + break; + case 'w': + rx_wave_file = strdup(argv[argi]); + break; + case 'a': + tx_audiodev = strdup(argv[argi]); + rx_audiodev = strdup(argv[argi]); + break; + case 'M': + if (!strcasecmp(argv[argi], "fm")) + modulation = MODULATION_FM; + else + if (!strcasecmp(argv[argi], "am")) + modulation = MODULATION_AM_DSB; + else + if (!strcasecmp(argv[argi], "usb")) + modulation = MODULATION_AM_USB; + else + if (!strcasecmp(argv[argi], "lsb")) + modulation = MODULATION_AM_LSB; + else + { + fprintf(stderr, "Invalid modulation option, use '-h' for help!\n"); + return -EINVAL; } + break; + case 'R': + rx = 1; + break; + case 'T': + tx = 1; + break; + case 'B': + bandwidth = atof(argv[argi]); + break; + case 'D': + deviation = atof(argv[argi]); + break; + case 'I': + modulation_index = atof(argv[argi]); + if (modulation_index < 0.0 || modulation_index > 1.0) { + fprintf(stderr, "Invalid modulation index, use '-h' for help!\n"); + return -EINVAL; + } + break; + case 'E': + time_constant_us = atof(argv[argi]); + break; + case 'S': + stereo = 1; + break; + case OPT_LIMESDR: + { + char *argv_lime[] = { argv[0], + "--sdr-soapy", + "--sdr-rx-antenna", "LNAL", + "--sdr-rx-gain", "50", + "--sdr-tx-gain", "50", + "--sdr-samplerate", "5000000", + "--sdr-bandwidth", "15000000", + }; + int argc_lime = sizeof(argv_lime) / sizeof (*argv_lime); + return options_command_line(argc_lime, argv_lime, handle_options); + } + default: + return sdr_config_handle_options(short_option, argi, argv); } - return skip_args; + return 1; } int main(int argc, char *argv[]) { - int skip_args; - int rc; - const char *arg0 = argv[0]; + int rc, argi; radio_t radio; struct termios term, term_orig; int c; @@ -310,13 +262,18 @@ int main(int argc, char *argv[]) sdr_config_init(DEFAULT_LO_OFFSET); - skip_args = handle_options(argc, argv); - argc -= skip_args + 1; - argv += skip_args + 1; + /* handle options / config file */ + add_options(); + rc = options_config_file("~/.osmocom/analog/radio.conf", handle_options); + if (rc < 0) + return 0; + argi = options_command_line(argc, argv, handle_options); + if (argi <= 0) + return argi; if (frequency == 0.0) { printf("No frequency given, I suggest to use 100000000 (100 MHz) and FM\n\n"); - print_help(arg0); + print_help(argv[0]); exit(0); } @@ -324,12 +281,12 @@ int main(int argc, char *argv[]) if (rc < 0) return rc; if (rc == 0) { - fprintf(stderr, "Please select SDR, see help!\n"); + fprintf(stderr, "Please select SDR, use '-h' for help!\n"); exit(0); } if (modulation == MODULATION_NONE) { - fprintf(stderr, "Please select modulation, see help!\n"); + fprintf(stderr, "Please select modulation, use '-h' for help!\n"); exit(0); } @@ -341,18 +298,18 @@ int main(int argc, char *argv[]) } if (stereo && modulation != MODULATION_FM) { - fprintf(stderr, "Stereo works with FM only, see help!\n"); + fprintf(stderr, "Stereo works with FM only, use '-h' for help!\n"); exit(0); } if (!rx && !tx) { - fprintf(stderr, "You need to specify --rx (receiver) and/or --tx (transmitter), see help!\n"); + fprintf(stderr, "You need to specify --rx (receiver) and/or --tx (transmitter), use '-h' for help!\n"); exit(0); } if (stereo && bandwidth != 15000.0) { fprintf(stderr, "Warning: Stereo works with bandwidth of 15 KHz only, using this bandwidth!\n"); } if (stereo && time_constant_us != 75.0 && time_constant_us != 50.0) { - fprintf(stderr, "Stereo works with time constant of 50 uS or 75 uS only, see help!\n"); + fprintf(stderr, "Stereo works with time constant of 50 uS or 75 uS only, use '-h' for help!\n"); exit(0); } diff --git a/src/tacs/Makefile.am b/src/tacs/Makefile.am index ec9b593..5a0a894 100644 --- a/src/tacs/Makefile.am +++ b/src/tacs/Makefile.am @@ -13,6 +13,7 @@ tacs_SOURCES = \ tacs_LDADD = \ $(COMMON_LA) \ ../amps/libamps.a \ + $(top_builddir)/src/liboptions/liboptions.a \ $(top_builddir)/src/libdebug/libdebug.a \ $(top_builddir)/src/libmobile/libmobile.a \ $(top_builddir)/src/libdisplay/libdisplay.a \ diff --git a/src/test/Makefile.am b/src/test/Makefile.am index 5f7a86e..141d88d 100644 --- a/src/test/Makefile.am +++ b/src/test/Makefile.am @@ -57,6 +57,7 @@ test_dms_LDADD = \ $(COMMON_LA) \ $(top_builddir)/src/libdebug/libdebug.a \ $(top_builddir)/src/libmobile/libmobile.a \ + $(top_builddir)/src/liboptions/liboptions.a \ $(top_builddir)/src/libdisplay/libdisplay.a \ $(top_builddir)/src/nmt/libdmssms.a \ $(top_builddir)/src/libjitter/libjitter.a \ @@ -90,6 +91,7 @@ test_sms_LDADD = \ $(COMMON_LA) \ $(top_builddir)/src/libdebug/libdebug.a \ $(top_builddir)/src/libmobile/libmobile.a \ + $(top_builddir)/src/liboptions/liboptions.a \ $(top_builddir)/src/libdisplay/libdisplay.a \ $(top_builddir)/src/nmt/libdmssms.a \ $(top_builddir)/src/libjitter/libjitter.a \ diff --git a/src/test/test_dms.c b/src/test/test_dms.c index 1d3492f..5a29543 100644 --- a/src/test/test_dms.c +++ b/src/test/test_dms.c @@ -43,7 +43,7 @@ void dms_receive(nmt_t *nmt, const uint8_t *data, int length, int eight_bits) { printf("(getting %d digits from DMS layer)\n", length); - assert(!memcmp((const char *)data, check_sequence, length), "Expecting received data to macht"); + assert(!memcmp((const char *)data, check_sequence, length), "Expecting received data to match"); check_sequence += length; check_length = length; diff --git a/src/tv/Makefile.am b/src/tv/Makefile.am index 733541a..d1fdb37 100644 --- a/src/tv/Makefile.am +++ b/src/tv/Makefile.am @@ -14,6 +14,7 @@ osmotv_SOURCES = \ main.c osmotv_LDADD = \ $(COMMON_LA) \ + $(top_builddir)/src/liboptions/liboptions.a \ $(top_builddir)/src/libdebug/libdebug.a \ $(top_builddir)/src/libimage/libimage.a \ $(top_builddir)/src/libfm/libfm.a \ diff --git a/src/tv/main.c b/src/tv/main.c index 01b27f0..7331c1d 100644 --- a/src/tv/main.c +++ b/src/tv/main.c @@ -1,4 +1,4 @@ -/* main function +/* JollyTV main function * * (C) 2017 by Andreas Eversberg <jolly@eversberg.eu> * All Rights Reserved @@ -24,8 +24,8 @@ enum paging_signal; #include <string.h> #include <unistd.h> #include <stdlib.h> -#include <getopt.h> #include <signal.h> +#include <errno.h> #include <math.h> #include "../libsample/sample.h" #include "../libfilter/iir_filter.h" @@ -37,6 +37,7 @@ enum paging_signal; #include "../libsdr/sdr_config.h" #include "../libsdr/sdr.h" #endif +#include "../liboptions/options.h" #include "bas.h" #include "tv_modulate.h" #include "channels.h" @@ -114,149 +115,104 @@ void print_help(const char *arg0) printf(" Give exactly 12 characters to display as Station ID.\n"); printf(" (default = \"%s\")\n", station_id); #ifdef HAVE_SDR + printf(" --limesdr\n"); + printf(" Auto-select several required options for LimeSDR\n"); sdr_config_print_help(); #endif } -static struct option long_options_common[] = { - {"help", 0, 0, 'h'}, - {"frequency", 1, 0, 'f'}, - {"channel", 1, 0, 'c'}, - {"samplerate", 1, 0, 'r'}, - {"wave-file", 1, 0, 'w'}, - {"fbas", 1, 0, 'F'}, - {"tone", 1, 0, 'T'}, - {"circle-radius", 1, 0, 'R'}, - {"color-bar", 1, 0, 'C'}, - {"grid-only", 1, 0, 'G'}, - {"station-id", 1, 0, 'I'}, - {0, 0, 0, 0} -}; - -static const char *optstring_common = "hf:c:r:w:F:T:R:C:G:I:"; - -struct option *long_options; -char *optstring; - -static void check_duplicate_option(int num, struct option *option) -{ - int i; +#define OPT_LIMESDR 1100 - for (i = 0; i < num; i++) { - if (long_options[i].val == option->val) { - fprintf(stderr, "Duplicate option %d. Please fix!\n", option->val); - abort(); - } - } -} - -void set_options_common(void) +static void add_options(void) { - int i = 0, j; - - long_options = calloc(sizeof(*long_options), 256); - for (j = 0; long_options_common[i].name; i++, j++) { - check_duplicate_option(i, &long_options_common[j]); - memcpy(&long_options[i], &long_options_common[j], sizeof(*long_options)); - } -#ifdef HAVE_SDR - for (j = 0; sdr_config_long_options[j].name; i++, j++) { - check_duplicate_option(i, &sdr_config_long_options[j]); - memcpy(&long_options[i], &sdr_config_long_options[j], sizeof(*long_options)); - } -#endif - - optstring = calloc(256, 2); - strcpy(optstring, optstring_common); + option_add('h', "help", 0); + option_add('f', "frequency", 1); + option_add('c', "channel", 1); + option_add('r', "samplerate", 1); + option_add('w', "wave-file", 1); + option_add('F', "fbas", 1); + option_add('T', "tone", 1); + option_add('R', "circle-radius", 1); + option_add('C', "color-bar", 1); + option_add('G', "grid-only", 1); + option_add('I', "station-id", 1); #ifdef HAVE_SDR - strcat(optstring, sdr_config_optstring); + option_add(OPT_LIMESDR, "limesdr", 0); + sdr_config_add_options(); #endif } -static int handle_options(int argc, char **argv) +static int handle_options(int short_option, int argi, char **argv) { - int skip_args = 0; + switch (short_option) { + case 'h': + print_help(argv[0]); + return 0; + case 'f': + frequency = atof(argv[argi]); + break; + case 'c': + if (!strcmp(argv[argi], "list")) { + list_tv_channels(); + return 0; + } + frequency = get_tv_video_frequency(atoi(argv[argi])); + if (frequency == 0.0) { + fprintf(stderr, "Given channel number unknown, use \"-c list\" to get a list.\n"); + return -EINVAL; + } + break; + case 'r': + samplerate = atof(argv[argi]); + break; + case 'w': + wave_file = strdup(argv[argi]); + break; + case 'F': + fbas = atoi(argv[argi]); + break; + case 'T': + tone = atoi(argv[argi]); + break; + case 'R': + circle_radius = atof(argv[argi]); + break; + case 'C': + color_bar = atoi(argv[argi]); + break; + case 'G': + grid_only = atoi(argv[argi]); + break; + case 'I': + station_id = strdup(argv[argi]); + if (strlen(station_id) != 12) { + fprintf(stderr, "Given station ID must be exactly 12 charaters long. (Use spaces to fill it.)\n"); + return -EINVAL; + } + break; #ifdef HAVE_SDR - int rc; + case OPT_LIMESDR: + { + char *argv_lime[] = { argv[0], + "--sdr-soapy", + "--sdr-tx-gain", "50", + "--sdr-lo-offset", "-3000000", + "--sdr-bandwidth", "60000000", + "-r", "13750000", + }; + int argc_lime = sizeof(argv_lime) / sizeof (*argv_lime); + return options_command_line(argc_lime, argv_lime, handle_options); + } #endif - - set_options_common(); - - while (1) { - int option_index = 0, c; - - c = getopt_long(argc, argv, optstring, long_options, &option_index); - - if (c == -1) - break; - - switch (c) { - case 'h': - print_help(argv[0]); - exit(0); - case 'f': - frequency = atof(optarg); - skip_args += 2; - break; - case 'c': - if (!strcmp(optarg, "list")) { - list_tv_channels(); - exit(0); - } - frequency = get_tv_video_frequency(atoi(optarg)); - if (frequency == 0.0) { - fprintf(stderr, "Given channel number unknown, use \"-c list\" to get a list.\n"); - exit(0); - } - skip_args += 2; - break; - case 'r': - samplerate = atof(optarg); - skip_args += 2; - break; - case 'w': - wave_file = strdup(optarg); - skip_args += 2; - break; - case 'F': - fbas = atoi(optarg); - skip_args += 2; - break; - case 'T': - tone = atoi(optarg); - skip_args += 2; - break; - case 'R': - circle_radius = atof(optarg); - skip_args += 2; - break; - case 'C': - color_bar = atoi(optarg); - skip_args += 2; - break; - case 'G': - grid_only = atoi(optarg); - skip_args += 2; - break; - case 'I': - station_id = strdup(optarg); - if (strlen(station_id) != 12) { - fprintf(stderr, "Given station ID must be exactly 12 charaters long. (Use spaces to fill it.)\n"); - exit(0); - } - skip_args += 2; - break; - default: + default: #ifdef HAVE_SDR - rc = sdr_config_opt_switch(c, &skip_args); - if (rc < 0) - exit(0); + return sdr_config_handle_options(short_option, argi, argv); +#else + return -EINVAL; #endif - break; - } } - return skip_args; + return 1; } static void tx_bas(sample_t *sample_bas, __attribute__((__unused__)) sample_t *sample_tone, __attribute__((__unused__)) uint8_t *power_tone, int samples) @@ -448,9 +404,7 @@ error: int main(int argc, char *argv[]) { - int skip_args; - int __attribute__((__unused__)) rc; - const char *arg0 = argv[0]; + int __attribute__((__unused__)) rc, argi; debuglevel = 0; @@ -458,12 +412,17 @@ int main(int argc, char *argv[]) sdr_config_init(DEFAULT_LO_OFFSET); #endif - skip_args = handle_options(argc, argv); - argc -= skip_args + 1; - argv += skip_args + 1; + /* handle options / config file */ + add_options(); + rc = options_config_file("~/.osmocom/analog/osmotv.conf", handle_options); + if (rc < 0) + return 0; + argi = options_command_line(argc, argv, handle_options); + if (argi <= 0) + return argi; if (frequency == 0.0 && !wave_file) { - print_help(arg0); + print_help(argv[0]); exit(0); } @@ -475,22 +434,22 @@ int main(int argc, char *argv[]) #endif } - if (argc < 1) { - fprintf(stderr, "Expecting command, see help!\n"); + if (argi >= argc) { + fprintf(stderr, "Expecting command, use '-h' for help!\n"); exit(0); - } else if (!strcmp(argv[0], "tx-fubk")) { + } else if (!strcmp(argv[argi], "tx-fubk")) { tx_test_picture(BAS_FUBK); - } else if (!strcmp(argv[0], "tx-vcr")) { + } else if (!strcmp(argv[argi], "tx-vcr")) { tx_test_picture(BAS_VCR); - } else if (!strcmp(argv[0], "tx-img")) { - if (argc < 2) { - fprintf(stderr, "Expecting image file, see help!\n"); - exit(0); + } else if (!strcmp(argv[argi], "tx-img")) { + if (argi + 1 >= argc) { + fprintf(stderr, "Expecting image file, use '-h' for help!\n"); + return -EINVAL; } - tx_img(argv[1]); + tx_img(argv[argi + 1]); } else { - fprintf(stderr, "Unknown command '%s', see help!\n", argv[0]); - exit(0); + fprintf(stderr, "Unknown command '%s', use '-h' for help!\n", argv[argi]); + return -EINVAL; } return 0; |