Don't add duplicate tags
[cmus.git] / comment.c
blobc74e33ae108376e95fc719abe5d176e823c31309
1 /*
2 * Copyright 2004-2007 Timo Hirvonen
3 */
5 #include "comment.h"
6 #include "xmalloc.h"
7 #include "utils.h"
9 #include <string.h>
11 struct keyval *comments_dup(const struct keyval *comments)
13 struct keyval *c;
14 int i;
16 for (i = 0; comments[i].key; i++)
17 ; /* nothing */
18 c = xnew(struct keyval, i + 1);
19 for (i = 0; comments[i].key; i++) {
20 c[i].key = xstrdup(comments[i].key);
21 c[i].val = xstrdup(comments[i].val);
23 c[i].key = NULL;
24 c[i].val = NULL;
25 return c;
28 void comments_free(struct keyval *comments)
30 int i;
32 for (i = 0; comments[i].key; i++) {
33 free(comments[i].key);
34 free(comments[i].val);
36 free(comments);
39 const char *comments_get_val(const struct keyval *comments, const char *key)
41 int i;
43 for (i = 0; comments[i].key; i++) {
44 if (strcasecmp(comments[i].key, key) == 0)
45 return comments[i].val;
47 return NULL;
50 int comments_get_int(const struct keyval *comments, const char *key)
52 const char *val;
53 long int ival;
55 val = comments_get_val(comments, key);
56 if (val == NULL)
57 return -1;
58 if (str_to_int(val, &ival) == -1)
59 return -1;
60 return ival;
63 /* Return date as an integer in the form YYYYMMDD, for sorting purposes.
64 * This function is not year 10000 compliant. */
65 int comments_get_date(const struct keyval *comments, const char *key)
67 const char *val;
68 char *endptr;
69 int year, month, day;
70 long int ival;
72 val = comments_get_val(comments, key);
73 if (val == NULL)
74 return -1;
76 year = strtol(val, &endptr, 10);
77 /* Looking for a four-digit number */
78 if (year < 1000 || year > 9999)
79 return -1;
80 ival = year * 10000;
82 if (*endptr == '-' || *endptr == ' ' || *endptr == '/') {
83 month = strtol(endptr+1, &endptr, 10);
84 if (month < 1 || month > 12)
85 return ival;
86 ival += month * 100;
89 if (*endptr == '-' || *endptr == ' ' || *endptr == '/') {
90 day = strtol(endptr+1, &endptr, 10);
91 if (day < 1 || day > 31)
92 return ival;
93 ival += day;
97 return ival;
100 static const char *interesting[] = {
101 "artist", "album", "title", "tracknumber", "discnumber", "genre",
102 "date", "compilation", "albumartist", "artistsort", "albumartistsort",
103 "replaygain_track_gain",
104 "replaygain_track_peak",
105 "replaygain_album_gain",
106 "replaygain_album_peak",
107 NULL
110 static struct {
111 const char *old;
112 const char *new;
113 } key_map[] = {
114 { "album_artist", "albumartist" },
115 { "album artist", "albumartist" },
116 { "disc", "discnumber" },
117 { "track", "tracknumber" },
118 { NULL, NULL }
121 static const char *fix_key(const char *key)
123 int i;
125 for (i = 0; interesting[i]; i++) {
126 if (!strcasecmp(key, interesting[i]))
127 return interesting[i];
129 for (i = 0; key_map[i].old; i++) {
130 if (!strcasecmp(key, key_map[i].old))
131 return key_map[i].new;
133 return NULL;
136 int comments_add(struct growing_keyvals *c, const char *key, char *val)
138 int i, n = c->count + 1;
140 key = fix_key(key);
141 if (!key) {
142 free(val);
143 return 0;
146 if (!strcmp(key, "tracknumber") || !strcmp(key, "discnumber")) {
147 char *slash = strchr(val, '/');
148 if (slash)
149 *slash = 0;
152 /* don't add duplicates. can't use comments_get_val() */
153 for (i = 0; i < c->count; i++) {
154 if (!strcasecmp(key, c->comments[i].key) && !strcmp(val, c->comments[i].val)) {
155 free(val);
156 return 0;
160 if (n > c->alloc) {
161 n = (n + 3) & ~3;
162 c->comments = xrenew(struct keyval, c->comments, n);
163 c->alloc = n;
166 c->comments[c->count].key = xstrdup(key);
167 c->comments[c->count].val = val;
168 c->count++;
169 return 1;
172 int comments_add_const(struct growing_keyvals *c, const char *key, const char *val)
174 return comments_add(c, key, xstrdup(val));
177 void comments_terminate(struct growing_keyvals *c)
179 int alloc = c->count + 1;
181 if (alloc > c->alloc) {
182 c->comments = xrenew(struct keyval, c->comments, alloc);
183 c->alloc = alloc;
185 c->comments[c->count].key = NULL;
186 c->comments[c->count].val = NULL;