/** \file afs.c Paraslash's audio file selector. */
+#include <fnmatch.h>
#include "server.cmdline.h"
#include "para.h"
#include "afh.h"
return send_option_arg_callback_request(NULL, argc, argv, f, result);
}
+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_get_object(pmd->table, row, pmd->match_col_num, &name_obj);
+ const char *pattern_txt = (const char *)pmd->patterns.data;
+
+ if (ret < 0)
+ return ret;
+ name = (char *)name_obj.data;
+ if ((!name || !*name) && (pmd->pm_flags & PM_SKIP_EMPTY_NAME))
+ return 1;
+ if (!pmd->patterns.size && (pmd->pm_flags & PM_NO_PATTERN_MATCHES_EVERYTHING))
+ return pmd->action(pmd->table, row, name, pmd->data);
+ for (p = pattern_txt; p < pattern_txt + pmd->patterns.size;
+ p += strlen(p) + 1) {
+ ret = fnmatch(p, name, pmd->fnmatch_flags);
+ if (ret == FNM_NOMATCH)
+ continue;
+ if (ret)
+ return -E_FNMATCH;
+ return pmd->action(pmd->table, row, name, pmd->data);
+ }
+ return 1;
+}
+
+int for_each_matching_row(struct pattern_match_data *pmd)
+{
+ if (pmd->pm_flags & PM_REVERSE_LOOP)
+ return osl_rbtree_loop_reverse(pmd->table, pmd->loop_col_num, pmd,
+ action_if_pattern_matches);
+ return osl_rbtree_loop(pmd->table, pmd->loop_col_num, pmd,
+ action_if_pattern_matches);
+}
+
/**
* Compare two osl objects of string type.
*
struct osl_object map;
};
+enum pattern_match_flags {
+ PM_REVERSE_LOOP = 1,
+ PM_NO_PATTERN_MATCHES_EVERYTHING = 2,
+ PM_SKIP_EMPTY_NAME = 4,
+};
+
+struct pattern_match_data {
+ struct osl_table *table;
+ unsigned loop_col_num;
+ unsigned match_col_num;
+ unsigned pm_flags;
+ int fnmatch_flags;
+ struct osl_object patterns;
+ void *data;
+ int (*action)(struct osl_table *table, struct osl_row *row, const char *name, void *data);
+};
+
/* afs */
typedef int callback_function(const struct osl_object *, struct osl_object *);
__noreturn int afs_init(uint32_t cookie, int socket_fd);
int para_atol(const char *str, long *result);
int open_next_audio_file(struct audio_file_data *afd);
int close_audio_file(struct audio_file_data *afd);
+int for_each_matching_row(struct pattern_match_data *pmd);
/* score */
int score_init(struct table_info *ti, const char *db);
return 1;
}
-enum blob_match_loop_flags {
- BM_NAME_LOOP = 1,
- BM_REVERSE_LOOP = 2
-};
-
-struct blob_match_data {
- struct osl_table *table;
- const char *patterns;
- size_t patterns_size;
- int fnmatch_flags;
- unsigned loop_flags;
- void *data;
- int (*action)(struct osl_table *table, struct osl_row *row, const char *name, void *data);
-};
-
-static int action_if_blob_matches(struct osl_row *row, void *data)
-{
- struct blob_match_data *bmd = data;
- struct osl_object name_obj;
- const char *p, *name;
- int ret = osl_get_object(bmd->table, row, BLOBCOL_NAME, &name_obj);
-
- if (ret < 0) {
- PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret));
- return ret;
- }
- name = (char *)name_obj.data;
- if (!*name) /* ignore dummy row */
- return 1;
- if (!bmd->patterns_size) /* match everything if no pattern was given */
- return bmd->action(bmd->table, row, name, bmd->data);
- for (p = bmd->patterns; p < bmd->patterns + bmd->patterns_size;
- p += strlen(p) + 1) {
- ret = fnmatch(p, name, bmd->fnmatch_flags);
- if (ret == FNM_NOMATCH)
- continue;
- if (ret)
- return -E_FNMATCH;
- return bmd->action(bmd->table, row, name, bmd->data);
- }
- return 1;
-}
-
-static int for_each_matching_blob(struct blob_match_data *bmd)
-{
- unsigned col = (bmd->loop_flags & BM_NAME_LOOP)?
- BLOBCOL_NAME : BLOBCOL_ID;
-
- if (bmd->loop_flags & BM_REVERSE_LOOP)
- return osl_rbtree_loop_reverse(bmd->table, col, bmd, action_if_blob_matches);
- return osl_rbtree_loop(bmd->table, col, bmd, action_if_blob_matches);
-}
-
int com_lsblob_callback(struct osl_table *table,
const struct osl_object *query, struct osl_object *ls_output)
{
struct lsblob_data lbd = {.flags = *(uint32_t *)query};
- struct blob_match_data bmd = {
+ struct pattern_match_data pmd = {
.table = table,
- .patterns = (char *)query->data + sizeof(uint32_t),
- .patterns_size = query->size - sizeof(uint32_t),
+ .patterns = {.data = (char *)query->data + sizeof(uint32_t),
+ .size = query->size - sizeof(uint32_t)},
+ .pm_flags = PM_NO_PATTERN_MATCHES_EVERYTHING | PM_SKIP_EMPTY_NAME,
+ .match_col_num = BLOBCOL_NAME,
.data = &lbd,
- .action = print_blob
+ .action = print_blob,
};
int ret;
if (lbd.flags & BLOB_LS_FLAG_REVERSE)
- bmd.loop_flags |= BM_REVERSE_LOOP;
+ pmd.pm_flags |= PM_REVERSE_LOOP;
if (!(lbd.flags & BLOB_LS_FLAG_SORT_BY_ID))
- bmd.loop_flags |= BM_NAME_LOOP;
- ret = for_each_matching_blob(&bmd);
+ pmd.loop_col_num = BLOBCOL_ID;
+ else
+ pmd.loop_col_num = BLOBCOL_NAME;
+ ret = for_each_matching_row(&pmd);
if (lbd.pb.buf) {
ls_output->data = lbd.pb.buf;
ls_output->size = lbd.pb.size;
const struct osl_object *query, struct osl_object *result)
{
int ret;
- struct blob_match_data bmd = {
+ struct pattern_match_data pmd = {
.table = table,
- .patterns = (char *)query->data,
- .patterns_size = query->size,
+ .patterns = *query,
+ .loop_col_num = BLOBCOL_NAME,
+ .match_col_num = BLOBCOL_NAME,
+ .pm_flags = PM_SKIP_EMPTY_NAME,
.data = result,
.action = cat_blob
};
result->data = NULL;
- ret = for_each_matching_blob(&bmd);
+ ret = for_each_matching_row(&pmd);
if (result->data)
return 1;
return (ret > 0)? 0 : ret;
{
int ret;
struct rmblob_data rmbd = {.num_removed = 0};
- struct blob_match_data bmd = {
+ struct pattern_match_data pmd = {
.table = table,
- .patterns = (char *)query->data,
- .patterns_size = query->size,
+ .patterns = *query,
+ .loop_col_num = BLOBCOL_NAME,
+ .match_col_num = BLOBCOL_NAME,
+ .pm_flags = PM_SKIP_EMPTY_NAME,
.data = &rmbd,
.action = remove_blob
};
result->data = NULL;
- ret = for_each_matching_blob(&bmd);
+ ret = for_each_matching_row(&pmd);
if (ret < 0)
para_printf(&rmbd.pb, "%s\n", PARA_STRERROR(-ret));
if (!rmbd.num_removed)