server: Convert com_lsatt() to lopsub.
authorAndre Noll <maan@tuebingen.mpg.de>
Sun, 20 Mar 2016 18:40:19 +0000 (18:40 +0000)
committerAndre Noll <maan@tuebingen.mpg.de>
Sun, 26 Mar 2017 09:02:28 +0000 (11:02 +0200)
This is the first afs subcommand which needs to pass a pattern list
to its callback. The new send_lls_callback_request() provides this
functionality. It serializes the parse result into a buffer and passes
this buffer to the callback.

Since there are non-lopsub commands which also pass a pattern list,
action_if_pattern_matches() is patched to receive the pattern
list either from the serialized parse result or in the old way via
pmd->data. To achieve this, a parse result pointer is added to struct
pattern_match_data. If this pointer is not NULL, we are dealing with
a subcommand that has been converted.

Since the ls subcommand has not been converted yet, lopsub will
regard "ls" as a uniqe abbreviation of the lsatt command, which
breaks t0004. To work around this, we deactivate prefix matching by
only accepting exact matches in run_command(). This workaround can
be removed after com_ls() has been converted.

13 files changed:
afs.c
afs.cmd
afs.h
attribute.c
command.c
m4/lls/server_cmd.suite.m4
mm.c
mood.c
playlist.c
score.c
send_common.c
server.c
vss.c

diff --git a/afs.c b/afs.c
index f0fa57f..21035cd 100644 (file)
--- a/afs.c
+++ b/afs.c
@@ -281,6 +281,36 @@ out:
        return num_dispatched;
 }
 
+/**
+ * Wrapper for send_callback_request() which passes a lopsub parse result.
+ *
+ * \param f The callback function.
+ * \param cmd Needed for (de-)serialization.
+ * \param lpr Must match cmd.
+ * \param private_result_data Passed to send_callback_request().
+ *
+ * This function serializes the parse result given by the lpr pointer into a
+ * buffer. The buffer is sent as the query to the afs process with the callback
+ * mechanism.
+ *
+ * \return The return value of the underlying call to send_callback_request().
+ */
+int send_lls_callback_request(afs_callback *f,
+               const struct lls_command * const cmd,
+               struct lls_parse_result *lpr, void *private_result_data)
+{
+       struct osl_object query;
+       char *buf = NULL;
+       int ret = lls_serialize_parse_result(lpr, cmd, &buf, &query.size);
+
+       assert(ret >= 0);
+       query.data = buf;
+       ret = send_callback_request(f, &query, afs_cb_result_handler,
+               private_result_data);
+       free(buf);
+       return ret;
+}
+
 /**
  * Send a callback request passing an options structure and an argument vector.
  *
@@ -356,7 +386,7 @@ static int action_if_pattern_matches(struct osl_row *row, void *data)
        struct pattern_match_data *pmd = data;
        struct osl_object name_obj;
        const char *p, *name;
-       int ret = osl(osl_get_object(pmd->table, row, pmd->match_col_num, &name_obj));
+       int i, ret = osl(osl_get_object(pmd->table, row, pmd->match_col_num, &name_obj));
        const char *pattern_txt = (const char *)pmd->patterns.data;
 
        if (ret < 0)
@@ -364,22 +394,37 @@ static int action_if_pattern_matches(struct osl_row *row, void *data)
        name = (char *)name_obj.data;
        if ((!name || !*name) && (pmd->pm_flags & PM_SKIP_EMPTY_NAME))
                return 1;
-       if (pmd->patterns.size == 0 &&
-                       (pmd->pm_flags & PM_NO_PATTERN_MATCHES_EVERYTHING)) {
-               pmd->num_matches++;
-               return pmd->action(pmd->table, row, name, pmd->data);
+       if ((pmd->lpr && lls_num_inputs(pmd->lpr) == 0) || pmd->patterns.size == 0) {
+               if (pmd->pm_flags & PM_NO_PATTERN_MATCHES_EVERYTHING) {
+                       pmd->num_matches++;
+                       return pmd->action(pmd->table, row, name, pmd->data);
+               }
        }
-       for (p = pattern_txt; p < pattern_txt + pmd->patterns.size;
-                       p += strlen(p) + 1) {
+       p = pattern_txt;
+       i = 0;
+       for (;;) {
+               if (pmd->lpr) {
+                       if (i >= lls_num_inputs(pmd->lpr))
+                               break;
+                       p = lls_input(i, pmd->lpr);
+               } else {
+                       if (p >= pattern_txt + pmd->patterns.size)
+                               break;
+               }
                ret = fnmatch(p, name, pmd->fnmatch_flags);
-               if (ret == FNM_NOMATCH)
-                       continue;
-               if (ret)
-                       return -E_FNMATCH;
-               ret = pmd->action(pmd->table, row, name, pmd->data);
-               if (ret >= 0)
-                       pmd->num_matches++;
-               return ret;
+               if (ret != FNM_NOMATCH) {
+                       if (ret != 0)
+                               return -E_FNMATCH;
+                       ret = pmd->action(pmd->table, row, name, pmd->data);
+                       if (ret >= 0)
+                               pmd->num_matches++;
+                       return ret;
+
+               }
+               if (pmd->lpr)
+                       i++;
+               else
+                       p += strlen(p) + 1;
        }
        return 1;
 }
diff --git a/afs.cmd b/afs.cmd
index 6e2967a..5a3615b 100644 (file)
--- a/afs.cmd
+++ b/afs.cmd
@@ -52,22 +52,6 @@ H:   b: by bit rate
 H:   d: by duration
 H:   a: by audio format
 ---
-N: lsatt
-P: AFS_READ
-D: List attributes.
-U: lsatt [-i] [-l] [-r] [pattern]
-H: Print the list of all defined attributes which match the given
-H: pattern. If no pattern is given, the full list is printed.
-H:
-H: Options:
-H:
-H: -i  Sort attributes by id. The default is to sort alphabetically by name.
-H:
-H: -l  Print a long listing containing both identifier and attribute name. The
-H:     default is to print only the name.
-H:
-H: -r  Reverse sort order.
----
 N: setatt
 P: AFS_READ | AFS_WRITE
 D: Set attribute(s) for all files matching a pattern.
diff --git a/afs.h b/afs.h
index a313503..c73eb73 100644 (file)
--- a/afs.h
+++ b/afs.h
@@ -145,6 +145,8 @@ struct pattern_match_data {
        unsigned pm_flags;
        /** This value is passed verbatim to fnmatch(). */
        int fnmatch_flags;
+       /** Obtained by deserializing the query buffer in the callback. */
+       struct lls_parse_result *lpr;
        /** Null-terminated array of patterns. */
        struct osl_object patterns;
        /** Data pointer passed to the action function. */
@@ -229,6 +231,9 @@ int send_option_arg_callback_request(struct osl_object *options,
 int send_standard_callback_request(int argc,  char * const * const argv,
                afs_callback *f, callback_result_handler *result_handler,
                void *private_result_data);
+int send_lls_callback_request(afs_callback *f,
+               const struct lls_command * const cmd,
+               struct lls_parse_result *lpr, void *private_result_data);
 int string_compare(const struct osl_object *obj1, const struct osl_object *obj2);
 int for_each_matching_row(struct pattern_match_data *pmd);
 
index d5f4884..99e7865 100644 (file)
@@ -10,6 +10,7 @@
 #include <osl.h>
 #include <lopsub.h>
 
+#include "server_cmd.lsg.h"
 #include "para.h"
 #include "error.h"
 #include "crypt.h"
@@ -107,30 +108,16 @@ int get_attribute_bitnum_by_name(const char *att_name, unsigned char *bitnum)
        return 1;
 }
 
-/**
- * Flags used by the lsatt command.
- *
- * \param \sa com_lsatt().
- */
-enum lsatt_flags {
-       /** Whether "-a" was given for the lsatt command. */
-       LSATT_FLAG_SORT_BY_ID = 1,
-       /** Whether "-l" was given for the lsatt command. */
-       LSATT_FLAG_LONG = 2,
-       /** Reverse sort order. */
-       LSATT_FLAG_REVERSE = 4
-};
-
 /** Data passed to the action function of lsatt */
 static int print_attribute(struct osl_table *table, struct osl_row *row,
                const char *name, void *data)
 {
        struct afs_callback_arg *aca = data;
-       unsigned flags = *(unsigned *)aca->query.data;
+       bool l_given = SERVER_CMD_OPT_GIVEN(LSATT, LONG, aca->lpr);
        struct osl_object bitnum_obj;
        int ret;
 
-       if (!(flags & LSATT_FLAG_LONG)) {
+       if (!l_given) {
                para_printf(&aca->pbout, "%s\n", name);
                return 1;
        }
@@ -146,21 +133,27 @@ static int print_attribute(struct osl_table *table, struct osl_row *row,
 
 static int com_lsatt_callback(struct afs_callback_arg *aca)
 {
-       unsigned flags = *(unsigned *)aca->query.data;
+       const struct lls_command *cmd = SERVER_CMD_CMD_PTR(LSATT);
+       bool i_given, r_given;
        int ret;
        struct pattern_match_data pmd = {
                .table = attribute_table,
                .loop_col_num = ATTCOL_NAME,
                .match_col_num = ATTCOL_NAME,
-               .patterns = {.data = (char *)aca->query.data + sizeof(flags),
-                       .size = aca->query.size - sizeof(flags)},
                .pm_flags = PM_NO_PATTERN_MATCHES_EVERYTHING,
                .data = aca,
                .action = print_attribute
        };
-       if (flags & LSATT_FLAG_SORT_BY_ID)
+
+       ret = lls(lls_deserialize_parse_result(aca->query.data, cmd, &aca->lpr));
+       assert(ret >= 0);
+       pmd.lpr = aca->lpr;
+       i_given = SERVER_CMD_OPT_GIVEN(LSATT, ID_SORT, aca->lpr);
+       r_given = SERVER_CMD_OPT_GIVEN(LSATT, REVERSE, aca->lpr);
+
+       if (i_given)
                pmd.loop_col_num = ATTCOL_BITNUM;
-       if (flags & LSATT_FLAG_REVERSE)
+       if (r_given)
                pmd.pm_flags |= PM_REVERSE_LOOP;
        ret = for_each_matching_row(&pmd);
        if (ret < 0)
@@ -168,46 +161,22 @@ static int com_lsatt_callback(struct afs_callback_arg *aca)
        if (pmd.num_matches == 0)
                ret = -E_NO_MATCH;
 out:
+       lls_free_parse_result(aca->lpr, cmd);
        return ret;
 }
 
-int com_lsatt(struct command_context *cc)
+static int com_lsatt(struct command_context *cc, struct lls_parse_result *lpr)
 {
-       unsigned flags = 0;
-       struct osl_object options = {.data = &flags, .size = sizeof(flags)};
-       int i;
-
-       for (i = 1; i < cc->argc; i++) {
-               const char *arg = cc->argv[i];
-               if (arg[0] != '-')
-                       break;
-               if (!strcmp(arg, "--")) {
-                       i++;
-                       break;
-               }
-               if (!strcmp(arg, "-i")) {
-                       flags |= LSATT_FLAG_SORT_BY_ID;
-                       continue;
-               }
-               if (!strcmp(arg, "-l")) {
-                       flags |= LSATT_FLAG_LONG;
-                       continue;
-               }
-               if (!strcmp(arg, "-r")) {
-                       flags |= LSATT_FLAG_REVERSE;
-                       continue;
-               }
-       }
-       return send_option_arg_callback_request(&options, cc->argc - i, cc->argv + i,
-               com_lsatt_callback, afs_cb_result_handler, cc);
+       const struct lls_command *cmd = SERVER_CMD_CMD_PTR(LSATT);
+       return send_lls_callback_request(com_lsatt_callback, cmd, lpr, cc);
 }
+EXPORT_SERVER_CMD_HANDLER(lsatt);
 
 struct addatt_event_data {
        const char *name;
        unsigned char bitnum;
 };
 
-
 static int com_addatt_callback(struct afs_callback_arg *aca)
 {
        char *p;
index 491ce39..d55d1e6 100644 (file)
--- a/command.c
+++ b/command.c
@@ -873,7 +873,8 @@ static int run_command(struct command_context *cc, struct iovec *iov,
        p[iov->iov_len - 1] = '\0'; /* just to be sure */
 
        ret = lls(lls_lookup_subcmd(p, server_cmd_suite, &errctx));
-       if (ret >= 0) {
+       if (ret >= 0 && !strcmp(p, lls_command_name(lls_cmd(ret,
+                       server_cmd_suite)))) {
                perms = server_command_perms[ret];
                if ((perms & cc->u->perms) != perms)
                        return -E_PERM;
index 4a1f9f4..b10f355 100644 (file)
@@ -107,6 +107,35 @@ aux_info_prefix = Permissions:
                n <= 100.
        [/description]
 
+[subcommand lsatt]
+       purpose = list attributes
+       aux_info = AFS_READ
+       [description]
+               Print the list of all defined attributes which match the given
+               pattern. If no pattern is given, the full list is printed.
+       [/description]
+
+       [option id-sort]
+               short_opt = i
+               summary = sort attributes by id
+               [help]
+                       The default is to sort alphabetically by name.
+
+                       Attributes are internally represented as an 64 bit array. The attribute
+                       id is the bit number in this array.
+               [/help]
+       [option long]
+               short_opt = l
+               summary = print long listing
+               [help]
+                       The long listing prints the attribute id in addition to the name of
+                       the attribute. The id is printed as a decimal number and is separated
+                       from the name by a tab character.
+               [/help]
+       [option reverse]
+               short_opt = r
+               summary = reverse sort order
+
 [subcommand next]
        purpose = close the stream and start to stream the next audio file
        aux_info = VSS_READ | VSS_WRITE
diff --git a/mm.c b/mm.c
index 92856ec..47e8886 100644 (file)
--- a/mm.c
+++ b/mm.c
@@ -9,6 +9,7 @@
 #include <regex.h>
 #include <fnmatch.h>
 #include <osl.h>
+#include <lopsub.h>
 
 #include "para.h"
 #include "error.h"
diff --git a/mood.c b/mood.c
index 79f47e5..acc5583 100644 (file)
--- a/mood.c
+++ b/mood.c
@@ -8,6 +8,7 @@
 
 #include <regex.h>
 #include <osl.h>
+#include <lopsub.h>
 
 #include "para.h"
 #include "error.h"
index 8ea1854..b9e52c7 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <regex.h>
 #include <osl.h>
+#include <lopsub.h>
 
 #include "para.h"
 #include "error.h"
diff --git a/score.c b/score.c
index 81b3ded..ddd3c7a 100644 (file)
--- a/score.c
+++ b/score.c
@@ -7,6 +7,7 @@
 /** \file score.c Scoring functions to determine the audio file streaming order. */
 #include <regex.h>
 #include <osl.h>
+#include <lopsub.h>
 
 #include "para.h"
 #include "error.h"
index ec7ab67..a9df02a 100644 (file)
@@ -13,6 +13,7 @@
 #include <arpa/inet.h>
 #include <sys/un.h>
 #include <netdb.h>
+#include <lopsub.h>
 
 #include "para.h"
 #include "error.h"
index a023b15..a0eb50e 100644 (file)
--- a/server.c
+++ b/server.c
@@ -40,6 +40,7 @@
 #include <arpa/inet.h>
 #include <sys/un.h>
 #include <netdb.h>
+#include <lopsub.h>
 
 #include "para.h"
 #include "error.h"
diff --git a/vss.c b/vss.c
index 5484db9..72eb53a 100644 (file)
--- a/vss.c
+++ b/vss.c
@@ -19,6 +19,7 @@
 #include <arpa/inet.h>
 #include <sys/un.h>
 #include <netdb.h>
+#include <lopsub.h>
 
 #include "para.h"
 #include "error.h"