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