Added SILC Thread Queue API
[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[2], *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   sep[1] = '\0';
144   cp = (char *)string;
145   while (cp) {
146     len = strcspn(cp, sep);
147     if (!len)
148       break;
149
150     item = silc_memdup(cp, len);
151     if (!item) {
152       silc_free(splitted);
153       return NULL;
154     }
155
156     cp += len;
157     if (strlen(cp) == 0)
158       cp = NULL;
159     else
160       cp++;
161
162     splitted[i++] = item;
163
164     if (cp) {
165       splitted = silc_realloc(splitted, (i + 1) * sizeof(*splitted));
166       if (!splitted)
167         return NULL;
168     }
169   }
170   *ret_count = i;
171
172   return splitted;
173 }
174
175 /* Inspects the `string' for wildcards and returns regex string that can
176    be used by the GNU regex library. A comma (`,') in the `string' means
177    that the string is list. */
178
179 char *silc_string_regexify(const char *string)
180 {
181   int i, len, count;
182   char *regex;
183
184   if (!string) {
185     silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
186     return NULL;
187   }
188
189   len = strlen(string);
190   count = 4;
191   for (i = 0; i < len; i++) {
192     if (string[i] == '*' || string[i] == '?')
193       count++;                  /* Will add '.' */
194     if (string[i] == ',')
195       count += 2;               /* Will add '|' and '^' */
196   }
197
198   regex = silc_calloc(len + count + 1, sizeof(*regex));
199   if (!regex)
200     return NULL;
201
202   count = 0;
203   regex[count++] = '(';
204   regex[count++] = '^';
205
206   for (i = 0; i < len; i++) {
207     if (string[i] == '*' || string[i] == '?') {
208       regex[count] = '.';
209       count++;
210     } else if (string[i] == ',') {
211       if (i + 2 == len)
212         continue;
213       regex[count++] = '|';
214       regex[count++] = '^';
215       continue;
216     }
217
218     regex[count++] = string[i];
219   }
220
221   regex[count++] = ')';
222   regex[count] = '$';
223
224   return regex;
225 }
226
227 /* Combines two regex strings into one regex string so that they can be
228    used as one by the GNU regex library. The `string2' is combine into
229    the `string1'. */
230
231 char *silc_string_regex_combine(const char *string1, const char *string2)
232 {
233   char *tmp;
234   int len1, len2;
235
236   if (!string1 || !string2) {
237     silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
238     return NULL;
239   }
240
241   len1 = strlen(string1);
242   len2 = strlen(string2);
243
244   tmp = silc_calloc(2 + len1 + len2, sizeof(*tmp));
245   strncat(tmp, string1, len1 - 2);
246   strncat(tmp, "|", 1);
247   strncat(tmp, string2 + 1, len2 - 1);
248
249   return tmp;
250 }
251
252 /* Do regex match to the two strings `string1' and `string2'. If the
253    `string2' matches the `string1' this returns TRUE. */
254
255 int silc_string_match(const char *string1, const char *string2)
256 {
257   char *s1;
258   int ret = FALSE;
259
260   if (!string1 || !string2) {
261     silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
262     return ret;
263   }
264
265   s1 = silc_string_regexify(string1);
266   ret = silc_string_regex_match(s1, string2);
267   silc_free(s1);
268
269   return ret;
270 }