Merge branch 'refs/heads/t/lopsub'
authorAndre Noll <maan@tuebingen.mpg.de>
Thu, 27 Apr 2017 18:39:32 +0000 (20:39 +0200)
committerAndre Noll <maan@tuebingen.mpg.de>
Thu, 27 Apr 2017 18:47:05 +0000 (20:47 +0200)
The bulk of the changes in this release is the conversion of all
command line parsers from gengetopt to lopsub.

The series also contains a few cleanups that have become possible
due to the switch from gengetopt to lopsub.

The patches towards the end of the series rename para_fade to
para_mixer.

Naturally, the merge conflicted rather heavily against the other
topic branches that have been merged since the lopsub branch was
started. Conflicting files:

Makefile.real afh.c afh_recv.c configure.ac osx_write.c write.c

The resolutions for these conflicts were recorded with git rerere
and have been tested for quite some time.

Cooking for three weeks.

* refs/heads/t/lopsub: (74 commits)
  audioc: Avoid double free in audioc_i9e_line_handler().
  audiod: Avoid uninitialized memory access.
  Simplify mixer setup.
  mixer: Implement non-linear time scale for fading.
  mixer: Allow arbitrary relative time for sleep subcommand.
  Convert para_fade to subcommands, rename it to para_mixer.
  build: Create .dep files only during compilation.
  build: Simplify definition of $m4_lls_deps.
  build: Rename command list variables.
  build: Combine $(CFLAGS) and $(STRICT_CFLAGS).
  build: Let .d files depend only on .c.
  build: Don't create phony targets for dependencies.
  build: Remove duplicate dependency.
  build: Remove cmdline_dir and friends.
  build: Remove some unused variables from Makefile.real.
  build: Remove m4/gengetopt.
  Remove gengetopt and help2man checks from configure.ac.
  Remove man_util.bash.
  Remove ggo.c and ggo.h.
  manual: Do not mention gengetopt and help2man any more.
  ...

18 files changed:
1  2 
INSTALL
Makefile.in
Makefile.real
NEWS.md
aacdec_filter.c
afh.c
afh_recv.c
afs.c
aft.c
audiod.c
client_common.c
command.c
configure.ac
error.h
server.h
vss.c
web/manual.md
wmadec_filter.c

diff --cc INSTALL
Simple merge
diff --cc Makefile.in
@@@ -8,16 -8,10 +8,9 @@@ datarootdir := @datarootdir
  PACKAGE_TARNAME := @PACKAGE_TARNAME@
  PACKAGE_VERSION := @PACKAGE_VERSION@
  
 -INSTALL := @INSTALL@
  M4 := @M4@
- GENGETOPT := @GENGETOPT@
- HELP2MAN := @HELP2MAN@
- ggo_descriptions_declared := @ggo_descriptions_declared@
  
  executables := @executables@
- receivers := @receivers@
- filters := @filters@
- writers := @writers@
  
  recv_objs := @recv_objs@
  filter_objs := @filter_objs@
diff --cc Makefile.real
@@@ -7,8 -7,10 +7,9 @@@ ifeq ("$(origin CC)", "default"
          CC := cc
  endif
  
+ LOGLEVELS := LL_DEBUG,LL_INFO,LL_NOTICE,LL_WARNING,LL_ERROR,LL_CRIT,LL_EMERG
  vardir := /var/paraslash
  mandir := $(datarootdir)/man/man1
 -STRIP := $(CROSS_COMPILE)strip
  MKDIR_P := mkdir -p
  prefixed_executables := $(addprefix para_, $(executables))
  
@@@ -60,15 -76,14 +75,15 @@@ man_pages := $(patsubst %, $(man_dir)/%
  autocrap := config.h.in configure
  tarball_pfx := $(PACKAGE_TARNAME)-$(GIT_VERSION)
  tarball_delete := $(addprefix $(tarball_pfx)/, web .gitignore)
 -tarball := $(tarball_pfx).tar.bz2
 +tarball := $(tarball_pfx).tar.xz
  
 -.PHONY: all clean clean2 distclean maintainer-clean install man tarball
  all: $(prefixed_executables) $(man_pages)
 +.PHONY: all mostlyclean clean distclean maintainer-clean install \
 +      install-strip man dist tarball
 +
  man: $(man_pages)
 -tarball: $(tarball)
  
- include $(m4_ggo_dir)/makefile
+ include $(lls_m4_dir)/makefile
  include $(test_dir)/makefile.test
  ifeq ($(findstring clean, $(MAKECMDGOALS)),)
  -include $(deps)
@@@ -94,25 -100,24 +100,22 @@@ CPPFLAGS += -DLOGLEVELS='$(LOGLEVELS)
  CPPFLAGS += -DUNAME_RS='"$(uname_rs)"'
  CPPFLAGS += -DCC_VERSION='"$(cc_version)"'
  CPPFLAGS += -I/usr/local/include
- CPPFLAGS += -I$(cmdline_dir)
- CPPFLAGS += -I$(cmdlist_dir)
- CFLAGS += -Os
- CFLAGS += -Wuninitialized
- CFLAGS += -Wchar-subscripts
- CFLAGS += -Werror-implicit-function-declaration
- CFLAGS += -Wmissing-noreturn
- CFLAGS += -Wbad-function-cast
- CFLAGS += -fno-strict-aliasing
- STRICT_CFLAGS = $(CFLAGS)
- STRICT_CFLAGS += -g -Wundef -W
+ CPPFLAGS += -I$(lls_suite_dir)
+ CPPFLAGS += $(lopsub_cppflags)
+ STRICT_CFLAGS += -fno-strict-aliasing
+ STRICT_CFLAGS += -g
+ STRICT_CFLAGS += -Os
+ STRICT_CFLAGS += -Wundef -W -Wuninitialized
+ STRICT_CFLAGS += -Wchar-subscripts
+ STRICT_CFLAGS += -Werror-implicit-function-declaration
+ STRICT_CFLAGS += -Wmissing-noreturn
+ STRICT_CFLAGS += -Wbad-function-cast
  STRICT_CFLAGS += -Wredundant-decls
  STRICT_CFLAGS += -Wno-sign-compare -Wno-unknown-pragmas
- STRICT_CFLAGS += -Wformat -Wformat-security
- STRICT_CFLAGS += -Wmissing-format-attribute
  STRICT_CFLAGS += -Wdeclaration-after-statement
+ STRICT_CFLAGS += -Wformat -Wformat-security -Wmissing-format-attribute
  
 -LDFLAGS += $(clock_gettime_ldflags)
 -
  ifeq ($(uname_s),Linux)
        # these cause warnings on *BSD
        CPPFLAGS += -Wunused-macros
@@@ -194,87 -173,75 +171,73 @@@ $(man_dir)/para_%.1: $(lls_suite_dir)/%
  
  $(object_dir)/%.o: %.c | $(object_dir)
  
- $(object_dir)/opus%.o $(dep_dir)/opus%.d: CPPFLAGS += $(opus_cppflags)
- $(object_dir)/gui.o $(object_dir)/gui%.o $(dep_dir)/gui%.d \
+ $(object_dir)/opus%.o: CPPFLAGS += $(opus_cppflags)
+ $(object_dir)/gui.o $(object_dir)/gui%.o \
  : CPPFLAGS += $(curses_cppflags)
- $(object_dir)/spx%.o $(dep_dir)/spx%.d: CPPFLAGS += $(speex_cppflags)
- $(object_dir)/flac%.o $(dep_dir)/flac%.d: CPPFLAGS += $(flac_cppflags)
+ $(object_dir)/spx%.o: CPPFLAGS += $(speex_cppflags)
+ $(object_dir)/flac%.o: CPPFLAGS += $(flac_cppflags)
  
- $(object_dir)/mp3_afh.o $(dep_dir)/mp3_afh.d: CPPFLAGS += $(id3tag_cppflags)
- $(object_dir)/crypt.o $(dep_dir)/crypt.d: CPPFLAGS += $(openssl_cppflags)
- $(object_dir)/gcrypt.o $(dep_dir)/gcrypt.d: CPPFLAGS += $(gcrypt_cppflags)
- $(object_dir)/ao_write.o $(dep_dir)/ao_write.d: CPPFLAGS += $(ao_cppflags)
- $(object_dir)/alsa%.o $(dep_dir)/alsa%.d: CPPFLAGS += $(alsa_cppflags)
+ $(object_dir)/mp3_afh.o: CPPFLAGS += $(id3tag_cppflags)
+ $(object_dir)/crypt.o: CPPFLAGS += $(openssl_cppflags)
+ $(object_dir)/gcrypt.o: CPPFLAGS += $(gcrypt_cppflags)
+ $(object_dir)/ao_write.o: CPPFLAGS += $(ao_cppflags)
 -$(object_dir)/aac_afh.o: CPPFLAGS += $(mp4v2_cppflags)
+ $(object_dir)/alsa%.o: CPPFLAGS += $(alsa_cppflags)
  
- $(object_dir)/interactive.o $(dep_dir)/interactive.d \
+ $(object_dir)/interactive.o \
  : CPPFLAGS += $(readline_cppflags)
  
- $(object_dir)/resample_filter.o $(dep_dir)/resample_filter.d \
+ $(object_dir)/resample_filter.o \
  : CPPFLAGS += $(samplerate_cppflags)
  
- $(object_dir)/oss_write.o $(dep_dir)/oss_write.d \
+ $(object_dir)/oss_write.o \
  : CPPFLAGS += $(oss_cppflags)
  
- $(object_dir)/ao_write.o $(dep_dir)/ao_write.d \
+ $(object_dir)/ao_write.o \
  : CPPFLAGS += $(ao_cppflags) $(pthread_cppflags)
  
- $(object_dir)/mp3dec_filter.o $(dep_dir)/mp3dec_filter.d \
+ $(object_dir)/mp3dec_filter.o \
  : CPPFLAGS += $(mad_cppflags)
  
- $(object_dir)/aacdec_filter.o $(dep_dir)/aacdec_filter.d \
- $(object_dir)/aac_afh.o $(dep_dir)/aac_afh.d \
+ $(object_dir)/aacdec_filter.o \
 -$(object_dir)/aac_common.o \
+ $(object_dir)/aac_afh.o \
  : CPPFLAGS += $(faad_cppflags)
  
- $(object_dir)/ogg_afh.o $(dep_dir)/ogg_afh.d \
- $(object_dir)/oggdec_filter.o $(dep_dir)/oggdec_filter.d \
+ $(object_dir)/ogg_afh.o \
+ $(object_dir)/oggdec_filter.o \
  : CPPFLAGS += $(vorbis_cppflags)
  
- $(object_dir)/spx_common.o $(dep_dir)/spx_common.d \
- $(object_dir)/spxdec_filter.o $(dep_dir)/spxdec_filter.d \
- $(object_dir)/spx_afh.o $(dep_dir)/spx_afh.d \
- $(object_dir)/oggdec_filter.o $(dep_dir)/oggdec_filter.d \
- $(object_dir)/ogg_afh.o $(dep_dir)/ogg_afh.d \
- $(object_dir)/ogg_afh_common.o $(dep_dir)/ogg_afh_common.d \
- $(object_dir)/opus%.o $(dep_dir)/opus%.d \
+ $(object_dir)/spx_common.o \
+ $(object_dir)/spxdec_filter.o \
+ $(object_dir)/spx_afh.o \
+ $(object_dir)/oggdec_filter.o \
+ $(object_dir)/ogg_afh.o \
+ $(object_dir)/ogg_afh_common.o \
+ $(object_dir)/opus%.o \
  : CPPFLAGS += $(ogg_cppflags)
  
- $(object_dir)/afs.o $(dep_dir)/afs.d \
- $(object_dir)/aft.o $(dep_dir)/aft.d \
- $(object_dir)/attribute.o $(dep_dir)/attribute.d \
- $(object_dir)/blob.o $(dep_dir)/blob.d  \
- $(object_dir)/mood.o $(dep_dir)/mood.d \
- $(object_dir)/playlist.o $(dep_dir)/playlist.d \
- $(object_dir)/score.o $(dep_dir)/score.d \
- $(object_dir)/server.o $(dep_dir)/server.d \
- $(object_dir)/vss.o $(dep_dir)/vss.d \
- $(object_dir)/command.o $(dep_dir)/command.d \
- $(object_dir)/http_send.o $(dep_dir)/http_send.d \
- $(object_dir)/dccp_send.o $(dep_dir)/dccp_send.d \
- $(object_dir)/udp_send.o $(dep_dir)/udp_send.d \
- $(object_dir)/send_common.o $(dep_dir)/send_common.d \
- $(object_dir)/mm.o $(dep_dir)/mm.d \
+ $(object_dir)/afs.o \
+ $(object_dir)/aft.o \
+ $(object_dir)/attribute.o \
+ $(object_dir)/blob.o  \
+ $(object_dir)/mood.o \
+ $(object_dir)/playlist.o \
+ $(object_dir)/score.o \
+ $(object_dir)/server.o \
+ $(object_dir)/vss.o \
+ $(object_dir)/command.o \
+ $(object_dir)/http_send.o \
+ $(object_dir)/dccp_send.o \
+ $(object_dir)/udp_send.o \
+ $(object_dir)/send_common.o \
+ $(object_dir)/mm.o \
  : CPPFLAGS += $(osl_cppflags)
  
- $(object_dir)/%.cmdline.o: CFLAGS += -Wno-unused-function
  $(object_dir)/compress_filter.o: CFLAGS += -O3
  
- $(object_dir)/%.o: %.c | $(object_dir)
-       @[ -z "$(Q)" ] || echo 'CC $<'
-       $(Q) $(CC) -c -o $@ $(CPPFLAGS) $(STRICT_CFLAGS) $<
- $(object_dir)/%.cmdline.o: $(cmdline_dir)/%.cmdline.c $(cmdline_dir)/%.cmdline.h | $(object_dir)
+ $(object_dir)/%.o: %.c | $(object_dir) $(dep_dir) $(lsg_h)
        @[ -z "$(Q)" ] || echo 'CC $<'
-       $(Q) $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $<
- # The compiler outputs dependencies either as foo.h or as some_directory/foo.h,
- # depending on whether the latter file exists. Since make needs the directory
- # part we prefix the dependency as appropriate.
- $(dep_dir)/%.d: %.c | $(dep_dir)
-       @[ -z "$(Q)" ] || echo 'DEP $<'
-       $(Q) $(CC) $(CPPFLAGS) -MM -MG -MP -MT $@ -MT $(object_dir)/$(*F).o $< \
-               | sed -e "s@ \([a-zA-Z0-9_]\{1,\}\.cmdline.h\)@ $(cmdline_dir)/\1@g" \
-               -e "s@ \([a-zA-Z0-9_]\{1,\}\.command_list.h\)@ $(cmdlist_dir)/\1@g" \
-               -e "s@ \([a-zA-Z0-9_]\{1,\}\.completion.h\)@ $(cmdlist_dir)/\1@g" > $@
+       $(Q) $(CC) -c -o $@ -MMD -MF $(dep_dir)/$(*F).d -MT $@ $(CPPFLAGS) \
+               $(STRICT_CFLAGS) $(CFLAGS) $<
  
  para_recv para_afh para_play para_server: LDFLAGS += $(id3tag_ldflags)
  para_write para_play para_audiod \
diff --cc NEWS.md
+++ b/NEWS.md
@@@ -1,45 -1,6 +1,69 @@@
  NEWS
  ====
  
 +------------------------------------
 +0.6.0 (to be announced) "fuzzy flux"
 +------------------------------------
 +- Support for Mac OS X has been removed.
 +- On Linux systems, glibc-2.17 or newer is required to build the
 +  source tree.
 +- Support for RSA public keys in ASN format (as generated by openssl
 +  genrsa) has been removed. These keys have been deprecated since
 +  2011, so users should have long switched to keys generated with
 +  ssh-keygen(1).
 +- If libgcrypt is used as the crypto library, we now require version
 +  1.5.0 (released in 2011) or later.
 +- The insecure RC4 stream cipher has been removed. It was superseded
 +  by aes_ctr128 three years ago but the RC4 code had been kept for
 +  backwards compatibility.
 +- On Linux, abstract unix domain sockets are used unconditionally.
 +- The "install" target no longer strips executables, the new
 +  install-strip target can be used to get the old behaviour.
 +- The clean targets have been renamed: clean2 is gone, and the new
 +  mostlyclean removes only the executables and object files.
 +- New target: check (identical to test).
 +- The DESTDIR make variable is honored to prepend a path to the
 +  installation directory. This feature is orthogonal to the --prefix
 +  option to configure.
 +- Minor WMA cleanups.
 +- The aac audio format handler has been rewritten to use the mp4ff library.
 +  See the manual for how to install the library on your system.
 +- New status item: max_chunk_size. The value is stored in a previously
 +  unused field of the afhi object of the aft table. Although backwards
 +  compatible, users are encouraged to re-add m4a files to populate
 +  the new field.
 +- No more chunk tables for aac. Chunk boundaries are determined
 +  dynamically at stream time.
 +- Release and master branch tarballs are now compressed with xz rather
 +  than bzip2.
++- The lopsub package is required to install the paraslash package.
++  Gengetopt is no longer needed.
++- make dep is gone. Dependencies have been created automatically for
++  a long time and it was never necessary to run make dep manually.
++- para_gui lost its --timeout option.
++- Most manual pages have been extended to include an overall
++  description of the command.
++- The --stream-delay option of para_audiod has been removed. It had
++  been a no-op for many years.
++- The deprecated --path option of the server ls command has been
++  removed.  The command now prints full paths by default, making
++  --full-path a no-op. Hence --full-path has been depreacted and is
++  scheduled for removal in v0.6.1.
++- It is now possible to use 'CFLAGS' to override the default compiler
++  options.
++- para_fade has been renamed to para_mixer. The four modes of operation
++  (set, fade, snooze, sleep) are implemented as subcommands of the
++  new program.
++- The sleep subcommand of para_mixer (former sleep mode of para_fade)
++  lost its --wake-hour and --wake-min options in favor of the new
++  --wake-time option which also accepts relative wakeup times like
++  "+9:30".
++- The new --fade-exponent option of para_mixer allows for non-linear
++  channel fading.
 +
 +Downloads:
 +[tarball](./releases/paraslash-git.tar.bz2),
 +
  -------------------------------------
  0.5.7 (2016-12-31) "semantic density"
  -------------------------------------
diff --cc aacdec_filter.c
  /** \file aacdec_filter.c paraslash's aac (m4a) decoder. */
  
  #include <regex.h>
 +#include <neaacdec.h>
  
  #include "para.h"
 +#include "portable_io.h"
  #include "list.h"
  #include "sched.h"
- #include "ggo.h"
  #include "buffer_tree.h"
  #include "filter.h"
  #include "error.h"
diff --cc afh.c
--- 1/afh.c
--- 2/afh.c
+++ b/afh.c
@@@ -125,48 -135,44 +135,53 @@@ static void print_info(int audio_format
        free(msg);
  }
  
 -static void print_chunk_table(struct afh_info *afhi)
 +static void print_chunk_table(struct afh_info *afhi, int audio_format_id,
 +              const void *map, size_t mapsize)
  {
 -      int i;
 +      int i, ret;
 +      void *ctx = NULL;
  
 -      if (OPT_GIVEN(PARSER_FRIENDLY)) {
 -              printf("chunk_table: ");
 -              for (i = 0; i <= afhi->chunks_total; i++)
 -                      printf("%u ", afhi->chunk_table[i]);
 -              printf("\n");
 -              return;
 -      }
 -      for (i = 1; i <= afhi->chunks_total; i++) {
 +      for (i = 0; i < afhi->chunks_total; i++) {
                struct timeval tv;
                long unsigned from, to;
 -              tv_scale(i - 1, &afhi->chunk_tv, &tv);
 -              from = tv2ms(&tv);
 +              const char *buf;
 +              size_t len;
                tv_scale(i, &afhi->chunk_tv, &tv);
 +              from = tv2ms(&tv);
 +              tv_scale(i + 1, &afhi->chunk_tv, &tv);
                to = tv2ms(&tv);
 -              printf("%d [%lu.%03lu - %lu.%03lu] %u - %u (%u)\n", i - 1,
 -                      from / 1000, from % 1000, to / 1000, to % 1000,
 -                      afhi->chunk_table[i - 1], afhi->chunk_table[i],
 -                      afhi->chunk_table[i] - afhi->chunk_table[i - 1]);
 +              ret = afh_get_chunk(i, afhi, audio_format_id, map, mapsize,
 +                      &buf, &len, &ctx);
 +              if (ret < 0) {
 +                      PARA_ERROR_LOG("fatal: chunk %d: %s\n", i,
 +                              para_strerror(-ret));
 +                      return;
 +              }
-               if (!conf.parser_friendly_given)
++              if (!OPT_GIVEN(PARSER_FRIENDLY))
 +                      printf("%d [%lu.%03lu - %lu.%03lu] ", i, from / 1000,
 +                              from % 1000, to / 1000, to % 1000);
 +              printf("%td - %td", buf - (const char *)map,
 +                      buf + len - (const char *)map);
-               if (!conf.parser_friendly_given)
++              if (!OPT_GIVEN(PARSER_FRIENDLY))
 +                      printf(" (%zu)", len);
 +              printf("\n");
        }
 +      afh_close(ctx, audio_format_id);
  }
  
__noreturn static void print_help_and_die(void)
static void handle_help_flags(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);
+       char *help;
+       if (OPT_GIVEN(DETAILED_HELP))
+               help = lls_long_help(CMD_PTR);
+       else if (OPT_GIVEN(HELP) || lls_num_inputs(lpr) == 0)
+               help = lls_short_help(CMD_PTR);
+       else
+               return;
+       printf("%s", help);
+       free(help);
+       printf("Supported audio formats\n  %s\n", AUDIO_FORMAT_HANDLERS);
        exit(EXIT_SUCCESS);
  }
  
@@@ -203,15 -212,15 +221,15 @@@ int main(int argc, char **argv
                        fd, &afhi);
                if (ret >= 0) {
                        audio_format_num = ret;
-                       if (conf.modify_given) {
-                               ret = rewrite_tags(conf.inputs[i], fd, audio_file_data,
+                       if (OPT_GIVEN(MODIFY)) {
+                               ret = rewrite_tags(path, fd, audio_file_data,
                                        audio_file_size, audio_format_num, &afhi);
                        } else {
-                               printf("File %d: %s\n", i + 1, conf.inputs[i]);
+                               printf("File %d: %s\n", i + 1, path);
                                print_info(audio_format_num, &afhi);
-                               if (conf.chunk_table_given)
+                               if (OPT_GIVEN(CHUNK_TABLE))
 -                                      print_chunk_table(&afhi);
 -                              printf("\n");
 +                                      print_chunk_table(&afhi, audio_format_num,
 +                                              audio_file_data, audio_file_size);
                        }
                        clear_afhi(&afhi);
                }
diff --cc afh_recv.c
@@@ -108,24 -91,22 +93,23 @@@ static int afh_recv_open(struct receive
        ret = -ERRNO_TO_PARA_ERROR(EINVAL);
        if (afhi->chunks_total == 0)
                goto out_clear_afhi;
-       if (PARA_ABS(conf->begin_chunk_arg) >= afhi->chunks_total)
+       if (PARA_ABS(bc) >= afhi->chunks_total)
                goto out_clear_afhi;
-       if (conf->begin_chunk_arg >= 0)
-               pard->first_chunk = afh_get_start_chunk(
-                       conf->begin_chunk_arg, &pard->afhi,
+       if (bc >= 0)
 -              pard->first_chunk = afh_get_start_chunk(bc, &pard->afhi);
++              pard->first_chunk = afh_get_start_chunk(bc, &pard->afhi,
 +                      pard->audio_format_num);
        else
-               pard->first_chunk = afh_get_start_chunk(
-                       afhi->chunks_total + conf->begin_chunk_arg,
+               pard->first_chunk = afh_get_start_chunk(afhi->chunks_total + bc,
 -                      &pard->afhi);
 +                      &pard->afhi, pard->audio_format_num);
-       if (conf->end_chunk_given) {
+       if (lls_opt_given(r_e)) {
+               int32_t ec = lls_int32_val(0, r_e);
                ret = -ERRNO_TO_PARA_ERROR(EINVAL);
-               if (PARA_ABS(conf->end_chunk_arg) > afhi->chunks_total)
+               if (PARA_ABS(ec) > afhi->chunks_total)
                        goto out_clear_afhi;
-               if (conf->end_chunk_arg >= 0)
-                       pard->last_chunk = conf->end_chunk_arg;
+               if (ec >= 0)
+                       pard->last_chunk = ec;
                else
-                       pard->last_chunk = afhi->chunks_total + conf->end_chunk_arg;
+                       pard->last_chunk = afhi->chunks_total + ec;
        } else
                pard->last_chunk = afhi->chunks_total - 1;
        ret = -ERRNO_TO_PARA_ERROR(EINVAL);
@@@ -186,9 -167,11 +171,11 @@@ static int afh_recv_post_select(__a_unu
        struct afh_info *afhi = &pard->afhi;
        int ret;
        char *buf;
 -      const char *start, *end;
 +      const char *start;
        size_t size;
        struct timeval chunk_time;
+       unsigned j_given = RECV_CMD_OPT_GIVEN(AFH, JUST_IN_TIME, lpr);
+       unsigned H_given = RECV_CMD_OPT_GIVEN(AFH, NO_HEADER, lpr);
  
        ret = btr_node_status(btrn, 0, BTR_NT_ROOT);
        if (ret <= 0)
                        afh_free_header(header, pard->audio_format_num);
                }
        }
-       if (!conf->just_in_time_given) {
+       if (!j_given) {
 -              afh_get_chunk(pard->first_chunk, afhi, pard->map, &start, &size);
 -              afh_get_chunk(pard->last_chunk, afhi, pard->map, &end, &size);
 -              end += size;
 -              PARA_INFO_LOG("adding %td bytes\n", end - start);
 -              btr_add_output_dont_free(start, end - start, btrn);
 +              long unsigned n;
 +              for (n = pard->first_chunk; n < pard->last_chunk; n++) {
 +                      ret = afh_get_chunk(n, afhi, pard->audio_format_num,
 +                              pard->map, pard->map_size, &start, &size,
 +                              &pard->afh_context);
 +                      if (ret < 0)
 +                              goto out;
 +                      PARA_INFO_LOG("adding %zu bytes\n", size);
 +                      btr_add_output_dont_free(start, size, btrn);
 +              }
                ret = -E_RECV_EOF;
                goto out;
        }
diff --cc afs.c
--- 1/afs.c
--- 2/afs.c
+++ b/afs.c
@@@ -646,13 -623,18 +623,13 @@@ static void init_admissible_files(cons
  static int setup_command_socket_or_die(void)
  {
        int ret, socket_fd;
-       char *socket_name = conf.afs_socket_arg;
+       const char *socket_name = OPT_STRING_VAL(AFS_SOCKET);
  
        unlink(socket_name);
 -      ret = create_local_socket(socket_name, 0);
 +      ret = create_local_socket(socket_name);
        if (ret < 0) {
 -              ret = create_local_socket(socket_name,
 -                      S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IROTH);
 -              if (ret < 0) {
 -                      PARA_EMERG_LOG("%s: %s\n", para_strerror(-ret),
 -                              socket_name);
 -                      exit(EXIT_FAILURE);
 -              }
 +              PARA_EMERG_LOG("%s: %s\n", para_strerror(-ret), socket_name);
 +              exit(EXIT_FAILURE);
        }
        socket_fd = ret;
        PARA_INFO_LOG("listening on socket %s (fd %d)\n", socket_name,
diff --cc aft.c
--- 1/aft.c
--- 2/aft.c
+++ b/aft.c
@@@ -2297,22 -2112,20 +2137,22 @@@ static int copy_selector_info(__a_unuse
        ret = get_afsi_object_of_row(row, &target_afsi_obj);
        if (ret < 0)
                return ret;
 -      load_afsi(&target_afsi, &target_afsi_obj);
 +      ret = load_afsi(&target_afsi, &target_afsi_obj);
 +      if (ret < 0)
 +              return ret;
        old_afsi = target_afsi;
-       if (cad->flags & CPSI_FLAG_COPY_LYRICS_ID)
+       if (cad->copy_all || y_given)
                target_afsi.lyrics_id = cad->source_afsi.lyrics_id;
-       if (cad->flags & CPSI_FLAG_COPY_IMAGE_ID)
+       if (cad->copy_all || i_given)
                target_afsi.image_id = cad->source_afsi.image_id;
-       if (cad->flags & CPSI_FLAG_COPY_LASTPLAYED)
+       if (cad->copy_all || l_given)
                target_afsi.last_played = cad->source_afsi.last_played;
-       if (cad->flags & CPSI_FLAG_COPY_NUMPLAYED)
+       if (cad->copy_all || n_given)
                target_afsi.num_played = cad->source_afsi.num_played;
-       if (cad->flags & CPSI_FLAG_COPY_ATTRIBUTES)
+       if (cad->copy_all || a_given)
                target_afsi.attributes = cad->source_afsi.attributes;
        save_afsi(&target_afsi, &target_afsi_obj); /* in-place update */
-       if (cad->flags & CPSI_FLAG_VERBOSE)
+       if (v_given)
                para_printf(&cad->aca->pbout, "copied afsi to %s\n", name);
        aced.aft_row = row;
        aced.old_afsi = &old_afsi;
diff --cc audiod.c
+++ b/audiod.c
@@@ -1047,10 -1078,10 +1066,10 @@@ static int parse_stream_args(void
  }
  
  /* does not unlink socket on errors */
 -static void init_local_sockets(struct command_task *ct)
 +static void init_local_socket(struct command_task *ct)
  {
-       if (conf.socket_given)
-               socket_name = para_strdup(conf.socket_arg);
+       if (OPT_GIVEN(SOCKET))
+               socket_name = para_strdup(OPT_STRING_VAL(SOCKET));
        else {
                char *hn = para_hostname();
                socket_name = make_message("/var/paraslash/audiod_socket.%s",
                free(hn);
        }
        PARA_NOTICE_LOG("local socket: %s\n", socket_name);
-       if (conf.force_given)
+       if (OPT_GIVEN(FORCE))
                unlink(socket_name);
 -      ct->fd[0] = create_local_socket(socket_name, 0);
 -      ct->fd[1] = create_local_socket(socket_name,
 -              S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
 -      if (ct->fd[0] >= 0 || ct->fd[1] >= 0)
 +      ct->fd = create_local_socket(socket_name);
 +      if (ct->fd >= 0)
                return;
 -      PARA_EMERG_LOG("%s\n", para_strerror(-ct->fd[1]));
 +      PARA_EMERG_LOG("%s\n", para_strerror(-ct->fd));
        exit(EXIT_FAILURE);
  }
  
diff --cc client_common.c
Simple merge
diff --cc command.c
Simple merge
diff --cc configure.ac
@@@ -59,9 -55,13 +55,9 @@@ AC_PATH_PROG([M4], [m4]
  test -z "$M4" && AC_MSG_ERROR(
        [The m4 macro processor is required to build this package])
  
- AC_PATH_PROG([HELP2MAN], [help2man])
- test -z "$HELP2MAN" && AC_MSG_ERROR(
-       [help2man is required to build this package])
 -AC_PATH_PROG([INSTALL], [install])
 -test -z "$INSTALL" && AC_MSG_ERROR(
 -      [The install program is required to build this package])
 -
+ AC_PATH_PROG([lopsubgen], [lopsubgen])
+ test -z "$lopsubgen" && AC_MSG_ERROR(
+       [lopsubgen is required to build this package])
  
  AC_PROG_CC
  AC_PROG_CPP
@@@ -399,10 -441,10 +400,10 @@@ if test -n "$CRYPTOLIB" && test $HAVE_O
        NEED_SPEEX_OBJECTS() && server_errlist_objs="$server_errlist_objs spx_afh spx_common"
        NEED_OPUS_OBJECTS() && server_errlist_objs="$server_errlist_objs opus_afh opus_common"
        NEED_FLAC_OBJECTS && server_errlist_objs="$server_errlist_objs flac_afh"
 -      if test $HAVE_FAAD = yes && test $HAVE_MP4V2 = yes; then
 -              server_errlist_objs="$server_errlist_objs aac_afh aac_common"
 +      if test $HAVE_FAAD = yes; then
 +              server_errlist_objs="$server_errlist_objs aac_afh"
        fi
-       server_objs="add_cmdline($server_cmdline_objs) $server_errlist_objs"
+       server_objs="$server_errlist_objs"
        AC_SUBST(server_objs, add_dot_o($server_objs))
  else
        build_server="no"
@@@ -657,37 -645,15 +601,15 @@@ filter_errlist_objs=
        net
        sync_filter
  "
- filter_cmdline_objs="
-       filter
-       compress_filter
-       amp_filter
-       prebuffer_filter
-       sync_filter
- "
- NEED_VORBIS_OBJECTS && {
-       filters="$filters oggdec"
-       filter_errlist_objs="$filter_errlist_objs oggdec_filter"
- }
- NEED_SPEEX_OBJECTS && {
-       filters="$filters spxdec"
-       filter_errlist_objs="$filter_errlist_objs spxdec_filter spx_common"
- }
- NEED_OPUS_OBJECTS && {
-       filters="$filters opusdec"
-       filter_errlist_objs="$filter_errlist_objs opusdec_filter opus_common"
- }
- NEED_FLAC_OBJECTS && {
-       filter_errlist_objs="$filter_errlist_objs flacdec_filter"
-       filters="$filters flacdec"
- }
+ NEED_VORBIS_OBJECTS && filter_errlist_objs="$filter_errlist_objs oggdec_filter"
+ NEED_SPEEX_OBJECTS && filter_errlist_objs="$filter_errlist_objs spxdec_filter spx_common"
+ NEED_OPUS_OBJECTS && filter_errlist_objs="$filter_errlist_objs opusdec_filter opus_common"
+ NEED_FLAC_OBJECTS && filter_errlist_objs="$filter_errlist_objs flacdec_filter"
  if test $HAVE_FAAD = yes; then
 -      filter_errlist_objs="$filter_errlist_objs aacdec_filter aac_common"
 +      filter_errlist_objs="$filter_errlist_objs aacdec_filter"
-       filters="$filters aacdec"
  fi
  if test $HAVE_MAD = yes; then
-       filter_cmdline_objs="$filter_cmdline_objs mp3dec_filter"
        filter_errlist_objs="$filter_errlist_objs mp3dec_filter"
-       filters="$filters mp3dec"
  fi
  if test $HAVE_SAMPLERATE = yes; then
        filter_errlist_objs="$filter_errlist_objs resample_filter check_wav"
@@@ -743,11 -688,10 +644,10 @@@ NEED_SPEEX_OBJECTS && recv_errlist_objs
  NEED_OPUS_OBJECTS && recv_errlist_objs="$recv_errlist_objs opus_afh opus_common"
  NEED_FLAC_OBJECTS && recv_errlist_objs="$recv_errlist_objs flac_afh"
  
 -if test $HAVE_FAAD = yes -a $HAVE_MP4V2 = yes; then
 -      recv_errlist_objs="$recv_errlist_objs aac_afh aac_common"
 +if test $HAVE_FAAD = yes; then
 +      recv_errlist_objs="$recv_errlist_objs aac_afh"
  fi
- recv_objs="add_cmdline($recv_cmdline_objs) $recv_errlist_objs"
- AC_SUBST(receivers, "http dccp udp afh")
+ recv_objs="$recv_errlist_objs"
  AC_SUBST(recv_objs, add_dot_o($recv_objs))
  ########################################################################### afh
  audio_format_handlers="mp3 wma"
@@@ -823,18 -764,9 +720,6 @@@ play_errlist_objs=
        version
        sync_filter
  "
- play_cmdline_objs="
-       http_recv
-       dccp_recv
-       udp_recv
-       afh_recv
-       compress_filter
-       amp_filter
-       prebuffer_filter
-       file_write
-       play
-       sync_filter
- "
 -if test "$have_core_audio" = "yes"; then
 -      play_errlist_objs="$play_errlist_objs osx_write ipc"
 -fi
  NEED_OGG_OBJECTS && play_errlist_objs="$play_errlist_objs ogg_afh_common"
  NEED_VORBIS_OBJECTS && {
        play_errlist_objs="$play_errlist_objs oggdec_filter ogg_afh"
@@@ -852,10 -784,15 +737,9 @@@ NEED_FLAC_OBJECTS && 
        play_errlist_objs="$play_errlist_objs flacdec_filter flac_afh"
  }
  if test $HAVE_FAAD = yes; then
 -      play_errlist_objs="$play_errlist_objs aacdec_filter"
 -fi
 -if test $HAVE_MP4V2 = yes; then
 -      play_errlist_objs="$play_errlist_objs aac_afh"
 -fi
 -if test $HAVE_MP4V2 = yes || test $HAVE_FAAD = yes; then
 -      play_errlist_objs="$play_errlist_objs aac_common"
 +      play_errlist_objs="$play_errlist_objs aac_afh aacdec_filter"
  fi
  if test $HAVE_MAD = yes; then
-       play_cmdline_objs="$play_cmdline_objs mp3dec_filter"
        play_errlist_objs="$play_errlist_objs mp3dec_filter"
  fi
  if test $HAVE_OSS = yes; then
@@@ -898,15 -827,12 +774,9 @@@ write_errlist_objs=
        check_wav
        version
  "
- writers="file"
- default_writer="FILE_WRITE"
  
 -if test "$have_core_audio" = "yes"; then
 -      write_errlist_objs="$write_errlist_objs osx_write ipc"
 -fi
  NEED_AO_OBJECTS && {
        write_errlist_objs="$write_errlist_objs ao_write"
-       write_cmdline_objs="$write_cmdline_objs ao_write"
-       writers="$writers ao"
-       default_writer="AO_WRITE"
  }
  if test $HAVE_OSS = yes; then
        write_errlist_objs="$write_errlist_objs oss_write"
@@@ -991,10 -898,8 +842,7 @@@ unix socket credentials: $have_ucre
  readline (interactive CLIs): $HAVE_READLINE
  id3 version 2 support: $HAVE_ID3TAG
  faad: $HAVE_FAAD
 -mp4v2: $HAVE_MP4V2
  audio format handlers: $audio_format_handlers
- filters: $(echo $filters)
- writers: $writers
  
  para_server: $build_server
  para_gui: $build_gui
diff --cc error.h
+++ b/error.h
        PARA_ERROR(PERM, "permission denied"), \
        PARA_ERROR(PLAYLIST_EMPTY, "attempted to load empty playlist"), \
        PARA_ERROR(PLAYLIST_LOADED, ""), /* not really an error */ \
-       PARA_ERROR(PLAY_SYNTAX, "para_play: syntax error"), \
        PARA_ERROR(PREBUFFER_SUCCESS, "prebuffering complete"), \
        PARA_ERROR(PRIVATE_KEY, "can not read private key"), \
 -      PARA_ERROR(PUBLIC_KEY, "can not read public key"), \
        PARA_ERROR(QUEUE, "packet queue overrun"), \
        PARA_ERROR(READ_PATTERN, "did not read expected pattern"), \
        PARA_ERROR(RECV_EOF, "end of file"), \
diff --cc server.h
Simple merge
diff --cc vss.c
Simple merge
diff --cc web/manual.md
Simple merge
diff --cc wmadec_filter.c
Simple merge