1 /*
2 * t_tune.c
3 *
4 * A tune represent a music file with tags (or comments) attributes.
5 */
6 #include "t_config.h"
7 #include "t_backend.h"
8 #include "t_tag.h"
9 #include "t_tune.h"
10
11
12 /* t_tune definition */
13 struct t_tune {
14 char *path; /* the file's path */
15 int dirty; /* 0 if clean (tags have not changed), >0 otherwise. */
16 void *opaque; /* pointer used by the backend's read and write routines */
17 const struct t_backend *backend; /* backend used to handle this file. */
18 struct t_taglist *tlist; /* used internal by t_tune routines. use t_tune_tags() instead */
19 };
20
21
22 /*
23 * initialize internal data, find a backend able to handle the tune.
24 *
25 * @return
26 * 0 on success and the t_tune is ready to be passed to t_tune_tags(),
27 * t_tune_set_tags() and t_tune_save() routines, -1 on error (ENOMEM) or if no
28 * backend was found.
29 */
30 static int t_tune_init(struct t_tune *tune, const char *path);
31
32 /*
33 * free all the memory used internally by the t_tune.
34 */
35 static void t_tune_clear(struct t_tune *tune);
36
37
38 struct t_tune *
t_tune_new(const char * path)39 t_tune_new(const char *path)
40 {
41 struct t_tune *tune;
42
43 assert(path != NULL);
44
45 tune = malloc(sizeof(struct t_tune));
46 if (tune != NULL) {
47 if (t_tune_init(tune, path) == -1) {
48 free(tune);
49 tune = NULL;
50 }
51 }
52
53 return (tune);
54 }
55
56
57 static int
t_tune_init(struct t_tune * tune,const char * path)58 t_tune_init(struct t_tune *tune, const char *path)
59 {
60 const struct t_backend *b;
61 const struct t_backendQ *bQ;
62
63 assert(tune != NULL);
64 assert(path != NULL);
65
66 bzero(tune, sizeof(struct t_tune));
67 tune->path = strdup(path);
68 if (tune->path == NULL)
69 return (-1);
70
71 /* find the first backend able to handle path */
72 bQ = t_all_backends();
73 TAILQ_FOREACH(b, bQ, entries) {
74 if (b->init != NULL) {
75 void *o = b->init(tune->path);
76 if (o != NULL) {
77 tune->backend = b;
78 tune->opaque = o;
79 return (0);
80 }
81 }
82 }
83 /* no backend found */
84
85 free(tune->path);
86 tune->path = NULL;
87 return (-1);
88 }
89
90
91 struct t_taglist *
t_tune_tags(struct t_tune * tune)92 t_tune_tags(struct t_tune *tune)
93 {
94
95 assert(tune != NULL);
96
97 if (tune->tlist == NULL)
98 tune->tlist = tune->backend->read(tune->opaque);
99
100 return (t_taglist_clone(tune->tlist));
101 }
102
103
104 const char *
t_tune_path(struct t_tune * tune)105 t_tune_path(struct t_tune *tune)
106 {
107 assert(tune != NULL);
108
109 return (tune->path);
110 }
111
112
113 const struct t_backend *
t_tune_backend(struct t_tune * tune)114 t_tune_backend(struct t_tune *tune)
115 {
116 assert(tune != NULL);
117
118 return (tune->backend);
119 }
120
121
122 int
t_tune_set_tags(struct t_tune * tune,const struct t_taglist * neo)123 t_tune_set_tags(struct t_tune *tune, const struct t_taglist *neo)
124 {
125 struct t_taglist *copy;
126
127 assert(tune != NULL);
128 assert(neo != NULL);
129
130 if (tune->tlist != neo) {
131 copy = t_taglist_clone(neo);
132 if (copy == NULL)
133 return (-1);
134 t_taglist_delete(tune->tlist);
135 tune->tlist = copy;
136 tune->dirty++;
137 }
138
139 return (0);
140 }
141
142
143 int
t_tune_save(struct t_tune * tune)144 t_tune_save(struct t_tune *tune)
145 {
146
147 assert(tune != NULL);
148
149 if (tune->dirty) {
150 int ret = tune->backend->write(tune->opaque, tune->tlist);
151 if (ret == 0) /* success */
152 tune->dirty = 0;
153 }
154
155 return (tune->dirty ? -1 : 0);
156 }
157
158
159 static void
t_tune_clear(struct t_tune * tune)160 t_tune_clear(struct t_tune *tune)
161 {
162
163 assert(tune != NULL);
164
165 /* tune is either initialized with both path and backend set, or it's
166 uninitialized */
167 if (tune->backend != NULL)
168 tune->backend->clear(tune->opaque);
169 t_taglist_delete(tune->tlist);
170 free(tune->path);
171 bzero(tune, sizeof(struct t_tune));
172 }
173
174
175 void
t_tune_delete(struct t_tune * tune)176 t_tune_delete(struct t_tune *tune)
177 {
178
179 if (tune != NULL)
180 t_tune_clear(tune);
181 free(tune);
182 }
183
184 /* this is needed because we don't expose t_tune_init nor t_tune_clear. The
185 renamer does something pretty unusual so it's implemented that way for the
186 time being. */
187 int
t__tune_reload__(struct t_tune * tune,const char * path)188 t__tune_reload__(struct t_tune *tune, const char *path)
189 {
190 assert(tune != NULL);
191
192 t_tune_clear(tune);
193 return (t_tune_init(tune, path));
194 }
195