-/*
- * Copyright (C) 2007 Andre Noll <maan@tuebingen.mpg.de>
- *
- * Licensed under the GPL v2. For licencing details see COPYING.
- */
+/* Copyright (C) 2007 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
/** \file aft.c Audio file table functions. */
#include "sideband.h"
#include "command.h"
-static struct osl_table *audio_file_table;
+/* Data about one audio file. Needed for ls and stat output. */
+struct ls_data {
+ /* Usual audio format handler information. */
+ struct afh_info afhi;
+ /* Audio file selector information. */
+ struct afs_info afsi;
+ /* The full path of the audio file. */
+ char *path;
+ /* The score value (if -a was given). */
+ long score;
+ /* The hash value of the audio file data. */
+ unsigned char *hash;
+};
+
+/*
+ * The internal state of the audio file table is described by the following
+ * variables which are private to aft.c.
+ */
+static struct osl_table *audio_file_table; /* NULL if table not open */
+static struct osl_row *current_aft_row; /* NULL if no audio file open */
+
static char *status_items;
static char *parser_friendly_status_items;
+static struct ls_data status_item_ls_data;
/** The different sorting methods of the ls command. */
enum ls_sorting_method {
LS_MODE_PARSER,
};
-/* Data about one audio file. Needed for ls and stat output. */
-struct ls_data {
- /* Usual audio format handler information. */
- struct afh_info afhi;
- /* Audio file selector information. */
- struct afs_info afsi;
- /* The full path of the audio file. */
- char *path;
- /* The score value (if -a was given). */
- long score;
- /* The hash value of the audio file data. */
- unsigned char *hash;
-};
-
/**
* The size of the individual output fields of the ls command.
*
/**
* Describes the layout of the mmapped-afs info struct.
*
- * \sa struct afs_info.
+ * \sa struct \ref afs_info.
*/
enum afsi_offsets {
/** Where .last_played is stored. */
* \param afsi Pointer to the audio file info to be converted.
* \param obj Result pointer.
*
- * \sa load_afsi().
+ * \sa \ref load_afsi().
*/
static void save_afsi(struct afs_info *afsi, struct osl_object *obj)
{
*
* \return Standard.
*
- * \sa save_afsi().
+ * \sa \ref save_afsi().
*/
static int load_afsi(struct afs_info *afsi, struct osl_object *obj)
{
write_u32(buf + CHUNK_TV_TV_SEC_OFFSET, afhi->chunk_tv.tv_sec);
write_u32(buf + CHUNK_TV_TV_USEC_OFFSET, afhi->chunk_tv.tv_usec);
p = buf + AFHI_INFO_STRING_OFFSET;
- /* The sprintf's below are OK as our caller made sure that buf is large enough */
+ /*
+ * The below sprintf(3) calls are OK because our caller already made
+ * sure that buf is large enough.
+ */
p += sprintf(p, "%s", afhi->techinfo) + 1;
p += sprintf(p, "%s", afhi->tags.artist) + 1;
p += sprintf(p, "%s", afhi->tags.title) + 1;
sprintf(p, "%s", afhi->tags.comment);
}
+/* does not load the chunk table */
static void load_afhi(const char *buf, struct afh_info *afhi)
{
afhi->seconds_total = read_u32(buf + AFHI_SECONDS_TOTAL_OFFSET);
* \param row Pointer to a row in the audio file table.
* \param path Result pointer.
*
- * The result is a pointer to mmapped data. The caller must not attempt
+ * The result is a pointer to memory-mapped data. The caller must not attempt
* to free it.
*
* \return Standard.
struct osl_object path_obj;
int ret = osl(osl_get_object(audio_file_table, row, AFTCOL_PATH,
&path_obj));
+
if (ret < 0)
- return ret;
- *path = path_obj.data;
- return 1;
+ *path = NULL;
+ else
+ *path = path_obj.data;
+ return ret;
}
/**
*
* \return The return value of the underlying call to osl_get_object().
*
- * \sa get_hash_of_row().
+ * \sa \ref get_hash_of_row().
*/
static int get_hash_object_of_aft_row(const struct osl_row *row,
struct osl_object *obj)
*
* \return The return value of the underlying call to osl_get_object().
*
- * \sa get_chunk_table_of_row().
+ * After the call the members of the afhi structure point to mapped memory
+ * which is owned by the osl table, Hence the caller must not attempt to free
+ * this memory by calling \ref clear_afhi().
*/
int get_afhi_of_row(const struct osl_row *row, struct afh_info *afhi)
{
/*
* 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
+ * string below makes the formatted date align nicely with dates that
* contain the time (those written by the above strftime() statement).
*/
if (!strftime(buf, size, "%b %e %Y", tm))
char *att_text;
int ret;
- WRITE_STATUS_ITEM(b, SI_ATTRIBUTES_BITMAP, "%s\n", att_bitmap);
+ WRITE_STATUS_ITEM(b, SI_attributes_bitmap, "%s\n", att_bitmap);
ret = get_attribute_text(&afsi->attributes, " ", &att_text);
if (ret < 0)
return ret;
- WRITE_STATUS_ITEM(b, SI_ATTRIBUTES_TXT, "%s\n", att_text);
+ WRITE_STATUS_ITEM(b, SI_attributes_txt, "%s\n", att_text);
free(att_text);
return ret;
}
{
char *lyrics_name;
- WRITE_STATUS_ITEM(b, SI_LYRICS_ID, "%u\n", afsi->lyrics_id);
+ WRITE_STATUS_ITEM(b, SI_lyrics_id, "%u\n", afsi->lyrics_id);
lyr_get_name_by_id(afsi->lyrics_id, &lyrics_name);
- WRITE_STATUS_ITEM(b, SI_LYRICS_NAME, "%s\n", lyrics_name?
+ WRITE_STATUS_ITEM(b, SI_lyrics_name, "%s\n", lyrics_name?
lyrics_name : "(none)");
}
{
char *image_name;
- WRITE_STATUS_ITEM(b, SI_IMAGE_ID, "%u\n", afsi->image_id);
+ WRITE_STATUS_ITEM(b, SI_image_id, "%u\n", afsi->image_id);
img_get_name_by_id(afsi->image_id, &image_name);
- WRITE_STATUS_ITEM(b, SI_IMAGE_NAME, "%s\n", image_name?
+ WRITE_STATUS_ITEM(b, SI_image_name, "%s\n", image_name?
image_name : "(none)");
}
char *val;
if (basename) {
- WRITE_STATUS_ITEM(b, SI_BASENAME, "%s\n", path);
+ WRITE_STATUS_ITEM(b, SI_basename, "%s\n", path);
return;
}
- WRITE_STATUS_ITEM(b, SI_PATH, "%s\n", path);
+ WRITE_STATUS_ITEM(b, SI_path, "%s\n", path);
val = para_basename(path);
- WRITE_STATUS_ITEM(b, SI_BASENAME, "%s\n", val? val : "");
+ WRITE_STATUS_ITEM(b, SI_basename, "%s\n", val? val : "");
val = para_dirname(path);
- WRITE_STATUS_ITEM(b, SI_DIRECTORY, "%s\n", val? val : "");
+ WRITE_STATUS_ITEM(b, SI_directory, "%s\n", val? val : "");
free(val);
}
}
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);
+ WRITE_STATUS_ITEM(b, SI_score, "%li\n", d->score);
ret = write_attribute_items(b, att_buf, afsi);
if (ret < 0)
goto out;
write_image_items(b, afsi);
write_lyrics_items(b, afsi);
hash_to_asc(d->hash, asc_hash);
- WRITE_STATUS_ITEM(b, SI_HASH, "%s\n", asc_hash);
- WRITE_STATUS_ITEM(b, SI_BITRATE, "%dkbit/s\n", afhi->bitrate);
- WRITE_STATUS_ITEM(b, SI_FORMAT, "%s\n",
+ WRITE_STATUS_ITEM(b, SI_hash, "%s\n", asc_hash);
+ WRITE_STATUS_ITEM(b, SI_bitrate, "%dkbit/s\n", afhi->bitrate);
+ WRITE_STATUS_ITEM(b, SI_format, "%s\n",
audio_format_name(afsi->audio_format_id));
- WRITE_STATUS_ITEM(b, SI_FREQUENCY, "%dHz\n", afhi->frequency);
- WRITE_STATUS_ITEM(b, SI_CHANNELS, "%d\n", afhi->channels);
- WRITE_STATUS_ITEM(b, SI_DURATION, "%s\n", duration_buf);
- WRITE_STATUS_ITEM(b, SI_SECONDS_TOTAL, "%" PRIu32 "\n",
+ WRITE_STATUS_ITEM(b, SI_frequency, "%dHz\n", afhi->frequency);
+ WRITE_STATUS_ITEM(b, SI_channels, "%d\n", afhi->channels);
+ WRITE_STATUS_ITEM(b, SI_duration, "%s\n", duration_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, "%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",
+ WRITE_STATUS_ITEM(b, SI_last_played, "%s\n", last_played_time);
+ 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",
afhi->chunks_total);
- WRITE_STATUS_ITEM(b, SI_MAX_CHUNK_SIZE, "%" PRIu32 "\n",
+ WRITE_STATUS_ITEM(b, SI_max_chunk_size, "%" PRIu32 "\n",
afhi->max_chunk_size);
- WRITE_STATUS_ITEM(b, SI_TECHINFO, "%s\n", afhi->techinfo);
- WRITE_STATUS_ITEM(b, SI_ARTIST, "%s\n", afhi->tags.artist);
- WRITE_STATUS_ITEM(b, SI_TITLE, "%s\n", afhi->tags.title);
- WRITE_STATUS_ITEM(b, SI_YEAR, "%s\n", afhi->tags.year);
- WRITE_STATUS_ITEM(b, SI_ALBUM, "%s\n", afhi->tags.album);
- WRITE_STATUS_ITEM(b, SI_COMMENT, "%s\n", afhi->tags.comment);
+ WRITE_STATUS_ITEM(b, SI_techinfo, "%s\n", afhi->techinfo);
+ WRITE_STATUS_ITEM(b, SI_artist, "%s\n", afhi->tags.artist);
+ WRITE_STATUS_ITEM(b, SI_title, "%s\n", afhi->tags.title);
+ WRITE_STATUS_ITEM(b, SI_year, "%s\n", afhi->tags.year);
+ WRITE_STATUS_ITEM(b, SI_album, "%s\n", afhi->tags.album);
+ WRITE_STATUS_ITEM(b, SI_comment, "%s\n", afhi->tags.comment);
if (opts->mode == LS_MODE_MBOX) {
struct osl_object lyrics_def;
lyr_get_def_by_id(afsi->lyrics_id, &lyrics_def);
return ret;
}
-static struct ls_data status_item_ls_data;
-static struct osl_row *current_aft_row;
-
static void make_inode_status_items(struct para_buffer *pb)
{
struct stat statbuf = {.st_size = 0};
ret = strftime(mtime_str, 29, "%b %d %Y", &mtime_tm);
assert(ret > 0); /* number of bytes placed in mtime_str */
out:
- WRITE_STATUS_ITEM(pb, SI_MTIME, "%s\n", mtime_str);
- WRITE_STATUS_ITEM(pb, SI_FILE_SIZE, "%ld\n", statbuf.st_size / 1024);
+ WRITE_STATUS_ITEM(pb, SI_mtime, "%s\n", mtime_str);
+ WRITE_STATUS_ITEM(pb, SI_file_size, "%ld\n", statbuf.st_size / 1024);
}
static int make_status_items(void)
return ret;
}
+static int ls_hash_compare(const void *a, const void *b)
+{
+ struct ls_data *d1 = *(struct ls_data **)a, *d2 = *(struct ls_data **)b;
+ return memcmp(d1->hash, d2->hash, HASH_SIZE);
+}
+
static int ls_audio_format_compare(const void *a, const void *b)
{
struct ls_data *d1 = *(struct ls_data **)a, *d2 = *(struct ls_data **)b;
compar = ls_duration_compare; break;
case LS_SORT_BY_AUDIO_FORMAT:
compar = ls_audio_format_compare; break;
+ case LS_SORT_BY_HASH:
+ compar = ls_hash_compare; break;
default:
return -E_BAD_SORT;
}
return ret;
}
-/* TODO: flags -h (sort by hash) */
static int com_ls(struct command_context *cc, struct lls_parse_result *lpr)
{
const struct lls_command *cmd = SERVER_CMD_CMD_PTR(LS);
opts->sorting = LS_SORT_BY_DURATION;
else if (!strcmp(val, "a") || !strcmp(val, "audio-format"))
opts->sorting = LS_SORT_BY_AUDIO_FORMAT;
+ else if (!strcmp(val, "h") || !strcmp(val, "hash"))
+ opts->sorting = LS_SORT_BY_HASH;
else {
ret = -E_AFT_SYNTAX;
goto out;
+----+----+---+------+---------------------------------------------------+
| N | N | Y | Y | (new file) create new entry (force has no effect)
+----+----+---+------+---------------------------------------------------+
-| N | N | N | Y | (new file) create new entry
+| N | N | N | Y | (new file) create new entry
+----+----+---+------+---------------------------------------------------+
Notes:
}
EXPORT_SERVER_CMD_HANDLER(add);
-/**
- * Flags used by the touch command.
- *
- * \sa com_touch().
- */
+/** Flags used by the touch command. */
enum touch_flags {
/** Whether the \p FNM_PATHNAME flag should be passed to fnmatch(). */
TOUCH_FLAG_FNM_PATHNAME = 1,
* \param aca Only ->pbout is used for diagnostics.
*
* \return Standard. Inconsistencies are reported but not regarded as an error.
- *
- * \sa com_check().
*/
int aft_check_callback(struct afs_callback_arg *aca)
{
*
* \param flags Usual flags that are passed to osl_close_table().
*
- * \sa osl_close_table().
+ * \sa \ref osl_close_table().
*/
static void aft_close(void)
{
*
* \return Standard.
*
- * \sa osl_open_table().
+ * \sa \ref osl_open_table().
*/
static int aft_open(const char *dir)
{
status_item_ls_data.afsi.last_played = old_last_played;
make_status_items();
return 1;
+ } case AUDIO_FILE_RENAME: {
+ char *path;
+ if (data != current_aft_row)
+ return 0;
+ ret = get_audio_file_path_of_row(current_aft_row, &path);
+ if (ret < 0)
+ return ret;
+ status_item_ls_data.path = path;
+ make_status_items();
+ return 1;
} case AFHI_CHANGE: {
if (data != current_aft_row)
return 0;
* every time.
*/
make_status_items();
+ return 0;
} default:
return 0;
}