Merge branch 'refs/heads/t/si_conversion'
authorAndre Noll <maan@tuebingen.mpg.de>
Sun, 27 Aug 2017 10:11:22 +0000 (12:11 +0200)
committerAndre Noll <maan@tuebingen.mpg.de>
Sun, 27 Aug 2017 10:11:22 +0000 (12:11 +0200)
A single patch which moves the list of status items from configure.ac
to para.h.

Cooking for five weeks.

* refs/heads/t/si_conversion:
  Define status items in para.h.

1  2 
afh_common.c
aft.c
audioc.c
audiod.c
audiod_command.c
command.c
configure.ac

diff --combined afh_common.c
  #include "afh.h"
  
  typedef void afh_init_func(struct audio_format_handler *);
 -/* It does not hurt to declare init functions which are not available. */
 +
 +/*
 + * Declaration of the audio format handler init functions.
 + *
 + * These symbols are referenced in the afl array below.
 + *
 + * Most audio format handlers depend on an external library and are not
 + * compiled in if the library is not installed. Hence it is well possible that
 + * not all of these functions are defined. It does not hurt to declare them
 + * anyway, and this avoids another set of ifdefs.
 + */
  extern afh_init_func mp3_afh_init, ogg_afh_init, aac_afh_init, wma_afh_init,
        spx_afh_init, flac_afh_init, opus_afh_init;
  
  /** The list of all status items */
- const char *status_item_list[] = {STATUS_ITEM_ARRAY};
+ const char *status_item_list[] = {STATUS_ITEMS};
  
  /**
   * The list of supported audio formats.
@@@ -464,21 -454,21 +464,21 @@@ unsigned afh_get_afhi_txt(int audio_for
                "%s: %s\n" /* year */
                "%s: %s\n" /* album */
                "%s: %s\n", /* comment */
-               status_item_list[SI_BITRATE], afhi->bitrate,
-               status_item_list[SI_FORMAT], audio_format_name(audio_format_num),
-               status_item_list[SI_FREQUENCY], afhi->frequency,
-               status_item_list[SI_CHANNELS], afhi->channels,
-               status_item_list[SI_SECONDS_TOTAL], afhi->seconds_total,
-               status_item_list[SI_CHUNK_TIME], (long unsigned)afhi->chunk_tv.tv_sec,
+               status_item_list[SI_bitrate], afhi->bitrate,
+               status_item_list[SI_format], audio_format_name(audio_format_num),
+               status_item_list[SI_frequency], afhi->frequency,
+               status_item_list[SI_channels], afhi->channels,
+               status_item_list[SI_seconds_total], afhi->seconds_total,
+               status_item_list[SI_chunk_time], (long unsigned)afhi->chunk_tv.tv_sec,
                        (long unsigned)afhi->chunk_tv.tv_usec,
-               status_item_list[SI_NUM_CHUNKS], afhi->chunks_total,
-               status_item_list[SI_MAX_CHUNK_SIZE], afhi->max_chunk_size,
-               status_item_list[SI_TECHINFO], afhi->techinfo? afhi->techinfo : "",
-               status_item_list[SI_ARTIST], afhi->tags.artist? afhi->tags.artist : "",
-               status_item_list[SI_TITLE], afhi->tags.title? afhi->tags.title : "",
-               status_item_list[SI_YEAR], afhi->tags.year? afhi->tags.year : "",
-               status_item_list[SI_ALBUM], afhi->tags.album? afhi->tags.album : "",
-               status_item_list[SI_COMMENT], afhi->tags.comment? afhi->tags.comment : ""
+               status_item_list[SI_num_chunks], afhi->chunks_total,
+               status_item_list[SI_max_chunk_size], afhi->max_chunk_size,
+               status_item_list[SI_techinfo], afhi->techinfo? afhi->techinfo : "",
+               status_item_list[SI_artist], afhi->tags.artist? afhi->tags.artist : "",
+               status_item_list[SI_title], afhi->tags.title? afhi->tags.title : "",
+               status_item_list[SI_year], afhi->tags.year? afhi->tags.year : "",
+               status_item_list[SI_album], afhi->tags.album? afhi->tags.album : "",
+               status_item_list[SI_comment], afhi->tags.comment? afhi->tags.comment : ""
        );
  }
  
diff --combined aft.c
--- 1/aft.c
--- 2/aft.c
+++ b/aft.c
@@@ -138,7 -138,7 +138,7 @@@ struct ls_options 
  /**
   * Describes the layout of the mmapped-afs info struct.
   *
 - * \sa struct afs_info.
 + * \sa struct \ref afs_info.
   */
  enum afsi_offsets {
        /** Where .last_played is stored. */
   * \param afsi Pointer to the audio file info to be converted.
   * \param obj Result pointer.
   *
 - * \sa load_afsi().
 + * \sa \ref load_afsi().
   */
  static void save_afsi(struct afs_info *afsi, struct osl_object *obj)
  {
   *
   * \return Standard.
   *
 - * \sa save_afsi().
 + * \sa \ref save_afsi().
   */
  static int load_afsi(struct afs_info *afsi, struct osl_object *obj)
  {
@@@ -365,10 -365,7 +365,10 @@@ static void save_afhi(struct afh_info *
        write_u32(buf + CHUNK_TV_TV_SEC_OFFSET, afhi->chunk_tv.tv_sec);
        write_u32(buf + CHUNK_TV_TV_USEC_OFFSET, afhi->chunk_tv.tv_usec);
        p = buf + AFHI_INFO_STRING_OFFSET;
 -      /* The sprintf's below are OK as our caller made sure that buf is large enough */
 +      /*
 +       * The below sprintf(3) calls are OK because our caller already made
 +       * sure that buf is large enough.
 +       */
        p += sprintf(p, "%s", afhi->techinfo) + 1;
        p += sprintf(p, "%s", afhi->tags.artist) + 1;
        p += sprintf(p, "%s", afhi->tags.title) + 1;
@@@ -532,7 -529,7 +532,7 @@@ static int get_afsi_of_path(const char 
   * \param row Pointer to a row in the audio file table.
   * \param path Result pointer.
   *
 - * The result is a pointer to mmapped data. The caller must not attempt
 + * The result is a pointer to memory-mapped data. The caller must not attempt
   * to free it.
   *
   * \return Standard.
@@@ -542,12 -539,10 +542,12 @@@ int get_audio_file_path_of_row(const st
        struct osl_object path_obj;
        int ret = osl(osl_get_object(audio_file_table, row, AFTCOL_PATH,
                &path_obj));
 +
        if (ret < 0)
 -              return ret;
 -      *path = path_obj.data;
 -      return 1;
 +              *path = NULL;
 +      else
 +              *path = path_obj.data;
 +      return ret;
  }
  
  /**
   *
   * \return The return value of the underlying call to osl_get_object().
   *
 - * \sa get_hash_of_row().
 + * \sa \ref get_hash_of_row().
   */
  static int get_hash_object_of_aft_row(const struct osl_row *row,
                struct osl_object *obj)
@@@ -599,6 -594,8 +599,6 @@@ static int get_hash_of_row(const struc
   * After the call the members of the afhi structure point to mapped memory
   * which is owned by the osl table, Hence the caller must not attempt to free
   * this memory by calling \ref clear_afhi().
 - *
 - * \sa get_chunk_table_of_row().
   */
  int get_afhi_of_row(const struct osl_row *row, struct afh_info *afhi)
  {
@@@ -756,11 -753,11 +756,11 @@@ static int write_attribute_items(struc
        char *att_text;
        int ret;
  
-       WRITE_STATUS_ITEM(b, SI_ATTRIBUTES_BITMAP, "%s\n", att_bitmap);
+       WRITE_STATUS_ITEM(b, SI_attributes_bitmap, "%s\n", att_bitmap);
        ret = get_attribute_text(&afsi->attributes, " ", &att_text);
        if (ret < 0)
                return ret;
-       WRITE_STATUS_ITEM(b, SI_ATTRIBUTES_TXT, "%s\n", att_text);
+       WRITE_STATUS_ITEM(b, SI_attributes_txt, "%s\n", att_text);
        free(att_text);
        return ret;
  }
@@@ -769,9 -766,9 +769,9 @@@ static void write_lyrics_items(struct p
  {
        char *lyrics_name;
  
-       WRITE_STATUS_ITEM(b, SI_LYRICS_ID, "%u\n", afsi->lyrics_id);
+       WRITE_STATUS_ITEM(b, SI_lyrics_id, "%u\n", afsi->lyrics_id);
        lyr_get_name_by_id(afsi->lyrics_id, &lyrics_name);
-       WRITE_STATUS_ITEM(b, SI_LYRICS_NAME, "%s\n", lyrics_name?
+       WRITE_STATUS_ITEM(b, SI_lyrics_name, "%s\n", lyrics_name?
                lyrics_name : "(none)");
  }
  
@@@ -779,9 -776,9 +779,9 @@@ static void write_image_items(struct pa
  {
        char *image_name;
  
-       WRITE_STATUS_ITEM(b, SI_IMAGE_ID, "%u\n", afsi->image_id);
+       WRITE_STATUS_ITEM(b, SI_image_id, "%u\n", afsi->image_id);
        img_get_name_by_id(afsi->image_id, &image_name);
-       WRITE_STATUS_ITEM(b, SI_IMAGE_NAME, "%s\n", image_name?
+       WRITE_STATUS_ITEM(b, SI_image_name, "%s\n", image_name?
                image_name : "(none)");
  }
  
@@@ -791,14 -788,14 +791,14 @@@ static void write_filename_items(struc
        char *val;
  
        if (basename) {
-               WRITE_STATUS_ITEM(b, SI_BASENAME, "%s\n", path);
+               WRITE_STATUS_ITEM(b, SI_basename, "%s\n", path);
                return;
        }
-       WRITE_STATUS_ITEM(b, SI_PATH, "%s\n", path);
+       WRITE_STATUS_ITEM(b, SI_path, "%s\n", path);
        val = para_basename(path);
-       WRITE_STATUS_ITEM(b, SI_BASENAME, "%s\n", val? val : "");
+       WRITE_STATUS_ITEM(b, SI_basename, "%s\n", val? val : "");
        val = para_dirname(path);
-       WRITE_STATUS_ITEM(b, SI_DIRECTORY, "%s\n", val? val : "");
+       WRITE_STATUS_ITEM(b, SI_directory, "%s\n", val? val : "");
        free(val);
  }
  
@@@ -915,36 -912,36 +915,36 @@@ static int print_list_item(struct ls_da
        }
        write_filename_items(b, d->path, lls_opt_given(r_b));
        if (lls_opt_given(r_a))
-               WRITE_STATUS_ITEM(b, SI_SCORE, "%li\n", d->score);
+               WRITE_STATUS_ITEM(b, SI_score, "%li\n", d->score);
        ret = write_attribute_items(b, att_buf, afsi);
        if (ret < 0)
                goto out;
        write_image_items(b, afsi);
        write_lyrics_items(b, afsi);
        hash_to_asc(d->hash, asc_hash);
-       WRITE_STATUS_ITEM(b, SI_HASH, "%s\n", asc_hash);
-       WRITE_STATUS_ITEM(b, SI_BITRATE, "%dkbit/s\n", afhi->bitrate);
-       WRITE_STATUS_ITEM(b, SI_FORMAT, "%s\n",
+       WRITE_STATUS_ITEM(b, SI_hash, "%s\n", asc_hash);
+       WRITE_STATUS_ITEM(b, SI_bitrate, "%dkbit/s\n", afhi->bitrate);
+       WRITE_STATUS_ITEM(b, SI_format, "%s\n",
                audio_format_name(afsi->audio_format_id));
-       WRITE_STATUS_ITEM(b, SI_FREQUENCY, "%dHz\n", afhi->frequency);
-       WRITE_STATUS_ITEM(b, SI_CHANNELS, "%d\n", afhi->channels);
-       WRITE_STATUS_ITEM(b, SI_DURATION, "%s\n", duration_buf);
-       WRITE_STATUS_ITEM(b, SI_SECONDS_TOTAL, "%" PRIu32 "\n",
+       WRITE_STATUS_ITEM(b, SI_frequency, "%dHz\n", afhi->frequency);
+       WRITE_STATUS_ITEM(b, SI_channels, "%d\n", afhi->channels);
+       WRITE_STATUS_ITEM(b, SI_duration, "%s\n", duration_buf);
+       WRITE_STATUS_ITEM(b, SI_seconds_total, "%" PRIu32 "\n",
                afhi->seconds_total);
-       WRITE_STATUS_ITEM(b, SI_LAST_PLAYED, "%s\n", last_played_time);
-       WRITE_STATUS_ITEM(b, SI_NUM_PLAYED, "%u\n", afsi->num_played);
-       WRITE_STATUS_ITEM(b, SI_AMPLIFICATION, "%u\n", afsi->amp);
-       WRITE_STATUS_ITEM(b, SI_CHUNK_TIME, "%lu\n", tv2ms(&afhi->chunk_tv));
-       WRITE_STATUS_ITEM(b, SI_NUM_CHUNKS, "%" PRIu32 "\n",
+       WRITE_STATUS_ITEM(b, SI_last_played, "%s\n", last_played_time);
+       WRITE_STATUS_ITEM(b, SI_num_played, "%u\n", afsi->num_played);
+       WRITE_STATUS_ITEM(b, SI_amplification, "%u\n", afsi->amp);
+       WRITE_STATUS_ITEM(b, SI_chunk_time, "%lu\n", tv2ms(&afhi->chunk_tv));
+       WRITE_STATUS_ITEM(b, SI_num_chunks, "%" PRIu32 "\n",
                afhi->chunks_total);
-       WRITE_STATUS_ITEM(b, SI_MAX_CHUNK_SIZE, "%" PRIu32 "\n",
+       WRITE_STATUS_ITEM(b, SI_max_chunk_size, "%" PRIu32 "\n",
                afhi->max_chunk_size);
-       WRITE_STATUS_ITEM(b, SI_TECHINFO, "%s\n", afhi->techinfo);
-       WRITE_STATUS_ITEM(b, SI_ARTIST, "%s\n", afhi->tags.artist);
-       WRITE_STATUS_ITEM(b, SI_TITLE, "%s\n", afhi->tags.title);
-       WRITE_STATUS_ITEM(b, SI_YEAR, "%s\n", afhi->tags.year);
-       WRITE_STATUS_ITEM(b, SI_ALBUM, "%s\n", afhi->tags.album);
-       WRITE_STATUS_ITEM(b, SI_COMMENT, "%s\n", afhi->tags.comment);
+       WRITE_STATUS_ITEM(b, SI_techinfo, "%s\n", afhi->techinfo);
+       WRITE_STATUS_ITEM(b, SI_artist, "%s\n", afhi->tags.artist);
+       WRITE_STATUS_ITEM(b, SI_title, "%s\n", afhi->tags.title);
+       WRITE_STATUS_ITEM(b, SI_year, "%s\n", afhi->tags.year);
+       WRITE_STATUS_ITEM(b, SI_album, "%s\n", afhi->tags.album);
+       WRITE_STATUS_ITEM(b, SI_comment, "%s\n", afhi->tags.comment);
        if (opts->mode == LS_MODE_MBOX) {
                struct osl_object lyrics_def;
                lyr_get_def_by_id(afsi->lyrics_id, &lyrics_def);
@@@ -978,8 -975,8 +978,8 @@@ static void make_inode_status_items(str
        ret = strftime(mtime_str, 29, "%b %d %Y", &mtime_tm);
        assert(ret > 0); /* number of bytes placed in mtime_str */
  out:
-       WRITE_STATUS_ITEM(pb, SI_MTIME, "%s\n", mtime_str);
-       WRITE_STATUS_ITEM(pb, SI_FILE_SIZE, "%ld\n", statbuf.st_size / 1024);
+       WRITE_STATUS_ITEM(pb, SI_mtime, "%s\n", mtime_str);
+       WRITE_STATUS_ITEM(pb, SI_file_size, "%ld\n", statbuf.st_size / 1024);
  }
  
  static int make_status_items(void)
        time_t current_time;
        int ret;
  
 +      if (!status_item_ls_data.path) /* no audio file open */
 +              return 0;
        ret = lls_parse(ARRAY_SIZE(argv), argv, cmd, &opts.lpr, NULL);
        assert(ret >= 0);
        time(&current_time);
        return ret;
  }
  
 +static int ls_hash_compare(const void *a, const void *b)
 +{
 +      struct ls_data *d1 = *(struct ls_data **)a, *d2 = *(struct ls_data **)b;
 +      return memcmp(d1->hash, d2->hash, HASH_SIZE);
 +}
 +
  static int ls_audio_format_compare(const void *a, const void *b)
  {
        struct ls_data *d1 = *(struct ls_data **)a, *d2 = *(struct ls_data **)b;
@@@ -1237,8 -1226,6 +1237,8 @@@ static int sort_matching_paths(struct l
                compar = ls_duration_compare; break;
        case LS_SORT_BY_AUDIO_FORMAT:
                compar = ls_audio_format_compare; break;
 +      case LS_SORT_BY_HASH:
 +              compar = ls_hash_compare; break;
        default:
                return -E_BAD_SORT;
        }
@@@ -1387,6 -1374,7 +1387,6 @@@ out
        return ret;
  }
  
 -/* TODO: flags -h (sort by hash) */
  static int com_ls(struct command_context *cc, struct lls_parse_result *lpr)
  {
        const struct lls_command *cmd = SERVER_CMD_CMD_PTR(LS);
                        opts->sorting = LS_SORT_BY_DURATION;
                else if (!strcmp(val, "a") || !strcmp(val, "audio-format"))
                        opts->sorting = LS_SORT_BY_AUDIO_FORMAT;
 +              else if (!strcmp(val, "h") || !strcmp(val, "hash"))
 +                      opts->sorting = LS_SORT_BY_HASH;
                else {
                        ret = -E_AFT_SYNTAX;
                        goto out;
@@@ -1926,7 -1912,11 +1926,7 @@@ out
  }
  EXPORT_SERVER_CMD_HANDLER(add);
  
 -/**
 - * Flags used by the touch command.
 - *
 - * \sa com_touch().
 - */
 +/** Flags used by the touch command. */
  enum touch_flags {
        /** Whether the \p FNM_PATHNAME flag should be passed to fnmatch(). */
        TOUCH_FLAG_FNM_PATHNAME = 1,
@@@ -2412,6 -2402,8 +2412,6 @@@ static int check_audio_file(struct osl_
   * \param aca Only ->pbout is used for diagnostics.
   *
   * \return Standard. Inconsistencies are reported but not regarded as an error.
 - *
 - * \sa com_check().
   */
  int aft_check_callback(struct afs_callback_arg *aca)
  {
@@@ -2480,7 -2472,7 +2480,7 @@@ int aft_check_attributes(uint64_t att_m
   *
   * \param flags Usual flags that are passed to osl_close_table().
   *
 - * \sa osl_close_table().
 + * \sa \ref osl_close_table().
   */
  static void aft_close(void)
  {
   *
   * \return Standard.
   *
 - * \sa osl_open_table().
 + * \sa \ref osl_open_table().
   */
  static int aft_open(const char *dir)
  {
@@@ -2571,16 -2563,6 +2571,16 @@@ static int aft_event_handler(enum afs_e
                        return ret;
                make_status_items();
                return 1;
 +      }
 +      case BLOB_RENAME:
 +      case BLOB_REMOVE:
 +      case BLOB_ADD: {
 +              /*
 +               * These events are rare. We don't bother to check whether the
 +               * current status items are affected and simply recreate them
 +               * every time.
 +               */
 +              make_status_items();
        } default:
                return 0;
        }
diff --combined audioc.c
+++ b/audioc.c
@@@ -116,7 -116,7 +116,7 @@@ static void version_completer(struct i9
  static void stat_completer(struct i9e_completion_info *ci,
                struct i9e_completion_result *cr)
  {
-       char *sia[] = {STATUS_ITEM_ARRAY NULL};
+       char *sia[] = {STATUS_ITEMS NULL};
        char *opts[] = {LSG_AUDIOD_CMD_STAT_OPTS, NULL};
  
        if (ci->word_num <= 2 && ci->word && ci->word[0] == '-')
@@@ -132,6 -132,7 +132,6 @@@ static void grab_completer(struct i9e_c
        i9e_complete_option(opts, ci, cr);
  }
  
 -I9E_DUMMY_COMPLETER(SUPERCOMMAND_UNAVAILABLE);
  static struct i9e_completer audiod_completers[] = {
  #define LSG_AUDIOD_CMD_CMD(_name) {.name = #_name, \
        .completer = _name ## _completer}
@@@ -331,7 -332,7 +331,7 @@@ static void handle_help_flag(void
   *
   * \return EXIT_SUCCESS or EXIT_FAILURE.
   *
 - * \sa send_cred_buffer(), para_audioc(1), para_audiod(1).
 + * \sa \ref send_cred_buffer(), para_audioc(1), para_audiod(1).
   */
  int main(int argc, char *argv[])
  {
diff --combined audiod.c
+++ b/audiod.c
@@@ -109,7 -109,9 +109,7 @@@ struct slot_info 
   * para_audiod uses \p MAX_STREAM_SLOTS different slots, each of which may
   * be associated with a receiver/filter/writer triple. This array holds all
   * information on the status of these slots.
 - *
 - * \sa struct slot_info
 - * */
 + */
  struct slot_info slot[MAX_STREAM_SLOTS];
  
  /** The vss status flags audiod is interested in. */
@@@ -165,8 -167,8 +165,8 @@@ struct status_task 
  char *stat_item_values[NUM_STAT_ITEMS] = {NULL};
  
  /**
 - * the current mode of operation of which can be changed by the on/off/cycle
 - * commands. It is either, AUDIOD_OFF, AUDIOD_ON or AUDIOD_STANDBY.
 + * The current mode of operation (AUDIOD_OFF, AUDIOD_ON or AUDIOD_STANDBY).
 + * Set by the on/off/cycle commands.
   */
  int audiod_status = AUDIOD_ON;
  
@@@ -177,20 -179,20 +177,20 @@@ static struct status_task status_task_s
  static uid_t *uid_whitelist;
  
  /**
 - * the task that calls the status command of para_server
 + * The task that calls the status command of para_server.
   *
 - * \sa struct status_task
 + * \sa \ref struct status_task.
   */
  static struct status_task *stat_task = &status_task_struct;
  
  struct command_task {
        /** The local listening socket. */
        int fd;
 -      /** the associated task structure */
 +      /** The associated task structure. */
        struct task *task;
  };
  
 -/** iterate over all supported audio formats */
 +/** Iterate over all supported audio formats. */
  #define FOR_EACH_AUDIO_FORMAT(af) for (af = 0; af < NUM_AUDIO_FORMATS; af++)
  
  /**
@@@ -666,7 -668,6 +666,7 @@@ static int open_receiver(int format
                EMBRACE(.name = name, .context = rn));
        ret = r->open(rn);
        if (ret < 0) {
 +              PARA_ERROR_LOG("could not open %s receiver\n", name);
                btr_remove_node(&rn->btrn);
                free(rn);
                return ret;
@@@ -802,38 -803,38 +802,38 @@@ static int update_item(int itemnum, cha
  {
        long unsigned sec, usec;
  
-       if (stat_task->clock_diff_count && itemnum != SI_CURRENT_TIME)
+       if (stat_task->clock_diff_count && itemnum != SI_current_time)
                return 1;
        free(stat_item_values[itemnum]);
        stat_item_values[itemnum] = para_strdup(buf);
        stat_client_write_item(itemnum);
        switch (itemnum) {
-       case SI_STATUS_FLAGS:
+       case SI_status_flags:
                stat_task->vss_status = 0;
                if (strchr(buf, 'N'))
                        stat_task->vss_status |= VSS_STATUS_FLAG_NEXT;
                if (strchr(buf, 'P'))
                        stat_task->vss_status |= VSS_STATUS_FLAG_PLAYING;
                break;
-       case SI_OFFSET:
+       case SI_offset:
                stat_task->offset_seconds = atoi(buf);
                break;
-       case SI_SECONDS_TOTAL:
+       case SI_seconds_total:
                stat_task->length_seconds = atoi(buf);
                break;
-       case SI_STREAM_START:
+       case SI_stream_start:
                if (sscanf(buf, "%lu.%lu", &sec, &usec) == 2) {
                        stat_task->server_stream_start.tv_sec = sec;
                        stat_task->server_stream_start.tv_usec = usec;
                }
                break;
-       case SI_CURRENT_TIME:
+       case SI_current_time:
                if (sscanf(buf, "%lu.%lu", &sec, &usec) == 2) {
                        struct timeval tv = {sec, usec};
                        compute_time_diff(&tv);
                }
                break;
-       case SI_FORMAT:
+       case SI_format:
                stat_task->current_audio_format_num
                        = get_audio_format_num(buf);
        }
@@@ -1385,10 -1386,10 +1385,10 @@@ static int status_post_select(struct sc
                client_open(argc, argv, &st->ct, NULL, NULL, st->btrn, s);
                set_stat_task_restart_barrier(5);
        }
-       free(stat_item_values[SI_BASENAME]);
-       stat_item_values[SI_BASENAME] = para_strdup(
+       free(stat_item_values[SI_basename]);
+       stat_item_values[SI_basename] = para_strdup(
                "no connection to para_server");
-       stat_client_write_item(SI_BASENAME);
+       stat_client_write_item(SI_basename);
        st->last_status_read = *now;
  out:
        start_stop_decoders();
diff --combined audiod_command.c
@@@ -82,7 -82,7 +82,7 @@@ static INITIALIZED_LIST_HEAD(client_lis
  static int num_clients;
  
  /** The list of all status items used by para_{server,audiod,gui}. */
- const char *status_item_list[] = {STATUS_ITEM_ARRAY};
+ const char *status_item_list[] = {STATUS_ITEMS};
  
  static void dump_stat_client_list(void)
  {
@@@ -416,7 -416,7 +416,7 @@@ EXPORT_AUDIOD_CMD_HANDLER(version
   * \return Positive on success, negative on errors, zero if there was no
   * connection to accept.
   *
 - * \sa para_accept(), recv_cred_buffer()
 + * \sa \ref para_accept(), \ref recv_cred_buffer().
   * */
  int handle_connect(int accept_fd, fd_set *rfds)
  {
@@@ -481,41 -481,41 +481,41 @@@ void audiod_status_dump(bool force
  {
        char *old, *new;
  
-       old = stat_item_values[SI_PLAY_TIME];
+       old = stat_item_values[SI_play_time];
        new = get_time_string();
        if (new) {
                if (force || !old || strcmp(old, new)) {
                        free(old);
-                       stat_item_values[SI_PLAY_TIME] = new;
-                       stat_client_write_item(SI_PLAY_TIME);
+                       stat_item_values[SI_play_time] = new;
+                       stat_client_write_item(SI_play_time);
                } else
                        free(new);
        }
  
        new = daemon_get_uptime_str(now);
-       old = stat_item_values[SI_AUDIOD_UPTIME];
+       old = stat_item_values[SI_audiod_uptime];
        if (force || !old || strcmp(old, new)) {
                free(old);
-               stat_item_values[SI_AUDIOD_UPTIME] = new;
-               stat_client_write_item(SI_AUDIOD_UPTIME);
+               stat_item_values[SI_audiod_uptime] = new;
+               stat_client_write_item(SI_audiod_uptime);
        } else
                free(new);
  
-       old = stat_item_values[SI_AUDIOD_STATUS];
+       old = stat_item_values[SI_audiod_status];
        new = audiod_status_string();
        if (force || !old || strcmp(old, new)) {
                free(old);
-               stat_item_values[SI_AUDIOD_STATUS] = new;
-               stat_client_write_item(SI_AUDIOD_STATUS);
+               stat_item_values[SI_audiod_status] = new;
+               stat_client_write_item(SI_audiod_status);
        } else
                free(new);
  
-       old = stat_item_values[SI_DECODER_FLAGS];
+       old = stat_item_values[SI_decoder_flags];
        new = audiod_get_decoder_flags();
        if (force || !old || strcmp(old, new)) {
                free(old);
-               stat_item_values[SI_DECODER_FLAGS] = new;
-               stat_client_write_item(SI_DECODER_FLAGS);
+               stat_item_values[SI_decoder_flags] = new;
+               stat_client_write_item(SI_decoder_flags);
        } else
                free(new);
  }
diff --combined command.c
+++ b/command.c
@@@ -107,18 -107,18 +107,18 @@@ static unsigned get_status(struct misc_
        clock_get_realtime(&current_time);
        /*
         * The calls to WRITE_STATUS_ITEM() below never fail because
 -       * b->max_size is zero (unlimited), see para_printf(). However, clang
 -       * is not smart enough to prove this and complains nevertheless.
 +       * b->max_size is zero (unlimited), see \ref para_printf(). However,
 +       * clang is not smart enough to prove this and complains nevertheless.
         * Casting the return value to void silences clang.
         */
-       (void)WRITE_STATUS_ITEM(&b, SI_STATUS, "%s\n", status);
-       (void)WRITE_STATUS_ITEM(&b, SI_STATUS_FLAGS, "%s\n", flags);
-       (void)WRITE_STATUS_ITEM(&b, SI_OFFSET, "%li\n", offset);
-       (void)WRITE_STATUS_ITEM(&b, SI_AFS_MODE, "%s\n", mmd->afs_mode_string);
-       (void)WRITE_STATUS_ITEM(&b, SI_STREAM_START, "%lu.%lu\n",
+       (void)WRITE_STATUS_ITEM(&b, SI_status, "%s\n", status);
+       (void)WRITE_STATUS_ITEM(&b, SI_status_flags, "%s\n", flags);
+       (void)WRITE_STATUS_ITEM(&b, SI_offset, "%li\n", offset);
+       (void)WRITE_STATUS_ITEM(&b, SI_afs_mode, "%s\n", mmd->afs_mode_string);
+       (void)WRITE_STATUS_ITEM(&b, SI_stream_start, "%lu.%lu\n",
                (long unsigned)nmmd->stream_start.tv_sec,
                (long unsigned)nmmd->stream_start.tv_usec);
-       (void)WRITE_STATUS_ITEM(&b, SI_CURRENT_TIME, "%lu.%lu\n",
+       (void)WRITE_STATUS_ITEM(&b, SI_current_time, "%lu.%lu\n",
                (long unsigned)current_time.tv_sec,
                (long unsigned)current_time.tv_usec);
        free(flags);
@@@ -227,7 -227,7 +227,7 @@@ static int check_sender_args(struct com
                struct lls_parse_result *lpr, struct sender_command_data *scd)
  {
        int i, ret;
 -      const char *subcmds[] = {SENDER_SUBCOMMANDS};
 +      const char * const subcmds[] = {SENDER_SUBCOMMANDS};
        const char *arg;
        char *errctx;
        unsigned num_inputs = lls_num_inputs(lpr);
                return -E_COMMAND_SYNTAX;
        scd->sender_num = i;
        arg = lls_input(1, lpr);
 -      for (i = 0; subcmds[i]; i++)
 +      for (i = 0; i < NUM_SENDER_CMDS; i++)
                if (!strcmp(subcmds[i], arg))
                        break;
 -      if (!subcmds[i])
 +      if (i == NUM_SENDER_CMDS)
                return -E_COMMAND_SYNTAX;
        scd->cmd_num = i;
        if (!senders[scd->sender_num].client_cmds[scd->cmd_num])
@@@ -426,40 -426,41 +426,40 @@@ EXPORT_SERVER_CMD_HANDLER(version)
  
  /** These status items are cleared if no audio file is currently open. */
  #define EMPTY_STATUS_ITEMS \
-       ITEM(PATH) \
-       ITEM(DIRECTORY) \
-       ITEM(BASENAME) \
-       ITEM(SCORE) \
-       ITEM(ATTRIBUTES_BITMAP) \
-       ITEM(ATTRIBUTES_TXT) \
-       ITEM(HASH) \
-       ITEM(IMAGE_ID) \
-       ITEM(IMAGE_NAME) \
-       ITEM(LYRICS_ID) \
-       ITEM(LYRICS_NAME) \
-       ITEM(BITRATE) \
-       ITEM(FORMAT) \
-       ITEM(FREQUENCY) \
-       ITEM(CHANNELS) \
-       ITEM(DURATION) \
-       ITEM(SECONDS_TOTAL) \
-       ITEM(NUM_PLAYED) \
-       ITEM(LAST_PLAYED) \
-       ITEM(TECHINFO) \
-       ITEM(ARTIST) \
-       ITEM(TITLE) \
-       ITEM(YEAR) \
-       ITEM(ALBUM) \
-       ITEM(COMMENT) \
-       ITEM(MTIME) \
-       ITEM(FILE_SIZE) \
-       ITEM(CHUNK_TIME) \
-       ITEM(NUM_CHUNKS) \
-       ITEM(AMPLIFICATION) \
+       ITEM(path) \
+       ITEM(directory) \
+       ITEM(basename) \
+       ITEM(score) \
+       ITEM(attributes_bitmap) \
+       ITEM(attributes_txt) \
+       ITEM(hash) \
+       ITEM(image_id) \
+       ITEM(image_name) \
+       ITEM(lyrics_id) \
+       ITEM(lyrics_name) \
+       ITEM(bitrate) \
+       ITEM(format) \
+       ITEM(frequency) \
+       ITEM(channels) \
+       ITEM(duration) \
+       ITEM(seconds_total) \
+       ITEM(num_played) \
+       ITEM(last_played) \
+       ITEM(techinfo) \
+       ITEM(artist) \
+       ITEM(title) \
+       ITEM(year) \
+       ITEM(album) \
+       ITEM(comment) \
+       ITEM(mtime) \
+       ITEM(file_size) \
+       ITEM(chunk_time) \
+       ITEM(num_chunks) \
+       ITEM(amplification) \
  
 -/**
 - * Write a list of audio-file related status items with empty values.
 - *
 - * This is used by vss when currently no audio file is open.
 +/*
 + * Create a set of audio-file related status items with empty values. These are
 + * written to stat clients when no audio file is open.
   */
  static unsigned empty_status_items(bool parser_friendly, char **result)
  {
@@@ -883,7 -884,7 +883,7 @@@ static int run_command(struct command_c
   * the function if the connection was not authenticated when the timeout
   * expires.
   *
 - * \sa alarm(2), crypt.c, crypt.h
 + * \sa alarm(2), \ref crypt.c, \ref crypt.h.
   */
  __noreturn void handle_connect(int fd, const char *peername)
  {
        unsigned char challenge_hash[HASH_SIZE];
        char *command = NULL, *buf = para_malloc(HANDSHAKE_BUFSIZE) /* must be on the heap */;
        size_t numbytes;
 -      struct command_context cc_struct = {.peer = peername}, *cc = &cc_struct;
 +      struct command_context cc_struct = {.u = NULL}, *cc = &cc_struct;
        struct iovec iov;
        struct connection_features cf;
  
diff --combined configure.ac
@@@ -54,6 -54,10 +54,6 @@@ AC_PATH_PROG([M4], [m4]
  test -z "$M4" && AC_MSG_ERROR(
        [The m4 macro processor 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
  
@@@ -67,11 -71,9 +67,11 @@@ AC_CHECK_LIB([osl], [osl_open_table], [
  LIB_SUBST_FLAGS(osl)
  UNSTASH_FLAGS
  ######################################################################## lopsub
 +HAVE_LOPSUB=yes
 +AC_PATH_PROG([LOPSUBGEN], [lopsubgen])
 +test -z "$LOPSUBGEN" && HAVE_LOPSUB=no
  STASH_FLAGS
  LIB_ARG_WITH([lopsub], [-llopsub])
 -HAVE_LOPSUB=yes
  AC_CHECK_HEADER(lopsub.h, [], [HAVE_LOPSUB=no])
  AC_CHECK_LIB([lopsub], [lls_merge], [], [HAVE_LOPSUB=no])
  if test $HAVE_LOPSUB = no; then AC_MSG_ERROR([
@@@ -163,12 -165,17 +163,12 @@@ AC_DEFINE_UNQUOTED(ICONV_CAST, $cast, [
  AC_MSG_RESULT($msg)
  UNSTASH_FLAGS
  ########################################################################### ucred
 -AC_MSG_CHECKING(for struct ucred)
 -AC_LINK_IFELSE([AC_LANG_PROGRAM([[
 +AC_CHECK_TYPE([struct ucred], [
 +      AC_DEFINE(HAVE_UCRED, 1, define to 1 you have struct ucred)
 +], [], [
        #include <sys/types.h>
        #include <sys/socket.h>
 -]], [[
 -      struct ucred sucred; sucred.pid=0;
 -]])],[have_ucred=yes],[have_ucred=no])
 -AC_MSG_RESULT($have_ucred)
 -if test ${have_ucred} = yes; then
 -      AC_DEFINE(HAVE_UCRED, 1, define to 1 you have struct ucred)
 -fi
 +])
  ########################################################################### curses
  STASH_FLAGS
  LIB_ARG_WITH([curses], [])
@@@ -179,12 -186,18 +179,12 @@@ curses_ldflags="$curses_ldflags $LIBS
  LIB_SUBST_FLAGS(curses)
  UNSTASH_FLAGS
  ########################################################################### ip_mreqn
 -AC_MSG_CHECKING(for struct ip_mreqn (UDPv4 multicast))
 -AC_LINK_IFELSE([AC_LANG_PROGRAM([[
 +AC_CHECK_TYPE([struct ip_mreqn], [
 +      AC_DEFINE(HAVE_IP_MREQN, 1, define to 1 if you have struct ip_mreqn)
 +], [], [
        #include <netdb.h>
        #include <net/if.h>
 -]], [[
 -      struct ip_mreqn mn;
 -      mn.imr_ifindex = 0;
 -]])],[have_ip_mreqn=yes],[have_ip_mreqn=no])
 -AC_MSG_RESULT($have_ip_mreqn)
 -if test ${have_ip_mreqn} = yes; then
 -      AC_DEFINE(HAVE_IP_MREQN, 1, define to 1 if you have struct ip_mreqn)
 -fi
 +])
  ########################################################################### ogg
  STASH_FLAGS
  LIB_ARG_WITH([ogg], [-logg])
@@@ -790,33 -803,9 +790,9 @@@ if test $HAVE_READLINE = yes; the
  fi
  audioc_objs="$audioc_errlist_objs"
  AC_SUBST(audioc_objs, add_dot_o($audioc_objs))
- ################################################################## status items
- status_items="basename status num_played mtime bitrate frequency file_size
- status_flags format score techinfo afs_mode
- attributes_txt decoder_flags audiod_status play_time attributes_bitmap
- offset seconds_total stream_start current_time audiod_uptime image_id
- lyrics_id duration directory lyrics_name image_name path hash channels
- last_played num_chunks chunk_time amplification artist title year album
- comment max_chunk_size"
- result=
- for i in $status_items; do
-       result="$result SI_$(echo $i | tr 'a-z' 'A-Z'), "
- done
- AC_DEFINE_UNQUOTED(STATUS_ITEM_ENUM, [$result],
-       [enum of all status items])
- result=
- for i in $status_items; do
-       result="$result \"$i\", "
- done
- AC_DEFINE_UNQUOTED(STATUS_ITEM_ARRAY, [$result],
-       [char * array of all status items])
  
  AC_DEFINE_UNQUOTED(AUDIO_FORMAT_HANDLERS, "$audio_format_handlers",
        [formats supported by para_server and para_afh])
  AC_SUBST(executables)
  
  AC_OUTPUT