Improve help/man page of para_filter.
[paraslash.git] / aft.c
diff --git a/aft.c b/aft.c
index 0ffacbe4f4b0a52ae6cfc73625d3cc5f29de8100..d5a355566e387df5bc6e8b1ec06fad03bb660c3e 100644 (file)
--- a/aft.c
+++ b/aft.c
@@ -20,6 +20,7 @@
 #include "vss.h"
 #include "fd.h"
 #include "ipc.h"
+#include "portable_io.h"
 
 static struct osl_table *audio_file_table;
 
@@ -98,6 +99,8 @@ struct ls_widths {
        unsigned short duration_width;
        /** size of the num played field. */
        unsigned short num_played_width;
+       /** size of the amp field. */
+       unsigned short amp_width;
 };
 
 /** Data passed from the ls command handler to its callback function. */
@@ -142,8 +145,10 @@ enum afsi_offsets {
        AFSI_LYRICS_ID_OFFSET = 24,
        /** Storage position of the .audio_format_id field. */
        AFSI_AUDIO_FORMAT_ID_OFFSET = 28,
-       /** 3 bytes reserved space for future usage. */
-       AFSI_AUDIO_FORMAT_UNUSED_OFFSET = 29,
+       /** Storage position of the amplification field. */
+       AFSI_AMP_OFFSET = 29,
+       /** 2 bytes reserved space for future usage. */
+       AFSI_AUDIO_FORMAT_UNUSED_OFFSET = 30,
        /** On-disk storage space needed. */
        AFSI_SIZE = 32
 };
@@ -167,7 +172,8 @@ void save_afsi(struct afs_info *afsi, struct osl_object *obj)
        write_u32(buf + AFSI_LYRICS_ID_OFFSET, afsi->lyrics_id);
        write_u8(buf + AFSI_AUDIO_FORMAT_ID_OFFSET,
                afsi->audio_format_id);
-       memset(buf + AFSI_AUDIO_FORMAT_UNUSED_OFFSET, 0, 3);
+       write_u8(buf + AFSI_AMP_OFFSET, afsi->amp);
+       memset(buf + AFSI_AUDIO_FORMAT_UNUSED_OFFSET, 0, 2);
 }
 
 /**
@@ -192,6 +198,7 @@ int load_afsi(struct afs_info *afsi, struct osl_object *obj)
        afsi->lyrics_id = read_u32(buf + AFSI_LYRICS_ID_OFFSET);
        afsi->audio_format_id = read_u8(buf +
                AFSI_AUDIO_FORMAT_ID_OFFSET);
+       afsi->amp = read_u8(buf + AFSI_AMP_OFFSET);
        return 1;
 }
 
@@ -377,7 +384,7 @@ static void load_afhi(const char *buf, struct afh_info *afhi)
        afhi->chunk_tv.tv_sec = read_u32(buf + CHUNK_TV_TV_SEC_OFFSET);
        afhi->chunk_tv.tv_usec = read_u32(buf + CHUNK_TV_TV_USEC_OFFSET);
        ms2tv(read_u16(buf + AFHI_EOF_OFFSET), &afhi->eof_tv);
-       strcpy(afhi->info_string, buf + AFHI_INFO_STRING_OFFSET);
+       afhi->info_string = para_strdup(buf + AFHI_INFO_STRING_OFFSET);
 }
 
 static unsigned sizeof_chunk_table(struct afh_info *afhi)
@@ -582,8 +589,6 @@ int get_afhi_of_row(const struct osl_row *row, struct afh_info *afhi)
 static int save_afd(struct audio_file_data *afd)
 {
        size_t size = sizeof(*afd) + sizeof_chunk_table(&afd->afhi);
-
-       PARA_DEBUG_LOG("size: %zu\n", size);
        int shmid, ret = shm_new(size);
        void *shm_afd;
        char *buf;
@@ -660,11 +665,11 @@ int open_and_update_audio_file(struct osl_row *aft_row, long score,
        ret = get_afhi_of_row(aft_row, &afd->afhi);
        if (ret < 0)
                return ret;
+       afd->afhi.chunk_table = NULL;
        ret = osl_open_disk_object(audio_file_table, aft_row,
                AFTCOL_CHUNKS, &chunk_table_obj);
        if (ret < 0)
-               return ret;
-       afd->afhi.chunk_table = NULL;
+               goto err;
        ret = mmap_full_file(path, O_RDONLY, &map.data,
                &map.size, &afd->fd);
        if (ret < 0)
@@ -684,14 +689,15 @@ int open_and_update_audio_file(struct osl_row *aft_row, long score,
        load_chunk_table(&afd->afhi, chunk_table_obj.data);
        {
                struct ls_data d = {
-                       .afhi = afd->afhi,
+                       .afhi = afd->afhi, /* struct copy */
                        .afsi = old_afsi,
                        .path = path,
                        .score = score,
                        .hash = file_hash
                };
                struct para_buffer pb = {.max_size = VERBOSE_LS_OUTPUT_SIZE - 1};
-               ret = make_status_items(&d, &pb);
+               ret = make_status_items(&d, &pb); /* frees info string */
+               afd->afhi.info_string = NULL;
                if (ret < 0)
                        goto err;
                strncpy(afd->verbose_ls_output, pb.buf, VERBOSE_LS_OUTPUT_SIZE);
@@ -704,6 +710,7 @@ int open_and_update_audio_file(struct osl_row *aft_row, long score,
        ret = save_afd(afd);
 err:
        free(afd->afhi.chunk_table);
+       free(afd->afhi.info_string);
        osl_close_disk_object(&chunk_table_obj);
        return ret;
 }
@@ -872,15 +879,19 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts,
        char asc_hash[2 * HASH_SIZE + 1];
        char *att_lines, *lyrics_lines, *image_lines, *filename_lines;
 
-       if (opts->mode == LS_MODE_SHORT)
-               return para_printf(b, "%s\n", d->path);
-       if (opts->mode == LS_MODE_CHUNKS)
-               return print_chunk_table(d, b);
+       if (opts->mode == LS_MODE_SHORT) {
+               ret = para_printf(b, "%s\n", d->path);
+               goto out;
+       }
+       if (opts->mode == LS_MODE_CHUNKS) {
+               ret = print_chunk_table(d, b);
+               goto out;
+       }
        get_attribute_bitmap(&afsi->attributes, att_buf);
        ret = get_local_time(&afsi->last_played, last_played_time,
                sizeof(last_played_time), current_time, opts->mode);
        if (ret < 0)
-               return ret;
+               goto out;
        get_duration_buf(afhi->seconds_total, duration_buf, opts);
        if (have_score) {
                if (opts->mode == LS_MODE_LONG)
@@ -890,9 +901,10 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts,
        }
 
        if (opts->mode == LS_MODE_LONG) {
-               return para_printf(b,
+               ret = para_printf(b,
                        "%s"    /* score */
                        "%s "   /* attributes */
+                       "%*u "  /* amp */
                        "%*d "  /* image_id  */
                        "%*d "  /* lyrics_id */
                        "%*d "  /* bitrate */
@@ -905,6 +917,7 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts,
                        "%s\n", /* path */
                        score_buf,
                        att_buf,
+                       w->amp_width, afsi->amp,
                        w->image_id_width, afsi->image_id,
                        w->lyrics_id_width, afsi->lyrics_id,
                        w->bitrate_width, afhi->bitrate,
@@ -916,6 +929,7 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts,
                        last_played_time,
                        d->path
                );
+               goto out;
        }
        hash_to_asc(d->hash, asc_hash);
        att_lines = make_attribute_lines(att_buf, afsi);
@@ -931,7 +945,7 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts,
                        last_played_time,
                        bn? bn : "?");
                if (ret < 0)
-                       return ret;
+                       goto out;
        }
        ret = para_printf(b,
                "%s" /* filename stuff */
@@ -948,6 +962,7 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts,
                "%s: %lu\n" /* seconds total */
                "%s: %s\n" /* last played time */
                "%s: %d\n" /* num_played */
+               "%s: %u\n" /* ampplification */
                "%s" /* tag info */
                "%s: %lu\n" /* chunk time */
                "%s: %lu\n", /* num chunks */
@@ -968,12 +983,13 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts,
                status_item_list[SI_SECONDS_TOTAL], afhi->seconds_total,
                status_item_list[SI_LAST_PLAYED], last_played_time,
                status_item_list[SI_NUM_PLAYED], afsi->num_played,
+               status_item_list[SI_AMPLIFICATION], afsi->amp,
                afhi->info_string,
                status_item_list[SI_CHUNK_TIME], tv2ms(&afhi->chunk_tv),
                status_item_list[SI_NUM_CHUNKS], afhi->chunks_total
        );
        if (ret < 0)
-               return ret;
+               goto out;
        if (opts->mode == LS_MODE_MBOX) {
                struct osl_object lyrics_def;
                lyr_get_def_by_id(afsi->lyrics_id, &lyrics_def);
@@ -987,6 +1003,8 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts,
        free(lyrics_lines);
        free(image_lines);
        free(filename_lines);
+out:
+       free(afhi->info_string);
        return ret;
 }
 
@@ -1012,6 +1030,10 @@ void make_empty_status_items(char *buf)
                "%s: \n" /* seconds total */
                "%s: \n" /* num played */
                "%s: \n" /* last played */
+               "%s: \n" /* audio file info */
+               "%s: \n" /* taginfo1 */
+               "%s: \n" /* taginfo2 */
+               "%s: \n" /* amplification */
                ,
                status_item_list[SI_PATH],
                status_item_list[SI_DIRECTORY],
@@ -1031,7 +1053,11 @@ void make_empty_status_items(char *buf)
                status_item_list[SI_DURATION],
                status_item_list[SI_SECONDS_TOTAL],
                status_item_list[SI_NUM_PLAYED],
-               status_item_list[SI_LAST_PLAYED]
+               status_item_list[SI_LAST_PLAYED],
+               status_item_list[SI_AUDIO_FILE_INFO],
+               status_item_list[SI_TAGINFO1],
+               status_item_list[SI_TAGINFO2],
+               status_item_list[SI_AMPLIFICATION]
        );
 }
 
@@ -1221,7 +1247,7 @@ static int prepare_ls_row(struct osl_row *row, void *ls_opts)
        d->path = path;
        ret = get_hash_of_row(aft_row, &d->hash);
        if (ret < 0)
-               return ret;
+               goto err;
        w = &options->widths;
        GET_NUM_DIGITS(d->afsi.image_id, &num_digits);
        w->image_id_width = PARA_MAX(w->image_id_width, num_digits);
@@ -1234,8 +1260,10 @@ static int prepare_ls_row(struct osl_row *row, void *ls_opts)
        GET_NUM_DIGITS(d->afsi.num_played, &num_digits);
        w->num_played_width = PARA_MAX(w->num_played_width, num_digits);
        /* get the number of chars to print this amount of time */
-       tmp = get_duration_width(d->afhi.seconds_total);
-       w->duration_width = PARA_MAX(w->duration_width, tmp);
+       num_digits = get_duration_width(d->afhi.seconds_total);
+       w->duration_width = PARA_MAX(w->duration_width, num_digits);
+       GET_NUM_DIGITS(d->afsi.amp, &num_digits);
+       w->amp_width = PARA_MAX(w->amp_width, num_digits);
        if (options->flags & LS_FLAG_ADMISSIBLE_ONLY) {
                GET_NUM_DIGITS(score, &num_digits);
                num_digits++; /* add one for the sign (space or "-") */
@@ -1243,6 +1271,9 @@ static int prepare_ls_row(struct osl_row *row, void *ls_opts)
                d->score = score;
        }
        return 1;
+err:
+       free(d->afhi.info_string);
+       return ret;
 }
 
 static void com_ls_callback(int fd, const struct osl_object *query)
@@ -1567,6 +1598,7 @@ static void com_add_callback(int fd, const struct osl_object *query)
        struct afs_info default_afsi = {.last_played = 0};
        struct para_buffer msg = {.max_size = SHMMAX,
                .max_size_handler = pass_buffer_as_shm, .private_data = &fd};
+       uint16_t afhi_offset, chunks_offset;
 
        hash = (HASH_TYPE *)buf + CAB_HASH_OFFSET;
        hash_to_asc(hash, asc);;
@@ -1621,8 +1653,8 @@ static void com_add_callback(int fd, const struct osl_object *query)
                        goto out;
        }
        /* no hs or force mode, child must have sent afhi */
-       uint16_t afhi_offset = read_u16(buf + CAB_AFHI_OFFSET_POS);
-       uint16_t chunks_offset = read_u16(buf + CAB_CHUNKS_OFFSET_POS);
+       afhi_offset = read_u16(buf + CAB_AFHI_OFFSET_POS);
+       chunks_offset = read_u16(buf + CAB_CHUNKS_OFFSET_POS);
 
        objs[AFTCOL_AFHI].data = buf + afhi_offset;
        objs[AFTCOL_AFHI].size = chunks_offset - afhi_offset;
@@ -1728,7 +1760,7 @@ static int get_row_pointer_from_result(struct osl_object *result, void *private)
 
 static int add_one_audio_file(const char *path, void *private_data)
 {
-       int ret, send_ret = 1;
+       int ret, send_ret = 1, fd;
        uint8_t format_num = -1;
        struct private_add_data *pad = private_data;
        struct afh_info afhi, *afhi_ptr = NULL;
@@ -1752,7 +1784,7 @@ static int add_one_audio_file(const char *path, void *private_data)
                goto out_free;
        }
        /* We still want to add this file. Compute its hash. */
-       ret = mmap_full_file(path, O_RDONLY, &map.data, &map.size, NULL);
+       ret = mmap_full_file(path, O_RDONLY, &map.data, &map.size, &fd);
        if (ret < 0)
                goto out_free;
        hash_function(map.data, map.size, hash);
@@ -1777,13 +1809,14 @@ static int add_one_audio_file(const char *path, void *private_data)
         * there is a hash sister and FORCE was not given.
         */
        if (!hs || (pad->flags & ADD_FLAG_FORCE)) {
-               ret = compute_afhi(path, map.data, map.size, &afhi);
+               ret = compute_afhi(path, map.data, map.size, fd, &afhi);
                if (ret < 0)
                        goto out_unmap;
                format_num = ret;
                afhi_ptr = &afhi;
        }
        munmap(map.data, map.size);
+       close(fd);
        if (pad->flags & ADD_FLAG_VERBOSE) {
                send_ret = send_va_buffer(pad->fd, "adding %s\n", path);
                if (send_ret < 0)
@@ -1795,14 +1828,17 @@ static int add_one_audio_file(const char *path, void *private_data)
        goto out_free;
 
 out_unmap:
+       close(fd);
        munmap(map.data, map.size);
 out_free:
        if (ret < 0 && send_ret >= 0)
                send_ret = send_va_buffer(pad->fd, "failed to add %s (%s)\n", path,
                        para_strerror(-ret));
        free(obj.data);
-       if (afhi_ptr)
+       if (afhi_ptr) {
                free(afhi_ptr->chunk_table);
+               free(afhi_ptr->info_string);
+       }
        /* Stop adding files only on send errors. */
        return send_ret;
 }
@@ -1893,11 +1929,13 @@ struct com_touch_options {
        int32_t num_played;
        /** New last played count. */
        int64_t last_played;
-       /** new lyrics id. */
+       /** New lyrics id. */
        int32_t lyrics_id;
-       /** new image id. */
+       /** New image id. */
        int32_t image_id;
-       /** command line flags (see \ref touch_flags). */
+       /** New amplification value. */
+       int32_t amp;
+       /** Command line flags (see \ref touch_flags). */
        unsigned flags;
 };
 
@@ -1918,7 +1956,7 @@ static int touch_audio_file(__a_unused struct osl_table *table,
        struct osl_object obj;
        struct afs_info old_afsi, new_afsi;
        int ret, no_options = tad->cto->num_played < 0 && tad->cto->last_played < 0 &&
-               tad->cto->lyrics_id < 0 && tad->cto->image_id < 0;
+               tad->cto->lyrics_id < 0 && tad->cto->image_id < 0 && tad->cto->amp < 0;
        struct afsi_change_event_data aced;
 
        ret = get_afsi_object_of_row(row, &obj);
@@ -1952,6 +1990,8 @@ static int touch_audio_file(__a_unused struct osl_table *table,
                        new_afsi.num_played = tad->cto->num_played;
                if (tad->cto->last_played >= 0)
                        new_afsi.last_played = tad->cto->last_played;
+               if (tad->cto->amp >= 0)
+                       new_afsi.amp = tad->cto->amp;
        }
        tad->num_matches++;
        save_afsi(&new_afsi, &obj); /* in-place update */
@@ -1999,7 +2039,8 @@ int com_touch(int fd, int argc, char * const * const argv)
                .num_played = -1,
                .last_played = -1,
                .lyrics_id = -1,
-               .image_id = -1
+               .image_id = -1,
+               .amp = -1,
        };
        struct osl_object query = {.data = &cto, .size = sizeof(cto)};
        int i, ret;
@@ -2037,6 +2078,16 @@ int com_touch(int fd, int argc, char * const * const argv)
                                return ret;
                        continue;
                }
+               if (!strncmp(arg, "-a", 2)) {
+                       int32_t val;
+                       ret = para_atoi32(arg + 2, &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;
@@ -2253,10 +2304,6 @@ static void com_cpsi_callback(int fd, const struct osl_object *query)
        };
        int ret;
        char *source_path = (char *)query->data + sizeof(cad.flags);
-
-       ret = get_afsi_of_path(source_path, &cad.source_afsi);
-       if (ret < 0)
-               goto out;
        struct pattern_match_data pmd = {
                .table = audio_file_table,
                .loop_col_num = AFTCOL_HASH,
@@ -2267,6 +2314,10 @@ static void com_cpsi_callback(int fd, const struct osl_object *query)
                .data = &cad,
                .action = copy_selector_info
        };
+
+       ret = get_afsi_of_path(source_path, &cad.source_afsi);
+       if (ret < 0)
+               goto out;
        ret = for_each_matching_row(&pmd);
 out:
        if (ret < 0)
@@ -2378,8 +2429,8 @@ static int check_audio_file(struct osl_row *row, void *data)
 /**
  * Check the audio file table for inconsistencies.
  *
+ * \param fd The afs socket.
  * \param query Unused.
- * \param result Contains message string upon return.
  *
  * This function always succeeds.
  *