]> git.tuebingen.mpg.de Git - paraslash.git/commitdiff
Merge topic branch t/ls-L into master
authorAndre Noll <maan@tuebingen.mpg.de>
Sat, 28 Oct 2023 17:20:14 +0000 (19:20 +0200)
committerAndre Noll <maan@tuebingen.mpg.de>
Sat, 28 Oct 2023 19:50:40 +0000 (21:50 +0200)
A single patch which implements the new --limit option for the ls
server command. The confict in aft.c was trivial to fix.

* refs/heads/t/ls-L:
  server: Implement ls --limit.

1  2 
NEWS.md
aft.c
m4/lls/server_cmd.suite.m4

diff --combined NEWS.md
index aa515e5af091eb23f266549a0cd33e974f993972,598db71fae93734158509fa5f76853ceb09ccb7b..5430790bcc151fa90c93eabe66c009a1592c994f
+++ b/NEWS.md
@@@ -1,27 -1,6 +1,29 @@@
  NEWS
  ====
  
 +----------------------------------------------
 +0.7.3 (to be announced) "weighted correctness"
 +----------------------------------------------
 +
 +- Old style PEM keys are now deprecated. They still work but their
 +  use results in a run-time warning. The removal of PEM key support is
 +  scheduled for paraslash-0.8.0.
 +- Version 1.0 of the openssl library has been deprecated. A warning
 +  is printed at compile-time on systems which have this outdated version
 +  because it will no longer be supported once paraslash-0.8.0 comes out.
 +- A spring cleanup for the senescent code in fd.c.
 +- The --admissible option of the ls command now takes an optional
 +  argument. When invoked like --admissible=m/foo, only files which are
 +  admissible with respect to mood foo are listed.
 +- The select server command is now quiet by default, The new --verbose
 +  option can be used to show information about the newly loaded mood
 +  or playlist.
++- The ls server command gained the --limit option to force a limit
++  on the number of files listed.
 +
 +Downloads:
 +[tarball](./releases/paraslash-git.tar.xz)
 +
  -------------------------------------
  0.7.2 (2023-03-08) "optical friction"
  -------------------------------------
diff --combined aft.c
index 4ea8641b2acce666e53d7005bd755ae2099cb07a,ff75361d374b9dea3669d24d819afefaf9f50a52..f1aca7fb8ccc3e31575303a4762d6a7ea35a054f
--- 1/aft.c
--- 2/aft.c
+++ b/aft.c
@@@ -6,7 -6,6 +6,7 @@@
  #include <sys/mman.h>
  #include <fnmatch.h>
  #include <sys/shm.h>
 +#include <dirent.h>
  #include <osl.h>
  #include <lopsub.h>
  
        return ret;
  }
  
 +static int mop_loop(const char *arg, struct afs_callback_arg *aca,
 +              struct ls_options *opts)
 +{
 +      int ret;
 +      char *msg;
 +
 +      if (!arg || strcmp(arg, ".") == 0)
 +              return score_loop(prepare_ls_row, NULL, opts);
 +      if (!strncmp(arg, "m/", 2)) {
 +              struct mood_instance *m;
 +              ret = mood_load(arg + 2, &m, &msg);
 +              if (ret < 0)
 +                      afs_error(aca, "%s", msg);
 +              free(msg);
 +              if (ret < 0)
 +                      return ret;
 +              ret = mood_loop(m, prepare_ls_row, opts);
 +              mood_unload(m);
 +              return ret;
 +      }
 +      if (!strncmp(arg, "p/", 2)) {
 +              struct playlist_instance *pi;
 +              ret = playlist_load(arg + 2, &pi, &msg);
 +              if (ret < 0)
 +                      afs_error(aca, "%s", msg);
 +              free(msg);
 +              if (ret < 0)
 +                      return ret;
 +              ret = playlist_loop(pi, prepare_ls_row, opts);
 +              playlist_unload(pi);
 +              return ret;
 +      }
 +      afs_error(aca, "bad mood/playlist specifier: %s\n", arg);
 +      return -ERRNO_TO_PARA_ERROR(EINVAL);
 +}
 +
  static int com_ls_callback(struct afs_callback_arg *aca)
  {
        const struct lls_command *cmd = SERVER_CMD_CMD_PTR(LS);
        struct ls_options *opts = aca->query.data;
-       int i = 0, ret;
+       int ret;
        time_t current_time;
 -      const struct lls_opt_result *r_r;
 +      const struct lls_opt_result *r_r, *r_a;
+       uint32_t limit, k, n;
  
        ret = lls_deserialize_parse_result(
                (char *)aca->query.data + sizeof(*opts), cmd, &opts->lpr);
        assert(ret >= 0);
        r_r = SERVER_CMD_OPT_RESULT(LS, REVERSE, opts->lpr);
 -
 +      r_a = SERVER_CMD_OPT_RESULT(LS, ADMISSIBLE, opts->lpr);
        aca->pbout.flags = (opts->mode == LS_MODE_PARSER)? PBF_SIZE_PREFIX : 0;
 -      if (admissible_only(opts))
 -              ret = score_loop(prepare_ls_row, opts);
 -      else
 +      if (admissible_only(opts)) {
 +              const char *arg = lls_string_val(0, r_a);
 +              ret = mop_loop(arg, aca, opts);
 +      } else
                ret = osl(osl_rbtree_loop(audio_file_table, AFTCOL_PATH, opts,
                        prepare_ls_row));
        if (ret < 0)
                goto out;
-       if (opts->num_matching_paths == 0) {
+       n = opts->num_matching_paths;
+       if (n == 0) {
                ret = lls_num_inputs(opts->lpr) > 0? -E_NO_MATCH : 0;
                goto out;
        }
        if (ret < 0)
                goto out;
        time(&current_time);
-       if (lls_opt_given(r_r))
-               for (i = opts->num_matching_paths - 1; i >= 0; i--) {
-                       ret = print_list_item(opts->data_ptr[i], opts,
-                               &aca->pbout, current_time);
-                       if (ret < 0)
-                               goto out;
-               }
-       else
-               for (i = 0; i < opts->num_matching_paths; i++) {
-                       ret = print_list_item(opts->data_ptr[i], opts,
-                               &aca->pbout, current_time);
-                       if (ret < 0)
-                               goto out;
-               }
+       limit = SERVER_CMD_UINT32_VAL(LS, LIMIT, opts->lpr);
+       for (k = 0; k < n && (limit == 0 || k < limit); k++) {
+               uint32_t idx = lls_opt_given(r_r)? n - 1 - k : k;
+               ret = print_list_item(opts->data_ptr[idx], opts, &aca->pbout,
+                       current_time);
+               if (ret < 0)
+                       goto out;
+       }
  out:
        lls_free_parse_result(opts->lpr, cmd);
        free(opts->data);
@@@ -1944,53 -1902,6 +1940,53 @@@ out_free
        return send_ret;
  }
  
 +/*
 + * Call back once for each regular file below a directory.
 + *
 + * Traverse the given directory recursively and call the supplied callback for
 + * each regular file encountered. The first argument to the callback will be
 + * the path to the regular file and the second argument will be the data
 + * pointer. All file types except regular files and directories are ignored. In
 + * particular, symlinks are not followed. Subdirectories are ignored silently
 + * if the calling process has insufficient access permissions.
 + */
 +static int for_each_file_in_dir(const char *dirname,
 +              int (*func)(const char *, void *), void *data)
 +{
 +      int ret;
 +      DIR *dir;
 +      struct dirent *entry;
 +
 +      dir = opendir(dirname);
 +      if (!dir)
 +              return errno == EACCES? 1 : -ERRNO_TO_PARA_ERROR(errno);
 +      /* scan cwd recursively */
 +      while ((entry = readdir(dir))) {
 +              char *tmp;
 +              struct stat s;
 +
 +              if (!strcmp(entry->d_name, "."))
 +                      continue;
 +              if (!strcmp(entry->d_name, ".."))
 +                      continue;
 +              tmp = make_message("%s/%s", dirname, entry->d_name);
 +              ret = 0;
 +              if (lstat(tmp, &s) != -1) {
 +                      if (S_ISREG(s.st_mode))
 +                              ret = func(tmp, data);
 +                      else if (S_ISDIR(s.st_mode))
 +                              ret = for_each_file_in_dir(tmp, func, data);
 +              }
 +              free(tmp);
 +              if (ret < 0)
 +                      goto out;
 +      }
 +      ret = 1;
 +out:
 +      closedir(dir);
 +      return ret;
 +}
 +
  static int com_add(struct command_context *cc, struct lls_parse_result *lpr)
  {
        int i, ret;
index 5b5c59ad58ad4ca07edefa3bd01311155ca1e5d5,cafdbccf16e8e0511e7722999ca8bcb3a7d254bf..02afaabb5252a0580711547ad399cef932cfcadc
@@@ -222,6 -222,16 +222,16 @@@ m4_include(`com_ll.m4'
                        also given), chunk time and chunk offsets.
  
                [/help]
+       [option limit]
+               short_opt = L
+               summary = list at most this many files
+               arg_type = uint32
+               arg_info = required_arg
+               typestr = num
+               [help]
+                       An argument of zero means "unlimited". This is also the default which
+                       applies if the option is not given.
+               [/help]
        [option basename]
                short_opt = b
                summary = list and match basenames only
        [option admissible]
                short_opt = a
                summary = list only admissible files
 +              arg_type = string
 +              arg_info = optional_arg
 +              typestr = specifier/name
 +              default_val = .
                [help]
 -                      List only files which are admissible with respect to the current mood
 -                      or playlist.
 +                      If the optional argument is supplied, it must be of the form "p/foo"
 +                      or "m/bar" (which refer to the playlist named "foo" and the mood named
 +                      "bar", respectively). The command then restricts its output to the set
 +                      of files which are admissible with respect to the thusly identified
 +                      mood or playlist.
 +
 +                      If no argument is given, or if the argument is the special value ".",
 +                      the current mood or playlist is assumed.
                [/help]
        [option reverse]
                short_opt = r
  
                activates the mood named 'foo'.
        [/description]
 +      [option verbose]
 +              short_opt = v
 +              summary = print information about the loaded mood or playlist
  
  [subcommand sender]
        purpose = control paraslash senders