]> git.tuebingen.mpg.de Git - paraslash.git/commitdiff
Merge branch 'refs/heads/t/doxygen'
authorAndre Noll <maan@tuebingen.mpg.de>
Fri, 21 Jul 2017 17:45:31 +0000 (19:45 +0200)
committerAndre Noll <maan@tuebingen.mpg.de>
Fri, 21 Jul 2017 17:51:17 +0000 (19:51 +0200)
This series contains an update of Doxyfile to a newer doxygen version
and an overhaul of the source code documentation. Several stale
references have been fixed. Other parts of the documentation have
been improved.

Cooking for almost a month.

* refs/heads/t/doxygen:
  aft.c: Trivial spelling/whitespace fixes.
  afh: Expand documentation of init function declarations.
  filter: Remove duplicate documentation of filter_get().
  doxygen: Improve documentation of struct receiver.
  doxygen: Add \ref to references.
  Improve documentation of mm.c and mm.h.
  doxygen: Don't refer to Black Hats Manual.
  doxygen: Don't refer to libosl functions.
  doxygen: Trivial cleanups.
  doxygen: Remove some stale doxygen references.
  recv: Explain user data mechanism.
  Update to doxygen-1.8.11.

The merge resulted in a few conflicts which were easy to resolve.

1  2 
NEWS.md
afh_common.c
afs.h
aft.c
error.h
mood.c
play.c
string.c

diff --combined NEWS.md
index 313446f82956fd1f344ee483a45dcef6d9436adb,60b942389ffe1a7d71a61ced088965995548d416..5398d3a53a423716b0243a7543f9a3bbd15c1162
+++ b/NEWS.md
@@@ -1,13 -1,6 +1,16 @@@
  NEWS
  ====
  
 +------------------------------------------------
 +0.6.1 (to be announced) "hyperbolic correlation"
 +------------------------------------------------
 +
 +- The contents of overview.pdf have been integrated into the user
 +  manual.
++- The doxygen source browser has been disabled temporarily. The
++  API reference is still online, though.
++- Overhaul of the source code documentation.
 +
  -------------------------------
  0.6.0 (2017-04-28) "fuzzy flux"
  -------------------------------
diff --combined afh_common.c
index b47def871a94e781c4afe3987c1f68071e1ea0b2,0d8d905c4a9c764097fa6e7acf6023c50454f958..1614c27c6c9dd6d7588399ca164a9fd754087e83
  #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_init, ogg_init, aac_afh_init, wma_afh_init,
 +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 */
@@@ -28,7 -37,7 +38,7 @@@ const char *status_item_list[] = {STATU
   *
   * We always define the full array of audio formats even if some audio formats
   * were not compiled in. This is because for each audio file the number of its
 - * audio format is stored in the database. We don't want that numbers to become
 + * audio format is stored in the database. We don't want these numbers to become
   * stale just because the user installed a new version of paraslash that
   * supports a different set of audio formats.
   *
  static struct audio_format_handler afl[] = {
        {
                .name = "mp3",
 -              .init = mp3_init,
 +              .init = mp3_afh_init,
        },
        {
                .name = "ogg",
  #if defined(HAVE_OGG) && defined(HAVE_VORBIS)
 -              .init = ogg_init,
 +              .init = ogg_afh_init,
  #endif
        },
        {
diff --combined afs.h
index c2a8f2e9435b2dfaebe784167ab6255e42529bae,e113915ccb69942611f3e4166852b3cb0f2052ef..ea4b497e4b3b1bc2e54ab202962638ab25598d4d
--- 1/afs.h
--- 2/afs.h
+++ b/afs.h
@@@ -141,7 -141,7 +141,7 @@@ struct pattern_match_data 
        unsigned loop_col_num;
        /** Data from this column is matched against the given patterns. */
        unsigned match_col_num;
-       /** \see pattern_match_flags. */
+       /** \see \ref pattern_match_flags. */
        unsigned pm_flags;
        /** This value is passed verbatim to fnmatch(). */
        int fnmatch_flags;
@@@ -174,14 -174,16 +174,14 @@@ struct afs_callback_arg 
   * Therefore afs commands typically consist of two functions: The command
   * handler and the corresponding callback function that runs in afs context.
   *
-  * \sa send_callback_request().
+  * \sa \ref send_callback_request().
   */
  typedef int afs_callback(struct afs_callback_arg *aca);
  
  /**
 - * Callbacks send chunks to data back to the command handler. Pointers to
 - * this type of function are used by \ref send_callback_request and friends
 - * to deal with the data in the command handler process.
 - *
 - * \sa \ref send_callback_request().
 + * Some AFS callbacks need to send data back to the command handler. Pointers
 + * to this type of function are passed to \ref send_callback_request() and
 + * related functions to dispatch the data in the command handler process.
   */
  typedef int callback_result_handler(struct osl_object *result, uint8_t band, void *private);
  int afs_cb_result_handler(struct osl_object *result, uint8_t band, void *private);
diff --combined aft.c
index 0c4c93280a3f409b7a791aa0b33c5e82369da732,d58f9daf014c0237148db3e0837f11f003bd0230..c2642ed3d13ceb139335cdef0c06c6999cd2ae7b
--- 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,7 -365,10 +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;
        sprintf(p, "%s", afhi->tags.comment);
  }
  
 +/* does not load the chunk table */
  static void load_afhi(const char *buf, struct afh_info *afhi)
  {
        afhi->seconds_total = read_u32(buf + AFHI_SECONDS_TOTAL_OFFSET);
@@@ -529,7 -531,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.
@@@ -553,7 -555,7 +556,7 @@@ int get_audio_file_path_of_row(const st
   *
   * \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)
@@@ -590,12 -592,6 +593,10 @@@ static int get_hash_of_row(const struc
   * \param afhi Result pointer.
   *
   * \return The return value of the underlying call to osl_get_object().
-  *
-  * \sa get_chunk_table_of_row().
 + *
 + * 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().
   */
  int get_afhi_of_row(const struct osl_row *row, struct afh_info *afhi)
  {
@@@ -1912,11 -1908,7 +1913,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,
@@@ -2402,8 -2394,6 +2399,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)
  {
@@@ -2472,7 -2462,7 +2467,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)
  {
diff --combined error.h
index 407859ca5a591b42ca8a489ee58aeeb76e5b3c8e,ea25f8ccf47f33680bf15ae3569427c3b3e54d60..e5d2469bd5492986c231eeded9b311f0753c804f
+++ b/error.h
@@@ -8,7 -8,6 +8,7 @@@
  
  /** Codes and messages. */
  #define PARA_ERRORS \
 +      PARA_ERROR(SUCCESS, "success"), \
        PARA_ERROR(AACDEC_INIT, "failed to init aac decoder"), \
        PARA_ERROR(AAC_DECODE, "aac decode error"), \
        PARA_ERROR(ACL_PERM, "access denied by acl"), \
@@@ -339,8 -338,8 +339,8 @@@ _static_inline_ int osl(int ret
  /**
   * Wrapper for lopsub library calls.
   *
-  * \param ret See osl().
-  * \return See osl().
+  * \param ret See \ref osl().
+  * \return See \ref osl().
   */
  _static_inline_ int lls(int ret)
  {
diff --combined mood.c
index 208bdc45ea5adf7d9c4ca67e505902d694718306,92bef0fa8c04554da7b442cb63dbfb561ee828bd..315ef0cbdc61b7de1a3bbbd8f8683d7ab81d9c81
--- 1/mood.c
--- 2/mood.c
+++ b/mood.c
@@@ -59,15 -59,13 +59,13 @@@ struct mood_item 
        struct list_head mood_item_node;
  };
  
- /**
-  * Created from the mood definition by mood_open().
+ /*
+  * Created from the mood definition by \ref change_current_mood().
   *
   * When a mood is opened, each line of its definition is investigated, and a
-  * corresponding mood item is produced. Each mood line starts with \p accept,
-  * \p deny, or \p score which determines the type of the mood line.  For each
-  * such type a linked list is maintained whose entries are the mood items.
-  *
-  * \sa mood_item, mood_open().
+  * corresponding mood item is produced. Each mood line starts with accept,
+  * deny, or score which determines the type of the mood line. For each such
+  * type a linked list is maintained whose entries are the mood items.
   */
  struct mood {
        /** The name of this mood. */
@@@ -82,7 -80,7 +80,7 @@@
  
  /*
   * If current_mood is NULL then no mood is currently open. If
-  * current_mood->name is NULL, the dummy mood is currently open
+  * current_mood->name is NULL, the dummy mood is currently open.
   */
  static struct mood *current_mood;
  
@@@ -142,8 -140,8 +140,8 @@@ static bool get_item_score(struct mood_
  }
  
  /* returns 1 if row admissible, 0 if not, negative on errors */
 -static int compute_mood_score(const struct osl_row *aft_row, struct mood *m,
 -              long *result)
 +static int row_is_admissible(const struct osl_row *aft_row, struct mood *m,
 +              long *scorep)
  {
        struct mood_item *item;
        int ret;
        if (!m)
                return -E_NO_MOOD;
        ret = get_afsi_of_row(aft_row, &afsi);
 -      if (ret< 0)
 +      if (ret < 0)
                return ret;
        ret = get_afhi_of_row(aft_row, &afhi);
 -      if (ret< 0)
 +      if (ret < 0)
                return ret;
        ret = get_audio_file_path_of_row(aft_row, &path);
 -      if (ret< 0)
 +      if (ret < 0)
                return ret;
        /* reject audio file if it matches any entry in the deny list */
        list_for_each_entry(item, &m->deny_list, mood_item_node) {
        }
        if (score_arg_sum)
                score /= score_arg_sum;
 -      *result = score;
 +      *scorep = score;
        return 1;
  }
  
@@@ -259,6 -257,7 +257,6 @@@ struct mood_line_parser_data 
   * <score> is either an integer or "random" which assigns a random score to
   * all matching files
   */
 -
  static int parse_mood_line(char *mood_line, void *data)
  {
        struct mood_line_parser_data *mlpd = data;
@@@ -523,9 -522,7 +521,7 @@@ static int del_afs_statistics(const str
        return 1;
  }
  
- /**
-  * Structure used during mood_open().
-  *
+ /*
   * At mood open time we determine the set of admissible files for the given
   * mood. The mood score of each admissible file is computed by adding up all
   * mood item scores. Next, we update the afs statistics and append a struct
   * the afs_statistics and the current time) to the mood score. Finally, all
   * audio files in the temporary array are added to the score table and the
   * array is freed.
-  *
-  * \sa mood_method, admissible_array.
   */
  struct admissible_file_info
  {
@@@ -571,7 -566,7 +565,7 @@@ static int add_if_admissible(struct osl
        int ret;
        long score = 0;
  
 -      ret = compute_mood_score(aft_row, aa->m, &score);
 +      ret = row_is_admissible(aft_row, aa->m, &score);
        if (ret <= 0)
                return ret;
        if (statistics.num >= aa->size) {
@@@ -630,8 -625,7 +624,8 @@@ _static_inline_ int64_t update_quadrati
        return old_qd + delta * (sigma - 2 * old_sum / n - delta / n);
  }
  
 -static int update_afs_statistics(struct afs_info *old_afsi, struct afs_info *new_afsi)
 +static int update_afs_statistics(struct afs_info *old_afsi,
 +              struct afs_info *new_afsi)
  {
        unsigned n;
        int ret = get_num_admissible_files(&n);
@@@ -679,7 -673,7 +673,7 @@@ static int delete_from_statistics_and_s
   *
   * \return Positive on success, negative on errors.
   *
-  * \sa score_delete().
+  * \sa \ref score_delete().
   */
  static int mood_delete_audio_file(const struct osl_row *aft_row)
  {
@@@ -718,7 -712,7 +712,7 @@@ static int mood_update_audio_file(cons
        if (ret < 0)
                return ret;
        was_admissible = ret;
 -      ret = compute_mood_score(aft_row, current_mood, &score);
 +      ret = row_is_admissible(aft_row, current_mood, &score);
        if (ret < 0)
                return ret;
        is_admissible = (ret > 0);
@@@ -782,8 -776,7 +776,7 @@@ static void log_statistics(void
  /**
   * Close the current mood.
   *
-  * Free all resources of the current mood which were allocated during
-  * mood_open().
+  * Frees all resources of the current mood.
   */
  void close_current_mood(void)
  {
   * \return Positive on success, negative on errors. Loading the dummy mood
   * always succeeds.
   *
-  * \sa struct admissible_file_info, struct admissible_array, struct
-  * afs_info::last_played, mood_close().
+  * \sa struct \ref afs_info::last_played.
   */
  int change_current_mood(const char *mood_name)
  {
@@@ -854,19 -846,14 +846,15 @@@ out
        free(aa.array);
        return ret;
  }
- /**
 +
+ /*
   * Close and re-open the current mood.
   *
-  * This function is used if changes to the audio file table or the
-  * attribute table were made that render the current list of admissible
-  * files useless. For example, if an attribute is removed from the
-  * attribute table, this function is called.
-  *
-  * \return Positive on success, negative on errors. If no mood is currently
-  * open, the function returns success.
+  * This function is called on events which render the current list of
+  * admissible files useless, for example if an attribute is removed from the
+  * attribute table.
   *
-  * \sa mood_open(), mood_close().
+  * If no mood is currently open, the function returns success.
   */
  static int reload_current_mood(void)
  {
diff --combined play.c
index 7b8192d46172a73b33869603630b2b02a4f28bf8,7ffcd9ed7b24a83d744d99d74f841128560c7c44..5fbf44c61817876c11144eaa94dbd36a507082f5
--- 1/play.c
--- 2/play.c
+++ b/play.c
@@@ -8,6 -8,7 +8,6 @@@
  
  #include <regex.h>
  #include <signal.h>
 -#include <inttypes.h>
  #include <lopsub.h>
  
  #include "recv_cmd.lsg.h"
@@@ -85,7 -86,7 +85,7 @@@ struct play_task 
        struct filter_node fn;
        struct writer_node wn;
  
-       /* See comment to enum state_change_request_type above */
+       /* See comment to enum \ref state_change_request_type above. */
        enum state_change_request_type rq;
        /* only relevant if rq == CRT_FILE_CHANGE */
        unsigned next_file;
        char *afhi_txt;
  };
  
 -typedef int (*play_cmd_handler_t)(struct play_task *pt,
 -              struct lls_parse_result *lpr);
 +typedef int (*play_cmd_handler_t)(struct lls_parse_result *lpr);
  struct play_command_info {
        play_cmd_handler_t handler;
  };
@@@ -125,7 -127,7 +125,7 @@@ INIT_STDERR_LOGGING(loglevel)
  char *stat_item_values[NUM_STAT_ITEMS] = {NULL};
  
  static struct sched sched = {.max_fileno = 0};
 -static struct play_task play_task;
 +static struct play_task play_task, *pt = &play_task;
  
  #define AFH_RECV_CMD (lls_cmd(LSG_RECV_CMD_CMD_AFH, recv_cmd_suite))
  #define AFH_RECV ((struct receiver *)lls_user_data(AFH_RECV_CMD))
@@@ -226,7 -228,7 +226,7 @@@ fail
        exit(EXIT_FAILURE);
  }
  
 -static char get_playback_state(struct play_task *pt)
 +static char get_playback_state(void)
  {
        switch (pt->rq) {
        case CRT_NONE: return pt->playing? 'P' : 'U';
        assert(false);
  };
  
 -static long unsigned get_play_time(struct play_task *pt)
 +static long unsigned get_play_time(void)
  {
 -      char state = get_playback_state(pt);
 +      char state = get_playback_state();
        long unsigned result;
  
        if (state != 'P' && state != 'U')
  }
  
  
 -static void wipe_receiver_node(struct play_task *pt)
 +static void wipe_receiver_node(void)
  {
        PARA_NOTICE_LOG("cleaning up receiver node\n");
        btr_remove_node(&pt->rn.btrn);
  }
  
  /* returns: 0 not eof, 1: eof, < 0: fatal error.  */
 -static int get_playback_error(struct play_task *pt)
 +static int get_playback_error(void)
  {
        int err;
  
        return err;
  }
  
 -static int eof_cleanup(struct play_task *pt)
 +static int eof_cleanup(void)
  {
        const struct filter *decoder;
        const struct writer *w = writer_get(-1); /* default writer */
        int ret;
  
 -      ret = get_playback_error(pt);
 +      ret = get_playback_error();
        if (ret == 0)
                return ret;
        PARA_NOTICE_LOG("cleaning up wn/fn nodes\n");
         * paused.
         */
        if (ret < 0)
 -              wipe_receiver_node(pt);
 +              wipe_receiver_node();
        return ret;
  }
  
@@@ -350,7 -352,7 +350,7 @@@ static struct btr_node *new_recv_btrn(s
                        .handler = AFH_RECV->execute));
  }
  
 -static int open_new_file(struct play_task *pt)
 +static int open_new_file(void)
  {
        int ret;
        const char *path = get_playlist_file(pt->next_file);
        char *argv[] = {"play", "-f", tmp, "-b", "0", NULL};
  
        PARA_NOTICE_LOG("next file: %s\n", path);
 -      wipe_receiver_node(pt);
 +      wipe_receiver_node();
        pt->start_chunk = 0;
        pt->rn.btrn = new_recv_btrn(&pt->rn);
        ret = lls(lls_parse(ARRAY_SIZE(argv) - 1, argv, AFH_RECV_CMD,
        }
        return 1;
  fail:
 -      wipe_receiver_node(pt);
 +      wipe_receiver_node();
        return ret;
  }
  
 -static int load_file(struct play_task *pt)
 +static int load_file(void)
  {
        const char *af;
        char *tmp, buf[20];
  
        btr_remove_node(&pt->rn.btrn);
        if (!pt->rn.receiver || pt->next_file != pt->current_file) {
 -              ret = open_new_file(pt);
 +              ret = open_new_file();
                if (ret < 0)
                        return ret;
        } else {
        register_writer_node(&pt->wn, pt->fn.btrn, &sched);
        return 1;
  fail:
 -      wipe_receiver_node(pt);
 +      wipe_receiver_node();
        return ret;
  }
  
 -static int next_valid_file(struct play_task *pt)
 +static int next_valid_file(void)
  {
        int i, j = pt->current_file;
        unsigned num_inputs = lls_num_inputs(play_lpr);
        return -E_NO_VALID_FILES;
  }
  
 -static int load_next_file(struct play_task *pt)
 +static int load_next_file(void)
  {
        int ret;
  
  again:
        if (pt->rq == CRT_NONE) {
                pt->start_chunk = 0;
 -              ret = next_valid_file(pt);
 +              ret = next_valid_file();
                if (ret < 0)
                        return ret;
                pt->next_file = ret;
        } else if (pt->rq == CRT_REPOS)
                pt->next_file = pt->current_file;
 -      ret = load_file(pt);
 +      ret = load_file();
        if (ret < 0) {
                PARA_ERROR_LOG("%s: marking file as invalid\n",
                        para_strerror(-ret));
        return ret;
  }
  
 -static void kill_stream(struct play_task *pt)
 +static void kill_stream(void)
  {
        if (pt->wn.task)
                task_notify(pt->wn.task, E_EOF);
  #ifdef HAVE_READLINE
  
  /* only called from com_prev(), nec. only if we have readline */
 -static int previous_valid_file(struct play_task *pt)
 +static int previous_valid_file(void)
  {
        int i, j = pt->current_file;
        unsigned num_inputs = lls_num_inputs(play_lpr);
@@@ -727,7 -729,7 +727,7 @@@ static struct i9e_completer pp_complete
        {.name = NULL}
  };
  
 -static void attach_stdout(struct play_task *pt, const char *name)
 +static void attach_stdout(const char *name)
  {
        if (pt->btrn)
                return;
        i9e_attach_to_stdout(pt->btrn);
  }
  
 -static void detach_stdout(struct play_task *pt)
 +static void detach_stdout(void)
  {
        btr_remove_node(&pt->btrn);
  }
  
 -static int com_quit(struct play_task *pt,
 -              __a_unused struct lls_parse_result *lpr)
 +static int com_quit(__a_unused struct lls_parse_result *lpr)
  {
        pt->rq = CRT_TERM_RQ;
        return 0;
  }
  EXPORT_PLAY_CMD_HANDLER(quit);
  
 -static int com_help(struct play_task *pt, struct lls_parse_result *lpr)
 +static int com_help(struct lls_parse_result *lpr)
  {
        int i, ret;
        char *buf, *errctx;
  }
  EXPORT_PLAY_CMD_HANDLER(help);
  
 -static int com_info(struct play_task *pt,
 -              __a_unused struct lls_parse_result *lpr)
 +static int com_info(__a_unused struct lls_parse_result *lpr)
  {
        char *buf;
        size_t sz;
  }
  EXPORT_PLAY_CMD_HANDLER(info);
  
 -static void list_file(struct play_task *pt, int num)
 +static void list_file(int num)
  {
        char *buf;
        size_t sz;
        btr_add_output(buf, sz, pt->btrn);
  }
  
 -static int com_tasks(struct play_task *pt,
 -              __a_unused struct lls_parse_result *lpr)
 +static int com_tasks(__a_unused struct lls_parse_result *lpr)
  {
        static char state;
        char *buf;
  
        buf = get_task_list(&sched);
        btr_add_output(buf, strlen(buf), pt->btrn);
 -      state = get_playback_state(pt);
 +      state = get_playback_state();
        sz = xasprintf(&buf, "state: %c\n", state);
        btr_add_output(buf, sz, pt->btrn);
        return 0;
  }
  EXPORT_PLAY_CMD_HANDLER(tasks);
  
 -static int com_ls(struct play_task *pt,
 -      __a_unused struct lls_parse_result *lpr)
 +static int com_ls(__a_unused struct lls_parse_result *lpr)
  {
        int i;
        unsigned num_inputs = lls_num_inputs(play_lpr);
  
        for (i = 0; i < num_inputs; i++)
 -              list_file(pt, i);
 +              list_file(i);
        return 0;
  }
  EXPORT_PLAY_CMD_HANDLER(ls);
  
 -static int com_play(struct play_task *pt, struct lls_parse_result *lpr)
 +static int com_play(struct lls_parse_result *lpr)
  {
        int32_t x;
        int ret;
                free(errctx);
                return ret;
        }
 -      state = get_playback_state(pt);
 +      state = get_playback_state();
        if (lls_num_inputs(lpr) == 0) {
                if (state == 'P')
                        return 0;
                return ret;
        if (x < 0 || x >= lls_num_inputs(play_lpr))
                return -ERRNO_TO_PARA_ERROR(EINVAL);
 -      kill_stream(pt);
 +      kill_stream();
        pt->next_file = x;
        pt->rq = CRT_FILE_CHANGE;
        return 0;
  }
  EXPORT_PLAY_CMD_HANDLER(play);
  
 -static int com_pause(struct play_task *pt,
 -              __a_unused struct lls_parse_result *lpr)
 +static int com_pause(__a_unused struct lls_parse_result *lpr)
  {
        char state;
        long unsigned seconds, ss;
  
 -      state = get_playback_state(pt);
 +      state = get_playback_state();
        pt->playing = false;
        if (state != 'P')
                return 0;
 -      seconds = get_play_time(pt);
 +      seconds = get_play_time();
        pt->playing = false;
        ss = 0;
        if (pt->seconds > 0)
        ss = PARA_MAX(ss, 0UL);
        ss = PARA_MIN(ss, pt->num_chunks);
        pt->start_chunk = ss;
 -      kill_stream(pt);
 +      kill_stream();
        return 0;
  }
  EXPORT_PLAY_CMD_HANDLER(pause);
  
 -static int com_prev(struct play_task *pt,
 -      __a_unused struct lls_parse_result *lpr)
 +static int com_prev(__a_unused struct lls_parse_result *lpr)
  {
        int ret;
  
 -      ret = previous_valid_file(pt);
 +      ret = previous_valid_file();
        if (ret < 0)
                return ret;
 -      kill_stream(pt);
 +      kill_stream();
        pt->next_file = ret;
        pt->rq = CRT_FILE_CHANGE;
        pt->start_chunk = 0;
  }
  EXPORT_PLAY_CMD_HANDLER(prev);
  
 -static int com_next(struct play_task *pt,
 -              __a_unused struct lls_parse_result *lpr)
 +static int com_next(__a_unused struct lls_parse_result *lpr)
  {
        int ret;
  
 -      ret = next_valid_file(pt);
 +      ret = next_valid_file();
        if (ret < 0)
                return ret;
 -      kill_stream(pt);
 +      kill_stream();
        pt->next_file = ret;
        pt->rq = CRT_FILE_CHANGE;
        pt->start_chunk = 0;
  }
  EXPORT_PLAY_CMD_HANDLER(next);
  
 -static int com_fg(struct play_task *pt,
 -              __a_unused struct lls_parse_result *lpr)
 +static int com_fg(__a_unused struct lls_parse_result *lpr)
  {
        pt->background = false;
        return 0;
  }
  EXPORT_PLAY_CMD_HANDLER(fg);
  
 -static int com_bg(struct play_task *pt,
 -      __a_unused struct lls_parse_result *lpr)
 +static int com_bg(__a_unused struct lls_parse_result *lpr)
  {
        pt->background = true;
        return 0;
  }
  EXPORT_PLAY_CMD_HANDLER(bg);
  
 -static int com_jmp(struct play_task *pt, struct lls_parse_result *lpr)
 +static int com_jmp(struct lls_parse_result *lpr)
  {
        int32_t percent;
        int ret;
        if (percent < 0 || percent > 100)
                return -ERRNO_TO_PARA_ERROR(EINVAL);
        if (percent == 100)
 -              return com_next(pt, NULL);
 +              return com_next(NULL);
        if (pt->playing && !pt->fn.btrn)
                return 0;
        pt->start_chunk = percent * pt->num_chunks / 100;
        if (!pt->playing)
                return 0;
        pt->rq = CRT_REPOS;
 -      kill_stream(pt);
 +      kill_stream();
        return 0;
  }
  EXPORT_PLAY_CMD_HANDLER(jmp);
  
 -static int com_ff(struct play_task *pt, struct lls_parse_result *lpr)
 +static int com_ff(struct lls_parse_result *lpr)
  {
        int32_t seconds;
        char *errctx;
                return ret;
        if (pt->playing && !pt->fn.btrn)
                return 0;
 -      seconds += get_play_time(pt);
 +      seconds += get_play_time();
        seconds = PARA_MIN(seconds, (typeof(seconds))pt->seconds - 4);
        seconds = PARA_MAX(seconds, 0);
        pt->start_chunk = pt->num_chunks * seconds / pt->seconds;
        if (!pt->playing)
                return 0;
        pt->rq = CRT_REPOS;
 -      kill_stream(pt);
 +      kill_stream();
        return 0;
  }
  EXPORT_PLAY_CMD_HANDLER(ff);
  
 -static int run_command(char *line, struct play_task *pt)
 +static int run_command(char *line)
  {
        int ret, argc;
        char **argv = NULL;
        struct lls_parse_result *lpr;
        const struct lls_command *cmd;
  
 -      attach_stdout(pt, __FUNCTION__);
 +      attach_stdout(__FUNCTION__);
        ret = create_argv(line, " ", &argv);
        if (ret < 0)
                goto out;
        if (ret < 0)
                goto out;
        pci = lls_user_data(cmd);
 -      ret = pci->handler(pt, lpr);
 +      ret = pci->handler(lpr);
        lls_free_parse_result(lpr, cmd);
  out:
        if (errctx)
  
  static int play_i9e_line_handler(char *line)
  {
 -      return run_command(line, &play_task);
 +      return run_command(line);
  }
  
  static int play_i9e_key_handler(int key)
  {
 -      struct play_task *pt = &play_task;
        int idx = get_key_map_idx(key);
        char *seq = get_key_map_seq(key);
        char *cmd = get_key_map_cmd(key);
        PARA_NOTICE_LOG("pressed %d: %s key #%d (%s -> %s)\n",
                key, internal? "internal" : "user-defined",
                idx, seq, cmd);
 -      run_command(cmd, pt);
 +      run_command(cmd);
        free(seq);
        free(cmd);
        pt->next_update = *now;
@@@ -1081,7 -1093,7 +1081,7 @@@ static struct i9e_client_info ici = 
  
  static void sigint_handler(int sig)
  {
 -      play_task.background = true;
 +      pt->background = true;
        i9e_signal_dispatch(sig);
  }
  
   * stderr. Once the i9e subsystem has been initialized, we switch to the i9e
   * log facility.
   */
 -static void session_open(struct play_task *pt)
 +static void session_open(void)
  {
        int ret;
        char *history_file;
@@@ -1134,7 -1146,7 +1134,7 @@@ out
        exit(EXIT_FAILURE);
  }
  
 -static void session_update_time_string(struct play_task *pt, char *str, unsigned len)
 +static void session_update_time_string(char *str, unsigned len)
  {
        if (pt->background)
                return;
   * terminates. Subsequent calls to i9e_get_error() then return negative and we
   * are allowed to call i9e_close() and terminate as well.
   */
 -static int session_post_select(__a_unused struct sched *s, struct play_task *pt)
 +static int session_post_select(__a_unused struct sched *s)
  {
        int ret;
  
        if (pt->background)
 -              detach_stdout(pt);
 +              detach_stdout();
        else
 -              attach_stdout(pt, __FUNCTION__);
 +              attach_stdout(__FUNCTION__);
        ret = i9e_get_error();
        if (ret < 0) {
 -              kill_stream(pt);
 +              kill_stream();
                i9e_close();
                para_log = stderr_log;
                free(ici.history_file);
                return ret;
        }
 -      if (get_playback_state(pt) == 'X')
 +      if (get_playback_state() == 'X')
                i9e_signal_dispatch(SIGTERM);
        return 0;
  }
  
  #else /* HAVE_READLINE */
  
 -static int session_post_select(struct sched *s, struct play_task *pt)
 +static int session_post_select(struct sched *s)
  {
        char c;
  
                return 0;
        if (read(STDIN_FILENO, &c, 1))
                do_nothing;
 -      kill_stream(pt);
 +      kill_stream();
        return 1;
  }
  
 -static void session_open(__a_unused struct play_task *pt)
 +static void session_open(void)
  {
  }
  
 -static void session_update_time_string(__a_unused struct play_task *pt,
 -              char *str, __a_unused unsigned len)
 +static void session_update_time_string(char *str, __a_unused unsigned len)
  {
        printf("\r%s     ", str);
        fflush(stdout);
  }
  #endif /* HAVE_READLINE */
  
 -static void play_pre_select(struct sched *s, void *context)
 +static void play_pre_select(struct sched *s, __a_unused void *context)
  {
 -      struct play_task *pt = context;
        char state;
  
        para_fd_set(STDIN_FILENO, &s->rfds, &s->max_fileno);
 -      state = get_playback_state(pt);
 +      state = get_playback_state();
        if (state == 'R' || state == 'F' || state == 'X')
                return sched_min_delay(s);
        sched_request_barrier_or_min_delay(&pt->next_update, s);
  }
  
 -static unsigned get_time_string(struct play_task *pt, char **result)
 +static unsigned get_time_string(char **result)
  {
        int seconds, length;
 -      char state = get_playback_state(pt);
 +      char state = get_playback_state();
  
        /* do not return anything if things are about to change */
        if (state != 'P' && state != 'U') {
        length = pt->seconds;
        if (length == 0)
                return xasprintf(result, "0:00 [0:00] (0%%/0:00)");
 -      seconds = get_play_time(pt);
 +      seconds = get_play_time();
        return xasprintf(result, "#%u: %d:%02d [%d:%02d] (%d%%/%d:%02d) %s",
                pt->current_file,
                seconds / 60,
        );
  }
  
 -static int play_post_select(struct sched *s, void *context)
 +static int play_post_select(struct sched *s, __a_unused void *context)
  {
 -      struct play_task *pt = context;
        int ret;
  
 -      ret = eof_cleanup(pt);
 +      ret = eof_cleanup();
        if (ret < 0) {
                pt->rq = CRT_TERM_RQ;
                return 0;
        }
 -      ret = session_post_select(s, pt);
 +      ret = session_post_select(s);
        if (ret < 0)
                goto out;
        if (!pt->wn.btrn && !pt->fn.btrn) {
 -              char state = get_playback_state(pt);
 +              char state = get_playback_state();
                if (state == 'P' || state == 'R' || state == 'F') {
                        PARA_NOTICE_LOG("state: %c\n", state);
 -                      ret = load_next_file(pt);
 +                      ret = load_next_file();
                        if (ret < 0) {
                                PARA_ERROR_LOG("%s\n", para_strerror(-ret));
                                pt->rq = CRT_TERM_RQ;
        }
        if (tv_diff(now, &pt->next_update, NULL) >= 0) {
                char *str;
 -              unsigned len = get_time_string(pt, &str);
 +              unsigned len = get_time_string(&str);
                struct timeval delay = {.tv_sec = 0, .tv_usec = 100 * 1000};
                if (str && len > 0)
 -                      session_update_time_string(pt, str, len);
 +                      session_update_time_string(str, len);
                free(str);
                tv_add(now, &delay, &pt->next_update);
        }
@@@ -1294,6 -1309,7 +1294,6 @@@ out
  int main(int argc, char *argv[])
  {
        int ret;
 -      struct play_task *pt = &play_task;
        unsigned num_inputs;
  
        /* needed this early to make help work */
        sched.default_timeout.tv_sec = 5;
        parse_config_or_die(argc, argv);
        AFH_RECV->init();
 -      session_open(pt);
 +      session_open();
        num_inputs = lls_num_inputs(play_lpr);
        init_shuffle_map();
        pt->invalid = para_calloc(sizeof(*pt->invalid) * num_inputs);
diff --combined string.c
index 8dddd2fdb96d3b0ffedb41861e94e55e3cba9510,5eb1606e59ef546d6a7a55ce36b509a29c2dae18..e675502cf6707240a61be523c6fb510692991acd
+++ b/string.c
@@@ -10,6 -10,7 +10,6 @@@
  
  #include <pwd.h>
  #include <sys/utsname.h> /* uname() */
 -#include <string.h>
  #include <regex.h>
  #include <langinfo.h>
  #include <wchar.h>
@@@ -189,7 -190,7 +189,7 @@@ __printf_2_3 unsigned xasprintf(char **
   * \return This function either returns a pointer to a string that must be
   * freed by the caller or aborts without returning.
   *
-  * \sa printf(3), xasprintf().
+  * \sa printf(3), \ref xasprintf().
   */
  __must_check __printf_1_2 __malloc char *make_message(const char *fmt, ...)
  {
@@@ -229,7 -230,7 +229,7 @@@ void freep(void *arg
   * return \a a without making a copy of \a a.  Otherwise, construct the
   * concatenation \a c, free \a a (but not \a b) and return \a c.
   *
-  * \sa strcat(3)
+  * \sa strcat(3).
   */
  __must_check __malloc char *para_strcat(char *a, const char *b)
  {
@@@ -547,7 -548,7 +547,7 @@@ __printf_2_3 int para_printf(struct par
   *
   * \return Standard.
   *
-  * \sa para_atoi32(), strtol(3), atoi(3).
+  * \sa \ref para_atoi32(), strtol(3), atoi(3).
   */
  int para_atoi64(const char *str, int64_t *value)
  {
   *
   * \return Standard.
   *
-  * \sa para_atoi64().
+  * \sa \ref para_atoi64().
  */
  int para_atoi32(const char *str, int32_t *value)
  {