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