utf: module string 2
[scilab.git] / scilab / modules / string / sci_gateway / cpp / sci_regexp.cpp
1 /*
2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2008 - INRIA - Cong WU
4 * Copyright (C) 2008 - 2009 - DIGITEO - Allan CORNET
5 *
6 * This file must be used under the terms of the CeCILL.
7 * This source file is licensed as described in the file COPYING, which
8 * you should have received as part of this distribution.  The terms
9 * are also available at
10 * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
11 *
12 */
13
14 /* desc : search position of a character string in an other string
15 using regular expression .                                      */
16 /*------------------------------------------------------------------------*/
17 #include "function.hxx"
18 #include "context.hxx"
19 #include "string.hxx"
20 #include "double.hxx"
21 #include "string_gw.hxx"
22
23 extern "C"
24 {
25 #include "sci_malloc.h"
26 #include "localization.h"
27 #include "pcre.h"
28 #include "pcre_private.h"
29 #include "pcre_error.h"
30 #include "Scierror.h"
31 #include "charEncoding.h"
32 #include "os_string.h"
33 #include "freeArrayOfString.h"
34 }
35 /*------------------------------------------------------------------------*/
36 #define CHAR_S 's'
37 #define CHAR_R 'r'
38 #define STR_ONCE 'o'
39 /*------------------------------------------------------------------------*/
40 types::Function::ReturnValue sci_regexp(types::typed_list &in, int _iRetCount, types::typed_list &out)
41 {
42     char cType = CHAR_S;
43     char* pstInput = NULL;
44     char* pstPattern = NULL;
45
46     int iPcreStatus = 0;
47     int iStart = 0;
48     int iStep = 0;
49     int iwStep = 0;
50     int iEnd = 0;
51     int* piStart = NULL;
52     int* piEnd = NULL;
53     int iOccurs = 0;
54
55     /*for captured sub strings*/
56     char*** pstCapturedString = NULL;
57     int* piCapturedStringCount = NULL;
58
59     if (in.size() < 2 || in.size() > 3)
60     {
61         Scierror(999, _("%s: Wrong number of input arguments: %d or %d expected.\n"), "regexp", 2, 3);
62         return types::Function::Error;
63     }
64
65     // check output parameters
66     if (_iRetCount < 1 || _iRetCount > 4)
67     {
68         Scierror(999, _("%s: Wrong number of output arguments: %d to %d expected.\n"), "regexp", 1, 4);
69         return types::Function::Error;
70     }
71
72     if (in[0]->isString() == false || in[0]->getAs<types::String>()->getSize() != 1)
73     {
74         Scierror(999, _("%s: Wrong type for input argument #%d: string expected.\n"), "regexp", 1);
75         return types::Function::Error;
76     }
77
78     pstInput = in[0]->getAs<types::String>()->get(0);
79
80     if (in[1]->isString() == false || in[1]->getAs<types::String>()->getSize() != 1)
81     {
82         Scierror(999, _("%s: Wrong type for input argument #%d: string expected.\n"), "regexp", 2);
83         return types::Function::Error;
84     }
85
86     pstPattern = in[1]->getAs<types::String>()->get(0);
87
88     if (in.size() == 3)
89     {
90         if (in[2]->isString() == false || in[2]->getAs<types::String>()->getSize() != 1)
91         {
92             Scierror(999, _("%s: Wrong type for input argument #%d: string expected.\n"), "regexp", 3);
93             return types::Function::Error;
94         }
95
96         if (in[2]->getAs<types::String>()->get(0)[0] != STR_ONCE)
97         {
98             Scierror(999, _("%s: Wrong type for input argument #%d: '%s' expected.\n"), "regexp", 3, "o");
99             return types::Function::Error;
100         }
101         
102         cType = STR_ONCE;
103     }
104
105     //input is empty
106     if (strlen(pstInput) == 0)
107     {
108         types::Double* pStart = new types::Double(0, 0);
109         out.push_back(pStart);
110         if (_iRetCount > 1)
111         {
112             types::Double* pEnd = new types::Double(0, 0);
113             out.push_back(pEnd);
114
115             if (_iRetCount > 2)
116             {
117                 types::String* pS = new types::String(0, 0);
118                 out.push_back(pS);
119             }
120         }
121         return types::Function::OK;
122     }
123
124     piStart = new int[strlen(pstInput)];
125     piEnd = new int[strlen(pstInput)];
126
127     pstCapturedString = (char***)CALLOC(sizeof(char**), strlen(pstInput));
128     piCapturedStringCount = (int*)CALLOC(sizeof(int), strlen(pstInput));
129
130     do
131     {
132         iPcreStatus = pcre_private(pstInput + iStep, pstPattern, &iStart, &iEnd, &pstCapturedString[iOccurs], &piCapturedStringCount[iOccurs]);
133         if (iPcreStatus == PCRE_FINISHED_OK)
134         {
135             if (iEnd != iStart)
136             {
137                 //convert strat and end to codepoint value
138                 char* pstTempStart = NULL;
139                 char* pstTempEnd = NULL;
140                 wchar_t* pwstTempStart = NULL;
141                 wchar_t* pwstTempEnd = NULL;
142
143                 pstTempStart = os_strdup(pstInput + iStep);
144                 pstTempEnd = os_strdup(pstInput + iStep);
145                 pstTempEnd[iEnd] = 0;
146                 pstTempStart[iStart] = 0;
147
148
149                 pwstTempStart = to_wide_string(pstTempStart);
150                 pwstTempEnd = to_wide_string(pstTempEnd);
151
152                 int iwStart = (int)wcslen(pwstTempStart);
153                 int iwEnd = (int)wcslen(pwstTempEnd);
154
155                 piStart[iOccurs] = iwStart + iwStep;
156                 piEnd[iOccurs++] = iwEnd + iwStep;
157                 iStep += iEnd;
158                 iwStep += iwEnd;
159             }
160             else if (iEnd == 0 && pstInput[iStep] != '\0')
161             {
162                 //avoid infinite loop
163                 iStep++;
164             }
165         }
166         else if (iPcreStatus != NO_MATCH)
167         {
168             pcre_error("regexp", iPcreStatus);
169             delete[] piStart;
170             delete[] piEnd;
171             for (int i = 0; i < iOccurs; i++)
172             {
173                 freeArrayOfString(pstCapturedString[i], piCapturedStringCount[i]);
174             }
175
176             FREE(pstCapturedString);
177             FREE(piCapturedStringCount);
178             return types::Function::Error;
179         }
180     }
181     while (iPcreStatus == PCRE_FINISHED_OK && iStart != iEnd && cType != STR_ONCE);
182
183     if (iOccurs == 0)
184     {
185         out.push_back(types::Double::Empty());
186         if (_iRetCount > 1)
187         {
188             out.push_back(types::Double::Empty());
189         }
190
191         if (_iRetCount > 2)
192         {
193             out.push_back(new types::String(""));
194         }
195
196         if (_iRetCount > 3)
197         {
198             out.push_back(new types::String(""));
199         }
200
201         freeArrayOfString(pstCapturedString[0], piCapturedStringCount[0]);
202         FREE(pstCapturedString);
203         FREE(piCapturedStringCount);
204         delete[] piStart;
205         delete[] piEnd;
206         return types::Function::OK;
207     }
208
209     types::Double* pStart = new types::Double(1, iOccurs);
210     double* pdblStart = pStart->getReal();
211
212     for (int i = 0 ; i < iOccurs ; i++)
213     {
214         pdblStart[i] = piStart[i] + 1; //one indexed
215     }
216
217     out.push_back(pStart);
218
219     if (_iRetCount > 1)
220     {
221         types::Double* pEnd = new types::Double(1, iOccurs);
222         double* pdblEnd = pEnd->getReal();
223         for (int i = 0 ; i < iOccurs ; i++)
224         {
225             pdblEnd[i]   = piEnd[i];
226         }
227         out.push_back(pEnd);
228     }
229
230     if (_iRetCount > 2)
231     {
232         types::String *pS = NULL;
233         if (iOccurs == 0)
234         {
235             pS = new types::String(1, 1);
236             pS->set(0, "");
237         }
238         else
239         {
240             pS = new types::String(iOccurs, 1);
241             for (int i = 0 ; i < iOccurs ; i++)
242             {
243                 wchar_t* pwstTemp = new wchar_t[piEnd[i] - piStart[i] + 1];
244                 wchar_t* pwstInput = to_wide_string(pstInput);
245                 wcsncpy(pwstTemp, pwstInput + piStart[i], piEnd[i] - piStart[i]);
246                 pwstTemp[piEnd[i] - piStart[i]] = 0;
247                 char* pstTemp = wide_string_to_UTF8(pwstTemp);
248                 pS->set(i, 0, pstTemp);
249                 delete[] pstTemp;
250                 delete[] pwstInput;
251                 delete[] pwstTemp;
252             }
253         }
254         out.push_back(pS);
255     }
256
257     if (_iRetCount > 3)
258     {
259         //find max occurrences
260         int iMax = 0;
261         for (int i = 0 ; i < iOccurs ; i++)
262         {
263             iMax = std::max(iMax, piCapturedStringCount[i]);
264         }
265
266         types::String* pS = NULL;
267         if (iOccurs == 0 || iMax == 0)
268         {
269             pS = new types::String("");
270         }
271         else
272         {
273             int index = 0;
274             pS = new types::String(iOccurs, iMax);
275             for (int i = 0 ; i < iMax ; i++)
276             {
277                 for (int j = 0 ; j < iOccurs ; j++)
278                 {
279                     if (i < piCapturedStringCount[j])
280                     {
281                         pS->set(index, pstCapturedString[j][i]);
282                     }
283                     else
284                     {
285                         pS->set(index, "");
286                     }
287
288                     index++;
289                 }
290             }
291         }
292
293         out.push_back(pS);
294     }
295
296     for (int i = 0; i < iOccurs; i++)
297     {
298         freeArrayOfString(pstCapturedString[i], piCapturedStringCount[i]);
299     }
300
301     FREE(pstCapturedString);
302     FREE(piCapturedStringCount);
303     delete[] piStart;
304     delete[] piEnd;
305     return types::Function::OK;
306 }
307 /*-----------------------------------------------------------------------------------*/