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