cmus-remote: Read command results
[cmus.git] / comment.c
blob66cd5492e2b716e99e0273527e3488a59a128b71
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 const char *comments_get_albumartist(const struct keyval *comments)
52 const char *val = comments_get_val(comments, "albumartist");
53 if (!val)
54 val = comments_get_val(comments, "artist");
55 return val;
58 int comments_get_int(const struct keyval *comments, const char *key)
60 const char *val;
61 long int ival;
63 val = comments_get_val(comments, key);
64 if (val == NULL)
65 return -1;
66 if (str_to_int(val, &ival) == -1)
67 return -1;
68 return ival;
71 /* Return date as an integer in the form YYYYMMDD, for sorting purposes.
72 * This function is not year 10000 compliant. */
73 int comments_get_date(const struct keyval *comments, const char *key)
75 const char *val;
76 char *endptr;
77 int year, month, day;
78 long int ival;
80 val = comments_get_val(comments, key);
81 if (val == NULL)
82 return -1;
84 year = strtol(val, &endptr, 10);
85 /* Looking for a four-digit number */
86 if (year < 1000 || year > 9999)
87 return -1;
88 ival = year * 10000;
90 if (*endptr == '-' || *endptr == ' ' || *endptr == '/') {
91 month = strtol(endptr+1, &endptr, 10);
92 if (month < 1 || month > 12)
93 return ival;
94 ival += month * 100;
97 if (*endptr == '-' || *endptr == ' ' || *endptr == '/') {
98 day = strtol(endptr+1, &endptr, 10);
99 if (day < 1 || day > 31)
100 return ival;
101 ival += day;
105 return ival;
108 static const char *interesting[] = {
109 "artist", "album", "title", "tracknumber", "discnumber", "genre",
110 "date", "compilation", "albumartist", "artistsort", "albumartistsort",
111 "replaygain_track_gain",
112 "replaygain_track_peak",
113 "replaygain_album_gain",
114 "replaygain_album_peak",
115 NULL
118 static struct {
119 const char *old;
120 const char *new;
121 } key_map[] = {
122 { "album_artist", "albumartist" },
123 { "album artist", "albumartist" },
124 { "disc", "discnumber" },
125 { "track", "tracknumber" },
126 { NULL, NULL }
129 static const char *fix_key(const char *key)
131 int i;
133 for (i = 0; interesting[i]; i++) {
134 if (!strcasecmp(key, interesting[i]))
135 return interesting[i];
137 for (i = 0; key_map[i].old; i++) {
138 if (!strcasecmp(key, key_map[i].old))
139 return key_map[i].new;
141 return NULL;
144 int comments_add(struct growing_keyvals *c, const char *key, char *val)
146 int i, n = c->count + 1;
148 key = fix_key(key);
149 if (!key) {
150 free(val);
151 return 0;
154 if (!strcmp(key, "tracknumber") || !strcmp(key, "discnumber")) {
155 char *slash = strchr(val, '/');
156 if (slash)
157 *slash = 0;
160 /* don't add duplicates. can't use comments_get_val() */
161 for (i = 0; i < c->count; i++) {
162 if (!strcasecmp(key, c->comments[i].key) && !strcmp(val, c->comments[i].val)) {
163 free(val);
164 return 0;
168 if (n > c->alloc) {
169 n = (n + 3) & ~3;
170 c->comments = xrenew(struct keyval, c->comments, n);
171 c->alloc = n;
174 c->comments[c->count].key = xstrdup(key);
175 c->comments[c->count].val = val;
176 c->count++;
177 return 1;
180 int comments_add_const(struct growing_keyvals *c, const char *key, const char *val)
182 return comments_add(c, key, xstrdup(val));
185 void comments_terminate(struct growing_keyvals *c)
187 int alloc = c->count + 1;
189 if (alloc > c->alloc) {
190 c->comments = xrenew(struct keyval, c->comments, alloc);
191 c->alloc = alloc;
193 c->comments[c->count].key = NULL;
194 c->comments[c->count].val = NULL;