* Bug 16365 fixed: median(m,'r'|'c') was wrong after 5dc990
[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  * 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 /* desc : search position of a character string in another string
18 using regular expression .                                      */
19 /*------------------------------------------------------------------------*/
20 #include "function.hxx"
21 #include "context.hxx"
22 #include "string.hxx"
23 #include "double.hxx"
24 #include "string_gw.hxx"
25
26 extern "C"
27 {
28 #include "sci_malloc.h"
29 #include "localization.h"
30 #include "pcre.h"
31 #include "pcre_private.h"
32 #include "pcre_error.h"
33 #include "Scierror.h"
34 #include "charEncoding.h"
35 #include "os_string.h"
36 #include "freeArrayOfString.h"
37 }
38 /*------------------------------------------------------------------------*/
39 #define WCHAR_S L's'
40 #define WCHAR_R L'r'
41 #define WSTR_ONCE L'o'
42 /*------------------------------------------------------------------------*/
43 types::Function::ReturnValue sci_regexp(types::typed_list &in, int _iRetCount, types::typed_list &out)
44 {
45     wchar_t wcType          = WCHAR_S;
46     wchar_t* pwstInput      = NULL;
47     wchar_t* pwstPattern    = NULL;
48
49     int iPcreStatus         = 0;
50     int iStart              = 0;
51     int iStep               = 0;
52     int iEnd                = 0;
53     int* piStart            = NULL;
54     int* piEnd              = NULL;
55     int iOccurs             = 0;
56
57     /*for captured sub strings*/
58     wchar_t*** pwstCapturedString = NULL;
59     int* piCapturedStringCount = NULL;
60
61     if (in.size() < 2 || in.size() > 3)
62     {
63         Scierror(999, _("%s: Wrong number of input arguments: %d or %d expected.\n"), "regexp", 2, 3);
64         return types::Function::Error;
65     }
66
67     // check output parameters
68     if (_iRetCount > 4)
69     {
70         Scierror(999, _("%s: Wrong number of output arguments: %d to %d expected.\n"), "regexp", 1, 4);
71         return types::Function::Error;
72     }
73
74     if (in[0]->isString() == false || in[0]->getAs<types::String>()->getSize() != 1)
75     {
76         Scierror(999, _("%s: Wrong type for input argument #%d: string expected.\n"), "regexp", 1);
77         return types::Function::Error;
78     }
79     pwstInput = in[0]->getAs<types::String>()->get(0);
80
81     if (in[1]->isString() == false || in[1]->getAs<types::String>()->getSize() != 1)
82     {
83         Scierror(999, _("%s: Wrong type for input argument #%d: string expected.\n"), "regexp", 2);
84         return types::Function::Error;
85     }
86     pwstPattern = 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] != WSTR_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         wcType = WSTR_ONCE;
102     }
103
104     //input is empty
105     if (wcslen(pwstInput) == 0)
106     {
107         types::Double* pStart = new types::Double(0, 0);
108         out.push_back(pStart);
109         if (_iRetCount > 1)
110         {
111             types::Double* pEnd = new types::Double(0, 0);
112             out.push_back(pEnd);
113
114             if (_iRetCount > 2)
115             {
116                 types::String* pS = new types::String(0, 0);
117                 out.push_back(pS);
118             }
119         }
120         return types::Function::OK;
121     }
122
123     piStart     = new int[wcslen(pwstInput)];
124     piEnd       = new int[wcslen(pwstInput)];
125
126     pwstCapturedString = (wchar_t***)CALLOC(sizeof(wchar_t**), wcslen(pwstInput));
127     piCapturedStringCount = (int*)CALLOC(sizeof(int), wcslen(pwstInput));
128
129     do
130     {
131         iPcreStatus = wide_pcre_private(pwstInput + iStep, pwstPattern, &iStart, &iEnd, &pwstCapturedString[iOccurs], &piCapturedStringCount[iOccurs]);
132         if (iPcreStatus == PCRE_FINISHED_OK)
133         {
134             if (iEnd != iStart)
135             {
136                 piStart[iOccurs]    = iStart + iStep;
137                 piEnd[iOccurs++]    = iEnd + iStep;
138                 iStep               += iEnd;
139             }
140             else if (iEnd == 0 && pwstInput[iStep] != L'\0')
141             {
142                 //avoid infinite loop
143                 iStep++;
144             }
145         }
146         else if (iPcreStatus != NO_MATCH)
147         {
148             pcre_error("regexp", iPcreStatus);
149             delete[] piStart;
150             delete[] piEnd;
151             for (int i = 0; i < iOccurs; i++)
152             {
153                 freeArrayOfWideString(pwstCapturedString[i], piCapturedStringCount[i]);
154             }
155
156             FREE(pwstCapturedString);
157             FREE(piCapturedStringCount);
158             return types::Function::Error;
159         }
160     }
161     while (iPcreStatus == PCRE_FINISHED_OK && iStart != iEnd && wcType != WSTR_ONCE);
162
163     if (iOccurs == 0)
164     {
165         out.push_back(types::Double::Empty());
166         if (_iRetCount > 1)
167         {
168             out.push_back(types::Double::Empty());
169         }
170
171         if (_iRetCount > 2)
172         {
173             out.push_back(new types::String(L""));
174         }
175
176         if (_iRetCount > 3)
177         {
178             out.push_back(new types::String(L""));
179         }
180
181         freeArrayOfWideString(pwstCapturedString[0], piCapturedStringCount[0]);
182         FREE(pwstCapturedString);
183         FREE(piCapturedStringCount);
184         delete[] piStart;
185         delete[] piEnd;
186         return types::Function::OK;
187     }
188
189     types::Double* pStart = new types::Double(1, iOccurs);
190     double* pdblStart = pStart->getReal();
191
192     for (int i = 0 ; i < iOccurs ; i++)
193     {
194         pdblStart[i] = piStart[i] + 1; //one indexed
195     }
196
197     out.push_back(pStart);
198
199     if (_iRetCount > 1)
200     {
201         types::Double* pEnd = new types::Double(1, iOccurs);
202         double* pdblEnd = pEnd->getReal();
203         for (int i = 0 ; i < iOccurs ; i++)
204         {
205             pdblEnd[i]   = piEnd[i];
206         }
207         out.push_back(pEnd);
208     }
209
210     if (_iRetCount > 2)
211     {
212         types::String *pS = NULL;
213         if (iOccurs == 0)
214         {
215             pS = new types::String(1, 1);
216             pS->set(0, L"");
217         }
218         else
219         {
220             pS = new types::String(iOccurs, 1);
221             for (int i = 0 ; i < iOccurs ; i++)
222             {
223                 wchar_t* pwstTemp = new wchar_t[piEnd[i] - piStart[i] + 1];
224                 wcsncpy(pwstTemp, pwstInput + piStart[i], piEnd[i] - piStart[i]);
225                 pwstTemp[piEnd[i] - piStart[i]] = 0;
226                 pS->set(i, 0, pwstTemp);
227                 delete[] pwstTemp;
228             }
229         }
230         out.push_back(pS);
231     }
232
233     if (_iRetCount > 3)
234     {
235         //find max occurrences
236         int iMax = 0;
237         for (int i = 0 ; i < iOccurs ; i++)
238         {
239             iMax = std::max(iMax, piCapturedStringCount[i]);
240         }
241
242         types::String* pS = NULL;
243         if (iOccurs == 0 || iMax == 0)
244         {
245             pS = new types::String(L"");
246         }
247         else
248         {
249             int index = 0;
250             pS = new types::String(iOccurs, iMax);
251             for (int i = 0 ; i < iMax ; i++)
252             {
253                 for (int j = 0 ; j < iOccurs ; j++)
254                 {
255                     if (i < piCapturedStringCount[j])
256                     {
257                         pS->set(index, pwstCapturedString[j][i]);
258                     }
259                     else
260                     {
261                         pS->set(index, L"");
262                     }
263
264                     index++;
265                 }
266             }
267         }
268
269         out.push_back(pS);
270     }
271
272     for (int i = 0; i < iOccurs; i++)
273     {
274         freeArrayOfWideString(pwstCapturedString[i], piCapturedStringCount[i]);
275     }
276
277     FREE(pwstCapturedString);
278     FREE(piCapturedStringCount);
279     delete[] piStart;
280     delete[] piEnd;
281     return types::Function::OK;
282 }
283 /*-----------------------------------------------------------------------------------*/