summaryrefslogtreecommitdiffabout
path: root/src/idop.c
authorSergey Poznyakoff <gray@gnu.org.ua>2011-07-16 19:41:20 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2011-07-16 19:41:20 (GMT)
commit9a2df634f322d174014ac8d5090bfa87a25bb775 (patch) (side-by-side diff)
tree4346c4b392898c087c55fd20ca998eb39294027b /src/idop.c
parent8d89ce088cc25786cb9520f67e9fe81c86c70277 (diff)
downloadidest-9a2df634f322d174014ac8d5090bfa87a25bb775.tar.gz
idest-9a2df634f322d174014ac8d5090bfa87a25bb775.tar.bz2
Major rewrite.
* src/idest.h (ed_item): Remove union, leave only value instead. <ref>: New member. (describe_option,verbose_option,all_frames): New externs. (set_frame_value): Return int. (IDEST_OK,IDEST_ERR_*): New constants. (_idest_errstr, _idest_nerrs): New externs. (idest_frame_cmp_t,idest_frame_encoder_t) (idest_frame_decoder_t): New typedefs. (idest_frametab): New struct. (idest_frame_lookup) (find_matching_frame): New protos. (ed_list_add_item) (ed_list_print,ed_list_add_assignment) (ed_list_clear,ed_item_matches_frame) (ed_item_set_comment_fields): Remove. (qv_free,input_list_locate) (parse_ed_items): New protos. * src/idop.c: Rewrite. * src/.gitignore: Add src/frametab.c * src/Makefile.am (idest_SOURCES): Add editem.c and frametab.c (BUILT_SOURCES): Add frametab.c (.gperf.c): New rule (GPERF_FLAGS): New variable. * src/editem.c: New source. * src/frametab.gperf: New source. * src/cmdline.opt: Use input_list_add_assignment in --set handler. * src/guile.c (frame_to_scm,scm_to_tag): Rewrite using the new logic.
Diffstat (limited to 'src/idop.c') (more/less context) (ignore whitespace changes)
-rw-r--r--src/idop.c567
1 files changed, 305 insertions, 262 deletions
diff --git a/src/idop.c b/src/idop.c
index 45fd148..fe9c6f5 100644
--- a/src/idop.c
+++ b/src/idop.c
@@ -18,231 +18,136 @@
#include <file.h>
#include <signal.h>
+gl_list_t input_list, output_list;
+
void
-set_frame_value(struct id3_frame *frame, const struct ed_item *item)
+input_list_add_assignment(const char *name, const char *value)
{
- const char *value = item->v.value;
- union id3_field *field;
- enum id3_field_textencoding encoding =
- (latin1_option ? ID3_FIELD_TEXTENCODING_ISO_8859_1
- : ID3_FIELD_TEXTENCODING_UTF_8);
- id3_ucs4_t *ucs4;
- const char *condesc;
+ struct ed_item *itm;
+
+ if (!input_list)
+ input_list = ed_list_create();
+ itm = ed_item_from_frame_spec(name, strlen(name));
+ itm->value = xstrdup(value);
+ gl_list_add_last(input_list, itm);
+}
+
+struct ed_item const *
+input_list_locate(struct id3_frame *frame, idest_frame_cmp_t cmp)
+{
+ gl_list_iterator_t itr;
+ const void *p;
+ const struct ed_item *item = NULL;
- switch (frame_to_item_id(frame->id)) {
- default:
- field = id3_frame_field(frame, 0);
- id3_field_settextencoding(field, encoding);
-
- if (latin1_option)
- ucs4 = id3_latin1_ucs4duplicate(
- (const id3_latin1_t *) value);
- else
- ucs4 = id3_utf8_ucs4duplicate(
- (const id3_utf8_t *)value);
-
- field = id3_frame_field(frame, 1);
- id3_field_setstrings(field, 1, &ucs4);
- free(ucs4);
- break;
-
- case item_comment:
- /* Field 0: Encoding */
- field = id3_frame_field(frame, 0);
- id3_field_settextencoding(field, encoding);
- /* Field 1: Language */
- field = id3_frame_field(frame, 1);
- id3_field_setlanguage(field, item->lang ? item->lang : "eng");
- /* Field 2: Short content descriptor */
- field = id3_frame_field(frame, 2);
- condesc = item->condesc ? item->condesc : "";
- if (latin1_option)
- ucs4 = id3_latin1_ucs4duplicate(
- (const id3_latin1_t *)condesc);
- else
- ucs4 = id3_utf8_ucs4duplicate(
- (const id3_utf8_t *)condesc);
- id3_field_setstring(field, ucs4);
- /* Field 3: Comment */
- field = id3_frame_field(frame, 3);
- if (latin1_option)
- ucs4 = id3_latin1_ucs4duplicate(
- (const id3_latin1_t *) value);
- else
- ucs4 = id3_utf8_ucs4duplicate(
- (const id3_utf8_t *)value);
- id3_field_setfullstring(field, ucs4);
- free(ucs4);
- break;
+ itr = gl_list_iterator(input_list);
+ while (gl_list_iterator_next(&itr, &p, NULL)) {
+ item = p;
+ if (memcmp(item->id, frame->id, 4) == 0 &&
+ (!cmp || item->qc == 0 || cmp(frame, item) == 0))
+ break;
+ item = NULL;
}
+ gl_list_iterator_free(&itr);
+ return item;
}
void
-safe_id3_file_update_and_close(struct id3_file *file)
+parse_ed_items(const char *arg)
{
- sigset_t set, oldset;
-
- sigemptyset(&set);
- sigaddset(&set, SIGINT);
- sigaddset(&set, SIGTERM);
+ if (!input_list)
+ input_list = ed_list_create();
+ while (*arg) {
+ struct ed_item *itm;
+ size_t len = strcspn(arg, " \t,");
- sigprocmask(SIG_BLOCK, &set, &oldset);
- id3_file_update(file);
- id3_file_close(file);
- sigprocmask(SIG_SETMASK, &oldset, NULL);
-}
-
-static void
-update_frame(struct id3_tag *tag, const struct ed_item *item)
-{
- struct id3_frame *frame = id3_tag_findframe(tag, item->id, 0);
- if (!frame) {
- frame = id3_frame_new(item->id);
- if (id3_tag_attachframe(tag, frame))
- error(1, 0, "cannot attach new frame");
- } else if (strcmp(item->id, ID3_FRAME_COMMENT) == 0
- && item->condesc) {
- /* Special handling for comments */
- int i = 0;
-
- do {
- union id3_field *field = id3_frame_field(frame, 2);
- char *s;
-
- if (field && (s = field_to_string(field, 0))
- && strcmp(s, item->condesc) == 0)
- break;
- } while (frame = id3_tag_findframe(tag, item->id, ++i));
- if (!frame) {
- frame = id3_frame_new(item->id);
- if (id3_tag_attachframe(tag, frame))
- error(1, 0, "cannot attach new frame");
- }
- } else {
- struct id3_frame *fp;
-
- while (fp = id3_tag_findframe(tag, item->id, 1)) {
- id3_tag_detachframe(tag, fp);
- id3_frame_delete(fp);
- }
+ itm = ed_item_from_frame_spec(arg, len);
+ gl_list_add_last(input_list, itm);
+ arg += len;
+ if (!*arg)
+ break;
+ arg += strspn(arg, " \t,");
}
- set_frame_value(frame, item);
}
-static int
-build_tag_options(struct id3_tag *tag, unsigned long location,
- id3_length_t length, void *data)
+void
+input_list_init()
{
- unsigned int ver = id3_tag_version(tag);
-
- if (ID3_TAG_VERSION_MAJOR(ver) == 1)
- *(unsigned int*)data |= IDEST_ID3V_1;
- else
- *(unsigned int*)data |= IDEST_ID3V_2;
- return 0;
+ if (all_frames)
+ input_list = NULL;
+ else if (!input_list)
+ parse_ed_items(DEFAULT_ED_LIST);
+}
+
+void
+output_list_append(struct ed_item const *item, struct ed_item const *ref)
+{
+ struct ed_item *elt = ed_item_dup(item);
+ if (!output_list)
+ output_list = ed_list_create();
+ elt->ref = ref;
+ gl_list_add_last(output_list, elt);
}
void
-set_tags(const char *name)
+output_list_print()
{
- struct id3_file *file;
- struct id3_tag *tag;
- int modified = 0;
- int vopt = version_option;
-
- file = id3_file_open(name, ID3_FILE_MODE_READWRITE);
- if (!file)
- error(1, errno, "cannot open file %s", name);
- tag = id3_file_tag(file);
- if (!tag)
- abort(); /* FIXME */
+ gl_list_iterator_t itr;
+ const void *p;
- if (ed_list) {
- gl_list_iterator_t itr;
- const void *p;
-
- itr = gl_list_iterator(ed_list);
+ if (all_frames) {
+ itr = gl_list_iterator(output_list);
while (gl_list_iterator_next(&itr, &p, NULL)) {
const struct ed_item *item = p;
- update_frame(tag, item);
- modified |= 1;
+ ed_item_print(item);
}
gl_list_iterator_free(&itr);
- }
-
- /* FIXME */
- modified |= guile_transform(name, tag);
-
- if (convert_version == 0) {
- if (modified && !vopt) {
- if (id3_file_struct_ntags(file)) {
- id3_file_struct_iterate(file,
- build_tag_options,
- &vopt);
- } else
- vopt = default_version_option;
- }
- } else if (id3_file_struct_ntags(file)) {
- id3_file_struct_iterate(file, build_tag_options, &vopt);
- if (vopt != convert_version) {
- vopt = convert_version;
- modified |= 1;
+ } else {
+ itr = gl_list_iterator(input_list);
+ while (gl_list_iterator_next(&itr, &p, NULL)) {
+ int printed = 0;
+ const struct ed_item *input_item = p;
+ if (output_list) {
+ gl_list_iterator_t oitr;
+ oitr = gl_list_iterator(output_list);
+ while (gl_list_iterator_next(&oitr, &p, NULL)) {
+ const struct ed_item *output_item = p;
+ if (output_item->ref == input_item) {
+ ed_item_print(output_item);
+ printed = 1;
+ }
+ }
+ gl_list_iterator_free(&oitr);
+ }
+ if (!printed)
+ ed_item_print(input_item);
}
+ gl_list_iterator_free(&itr);
}
-
- if (modified && vopt) {
- int opts = 0;
-
- if (vopt & IDEST_ID3V_1)
- opts |= ID3_TAG_OPTION_ID3V1;
- if (!(vopt & IDEST_ID3V_2))
- opts |= ID3_TAG_OPTION_NO_ID3V2;
- id3_tag_options(tag,
- ID3_TAG_OPTION_ID3V1|ID3_TAG_OPTION_NO_ID3V2,
- opts);
- }
- if (modified)
- safe_id3_file_update_and_close(file);
- else
- id3_file_close(file);
}
void
-del_tags(const char *name)
+output_list_free()
{
- struct id3_file *file;
- struct id3_tag *tag;
-
- file = id3_file_open(name, ID3_FILE_MODE_READWRITE);
- if (!file)
- error(1, errno, "cannot open file %s", name);
- tag = id3_file_tag(file);
- if (!tag)
- abort(); /* FIXME */
- if (ed_list) {
- gl_list_iterator_t itr;
- const void *p;
-
- itr = gl_list_iterator(ed_list);
- while (gl_list_iterator_next(&itr, &p, NULL)) {
- const struct ed_item *item = p;
- struct id3_frame *frame;
- int i = 0;
-
- while (frame = id3_tag_findframe(tag, item->id, i)) {
- if (ed_item_matches_frame(item, frame)) {
- id3_tag_detachframe(tag, frame);
- id3_frame_delete(frame);
- } else
- i++;
- }
- }
- gl_list_iterator_free(&itr);
- } else
- id3_tag_clearframes(tag);
- safe_id3_file_update_and_close(file);
+ if (output_list) {
+ gl_list_free(output_list);
+ output_list = NULL;
+ }
}
+
+void
+safe_id3_file_update_and_close(struct id3_file *file)
+{
+ sigset_t set, oldset;
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGINT);
+ sigaddset(&set, SIGTERM);
+ sigprocmask(SIG_BLOCK, &set, &oldset);
+ id3_file_update(file);
+ id3_file_close(file);
+ sigprocmask(SIG_SETMASK, &oldset, NULL);
+}
char *
idest_ucs4_cvt(id3_ucs4_t const *ucs4)
@@ -290,7 +195,6 @@ field_to_string(union id3_field *field, int isgenre)
case ID3_FIELD_TYPE_INT16:
case ID3_FIELD_TYPE_INT24:
case ID3_FIELD_TYPE_INT32:
- case ID3_FIELD_TYPE_INT32PLUS:
snprintf(buf, sizeof(buf), "%ld", field->number.value);
ret = xstrdup(buf);
break;
@@ -343,77 +247,172 @@ field_to_string(union id3_field *field, int isgenre)
case ID3_FIELD_TYPE_BINARYDATA:
/* FIXME */
break;
+
+ case ID3_FIELD_TYPE_INT32PLUS:
+ /* FIXME */
+ break;
}
return ret;
}
+
+int
+set_frame_value(struct id3_frame *frame, const struct ed_item *item)
+{
+ const struct idest_frametab *ft = idest_frame_lookup(frame->id);
+ if (!ft)
+ return IDEST_ERR_BADTYPE;
+ return ft->encode(frame, item);
+}
-static void
-add_field(gl_list_t list, struct id3_frame *frame, union id3_field *field)
+static int
+build_tag_options(struct id3_tag *tag, unsigned long location,
+ id3_length_t length, void *data)
{
- id3_ucs4_t const *ucs4;
- char *str;
-
- switch (id3_field_type(field)) {
- case ID3_FIELD_TYPE_TEXTENCODING:
- break;
- case ID3_FIELD_TYPE_LATIN1:
- case ID3_FIELD_TYPE_LATIN1FULL:
- case ID3_FIELD_TYPE_LATIN1LIST:
- break;
- case ID3_FIELD_TYPE_STRING:
- break;
- case ID3_FIELD_TYPE_STRINGFULL:
- ucs4 = id3_field_getfullstring(field);
- str = idest_ucs4_cvt(ucs4);
- gl_list_add_last(list, str);
- break;
- case ID3_FIELD_TYPE_STRINGLIST:
- add_stringlist(list, field,
- strcmp(frame->id, ID3_FRAME_GENRE) == 0,
- NULL);
- break;
- case ID3_FIELD_TYPE_LANGUAGE:
- case ID3_FIELD_TYPE_FRAMEID:
- case ID3_FIELD_TYPE_DATE:
- case ID3_FIELD_TYPE_INT8:
- case ID3_FIELD_TYPE_INT16:
- case ID3_FIELD_TYPE_INT24:
- case ID3_FIELD_TYPE_INT32:
- case ID3_FIELD_TYPE_INT32PLUS:
- case ID3_FIELD_TYPE_BINARYDATA:;
- }
+ unsigned int ver = id3_tag_version(tag);
+
+ if (ID3_TAG_VERSION_MAJOR(ver) == 1)
+ *(unsigned int*)data |= IDEST_ID3V_1;
+ else
+ *(unsigned int*)data |= IDEST_ID3V_2;
+ return 0;
}
-void
-ed_item_set_comment_fields(struct ed_item *itm, struct id3_frame *frame)
+struct id3_frame *
+find_matching_frame(struct id3_tag *tag, const struct ed_item *item,
+ idest_frame_cmp_t cmp)
{
- union id3_field *field;
+ struct id3_frame *frame;
- if (strcmp(frame->id, ID3_FRAME_COMMENT) == 0) {
- field = id3_frame_field(frame, 1);
- if (!field)
- return;
- itm->lang = field_to_string(field, 0);
- field = id3_frame_field(frame, 2);
- if (!field)
- return;
- itm->condesc = field_to_string(field, 0);
+ if (item->qc == 0 || cmp == NULL)
+ frame = id3_tag_findframe(tag, item->id, 0);
+ else {
+ int i;
+ for (i = 0; frame = id3_tag_findframe(tag, item->id, i); i++) {
+ if (cmp(frame, item) == 0)
+ break;
+ }
}
+ return frame;
}
-static gl_list_t
-frame_to_list(struct id3_frame *frame)
+
+static int
+update_frame(struct id3_tag *tag, const struct ed_item *item)
{
- gl_list_t list;
- unsigned i;
- union id3_field *field;
+ const struct idest_frametab *ft = idest_frame_lookup(item->id);
+ struct id3_frame *frame;
- list = new_string_list(true);
- for (i = 0; (field = id3_frame_field(frame, i)); i++)
- add_field(list, frame, field);
- return list;
+ if (!ft)
+ return IDEST_ERR_BADTYPE;
+
+ frame = find_matching_frame(tag, item, ft->cmp);
+ if (!frame) {
+ frame = id3_frame_new(item->id);
+ if (id3_tag_attachframe(tag, frame))
+ error(1, 0, "cannot attach new frame");
+ }
+ return ft->encode(frame, item);
}
+void
+set_tags(const char *name)
+{
+ struct id3_file *file;
+ struct id3_tag *tag;
+ int modified = 0;
+ int vopt = version_option;
+
+ file = id3_file_open(name, ID3_FILE_MODE_READWRITE);
+ if (!file)
+ error(1, errno, "cannot open file %s", name);
+ tag = id3_file_tag(file);
+ if (!tag)
+ abort(); /* FIXME */
+
+ if (input_list) {
+ gl_list_iterator_t itr;
+ const void *p;
+
+ itr = gl_list_iterator(input_list);
+ while (gl_list_iterator_next(&itr, &p, NULL)) {
+ const struct ed_item *item = p;
+ int rc = update_frame(tag, item);
+ if (rc)
+ error(1, 0,
+ "cannot set frame %s: %s",
+ item->id, idest_strerror(rc));
+ modified |= 1;
+ }
+ gl_list_iterator_free(&itr);
+ }
+
+ /* FIXME */
+ modified |= guile_transform(name, tag);
+
+ if (convert_version == 0) {
+ if (modified && !vopt) {
+ if (id3_file_struct_ntags(file)) {
+ id3_file_struct_iterate(file,
+ build_tag_options,
+ &vopt);
+ } else
+ vopt = default_version_option;
+ }
+ } else if (id3_file_struct_ntags(file)) {
+ id3_file_struct_iterate(file, build_tag_options, &vopt);
+ if (vopt != convert_version) {
+ vopt = convert_version;
+ modified |= 1;
+ }
+ }
+
+ if (modified && vopt) {
+ int opts = 0;
+
+ if (vopt & IDEST_ID3V_1)
+ opts |= ID3_TAG_OPTION_ID3V1;
+ if (!(vopt & IDEST_ID3V_2))
+ opts |= ID3_TAG_OPTION_NO_ID3V2;
+ id3_tag_options(tag,
+ ID3_TAG_OPTION_ID3V1|ID3_TAG_OPTION_NO_ID3V2,
+ opts);
+ }
+ if (modified)
+ safe_id3_file_update_and_close(file);
+ else
+ id3_file_close(file);
+}
+
+void
+del_tags(const char *name)
+{
+ struct id3_file *file;
+ struct id3_tag *tag;
+
+ file = id3_file_open(name, ID3_FILE_MODE_READWRITE);
+ if (!file)
+ error(1, errno, "cannot open file %s", name);
+ tag = id3_file_tag(file);
+ if (!tag)
+ abort(); /* FIXME */
+ if (input_list) {
+ int i;
+ struct id3_frame *frame;
+
+ for (i = 0; (frame = id3_tag_findframe(tag, NULL, i)); ) {
+ const struct idest_frametab *ft =
+ idest_frame_lookup(frame->id);
+ if (input_list_locate(frame, ft ? ft->cmp : NULL)) {
+ id3_tag_detachframe(tag, frame);
+ id3_frame_delete(frame);
+ } else
+ i++;
+ }
+ } else
+ id3_tag_clearframes(tag);
+ safe_id3_file_update_and_close(file);
+}
+
static void
show_tags(struct id3_tag *tag)
{
@@ -421,14 +420,53 @@ show_tags(struct id3_tag *tag)
unsigned i;
for (i = 0; (frame = id3_tag_findframe(tag, NULL, i)); i++) {
- gl_list_t list = frame_to_list(frame);
- if (gl_list_size(list) > 0)
- ed_list_add_item(frame, list);
- else
- gl_list_free(list);
+ const struct idest_frametab *ft =
+ idest_frame_lookup(frame->id);
+ if (!ft) {
+ if (verbose_option)
+ error(0, 0,
+ "%s: unsupported frame", frame->id);
+ continue;
+ }
+
+ if (all_frames) {
+ struct ed_item outitm;
+ ed_item_zero(&outitm);
+ if (describe_option) {
+ struct id3_frametype const *frametype;
+ frametype = id3_frametype_lookup(frame->id,
+ 4);
+ outitm.name = xstrdup(frametype->description);
+ } else
+ outitm.name = xstrdup(frame->id);
+ memcpy(outitm.id, frame->id, 4);
+ if (ft->decode(&outitm, frame)) {
+ error(0, 0, "%s: decoding failed", frame->id);
+ continue;
+ }
+ output_list_append(&outitm, NULL);
+ ed_item_free_content(&outitm);
+ } else {
+ struct ed_item const *ref;
+
+ ref = input_list_locate(frame, ft->cmp);
+ if (ref) {
+ struct ed_item outitm;
+ ed_item_zero(&outitm);
+ outitm.name = xstrdup(ref->name);
+ memcpy(outitm.id, ref->id, 4);
+ if (ft->decode(&outitm, frame)) {
+ error(0, 0,
+ "%s: decoding failed", frame->id);
+ continue;
+ }
+ output_list_append(&outitm, ref);
+ ed_item_free_content(&outitm);
+ }
+ }
}
- ed_list_print();
- ed_list_clear();
+ output_list_print();
+ output_list_free();
}
void
@@ -437,6 +475,8 @@ query_tags(const char *name)
struct id3_file *file;
struct id3_tag *tag;
+ input_list_init();
+
file = id3_file_open(name, ID3_FILE_MODE_READONLY);
if (!file)
error(1, errno, "cannot open file %s", name);
@@ -449,16 +489,19 @@ query_tags(const char *name)
id3_file_close(file);
}
-
+
static int
prinfo(struct id3_tag *tag, unsigned long location,
id3_length_t length, void *data)
{
unsigned int ver = id3_tag_version(tag);
unsigned int major = ID3_TAG_VERSION_MAJOR(ver);
- printf("version: %u.%u\n",
- major > 1 ? 20 + major : major,
- ID3_TAG_VERSION_MINOR(ver));
+ if (major > 1)
+ printf("version: 2.%u.%u\n",
+ major, ID3_TAG_VERSION_MINOR(ver));
+ else
+ printf("version: %u.%u\n",
+ major, ID3_TAG_VERSION_MINOR(ver));
printf("offset: %lu\n", location);
printf("length: %lu\n", length);
return 0;

Return to:

Send suggestions and report system problems to the System administrator.