1 /** \file gphoto2-list.c
2 *
3 * \author Copyright 2000 Scott Fritzinger
4 *
5 * \note
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * \note
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * \note
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301 USA
22 */
23
24 #define _DEFAULT_SOURCE
25
26 #include "config.h"
27 #include <gphoto2/gphoto2-list.h>
28 #include <gphoto2/gphoto2-port-log.h>
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include <gphoto2/gphoto2-result.h>
35
36 #define CHECK_RESULT(result) {int r = (result); if (r < 0) return (r);}
37
38 /**
39 * Internal _CameraList data structure
40 **/
41
42 struct _entry {
43 char *name;
44 char *value;
45 };
46
47 struct _CameraList {
48 int used; /* used entries */
49 int max; /* allocated entries */
50 struct _entry *entry;
51 int ref_count;
52 };
53
54
55 /**
56 * \brief Creates a new #CameraList.
57 *
58 * \param list
59 * \return a gphoto2 error code
60 *
61 **/
62 int
gp_list_new(CameraList ** list)63 gp_list_new (CameraList **list)
64 {
65 C_PARAMS (list);
66
67 C_MEM (*list = calloc (1, sizeof (CameraList)));
68
69 (*list)->ref_count = 1;
70
71 return (GP_OK);
72 }
73
74 /**
75 * \brief Increments the reference count of the list.
76 *
77 * \param list a #CameraList
78 * \return a gphoto2 error code.
79 *
80 **/
81 int
gp_list_ref(CameraList * list)82 gp_list_ref (CameraList *list)
83 {
84 C_PARAMS (list && list->ref_count);
85
86 list->ref_count++;
87
88 return (GP_OK);
89 }
90
91 /**
92 * \brief Decrements the reference count of the \c list.
93 *
94 * \param list a #CameraList
95 * \return a gphoto2 error code
96 *
97 * If there are no references left, the \c list will be freed.
98 *
99 **/
100 int
gp_list_unref(CameraList * list)101 gp_list_unref (CameraList *list)
102 {
103 C_PARAMS (list && list->ref_count);
104
105 if (list->ref_count == 1) /* time to free */
106 gp_list_free (list);
107 else
108 list->ref_count--;
109 return (GP_OK);
110 }
111
112 /**
113 * Frees the \c list. It is recommended to use #gp_list_unref instead.
114 *
115 * \param list the #CameraList to be freed
116 * \return a gphoto2 error code
117 *
118 **/
119 int
gp_list_free(CameraList * list)120 gp_list_free (CameraList *list)
121 {
122 int i;
123 C_PARAMS (list && list->ref_count);
124
125 for (i=0;i<list->used;i++) {
126 free (list->entry[i].name);
127 list->entry[i].name = NULL;
128 free (list->entry[i].value);
129 list->entry[i].value = NULL;
130 }
131 free (list->entry);
132 /* Mark this list as having been freed. That may help us
133 * prevent access to already freed lists.
134 */
135 list->ref_count = 0;
136 free (list);
137 return (GP_OK);
138 }
139
140 /**
141 * Resets the \c list and removes all entries.
142 *
143 * \param list a #CameraList
144 * \return a gphoto2 error code
145 *
146 **/
147 int
gp_list_reset(CameraList * list)148 gp_list_reset (CameraList *list)
149 {
150 int i;
151 C_PARAMS (list && list->ref_count);
152
153 for (i=0;i<list->used;i++) {
154 free (list->entry[i].name);
155 list->entry[i].name = NULL;
156 free (list->entry[i].value);
157 list->entry[i].value = NULL;
158 }
159 /* keeps -> entry allocated for reuse. */
160 list->used = 0;
161 return (GP_OK);
162 }
163
164 /**
165 * Appends \c name and \c value to the \c list.
166 *
167 * \param list a #CameraList
168 * \param name the name of the entry to append
169 * \param value the value of the entry to append
170 * \return a gphoto2 error code
171 *
172 **/
173 int
gp_list_append(CameraList * list,const char * name,const char * value)174 gp_list_append (CameraList *list, const char *name, const char *value)
175 {
176 C_PARAMS (list && list->ref_count);
177
178 if (list->used == list->max) {
179 C_MEM (list->entry = realloc(list->entry,(list->max+100)*sizeof(struct _entry)));
180 list->max += 100;
181 }
182
183 if (name) {
184 C_MEM (list->entry[list->used].name = strdup (name));
185 } else {
186 list->entry[list->used].name = NULL;
187 }
188 if (value) {
189 C_MEM (list->entry[list->used].value = strdup (value));
190 } else {
191 list->entry[list->used].value = NULL;
192 }
193 list->used++;
194 return (GP_OK);
195 }
196
197 static int
cmp_list(const void * a,const void * b)198 cmp_list (const void *a, const void *b) {
199 const struct _entry *ca = a;
200 const struct _entry *cb = b;
201
202 return strcmp (ca->name, cb->name);
203 }
204
205 /**
206 * Sorts the \c list entries with respect to the names.
207 *
208 * \param list a #CameraList
209 * \return a gphoto2 error code
210 *
211 **/
212 int
gp_list_sort(CameraList * list)213 gp_list_sort (CameraList *list)
214 {
215 C_PARAMS (list && list->ref_count);
216
217 qsort (list->entry, list->used, sizeof(list->entry[0]), cmp_list);
218 return GP_OK;
219 }
220
221 /**
222 * Counts the entries in the \c list.
223 *
224 * \param list a #CameraList
225 * \return a gphoto2 error code
226 *
227 **/
228 int
gp_list_count(CameraList * list)229 gp_list_count (CameraList *list)
230 {
231 C_PARAMS (list && list->ref_count);
232
233 return (list->used);
234 }
235
236 /**
237 * Retrieves the \c index of an arbitrary entry with \c name.
238 *
239 * \param list a #CameraList
240 * \param index pointer to the result index (may be NULL, only set if found)
241 * \param name name of the entry
242 * \return a gphoto2 error code: GP_OK if found.
243 *
244 * No guarantees as to the speed of the search, or in what sequence
245 * the list is searched.
246 *
247 **/
248 int
gp_list_find_by_name(CameraList * list,int * index,const char * name)249 gp_list_find_by_name (CameraList *list, int *index, const char *name)
250 {
251 int i;
252 C_PARAMS (list && list->ref_count);
253 C_PARAMS (name);
254
255 /* We search backwards because our only known user
256 * camlibs/ptp2/library.c thinks this is faster
257 */
258 for (i=list->used-1; i >= 0; i--) {
259 if (0==strcmp(list->entry[i].name, name)) {
260 if (index) {
261 (*index) = i;
262 }
263 return (GP_OK);
264 }
265 }
266
267 return (GP_ERROR);
268 }
269
270 /**
271 * Retrieves the \c name of entry with \c index.
272 *
273 * \param list a #CameraList
274 * \param index index of the entry
275 * \param name
276 * \return a gphoto2 error code.
277 *
278 **/
279 int
gp_list_get_name(CameraList * list,int index,const char ** name)280 gp_list_get_name (CameraList *list, int index, const char **name)
281 {
282 C_PARAMS (list && list->ref_count);
283 C_PARAMS (name);
284 C_PARAMS (0 <= index && index < list->used);
285
286 *name = list->entry[index].name;
287
288 return (GP_OK);
289 }
290
291 /**
292 * Retrieves the value of entry with \c index.
293 *
294 * \param list a #CameraList
295 * \param index index of the entry
296 * \param value
297 * \return a gphoto2 error code
298 *
299 **/
300 int
gp_list_get_value(CameraList * list,int index,const char ** value)301 gp_list_get_value (CameraList *list, int index, const char **value)
302 {
303 C_PARAMS (list && list->ref_count);
304 C_PARAMS (value);
305 C_PARAMS (0 <= index && index < list->used);
306
307 *value = list->entry[index].value;
308
309 return (GP_OK);
310 }
311
312 /**
313 * Sets the \c value of an entry.
314 *
315 * \param list a #CameraList
316 * \param index index of the entry
317 * \param value the value to be set
318 * \return a gphoto2 error code
319 *
320 **/
321 int
gp_list_set_value(CameraList * list,int index,const char * value)322 gp_list_set_value (CameraList *list, int index, const char *value)
323 {
324 char *newval;
325 C_PARAMS (list && list->ref_count);
326 C_PARAMS (value);
327 C_PARAMS (0 <= index && index < list->used);
328
329 C_MEM (newval = strdup(value));
330 free (list->entry[index].value);
331 list->entry[index].value = newval;
332 return (GP_OK);
333 }
334
335 /**
336 * Sets the name of an entry.
337 *
338 * \param list a #CameraList
339 * \param index index of entry
340 * \param name name to be set
341 * \return a gphoto2 error code
342 *
343 **/
344 int
gp_list_set_name(CameraList * list,int index,const char * name)345 gp_list_set_name (CameraList *list, int index, const char *name)
346 {
347 char *newname;
348 C_PARAMS (list && list->ref_count);
349 C_PARAMS (name);
350 C_PARAMS (0 <= index && index < list->used);
351
352 C_MEM (newname = strdup(name));
353 free (list->entry[index].name);
354 list->entry[index].name = newname;
355 return (GP_OK);
356 }
357
358 /**
359 * Adds \c count entries to the list.
360 *
361 * \param list a #CameraList
362 * \param format the format
363 * \param count number of entries to be added to the list
364 * return a gphoto2 error code
365 *
366 * Typically, this function is called by a camera driver when there is no way
367 * of retrieving the real name of a picture. In this case, when asked for a
368 * file list (see #CameraFilesystemListFunc), the list is populated with dummy
369 * names generated by this function.
370 *
371 **/
372 int
gp_list_populate(CameraList * list,const char * format,int count)373 gp_list_populate (CameraList *list, const char *format, int count)
374 {
375 int x;
376 char buf[1024];
377
378 C_PARAMS (list && list->ref_count);
379 C_PARAMS (format);
380
381 gp_list_reset (list);
382 for (x = 0; x < count; x++) {
383 snprintf (buf, sizeof (buf), format, x + 1);
384 CHECK_RESULT (gp_list_append (list, buf, NULL));
385 }
386
387 return (GP_OK);
388 }
389
390
391
392 /*
393 * Local Variables:
394 * c-file-style:"linux"
395 * indent-tabs-mode:nil
396 * End:
397 */
398