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.
*
/** 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. */
}
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;
}
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];
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 {
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 */
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;
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;
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;
}
/**
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 *);
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:
{
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;
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++;
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);
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,
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);
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.
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);
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;
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);
-}
-
-/** Flags for com_rm(). */
-enum rm_flags {
- /** -v */
- RM_FLAG_VERBOSE = 1,
- /** -f */
- RM_FLAG_FORCE = 2,
- /** -p */
- RM_FLAG_FNM_PATHNAME = 4
-};
+ 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)
{
struct afs_callback_arg *aca = data;
- uint32_t flags =*(uint32_t *)aca->query.data;
+ bool v_given = SERVER_CMD_OPT_GIVEN(RM, VERBOSE, aca->lpr);
int ret;
- if (flags & RM_FLAG_VERBOSE)
+ if (v_given)
para_printf(&aca->pbout, "removing %s\n", name);
ret = afs_event(AUDIO_FILE_REMOVE, &aca->pbout, row);
if (ret < 0)
static int com_rm_callback(struct afs_callback_arg *aca)
{
+ const struct lls_command *cmd = SERVER_CMD_CMD_PTR(RM);
int ret;
- uint32_t flags = *(uint32_t *)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(uint32_t),
- .size = aca->query.size - sizeof(uint32_t)},
.data = aca,
.action = remove_audio_file
};
- if (flags & RM_FLAG_FNM_PATHNAME)
+ bool v_given, p_given, f_given;
+
+ ret = lls_deserialize_parse_result(aca->query.data, cmd, &aca->lpr);
+ assert(ret >= 0);
+ pmd.lpr = aca->lpr;
+ v_given = SERVER_CMD_OPT_GIVEN(RM, VERBOSE, aca->lpr);
+ p_given = SERVER_CMD_OPT_GIVEN(RM, PATHNAME_MATCH, aca->lpr);
+ f_given = SERVER_CMD_OPT_GIVEN(RM, FORCE, aca->lpr);
+
+ if (p_given)
pmd.fnmatch_flags |= FNM_PATHNAME;
ret = for_each_matching_row(&pmd);
if (ret < 0)
goto out;
if (pmd.num_matches == 0) {
- if (!(flags & RM_FLAG_FORCE))
+ if (!f_given)
ret = -E_NO_MATCH;
- } else if (flags & RM_FLAG_VERBOSE)
+ } else if (v_given)
para_printf(&aca->pbout, "removed %u file(s)\n",
pmd.num_matches);
out:
+ lls_free_parse_result(aca->lpr, cmd);
return ret;
}
/* TODO options: -r (recursive) */
-int com_rm(struct command_context *cc)
+static int com_rm(struct command_context *cc, struct lls_parse_result *lpr)
{
- uint32_t flags = 0;
- struct osl_object query = {.data = &flags, .size = sizeof(flags)};
- int i;
+ const struct lls_command *cmd = SERVER_CMD_CMD_PTR(RM);
+ char *errctx;
+ int ret;
- for (i = 1; i < cc->argc; i++) {
- const char *arg = cc->argv[i];
- if (arg[0] != '-')
- break;
- if (!strcmp(arg, "--")) {
- 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;
- }
- break;
+ 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_rm_callback, afs_cb_result_handler, cc);
+ return send_lls_callback_request(com_rm_callback, cmd, lpr, cc);
}
-
-/**
- * Flags used by the cpsi command.
- *
- * \sa com_cpsi().
- */
-enum cpsi_flags {
- /** Whether the lyrics id should be copied. */
- CPSI_FLAG_COPY_LYRICS_ID = 1,
- /** Whether the image id should be copied. */
- CPSI_FLAG_COPY_IMAGE_ID = 2,
- /** Whether the lastplayed time should be copied. */
- CPSI_FLAG_COPY_LASTPLAYED = 4,
- /** Whether the numplayed count should be copied. */
- CPSI_FLAG_COPY_NUMPLAYED = 8,
- /** Whether the attributes should be copied. */
- CPSI_FLAG_COPY_ATTRIBUTES = 16,
- /** Activates verbose mode. */
- CPSI_FLAG_VERBOSE = 32,
-};
+EXPORT_SERVER_CMD_HANDLER(rm);
/** Data passed to the action handler of com_cpsi(). */
struct cpsi_action_data {
- /** command line flags (see \ref cpsi_flags). */
- unsigned flags;
/** Values are copied from here. */
struct afs_info source_afsi;
/** What was passed to com_cpsi_callback(). */
struct afs_callback_arg *aca;
+ bool copy_all;
};
static int copy_selector_info(__a_unused struct osl_table *table,
int ret;
struct afs_info old_afsi, target_afsi;
struct afsi_change_event_data aced;
+ bool a_given, y_given, i_given, l_given, n_given, v_given;
+
+ a_given = SERVER_CMD_OPT_GIVEN(CPSI, ATTRIBUTE_BITMAP, cad->aca->lpr);
+ y_given = SERVER_CMD_OPT_GIVEN(CPSI, LYRICS_ID, cad->aca->lpr);
+ i_given = SERVER_CMD_OPT_GIVEN(CPSI, IMAGE_ID, cad->aca->lpr);
+ l_given = SERVER_CMD_OPT_GIVEN(CPSI, LASTPLAYED, cad->aca->lpr);
+ n_given = SERVER_CMD_OPT_GIVEN(CPSI, NUMPLAYED, cad->aca->lpr);
+ v_given = SERVER_CMD_OPT_GIVEN(CPSI, VERBOSE, cad->aca->lpr);
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)
+ if (cad->copy_all || y_given)
target_afsi.lyrics_id = cad->source_afsi.lyrics_id;
- if (cad->flags & CPSI_FLAG_COPY_IMAGE_ID)
+ if (cad->copy_all || i_given)
target_afsi.image_id = cad->source_afsi.image_id;
- if (cad->flags & CPSI_FLAG_COPY_LASTPLAYED)
+ if (cad->copy_all || l_given)
target_afsi.last_played = cad->source_afsi.last_played;
- if (cad->flags & CPSI_FLAG_COPY_NUMPLAYED)
+ if (cad->copy_all || n_given)
target_afsi.num_played = cad->source_afsi.num_played;
- if (cad->flags & CPSI_FLAG_COPY_ATTRIBUTES)
+ if (cad->copy_all || a_given)
target_afsi.attributes = cad->source_afsi.attributes;
save_afsi(&target_afsi, &target_afsi_obj); /* in-place update */
- if (cad->flags & CPSI_FLAG_VERBOSE)
+ if (v_given)
para_printf(&cad->aca->pbout, "copied afsi to %s\n", name);
aced.aft_row = row;
aced.old_afsi = &old_afsi;
static int com_cpsi_callback(struct afs_callback_arg *aca)
{
- struct cpsi_action_data cad = {
- .flags = *(unsigned *)aca->query.data,
- .aca = aca
- };
+ const struct lls_command *cmd = SERVER_CMD_CMD_PTR(CPSI);
+ bool a_given, y_given, i_given, l_given, n_given, v_given;
+ struct cpsi_action_data cad = {.aca = aca};
int ret;
- char *source_path = (char *)aca->query.data + sizeof(cad.flags);
struct pattern_match_data pmd = {
.table = audio_file_table,
.loop_col_num = AFTCOL_HASH,
.match_col_num = AFTCOL_PATH,
- .patterns = {.data = source_path + strlen(source_path) + 1,
- .size = aca->query.size - sizeof(cad.flags)
- - strlen(source_path) - 1},
+ .input_skip = 1, /* skip first argument (source file) */
.data = &cad,
.action = copy_selector_info
};
- ret = get_afsi_of_path(source_path, &cad.source_afsi);
+ ret = lls_deserialize_parse_result(aca->query.data, cmd, &aca->lpr);
+ assert(ret >= 0);
+ pmd.lpr = aca->lpr;
+
+ a_given = SERVER_CMD_OPT_GIVEN(CPSI, ATTRIBUTE_BITMAP, aca->lpr);
+ y_given = SERVER_CMD_OPT_GIVEN(CPSI, LYRICS_ID, aca->lpr);
+ i_given = SERVER_CMD_OPT_GIVEN(CPSI, IMAGE_ID, aca->lpr);
+ l_given = SERVER_CMD_OPT_GIVEN(CPSI, LASTPLAYED, aca->lpr);
+ n_given = SERVER_CMD_OPT_GIVEN(CPSI, NUMPLAYED, aca->lpr);
+ v_given = SERVER_CMD_OPT_GIVEN(CPSI, VERBOSE, aca->lpr);
+ cad.copy_all = !a_given && !y_given && !i_given && !l_given && !n_given;
+
+ ret = get_afsi_of_path(lls_input(0, aca->lpr), &cad.source_afsi);
if (ret < 0)
goto out;
ret = for_each_matching_row(&pmd);
if (ret < 0)
goto out;
if (pmd.num_matches > 0) {
- if (cad.flags & CPSI_FLAG_VERBOSE)
+ if (v_given)
para_printf(&aca->pbout, "updated afsi of %u file(s)\n",
pmd.num_matches);
} else
ret = -E_NO_MATCH;
out:
+ lls_free_parse_result(aca->lpr, cmd);
return ret;
}
-int com_cpsi(struct command_context *cc)
+static int com_cpsi(struct command_context *cc, struct lls_parse_result *lpr)
{
- unsigned flags = 0;
- int i;
- struct osl_object options = {.data = &flags, .size = sizeof(flags)};
-
- for (i = 1; i < cc->argc; i++) {
- const char *arg = cc->argv[i];
- if (arg[0] != '-')
- break;
- if (!strcmp(arg, "--")) {
- i++;
- break;
- }
- if (!strcmp(arg, "-y")) {
- flags |= CPSI_FLAG_COPY_LYRICS_ID;
- continue;
- }
- if (!strcmp(arg, "-i")) {
- flags |= CPSI_FLAG_COPY_IMAGE_ID;
- continue;
- }
- if (!strcmp(arg, "-l")) {
- flags |= CPSI_FLAG_COPY_LASTPLAYED;
- continue;
- }
- if (!strcmp(arg, "-n")) {
- flags |= CPSI_FLAG_COPY_NUMPLAYED;
- continue;
- }
- if (!strcmp(arg, "-a")) {
- flags |= CPSI_FLAG_COPY_ATTRIBUTES;
- continue;
- }
- if (!strcmp(arg, "-v")) {
- flags |= CPSI_FLAG_VERBOSE;
- continue;
- }
- break;
+ const struct lls_command *cmd = SERVER_CMD_CMD_PTR(CPSI);
+ char *errctx;
+ int ret = lls(lls_check_arg_count(lpr, 2, INT_MAX, &errctx));
+ if (ret < 0) {
+ send_errctx(cc, errctx);
+ return ret;
}
- if (i + 1 >= cc->argc) /* need at least source file and pattern */
- return -E_AFT_SYNTAX;
- if (!(flags & ~CPSI_FLAG_VERBOSE)) /* no copy flags given */
- flags = ~(unsigned)CPSI_FLAG_VERBOSE | flags;
- return send_option_arg_callback_request(&options, cc->argc - i,
- cc->argv + i, com_cpsi_callback, afs_cb_result_handler, cc);
+ return send_lls_callback_request(com_cpsi_callback, cmd, lpr, cc);
}
+EXPORT_SERVER_CMD_HANDLER(cpsi);
struct change_atts_data {
uint64_t add_mask, del_mask;
static int com_setatt_callback(struct afs_callback_arg *aca)
{
- char *p;
- int ret;
- size_t len;
+ const struct lls_command *cmd = SERVER_CMD_CMD_PTR(SETATT);
+ int i, ret;
struct change_atts_data cad = {.aca = aca};
struct pattern_match_data pmd = {
.table = audio_file_table,
.data = &cad,
.action = change_atts
};
+ unsigned num_inputs;
+
+ ret = lls_deserialize_parse_result(aca->query.data, cmd, &aca->lpr);
+ assert(ret >= 0);
+ pmd.lpr = aca->lpr;
- for (
- p = aca->query.data;
- p < (char *)aca->query.data + aca->query.size;
- p += len + 1
- ) {
- char c;
+ num_inputs = lls_num_inputs(aca->lpr);
+ for (i = 0; i < num_inputs; i++) {
unsigned char bitnum;
uint64_t one = 1;
+ const char *arg = lls_input(i, aca->lpr);
+ char c, *p;
+ size_t len = strlen(arg);
- len = strlen(p);
ret = -E_ATTR_SYNTAX;
if (len == 0)
goto out;
- c = p[len - 1];
- if (c != '+' && c != '-')
- break;
+ c = arg[len - 1];
+ if (c != '+' && c != '-') {
+ if (cad.add_mask == 0 && cad.del_mask == 0)
+ goto out; /* no attribute modifier given */
+ goto set_atts;
+ }
+ p = para_malloc(len);
+ memcpy(p, arg, len - 1);
p[len - 1] = '\0';
ret = get_attribute_bitnum_by_name(p, &bitnum);
+ free(p);
if (ret < 0) {
- para_printf(&aca->pbout, "attribute not found: %s\n", p);
+ para_printf(&aca->pbout, "invalid argument: %s\n", arg);
goto out;
}
if (c == '+')
else
cad.del_mask |= (one << bitnum);
}
+ /* no pattern given */
ret = -E_ATTR_SYNTAX;
- if (!cad.add_mask && !cad.del_mask)
- goto out;
- pmd.patterns.data = p;
- if (p >= (char *)aca->query.data + aca->query.size)
- goto out;
- pmd.patterns.size = (char *)aca->query.data + aca->query.size - p;
+ goto out;
+set_atts:
+ pmd.input_skip = i;
ret = for_each_matching_row(&pmd);
- if (ret < 0)
- goto out;
- if (pmd.num_matches == 0)
+ if (ret >= 0 && pmd.num_matches == 0)
ret = -E_NO_MATCH;
out:
+ lls_free_parse_result(aca->lpr, cmd);
return ret;
}
-int com_setatt(struct command_context *cc)
+static int com_setatt(struct command_context *cc, struct lls_parse_result *lpr)
{
- if (cc->argc < 3)
- return -E_ATTR_SYNTAX;
- return send_standard_callback_request(cc->argc - 1, cc->argv + 1,
- com_setatt_callback, afs_cb_result_handler, cc);
+ const struct lls_command *cmd = SERVER_CMD_CMD_PTR(SETATT);
+ char *errctx;
+ int ret = lls(lls_check_arg_count(lpr, 2, INT_MAX, &errctx));
+
+ if (ret < 0) {
+ send_errctx(cc, errctx);
+ return ret;
+ }
+ return send_lls_callback_request(com_setatt_callback, cmd, lpr, cc);
}
+EXPORT_SERVER_CMD_HANDLER(setatt);
static int afs_stat_callback(struct afs_callback_arg *aca)
{