X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=mood.c;h=24d1de29056812973d33a18a5ed7df378a9f72ad;hp=a89ae85f4c102b6078ae1d76a0919e52b47af20c;hb=2a4d7bb5f5cecdbcbda6b9f9b531c919ecc6b161;hpb=d894e0cc7ce94d09847a8a35f47127968d4268f1 diff --git a/mood.c b/mood.c index a89ae85f..24d1de29 100644 --- a/mood.c +++ b/mood.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Andre Noll + * Copyright (C) 2007-2009 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -13,6 +13,7 @@ #include "afh.h" #include "afs.h" #include "list.h" +#include "ipc.h" /** * Contains statistical data of the currently admissible audio files. @@ -47,7 +48,7 @@ struct afs_statistics statistics; * \sa struct mood_method, mood_parser. */ typedef int mood_score_function(const char *path, const struct afs_info *afsi, - const struct audio_format_info *afhi, const void *data); + const struct afh_info *afhi, const void *data); /** * Pre-process a mood line. @@ -83,7 +84,7 @@ typedef void mood_cleanup_function(void *); * Used for scoring and to determine whether a file is admissible. */ struct mood_method { - /* The name of the method. */ + /** The name of the method. */ const char *name; /** Pointer to the mood parser. */ mood_parser *parser; @@ -172,7 +173,7 @@ static int mm_no_attributes_set_parser(const char *arg, __a_unused void **ignore static int mm_no_attributes_set_score_function(__a_unused const char *path, const struct afs_info *afsi, - __a_unused const struct audio_format_info *afhi, + __a_unused const struct afh_info *afhi, __a_unused const void *data) { if (!afsi->attributes) @@ -182,7 +183,7 @@ static int mm_no_attributes_set_score_function(__a_unused const char *path, static int mm_played_rarely_score_function(__a_unused const char *path, const struct afs_info *afsi, - __a_unused const struct audio_format_info *afhi, + __a_unused const struct afh_info *afhi, __a_unused const void *data) { unsigned num; @@ -203,9 +204,9 @@ static int mm_played_rarely_parser(const char *arg, __a_unused void **ignored) return 1; } -static int mm_name_like_score_function(const char *path, +static int mm_path_matches_score_function(const char *path, __a_unused const struct afs_info *afsi, - __a_unused const struct audio_format_info *afhi, + __a_unused const struct afh_info *afhi, const void *data) { if (fnmatch(data, path, 0)) @@ -213,13 +214,13 @@ static int mm_name_like_score_function(const char *path, return 100; } -static int mm_name_like_parser(const char *arg, void **data) +static int mm_path_matches_parser(const char *arg, void **data) { *data = para_strdup(arg); return 1; } -static void mm_name_like_cleanup(void *data) +static void mm_path_matches_cleanup(void *data) { free(data); } @@ -238,7 +239,7 @@ static int mm_is_set_parser(const char *arg, void **bitnum) static int mm_is_set_score_function(__a_unused const char *path, __a_unused const struct afs_info *afsi, - __a_unused const struct audio_format_info *afhi, + __a_unused const struct afh_info *afhi, const void *data) { const unsigned char *bn = data; @@ -247,14 +248,14 @@ static int mm_is_set_score_function(__a_unused const char *path, return -100; } -/* returns 1 if row matches score item, negative otherwise */ -static int add_item_score(const struct osl_row *row, struct mood_item *item, long *score, - long *score_arg_sum) +/* returns 1 if row matches score item, 0 if not, negative on errors */ +static int get_item_score(const struct osl_row *row, struct mood_item *item, + long *score, long *score_arg_sum) { struct afs_info afsi; - struct audio_format_info afhi; + struct afh_info afhi; char *path; - int ret; + int ret, match = 1; *score_arg_sum += item->random_score? 100 : PARA_ABS(item->score_arg); ret = 100; @@ -265,42 +266,62 @@ static int add_item_score(const struct osl_row *row, struct mood_item *item, lon ret = get_afhi_of_row(row, &afhi); if (ret< 0) return ret; + free(afhi.info_string); /* don't need the tag info */ ret = get_audio_file_path_of_row(row, &path); if (ret< 0) return ret; ret = item->method->score_function(path, &afsi, &afhi, item->parser_data); if ((ret < 0 && !item->logical_not) || (ret >= 0 && item->logical_not)) - return -1; /* no match */ + match = 0; /* no match */ } if (item->random_score) - *score += PARA_ABS(ret) * para_random(100); + *score = PARA_ABS(ret) * para_random(100); else - *score += PARA_ABS(ret) * item->score_arg; - return 1; + *score = PARA_ABS(ret) * item->score_arg; + return match; } +/* returns 1 if row admissible, 0 if not, negative on errors */ static int compute_mood_score(const struct osl_row *aft_row, struct mood *m, long *result) { struct mood_item *item; - int match = 0; - long score_arg_sum = 0, score = 0; + int ret, match = 0; + long score_arg_sum = 0, score = 0, item_score; if (!m) return -E_NO_MOOD; /* reject audio file if it matches any entry in the deny list */ - list_for_each_entry(item, &m->deny_list, mood_item_node) - if (add_item_score(aft_row, item, &score, &score_arg_sum) > 0) - return -E_NOT_ADMISSIBLE; - list_for_each_entry(item, &m->accept_list, mood_item_node) - if (add_item_score(aft_row, item, &score, &score_arg_sum) > 0) - match = 1; + list_for_each_entry(item, &m->deny_list, mood_item_node) { + ret = get_item_score(aft_row, item, &item_score, + &score_arg_sum); + if (ret < 0) + return ret; + if (ret > 0) /* not admissible */ + return 0; + score += item_score; + } + list_for_each_entry(item, &m->accept_list, mood_item_node) { + ret = get_item_score(aft_row, item, &item_score, + &score_arg_sum); + if (ret < 0) + return ret; + if (ret == 0) + continue; + match = 1; + score += item_score; + } /* reject if there is no matching entry in the accept list */ if (!match && !list_empty(&m->accept_list)) - return -E_NOT_ADMISSIBLE; - list_for_each_entry(item, &m->score_list, mood_item_node) - add_item_score(aft_row, item, &score, &score_arg_sum); + return 0; + list_for_each_entry(item, &m->score_list, mood_item_node) { + ret = get_item_score(aft_row, item, &item_score, + &score_arg_sum); + if (ret < 0) + return ret; + score += item_score; + } if (score_arg_sum) score /= score_arg_sum; *result = score; @@ -320,7 +341,7 @@ static const struct mood_method mood_methods[] = { {DEFINE_MOOD_METHOD(no_attributes_set)}, {DEFINE_MOOD_METHOD(played_rarely)}, {DEFINE_MOOD_METHOD(is_set)}, - {DEFINE_MOOD_METHOD_WITH_CLEANUP(name_like)}, + {DEFINE_MOOD_METHOD_WITH_CLEANUP(path_matches)}, {.parser = NULL} }; @@ -372,8 +393,11 @@ enum mood_line_type { ML_SCORE }; +/** Data passed to the parser of a mood line. */ struct mood_line_parser_data { + /** The mood this mood line belongs to. */ struct mood *m; + /** The line number in the mood definition. */ unsigned line_num; }; @@ -419,11 +443,13 @@ static int parse_mood_line(char *mood_line, void *data) w++; if (!*w) goto out; - if (!strcmp(*w, "with")) { - w++; - if (!*w) - goto out; - } + if (strcmp(*w, "with")) + goto check_for_if; + w++; + if (!*w) + goto out; + if (strcmp(*w, "score")) + goto out; } if (mlt == ML_SCORE || !strcmp(*w, "score")) { ret = -E_MOOD_SYNTAX; @@ -446,6 +472,7 @@ static int parse_mood_line(char *mood_line, void *data) w++; if (!*w) goto out; +check_for_if: if (!strcmp(*w, "if")) { ret = -E_MOOD_SYNTAX; w++; @@ -514,11 +541,10 @@ static int load_mood(const struct osl_row *mood_row, struct mood **m) osl_close_disk_object(&mood_def); if (ret < 0) { PARA_ERROR_LOG("unable to load mood %s: %s\n", mlpd.m->name, - PARA_STRERROR(-ret)); + para_strerror(-ret)); destroy_mood(mlpd.m); return ret; } - PARA_INFO_LOG("loaded mood %s\n", mlpd.m->name); *m = mlpd.m; return 1; } @@ -533,39 +559,47 @@ static int check_mood(struct osl_row *mood_row, void *data) int ret = mood_get_name_and_def_by_row(mood_row, &mood_name, &mood_def); if (ret < 0) { - para_printf(pb, "failed to get mood definition\n"); + para_printf(pb, "failed to get mood definition: %s\n", + para_strerror(-ret)); return ret; } if (!*mood_name) /* ignore dummy row */ goto out; - para_printf(pb, "checking mood %s...\n", mood_name); + ret = para_printf(pb, "checking mood %s...\n", mood_name); + if (ret < 0) + goto out; ret = for_each_line_ro(mood_def.data, mood_def.size, parse_mood_line, &mlpd); if (ret < 0) para_printf(pb, "%s line %u: %s\n", mood_name, mlpd.line_num, - PARA_STRERROR(-ret)); + para_strerror(-ret)); out: osl_close_disk_object(&mood_def); - return 1; + return ret; } /** * Check all moods for syntax errors. * + * \param fd The afs socket. * \param query Unused. - * \param result: Contains check messages. */ -int mood_check_callback(__a_unused const struct osl_object *query, - struct osl_object *result) +void mood_check_callback(int fd, __a_unused const struct osl_object *query) { - struct para_buffer pb = {.buf = NULL}; + struct para_buffer pb = { + .max_size = SHMMAX, + .private_data = &fd, + .max_size_handler = pass_buffer_as_shm + }; - para_printf(&pb, "checking moods...\n"); + int ret = para_printf(&pb, "checking moods...\n"); + if (ret < 0) + return; osl_rbtree_loop(moods_table, BLOBCOL_ID, &pb, check_mood); - result->data = pb.buf; - result->size = pb.size; - return 1; + if (pb.offset) + pass_buffer_as_shm(pb.buf, pb.offset, &fd); + free(pb.buf); } #if 0 @@ -715,7 +749,7 @@ struct admissible_array { * \param aft_row The audio file to be added. * \param private_data Pointer to a struct admissible_file_info. * - * \return Negative on errors, positive on success. + * \return 1 if row admissible, 0 if not, negative on errors. */ static int add_if_admissible(struct osl_row *aft_row, void *data) { @@ -724,8 +758,8 @@ static int add_if_admissible(struct osl_row *aft_row, void *data) long score = 0; ret = compute_mood_score(aft_row, aa->m, &score); - if (ret < 0) - return (ret == -E_NOT_ADMISSIBLE)? 1 : ret; + if (ret <= 0) + return ret; if (statistics.num >= aa->size) { aa->size *= 2; aa->size += 100; @@ -863,6 +897,8 @@ static int mood_update_audio_file(const struct osl_row *aft_row, return ret; was_admissible = ret; ret = compute_mood_score(aft_row, current_mood, &score); + if (ret < 0) + return ret; is_admissible = (ret > 0); if (!was_admissible && !is_admissible) return 1; @@ -904,10 +940,10 @@ static void log_statistics(void) PARA_NOTICE_LOG("no admissible files\n"); return; } - PARA_NOTICE_LOG("last_played mean: %lli, last_played sigma: %llu\n", + PARA_INFO_LOG("last_played mean: %lli, last_played sigma: %llu\n", (long long int)(statistics.last_played_sum / n), (long long unsigned)int_sqrt(statistics.last_played_qd / n)); - PARA_NOTICE_LOG("num_played mean: %lli, num_played sigma: %llu\n", + PARA_INFO_LOG("num_played mean: %lli, num_played sigma: %llu\n", (long long int)statistics.num_played_sum / n, (long long unsigned)int_sqrt(statistics.num_played_qd / n)); } @@ -972,20 +1008,19 @@ int change_current_mood(char *mood_name) current_mood = alloc_new_mood("dummy"); } aa.m = current_mood; - PARA_NOTICE_LOG("loaded mood %s\n", current_mood->name); - PARA_INFO_LOG("%s\n", "computing statistics of admissible files"); + PARA_NOTICE_LOG("computing statistics of admissible files\n"); ret = audio_file_loop(&aa, add_if_admissible); if (ret < 0) return ret; log_statistics(); - PARA_NOTICE_LOG("%d admissible files \n", statistics.num); + PARA_INFO_LOG("%d admissible files \n", statistics.num); for (i = 0; i < statistics.num; i++) { struct admissible_file_info *a = aa.array + i; ret = add_to_score_table(a->aft_row, a->score); if (ret < 0) goto out; } - PARA_NOTICE_LOG("score add complete\n"); + PARA_NOTICE_LOG("loaded mood %s\n", current_mood->name); ret = statistics.num; out: free(aa.array); @@ -1009,9 +1044,10 @@ int reload_current_mood(void) int ret; char *mood_name = NULL; - PARA_NOTICE_LOG("reloading current mood\n"); if (!current_mood) return 1; + PARA_NOTICE_LOG("reloading %s\n", current_mood->name? + current_mood->name : "(dummy)"); if (current_mood->name) mood_name = para_strdup(current_mood->name); close_current_mood(); @@ -1020,7 +1056,7 @@ int reload_current_mood(void) return ret; } -int moods_event_handler(enum afs_events event, struct para_buffer *pb, +int moods_event_handler(enum afs_events event, __a_unused struct para_buffer *pb, void *data) { switch(event) { @@ -1053,6 +1089,5 @@ int moods_event_handler(enum afs_events event, struct para_buffer *pb, default: return 1; } - return 1; }