From c2ac39f76d245816a919d94790672fb66e9a7253 Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Thu, 18 Oct 2007 22:00:16 +0200 Subject: [PATCH] Implement afs events. --- afs.c | 27 +++++++++++++++ afs.cmd | 6 ++++ afs.h | 54 +++++++++++++++++++++++------ aft.c | 84 ++++++++++++++++++++++++++++++++++----------- attribute.c | 98 ++++++++++++++++++++++++++++++++++------------------- blob.c | 26 ++++++++++++++ error.h | 1 + mood.c | 40 ++++++++++++++++++---- osl.c | 18 +++------- playlist.c | 72 +++++++++++++++++++++++++++++++++++++-- score.c | 56 ++++++++++++++++++++---------- 11 files changed, 378 insertions(+), 104 deletions(-) diff --git a/afs.c b/afs.c index 95f6b311..c4e8d169 100644 --- a/afs.c +++ b/afs.c @@ -963,3 +963,30 @@ int com_check(int fd, int argc, char * const * const argv) } return 1; } + +void afs_event(enum afs_events event, struct para_buffer *pb, + void *data) +{ + int i, ret; + + for (i = 0; i < NUM_AFS_TABLES; i++) { + struct afs_table *t = &afs_tables[i]; + if (!t->event_handler) + continue; + ret = t->event_handler(event, pb, data); + if (ret < 0) + PARA_CRIT_LOG("%s\n", PARA_STRERROR(-ret)); + } +} + +int images_event_handler(__a_unused enum afs_events event, + __a_unused struct para_buffer *pb, __a_unused void *data) +{ + return 1; +} + +int lyrics_event_handler(__a_unused enum afs_events event, + __a_unused struct para_buffer *pb, __a_unused void *data) +{ + return 1; +} diff --git a/afs.cmd b/afs.cmd index 2b031be2..15a30d0b 100644 --- a/afs.cmd +++ b/afs.cmd @@ -124,6 +124,12 @@ U: addatt attribute1... H: This adds new attributes to the attribute table. At most 64 H: attributes may be defined. --- +N: mvatt +P: AFS_READ | AFS_WRITE +D: Rename an attribute. +U: mvatt old new +H: Rename attribute old to new. +--- N: check P: AFS_READ D: Run integrity checks against osl tables. diff --git a/afs.h b/afs.h index 1399b2ab..57cecebd 100644 --- a/afs.h +++ b/afs.h @@ -27,29 +27,60 @@ struct afs_info { }; enum afs_events { + ATTRIBUTE_ADD, + ATTRIBUTE_RENAME, + ATTRIBUTE_REMOVE, AFSI_CHANGE, AFHI_CHANGE, AUDIO_FILE_RENAME, AUDIO_FILE_ADD, AUDIO_FILE_REMOVE, - AUDIO_FILE_STREAMED, - ATTRIBUTE_ADD, - ATTRIBUTE_RENAME, - ATTRIBUTE_DELETE, - LYRICS_DELETE, - IMAGE_DELETE, + LYRICS_ADD, + LYRICS_REMOVE, LYRICS_RENAME, + IMAGE_ADD, + IMAGE_REMOVE, IMAGE_RENAME, }; +struct rmatt_event_data { + const char *name; + unsigned char bitnum; +}; + + +struct addatt_event_data { + const char *name; + unsigned char bitnum; +}; + +struct afsi_change_event_data { + const struct osl_row *aft_row; + struct afs_info *old_afsi; +}; + +union afs_event_data { + struct { + const char *name; + unsigned char bitnum; + } rmatt_event_data; + struct osl_row *row; + struct { + const struct osl_row *row; + struct afs_info *old_afsi; + } afsi_change; + +}; + struct afs_table { void (*init)(struct afs_table *t); const char *name; int (*open)(const char *base_dir); void (*close)(void); int (*create)(const char *); - int (*event_handler)(enum afs_events event, struct para_buffer *pb, void *data); + int (*event_handler)(enum afs_events event, struct para_buffer *pb, + void *data); /* int *(check)() */ }; @@ -97,6 +128,8 @@ struct pattern_match_data { /* afs */ typedef int callback_function(const struct osl_object *, struct osl_object *); __noreturn void afs_init(uint32_t cookie, int socket_fd); +void afs_event(enum afs_events event, struct para_buffer *pb, + void *data); int send_callback_request(callback_function *f, struct osl_object *query, struct osl_object *result); int send_standard_callback_request(int argc, char * const * const argv, @@ -121,7 +154,7 @@ int score_add(const struct osl_row *row, long score); int score_update(const struct osl_row *aft_row, long new_score); int get_num_admissible_files(unsigned *num); int score_delete(const struct osl_row *aft_row); -int row_belongs_to_score_table(const struct osl_row *aft_row); +int row_belongs_to_score_table(const struct osl_row *aft_row, unsigned *rank); /* attribute */ void attribute_init(struct afs_table *t); @@ -145,9 +178,7 @@ int aft_check_callback(const struct osl_object *query, struct osl_object *result /* mood */ int change_current_mood(char *mood_name); -int mood_update_audio_file(const struct osl_row *aft_row, struct afs_info *old_afsi); int reload_current_mood(void); -int mood_delete_audio_file(const struct osl_row *aft_row); int mood_check_callback(__a_unused const struct osl_object *query, struct osl_object *result); @@ -166,8 +197,11 @@ int playlist_check_callback(__a_unused const struct osl_object *query, void table_name ## _init(struct afs_table *t); \ int cmd_prefix ## _get_name_by_id(uint32_t id, char **name); \ int cmd_prefix ## _get_def_by_id(uint32_t id, struct osl_object *def); \ + int cmd_prefix ## _get_def_by_name(char *name, struct osl_object *def); \ int cmd_prefix ## _get_name_and_def_by_row(const struct osl_row *row, \ char **name, struct osl_object *def); \ + int table_name ##_event_handler(enum afs_events event, \ + struct para_buffer *pb, void *data); \ extern struct osl_table *table_name ## _table; DECLARE_BLOB_SYMBOLS(lyrics, lyr); diff --git a/aft.c b/aft.c index c63ab471..46d67292 100644 --- a/aft.c +++ b/aft.c @@ -647,8 +647,11 @@ int open_and_update_audio_file(struct osl_row *aft_row, struct audio_file_data * save_afsi(&new_afsi, &afsi_obj); /* in-place update */ if (afd->current_play_mode == PLAY_MODE_PLAYLIST) ret = playlist_update_audio_file(aft_row); - else - ret = mood_update_audio_file(aft_row, &afd->afsi); + else { + struct afsi_change_event_data aced = {.aft_row = aft_row, + .old_afsi = &afd->afsi}; + afs_event(AFSI_CHANGE, NULL, &aced); + } return ret; err: free(afd->afhi.chunk_table); @@ -774,7 +777,6 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts, sprintf(score_buf, "%li ", d->score); } - PARA_NOTICE_LOG("id: %s, %d\n", d->path, afsi->audio_format_id); if (opts->mode == LS_MODE_LONG) { para_printf(b, "%s" /* score */ @@ -1096,13 +1098,11 @@ static int com_ls_callback(const struct osl_object *query, time_t current_time; - PARA_NOTICE_LOG("%d patterns\n", opts->num_patterns); if (opts->num_patterns) { opts->patterns = para_malloc(opts->num_patterns * sizeof(char *)); for (i = 0, p = pattern_start; i < opts->num_patterns; i++) { opts->patterns[i] = p; p += strlen(p) + 1; - PARA_NOTICE_LOG("pattern %d: %s\n", i, opts->patterns[i]); } } else opts->patterns = NULL; @@ -1114,10 +1114,8 @@ static int com_ls_callback(const struct osl_object *query, if (ret < 0) goto out; ret = opts->num_patterns? -E_NO_MATCH : 0; - if (!opts->num_matching_paths) { - PARA_NOTICE_LOG("no match, ret: %d\n", ret); + if (!opts->num_matching_paths) goto out; - } ret = sort_matching_paths(opts); if (ret < 0) goto out; @@ -1137,7 +1135,6 @@ static int com_ls_callback(const struct osl_object *query, ret = 1; out: ls_output->data = b.buf; - PARA_NOTICE_LOG("ls_outoute.data: %p\n", ls_output->data); ls_output->size = b.size; free(opts->data); free(opts->data_ptr); @@ -1388,7 +1385,7 @@ static int com_add_callback(const struct osl_object *query, { char *buf = query->data, *path; struct osl_row *pb, *aft_row; - const struct osl_row *hs; + struct osl_row *hs; struct osl_object objs[NUM_AFT_COLUMNS]; HASH_TYPE *hash; char asc[2 * HASH_SIZE + 1]; @@ -1429,13 +1426,18 @@ static int com_add_callback(const struct osl_object *query, pb = NULL; } /* file rename, update hs' path */ - ret = osl_get_object(audio_file_table, hs, AFTCOL_PATH, &obj); - if (flags & ADD_FLAG_VERBOSE) + if (flags & ADD_FLAG_VERBOSE) { + ret = osl_get_object(audio_file_table, hs, + AFTCOL_PATH, &obj); + if (ret < 0) + goto out; para_printf(&msg, "renamed from %s\n", (char *)obj.data); + } ret = osl_update_object(audio_file_table, hs, AFTCOL_PATH, &objs[AFTCOL_PATH]); if (ret < 0) goto out; + afs_event(AUDIO_FILE_RENAME, &msg, hs); if (!(flags & ADD_FLAG_FORCE)) goto out; } @@ -1466,7 +1468,7 @@ static int com_add_callback(const struct osl_object *query, goto out; } if (hs || pb) { /* (hs != NULL and pb != NULL) implies hs == pb */ - const struct osl_row *row = pb? pb : hs; + struct osl_row *row = pb? pb : hs; /* update afhi and chunk_table */ if (flags & ADD_FLAG_VERBOSE) para_printf(&msg, "updating afhi and chunk table\n"); @@ -1476,6 +1478,9 @@ static int com_add_callback(const struct osl_object *query, goto out; ret = osl_update_object(audio_file_table, row, AFTCOL_CHUNKS, &objs[AFTCOL_CHUNKS]); + if (ret < 0) + goto out; + afs_event(AFHI_CHANGE, &msg, row); goto out; } /* new entry, use default afsi */ @@ -1728,6 +1733,7 @@ static int touch_audio_file(__a_unused struct osl_table *table, struct afs_info old_afsi, new_afsi; int ret, no_options = tad->cto->num_played < 0 && tad->cto->last_played < 0 && tad->cto->lyrics_id < 0 && tad->cto->image_id < 0; + struct afsi_change_event_data aced; ret = get_afsi_object_of_row(row, &obj); if (ret < 0) { @@ -1760,9 +1766,9 @@ static int touch_audio_file(__a_unused struct osl_table *table, new_afsi.last_played = tad->cto->last_played; } save_afsi(&new_afsi, &obj); /* in-place update */ - ret = mood_update_audio_file(row, &old_afsi); - if (ret < 0) - para_printf(&tad->pb, "%s: %s\n", name, PARA_STRERROR(-ret)); + aced.aft_row = row; + aced.old_afsi = &old_afsi; + afs_event(AFSI_CHANGE, &tad->pb, &aced); return 1; } @@ -1880,9 +1886,7 @@ static int remove_audio_file(__a_unused struct osl_table *table, 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)); + afs_event(AUDIO_FILE_REMOVE, &crd->pb, row); ret = osl_del_row(audio_file_table, row); if (ret < 0) para_printf(&crd->pb, "%s: %s\n", name, PARA_STRERROR(-ret)); @@ -1999,12 +2003,14 @@ static int copy_selector_info(__a_unused struct osl_table *table, struct cpsi_action_data *cad = data; struct osl_object target_afsi_obj; int ret; - struct afs_info target_afsi; + struct afs_info old_afsi, target_afsi; + struct afsi_change_event_data aced; ret = get_afsi_object_of_row(row, &target_afsi_obj); if (ret < 0) return ret; load_afsi(&target_afsi, &target_afsi_obj); + old_afsi = target_afsi; if (cad->flags & CPSI_FLAG_COPY_LYRICS_ID) target_afsi.lyrics_id = cad->source_afsi.lyrics_id; if (cad->flags & CPSI_FLAG_COPY_IMAGE_ID) @@ -2019,6 +2025,9 @@ static int copy_selector_info(__a_unused struct osl_table *table, cad->num_copied++; if (cad->flags & CPSI_FLAG_VERBOSE) para_printf(&cad->pb, "copied afsi to %s\n", name); + aced.aft_row = row; + aced.old_afsi = &old_afsi; + afs_event(AFSI_CHANGE, &cad->pb, &aced); return 1; } @@ -2222,10 +2231,45 @@ static int aft_create(const char *dir) return osl_create_table(&audio_file_table_desc); } +static int clear_attribute(struct osl_row *row, void *data) +{ + struct rmatt_event_data *red = data; + struct afs_info afsi; + struct osl_object obj; + int ret = get_afsi_object_of_row(row, &obj); + uint64_t mask = ~(1ULL << red->bitnum); + + if (ret < 0) + return ret; + ret = load_afsi(&afsi, &obj); + if (ret < 0) + return ret; + afsi.attributes &= mask; + save_afsi(&afsi, &obj); + return 1; +} + +static int aft_event_handler(enum afs_events event, struct para_buffer *pb, + void *data) +{ + switch(event) { + case ATTRIBUTE_REMOVE: { + const struct rmatt_event_data *red = data; + para_printf(pb, "clearing attribute %s (bit %u) from all " + "entries in the audio file table\n", red->name, + red->bitnum); + return audio_file_loop(data, clear_attribute); + } + default: + return 1; + } +} + void aft_init(struct afs_table *t) { t->name = audio_file_table_desc.name; t->open = aft_open; t->close = aft_close; t->create = aft_create; + t->event_handler = aft_event_handler; } diff --git a/attribute.c b/attribute.c index 48f108c7..b130ab29 100644 --- a/attribute.c +++ b/attribute.c @@ -281,23 +281,6 @@ int com_setatt(__a_unused int fd, int argc, char * const * const argv) NULL); } -/* TODO: make it faster by only extracting the attribute member from afsi */ -static int logical_and_attribute(struct osl_row *aft_row, void *attribute_ptr) -{ - struct afs_info afsi; - uint64_t *att = attribute_ptr; - struct osl_object obj; - int ret = get_afsi_object_of_row(aft_row, &obj); - if (ret < 0) - return ret; - ret = load_afsi(&afsi, &obj); - if (ret < 0) - return ret; - afsi.attributes &= *att; - save_afsi(&afsi, &obj); - return 1; -} - static int com_addatt_callback(const struct osl_object *query, struct osl_object *result) { @@ -311,6 +294,7 @@ static int com_addatt_callback(const struct osl_object *query, struct osl_row *row; unsigned char bitnum; len = strlen(p); + struct addatt_event_data aed; if (!len || p[len - 1] == '-' || p[len - 1] == '+') { para_printf(&pb, "invalid attribute name: %s\n", p); @@ -320,14 +304,14 @@ static int com_addatt_callback(const struct osl_object *query, objs[ATTCOL_NAME].data = p; objs[ATTCOL_NAME].size = len + 1; ret = osl_get_row(attribute_table, ATTCOL_NAME, - &objs[ATTCOL_NAME], &row); /* expected to fail */ + &objs[ATTCOL_NAME], &row); /* expected to fail FIXME: Use get_attribute_bitnum_by_name() */ if (ret >= 0) { para_printf(&pb, "attribute %s already exists\n", p); continue; } if (ret != -E_RB_KEY_NOT_FOUND) /* error */ goto out; - /* find smallest non-used attribute */ + /* find smallest non-used attribute FIXME: Use find_greatest_att_bitnum() */ for (bitnum = 0; bitnum < 64; bitnum++) { objs[ATTCOL_BITNUM].data = &bitnum; ret = osl_get_row(attribute_table, ATTCOL_BITNUM, @@ -345,6 +329,9 @@ static int com_addatt_callback(const struct osl_object *query, ret = osl_add_row(attribute_table, objs); if (ret < 0) goto out; + aed.name = p; + aed.bitnum = bitnum; + afs_event(ATTRIBUTE_ADD, &pb, &aed); greatest_att_bitnum = PARA_MAX(greatest_att_bitnum, bitnum); } out: @@ -375,6 +362,56 @@ int com_addatt(int fd, int argc, char * const * const argv) return ret; } +static int com_mvatt_callback(const struct osl_object *query, + struct osl_object *result) +{ + char *old = query->data; + size_t size = strlen(old) + 1; + char *new = old + size; + struct osl_object obj = {.data = old, .size = size}; + struct osl_row *row; + struct para_buffer pb = {.size = 0}; + int ret; + + ret = osl_get_row(attribute_table, ATTCOL_NAME, &obj, &row); + if (ret < 0) + goto out; + obj.data = new; + obj.size = strlen(new) + 1; + ret = osl_update_object(attribute_table, row, ATTCOL_NAME, &obj); +out: + if (ret < 0) + para_printf(&pb, "%s\n", PARA_STRERROR(-ret)); + else + afs_event(ATTRIBUTE_RENAME, &pb, NULL); + if (!pb.buf) + return 0; + result->data = pb.buf; + result->size = pb.size; + return 1; +} + +int com_mvatt(int fd, int argc, char * const * const argv) +{ + struct osl_object result; + int ret; + + if (argc != 3) + return -E_ATTR_SYNTAX; + ret = send_standard_callback_request(argc - 1, argv + 1, com_mvatt_callback, + &result); + if (!ret) + return 1; + if (ret < 0) + return ret; + if (!result.data || !result.size) + return 1; + ret = send_va_buffer(fd, "%s", (char *) result.data); + free(result.data); + return ret; +} + + struct remove_attribute_action_data { struct para_buffer pb; int num_removed; @@ -385,10 +422,10 @@ static int remove_attribute(struct osl_table *table, struct osl_row *row, const char *name, void *data) { struct remove_attribute_action_data *raad = data; - unsigned char bitnum; int ret; + struct rmatt_event_data red = {.name = name}; - ret = get_attribute_bitnum_by_name(name, &bitnum); + ret = get_attribute_bitnum_by_name(name, &red.bitnum); if (ret < 0) { para_printf(&raad->pb, "%s: %s\n", name, PARA_STRERROR(-ret)); return 1; @@ -398,9 +435,10 @@ static int remove_attribute(struct osl_table *table, struct osl_row *row, para_printf(&raad->pb, "%s: %s\n", name, PARA_STRERROR(-ret)); return 1; } - para_printf(&raad->pb, "removed %s\n", name); + para_printf(&raad->pb, "removed attribute %s\n", name); raad->num_removed++; - raad->mask_of_removed_atts |= (1 << bitnum); + raad->mask_of_removed_atts |= (1 << red.bitnum); + afs_event(ATTRIBUTE_REMOVE, &raad->pb, &red); return 1; } @@ -420,17 +458,7 @@ static int com_rmatt_callback(const struct osl_object *query, ret = for_each_matching_row(&pmd); if (ret < 0) para_printf(&raad.pb, "%s\n", PARA_STRERROR(-ret)); - if (raad.num_removed) { - uint64_t and_mask = ~raad.mask_of_removed_atts; - ret = audio_file_loop(&and_mask, logical_and_attribute); - if (ret < 0) - para_printf(&raad.pb, "%s\n", PARA_STRERROR(-ret)); - find_greatest_att_bitnum(); - ret = reload_current_mood(); - if (ret < 0) - para_printf(&raad.pb, "%s\n", PARA_STRERROR(-ret)); - } - if (!raad.pb.buf) + if (!raad.num_removed) para_printf(&raad.pb, "no match -- nothing removed\n"); result->data = raad.pb.buf; result->size = raad.pb.size; @@ -455,7 +483,7 @@ int com_rmatt(int fd, int argc, char * const * const argv) } /** - * Return a binary representation of the geiven attribute value. + * Return a binary representation of the given attribute value. * * \param atts Pointer to the attribute value. * \param buf Result. diff --git a/blob.c b/blob.c index 3c877744..2abf2628 100644 --- a/blob.c +++ b/blob.c @@ -410,6 +410,30 @@ static int blob_get_name_by_id(struct osl_table *table, uint32_t id, return blob_get_name_by_id(table_name ## _table, id, name); \ } + +static int blob_get_def_by_name(struct osl_table *table, char *name, + struct osl_object *def) +{ + struct osl_row *row; + struct osl_object obj = {.data = name, .size = strlen(name) + 1}; + int ret; + + def->data = NULL; + if (!*name) + return 1; + ret = osl_get_row(table, BLOBCOL_NAME, &obj, &row); + if (ret < 0) + return ret; + return osl_open_disk_object(table, row, BLOBCOL_DEF, def); +} + +/** Define the \p get_def_by_id function for this blob type. */ +#define DEFINE_GET_DEF_BY_NAME(table_name, cmd_prefix) \ + int cmd_prefix ## _get_def_by_name(char *name, struct osl_object *def) \ + { \ + return blob_get_def_by_name(table_name ## _table, name, def); \ + } + static int blob_get_def_by_id(struct osl_table *table, uint32_t id, struct osl_object *def) { @@ -499,6 +523,7 @@ static int blob_open(struct osl_table **table, t->open = table_name ## _open; \ t->close = table_name ## _close; \ t->create = table_name ## _create;\ + t->event_handler = table_name ##_event_handler; \ } @@ -515,6 +540,7 @@ static int blob_open(struct osl_table **table, DEFINE_BLOB_COMMAND(mv, table_name, cmd_prefix) \ DEFINE_GET_NAME_BY_ID(table_name, cmd_prefix); \ DEFINE_GET_DEF_BY_ID(table_name, cmd_prefix); \ + DEFINE_GET_DEF_BY_NAME(table_name, cmd_prefix); \ DEFINE_GET_NAME_AND_DEF_BY_ROW(table_name, cmd_prefix); \ /** \cond doxygen isn't smart enough to recognize these */ diff --git a/error.h b/error.h index d4bbf85c..a3f80bb9 100644 --- a/error.h +++ b/error.h @@ -107,6 +107,7 @@ extern const char **para_errlist[]; #define PLAYLIST_ERRORS \ PARA_ERROR(NO_PLAYLIST, "no valid playlist found"), \ PARA_ERROR(PLAYLIST_LOADED, ""), /* not really an error */ \ + PARA_ERROR(PATH_FOUND, ""), /* not really an error */ \ PARA_ERROR(PLAYLIST_EMPTY, "attempted to load empty playlist"), \ diff --git a/mood.c b/mood.c index 64cfe835..a8d87cde 100644 --- a/mood.c +++ b/mood.c @@ -852,13 +852,13 @@ static int delete_from_statistics_and_score_table(const struct osl_row *aft_row) * * \return Positive on success, negative on errors. * - * \sa score_delete(), mood_update_audio_file(). + * \sa score_delete(). */ -int mood_delete_audio_file(const struct osl_row *aft_row) +static int mood_delete_audio_file(const struct osl_row *aft_row) { int ret; - ret = row_belongs_to_score_table(aft_row); + ret = row_belongs_to_score_table(aft_row, NULL); if (ret < 0) return ret; if (!ret) /* not admissible, nothing to do */ @@ -877,15 +877,17 @@ int mood_delete_audio_file(const struct osl_row *aft_row) * * \return Positive on success, negative on errors. */ -int mood_update_audio_file(const struct osl_row *aft_row, struct afs_info *old_afsi) +static int mood_update_audio_file(const struct osl_row *aft_row, + struct afs_info *old_afsi) { long score, percent; int ret, is_admissible, was_admissible = 0; struct afs_info afsi; + unsigned rank; if (!current_mood) return 1; /* nothing to do */ - ret = row_belongs_to_score_table(aft_row); + ret = row_belongs_to_score_table(aft_row, &rank); if (ret < 0) return ret; was_admissible = ret; @@ -919,7 +921,7 @@ int mood_update_audio_file(const struct osl_row *aft_row, struct afs_info *old_a percent = 100; else if (percent < 0) percent = 0; - PARA_DEBUG_LOG("re-inserting at %lu%%\n", percent); + PARA_DEBUG_LOG("moving from rank %u to %lu%%\n", rank, percent); return score_update(aft_row, percent); } @@ -1047,10 +1049,34 @@ int reload_current_mood(void) if (!current_mood) return 1; -// score_close(0); mood_name = para_strdup(current_mood->name); close_current_mood(); ret = change_current_mood(mood_name); free(mood_name); return ret; } + +int moods_event_handler(enum afs_events event, struct para_buffer *pb, + void *data) +{ + switch(event) { + case ATTRIBUTE_ADD: + case ATTRIBUTE_REMOVE: + case ATTRIBUTE_RENAME: + return reload_current_mood(); + case AFSI_CHANGE: { + struct afsi_change_event_data *aced = data; + return mood_update_audio_file(aced->aft_row, aced->old_afsi); + } + case AFHI_CHANGE: + case AUDIO_FILE_RENAME: + case AUDIO_FILE_ADD: + return mood_update_audio_file(data, NULL); + case AUDIO_FILE_REMOVE: + return mood_delete_audio_file(data); + default: + return 1; + } + return 1; +} + diff --git a/osl.c b/osl.c index 19d7961e..36da808a 100644 --- a/osl.c +++ b/osl.c @@ -366,7 +366,7 @@ static int init_column_descriptions(struct osl_table *t) if (ret < 0) goto err; ret = -E_BAD_DB_DIR; - if (!t->desc->dir) + if (!t->desc->dir && (t->num_disk_storage_columns || t->num_mapped_columns)) goto err; /* the size of the index header without column descriptions */ t->index_header_size = IDX_COLUMN_DESCRIPTIONS; @@ -659,10 +659,7 @@ static int create_table_index(struct osl_table *t) * * \param desc Pointer to the table description. * - * \return Positive on success, negative on errors. Possible errors include: \p - * E_BAD_TABLE_DESC, \p E_BAD_DB_DIR, \p E_BAD_NAME, \p E_NO_COMPARE_FUNC, \p - * E_NO_COLUMN_NAME, \p E_DUPLICATE_COL_NAME, \p E_MKDIR, any errors returned - * by para_open(). + * \return Standard. */ int osl_create_table(const struct osl_table_description *desc) { @@ -1203,10 +1200,7 @@ int init_rbtrees(struct osl_table *t) * The table description given by \a desc should coincide with the * description used at creation time. * - * \return Positive on success, negative on errors. Possible errors include: - * errors returned by init_table_structure(), \p E_NOENT, \p E_STAT, \p \p - * E_NOTDIR, \p E_BAD_TABLE_DESC, \p E_BAD_DB_DIR, \p E_NO_COMPARE_FUNC, \p - * E_NO_COLUMN_NAME, errors returned by init_rbtrees(). + * \return Standard. */ int osl_open_table(const struct osl_table_description *table_desc, struct osl_table **result) @@ -1836,9 +1830,7 @@ out: * mapped columns of constant size (which may be updated directly if \p * OSL_RBTREE is not set). Otherwise the rbtree might become corrupted. * - * \return Positive on success, negative on errors. Possible errors include: \p - * E_BAD_TABLE, \p E_RB_KEY_EXISTS, \p E_BAD_SIZE, \p E_NOENT, \p E_UNLINK, - * errors returned by para_write_file(), \p E_MKDIR. + * \return Standard */ int osl_update_object(struct osl_table *t, const struct osl_row *r, unsigned col_num, struct osl_object *obj) @@ -2007,7 +1999,7 @@ int osl_get_num_rows(const struct osl_table *t, unsigned *num_rows) * \param rank Result pointer. * * The rank is, by definition, the position of the row in the linear order - * determined by an inorder tree walk of the rbtree associated with column + * determined by an in-order tree walk of the rbtree associated with column * number \a col_num of \a table. * * \return Positive on success, negative on errors. diff --git a/playlist.c b/playlist.c index ca427bc7..56e19fed 100644 --- a/playlist.c +++ b/playlist.c @@ -40,7 +40,7 @@ static int add_playlist_entry(char *path, void *data) } ret = score_add(aft_row, -playlist->length); if (ret < 0) { - PARA_ERROR_LOG("failed to add %s: %d\n", path, ret); + PARA_ERROR_LOG("failed to add %s: %s\n", path, PARA_STRERROR(-ret)); return ret; } playlist->length++; @@ -181,5 +181,73 @@ int playlist_open(char *name) PARA_NOTICE_LOG("failed to load playlist %s\n", name); return ret; } - return load_playlist(row, ¤t_playlist); + ret = load_playlist(row, ¤t_playlist); + return (ret == -E_PLAYLIST_LOADED)? 1 : ret; +} + +static int search_path(char *path, void *data) +{ + if (strcmp(path, data)) + return 1; + return -E_PATH_FOUND; +} + +static int handle_audio_file_event(enum afs_events event, void *data) +{ + int ret, was_admissible = 0, is_admissible; + struct osl_object playlist_def; + char *new_path; + const struct osl_row *row = data; + + if (!current_playlist.name) + return 1; + if (event == AUDIO_FILE_RENAME) { + ret = row_belongs_to_score_table(row, NULL); + if (ret < 0) + return ret; + was_admissible = ret; + } + ret = get_audio_file_path_of_row(row, &new_path); + if (ret < 0) + return ret; + ret = pl_get_def_by_name(current_playlist.name, &playlist_def); + if (ret < 0) + return ret; + ret = for_each_line_ro(playlist_def.data, playlist_def.size, + search_path, new_path); + osl_close_disk_object(&playlist_def); + is_admissible = (ret < 0); + if (was_admissible && is_admissible) + return 1; + if (!was_admissible && !is_admissible) + return 1; + if (was_admissible && !is_admissible) { + current_playlist.length--; + return score_delete(row); + } + /* !was_admissible && is_admissible */ + current_playlist.length++; + return score_add(row, 0); /* play it immediately */ +} + +int playlists_event_handler(enum afs_events event, struct para_buffer *pb, + void *data) +{ + int ret; + + switch(event) { + case AUDIO_FILE_RENAME: + case AUDIO_FILE_ADD: + return handle_audio_file_event(event, data); + case AUDIO_FILE_REMOVE: + ret = row_belongs_to_score_table(data, NULL); + if (ret < 0) + return ret; + if (!ret) + return 1; + current_playlist.length--; + return score_delete(data); + default: + return 1; + } } diff --git a/score.c b/score.c index e233f735..abccb28f 100644 --- a/score.c +++ b/score.c @@ -28,7 +28,7 @@ static int ptr_compare(const struct osl_object *obj1, const struct osl_object *o * \param obj2 Pointer to the second score object. * * This function first compares the score values as usual integers. If they compare as - * equal, the addresss of \a obj1 and \a obj2 are compared. So this compare function + * equal, the address of \a obj1 and \a obj2 are compared. So this compare function * returns zero if and only if \a obj1 and \a obj2 point to the same memory area. * * \sa osl_compare_function. @@ -45,7 +45,7 @@ static int score_compare(const struct osl_object *obj1, const struct osl_object } /** - * The score table consists of two colums: The \a aft_row column contains + * The score table consists of two columns: The \a aft_row column contains * pointers to the rows of the audio file table, and the score column contains * the current score of the audio file associated with that row. */ @@ -144,7 +144,7 @@ int score_add(const struct osl_row *aft_row, long score) // PARA_DEBUG_LOG("adding %p\n", *(void **) (score_objs[SCORECOL_AFT_ROW].data)); ret = osl_add_row(score_table, score_objs); if (ret < 0) { - PARA_ERROR_LOG("failed to add row: %d\n", ret); + PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret)); free(score_objs[SCORECOL_AFT_ROW].data); free(score_objs[SCORECOL_SCORE].data); } @@ -167,7 +167,7 @@ static int get_nth_score(unsigned n, long *score) * \param aft_row Determines the audio file to change. * \param percent The position to re-insert the audio file. * - * The percent paramenter must be between \p 0 and 100 and. A value of zero + * The percent parameter must be between \p 0 and 100 and. A value of zero * means to re-insert the audio file into the score table with a score lower * than any other admissible file. * @@ -196,8 +196,7 @@ int score_update(const struct osl_row *aft_row, long percent) obj.size = sizeof(long); obj.data = para_malloc(obj.size); *(long *)obj.data = new_score; - PARA_DEBUG_LOG("new score: %ld, position: %u/%u\n", new_score, - new_pos, n); + PARA_DEBUG_LOG("new score: %ld, rank %u/%u\n", new_score, new_pos, n); return osl_update_object(score_table, row, SCORECOL_SCORE, &obj); } @@ -315,19 +314,27 @@ int score_delete(const struct osl_row *aft_row) * Find out whether an audio file is contained in the score table. * * \param aft_row The row of the audio file table. + * \param rank Result pointer * * \return Positive, if \a aft_row belongs to the audio file table, - * zero if not, negative on errors. + * zero if not, negative on errors. If \a aft_row was found, and \a rank + * is not \p NULL, the rank of \a aft_row is returned in \a rank. */ -int row_belongs_to_score_table(const struct osl_row *aft_row) +int row_belongs_to_score_table(const struct osl_row *aft_row, unsigned *rank) { struct osl_row *score_row; int ret = get_score_row_from_aft_row(aft_row, &score_row); - if (ret >= 0) - return 1; + if (ret == -E_RB_KEY_NOT_FOUND) return 0; - return ret; + if (ret < 0) + return ret; + if (!rank) + return 1; + ret = osl_get_rank(score_table, score_row, SCORECOL_SCORE, rank); + if (ret < 0) + return ret; + return 1; } /* Close the score table. */ @@ -340,26 +347,41 @@ static void score_close(void) /** * Open the score table. * - * \param dir The database directory. + * \param dir Unused. * * \return The return value of the underlying call to osl_open_table(). - * - * \sa score_shutdown(). */ -static int score_open(const char *dir) +static int score_open(__a_unused const char *dir) { - score_table_desc.dir = dir; + score_table_desc.dir = NULL; /* this table has only volatile columns */ return osl_open_table(&score_table_desc, &score_table); } +static int score_event_handler(enum afs_events event, struct para_buffer *pb, + void *data) +{ + int ret; + + switch(event) { + case ATTRIBUTE_ADD: + case ATTRIBUTE_REMOVE: + case ATTRIBUTE_RENAME: { + score_close(); + return score_open(NULL); + } + default: return 1; + } +} + /** * Initialize the scoring subsystem. * - * \param t Members Gets filled in by the function. + * \param t The members of \t are filled in by the function. */ void score_init(struct afs_table *t) { t->name = score_table_desc.name; t->open = score_open; t->close = score_close; + t->event_handler = score_event_handler; } -- 2.39.2