From: Andre Noll Date: Mon, 1 Jul 2013 19:06:48 +0000 (+0200) Subject: Merge branch 't/versioning_improvements' X-Git-Tag: v0.4.13~23 X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=commitdiff_plain;h=e2eebf654cae2fc004cee516a0e165127c0214ca;hp=1afc43be9a585ce634de84764f171e4478ec54be Merge branch 't/versioning_improvements' Cooking for ~2 weeks. 15e99a version.c: Mark version_git() as const. 9bdebf Remove CODENAME macro. be2f6b gui: Use version_single_line(). d60dae Improve man page layout. 5dbc9a afh/play: Include supported audio formats in help output. 042767 Use self-made help to avoid recompilations on version changes. 48f1fc Provide "purpose" texts. aa74a9 Revamp ggo help. 9f7a49 afh_recv: Replace ggo text section by description. b59e0e Make gengetopt descriptions work. 06b3e7 Introduce version.c to limit recompilation on version changes. 75feac Make all commands print git version and improve version string. b01605 Avoid unwanted log messages during startup. 625fdb Don't check return value of command line parsers unnecessarily. 533b03 Build receivers, filters and writers without -h and -V support. b59a3c filter: Wrap lines in the available filter list. 9e56d3 audioc: Print config file errors. e5264d doc: Rewrite udp sender description 5ec373 client: Fix typo in comment. 6d5159 client: Remove duplicate include. --- diff --git a/Makefile.in b/Makefile.in index 698599e5..f82afd7b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -9,6 +9,7 @@ PACKAGE_VERSION := @PACKAGE_VERSION@ PACKAGE_STRING := @PACKAGE_STRING@ install_sh := @install_sh@ executables := @executables@ +ggo_descriptions_declared := @ggo_descriptions_declared@ GENGETOPT := @gengetopt@ HELP2MAN := @help2man@ @@ -18,7 +19,6 @@ build_date := $(shell date) uname_s := $(shell uname -s 2>/dev/null || echo "UNKNOWN_OS") uname_rs := $(shell uname -rs) cc_version := $(shell $(CC) --version | head -n 1) -codename := spectral gravity GIT_VERSION := $(shell ./GIT-VERSION-GEN git-version.h) @@ -67,7 +67,6 @@ CPPFLAGS += -Wchar-subscripts CPPFLAGS += -DBINDIR='"$(BINDIR)"' CPPFLAGS += -DBUILD_DATE='"$(build_date)"' CPPFLAGS += -DUNAME_RS='"$(uname_rs)"' -CPPFLAGS += -DCODENAME='"$(codename)"' CPPFLAGS += -DCC_VERSION='"$(cc_version)"' CPPFLAGS += -Werror-implicit-function-declaration CPPFLAGS += -Wmissing-noreturn diff --git a/NEWS b/NEWS index 8a400d6f..866904e3 100644 --- a/NEWS +++ b/NEWS @@ -9,6 +9,10 @@ - Speed and usability improvements for para_gui. - para_client now restores the fd flags of stdin and stdout on shutdown. + - Improved manual pages. + - Consistent version strings for all executables. + - Reduced depencies on generated files result in fewer + recompilations on changes. - Performance improvements for the compress filter. - Improved downloads web page. diff --git a/afh.c b/afh.c index 4c65d7c1..3881955d 100644 --- a/afh.c +++ b/afh.c @@ -15,6 +15,7 @@ #include "afh.h" #include "error.h" #include "version.h" +#include "ggo.h" static struct afh_args_info conf; INIT_AFH_ERRLISTS; @@ -56,6 +57,17 @@ static void print_chunk_table(struct afh_info *afhi) } } +__noreturn static void print_help_and_die(void) +{ + struct ggo_help h = DEFINE_GGO_HELP(afh); + int d = conf.detailed_help_given; + unsigned flags = d? GPH_STANDARD_FLAGS_DETAILED : GPH_STANDARD_FLAGS; + + ggo_print_help(&h, flags); + printf("supported audio formats: %s\n", AUDIO_FORMAT_HANDLERS); + exit(EXIT_SUCCESS); +} + /** * The main function of para_afh. * @@ -72,8 +84,11 @@ int main(int argc, char **argv) struct afh_info afhi; afh_cmdline_parser(argc, argv, &conf); - HANDLE_VERSION_FLAG("afh", conf); loglevel = get_loglevel_by_name(conf.loglevel_arg); + version_handle_flag("afh", conf.version_given); + if (conf.help_given || conf.detailed_help_given) + print_help_and_die(); + afh_init(); ret = -E_AFH_SYNTAX; if (conf.inputs_num == 0) goto out; diff --git a/afh_recv.c b/afh_recv.c index 774ae88c..5c17dab7 100644 --- a/afh_recv.c +++ b/afh_recv.c @@ -70,10 +70,8 @@ static void *afh_recv_parse_config(int argc, char **argv) { struct afh_recv_args_info *tmp = para_calloc(sizeof(*tmp)); - if (!afh_recv_cmdline_parser(argc, argv, tmp)) - return tmp; - free(tmp); - return NULL; + afh_recv_cmdline_parser(argc, argv, tmp); + return tmp; } static void afh_recv_free_config(void *conf) @@ -256,9 +254,6 @@ void afh_recv_init(struct receiver *r) r->parse_config = afh_recv_parse_config; r->free_config = afh_recv_free_config; r->execute = afh_execute; - r->help = (struct ggo_help) { - .short_help = afh_recv_args_info_help, - .detailed_help = afh_recv_args_info_detailed_help - }; + r->help = (struct ggo_help)DEFINE_GGO_HELP(afh_recv); afh_recv_cmdline_parser_free(&dummy); } diff --git a/alsa_write.c b/alsa_write.c index 88e48b45..a3912c11 100644 --- a/alsa_write.c +++ b/alsa_write.c @@ -361,9 +361,6 @@ void alsa_write_init(struct writer *w) w->post_select = alsa_write_post_select; w->parse_config_or_die = alsa_parse_config_or_die; w->free_config = alsa_free_config; - w->help = (struct ggo_help) { - .short_help = alsa_write_args_info_help, - .detailed_help = alsa_write_args_info_detailed_help - }; + w->help = (struct ggo_help)DEFINE_GGO_HELP(alsa_write); alsa_write_cmdline_parser_free(&dummy); } diff --git a/amp_filter.c b/amp_filter.c index a6bfca25..f62ea8a2 100644 --- a/amp_filter.c +++ b/amp_filter.c @@ -137,8 +137,5 @@ void amp_filter_init(struct filter *f) f->post_select = amp_post_select; f->parse_config = amp_parse_config; f->free_config = amp_free_config; - f->help = (struct ggo_help) { - .short_help = amp_filter_args_info_help, - .detailed_help = amp_filter_args_info_detailed_help - }; + f->help = (struct ggo_help)DEFINE_GGO_HELP(amp_filter); } diff --git a/ao_write.c b/ao_write.c index 9d204ff3..fdae8eea 100644 --- a/ao_write.c +++ b/ao_write.c @@ -371,9 +371,7 @@ void ao_write_init(struct writer *w) w->post_select = aow_post_select; w->parse_config_or_die = aow_parse_config_or_die; w->free_config = aow_free_config; - w->help = (struct ggo_help) { - .short_help = ao_write_args_info_help, - }; + w->help = (struct ggo_help)DEFINE_GGO_HELP(ao_write); /* create detailed help containing all supported drivers/options */ for (i = 0; ao_write_args_info_detailed_help[i]; i++) ; /* nothing */ diff --git a/audioc.c b/audioc.c index be67ebda..0edab366 100644 --- a/audioc.c +++ b/audioc.c @@ -17,6 +17,7 @@ #include "net.h" #include "string.h" #include "fd.h" +#include "ggo.h" #include "version.h" INIT_AUDIOC_ERRLISTS; @@ -210,7 +211,7 @@ __noreturn static void interactive_session(void) .loglevel = loglevel, .completers = audiod_completers, }; - PARA_NOTICE_LOG("\n%s\n", VERSION_TEXT("audioc")); + PARA_NOTICE_LOG("\n%s\n", version_text("audioc")); if (conf.history_file_given) history_file = para_strdup(conf.history_file_arg); else { @@ -279,6 +280,15 @@ static char *configfile_exists(void) return NULL; } +__noreturn static void print_help_and_die(void) +{ + struct ggo_help h = DEFINE_GGO_HELP(audioc); + bool d = conf.detailed_help_given; + + ggo_print_help(&h, d? GPH_STANDARD_FLAGS_DETAILED : GPH_STANDARD_FLAGS); + exit(0); +} + /** * The client program to connect to para_audiod. * @@ -297,29 +307,29 @@ static char *configfile_exists(void) */ int main(int argc, char *argv[]) { - int ret = -E_AUDIOC_SYNTAX, fd; + int ret, fd; char *cf, *buf = NULL, *args = NULL; size_t bufsize; - if (audioc_cmdline_parser(argc, argv, &conf)) - goto out; - HANDLE_VERSION_FLAG("audioc", conf); + audioc_cmdline_parser(argc, argv, &conf); + loglevel = get_loglevel_by_name(conf.loglevel_arg); + version_handle_flag("audioc", conf.version_given); + if (conf.help_given || conf.detailed_help_given) + print_help_and_die(); cf = configfile_exists(); if (cf) { struct audioc_cmdline_parser_params params = { .override = 0, .initialize = 0, .check_required = 0, - .check_ambiguity = 0 + .check_ambiguity = 0, + .print_errors = 1, + }; - ret = audioc_cmdline_parser_config_file(cf, &conf, ¶ms); + audioc_cmdline_parser_config_file(cf, &conf, ¶ms); free(cf); - if (ret) { - fprintf(stderr, "parse error in config file\n"); - exit(EXIT_FAILURE); - } + loglevel = get_loglevel_by_name(conf.loglevel_arg); } - loglevel = get_loglevel_by_name(conf.loglevel_arg); if (conf.socket_given) socket_name = para_strdup(conf.socket_arg); else { diff --git a/audiod.c b/audiod.c index d2c66f2b..8552af6b 100644 --- a/audiod.c +++ b/audiod.c @@ -343,10 +343,11 @@ static void parse_config_or_die(void) PARA_EMERG_LOG("can not read config file %s\n", config_file); goto err; } - if (ret) + if (ret) { audiod_cmdline_parser_config_file(config_file, &conf, ¶ms); + daemon_set_loglevel(conf.loglevel_arg); + } free(config_file); - daemon_set_loglevel(conf.loglevel_arg); return; err: free(config_file); @@ -1300,18 +1301,17 @@ static void set_initial_status(void) __noreturn static void print_help_and_die(void) { - int d = conf.detailed_help_given; - const char **p = d? audiod_args_info_detailed_help - : audiod_args_info_help; - - printf_or_die("%s\n\n", AUDIOD_CMDLINE_PARSER_PACKAGE "-" - AUDIOD_CMDLINE_PARSER_VERSION); - printf_or_die("%s\n\n", audiod_args_info_usage); - for (; *p; p++) - printf_or_die("%s\n", *p); - print_receiver_helps(d); - print_filter_helps(d); - print_writer_helps(d); + struct ggo_help h = DEFINE_GGO_HELP(audiod); + bool d = conf.detailed_help_given; + unsigned flags; + + flags = d? GPH_STANDARD_FLAGS_DETAILED : GPH_STANDARD_FLAGS; + ggo_print_help(&h, flags); + + flags = d? GPH_MODULE_FLAGS_DETAILED : GPH_MODULE_FLAGS; + print_receiver_helps(flags); + print_filter_helps(flags); + print_writer_helps(flags); exit(0); } @@ -1350,9 +1350,9 @@ int main(int argc, char *argv[]) }; valid_fd_012(); - if (audiod_cmdline_parser_ext(argc, argv, &conf, ¶ms)) - exit(EXIT_FAILURE); - HANDLE_VERSION_FLAG("audiod", conf); + audiod_cmdline_parser_ext(argc, argv, &conf, ¶ms); + daemon_set_loglevel(conf.loglevel_arg); + version_handle_flag("audiod", conf.version_given); /* init receivers/filters/writers early to make help work */ recv_init(); filter_init(); diff --git a/client.c b/client.c index 8657b3aa..2d6ef31f 100644 --- a/client.c +++ b/client.c @@ -475,7 +475,7 @@ __noreturn static void interactive_session(void) .completers = completers, }; - PARA_NOTICE_LOG("\n%s\n", VERSION_TEXT("client")); + PARA_NOTICE_LOG("\n%s\n", version_text("client")); if (ct->conf.history_file_given) history_file = para_strdup(ct->conf.history_file_arg); else { diff --git a/client_common.c b/client_common.c index 8ea41922..1ecba730 100644 --- a/client_common.c +++ b/client_common.c @@ -13,7 +13,6 @@ #include "error.h" #include "list.h" #include "sched.h" -#include "client.cmdline.h" #include "crypt.h" #include "net.h" #include "fd.h" @@ -23,16 +22,17 @@ #include "client.h" #include "buffer_tree.h" #include "version.h" +#include "ggo.h" /** The size of the receiving buffer. */ #define CLIENT_BUFSIZE 4000 /** - * Close the connection to para_server and deallocate per-command ressources. + * Close the connection to para_server and deallocate per-command resources. * * \param ct The client task. * - * This frees all ressources of the current command but keeps the configuration + * This frees all resources of the current command but keeps the configuration * in \p ct->conf. * * \sa \ref client_close(). @@ -612,6 +612,15 @@ err_out: return ret; } +__noreturn static void print_help_and_die(struct client_task *ct) +{ + struct ggo_help h = DEFINE_GGO_HELP(client); + bool d = ct->conf.detailed_help_given; + + ggo_print_help(&h, d? GPH_STANDARD_FLAGS_DETAILED : GPH_STANDARD_FLAGS); + exit(0); +} + /** * Parse a client configuration. * @@ -642,7 +651,9 @@ int client_parse_config(int argc, char *argv[], struct client_task **ct_ptr, ret = -E_CLIENT_SYNTAX; if (client_cmdline_parser(argc, argv, &ct->conf)) goto out; - HANDLE_VERSION_FLAG("client", ct->conf); + version_handle_flag("client", ct->conf.version_given); + if (ct->conf.help_given || ct->conf.detailed_help_given) + print_help_and_die(ct); ct->config_file = ct->conf.config_file_given? para_strdup(ct->conf.config_file_arg) : diff --git a/command.c b/command.c index ec822c82..79ca3652 100644 --- a/command.c +++ b/command.c @@ -395,7 +395,8 @@ static int com_si(struct command_context *cc) free(info); } ut = get_server_uptime_str(now); - ret = xasprintf(&msg, "version: " GIT_VERSION "\n" + ret = xasprintf(&msg, + "version: %s\n" "up: %s\nplayed: %u\n" "server_pid: %d\n" "afs_pid: %d\n" @@ -403,6 +404,7 @@ static int com_si(struct command_context *cc) "current loglevel: %s\n" "supported audio formats: %s\n" "%s", + version_git(), ut, mmd->num_played, (int)getppid(), (int)mmd->afs_pid, @@ -431,11 +433,9 @@ static int com_version(struct command_context *cc) if (cc->argc != 1) return -E_COMMAND_SYNTAX; - msg = VERSION_TEXT("server") "built: " BUILD_DATE "\n" UNAME_RS - ", " CC_VERSION "\n"; - len = strlen(msg); + len = xasprintf(&msg, "%s", version_text("server")); if (cc->use_sideband) - return send_sb(&cc->scc, msg, len, SBD_OUTPUT, true); + return send_sb(&cc->scc, msg, len, SBD_OUTPUT, false); return sc_send_bin_buffer(&cc->scc, msg, len); } diff --git a/compress_filter.c b/compress_filter.c index f591123a..0c0200e7 100644 --- a/compress_filter.c +++ b/compress_filter.c @@ -158,8 +158,5 @@ void compress_filter_init(struct filter *f) f->post_select = compress_post_select; f->parse_config = compress_parse_config; f->free_config = compress_free_config; - f->help = (struct ggo_help) { - .short_help = compress_filter_args_info_help, - .detailed_help = compress_filter_args_info_detailed_help - }; + f->help = (struct ggo_help)DEFINE_GGO_HELP(compress_filter); } diff --git a/configure.ac b/configure.ac index 12959c81..3a0a36f6 100644 --- a/configure.ac +++ b/configure.ac @@ -102,7 +102,7 @@ all_errlist_objs="mp3_afh afh_common net string signal time daemon exec send_common ggo udp_recv color fec fecdec_filter prebuffer_filter bitstream imdct check_wav wma_afh wma_common wmadec_filter buffer_tree crypt_common - gui gui_theme sideband afh_recv play" + gui gui_theme sideband afh_recv play version" executables="recv filter audioc write client afh audiod play" @@ -111,49 +111,83 @@ recv_cmdline_objs="add_cmdline(recv http_recv dccp_recv udp_recv afh_recv)" recv_errlist_objs=" http_recv recv_common recv time string net dccp_recv fd sched stdout ggo udp_recv buffer_tree afh_recv afh_common - wma_afh wma_common mp3_afh + wma_afh wma_common mp3_afh version " recv_ldflags="" filter_cmdline_objs="add_cmdline(filter compress_filter amp_filter prebuffer_filter)" filter_errlist_objs="filter_common wav_filter compress_filter filter string - stdin stdout sched fd amp_filter ggo fecdec_filter fec + stdin stdout sched fd amp_filter ggo fecdec_filter fec version prebuffer_filter time bitstream imdct wma_common wmadec_filter buffer_tree" filter_ldflags="-lm" filters=" compress wav amp fecdec wmadec prebuffer" audioc_cmdline_objs="add_cmdline(audioc)" -audioc_errlist_objs="audioc string net fd" +audioc_errlist_objs=" + audioc + string + net + fd + version + ggo +" audioc_ldflags="" audiod_cmdline_objs="add_cmdline(audiod compress_filter http_recv dccp_recv file_write client amp_filter udp_recv prebuffer_filter)" audiod_errlist_objs="audiod signal string daemon stat net crypt_common sideband time grab_client filter_common wav_filter compress_filter amp_filter http_recv dccp_recv recv_common fd sched write_common file_write audiod_command fecdec_filter - client_common ggo udp_recv color fec prebuffer_filter + client_common ggo udp_recv color fec prebuffer_filter version bitstream imdct wma_common wmadec_filter buffer_tree" audiod_ldflags="-lm" audiod_audio_formats="wma" afh_cmdline_objs="add_cmdline(afh)" -afh_errlist_objs="afh string fd mp3_afh afh_common time wma_afh wma_common" +afh_errlist_objs="afh string fd mp3_afh afh_common time wma_afh wma_common + version ggo" afh_ldflags="" write_cmdline_objs="add_cmdline(write file_write)" write_errlist_objs="write write_common file_write time fd string sched stdin - buffer_tree ggo check_wav" + buffer_tree ggo check_wav version" write_ldflags="" writers=" file" default_writer="FILE_WRITE" client_cmdline_objs="add_cmdline(client)" -client_errlist_objs="client net string fd sched stdin stdout time sideband - client_common buffer_tree crypt_common" +client_errlist_objs=" + client + net + string + fd + sched + stdin + stdout + time + sideband + client_common + buffer_tree + crypt_common + version + ggo +" client_ldflags="" gui_cmdline_objs="add_cmdline(gui)" -gui_errlist_objs="exec signal string stat ringbuffer fd gui gui_theme time" +gui_errlist_objs=" + exec + signal + string + stat + ringbuffer + fd + gui + gui_theme + time + version + ggo +" gui_objs="$gui_cmdline_objs $gui_errlist_objs" play_errlist_objs="play fd sched ggo buffer_tree time string net afh_recv afh_common @@ -163,6 +197,7 @@ play_errlist_objs="play fd sched ggo buffer_tree time string net wav_filter compress_filter amp_filter prebuffer_filter fecdec_filter wmadec_filter write_common file_write + version " play_cmdline_objs="add_cmdline(http_recv dccp_recv udp_recv afh_recv compress_filter amp_filter prebuffer_filter file_write play)" play_ldflags="-lm" @@ -290,11 +325,43 @@ else extras="$extras server" executables="$executables server" server_cmdline_objs="add_cmdline(server)" - server_errlist_objs="server afh_common mp3_afh vss command net - string signal time daemon http_send close_on_fork mm - crypt_common ipc dccp_send fd user_list chunk_queue - afs aft mood score attribute blob playlist sched acl - send_common udp_send color fec wma_afh wma_common sideband" + server_errlist_objs=" + server + afh_common + mp3_afh + vss command + net + string + signal + time + daemon + http_send + close_on_fork + mm + crypt_common + ipc dccp_send + fd + user_list + chunk_queue + afs + aft + mood + score + attribute + blob + playlist + sched + acl + send_common + udp_send + color + fec + wma_afh + wma_common + sideband + version + ggo + " all_errlist_objs="$all_errlist_objs server vss command http_send close_on_fork mm ipc dccp_send user_list chunk_queue afs aft mood score attribute blob playlist @@ -462,7 +529,15 @@ AC_MSG_RESULT($have_ucred) if test ${have_ucred} = yes; then AC_DEFINE(HAVE_UCRED, 1, define to 1 you have struct ucred) fi - +########################################################################### gengetopt +echo 'option "z" z "" flag off' | $gengetopt --file-name conftest-ggo && +AC_CHECK_DECL( + [gengetopt_args_info_description], + [ggo_descriptions_declared=yes], + [ggo_descriptions_declared=no], + [#include "conftest-ggo.h"] +) +AC_SUBST(ggo_descriptions_declared) ########################################################################### curses have_curses="yes" OLD_CPPFLAGS="$CPPFLAGS" @@ -957,7 +1032,7 @@ if test -n "$mixers"; then extras="$extras fade" executables="$executables fade" all_errlist_objs="$all_errlist_objs fade" - fade_errlist_objs="$fade_errlist_objs fade exec string fd" + fade_errlist_objs="$fade_errlist_objs fade exec string fd version ggo" fade_cmdline_objs="add_cmdline(fade)" fade_objs="$fade_cmdline_objs $fade_errlist_objs" AC_SUBST(fade_objs, add_dot_o($fade_objs)) diff --git a/dccp_recv.c b/dccp_recv.c index 1f9df189..c751f2f7 100644 --- a/dccp_recv.c +++ b/dccp_recv.c @@ -107,11 +107,10 @@ static void *dccp_recv_parse_config(int argc, char **argv) { struct dccp_recv_args_info *tmp = para_calloc(sizeof(*tmp)); - if (!dccp_recv_cmdline_parser(argc, argv, tmp) && - dccp_recv_ccid_support_check(tmp)) - return tmp; - free(tmp); - return NULL; + dccp_recv_cmdline_parser(argc, argv, tmp); + if (!dccp_recv_ccid_support_check(tmp)) + exit(EXIT_FAILURE); + return tmp; } static void dccp_recv_pre_select(struct sched *s, struct task *t) @@ -181,9 +180,6 @@ void dccp_recv_init(struct receiver *r) r->post_select = dccp_recv_post_select; r->parse_config = dccp_recv_parse_config; r->free_config = dccp_recv_free_config; - r->help = (struct ggo_help) { - .short_help = dccp_recv_args_info_help, - .detailed_help = dccp_recv_args_info_detailed_help - }; + r->help = (struct ggo_help)DEFINE_GGO_HELP(dccp_recv); dccp_recv_cmdline_parser_free(&dummy); } diff --git a/error.h b/error.h index ca172cb4..41a7fe12 100644 --- a/error.h +++ b/error.h @@ -34,6 +34,7 @@ DEFINE_ERRLIST_OBJECT_ENUM; #define STDIN_ERRORS #define WRITE_ERRORS #define CHECK_WAV_ERRORS +#define VERSION_ERRORS extern const char **para_errlist[]; diff --git a/fade.c b/fade.c index fee8f8ca..878b83a1 100644 --- a/fade.c +++ b/fade.c @@ -14,6 +14,7 @@ #include "string.h" #include "mix.h" #include "error.h" +#include "ggo.h" #include "version.h" INIT_FADE_ERRLISTS; @@ -286,15 +287,26 @@ static struct mixer *get_mixer_or_die(void) exit(EXIT_FAILURE); } +__noreturn static void print_help_and_die(void) +{ + struct ggo_help h = DEFINE_GGO_HELP(fade); + bool d = conf.detailed_help_given; + + ggo_print_help(&h, d? GPH_STANDARD_FLAGS_DETAILED : GPH_STANDARD_FLAGS); + exit(0); +} + int main(int argc, char *argv[]) { int ret; struct mixer *m; struct mixer_handle *h = NULL; - if (fade_cmdline_parser(argc, argv, &conf)) - exit(EXIT_FAILURE); - HANDLE_VERSION_FLAG("fade", conf); + fade_cmdline_parser(argc, argv, &conf); + loglevel = get_loglevel_by_name(conf.loglevel_arg); + version_handle_flag("fade", conf.version_given); + if (conf.help_given || conf.detailed_help_given) + print_help_and_die(); ret = configfile_exists(); if (!ret && conf.config_file_given) { PARA_EMERG_LOG("can not read config file %s\n", @@ -311,8 +323,8 @@ int main(int argc, char *argv[]) }; fade_cmdline_parser_config_file(conf.config_file_arg, &conf, ¶ms); + loglevel = get_loglevel_by_name(conf.loglevel_arg); } - loglevel = get_loglevel_by_name(conf.loglevel_arg); init_mixers(); m = get_mixer_or_die(); ret = m->open(conf.mixer_device_arg, &h); diff --git a/file_write.c b/file_write.c index cea21cb3..f7b2b307 100644 --- a/file_write.c +++ b/file_write.c @@ -157,9 +157,6 @@ void file_write_init(struct writer *w) w->parse_config_or_die = file_write_parse_config_or_die; w->free_config = file_write_free_config; w->close = file_write_close; - w->help = (struct ggo_help) { - .short_help = file_write_args_info_help, - .detailed_help = file_write_args_info_detailed_help - }; + w->help = (struct ggo_help)DEFINE_GGO_HELP(file_write); file_write_cmdline_parser_free(&dummy); } diff --git a/filter.c b/filter.c index 40e3779e..3b688573 100644 --- a/filter.c +++ b/filter.c @@ -47,30 +47,22 @@ INIT_STDERR_LOGGING(loglevel); __noreturn static void print_help_and_die(void) { - int d = conf.detailed_help_given; - const char **p = d? filter_args_info_detailed_help - : filter_args_info_help; - - printf_or_die("%s\n\n", FILTER_CMDLINE_PARSER_PACKAGE "-" - FILTER_CMDLINE_PARSER_VERSION); - printf_or_die("%s\n\n", filter_args_info_usage); - for (; *p; p++) - printf_or_die("%s\n", *p); - print_filter_helps(d); + struct ggo_help h = DEFINE_GGO_HELP(filter); + bool d = conf.detailed_help_given; + + ggo_print_help(&h, d? GPH_STANDARD_FLAGS_DETAILED : GPH_STANDARD_FLAGS); + print_filter_helps(d? GPH_MODULE_FLAGS_DETAILED : GPH_MODULE_FLAGS); exit(0); } -static int parse_config(int argc, char *argv[]) +static int parse_config(void) { static char *cf; /* config file */ struct stat statbuf; - if (filter_cmdline_parser(argc, argv, &conf)) - return -E_FILTER_SYNTAX; - HANDLE_VERSION_FLAG("filter", conf); + version_handle_flag("filter", conf.version_given); if (conf.help_given || conf.detailed_help_given) print_help_and_die(); - loglevel = get_loglevel_by_name(conf.loglevel_arg); if (!cf) { char *home = para_homedir(); cf = make_message("%s/.paraslash/filter.conf", home); @@ -84,8 +76,8 @@ static int parse_config(int argc, char *argv[]) .check_ambiguity = 0, .print_errors = 1 }; - if (filter_cmdline_parser_config_file(cf, &conf, ¶ms)) - return -E_FILTER_SYNTAX; + filter_cmdline_parser_config_file(cf, &conf, ¶ms); + loglevel = get_loglevel_by_name(conf.loglevel_arg); } if (!conf.filter_given) return -E_NO_FILTERS; @@ -112,8 +104,10 @@ int main(int argc, char *argv[]) struct btr_node *parent; struct filter_node **fns; + filter_cmdline_parser(argc, argv, &conf); /* aborts on errors */ + loglevel = get_loglevel_by_name(conf.loglevel_arg); filter_init(); - ret = parse_config(argc, argv); + ret = parse_config(); if (ret < 0) goto out; sit->btrn = btr_new_node(&(struct btr_node_description) diff --git a/filter.h b/filter.h index 9c57904e..1cda119f 100644 --- a/filter.h +++ b/filter.h @@ -121,7 +121,7 @@ struct filter { void filter_init(void); int check_filter_arg(char *filter_arg, void **conf); -void print_filter_helps(int detailed); +void print_filter_helps(unsigned flags); void generic_filter_pre_select(struct sched *s, struct task *t); int decoder_execute(const char *cmd, unsigned sample_rate, unsigned channels, char **result); diff --git a/filter_common.c b/filter_common.c index 907912fd..2616c9bd 100644 --- a/filter_common.c +++ b/filter_common.c @@ -101,24 +101,30 @@ int check_filter_arg(char *fa, void **conf) /** * Print help text of each filter to stdout. * - * \param detailed If non-zero, print detailed help. + * \param flags Passed to \ref ggo_print_help(). */ -void print_filter_helps(int detailed) +void print_filter_helps(unsigned flags) { - int i; + int i, num = 0; - printf_or_die("\nAvailable filters: \n\t"); - FOR_EACH_SUPPORTED_FILTER(i) - printf_or_die("%s%s", i? " " : "", filters[i].name); - printf_or_die("\n\n"); + printf_or_die("\nAvailable filters: "); + FOR_EACH_SUPPORTED_FILTER(i) { + if (num > 50) { + printf_or_die("\n "); + num = 0; + } + num += printf_or_die("%s%s", i? " " : "", filters[i].name); + } + printf_or_die("\n"); FOR_EACH_SUPPORTED_FILTER(i) { struct filter *f = filters + i; if (!f->help.short_help) continue; - printf_or_die("Options for %s:\n", f->name); - ggo_print_help(&f->help, detailed); + printf_or_die("\nOptions for %s (%s):", f->name, + f->help.purpose); + ggo_print_help(&f->help, flags); } } diff --git a/ggo.c b/ggo.c index b2e079ab..58d86d07 100644 --- a/ggo.c +++ b/ggo.c @@ -9,13 +9,14 @@ #include "para.h" #include "ggo.h" +#include "version.h" /** * Wrapper for printf() that exits on errors. * * \param fmt Usual format string. */ -__printf_1_2 void printf_or_die(const char *fmt, ...) +__printf_1_2 int printf_or_die(const char *fmt, ...) { va_list argp; int ret; @@ -24,7 +25,7 @@ __printf_1_2 void printf_or_die(const char *fmt, ...) ret = vprintf(fmt, argp); va_end(argp); if (ret >= 0) - return; + return ret; exit(EXIT_FAILURE); } @@ -32,21 +33,25 @@ __printf_1_2 void printf_or_die(const char *fmt, ...) * Print one of the two given help texts. * * \param help contains the help texts. - * \param detailed_help Whether to print the detailed help text. + * \param flags What to print, see \ref ggo_print_help_flags. */ -void ggo_print_help(struct ggo_help *help, int detailed_help) +void ggo_print_help(struct ggo_help *help, unsigned flags) { const char **p; - if (!help) - return; - if (detailed_help) + if (help->purpose && (flags & GPH_PRINT_NAME_PURPOSE)) + printf_or_die("para_%s - %s\n", help->prefix, help->purpose); + if (help->usage && (flags & GPH_PRINT_USAGE)) + printf_or_die("\n%s\n", help->usage); + if (help->description && (flags & GPH_PRINT_DESCRIPTION)) + printf_or_die("\n%s\n", help->description); + printf_or_die("\n"); + if (flags & GPH_DETAILED) p = help->detailed_help; else p = help->short_help; if (!p) return; - p += 3; /* skip -h and -V */ for (; *p; p++) - printf_or_die("\t%s\n", *p); + printf_or_die("%s\n", *p); } diff --git a/ggo.h b/ggo.h index e81b10c6..81565e7c 100644 --- a/ggo.h +++ b/ggo.h @@ -7,14 +7,64 @@ /** \file ggo.h Functions and structures for help text handling. */ /** - * Used by executables that can not use gengetopt's generated help function. + * Information extracted from the .cmdline.h header files. */ struct ggo_help { - /** The lines of the short help text. */ + /** Program or module (receiver, filter, writer) name. */ + const char *prefix; + /** Generated by gengetopt from the options in the .ggo file. */ const char **short_help; - /** The lines of the detailed help text. */ + /** Like \a short_help, plus the \a details section. */ const char **detailed_help; + /** The purpose text as specified in the ggo file. */ + const char *purpose; + /** Generated by gengetopt and exported via the *.cmdline.h file. */ + const char *usage; + /** The description text given in the .ggo file. */ + const char *description; }; -void ggo_print_help(struct ggo_help *help, int detailed_help); -__printf_1_2 void printf_or_die(const char *fmt, ...); +/** + * Control the output of \ref ggo_print_help(). + * + * Any combination of these flags may be passed to ggo_print_help(). + * Note that the list of supported options is always printed. + */ +enum ggo_print_help_flags { + /** Whether to print the short help or the detailed help. */ + GPH_DETAILED = 1 << 0, + /** Print the program or module name and the purpose text. */ + GPH_PRINT_NAME_PURPOSE = 1 << 1, + /** Print the synopsis. */ + GPH_PRINT_USAGE = 1 << 2, + /** Print the description text. */ + GPH_PRINT_DESCRIPTION = 1 << 3, +}; + +/** Used to print the normal help of programs (--help) */ +#define GPH_STANDARD_FLAGS \ + (GPH_PRINT_NAME_PURPOSE | GPH_PRINT_USAGE) + +/** Additional information for --detailed-help. */ +#define GPH_STANDARD_FLAGS_DETAILED \ + (GPH_STANDARD_FLAGS | GPH_DETAILED | GPH_PRINT_DESCRIPTION) + +/** For module help embedded in a program help. */ +#define GPH_MODULE_FLAGS 0 + +/** Modules help with detailed descriptions. */ +#define GPH_MODULE_FLAGS_DETAILED GPH_DETAILED | GPH_PRINT_DESCRIPTION + +/** Make a ggo_help structure using information from the .cmdline.h file. */ +#define DEFINE_GGO_HELP(_prefix) \ + { \ + .prefix = #_prefix, \ + .short_help = _prefix ## _args_info_help, \ + .detailed_help = _prefix ## _args_info_detailed_help, \ + .purpose = _prefix ## _args_info_purpose, \ + .usage = _prefix ## _args_info_usage, \ + .description = _prefix ## _args_info_description, \ + } + +void ggo_print_help(struct ggo_help *help, unsigned flags); +__printf_1_2 int printf_or_die(const char *fmt, ...); diff --git a/gui.c b/gui.c index 0361347e..baab0bd9 100644 --- a/gui.c +++ b/gui.c @@ -23,6 +23,7 @@ #include "list.h" #include "sched.h" #include "signal.h" +#include "ggo.h" #include "version.h" /** define the array of error lists needed by para_gui */ @@ -604,8 +605,8 @@ static void print_welcome(void) { if (loglevel > LL_NOTICE) return; - outputf(COLOR_WELCOME, "Welcome to para_gui " PACKAGE_VERSION - " \"" CODENAME "\". Theme: %s", theme.name); + outputf(COLOR_WELCOME, "Welcome to %s. Theme: %s", + version_single_line("gui"), theme.name); wclrtoeol(bot.win); } @@ -1362,10 +1363,7 @@ static void com_reread_conf(void) } PARA_INFO_LOG("rereading command line options and config file"); gui_cmdline_parser_ext(_argc, _argv, &conf, ¶ms); - if (gui_cmdline_parser_config_file(cf, &conf, ¶ms) != 0) { - PARA_EMERG_LOG("errors in config file"); - finish(EXIT_FAILURE); - } + gui_cmdline_parser_config_file(cf, &conf, ¶ms); PARA_NOTICE_LOG("config file reloaded"); if (check_key_map_args() < 0) finish(EXIT_FAILURE); @@ -1434,8 +1432,7 @@ static void com_enlarge_top_win(void) static void com_version(void) { - print_in_bar(COLOR_MSG, "para_gui " PACKAGE_VERSION " \"" - CODENAME "\""); + print_in_bar(COLOR_MSG, "%s", version_single_line("gui")); } __noreturn static void com_quit(void) @@ -1514,6 +1511,15 @@ static void handle_command(int c) km_keyname(c)); } +__noreturn static void print_help_and_die(void) +{ + struct ggo_help h = DEFINE_GGO_HELP(gui); + bool d = conf.detailed_help_given; + + ggo_print_help(&h, d? GPH_STANDARD_FLAGS_DETAILED : GPH_STANDARD_FLAGS); + exit(0); +} + int main(int argc, char *argv[]) { int ret; @@ -1523,7 +1529,10 @@ int main(int argc, char *argv[]) _argv = argv; gui_cmdline_parser(argc, argv, &conf); /* exits on errors */ - HANDLE_VERSION_FLAG("gui", conf); + loglevel = get_loglevel_by_name(conf.loglevel_arg); + version_handle_flag("gui", conf.version_given); + if (conf.help_given || conf.detailed_help_given) + print_help_and_die(); cf = configfile_exists(); if (!cf && conf.config_file_given) { fprintf(stderr, "can not read config file %s\n", @@ -1538,10 +1547,9 @@ int main(int argc, char *argv[]) .check_ambiguity = 0, .print_errors = 1, }; - if (gui_cmdline_parser_config_file(cf, &conf, ¶ms) != 0) - exit(EXIT_FAILURE); + gui_cmdline_parser_config_file(cf, &conf, ¶ms); + loglevel = get_loglevel_by_name(conf.loglevel_arg); } - loglevel = get_loglevel_by_name(conf.loglevel_arg); if (check_key_map_args() < 0) { fprintf(stderr, "invalid key map\n"); exit(EXIT_FAILURE); diff --git a/http_recv.c b/http_recv.c index f1d85930..7db8ba19 100644 --- a/http_recv.c +++ b/http_recv.c @@ -143,10 +143,8 @@ static void *http_recv_parse_config(int argc, char **argv) { struct http_recv_args_info *tmp = para_calloc(sizeof(*tmp)); - if (!http_recv_cmdline_parser(argc, argv, tmp)) - return tmp; - free(tmp); - return NULL; + http_recv_cmdline_parser(argc, argv, tmp); + return tmp; } static int http_recv_open(struct receiver_node *rn) @@ -195,9 +193,6 @@ void http_recv_init(struct receiver *r) r->post_select = http_recv_post_select; r->parse_config = http_recv_parse_config; r->free_config = http_recv_free_config; - r->help = (struct ggo_help) { - .short_help = http_recv_args_info_help, - .detailed_help = http_recv_args_info_detailed_help - }; + r->help = (struct ggo_help)DEFINE_GGO_HELP(http_recv); http_recv_cmdline_parser_free(&dummy); } diff --git a/m4/gengetopt/afh.m4 b/m4/gengetopt/afh.m4 index beb84696..f8e29fea 100644 --- a/m4/gengetopt/afh.m4 +++ b/m4/gengetopt/afh.m4 @@ -1,14 +1,8 @@ -args "--unamed-opts=audio_file --no-handle-version" +args "--unamed-opts=audio_file --no-handle-version --no-handle-help" -include(header.m4) - -text " -para_afh, the audio format handler tool, is a simple program for analyzing -audio files. It prints technical information about the given audio file to -stdout. -" - +purpose "Print information about audio file(s)." +include(header.m4) include(loglevel.m4) diff --git a/m4/gengetopt/afh_recv.m4 b/m4/gengetopt/afh_recv.m4 index 4995e77f..f4da9d99 100644 --- a/m4/gengetopt/afh_recv.m4 +++ b/m4/gengetopt/afh_recv.m4 @@ -1,6 +1,8 @@ -include(header.m4) - -text " +args "--no-version --no-help" + +purpose "Make an audio stream from a local file." + +description " The afh (audio format handler) receiver can be used to write selected parts of the given audio file without decoding the data. @@ -8,9 +10,10 @@ text " The selected parts of the content of the audio file are passed to the child nodes of the buffer tree. Only complete chunks with respect of the underlying audio format are passed. - " +include(header.m4) + option "filename" f #~~~~~~~~~~~~~~~~~~ "file to open" diff --git a/m4/gengetopt/alsa_write.m4 b/m4/gengetopt/alsa_write.m4 index d0cd4071..04b4963d 100644 --- a/m4/gengetopt/alsa_write.m4 +++ b/m4/gengetopt/alsa_write.m4 @@ -1,3 +1,7 @@ +args "--no-version --no-help" + +purpose "Native ALSA output plugin." + include(header.m4) diff --git a/m4/gengetopt/amp_filter.m4 b/m4/gengetopt/amp_filter.m4 index 865df3ac..2d4d4ce6 100644 --- a/m4/gengetopt/amp_filter.m4 +++ b/m4/gengetopt/amp_filter.m4 @@ -1,3 +1,7 @@ +args "--no-version --no-help" + +purpose "Amplify the decoded audio stream." + option "amp" a #~~~~~~~~~~~~~ "amplification value" diff --git a/m4/gengetopt/ao_write.m4 b/m4/gengetopt/ao_write.m4 index baccc57f..ccee4ee6 100644 --- a/m4/gengetopt/ao_write.m4 +++ b/m4/gengetopt/ao_write.m4 @@ -1,3 +1,7 @@ +args "--no-version --no-help" + +purpose "Output plugin for libao." + include(header.m4) diff --git a/m4/gengetopt/audioc.m4 b/m4/gengetopt/audioc.m4 index 736d7072..36520bfa 100644 --- a/m4/gengetopt/audioc.m4 +++ b/m4/gengetopt/audioc.m4 @@ -1,4 +1,6 @@ -args "--unamed-opts=command --conf-parser --no-handle-version" +args "--unamed-opts=command --conf-parser --no-handle-version --no-handle-help" + +purpose "Communicate with para_audiod through a local socket." include(header.m4) diff --git a/m4/gengetopt/audiod.m4 b/m4/gengetopt/audiod.m4 index 5522a56d..7bae3435 100644 --- a/m4/gengetopt/audiod.m4 +++ b/m4/gengetopt/audiod.m4 @@ -1,5 +1,7 @@ args "--no-handle-help --no-handle-version --conf-parser" +purpose "Connect to para_server, receive, decode and play audio streams." + include(header.m4) define(CURRENT_PROGRAM,para_audiod) define(DEFAULT_CONFIG_FILE,~/.paraslash/audiod.conf) diff --git a/m4/gengetopt/client.m4 b/m4/gengetopt/client.m4 index 23f7c1e6..f0bbc0bd 100644 --- a/m4/gengetopt/client.m4 +++ b/m4/gengetopt/client.m4 @@ -1,4 +1,6 @@ -args "--unamed-opts=command --no-handle-error --conf-parser --no-handle-version" +args "--unamed-opts=command --no-handle-error --conf-parser --no-handle-version --no-handle-help" + +purpose "Communicate with para_server through the paraslash control port." include(header.m4) define(CURRENT_PROGRAM,para_client) diff --git a/m4/gengetopt/compress_filter.m4 b/m4/gengetopt/compress_filter.m4 index 74dcbc03..8c701a03 100644 --- a/m4/gengetopt/compress_filter.m4 +++ b/m4/gengetopt/compress_filter.m4 @@ -1,3 +1,7 @@ +args "--no-version --no-help" + +purpose "Dynamically adjust the volume of an audio stream." + option "blocksize" b #~~~~~~~~~~~~~~~~~~~ "adjust block size" diff --git a/m4/gengetopt/dccp_recv.m4 b/m4/gengetopt/dccp_recv.m4 index 80d31233..f8191fe0 100644 --- a/m4/gengetopt/dccp_recv.m4 +++ b/m4/gengetopt/dccp_recv.m4 @@ -1,3 +1,7 @@ +args "--no-version --no-help" + +purpose "Receive a DCCP audio stream." + option "host" i "ip or host" string default="localhost" diff --git a/m4/gengetopt/fade.m4 b/m4/gengetopt/fade.m4 index da7a27e2..7c731c2b 100644 --- a/m4/gengetopt/fade.m4 +++ b/m4/gengetopt/fade.m4 @@ -1,4 +1,6 @@ -args "--conf-parser --no-handle-version" +args "--conf-parser --no-handle-version --no-handle-help" + +purpose "An alarm clock and volume-fader for OSS and ALSA." include(header.m4) define(CURRENT_PROGRAM,para_fade) diff --git a/m4/gengetopt/file_write.m4 b/m4/gengetopt/file_write.m4 index 56c44f7a..045b8657 100644 --- a/m4/gengetopt/file_write.m4 +++ b/m4/gengetopt/file_write.m4 @@ -1,3 +1,7 @@ +args "--no-version --no-help" + +purpose "Output plugin that writes to a local file." + option "filename" f #~~~~~~~~~~~~~~~~~~ "specify output file name" diff --git a/m4/gengetopt/filter.m4 b/m4/gengetopt/filter.m4 index c7337beb..baf6ecdb 100644 --- a/m4/gengetopt/filter.m4 +++ b/m4/gengetopt/filter.m4 @@ -1,5 +1,7 @@ args "--no-handle-help --no-handle-version --conf-parser" +purpose "Decode or process audio data from STDIN to STDOUT." + include(header.m4) include(loglevel.m4) diff --git a/m4/gengetopt/gui.m4 b/m4/gengetopt/gui.m4 index bafd325b..1f5cf6e4 100644 --- a/m4/gengetopt/gui.m4 +++ b/m4/gengetopt/gui.m4 @@ -1,4 +1,6 @@ -args "--conf-parser --no-handle-version" +args "--conf-parser --no-handle-version --no-handle-help" + +purpose "Show para_audiod status in a curses window." include(header.m4) define(CURRENT_PROGRAM,para_gui) diff --git a/m4/gengetopt/http_recv.m4 b/m4/gengetopt/http_recv.m4 index 14ae99ab..b8ece39d 100644 --- a/m4/gengetopt/http_recv.m4 +++ b/m4/gengetopt/http_recv.m4 @@ -1,3 +1,7 @@ +args "--no-version --no-help" + +purpose "Receive an HTTP audio stream." + include(header.m4) diff --git a/m4/gengetopt/makefile b/m4/gengetopt/makefile index 05be1379..548a3d5d 100644 --- a/m4/gengetopt/makefile +++ b/m4/gengetopt/makefile @@ -1,6 +1,6 @@ define ggo_opts --output-dir=$(cmdline_dir) \ - --set-version="$(PACKAGE_VERSION)" \ + --set-version="$(GIT_VERSION) ($(codename))" \ --arg-struct-name=$(*F)_args_info \ --file-name=$(*F).cmdline \ --func-name=$(*F)_cmdline_parser \ @@ -12,6 +12,9 @@ endef $(cmdline_dir)/%.cmdline.h $(cmdline_dir)/%.cmdline.c: $(ggo_dir)/%.ggo | $(cmdline_dir) @[ -z "$(Q)" ] || echo 'GGO $<' $(Q) $(GENGETOPT) $(ggo_opts) < $< +ifeq ($(ggo_descriptions_declared),no) + echo 'extern const char *$(*F)_args_info_description;' >> $(cmdline_dir)/$(*F).cmdline.h +endif $(ggo_dir)/server.ggo $(ggo_dir)/audiod.ggo: \ $(m4_ggo_dir)/loglevel.m4 $(m4_ggo_dir)/color.m4 \ diff --git a/m4/gengetopt/mp3dec_filter.m4 b/m4/gengetopt/mp3dec_filter.m4 index c02f1583..a6425b3e 100644 --- a/m4/gengetopt/mp3dec_filter.m4 +++ b/m4/gengetopt/mp3dec_filter.m4 @@ -1,3 +1,7 @@ +args "--no-version --no-help" + +purpose "Decode an mp3 stream." + include(header.m4) diff --git a/m4/gengetopt/oss_write.m4 b/m4/gengetopt/oss_write.m4 index 351561cd..352bea5b 100644 --- a/m4/gengetopt/oss_write.m4 +++ b/m4/gengetopt/oss_write.m4 @@ -1,3 +1,7 @@ +args "--no-version --no-help" + +purpose "Output plugin for the Open Sound System." + option "device" d #~~~~~~~~~~~~~~~~ "set PCM device" diff --git a/m4/gengetopt/osx_write.m4 b/m4/gengetopt/osx_write.m4 index bee16d9e..5add6f2e 100644 --- a/m4/gengetopt/osx_write.m4 +++ b/m4/gengetopt/osx_write.m4 @@ -1,3 +1,7 @@ +args "--no-version --no-help" + +purpose "Output plugin for Mac OS coreaudio." + section "osx options" ##################### diff --git a/m4/gengetopt/play.m4 b/m4/gengetopt/play.m4 index 57f954c4..ea41f562 100644 --- a/m4/gengetopt/play.m4 +++ b/m4/gengetopt/play.m4 @@ -1,4 +1,14 @@ args "--unamed-opts=audio_file --no-handle-version --conf-parser --no-handle-help" + +purpose "Command line audio player." + +description "para_play operates either in command mode or in insert +mode. In insert mode it presents a prompt and allows to enter commands +like stop, play, pause etc. In command mode the current audio file +is shown and the program reads single key strokes from stdin. Keys +may be mapped to commands. Whenever a mapped key is pressed, the +associated command is executed." + include(header.m4) define(CURRENT_PROGRAM,para_play) define(DEFAULT_CONFIG_FILE,~/.paraslash/play.conf) diff --git a/m4/gengetopt/prebuffer_filter.m4 b/m4/gengetopt/prebuffer_filter.m4 index 7553e957..9e84dcfc 100644 --- a/m4/gengetopt/prebuffer_filter.m4 +++ b/m4/gengetopt/prebuffer_filter.m4 @@ -1,3 +1,7 @@ +args "--no-version --no-help" + +purpose "Delay processing of an audio stream." + option "duration" d #~~~~~~~~~~~~~~~~~~ "prebuffer time" diff --git a/m4/gengetopt/recv.m4 b/m4/gengetopt/recv.m4 index c7b89fe4..086c9c0a 100644 --- a/m4/gengetopt/recv.m4 +++ b/m4/gengetopt/recv.m4 @@ -1,5 +1,7 @@ args "--no-handle-help --no-handle-version" +purpose "A command line HTTP/DCCP/UDP stream grabber." + include(header.m4) include(loglevel.m4) diff --git a/m4/gengetopt/resample_filter.m4 b/m4/gengetopt/resample_filter.m4 index a4d081ff..4f4af4b0 100644 --- a/m4/gengetopt/resample_filter.m4 +++ b/m4/gengetopt/resample_filter.m4 @@ -1,3 +1,7 @@ +args "--no-version --no-help" + +purpose "Transform raw audio to a different sample rate." + include(header.m4) option "converter" C diff --git a/m4/gengetopt/server.m4 b/m4/gengetopt/server.m4 index 24d344e9..8707554f 100644 --- a/m4/gengetopt/server.m4 +++ b/m4/gengetopt/server.m4 @@ -1,4 +1,6 @@ -args "--conf-parser --no-handle-version" +args "--conf-parser --no-handle-version --no-handle-help" + +purpose "Manage and stream audio files." include(header.m4) define(CURRENT_PROGRAM,para_server) @@ -340,18 +342,19 @@ optional option "udp_header_interval" H #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ "duration for sending header" -int typestr="ms" -default="2000" +int typestr = "ms" +default = "2000" optional -details=" +details = " As the udp sender has no idea about connected clients it sends the audio file header periodically if necessary. This - option is used to specify the duration of the interval between - sending the header. Shorter values decrease the average time - clients have to wait before being able to start playback, - but this also increases the amount network traffic. Note - that this affects only ogg vorbis streams as this is the only - audio format that needs an audio file header. + option specifies the duration between subsequent headers are + sent. Smaller values decrease the average time clients have + to wait before starting playback, larger values decrease + network traffic. + + Note that this affects only ogg/* and wma streams. Other + audio formats, including mp3, don't need an audio file header. " option "udp_ttl" t diff --git a/m4/gengetopt/udp_recv.m4 b/m4/gengetopt/udp_recv.m4 index 4c37eace..48770d97 100644 --- a/m4/gengetopt/udp_recv.m4 +++ b/m4/gengetopt/udp_recv.m4 @@ -1,3 +1,7 @@ +args "--no-version --no-help" + +purpose "Receive an UDP audio stream." + option "host" i "ip or host to receive udp packets from" string default="224.0.1.38" diff --git a/m4/gengetopt/write.m4 b/m4/gengetopt/write.m4 index c022bc8f..8b13f457 100644 --- a/m4/gengetopt/write.m4 +++ b/m4/gengetopt/write.m4 @@ -1,5 +1,7 @@ args "--no-handle-help --no-handle-version" +purpose "Play wav or raw audio." + include(header.m4) include(loglevel.m4) diff --git a/mp3dec_filter.c b/mp3dec_filter.c index 98627504..33c0dfc9 100644 --- a/mp3dec_filter.c +++ b/mp3dec_filter.c @@ -221,8 +221,5 @@ void mp3dec_filter_init(struct filter *f) f->pre_select = generic_filter_pre_select; f->post_select = mp3dec_post_select; f->execute = mp3dec_execute; - f->help = (struct ggo_help) { - .short_help = mp3dec_filter_args_info_help, - .detailed_help = mp3dec_filter_args_info_detailed_help - }; + f->help = (struct ggo_help)DEFINE_GGO_HELP(mp3dec_filter); } diff --git a/oss_write.c b/oss_write.c index cd327243..3c61a445 100644 --- a/oss_write.c +++ b/oss_write.c @@ -235,9 +235,6 @@ void oss_write_init(struct writer *w) w->post_select = oss_post_select; w->parse_config_or_die = oss_parse_config_or_die; w->free_config = oss_free_config; - w->help = (struct ggo_help) { - .short_help = oss_write_args_info_help, - .detailed_help = oss_write_args_info_detailed_help - }; + w->help = (struct ggo_help)DEFINE_GGO_HELP(oss_write); oss_write_cmdline_parser_free(&dummy); } diff --git a/osx_write.c b/osx_write.c index 41b19030..f1e308d8 100644 --- a/osx_write.c +++ b/osx_write.c @@ -366,9 +366,6 @@ void osx_write_init(struct writer *w) w->post_select = osx_write_post_select; w->parse_config_or_die = osx_write_parse_config_or_die; w->free_config = osx_free_config; - w->help = (struct ggo_help) { - .short_help = osx_write_args_info_help, - .detailed_help = osx_write_args_info_detailed_help - }; + w->help = (struct ggo_help)DEFINE_GGO_HELP(osx_write); osx_write_cmdline_parser_free(&dummy); } diff --git a/play.c b/play.c index 02128af0..6eed58ab 100644 --- a/play.c +++ b/play.c @@ -137,30 +137,14 @@ static void check_afh_receiver_or_die(void) exit(EXIT_FAILURE); } -/** Description to be included in the --detailed-help output. */ -#define PP_DESC \ -"para_play is a command line audio player.\n" \ -"\n" \ -"It operates either in command mode or in insert mode. In insert mode it\n" \ -"presents a prompt and allows to enter para_play commands like stop, play, pause\n" \ -"etc. In command mode, the current audio file is shown and the program reads\n" \ -"single key strokes from stdin. Keys may be mapped to para_play commands.\n" \ -"Whenever a mapped key is pressed, the associated command is executed.\n" \ - __noreturn static void print_help_and_die(void) { - int d = conf.detailed_help_given; - const char **p = d? play_args_info_detailed_help - : play_args_info_help; - -// printf_or_die("%s\n\n", PLAY_CMDLINE_PARSER_PACKAGE "-" -// PLAY_CMDLINE_PARSER_VERSION); - - printf_or_die("%s\n\n", play_args_info_usage); - if (d) - printf_or_die("%s\n", PP_DESC); - for (; *p; p++) - printf_or_die("%s\n", *p); + struct ggo_help help = DEFINE_GGO_HELP(play); + unsigned flags = conf.detailed_help_given? + GPH_STANDARD_FLAGS_DETAILED : GPH_STANDARD_FLAGS; + + ggo_print_help(&help, flags); + printf("supported audio formats: %s\n", AUDIO_FORMAT_HANDLERS); exit(0); } @@ -176,12 +160,11 @@ static void parse_config_or_die(int argc, char *argv[]) .print_errors = 1 }; - if (play_cmdline_parser_ext(argc, argv, &conf, ¶ms)) - exit(EXIT_FAILURE); - HANDLE_VERSION_FLAG("play", conf); + play_cmdline_parser_ext(argc, argv, &conf, ¶ms); + loglevel = get_loglevel_by_name(conf.loglevel_arg); + version_handle_flag("play", conf.version_given); if (conf.help_given || conf.detailed_help_given) print_help_and_die(); - loglevel = get_loglevel_by_name(conf.loglevel_arg); if (conf.config_file_given) config_file = para_strdup(conf.config_file_arg); else { @@ -198,6 +181,7 @@ static void parse_config_or_die(int argc, char *argv[]) params.initialize = 0; params.check_required = 1; play_cmdline_parser_config_file(config_file, &conf, ¶ms); + loglevel = get_loglevel_by_name(conf.loglevel_arg); } for (i = 0; i < conf.key_map_given; i++) { char *s = strchr(conf.key_map_arg[i] + 1, ':'); @@ -1036,7 +1020,7 @@ static void session_open(__a_unused struct play_task *pt) char *history_file; struct sigaction act; - PARA_NOTICE_LOG("\n%s\n", VERSION_TEXT("play")); + PARA_NOTICE_LOG("\n%s\n", version_text("play")); if (conf.history_file_given) history_file = para_strdup(conf.history_file_arg); else { diff --git a/prebuffer_filter.c b/prebuffer_filter.c index 0759d678..655c981b 100644 --- a/prebuffer_filter.c +++ b/prebuffer_filter.c @@ -123,8 +123,5 @@ void prebuffer_filter_init(struct filter *f) f->free_config = prebuffer_free_config; f->pre_select = prebuffer_pre_select; f->post_select = prebuffer_post_select; - f->help = (struct ggo_help) { - .short_help = prebuffer_filter_args_info_help, - .detailed_help = prebuffer_filter_args_info_detailed_help - }; + f->help = (struct ggo_help)DEFINE_GGO_HELP(prebuffer_filter); } diff --git a/recv.c b/recv.c index 1fb5e25e..7a5549aa 100644 --- a/recv.c +++ b/recv.c @@ -39,28 +39,12 @@ INIT_RECV_ERRLISTS; __noreturn static void print_help_and_die(void) { - int d = conf.detailed_help_given; - const char **p = d? recv_args_info_detailed_help - : recv_args_info_help; - - printf_or_die("%s\n\n", RECV_CMDLINE_PARSER_PACKAGE "-" - RECV_CMDLINE_PARSER_VERSION); - printf_or_die("%s\n\n", recv_args_info_usage); - for (; *p; p++) - printf_or_die("%s\n", *p); - print_receiver_helps(d); - exit(0); -} + struct ggo_help h = DEFINE_GGO_HELP(recv); + bool d = conf.detailed_help_given; -static void *parse_config(int argc, char *argv[], int *receiver_num) -{ - if (recv_cmdline_parser(argc, argv, &conf)) - return NULL; - HANDLE_VERSION_FLAG("recv", conf); - if (conf.help_given || conf.detailed_help_given) - print_help_and_die(); - loglevel = get_loglevel_by_name(conf.loglevel_arg); - return check_receiver_arg(conf.receiver_arg, receiver_num); + ggo_print_help(&h, d? GPH_STANDARD_FLAGS_DETAILED : GPH_STANDARD_FLAGS); + print_receiver_helps(d? GPH_MODULE_FLAGS_DETAILED : GPH_MODULE_FLAGS); + exit(0); } /** @@ -82,16 +66,18 @@ int main(int argc, char *argv[]) struct stdout_task sot; static struct sched s; - s.default_timeout.tv_sec = 1; - s.default_timeout.tv_usec = 0; + recv_cmdline_parser(argc, argv, &conf); + loglevel = get_loglevel_by_name(conf.loglevel_arg); + version_handle_flag("recv", conf.version_given); + recv_init(); + if (conf.help_given || conf.detailed_help_given) + print_help_and_die(); - memset(&sot, 0, sizeof(struct stdout_task)); memset(&rn, 0, sizeof(struct receiver_node)); - recv_init(); - ret = -E_RECV_SYNTAX; - rn.conf = parse_config(argc, argv, &receiver_num); + rn.conf = check_receiver_arg(conf.receiver_arg, &receiver_num); if (!rn.conf) { - PARA_EMERG_LOG("parse failed\n"); + PARA_EMERG_LOG("invalid receiver specifier\n"); + ret = -E_RECV_SYNTAX; goto out; } r = &receivers[receiver_num]; @@ -103,6 +89,7 @@ int main(int argc, char *argv[]) goto out; r_opened = 1; + memset(&sot, 0, sizeof(struct stdout_task)); sot.btrn = btr_new_node(&(struct btr_node_description) EMBRACE(.parent = rn.btrn, .name = "stdout")); stdout_set_defaults(&sot); @@ -113,6 +100,8 @@ int main(int argc, char *argv[]) sprintf(rn.task.status, "%s", r->name); register_task(&s, &rn.task); + s.default_timeout.tv_sec = 1; + s.default_timeout.tv_usec = 0; ret = schedule(&s); out: if (r_opened) diff --git a/recv.h b/recv.h index cc44a602..008af39a 100644 --- a/recv.h +++ b/recv.h @@ -141,7 +141,7 @@ struct receiver { void recv_init(void); void *check_receiver_arg(char *ra, int *receiver_num); -void print_receiver_helps(int detailed); +void print_receiver_helps(unsigned flags); int generic_recv_pre_select(struct sched *s, struct task *t); /** \cond receiver */ diff --git a/recv_common.c b/recv_common.c index f899c301..2ea8a599 100644 --- a/recv_common.c +++ b/recv_common.c @@ -92,22 +92,23 @@ void *check_receiver_arg(char *ra, int *receiver_num) /** * Print out the help texts to all receivers. * - * \param detailed Whether the detailed help should be printed. + * \param flags Passed to \ref ggo_print_help(). */ -void print_receiver_helps(int detailed) +void print_receiver_helps(unsigned flags) { int i; - printf_or_die("\nAvailable receivers: \n\t"); + printf_or_die("\nAvailable receivers: "); FOR_EACH_RECEIVER(i) printf_or_die("%s%s", i? " " : "", receivers[i].name); - printf_or_die("\n\n"); + printf_or_die("\n"); FOR_EACH_RECEIVER(i) { struct receiver *r = receivers + i; if (!r->help.short_help) continue; - printf_or_die("Options for %s:\n", r->name); - ggo_print_help(&r->help, detailed); + printf_or_die("\n%s: %s", r->name, + r->help.purpose); + ggo_print_help(&r->help, flags); } } diff --git a/resample_filter.c b/resample_filter.c index bd8ece91..5ad584de 100644 --- a/resample_filter.c +++ b/resample_filter.c @@ -310,8 +310,5 @@ void resample_filter_init(struct filter *f) f->parse_config = resample_parse_config; f->free_config = resample_free_config; f->execute = resample_execute; - f->help = (struct ggo_help) { - .short_help = resample_filter_args_info_help, - .detailed_help = resample_filter_args_info_detailed_help - }; + f->help = (struct ggo_help)DEFINE_GGO_HELP(resample_filter); } diff --git a/server.c b/server.c index f3d5237f..f26abef5 100644 --- a/server.c +++ b/server.c @@ -91,6 +91,7 @@ #include "signal.h" #include "user_list.h" #include "color.h" +#include "ggo.h" #include "version.h" __printf_2_3 void (*para_log)(int, const char*, ...) = daemon_log; @@ -236,13 +237,13 @@ void parse_config_or_die(int override) .print_errors = !conf.daemon_given }; server_cmdline_parser_config_file(cf, &conf, ¶ms); + daemon_set_loglevel(conf.loglevel_arg); conf.daemon_given = tmp; } if (conf.logfile_given) { daemon_set_logfile(conf.logfile_arg); daemon_open_log_or_die(); } - daemon_set_loglevel(conf.loglevel_arg); init_colors_or_die(); daemon_set_flag(DF_LOG_PID); daemon_set_flag(DF_LOG_LL); @@ -473,6 +474,15 @@ static int init_afs(int argc, char **argv) return afs_server_socket[0]; } +__noreturn static void print_help_and_die(void) +{ + struct ggo_help h = DEFINE_GGO_HELP(server); + bool d = conf.detailed_help_given; + + ggo_print_help(&h, d? GPH_STANDARD_FLAGS_DETAILED : GPH_STANDARD_FLAGS); + exit(0); +} + static void server_init(int argc, char **argv) { struct server_cmdline_parser_params params = { @@ -488,7 +498,10 @@ static void server_init(int argc, char **argv) init_random_seed_or_die(); /* parse command line options */ server_cmdline_parser_ext(argc, argv, &conf, ¶ms); - HANDLE_VERSION_FLAG("server", conf); + daemon_set_loglevel(conf.loglevel_arg); + version_handle_flag("server", conf.version_given); + if (conf.help_given || conf.detailed_help_given) + print_help_and_die(); drop_privileges_or_die(conf.user_arg, conf.group_arg); /* parse config file, open log and set defaults */ parse_config_or_die(0); diff --git a/udp_recv.c b/udp_recv.c index f9c70ec8..436b298c 100644 --- a/udp_recv.c +++ b/udp_recv.c @@ -100,15 +100,9 @@ static void udp_recv_close(struct receiver_node *rn) static void *udp_recv_parse_config(int argc, char **argv) { - int ret; - struct udp_recv_args_info *tmp = - para_calloc(sizeof(struct udp_recv_args_info)); - - ret = udp_recv_cmdline_parser(argc, argv, tmp)? -E_UDP_SYNTAX : 1; - if (ret >= 0) - return tmp; - free(tmp); - return NULL; + struct udp_recv_args_info *tmp = para_calloc(sizeof(*tmp)); + udp_recv_cmdline_parser(argc, argv, tmp); + return tmp; } /* @@ -226,9 +220,6 @@ void udp_recv_init(struct receiver *r) r->post_select = udp_recv_post_select; r->parse_config = udp_recv_parse_config; r->free_config = udp_recv_free_config; - r->help = (struct ggo_help) { - .short_help = udp_recv_args_info_help, - .detailed_help = udp_recv_args_info_detailed_help - }; + r->help = (struct ggo_help)DEFINE_GGO_HELP(udp_recv); udp_recv_cmdline_parser_free(&dummy); } diff --git a/version.c b/version.c new file mode 100644 index 00000000..ff6b7cab --- /dev/null +++ b/version.c @@ -0,0 +1,78 @@ +#include "para.h" + +/** \file version.h Macros for printing the version string. */ + +#include "git-version.h" + +/** + * Get the raw git version string + * + * \return The string generated by the GIT-VERSION-GEN script. It is passed + * as a preprocessor define during compilation. + */ +__a_const const char *version_git(void) +{ + return GIT_VERSION; +} + +/** + * Get the version string for an executable. + * + * \param pfx The program name (without the leading "para_"). + * + * \return A statically allocated string which contains the program name, the + * git version and the codename. It must not be freed by the caller. + */ +const char *version_single_line(const char *pfx) +{ + static char buf[100]; + snprintf(buf, sizeof(buf) - 1, + "para_%s " GIT_VERSION, pfx); + return buf; +} + +/** + * Get the full version text. + * + * \param pfx See \ref version_single_line(). + * + * \return A string containing the same text as returned by \ref + * version_single_line(), augmented by additional build information, a + * copyright text and the email address of the author. + * + * Like \ref version_single_line(), this string is stored in a statically + * allocated buffer and must not be freed. + */ +const char *version_text(const char *pfx) +{ + static char buf[512]; + + snprintf(buf, sizeof(buf) - 1, "%s\n" + "Copyright (C) 2013 Andre Noll\n" + "This is free software with ABSOLUTELY NO WARRANTY." + " See COPYING for details.\n" + "Report bugs to .\n" + "build date: " BUILD_DATE ",\n" + "build system: " UNAME_RS ",\n" + "compiler: " CC_VERSION ".\n", + version_single_line(pfx) + ); + return buf; +} + +/** + * Print the version text and exit successfully. + * + * \param pfx See \ref version_single_line(). + * \param flag Whether --version was given. + * + * If \a flag is false, this function does nothing. Otherwise it prints the + * full version text as returned by \ref version_text() and exits successfully. + */ +void version_handle_flag(const char *pfx, bool flag) +{ + if (!flag) + return; + printf("%s", version_text(pfx)); + exit(EXIT_SUCCESS); +} diff --git a/version.h b/version.h index 3d865211..3dd5ba21 100644 --- a/version.h +++ b/version.h @@ -1,19 +1,6 @@ -/** \file version.h Macros for printing the version string. */ - -#include "git-version.h" - -/** Version text printed by all executables if -V was given. */ -#define VERSION_TEXT(prefix) "para_" prefix " " PACKAGE_VERSION \ - " (" GIT_VERSION ": " CODENAME ")" "\n" \ - "Copyright (C) 2013 Andre Noll\n" \ - "This is free software with ABSOLUTELY NO WARRANTY." \ - " See COPYING for details.\n" \ - "Report bugs to .\n" - -/** Print out \p VERSION_TEXT and exit if version flag was given. */ -#define HANDLE_VERSION_FLAG(_prefix, _args_info_struct) \ - if (_args_info_struct.version_given) { \ - printf("%s", VERSION_TEXT(_prefix)); \ - exit(EXIT_SUCCESS); \ - } +/** \file version.h Functions for printing the version string. */ +const char *version_git(void); +const char *version_single_line(const char *pfx); +const char *version_text(const char *pfx); +void version_handle_flag(const char *pfx, bool flag); diff --git a/write.c b/write.c index 866ea433..6799db41 100644 --- a/write.c +++ b/write.c @@ -35,16 +35,11 @@ INIT_STDERR_LOGGING(loglevel) __noreturn static void print_help_and_die(void) { - int d = conf.detailed_help_given; - const char **p = d? write_args_info_detailed_help - : write_args_info_help; - - printf_or_die("%s\n\n", WRITE_CMDLINE_PARSER_PACKAGE "-" - WRITE_CMDLINE_PARSER_VERSION); - printf_or_die("%s\n\n", write_args_info_usage); - for (; *p; p++) - printf_or_die("%s\n", *p); - print_writer_helps(d); + struct ggo_help h = DEFINE_GGO_HELP(write); + bool d = conf.detailed_help_given; + + ggo_print_help(&h, d? GPH_STANDARD_FLAGS_DETAILED : GPH_STANDARD_FLAGS); + print_writer_helps(d? GPH_MODULE_FLAGS_DETAILED : GPH_MODULE_FLAGS); exit(0); } @@ -107,7 +102,6 @@ static int setup_and_schedule(void) }, }; - loglevel = get_loglevel_by_name(conf.loglevel_arg); sit.btrn = btr_new_node(&(struct btr_node_description) EMBRACE(.name = "stdin")); stdin_set_defaults(&sit); @@ -173,9 +167,10 @@ int main(int argc, char *argv[]) { int ret; - writer_init(); write_cmdline_parser(argc, argv, &conf); - HANDLE_VERSION_FLAG("write", conf); + loglevel = get_loglevel_by_name(conf.loglevel_arg); + writer_init(); + version_handle_flag("write", conf.version_given); if (conf.help_given || conf.detailed_help_given) print_help_and_die(); diff --git a/write_common.c b/write_common.c index 44ccf88a..33ef8be6 100644 --- a/write_common.c +++ b/write_common.c @@ -121,23 +121,24 @@ void register_writer_node(struct writer_node *wn, struct btr_node *parent, /** * Print the help text of all writers to stdout. * - * \param detailed Whether to print the detailed help text. + * \param flags Passed to \ref ggo_print_help(). */ -void print_writer_helps(int detailed) +void print_writer_helps(unsigned flags) { int i; - printf_or_die("\nAvailable writers: \n\t"); + printf_or_die("\nAvailable writers: "); FOR_EACH_WRITER(i) printf_or_die("%s%s", i? " " : "", writer_names[i]); - printf_or_die("\n\n"); + printf_or_die("\n"); FOR_EACH_WRITER(i) { struct writer *w = writers + i; if (!w->help.short_help) continue; - printf_or_die("Options for %s:\n", writer_names[i]); - ggo_print_help(&w->help, detailed); + printf_or_die("\n%s: %s", writer_names[i], + w->help.purpose); + ggo_print_help(&w->help, flags); } } diff --git a/write_common.h b/write_common.h index 8788a4cf..ecad2d18 100644 --- a/write_common.h +++ b/write_common.h @@ -8,7 +8,7 @@ void writer_init(void); void *check_writer_arg_or_die(const char *wa, int *writer_num); -void print_writer_helps(int detailed); +void print_writer_helps(unsigned flags); void register_writer_node(struct writer_node *wn, struct btr_node *parent, struct sched *s); void get_btr_sample_rate(struct btr_node *btrn, int32_t *result);