e7344ad5b9d76fa5e3b351b570544bd17bc44ebf
[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)
128     return NULL;
129   if (!ret_count)
130     return NULL;
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     return NULL;
179
180   len = strlen(string);
181   count = 4;
182   for (i = 0; i < len; i++) {
183     if (string[i] == '*' || string[i] == '?')
184       count++;                  /* Will add '.' */
185     if (string[i] == ',')
186       count += 2;               /* Will add '|' and '^' */
187   }
188
189   regex = silc_calloc(len + count + 1, sizeof(*regex));
190   if (!regex)
191     return NULL;
192
193   count = 0;
194   regex[count++] = '(';
195   regex[count++] = '^';
196
197   for (i = 0; i < len; i++) {
198     if (string[i] == '*' || string[i] == '?') {
199       regex[count] = '.';
200       count++;
201     } else if (string[i] == ',') {
202       if (i + 2 == len)
203         continue;
204       regex[count++] = '|';
205       regex[count++] = '^';
206       continue;
207     }
208
209     regex[count++] = string[i];
210   }
211
212   regex[count++] = ')';
213   regex[count] = '$';
214
215   return regex;
216 }
217
218 /* Combines two regex strings into one regex string so that they can be
219    used as one by the GNU regex library. The `string2' is combine into
220    the `string1'. */
221
222 char *silc_string_regex_combine(const char *string1, const char *string2)
223 {
224   char *tmp;
225   int len1, len2;
226
227   if (!string1 || !string2)
228     return NULL;
229
230   len1 = strlen(string1);
231   len2 = strlen(string2);
232
233   tmp = silc_calloc(2 + len1 + len2, sizeof(*tmp));
234   strncat(tmp, string1, len1 - 2);
235   strncat(tmp, "|", 1);
236   strncat(tmp, string2 + 1, len2 - 1);
237
238   return tmp;
239 }
240
241 /* Matches the two strings and returns TRUE if the strings match. */
242
243 int silc_string_regex_match(const char *regex, const char *string)
244 {
245   regex_t preg;
246   int ret = FALSE;
247
248   if (regcomp(&preg, regex, REG_NOSUB | REG_EXTENDED) != 0)
249     return FALSE;
250
251   if (regexec(&preg, string, 0, NULL, 0) == 0)
252     ret = TRUE;
253
254   regfree(&preg);
255
256   return ret;
257 }
258
259 /* Do regex match to the two strings `string1' and `string2'. If the
260    `string2' matches the `string1' this returns TRUE. */
261
262 int silc_string_match(const char *string1, const char *string2)
263 {
264   char *s1;
265   int ret = FALSE;
266
267   if (!string1 || !string2)
268     return ret;
269
270   s1 = silc_string_regexify(string1);
271   ret = silc_string_regex_match(s1, string2);
272   silc_free(s1);
273
274   return ret;
275 }