Added SILC errno API. Added SilcResult, generic error code and
[silc.git] / lib / silcutil / silcstrutil.c
1 /*
2
3   silcstrutil.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2002 - 2007 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19 /* $Id$ */
20
21 #include "silc.h"
22 #include "silcstrutil.h"
23
24 /* Concatenates the `src' into `dest'.  If `src_len' is more than the
25    size of the `dest' (minus NULL at the end) the `src' will be
26    truncated to fit. */
27
28 char *silc_strncat(char *dest, SilcUInt32 dest_size,
29                    const char *src, SilcUInt32 src_len)
30 {
31   int len;
32
33   dest[dest_size - 1] = '\0';
34
35   len = dest_size - 1 - strlen(dest);
36   if (len < src_len) {
37     if (len > 0)
38       strncat(dest, src, len);
39   } else {
40     strncat(dest, src, src_len);
41   }
42
43   return dest;
44 }
45
46 /* Compares two strings. Strings may include wildcards '*' and '?'.
47    Returns TRUE if strings match. */
48
49 int silc_string_compare(char *string1, char *string2)
50 {
51   int i;
52   int slen1;
53   int slen2;
54   char *tmpstr1, *tmpstr2;
55
56   if (!string1 || !string2)
57     return FALSE;
58
59   slen1 = strlen(string1);
60   slen2 = strlen(string2);
61
62   /* See if they are same already */
63   if (!strncmp(string1, string2, slen2) && slen2 == slen1)
64     return TRUE;
65
66   if (slen2 < slen1)
67     if (!strchr(string1, '*'))
68       return FALSE;
69
70   /* Take copies of the original strings as we will change them */
71   tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
72   memcpy(tmpstr1, string1, slen1);
73   tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
74   memcpy(tmpstr2, string2, slen2);
75
76   for (i = 0; i < slen1; i++) {
77
78     /* * wildcard. Only one * wildcard is possible. */
79     if (tmpstr1[i] == '*')
80       if (!strncmp(tmpstr1, tmpstr2, i)) {
81         memset(tmpstr2, 0, slen2);
82         strncpy(tmpstr2, tmpstr1, i);
83         break;
84       }
85
86     /* ? wildcard */
87     if (tmpstr1[i] == '?') {
88       if (!strncmp(tmpstr1, tmpstr2, i)) {
89         if (!(slen1 < i + 1))
90           if (tmpstr1[i + 1] != '?' &&
91               tmpstr1[i + 1] != tmpstr2[i + 1])
92             continue;
93
94         if (!(slen1 < slen2))
95           tmpstr2[i] = '?';
96       }
97     }
98   }
99
100   /* if using *, remove it */
101   if (strchr(tmpstr1, '*'))
102     *strchr(tmpstr1, '*') = 0;
103
104   if (!strcmp(tmpstr1, tmpstr2)) {
105     memset(tmpstr1, 0, slen1);
106     memset(tmpstr2, 0, slen2);
107     silc_free(tmpstr1);
108     silc_free(tmpstr2);
109     return TRUE;
110   }
111
112   memset(tmpstr1, 0, slen1);
113   memset(tmpstr2, 0, slen2);
114   silc_free(tmpstr1);
115   silc_free(tmpstr2);
116   return FALSE;
117 }
118
119 /* Splits a string containing separator `ch' and returns an array of the
120    splitted strings. */
121
122 char **silc_string_split(const char *string, char ch, int *ret_count)
123 {
124   char **splitted = NULL, sep[1], *item, *cp;
125   int i = 0, len;
126
127   if (!string || !ret_count) {
128     silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
129     return NULL;
130   }
131
132   splitted = silc_calloc(1, sizeof(*splitted));
133   if (!splitted)
134     return NULL;
135
136   if (!strchr(string, ch)) {
137     splitted[0] = silc_memdup(string, strlen(string));
138     *ret_count = 1;
139     return splitted;
140   }
141
142   sep[0] = ch;
143   cp = (char *)string;
144   while(cp) {
145     len = strcspn(cp, sep);
146     item = silc_memdup(cp, len);
147     if (!item) {
148       silc_free(splitted);
149       return NULL;
150     }
151
152     cp += len;
153     if (strlen(cp) == 0)
154       cp = NULL;
155     else
156       cp++;
157
158     splitted = silc_realloc(splitted, (i + 1) * sizeof(*splitted));
159     if (!splitted)
160       return NULL;
161     splitted[i++] = item;
162   }
163   *ret_count = i;
164
165   return splitted;
166 }
167
168 /* Inspects the `string' for wildcards and returns regex string that can
169    be used by the GNU regex library. A comma (`,') in the `string' means
170    that the string is list. */
171
172 char *silc_string_regexify(const char *string)
173 {
174   int i, len, count;
175   char *regex;
176
177   if (!string) {
178     silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
179     return NULL;
180   }
181
182   len = strlen(string);
183   count = 4;
184   for (i = 0; i < len; i++) {
185     if (string[i] == '*' || string[i] == '?')
186       count++;                  /* Will add '.' */
187     if (string[i] == ',')
188       count += 2;               /* Will add '|' and '^' */
189   }
190
191   regex = silc_calloc(len + count + 1, sizeof(*regex));
192   if (!regex)
193     return NULL;
194
195   count = 0;
196   regex[count++] = '(';
197   regex[count++] = '^';
198
199   for (i = 0; i < len; i++) {
200     if (string[i] == '*' || string[i] == '?') {
201       regex[count] = '.';
202       count++;
203     } else if (string[i] == ',') {
204       if (i + 2 == len)
205         continue;
206       regex[count++] = '|';
207       regex[count++] = '^';
208       continue;
209     }
210
211     regex[count++] = string[i];
212   }
213
214   regex[count++] = ')';
215   regex[count] = '$';
216
217   return regex;
218 }
219
220 /* Combines two regex strings into one regex string so that they can be
221    used as one by the GNU regex library. The `string2' is combine into
222    the `string1'. */
223
224 char *silc_string_regex_combine(const char *string1, const char *string2)
225 {
226   char *tmp;
227   int len1, len2;
228
229   if (!string1 || !string2) {
230     silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
231     return NULL;
232   }
233
234   len1 = strlen(string1);
235   len2 = strlen(string2);
236
237   tmp = silc_calloc(2 + len1 + len2, sizeof(*tmp));
238   strncat(tmp, string1, len1 - 2);
239   strncat(tmp, "|", 1);
240   strncat(tmp, string2 + 1, len2 - 1);
241
242   return tmp;
243 }
244
245 /* Matches the two strings and returns TRUE if the strings match. */
246
247 int silc_string_regex_match(const char *regex, const char *string)
248 {
249   regex_t preg;
250   int ret = FALSE;
251
252   if (regcomp(&preg, regex, REG_NOSUB | REG_EXTENDED) != 0) {
253     silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
254     return FALSE;
255   }
256
257   if (regexec(&preg, string, 0, NULL, 0) == 0)
258     ret = TRUE;
259
260   regfree(&preg);
261
262   return ret;
263 }
264
265 /* Do regex match to the two strings `string1' and `string2'. If the
266    `string2' matches the `string1' this returns TRUE. */
267
268 int silc_string_match(const char *string1, const char *string2)
269 {
270   char *s1;
271   int ret = FALSE;
272
273   if (!string1 || !string2) {
274     silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
275     return ret;
276   }
277
278   s1 = silc_string_regexify(string1);
279   ret = silc_string_regex_match(s1, string2);
280   silc_free(s1);
281
282   return ret;
283 }