com_afs_rm(): Implement pattern matching and add -v, -p, -f flags.
authorAndre Noll <maan@systemlinux.org>
Thu, 27 Sep 2007 13:22:39 +0000 (15:22 +0200)
committerAndre Noll <maan@systemlinux.org>
Thu, 27 Sep 2007 13:22:39 +0000 (15:22 +0200)
The -r flag is still to be implemented though..

afs.cmd
aft.c

diff --git a/afs.cmd b/afs.cmd
index fca6046..200836e 100644 (file)
--- a/afs.cmd
+++ b/afs.cmd
@@ -144,10 +144,21 @@ H: about this attribute in the audio file table is lost.
 N: afs_rm
 P: AFS_READ | AFS_WRITE
 D: Remove entries from the audio file table.
-U: rm pattern...
+U: rm [-v] [-f] [-p] pattern...
 H: Delete all entries in the audio file table that match any given pattern.
 H: Note that affects the table entries only; paraslash won't touch your
 H: audio files in any way.
+H: Options:
+H:
+H: -v  Verbose mode. Explain what is being done.
+H:
+H: -f  Force mode. Ignore nonexistent files. Don't complain if nothing
+H:     was removed.
+H:
+H: -p  Pathname match. Match a slash in the path only with a slash
+H:     in pattern and not by an asterisk (*) or a question mark
+H:     (?) metacharacter, nor by a bracket expression ([]) containing
+H:     a slash (see fnmatch(3)).
 ---
 N: touch
 P: AFS_READ | AFS_WRITE
diff --git a/aft.c b/aft.c
index f8e8f40..362ce1c 100644 (file)
--- a/aft.c
+++ b/aft.c
@@ -747,6 +747,7 @@ static char *make_attribute_line(const char *att_bitmap, struct afs_info *afsi)
 static char *make_lyrics_line(struct afs_info *afsi)
 {
        char *lyrics_name;
+
        lyr_get_name_by_id(afsi->lyrics_id, &lyrics_name);
        if (!lyrics_name)
                return make_message("%u", afsi->lyrics_id);
@@ -1748,45 +1749,76 @@ err:
        return ret;
 }
 
-struct com_rm_options {
+enum rm_flags {
+       RM_FLAG_VERBOSE = 1,
+       RM_FLAG_FORCE = 2,
+       RM_FLAG_FNM_PATHNAME = 4
+};
+
+struct com_rm_data {
        uint32_t flags;
+       struct para_buffer pb;
+       unsigned num_removed;
 };
 
-static int com_rm_callback(const struct osl_object *query,
-               __a_unused struct osl_object *result)
+static int remove_audio_file(__a_unused struct osl_table *table,
+               struct osl_row *row, const char *name, void *data)
 {
-       struct com_rm_options *cro = query->data;
-       char *p = (char *)query->data + sizeof(*cro);
-       size_t len;
+       struct com_rm_data *crd = data;
        int ret;
 
-       for (;p < (char *)query->data + query->size; p += len + 1) {
-               struct osl_row *row;
-
-               len = strlen(p);
-               ret = aft_get_row_of_path(p, &row);
-               if (ret < 0)
-                       return ret;
-               ret = mood_delete_audio_file(row);
-               if (ret < 0)
-                       return ret;
-               ret = osl_del_row(audio_file_table, row);
-               if (ret < 0)
-                       return ret;
-       }
+       if (crd->flags & RM_FLAG_VERBOSE)
+               para_printf(&crd->pb, "removing %s\n", name);
+       ret = mood_delete_audio_file(row);
+       if (ret < 0)
+               para_printf(&crd->pb, "%s: %s\n", name, PARA_STRERROR(-ret));
+       ret = osl_del_row(audio_file_table, row);
+       if (ret < 0)
+               para_printf(&crd->pb, "%s: %s\n", name, PARA_STRERROR(-ret));
+       else
+               crd->num_removed++;
        return 1;
 }
 
-/*
- * TODO options: -v verbose, -f dont stop if file not found
- * -h remove by hash, use fnmatch
- *
- * */
+static int com_rm_callback(const struct osl_object *query,
+               __a_unused struct osl_object *result)
+{
+       struct com_rm_data crd = {.flags = *(uint32_t *)query->data};
+       int ret;
+       struct pattern_match_data pmd = {
+               .table = audio_file_table,
+               .loop_col_num = AFTCOL_HASH,
+               .match_col_num = AFTCOL_PATH,
+               .patterns = {.data = (char *)query->data + sizeof(uint32_t),
+                       .size = query->size - sizeof(uint32_t)},
+               .data = &crd,
+               .action = remove_audio_file
+       };
+       if (crd.flags & RM_FLAG_FNM_PATHNAME)
+               pmd.fnmatch_flags |= FNM_PATHNAME;
+       ret = for_each_matching_row(&pmd);
+       if (ret < 0)
+               para_printf(&crd.pb, "%s\n", PARA_STRERROR(-ret));
+       if (!crd.num_removed && !(crd.flags & RM_FLAG_FORCE))
+               para_printf(&crd.pb, "no matches -- nothing removed\n");
+       else {
+               if (crd.flags & RM_FLAG_VERBOSE)
+                       para_printf(&crd.pb, "removed %u files\n", crd.num_removed);
+       }
+       if (crd.pb.buf) {
+               result->data = crd.pb.buf;
+               result->size = crd.pb.size;
+               return 1;
+       }
+       return ret < 0? ret : 0;
+}
 
-int com_afs_rm(__a_unused int fd, int argc,  char * const * const argv)
+/* TODO options: -r (recursive) */
+int com_afs_rm(int fd, int argc,  char * const * const argv)
 {
-       struct com_rm_options cro = {.flags = 0};
-       struct osl_object options = {.data = &cro, .size = sizeof(cro)};
+       uint32_t flags = 0;
+       struct osl_object query = {.data = &flags, .size = sizeof(flags)},
+               result;
        int i, ret;
 
        for (i = 1; i < argc; i++) {
@@ -1797,13 +1829,28 @@ int com_afs_rm(__a_unused int fd, int argc,  char * const * const argv)
                        i++;
                        break;
                }
+               if (!strcmp(arg, "-f")) {
+                       flags |= RM_FLAG_FORCE;
+                       continue;
+               }
+               if (!strcmp(arg, "-p")) {
+                       flags |= RM_FLAG_FNM_PATHNAME;
+                       continue;
+               }
+               if (!strcmp(arg, "-v")) {
+                       flags |= RM_FLAG_VERBOSE;
+                       continue;
+               }
        }
-       ret = -E_AFT_SYNTAX;
        if (i >= argc)
-               goto err;
-       return send_option_arg_callback_request(&options, argc - i,
-               argv + i, com_rm_callback, NULL);
-err:
+               return -E_AFT_SYNTAX;
+       ret = send_option_arg_callback_request(&query, argc - i, argv + i,
+               com_rm_callback, &result);
+       if (ret > 0) {
+               send_buffer(fd, (char *)result.data);
+               free(result.data);
+       } else
+               send_va_buffer(fd, "%s\n", PARA_STRERROR(-ret));
        return ret;
 }