fix bug 3511: strindex did not return all occurrences in regexp mode.
[scilab.git] / scilab / modules / string / sci_gateway / c / sci_strindex.c
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2008 - INRIA - Cong WU
4  *
5  * This file must be used under the terms of the CeCILL.
6  * This source file is licensed as described in the file COPYING, which
7  * you should have received as part of this distribution.  The terms
8  * are also available at
9  * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
10  *
11  */
12
13 /* desc : search position of a character string in an other string        */
14 /*        using regular expression .                                      */
15 /*------------------------------------------------------------------------*/
16 #include <string.h>
17 #include <stdio.h>
18 #include <ctype.h>
19 #include <string.h>
20 #include "gw_string.h"
21 #include "pcre.h"
22 #include "stack-c.h"
23 #include "MALLOC.h"
24 #include "localization.h"
25 #include "freeArrayOfString.h"
26 #include "pcre_private.h"
27 #include "BOOL.h"
28 #include "pcre_error.h"
29 #include "Scierror.h"
30 #include "sciprint.h"
31 #include "charEncoding.h"
32 #include "sort_inter.h"
33 #ifdef _MSC_VER
34 #include "strdup_windows.h"
35 #endif
36 /*------------------------------------------------------------------------*/
37 #define CHAR_S "s"
38 #define CHAR_R "r"
39 /*------------------------------------------------------------------------*/
40 /*------------------------------------------------------------------------*/
41 int cmp(In left, In right)
42 {
43     return left.data < right.data;
44 }
45 /*------------------------------------------------------------------------*/
46 int sci_strindex(char *fname, unsigned long fname_len)
47 {
48     BOOL bStrindex_with_pattern = FALSE;
49     int outIndex = 0;
50     int numRow = 1;
51     int *next = NULL;
52
53     CheckRhs(2, 3);
54     CheckLhs(1, 2);
55
56     if (Rhs == 3)
57     {
58         int m3 = 0;
59         int n3 = 0;
60         char **Strings_Input3 = NULL;
61         int m3n3 = 0; /* m3 * n3 */
62
63         if (VarType(3) != sci_strings)
64         {
65             Scierror(999, _("%s: Wrong type for input argument #%d: Character expected.\n"), fname, 3);
66             return 0;
67         }
68         GetRhsVar(3, MATRIX_OF_STRING_DATATYPE, &m3, &n3, &Strings_Input3);
69         m3n3 = m3 * n3;
70
71         if (m3n3 != 1)
72         {
73             freeArrayOfString(Strings_Input3, m3n3);
74             Scierror(999, _("%s: Wrong type for input argument #%d: Character expected.\n"), fname, 3);
75             return 0;
76         }
77
78         if ( (strcmp(Strings_Input3[0], CHAR_R) == 0) || (strcmp(Strings_Input3[0], CHAR_S) == 0) )
79         {
80             if (strcmp(Strings_Input3[0], CHAR_R) == 0)
81             {
82                 bStrindex_with_pattern = TRUE;
83             }
84             else
85             {
86                 bStrindex_with_pattern = FALSE;
87             }
88             freeArrayOfString(Strings_Input3, m3n3);
89         }
90         else
91         {
92             freeArrayOfString(Strings_Input3, m3n3);
93             Scierror(999, _("%s: Wrong value for input argument #%d: '%s' or '%s' expected.\n"), fname, 3, CHAR_S, CHAR_R);
94             return 0;
95         }
96     }
97
98     if (VarType(1) == sci_matrix)
99     {
100         int m1 = 0;
101         int n1 = 0;
102         int l1 = 0;
103
104         GetRhsVar(1, MATRIX_OF_DOUBLE_DATATYPE, &m1, &n1, &l1);
105         if ((m1 == 0) && (n1 == 0))
106         {
107             CreateVar(Rhs + 1, MATRIX_OF_DOUBLE_DATATYPE, &m1, &n1, &l1);
108             LhsVar(1) = Rhs + 1 ;
109             PutLhsVar();
110             return 0;
111         }
112         else
113         {
114             Scierror(999, _("%s: Wrong type for input argument #%d: Matrix of strings or empty matrix expected.\n"), fname, 1);
115             return 0;
116         }
117     }
118
119     if ( (VarType(1) == sci_strings) && (VarType(2) == sci_strings) )
120     {
121         int m1 = 0, n1 = 0;
122         char **Strings_Input1 = NULL;
123         wchar_t *wStrings_Input1 = NULL;
124         int m1n1 = 0; /* m1 * n1 */
125
126         int m2 = 0, n2 = 0;
127         char **Strings_Input2 = NULL;
128         wchar_t **wStrings_Input2 = NULL;
129         int m2n2 = 0; /* m2 * n2 */
130
131         In *values = NULL;
132
133         int nbValues = 0;
134         int nbposition = 0;
135
136         int i = 0;
137
138         GetRhsVar(1, MATRIX_OF_STRING_DATATYPE, &m1, &n1, &Strings_Input1);
139         m1n1 = m1 * n1;
140
141         if (m1n1 != 1)
142         {
143             freeArrayOfString(Strings_Input1, m1n1);
144             Scierror(999, _("%s: Wrong size for input argument #%d: A string expected.\n"), fname, 1);
145             return 0;
146         }
147
148         wStrings_Input1 = to_wide_string(Strings_Input1[0]);
149         if (wStrings_Input1 == NULL)
150         {
151             /* string conversion fails */
152             freeArrayOfString(Strings_Input1, m1n1);
153             freeArrayOfString(Strings_Input2, m2n2);
154             Scierror(999, _("%s: Wrong value for input argument #%d: A valid string expected (UTF-8 Encoding problem).\n"), fname, 1);
155             return 0;
156         }
157
158         GetRhsVar(2, MATRIX_OF_STRING_DATATYPE, &m2, &n2, &Strings_Input2);
159         m2n2 = m2 * n2;
160
161         if ( (m2 != 1) && (n2 != 1) )
162         {
163             freeArrayOfString(Strings_Input1, m1n1);
164             freeArrayOfString(Strings_Input2, m2n2);
165             Scierror(999, _("%s: Wrong type for input argument #%d: Row vector of strings or column vector of strings expected.\n"), fname, 2);
166             return 0;
167         }
168
169         wStrings_Input2 = (wchar_t**)MALLOC(m2n2 * sizeof(wchar_t*));
170         for (i = 0 ; i < m2n2 ; i++)
171         {
172             wStrings_Input2[i] = to_wide_string(Strings_Input2[i]);
173         }
174
175         if ( (int)wcslen(wStrings_Input1) == 0 )
176         {
177             values = (In*)MALLOC(sizeof(In));
178         }
179         else
180         {
181             values = (In *)MALLOC( sizeof(In) * ( wcslen(wStrings_Input1) ) * m2n2);
182         }
183
184         if (bStrindex_with_pattern)
185         {
186             int x = 0;
187             pcre_error_code answer = PCRE_FINISHED_OK;
188
189             int Output_Start = 0;
190             int Output_End = 0;
191
192             int wcOutput_Start = 0;
193             int wcstart_point = 0;
194             int wcOutput_End = 0;
195
196             for (x = 0; x < m2n2; ++x)
197             {
198                 char *save = strdup(Strings_Input2[x]);
199                 if (save)
200                 {
201                     char *pointer = Strings_Input1[0];
202                     wcstart_point = 0;
203
204                     do
205                     {
206                         strcpy(save, Strings_Input2[x]);
207                         Output_Start = 0;
208                         Output_End = 0;
209
210                         answer = pcre_private(pointer, save, &Output_Start, &Output_End, NULL, NULL);
211                         if ( answer == PCRE_FINISHED_OK )
212                         {
213                             /* Start = End means that we matched a position and 0 characters.
214                             * Matching 0 characters, for us, means no match.
215                             */
216                             if (Output_Start != Output_End)
217                             {
218                                 char *  strOutput_Start = strdup(pointer);
219                                 char *  strOutput_End =  strdup(pointer);
220
221                                 wchar_t *wcstrOutput_Start = NULL;
222                                 wchar_t *wcstrOutput_End = NULL;
223
224                                 /* calculates positions with wide characters */
225                                 strOutput_Start[Output_Start] = '\0';
226                                 strOutput_End[Output_End] = '\0';
227
228                                 wcstrOutput_Start = to_wide_string(strOutput_Start);
229                                 wcstrOutput_End = to_wide_string(strOutput_End);
230
231                                 if (wcstrOutput_Start)
232                                 {
233                                     wcOutput_Start = (int)wcslen(wcstrOutput_Start);
234                                     FREE(wcstrOutput_Start);
235                                     wcstrOutput_Start = NULL;
236                                 }
237                                 else
238                                 {
239                                     wcOutput_Start = 0;
240                                 }
241
242                                 if (wcstrOutput_End)
243                                 {
244                                     wcOutput_End = (int)wcslen(wcstrOutput_End);
245                                     FREE(wcstrOutput_End);
246                                     wcstrOutput_End = NULL;
247                                 }
248                                 else
249                                 {
250                                     wcOutput_End = 0;
251                                 }
252
253                                 if (strOutput_Start)
254                                 {
255                                     FREE(strOutput_Start);
256                                     strOutput_Start = NULL;
257                                 }
258                                 if (strOutput_End)
259                                 {
260                                     FREE(strOutput_End);
261                                     strOutput_End = NULL;
262                                 }
263
264                                 /*adding the answer into the outputmatrix*/
265                                 values[nbValues].data = wcOutput_Start + wcstart_point + 1;
266                                 values[nbValues].position = x + 1;
267                                 nbValues++;
268                             }
269                             else if (Output_End == 0 && *pointer != '\0')
270                             {
271                                 /* Avoid an infinite loop */
272                                 pointer++;
273                             }
274
275                             pointer = &pointer[Output_End];
276                             wcstart_point = wcstart_point + wcOutput_End;
277                         }
278                         else
279                         {
280                             if (answer != NO_MATCH)
281                             {
282                                 pcre_error(fname, answer);
283                                 freeArrayOfString(Strings_Input1, m1n1);
284                                 freeArrayOfString(Strings_Input2, m2n2);
285                                 return 0;
286                             }
287                         }
288                     }
289                     while ( (answer == PCRE_FINISHED_OK) && (*pointer != '\0'));
290
291                     if (save)
292                     {
293                         FREE(save);
294                         save = NULL;
295                     }
296                 }
297                 else
298                 {
299                     freeArrayOfString(Strings_Input1, m1n1);
300                     freeArrayOfString(Strings_Input2, m2n2);
301                     Scierror(999, _("%s: No more memory.\n"), fname);
302                     return 0;
303                 }
304             }
305
306             sort_inert(values, values + nbValues, cmp);
307         }
308         else
309         {
310             /* We don't use pcre library */
311             int x = 0;
312
313             for (x = 0; x < m2n2 ; ++x)
314             {
315                 if ( wcslen(wStrings_Input2[x]) == 0 )
316                 {
317                     freeArrayOfWideString(wStrings_Input2, m2n2);
318                     freeArrayOfString(Strings_Input2, m2n2);
319                     freeArrayOfString(Strings_Input1, m1n1);
320                     if (next)
321                     {
322                         FREE(next);
323                         next = NULL;
324                     }
325                     if (values)
326                     {
327                         FREE(values);
328                         values = NULL;
329                     }
330                     Scierror(999, _("%s: Wrong size for input argument #%d: Non-empty string expected.\n"), fname, 2);
331                     return 0;
332                 }
333                 if (Strings_Input2)
334                 {
335                     wchar_t *pCur = wStrings_Input1;
336                     do
337                     {
338                         pCur = wcsstr(pCur, wStrings_Input2[x]);
339                         if (pCur != NULL)
340                         {
341                             pCur++;
342                             values[nbValues++].data = (int)(pCur - wStrings_Input1);
343                             values[nbposition++].position = x + 1;
344                         }
345                     }
346                     while (pCur != NULL && *pCur != 0); //Plus tard
347
348                     /* values are sorted */
349                     sort_inert(values, values + nbValues, cmp);
350                 }
351             }
352         }
353
354         FREE(wStrings_Input1);
355         freeArrayOfWideString(wStrings_Input2, m2n2);
356         freeArrayOfString(Strings_Input1, m1n1);
357         freeArrayOfString(Strings_Input2, m2n2);
358
359         numRow   = 1;
360         outIndex = 0;
361         CreateVar(Rhs + 1, MATRIX_OF_DOUBLE_DATATYPE, &numRow, &nbValues, &outIndex);
362         for ( i = 0 ; i < nbValues ; i++ )
363         {
364             stk(outIndex)[i] = (double)values[i].data ;
365         }
366         LhsVar(1) = Rhs + 1 ;
367
368         if (Lhs == 2)
369         {
370             numRow   = 1;
371             outIndex = 0;
372             CreateVar(Rhs + 2, MATRIX_OF_DOUBLE_DATATYPE, &numRow, &nbValues, &outIndex);
373             for ( i = 0 ; i < nbValues ; i++ )
374             {
375                 stk(outIndex)[i] = (double)values[i].position ;
376             }
377             LhsVar(2) = Rhs + 2;
378         }
379
380         if (values)
381         {
382             FREE(values);
383             values = NULL;
384         }
385         PutLhsVar();
386     }
387     else
388     {
389         if (VarType(1) != sci_strings)
390         {
391             Scierror(999, _("%s: Wrong type for input argument #%d: A string expected.\n"), fname, 1);
392         }
393         else
394         {
395             Scierror(999, _("%s: Wrong type for input argument #%d: Row vector of strings or column vector of strings expected.\n"), fname, 2);
396         }
397         return 0;
398     }
399     return 0;
400 }
401 /*------------------------------------------------------------------------*/