introduce and use helpers lms_string_size_strndup() and lms_string_size_dup()
[platform/upstream/lightmediascanner.git] / src / lib / lightmediascanner_utils.c
1 /**
2  * Copyright (C) 2008-2011 by ProFUSION embedded systems
3  * Copyright (C) 2007 by INdT
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public License
7  * as published by the Free Software Foundation; either version 2.1 of
8  * the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18  * 02110-1301 USA
19  *
20  * @author Gustavo Sverzut Barbieri <barbieri@profusion.mobi>
21  */
22
23 #include <lightmediascanner_utils.h>
24 #include <ctype.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <alloca.h>
28
29 /**
30  * Strips string, in place.
31  *
32  * @param str string to be stripped.
33  * @param p_len string length to analyse, also the place where the final size
34  *        is stored.
35  */
36 void
37 lms_strstrip(char *str, unsigned int *p_len)
38 {
39     int i, len;
40     char *p;
41
42     len = *p_len;
43
44     if (len == 0)
45         return;
46
47     if (*str == '\0') {
48         *p_len = 0;
49         return;
50     }
51
52     p = str + len - 1;
53     for (i = len - 1; i >= 0; i--) {
54         if (isspace(*p) || *p == '\0') {
55             *p = '\0';
56             len--;
57             p--;
58         } else
59             break;
60     }
61     if (len == 0) {
62         *p_len = 0;
63         return;
64     }
65
66     p = str;
67     for (i = 0; i < len; i++) {
68         if (isspace(*p))
69             p++;
70         else
71             break;
72     }
73     len -= i;
74     if (len == 0) {
75         *str = '\0';
76         *p_len = 0;
77         return;
78     }
79
80     *p_len = len;
81
82     if (str < p)
83         for (; len >= 0; len--, str++, p++)
84             *str = *p;
85 }
86
87 /**
88  * If string exists, strips it, in place, free if *p_len = 0
89  *
90  * @param p_str pointer to string to be stripped.
91  * @param p_len string length to analyse, also the place where the final size
92  *        is stored.
93  *
94  * @note this will call free() on *p_str if it becomes empty.
95  */
96 void
97 lms_strstrip_and_free(char **p_str, unsigned int *p_len)
98 {
99     if (!*p_str)
100         return;
101
102     lms_strstrip(*p_str, p_len);
103     if (*p_len == 0) {
104         free(*p_str);
105         *p_str = NULL;
106     }
107 }
108
109 /**
110  * lms_string_size version of lms_strstrip_and_free().
111  *
112  * @param *p pointer to lms_string_size to be stripped.
113  *
114  * @note this will call free() on lms_string_size->str if it becomes empty.
115  */
116 void
117 lms_string_size_strip_and_free(struct lms_string_size *p)
118 {
119     if (!p->str)
120         return;
121
122     lms_strstrip(p->str, &p->len);
123     if (p->len == 0) {
124         free(p->str);
125         p->str = NULL;
126     }
127 }
128
129 /**
130  * lms_string_size version of strdup().
131  *
132  * @param dst where to return the duplicated value.
133  * @param src pointer to lms_string_size to be duplicated.
134  *
135  * @return 1 on success, 0 on failure.
136  */
137 int
138 lms_string_size_dup(struct lms_string_size *dst, const struct lms_string_size *src)
139 {
140     if (src->len == 0) {
141         dst->str = NULL;
142         dst->len = 0;
143         return 1;
144     }
145
146     dst->str = malloc(src->len + 1);
147     if (!dst->str) {
148         dst->len = 0;
149         return 0;
150     }
151
152     dst->len = src->len;
153     memcpy(dst->str, src->str, dst->len);
154     dst->str[dst->len] = '\0';
155     return 1;
156 }
157
158 /**
159  * Similar to lms_string_size_dup(), but from a simple string.
160  *
161  * @param dst where to return the duplicated value.
162  * @param src pointer to string to be duplicated.
163  * @param size size to copy or -1 to auto-calculate.
164  *
165  * @return 1 on success, 0 on failure.
166  */
167 int
168 lms_string_size_strndup(struct lms_string_size *dst, const char *src, int size)
169 {
170     if (size < 0) {
171         if (!src)
172             size = 0;
173         else
174             size = strlen(src);
175     }
176
177     if (size == 0) {
178         dst->str = NULL;
179         dst->len = 0;
180         return 1;
181     }
182
183     dst->str = malloc(size + 1);
184     if (!dst->str) {
185         dst->len = 0;
186         return 0;
187     }
188
189     dst->len = size;
190     memcpy(dst->str, src, dst->len);
191     dst->str[dst->len] = '\0';
192     return 1;
193 }
194
195 /**
196  * Find out which of the given extensions matches the given name.
197  *
198  * @param name string to analyse.
199  * @param name_len string length.
200  * @param exts array of extensions to be checked.
201  * @param exts_len number of items in array @p exts
202  *
203  * @return index in @p exts or -1 if it doesn't match none.
204  */
205 int
206 lms_which_extension(const char *name, unsigned int name_len, const struct lms_string_size *exts, unsigned int exts_len) {
207     unsigned int i;
208     unsigned int *exts_pos;
209     const char *s;
210
211     exts_pos = alloca(exts_len * sizeof(*exts_pos));
212     for (i = 0; i < exts_len; i++)
213         exts_pos[i] = exts[i].len;
214
215     for (s = name + name_len - 1; s >= name; s--) {
216         int match;
217         char c1, c2;
218
219         c1 = *s;
220         if (c1 >= 'a')
221             c2 = c1;
222         else
223             c2 = 'a' + c1 - 'A';
224
225         match = 0;
226         for (i = 0; i < exts_len; i++) {
227             if (exts_pos[i] > 0) {
228                 char ce;
229
230                 ce = exts[i].str[exts_pos[i] - 1];
231                 if (ce == c1 || ce == c2) {
232                     if (exts_pos[i] == 1)
233                         return i;
234                     exts_pos[i]--;
235                     match = 1;
236                 } else
237                     exts_pos[i] = 0;
238             }
239         }
240         if (!match)
241             return -1;
242     }
243
244     return -1;
245 }