#include <fnmatch.h>
#include <sys/shm.h>
#include <osl.h>
+#include <lopsub.h>
+#include "server_cmd.lsg.h"
#include "para.h"
#include "error.h"
#include "crypt.h"
return -E_STRFTIME;
return 1;
}
- if (!strftime(buf, size, "%b %e %Y", tm))
+ /*
+ * If the given time is more than six month away from the current time,
+ * we print only the year. The additional space character in the format
+ * string below makes the formated date align nicely with dates that
+ * contain the time (those written by the above strftime() statement).
+ */
+ if (!strftime(buf, size, "%b %e %Y", tm))
return -E_STRFTIME;
return 1;
}
if (!hours) { /* m:ss or mm:ss */
max_width = opts->mode == LS_MODE_LONG?
opts->widths.duration_width : 4;
- sprintf(buf, "%*u:%02u", max_width - 3, mins, seconds % 60);
+ sprintf(buf, "%*u:%02d", max_width - 3, mins, seconds % 60);
} else { /* more than one hour => h:mm:ss, hh:mm:ss, hhh:mm:ss, ... */
max_width = opts->mode == LS_MODE_LONG?
opts->widths.duration_width : 7;
- sprintf(buf, "%*u:%02u:%02u", max_width - 6, hours, mins,
+ sprintf(buf, "%*u:%02u:%02d", max_width - 6, hours, mins,
seconds % 60);
}
}
para_printf(b,
"%s " /* attributes */
"%*u " /* amp */
- "%*d " /* image_id */
- "%*d " /* lyrics_id */
- "%*d " /* bitrate */
+ "%*u " /* image_id */
+ "%*u " /* lyrics_id */
+ "%*u " /* bitrate */
"%*s " /* audio format */
- "%*d " /* frequency */
- "%d " /* channels */
+ "%*u " /* frequency */
+ "%u " /* channels */
"%s " /* duration */
- "%*d " /* num_played */
+ "%*u " /* num_played */
"%s " /* last_played */
"%s\n", /* path */
att_buf,
WRITE_STATUS_ITEM(b, SI_SECONDS_TOTAL, "%" PRIu32 "\n",
afhi->seconds_total);
WRITE_STATUS_ITEM(b, SI_LAST_PLAYED, "%s\n", last_played_time);
- WRITE_STATUS_ITEM(b, SI_NUM_PLAYED, "%d\n", afsi->num_played);
+ WRITE_STATUS_ITEM(b, SI_NUM_PLAYED, "%u\n", afsi->num_played);
WRITE_STATUS_ITEM(b, SI_AMPLIFICATION, "%u\n", afsi->amp);
WRITE_STATUS_ITEM(b, SI_CHUNK_TIME, "%lu\n", tv2ms(&afhi->chunk_tv));
WRITE_STATUS_ITEM(b, SI_NUM_CHUNKS, "%" PRIu32 "\n",
return -E_AFT_SYNTAX;
}
}
- if (!strcmp(arg, "-p")) {
+ 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;
CAB_AFHI_OFFSET_POS = 0,
/** Start of the chunk table (if present). */
CAB_CHUNKS_OFFSET_POS = 4,
- /** Flags given to the add command. */
- CAB_FLAGS_OFFSET = 8,
+ /** Start of the (serialized) lopsub parse result. */
+ CAB_LPR_OFFSET = 8,
/** Audio format id. */
CAB_AUDIO_FORMAT_ID_OFFSET = 12,
/** The hash of the audio file being added. */
* handler info won't be stored in the buffer.
*/
static void save_add_callback_buffer(unsigned char *hash, const char *path,
- struct afh_info *afhi, uint32_t flags,
+ struct afh_info *afhi, const char *slpr, size_t slpr_size,
uint8_t audio_format_num, struct osl_object *obj)
{
size_t path_len = strlen(path) + 1;
size_t afhi_size = sizeof_afhi_buf(afhi);
size_t size = CAB_PATH_OFFSET + path_len + afhi_size
- + sizeof_chunk_table(afhi);
+ + sizeof_chunk_table(afhi) + slpr_size;
char *buf = para_malloc(size);
uint32_t pos;
+ assert(size <= ~(uint32_t)0);
+ write_u8(buf + CAB_AUDIO_FORMAT_ID_OFFSET, audio_format_num);
+ memcpy(buf + CAB_HASH_OFFSET, hash, HASH_SIZE);
+ strcpy(buf + CAB_PATH_OFFSET, path);
pos = CAB_PATH_OFFSET + path_len;
write_u32(buf + CAB_AFHI_OFFSET_POS, pos);
save_afhi(afhi, buf + pos);
pos += afhi_size;
-
write_u32(buf + CAB_CHUNKS_OFFSET_POS, pos);
- if (afhi)
+ if (afhi) {
save_chunk_table(afhi, buf + pos);
-
- write_u32(buf + CAB_FLAGS_OFFSET, flags);
- write_u8(buf + CAB_AUDIO_FORMAT_ID_OFFSET, audio_format_num);
-
- memcpy(buf + CAB_HASH_OFFSET, hash, HASH_SIZE);
- strcpy(buf + CAB_PATH_OFFSET, path);
-
+ pos += sizeof_chunk_table(afhi);
+ }
+ write_u32(buf + CAB_LPR_OFFSET, pos);
+ memcpy(buf + pos, slpr, slpr_size);
+ assert(pos + slpr_size == size);
obj->data = buf;
obj->size = size;
}
*/
-/** Flags passed to the add command. */
-enum com_add_flags {
- /** Skip paths that exist already. */
- ADD_FLAG_LAZY = 1,
- /** Force adding. */
- ADD_FLAG_FORCE = 2,
- /** Print what is being done. */
- ADD_FLAG_VERBOSE = 4,
- /** Try to add files with unknown suffixes. */
- ADD_FLAG_ALL = 8,
-};
-
static int com_add_callback(struct afs_callback_arg *aca)
{
char *buf = aca->query.data, *path;
char asc[2 * HASH_SIZE + 1];
int ret;
char afsi_buf[AFSI_SIZE];
- uint32_t flags = read_u32(buf + CAB_FLAGS_OFFSET);
+ char *slpr = buf + read_u32(buf + CAB_LPR_OFFSET);
struct afs_info default_afsi = {.last_played = 0};
uint16_t afhi_offset, chunks_offset;
+ const struct lls_command *cmd = SERVER_CMD_CMD_PTR(ADD);
+ const struct lls_opt_result *r_f, *r_v;
+
+ ret = lls_deserialize_parse_result(slpr, cmd, &aca->lpr);
+ assert(ret >= 0);
+ r_f = SERVER_CMD_OPT_RESULT(ADD, FORCE, aca->lpr);
+ r_v = SERVER_CMD_OPT_RESULT(ADD, VERBOSE, aca->lpr);
hash = (unsigned char *)buf + CAB_HASH_OFFSET;
hash_to_asc(hash, asc);
ret = find_path_brother(path, &pb);
if (ret < 0)
goto out;
- if (hs && pb && hs == pb && !(flags & ADD_FLAG_FORCE)) {
- if (flags & ADD_FLAG_VERBOSE)
+ if (hs && pb && hs == pb && !lls_opt_given(r_f)) {
+ if (lls_opt_given(r_v))
para_printf(&aca->pbout, "ignoring duplicate\n");
ret = 1;
goto out;
if (hs && hs != pb) {
struct osl_object obj;
if (pb) { /* hs trumps pb, remove pb */
- if (flags & ADD_FLAG_VERBOSE)
+ if (lls_opt_given(r_v))
para_printf(&aca->pbout, "removing %s\n", path);
ret = afs_event(AUDIO_FILE_REMOVE, &aca->pbout, pb);
if (ret < 0)
pb = NULL;
}
/* file rename, update hs' path */
- if (flags & ADD_FLAG_VERBOSE) {
+ if (lls_opt_given(r_v)) {
ret = osl(osl_get_object(audio_file_table, hs,
AFTCOL_PATH, &obj));
if (ret < 0)
ret = afs_event(AUDIO_FILE_RENAME, &aca->pbout, hs);
if (ret < 0)
goto out;
- if (!(flags & ADD_FLAG_FORCE))
+ if (!lls_opt_given(r_f))
goto out;
}
/* no hs or force mode, child must have sent afhi */
if (ret < 0)
goto out;
hash_to_asc(old_hash, old_asc);
- if (flags & ADD_FLAG_VERBOSE)
+ if (lls_opt_given(r_v))
para_printf(&aca->pbout, "file change: %s -> %s\n",
old_asc, asc);
- ret = osl_update_object(audio_file_table, pb, AFTCOL_HASH,
- &objs[AFTCOL_HASH]);
+ ret = osl(osl_update_object(audio_file_table, pb, AFTCOL_HASH,
+ &objs[AFTCOL_HASH]));
if (ret < 0)
goto out;
}
if (hs || pb) { /* (hs != NULL and pb != NULL) implies hs == pb */
struct osl_row *row = pb? pb : hs;
/* update afhi and chunk_table */
- if (flags & ADD_FLAG_VERBOSE)
+ if (lls_opt_given(r_v))
para_printf(&aca->pbout,
"updating afhi and chunk table\n");
ret = osl(osl_update_object(audio_file_table, row, AFTCOL_AFHI,
if (ret < 0)
goto out;
ret = afs_event(AFHI_CHANGE, &aca->pbout, row);
- if (ret < 0)
- goto out;
goto out;
}
/* new entry, use default afsi */
- if (flags & ADD_FLAG_VERBOSE)
+ if (lls_opt_given(r_v))
para_printf(&aca->pbout, "new file\n");
default_afsi.last_played = time(NULL) - 365 * 24 * 60 * 60;
default_afsi.audio_format_id = read_u8(buf + CAB_AUDIO_FORMAT_ID_OFFSET);
out:
if (ret < 0)
para_printf(&aca->pbout, "could not add %s\n", path);
+ lls_free_parse_result(aca->lpr, cmd);
return ret;
}
-/** Used by com_add(). */
+/* Used by com_add(). */
struct private_add_data {
- /** The pointer passed to the original command handler. */
+ /* The pointer passed to the original command handler. */
struct command_context *cc;
- /** The given add flags. */
- uint32_t flags;
+ /* Contains the flags given at the command line. */
+ struct lls_parse_result *lpr;
+ /* Serialized lopsub parse result. */
+ char *slpr;
+ /* Number of bytes. */
+ size_t slpr_size;
};
static int path_brother_callback(struct afs_callback_arg *aca)
struct osl_row *pb = NULL, *hs = NULL; /* path brother/hash sister */
struct osl_object map, obj = {.data = NULL}, query;
unsigned char hash[HASH_SIZE];
+ bool a_given = SERVER_CMD_OPT_GIVEN(ADD, ALL, pad->lpr);
+ bool f_given = SERVER_CMD_OPT_GIVEN(ADD, FORCE, pad->lpr);
+ bool l_given = SERVER_CMD_OPT_GIVEN(ADD, LAZY, pad->lpr);
+ bool v_given = SERVER_CMD_OPT_GIVEN(ADD, VERBOSE, pad->lpr);
ret = guess_audio_format(path);
- if (ret < 0 && !(pad->flags & ADD_FLAG_ALL)) {
+ if (ret < 0 && !a_given) {
ret = 0;
goto out_free;
}
if (ret < 0 && ret != -OSL_ERRNO_TO_PARA_ERROR(E_OSL_RB_KEY_NOT_FOUND))
goto out_free;
ret = 1;
- if (pb && (pad->flags & ADD_FLAG_LAZY)) { /* lazy is really cheap */
- if (pad->flags & ADD_FLAG_VERBOSE)
+ if (pb && l_given) { /* lazy is really cheap */
+ if (v_given)
send_ret = send_sb_va(&pad->cc->scc, SBD_OUTPUT,
"lazy-ignore: %s\n", path);
goto out_free;
goto out_unmap;
/* Return success if we already know this file. */
ret = 1;
- if (pb && hs && hs == pb && !(pad->flags & ADD_FLAG_FORCE)) {
- if (pad->flags & ADD_FLAG_VERBOSE)
+ if (pb && hs && hs == pb && !f_given) {
+ if (v_given)
send_ret = send_sb_va(&pad->cc->scc, SBD_OUTPUT,
"%s exists, not forcing update\n", path);
goto out_unmap;
* We won't recalculate the audio format info and the chunk table if
* there is a hash sister and FORCE was not given.
*/
- if (!hs || (pad->flags & ADD_FLAG_FORCE)) {
+ if (!hs || f_given) {
ret = compute_afhi(path, map.data, map.size, fd, &afhi);
if (ret < 0)
goto out_unmap;
}
munmap(map.data, map.size);
close(fd);
- if (pad->flags & ADD_FLAG_VERBOSE) {
+ if (v_given) {
send_ret = send_sb_va(&pad->cc->scc, SBD_OUTPUT,
"adding %s\n", path);
if (send_ret < 0)
goto out_free;
}
- save_add_callback_buffer(hash, path, afhi_ptr, pad->flags, format_num, &obj);
+ save_add_callback_buffer(hash, path, afhi_ptr, pad->slpr,
+ pad->slpr_size, format_num, &obj);
/* Ask afs to consider this entry for adding. */
ret = send_callback_request(com_add_callback, &obj,
afs_cb_result_handler, pad->cc);
return send_ret;
}
-int com_add(struct command_context *cc)
+static int com_add(struct command_context *cc, struct lls_parse_result *lpr)
{
int i, ret;
- struct private_add_data pad = {.cc = cc, .flags = 0};
+ struct private_add_data pad = {.cc = cc, .lpr = lpr};
+ const struct lls_command *cmd = SERVER_CMD_CMD_PTR(ADD);
+ unsigned num_inputs;
+ 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 (!strcmp(arg, "-a")) {
- pad.flags |= ADD_FLAG_ALL;
- continue;
- }
- if (!strcmp(arg, "-l")) {
- pad.flags |= ADD_FLAG_LAZY;
- continue;
- }
- if (!strcmp(arg, "-f")) {
- pad.flags |= ADD_FLAG_FORCE;
- continue;
- }
- if (!strcmp(arg, "-v")) {
- pad.flags |= ADD_FLAG_VERBOSE;
- continue;
- }
+ ret = lls(lls_check_arg_count(lpr, 1, INT_MAX, &errctx));
+ if (ret < 0) {
+ send_errctx(cc, errctx);
+ return ret;
}
- if (cc->argc <= i)
- return -E_AFT_SYNTAX;
- for (; i < cc->argc; i++) {
+ ret = lls_serialize_parse_result(lpr, cmd, &pad.slpr, &pad.slpr_size);
+ assert(ret >= 0);
+ num_inputs = lls_num_inputs(lpr);
+ for (i = 0; i < num_inputs; i++) {
char *path;
- ret = verify_path(cc->argv[i], &path);
+ ret = verify_path(lls_input(i, lpr), &path);
if (ret < 0) {
ret = send_sb_va(&cc->scc, SBD_ERROR_LOG, "%s: %s\n",
- cc->argv[i], para_strerror(-ret));
+ lls_input(i, lpr), para_strerror(-ret));
if (ret < 0)
- return ret;
+ goto out;
continue;
}
if (ret == 1) /* directory */
}
free(path);
}
- return 1;
+ ret = 1;
+out:
+ free(pad.slpr);
+ return ret;
}
+EXPORT_SERVER_CMD_HANDLER(add);
/**
* Flags used by the touch command.
.data = aca,
.action = touch_audio_file
};
+ if (cto->image_id >= 0) {
+ ret = img_get_name_by_id(cto->image_id, NULL);
+ if (ret < 0) {
+ para_printf(&aca->pbout, "invalid image ID: %d\n",
+ cto->image_id);
+ return ret;
+ }
+ }
+ if (cto->lyrics_id >= 0) {
+ ret = lyr_get_name_by_id(cto->lyrics_id, NULL);
+ if (ret < 0) {
+ para_printf(&aca->pbout, "invalid lyrics ID: %d\n",
+ cto->lyrics_id);
+ return ret;
+ }
+ }
if (cto->flags & TOUCH_FLAG_FNM_PATHNAME)
pmd.fnmatch_flags |= FNM_PATHNAME;
ret = for_each_matching_row(&pmd);
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
-};
-
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;
- for (
- p = aca->query.data;
- p < (char *)aca->query.data + aca->query.size;
- p += len + 1
- ) {
- char c;
+ ret = lls_deserialize_parse_result(aca->query.data, cmd, &aca->lpr);
+ assert(ret >= 0);
+ pmd.lpr = aca->lpr;
+
+ 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)
{
if (ret >= 0) {
unsigned num;
osl_get_num_rows(audio_file_table, &num);
- PARA_INFO_LOG("audio file table contains %d files\n", num);
+ PARA_INFO_LOG("audio file table contains %u files\n", num);
return ret;
}
PARA_NOTICE_LOG("failed to open audio file table\n");