X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=aft.c;h=3190a9bafa5e4fdd0ef750f3fcf4160057ce7ddf;hp=7141e3fa91f5fa8a1afeb0bd9fb460401d54f9ef;hb=534a94f441767947874cb15d18211edf758e9277;hpb=f2d9fcc2aad0df59ae5a635564760c1cff4fcfc6 diff --git a/aft.c b/aft.c index 7141e3fa..3190a9ba 100644 --- a/aft.c +++ b/aft.c @@ -88,18 +88,6 @@ struct ls_data { unsigned char *hash; }; -/** The flags accepted by the ls command. */ -enum ls_flags { - /** -p */ - LS_FLAG_FULL_PATH = 1, - /** -a */ - LS_FLAG_ADMISSIBLE_ONLY = 2, - /** -r */ - LS_FLAG_REVERSE = 4, - /** -d */ - LS_FLAG_UNIXDATE = 8, -}; - /** * The size of the individual output fields of the ls command. * @@ -130,16 +118,11 @@ struct ls_widths { /** Data passed from the ls command handler to its callback function. */ struct ls_options { - /** The given command line flags. */ - unsigned flags; - /** The sorting method given at the command line. */ + struct lls_parse_result *lpr; + /* Derived from lpr */ enum ls_sorting_method sorting; - /** The given listing mode (short, long, verbose, mbox). */ + /* Derived from lpr */ enum ls_listing_mode mode; - /** The arguments passed to the ls command. */ - char **patterns; - /** Number of non-option arguments. */ - int num_patterns; /** Used for long listing mode to align the output fields. */ struct ls_widths widths; /** Size of the \a data array. */ @@ -785,11 +768,11 @@ static void write_image_items(struct para_buffer *b, struct afs_info *afsi) } static void write_filename_items(struct para_buffer *b, const char *path, - unsigned flags) + bool basename) { char *val; - if (!(flags & LS_FLAG_FULL_PATH)) { + if (basename) { WRITE_STATUS_ITEM(b, SI_BASENAME, "%s\n", path); return; } @@ -830,17 +813,12 @@ static int print_chunk_table(struct ls_data *d, struct para_buffer *b) return ret; } -static void write_score(struct para_buffer *b, struct ls_data *d, - struct ls_options *opts) -{ - if (!(opts->flags & LS_FLAG_ADMISSIBLE_ONLY)) /* no score*/ - return; - WRITE_STATUS_ITEM(b, SI_SCORE, "%li\n", d->score); -} - static int print_list_item(struct ls_data *d, struct ls_options *opts, struct para_buffer *b, time_t current_time) { + const struct lls_opt_result *r_a = SERVER_CMD_OPT_RESULT(LS, ADMISSIBLE, opts->lpr); + const struct lls_opt_result *r_b = SERVER_CMD_OPT_RESULT(LS, BASENAME, opts->lpr); + const struct lls_opt_result *r_d = SERVER_CMD_OPT_RESULT(LS, UNIX_DATE, opts->lpr); int ret; char att_buf[65]; char last_played_time[30]; @@ -859,7 +837,7 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts, goto out; } get_attribute_bitmap(&afsi->attributes, att_buf); - if (opts->flags & LS_FLAG_UNIXDATE) + if (lls_opt_given(r_d)) sprintf(last_played_time, "%llu", (long long unsigned)afsi->last_played); else { @@ -871,10 +849,9 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts, get_duration_buf(afhi->seconds_total, duration_buf, opts); if (opts->mode == LS_MODE_LONG) { struct ls_widths *w = &opts->widths; - if (opts->flags & LS_FLAG_ADMISSIBLE_ONLY) { + if (lls_opt_given(r_a)) para_printf(b, "%*li ", opts->widths.score_width, d->score); - } para_printf(b, "%s " /* attributes */ "%*u " /* amp */ @@ -914,8 +891,9 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts, last_played_time, bn? bn : "?"); } - write_filename_items(b, d->path, opts->flags); - write_score(b, d, opts); + write_filename_items(b, d->path, lls_opt_given(r_b)); + if (lls_opt_given(r_a)) + WRITE_STATUS_ITEM(b, SI_SCORE, "%li\n", d->score); ret = write_attribute_items(b, att_buf, afsi); if (ret < 0) goto out; @@ -982,21 +960,23 @@ out: static int make_status_items(void) { - struct ls_options opts = { - .flags = LS_FLAG_FULL_PATH | LS_FLAG_ADMISSIBLE_ONLY, - .mode = LS_MODE_VERBOSE, - }; + const struct lls_command *cmd = SERVER_CMD_CMD_PTR(LS); + char *argv[] = {"ls", "--admissible", "--listing-mode=verbose"}; + struct ls_options opts = {.mode = LS_MODE_VERBOSE}; struct para_buffer pb = {.max_size = shm_get_shmmax() - 1}; time_t current_time; int ret; + ret = lls_parse(ARRAY_SIZE(argv), argv, cmd, &opts.lpr, NULL); + assert(ret >= 0); time(¤t_time); ret = print_list_item(&status_item_ls_data, &opts, &pb, current_time); if (ret < 0) - return ret; + goto out; make_inode_status_items(&pb); free(status_items); status_items = pb.buf; + memset(&pb, 0, sizeof(pb)); pb.max_size = shm_get_shmmax() - 1; pb.flags = PBF_SIZE_PREFIX; @@ -1009,7 +989,10 @@ static int make_status_items(void) make_inode_status_items(&pb); free(parser_friendly_status_items); parser_friendly_status_items = pb.buf; - return 1; + ret = 1; +out: + lls_free_parse_result(opts.lpr, cmd); + return ret; } /** @@ -1163,8 +1146,16 @@ static int ls_path_compare(const void *a, const void *b) return strcmp(d1->path, d2->path); } +static inline bool admissible_only(struct ls_options *opts) +{ + return SERVER_CMD_OPT_GIVEN(LS, ADMISSIBLE, opts->lpr) + || opts->sorting == LS_SORT_BY_SCORE; +} + static int sort_matching_paths(struct ls_options *options) { + const struct lls_opt_result *r_b = SERVER_CMD_OPT_RESULT(LS, BASENAME, + options->lpr); size_t nmemb = options->num_matching_paths; size_t size = sizeof(*options->data_ptr); int (*compar)(const void *, const void *); @@ -1175,13 +1166,13 @@ static int sort_matching_paths(struct ls_options *options) options->data_ptr[i] = options->data + i; /* In these cases the array is already sorted */ - if (options->sorting == LS_SORT_BY_PATH - && !(options->flags & LS_FLAG_ADMISSIBLE_ONLY) - && (options->flags & LS_FLAG_FULL_PATH)) - return 1; - if (options->sorting == LS_SORT_BY_SCORE && - options->flags & LS_FLAG_ADMISSIBLE_ONLY) - return 1; + if (admissible_only(options)) { + if (options->sorting == LS_SORT_BY_SCORE) + return 1; + } else { + if (options->sorting == LS_SORT_BY_PATH && !lls_opt_given(r_b)) + return 1; + } switch (options->sorting) { case LS_SORT_BY_PATH: @@ -1219,15 +1210,16 @@ static int prepare_ls_row(struct osl_row *row, void *ls_opts) { int ret, i; struct ls_options *options = ls_opts; + bool basename_given = SERVER_CMD_OPT_GIVEN(LS, BASENAME, options->lpr); struct ls_data *d; struct ls_widths *w; unsigned short num_digits; - unsigned tmp; + unsigned tmp, num_inputs; struct osl_row *aft_row; long score; char *path; - if (options->flags & LS_FLAG_ADMISSIBLE_ONLY) { + if (admissible_only(options)) { ret = get_score_and_aft_row(row, &score, &aft_row); if (ret < 0) return ret; @@ -1238,21 +1230,22 @@ static int prepare_ls_row(struct osl_row *row, void *ls_opts) ret = get_audio_file_path_of_row(aft_row, &path); if (ret < 0) return ret; - if (!(options->flags & LS_FLAG_FULL_PATH)) { + if (basename_given) { char *p = strrchr(path, '/'); if (p) path = p + 1; } - if (options->num_patterns) { - for (i = 0; i < options->num_patterns; i++) { - ret = fnmatch(options->patterns[i], path, 0); + num_inputs = lls_num_inputs(options->lpr); + if (num_inputs > 0) { + for (i = 0; i < num_inputs; i++) { + ret = fnmatch(lls_input(i, options->lpr), path, 0); if (!ret) break; if (ret == FNM_NOMATCH) continue; return -E_FNMATCH; } - if (i >= options->num_patterns) /* no match */ + if (i >= num_inputs) /* no match */ return 1; } tmp = options->num_matching_paths++; @@ -1291,7 +1284,7 @@ static int prepare_ls_row(struct osl_row *row, void *ls_opts) w->amp_width = PARA_MAX(w->amp_width, num_digits); num_digits = strlen(audio_format_name(d->afsi.audio_format_id)); w->audio_format_width = PARA_MAX(w->audio_format_width, num_digits); - if (options->flags & LS_FLAG_ADMISSIBLE_ONLY) { + if (admissible_only(options)) { GET_NUM_DIGITS(score, &num_digits); num_digits++; /* add one for the sign (space or "-") */ w->score_width = PARA_MAX(w->score_width, num_digits); @@ -1304,21 +1297,19 @@ err: static int com_ls_callback(struct afs_callback_arg *aca) { + const struct lls_command *cmd = SERVER_CMD_CMD_PTR(LS); struct ls_options *opts = aca->query.data; - char *p, *pattern_start = (char *)aca->query.data + sizeof(*opts); int i = 0, ret; time_t current_time; + const struct lls_opt_result *r_r; + + ret = lls_deserialize_parse_result( + (char *)aca->query.data + sizeof(*opts), cmd, &opts->lpr); + assert(ret >= 0); + r_r = SERVER_CMD_OPT_RESULT(LS, REVERSE, opts->lpr); aca->pbout.flags = (opts->mode == LS_MODE_PARSER)? PBF_SIZE_PREFIX : 0; - 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; - } - } else - opts->patterns = NULL; - if (opts->flags & LS_FLAG_ADMISSIBLE_ONLY) + if (admissible_only(opts)) ret = admissible_file_loop(opts, prepare_ls_row); else ret = osl(osl_rbtree_loop(audio_file_table, AFTCOL_PATH, opts, @@ -1326,14 +1317,14 @@ static int com_ls_callback(struct afs_callback_arg *aca) if (ret < 0) goto out; if (opts->num_matching_paths == 0) { - ret = opts->num_patterns > 0? -E_NO_MATCH : 0; + ret = lls_num_inputs(opts->lpr) > 0? -E_NO_MATCH : 0; goto out; } ret = sort_matching_paths(opts); if (ret < 0) goto out; time(¤t_time); - if (opts->flags & LS_FLAG_REVERSE) + if (lls_opt_given(r_r)) for (i = opts->num_matching_paths - 1; i >= 0; i--) { ret = print_list_item(opts->data_ptr[i], opts, &aca->pbout, current_time); @@ -1348,143 +1339,90 @@ static int com_ls_callback(struct afs_callback_arg *aca) goto out; } out: + lls_free_parse_result(opts->lpr, cmd); free(opts->data); free(opts->data_ptr); - free(opts->patterns); return ret; } -/* - * TODO: flags -h (sort by hash) - */ -int com_ls(struct command_context *cc) +/* TODO: flags -h (sort by hash) */ +static int com_ls(struct command_context *cc, struct lls_parse_result *lpr) { - int i; - unsigned flags = 0; - enum ls_sorting_method sort = LS_SORT_BY_PATH; - enum ls_listing_mode mode = LS_MODE_SHORT; - struct ls_options opts = {.patterns = NULL}; - struct osl_object query = {.data = &opts, .size = sizeof(opts)}; - - for (i = 1; i < cc->argc; i++) { - const char *arg = cc->argv[i]; - if (arg[0] != '-') - break; - if (!strcmp(arg, "--")) { - i++; - break; - } - /* - * Compatibility: Prior to 0.5.5 it was necessary to specify - * the listing mode without the '=' character as in -lv, for - * example. Now the variant with '=' is preferred and - * documented but we still accept the old way to specify the - * listing mode. - * - * Support for the legacy syntax can be dropped at 0.6.0 - * or later. - */ - if (!strncmp(arg, "-l", 2)) { - arg += 2; - if (*arg == '=') - arg++; - switch (*arg) { - case 's': - mode = LS_MODE_SHORT; - continue; - case 'l': - case '\0': - mode = LS_MODE_LONG; - continue; - case 'v': - mode = LS_MODE_VERBOSE; - continue; - case 'm': - mode = LS_MODE_MBOX; - continue; - case 'c': - mode = LS_MODE_CHUNKS; - continue; - case 'p': - mode = LS_MODE_PARSER; - continue; - default: - return -E_AFT_SYNTAX; - } - } - if (!strcmp(arg, "-p") || !strcmp(arg, "-F")) { - flags |= LS_FLAG_FULL_PATH; - continue; - } - if (!strcmp(arg, "-b")) { - flags &= ~LS_FLAG_FULL_PATH; - continue; - } - if (!strcmp(arg, "-a")) { - flags |= LS_FLAG_ADMISSIBLE_ONLY; - continue; - } - if (!strcmp(arg, "-r")) { - flags |= LS_FLAG_REVERSE; - continue; - } - if (!strcmp(arg, "-d")) { - flags |= LS_FLAG_UNIXDATE; - continue; + const struct lls_command *cmd = SERVER_CMD_CMD_PTR(LS); + struct ls_options *opts; + struct osl_object query; + const struct lls_opt_result *r_l = SERVER_CMD_OPT_RESULT(LS, LISTING_MODE, + lpr); + const struct lls_opt_result *r_s = SERVER_CMD_OPT_RESULT(LS, SORT, lpr); + int ret; + char *slpr; + + ret = lls_serialize_parse_result(lpr, cmd, NULL, &query.size); + assert(ret >= 0); + query.size += sizeof(*opts); + query.data = para_malloc(query.size); + opts = query.data; + memset(opts, 0, sizeof(*opts)); + slpr = query.data + sizeof(*opts); + ret = lls_serialize_parse_result(lpr, cmd, &slpr, NULL); + assert(ret >= 0); + opts->mode = LS_MODE_SHORT; + opts->sorting = LS_SORT_BY_PATH; + if (lls_opt_given(r_l)) { + const char *val = lls_string_val(0, r_l); + if (!strcmp(val, "l") || !strcmp(val, "long")) + opts->mode = LS_MODE_LONG; + else if (!strcmp(val, "s") || !strcmp(val, "short")) + opts->mode = LS_MODE_SHORT; + else if (!strcmp(val, "v") || !strcmp(val, "verbose")) + opts->mode = LS_MODE_VERBOSE; + else if (!strcmp(val, "m") || !strcmp(val, "mbox")) + opts->mode = LS_MODE_MBOX; + else if (!strcmp(val, "c") || !strcmp(val, "chunk-table")) + opts->mode = LS_MODE_MBOX; + else if (!strcmp(val, "p") || !strcmp(val, "parser-friendly")) + opts->mode = LS_MODE_PARSER; + else { + ret = -E_AFT_SYNTAX; + goto out; } - /* The compatibility remark above applies also to -s. */ - if (!strncmp(arg, "-s", 2)) { - arg += 2; - if (*arg == '=') - arg++; - switch (*arg) { - case 'p': - sort = LS_SORT_BY_PATH; - continue; - case 's': /* -ss implies -a */ - sort = LS_SORT_BY_SCORE; - flags |= LS_FLAG_ADMISSIBLE_ONLY; - continue; - case 'l': - sort = LS_SORT_BY_LAST_PLAYED; - continue; - case 'n': - sort = LS_SORT_BY_NUM_PLAYED; - continue; - case 'f': - sort = LS_SORT_BY_FREQUENCY; - continue; - case 'c': - sort = LS_SORT_BY_CHANNELS; - continue; - case 'i': - sort = LS_SORT_BY_IMAGE_ID; - continue; - case 'y': - sort = LS_SORT_BY_LYRICS_ID; - continue; - case 'b': - sort = LS_SORT_BY_BITRATE; - continue; - case 'd': - sort = LS_SORT_BY_DURATION; - continue; - case 'a': - sort = LS_SORT_BY_AUDIO_FORMAT; - continue; - default: - return -E_AFT_SYNTAX; - } + } + if (lls_opt_given(r_s)) { + const char *val = lls_string_val(0, r_s); + if (!strcmp(val, "p") || !strcmp(val, "path")) + opts->sorting = LS_SORT_BY_PATH; + else if (!strcmp(val, "s") || !strcmp(val, "score")) + opts->sorting = LS_SORT_BY_SCORE; + else if (!strcmp(val, "l") || !strcmp(val, "lastplayed")) + opts->sorting = LS_SORT_BY_LAST_PLAYED; + else if (!strcmp(val, "n") || !strcmp(val, "numplayed")) + opts->sorting = LS_SORT_BY_NUM_PLAYED; + else if (!strcmp(val, "f") || !strcmp(val, "frquency")) + opts->sorting = LS_SORT_BY_FREQUENCY; + else if (!strcmp(val, "c") || !strcmp(val, "channels")) + opts->sorting = LS_SORT_BY_CHANNELS; + else if (!strcmp(val, "i") || !strcmp(val, "image-id")) + opts->sorting = LS_SORT_BY_IMAGE_ID; + else if (!strcmp(val, "y") || !strcmp(val, "lyrics-id")) + opts->sorting = LS_SORT_BY_LYRICS_ID; + else if (!strcmp(val, "b") || !strcmp(val, "bitrate")) + opts->sorting = LS_SORT_BY_BITRATE; + else if (!strcmp(val, "d") || !strcmp(val, "duration")) + opts->sorting = LS_SORT_BY_DURATION; + else if (!strcmp(val, "a") || !strcmp(val, "audio-format")) + opts->sorting = LS_SORT_BY_AUDIO_FORMAT; + else { + ret = -E_AFT_SYNTAX; + goto out; } - return -E_AFT_SYNTAX; } - opts.flags = flags; - opts.sorting = sort; - opts.mode = mode; - opts.num_patterns = cc->argc - i; - return send_option_arg_callback_request(&query, opts.num_patterns, - cc->argv + i, com_ls_callback, afs_cb_result_handler, cc); + ret = send_callback_request(com_ls_callback, &query, + afs_cb_result_handler, cc); +out: + free(query.data); + return ret; } +EXPORT_SERVER_CMD_HANDLER(ls); /** * Call the given function for each file in the audio file table. @@ -1956,33 +1894,26 @@ enum touch_flags { TOUCH_FLAG_VERBOSE = 2 }; -/** Options used by com_touch(). */ -struct com_touch_options { - /** New num_played value. */ - int32_t num_played; - /** New last played count. */ - int64_t last_played; - /** New lyrics id. */ - int32_t lyrics_id; - /** New image id. */ - int32_t image_id; - /** New amplification value. */ - int32_t amp; - /** Command line flags (see \ref touch_flags). */ - unsigned flags; -}; - static int touch_audio_file(__a_unused struct osl_table *table, struct osl_row *row, const char *name, void *data) { struct afs_callback_arg *aca = data; - struct com_touch_options *cto = aca->query.data; + bool v_given = SERVER_CMD_OPT_GIVEN(TOUCH, VERBOSE, aca->lpr); + const struct lls_opt_result *r_n, *r_l, *r_i, *r_y, *r_a; + int ret; struct osl_object obj; struct afs_info old_afsi, new_afsi; - int ret, no_options = cto->num_played < 0 && cto->last_played < 0 && - cto->lyrics_id < 0 && cto->image_id < 0 && cto->amp < 0; + bool no_options; struct afsi_change_event_data aced; + r_n = SERVER_CMD_OPT_RESULT(TOUCH, NUMPLAYED, aca->lpr); + r_l = SERVER_CMD_OPT_RESULT(TOUCH, LASTPLAYED, aca->lpr); + r_i = SERVER_CMD_OPT_RESULT(TOUCH, IMAGE_ID, aca->lpr); + r_y = SERVER_CMD_OPT_RESULT(TOUCH, LYRICS_ID, aca->lpr); + r_a = SERVER_CMD_OPT_RESULT(TOUCH, AMP, aca->lpr); + no_options = !lls_opt_given(r_n) && !lls_opt_given(r_l) && !lls_opt_given(r_i) + && !lls_opt_given(r_y) && !lls_opt_given(r_a); + ret = get_afsi_object_of_row(row, &obj); if (ret < 0) { para_printf(&aca->pbout, "cannot touch %s\n", name); @@ -1997,23 +1928,23 @@ static int touch_audio_file(__a_unused struct osl_table *table, if (no_options) { new_afsi.num_played++; new_afsi.last_played = time(NULL); - if (cto->flags & TOUCH_FLAG_VERBOSE) + if (v_given) para_printf(&aca->pbout, "%s: num_played = %u, " "last_played = now()\n", name, new_afsi.num_played); } else { - if (cto->flags & TOUCH_FLAG_VERBOSE) + if (lls_opt_given(r_l)) + new_afsi.last_played = lls_uint64_val(0, r_l); + if (lls_opt_given(r_n)) + new_afsi.num_played = lls_uint32_val(0, r_n); + if (lls_opt_given(r_i)) + new_afsi.image_id = lls_uint32_val(0, r_i); + if (lls_opt_given(r_y)) + new_afsi.lyrics_id = lls_uint32_val(0, r_y); + if (lls_opt_given(r_a)) + new_afsi.amp = lls_uint32_val(0, r_a); + if (v_given) para_printf(&aca->pbout, "touching %s\n", name); - if (cto->lyrics_id >= 0) - new_afsi.lyrics_id = cto->lyrics_id; - if (cto->image_id >= 0) - new_afsi.image_id = cto->image_id; - if (cto->num_played >= 0) - new_afsi.num_played = cto->num_played; - if (cto->last_played >= 0) - new_afsi.last_played = cto->last_played; - if (cto->amp >= 0) - new_afsi.amp = cto->amp; } save_afsi(&new_afsi, &obj); /* in-place update */ aced.aft_row = row; @@ -2023,115 +1954,64 @@ static int touch_audio_file(__a_unused struct osl_table *table, static int com_touch_callback(struct afs_callback_arg *aca) { + const struct lls_command *cmd = SERVER_CMD_CMD_PTR(TOUCH); + bool p_given; + const struct lls_opt_result *r_i, *r_y; int ret; - struct com_touch_options *cto = aca->query.data; struct pattern_match_data pmd = { .table = audio_file_table, .loop_col_num = AFTCOL_HASH, .match_col_num = AFTCOL_PATH, - .patterns = { - .data = (char *)aca->query.data - + sizeof(struct com_touch_options), - .size = aca->query.size - - sizeof(struct com_touch_options) - }, .data = aca, .action = touch_audio_file }; - if (cto->image_id >= 0) { - ret = img_get_name_by_id(cto->image_id, NULL); + + ret = lls_deserialize_parse_result(aca->query.data, cmd, &aca->lpr); + assert(ret >= 0); + pmd.lpr = aca->lpr; + + r_i = SERVER_CMD_OPT_RESULT(TOUCH, IMAGE_ID, aca->lpr); + if (lls_opt_given(r_i)) { + uint32_t id = lls_uint32_val(0, r_i); + ret = img_get_name_by_id(id, NULL); if (ret < 0) { - para_printf(&aca->pbout, "invalid image ID: %d\n", - cto->image_id); + para_printf(&aca->pbout, "invalid image ID: %u\n", id); return ret; } } - if (cto->lyrics_id >= 0) { - ret = lyr_get_name_by_id(cto->lyrics_id, NULL); + r_y = SERVER_CMD_OPT_RESULT(TOUCH, LYRICS_ID, aca->lpr); + if (lls_opt_given(r_y)) { + uint32_t id = lls_uint32_val(0, r_y); + ret = lyr_get_name_by_id(id, NULL); if (ret < 0) { - para_printf(&aca->pbout, "invalid lyrics ID: %d\n", - cto->lyrics_id); + para_printf(&aca->pbout, "invalid lyrics ID: %u\n", id); return ret; } } - if (cto->flags & TOUCH_FLAG_FNM_PATHNAME) + p_given = SERVER_CMD_OPT_GIVEN(TOUCH, PATHNAME_MATCH, aca->lpr); + if (p_given) pmd.fnmatch_flags |= FNM_PATHNAME; ret = for_each_matching_row(&pmd); if (ret >= 0 && pmd.num_matches == 0) ret = -E_NO_MATCH; + lls_free_parse_result(aca->lpr, cmd); return ret; } -int com_touch(struct command_context *cc) +static int com_touch(struct command_context *cc, struct lls_parse_result *lpr) { - struct com_touch_options cto = { - .num_played = -1, - .last_played = -1, - .lyrics_id = -1, - .image_id = -1, - .amp = -1, - }; - struct osl_object query = {.data = &cto, .size = sizeof(cto)}; - int i, ret; - + const struct lls_command *cmd = SERVER_CMD_CMD_PTR(TOUCH); + int ret; + char *errctx; - for (i = 1; i < cc->argc; i++) { - const char *arg = cc->argv[i]; - if (arg[0] != '-') - break; - if (!strcmp(arg, "--")) { - i++; - break; - } - if (!strncmp(arg, "-n=", 3)) { - ret = para_atoi32(arg + 3, &cto.num_played); - if (ret < 0) - return ret; - continue; - } - if (!strncmp(arg, "-l=", 3)) { - ret = para_atoi64(arg + 3, &cto.last_played); - if (ret < 0) - return ret; - continue; - } - if (!strncmp(arg, "-y=", 3)) { - ret = para_atoi32(arg + 3, &cto.lyrics_id); - if (ret < 0) - return ret; - continue; - } - if (!strncmp(arg, "-i=", 3)) { - ret = para_atoi32(arg + 3, &cto.image_id); - if (ret < 0) - return ret; - continue; - } - if (!strncmp(arg, "-a=", 3)) { - int32_t val; - ret = para_atoi32(arg + 3, &val); - if (ret < 0) - return ret; - if (val < 0 || val > 255) - return -ERRNO_TO_PARA_ERROR(EINVAL); - cto.amp = val; - continue; - } - if (!strcmp(arg, "-p")) { - cto.flags |= TOUCH_FLAG_FNM_PATHNAME; - continue; - } - if (!strcmp(arg, "-v")) { - cto.flags |= TOUCH_FLAG_VERBOSE; - continue; - } - break; /* non-option starting with dash */ + ret = lls(lls_check_arg_count(lpr, 1, INT_MAX, &errctx)); + if (ret < 0) { + send_errctx(cc, errctx); + return ret; } - if (i >= cc->argc) - return -E_AFT_SYNTAX; - return send_option_arg_callback_request(&query, cc->argc - i, - cc->argv + i, com_touch_callback, afs_cb_result_handler, cc); + return send_lls_callback_request(com_touch_callback, cmd, lpr, cc); } +EXPORT_SERVER_CMD_HANDLER(touch); static int remove_audio_file(__a_unused struct osl_table *table, struct osl_row *row, const char *name, void *data)