[string] bug_4807 fixed
[scilab.git] / scilab / modules / string / src / c / strsubst.c
1
2 /*
3  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
4  * Copyright (C) INRIA - Allan CORNET
5  *
6  * Copyright (C) 2012 - 2016 - Scilab Enterprises
7  *
8  * This file is hereby licensed under the terms of the GNU GPL v2.0,
9  * pursuant to article 5.3.4 of the CeCILL v.2.1.
10  * This file was originally licensed under the terms of the CeCILL v2.1,
11  * and continues to be available under such terms.
12  * For more information, see the COPYING file which you should have received
13  * along with this program.
14  *
15  */
16
17 /*--------------------------------------------------------------------------*/
18 #include <stdio.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <wchar.h>
22 #include "strsubst.h"
23 #include "sci_malloc.h"
24 #include "pcre_private.h"
25 #include "os_string.h"
26 #include "charEncoding.h"
27 #include "pcre_error.h"
28 /*--------------------------------------------------------------------------*/
29 char **strsubst(const char **strings_input, int strings_dim, const char *string_to_search, const char *replacement_string)
30 {
31     char **replacedStrings = NULL;
32
33     if ( (strings_input) && (string_to_search) && (replacement_string) )
34     {
35         int i = 0;
36         replacedStrings = (char**)MALLOC(sizeof(char*) * strings_dim);
37         for (i = 0; i < strings_dim; i++)
38         {
39             const char *str = strings_input[i];
40             replacedStrings[i] = strsub (str, string_to_search, replacement_string);
41         }
42     }
43     return replacedStrings;
44 }
45 /*--------------------------------------------------------------------------*/
46 char **strsubst_reg(const char **strings_input, int strings_dim, const char *string_to_search, const char *replacement_string, int *ierr)
47 {
48     char **replacedStrings = NULL;
49
50     if ( (strings_input) && (string_to_search) && (replacement_string) )
51     {
52         int i = 0;
53         replacedStrings = (char**)MALLOC(sizeof(char*) * strings_dim);
54         for (i = 0; i < strings_dim; i++)
55         {
56             const char *str = strings_input[i];
57             replacedStrings[i] = strsub_reg(str, string_to_search, replacement_string, ierr);
58         }
59     }
60     return replacedStrings;
61 }
62 /*-------------------------------------------------------------------------------------*/
63 char *strsub(const char* input_string, const char* string_to_search, const char* replacement_string)
64 {
65     const char *occurrence_str = NULL;
66     char* result_str = NULL;
67     char *replacedString = NULL;
68     int count = 0, len = 0;
69
70     if (input_string == NULL)
71     {
72         return NULL;
73     }
74
75     if (string_to_search == NULL || replacement_string == NULL)
76     {
77         return os_strdup(input_string);
78     }
79
80     occurrence_str = strstr (input_string, string_to_search);
81     if (occurrence_str == NULL)
82     {
83         return os_strdup(input_string);
84     }
85
86     if (strlen (replacement_string) > strlen (string_to_search))
87     {
88         count = 0;
89         len = (int)strlen (string_to_search);
90         if (len)
91         {
92             occurrence_str = input_string;
93             while (occurrence_str != NULL && *occurrence_str != '\0')
94             {
95                 occurrence_str = strstr (occurrence_str, string_to_search);
96                 if (occurrence_str != NULL)
97                 {
98                     occurrence_str += len;
99                     count++;
100                 }
101             }
102         }
103         len = count * ((int)strlen(replacement_string) - (int)strlen(string_to_search)) + (int)strlen(input_string);
104     }
105     else
106     {
107         len = (int)strlen(input_string);
108     }
109
110     replacedString = (char*)MALLOC (sizeof(char) * (len + 1));
111     if (replacedString == NULL)
112     {
113         return NULL;
114     }
115
116     occurrence_str = input_string;
117     result_str = replacedString;
118     len = (int)strlen (string_to_search);
119     while (*occurrence_str != '\0')
120     {
121         if (*occurrence_str == string_to_search[0] && strncmp (occurrence_str, string_to_search, len) == 0)
122         {
123             const char *N = NULL;
124             N = replacement_string;
125             while (*N != '\0')
126             {
127                 *result_str++ = *N++;
128             }
129             occurrence_str += len;
130         }
131         else
132         {
133             *result_str++ = *occurrence_str++;
134         }
135     }
136     *result_str = '\0';
137
138     return replacedString;
139 }/*-------------------------------------------------------------------------------------*/
140 char *strsub_reg(const char* input_string, const char* string_to_search, const char* replacement_string, int *ierr)
141 {
142     pcre_error_code w = PCRE_FINISHED_OK;
143
144     int Output_Start = 0;
145     int Output_End = 0;
146
147     char *replacedString = NULL;
148     wchar_t *wcreplacedString = NULL;
149
150     wchar_t *wcreplacement_string = NULL;
151     wchar_t *wcinput_string = NULL;
152
153     int len = 0;
154
155     *ierr = (int)PCRE_FINISHED_OK;
156
157     if (input_string == NULL)
158     {
159         return NULL;
160     }
161
162     if (string_to_search == NULL || replacement_string == NULL)
163     {
164         return os_strdup(input_string);
165     }
166
167     w = pcre_private((char*)input_string, (char*)string_to_search, &Output_Start, &Output_End, NULL, NULL);
168     if (w != PCRE_FINISHED_OK)
169     {
170         *ierr = (int)w;
171         return os_strdup(input_string);
172     }
173
174     wcreplacement_string = to_wide_string((char*)replacement_string);
175     wcinput_string = to_wide_string((char*)input_string);
176
177     if (wcreplacement_string == NULL)
178     {
179         FREE(wcinput_string);
180         *ierr = (int)NOT_ENOUGH_MEMORY_FOR_VECTOR;
181         return os_strdup(input_string);
182     }
183
184     len = (int)wcslen(wcreplacement_string) + (int)wcslen(wcinput_string);
185
186     wcreplacedString = (wchar_t*)MALLOC (sizeof(wchar_t) * (len + 1));
187     if (wcreplacedString == NULL)
188     {
189         FREE(wcreplacement_string);
190         FREE(wcinput_string);
191         return NULL;
192     }
193
194     {
195         /* converts to wide characters */
196
197         wchar_t *wctail = NULL;
198
199         int wcOutput_Start = 0;
200         int wcOutput_End = 0;
201
202         char *  strOutput_Start = os_strdup(input_string);
203         char *  strOutput_End =  os_strdup(input_string);
204
205         wchar_t *wcstrOutput_Start = NULL;
206         wchar_t *wcstrOutput_End = NULL;
207
208         /* calculates positions with wide characters */
209         strOutput_Start[Output_Start] = '\0';
210         strOutput_End[Output_End] = '\0';
211
212         wcstrOutput_Start = to_wide_string(strOutput_Start);
213         wcstrOutput_End = to_wide_string(strOutput_End);
214
215         FREE(strOutput_Start);
216         FREE(strOutput_End);
217
218         if (wcstrOutput_Start)
219         {
220             wcOutput_Start = (int)wcslen(wcstrOutput_Start);
221             FREE(wcstrOutput_Start);
222         }
223         else
224         {
225             wcOutput_Start = 0;
226         }
227
228         if (wcstrOutput_End)
229         {
230             wcOutput_End = (int)wcslen(wcstrOutput_End);
231             FREE(wcstrOutput_End);
232         }
233         else
234         {
235             wcOutput_End = 0;
236         }
237
238         wcsncpy(wcreplacedString, wcinput_string, wcOutput_Start);
239         wcreplacedString[wcOutput_Start] = L'\0';
240         wcscat(wcreplacedString, wcreplacement_string);
241         wctail = wcinput_string + wcOutput_End;
242         wcscat(wcreplacedString, wctail);
243         replacedString = wide_string_to_UTF8(wcreplacedString);
244
245         FREE(wcreplacedString);
246     }
247
248     FREE(wcinput_string);
249     FREE(wcreplacement_string);
250
251     return replacedString;
252 }
253 /*-------------------------------------------------------------------------------------*/
254 wchar_t *wcssub_reg(const wchar_t* _pwstInput, const wchar_t* _pwstSearch, const wchar_t* _pwstReplace, int* _piErr)
255 {
256     pcre_error_code iPcreStatus = PCRE_FINISHED_OK;
257     int iStart = 0;
258     int iEnd = 0;
259     int len = 0;
260     int* arriStart = NULL;
261     int* arriEnd = NULL;
262     int iOccurs = 0;
263     int iJump = 0;
264
265     wchar_t* result = NULL;
266
267     if (_pwstInput == NULL)
268     {
269         return NULL;
270     }
271
272     len = (int)wcslen(_pwstInput);
273     arriStart = (int*)MALLOC(sizeof(int) * len);
274     arriEnd = (int*)MALLOC(sizeof(int) * len);
275
276     if (_pwstSearch == NULL || _pwstReplace == NULL)
277     {
278         FREE(arriStart);
279         FREE(arriEnd);
280         return os_wcsdup(_pwstInput);
281     }
282
283     do
284     {
285         iPcreStatus = wide_pcre_private(_pwstInput + iJump, _pwstSearch, &iStart, &iEnd, NULL, NULL);
286         if (iPcreStatus == PCRE_FINISHED_OK)
287         {
288             if (iEnd != iStart)
289             {
290                 arriStart[iOccurs] = iStart + iJump;
291                 arriEnd[iOccurs++] = iEnd + iJump;
292                 iJump += iEnd;
293             }
294             else if (iEnd == 0 && _pwstInput[iJump] != L'\0')
295             {
296                 //avoid infinite loop
297                 iJump++;
298             }
299         }
300         else if (iPcreStatus != NO_MATCH)
301         {
302             pcre_error("strsubst", iPcreStatus);
303             FREE(arriStart);
304             FREE(arriEnd);
305             *_piErr = iPcreStatus;
306             return NULL;
307         }
308     }
309     while (iPcreStatus == PCRE_FINISHED_OK && iStart != iEnd);
310
311     if (iOccurs)
312     {
313         int i = 0;
314         int replaceLen = (int)wcslen(_pwstReplace);
315         int finalSize = len;
316
317         //compute final size
318         for (i = 0; i < iOccurs; ++i)
319         {
320             finalSize -= (arriEnd[i] - arriStart[i]);
321             finalSize += replaceLen;
322         }
323
324         result = (wchar_t*)MALLOC(sizeof(wchar_t) * (finalSize + 1));
325         result[0] = '\0';
326
327         //from start to first occurence
328         wcsncat(result, _pwstInput, arriStart[0]);
329         result[arriStart[0]] = '\0';
330
331         for (i = 0; i < iOccurs - 1; ++i)
332         {
333             int curLen = (int)wcslen(result);
334             int partLen = arriStart[i + 1] - arriEnd[i];
335             //insert replace string
336             wcscat(result, _pwstReplace);
337             //copy part between 2 occurences
338             wcsncat(result, _pwstInput + arriEnd[i], partLen);
339             result[curLen + replaceLen + partLen] = '\0';
340         }
341
342         wcscat(result, _pwstReplace);
343         //copy part after last occurence
344         wcscat(result, _pwstInput + arriEnd[iOccurs - 1]);
345     }
346     else
347     {
348         *_piErr = iPcreStatus;
349         result = os_wcsdup(_pwstInput);
350     }
351
352     FREE(arriStart);
353     FREE(arriEnd);
354
355     return result;
356 }
357 /*-------------------------------------------------------------------------------------*/
358 wchar_t **wcssubst_reg(const wchar_t** _pwstInput, int _iInputSize, const wchar_t* _pwstSearch, const wchar_t* _pwstReplace, int* _piErr)
359 {
360     wchar_t** pwstOutput = NULL;
361
362     if (_pwstInput != NULL && _pwstSearch != NULL && _pwstReplace != NULL)
363     {
364         int i = 0;
365         pwstOutput = (wchar_t**)MALLOC(sizeof(wchar_t*) * _iInputSize);
366         for (i = 0 ; i < _iInputSize ; i++)
367         {
368             const wchar_t* pwst = _pwstInput[i];
369             pwstOutput[i] = wcssub_reg(pwst, _pwstSearch, _pwstReplace, _piErr);
370         }
371     }
372     return pwstOutput;
373 }
374 /*-------------------------------------------------------------------------------------*/
375 wchar_t **wcssubst(const wchar_t** _pwstInput, int _iInputSize, const wchar_t* _pwstSearch, const wchar_t* _pwstReplace)
376 {
377     wchar_t** pwstOutput = NULL;
378
379     if (_pwstInput != NULL && _pwstSearch != NULL && _pwstReplace != NULL)
380     {
381         int i = 0;
382         pwstOutput = (wchar_t**)MALLOC(sizeof(wchar_t*) * _iInputSize);
383         for (i = 0 ; i < _iInputSize ; i++)
384         {
385             const wchar_t* pwst = _pwstInput[i];
386             if (wcslen(pwst) == 0)
387             {
388                 if (wcslen(_pwstSearch) == 0)
389                 {
390                     pwstOutput[i] = os_wcsdup(_pwstReplace);
391                 }
392                 else
393                 {
394                     pwstOutput[i] = os_wcsdup(L"");
395                 }
396             }
397             else
398             {
399                 pwstOutput[i] = wcssub(pwst, _pwstSearch, _pwstReplace);
400             }
401         }
402     }
403     return pwstOutput;
404 }
405 /*-------------------------------------------------------------------------------------*/
406 wchar_t *wcssub(const wchar_t* _pwstInput, const wchar_t* _pwstSearch, const wchar_t* _pwstReplace)
407 {
408     int i               = 0;
409     int iOccurs         = 0;
410     size_t iReplace     = 0;
411     size_t iSearch      = 0;
412     size_t iOffset      = 0;
413
414     size_t* piStart     = NULL;
415
416     const wchar_t* pwstPos  = NULL;
417     wchar_t* pwstOutput     = NULL;
418
419     if (_pwstInput == NULL)
420     {
421         return NULL;
422     }
423
424     if (_pwstSearch == NULL || _pwstReplace == NULL)
425     {
426         return os_wcsdup(_pwstInput);
427     }
428
429     //no needle
430     if (_pwstSearch[0] == L'\0')
431     {
432         //no input
433         if (_pwstInput[0] == L'\0')
434         {
435             return os_wcsdup(_pwstReplace);
436         }
437         else
438         {
439             return os_wcsdup(_pwstInput);
440         }
441     }
442
443     //no input
444     if (_pwstInput[0] == L'\0')
445     {
446         return os_wcsdup(_pwstInput);
447     }
448
449     iSearch     = wcslen(_pwstSearch);
450     iReplace    = wcslen(_pwstReplace);
451     piStart     = (size_t*)MALLOC(sizeof(size_t) * wcslen(_pwstInput));
452     pwstPos     = _pwstInput;
453
454     while (pwstPos)
455     {
456         pwstPos = wcsstr(pwstPos, _pwstSearch);
457         if (pwstPos)
458         {
459             piStart[iOccurs++]  = pwstPos - _pwstInput;
460             iOffset             += iReplace - iSearch;
461             pwstPos             += iSearch;
462         }
463     }
464
465     pwstOutput = (wchar_t*)MALLOC(sizeof(wchar_t) * (wcslen(_pwstInput) + iOffset + 1));
466     memset(pwstOutput, 0x00, sizeof(wchar_t) * (wcslen(_pwstInput) + iOffset + 1));
467
468     if (iOccurs == 0)
469     {
470         wcscpy(pwstOutput, _pwstInput);
471     }
472     else
473     {
474         for (i = 0 ; i < iOccurs ; i++)
475         {
476             if (i == 0)
477             {
478                 //copy start of original string
479                 wcsncpy(pwstOutput, _pwstInput, piStart[i]);
480             }
481             else
482             {
483                 //copy start of original string
484                 wcsncpy(pwstOutput + wcslen(pwstOutput), _pwstInput + piStart[i - 1] + iSearch, piStart[i] - (iSearch + piStart[i - 1]));
485             }
486             //copy replace string
487             wcscpy(pwstOutput + wcslen(pwstOutput), _pwstReplace);
488         }
489         //copy end of original string
490         wcscpy(pwstOutput + wcslen(pwstOutput), _pwstInput + piStart[iOccurs - 1] + iSearch);
491     }
492
493     FREE(piStart);
494     return pwstOutput;
495 }
496 /*-------------------------------------------------------------------------------------*/