8af309e28f054c4bd3eb2a69d046455c87cf139c
[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_strdup.h"
33 #include "freeArrayOfString.h"
34 }
35 /*------------------------------------------------------------------------*/
36 #define WCHAR_S L's'
37 #define WCHAR_R L'r'
38 #define WSTR_ONCE L'o'
39 /*------------------------------------------------------------------------*/
40
41 using namespace types;
42
43 Function::ReturnValue sci_regexp(typed_list &in, int _iRetCount, 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 Function::Error;
65     }
66
67     // check output parameters
68     if (_iRetCount < 1 || _iRetCount > 4)
69     {
70         Scierror(999, _("%s: Wrong number of output arguments: %d to %d expected.\n"), "regexp", 1, 4);
71         return 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: Single string expected.\n"), "regexp", 1);
77         return 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: Single string expected.\n"), "regexp", 2);
84         return 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: Single string expected.\n"), "regexp", 3);
93             return 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 Function::Error;
100         }
101         wcType = WSTR_ONCE;
102     }
103
104     //input is empty
105     if (wcslen(pwstInput) == 0)
106     {
107         Double* pStart = new Double(0, 0);
108         out.push_back(pStart);
109         if (_iRetCount > 1)
110         {
111             Double* pEnd = new Double(0, 0);
112             out.push_back(pEnd);
113
114             if (_iRetCount > 2)
115             {
116                 String* pS = new String(0, 0);
117                 out.push_back(pS);
118             }
119         }
120         return Function::OK;
121     }
122
123     piStart     = new int[wcslen(pwstInput)];
124     piEnd       = new int[wcslen(pwstInput)];
125
126     pwstCapturedString = (wchar_t***)MALLOC(sizeof(wchar_t**) * wcslen(pwstInput));
127     piCapturedStringCount = (int*)MALLOC(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             return Function::Error;
152         }
153     }
154     while (iPcreStatus == PCRE_FINISHED_OK && iStart != iEnd && wcType != WSTR_ONCE);
155
156     if (iOccurs == 0)
157     {
158         out.push_back(types::Double::Empty());
159         if (_iRetCount > 1)
160         {
161             out.push_back(types::Double::Empty());
162         }
163
164         if (_iRetCount > 2)
165         {
166             out.push_back(new String(L""));
167         }
168
169         if (_iRetCount > 3)
170         {
171             out.push_back(new String(L""));
172         }
173         return Function::OK;
174     }
175
176     Double* pStart = new Double(1, iOccurs);
177     double* pdblStart = pStart->getReal();
178
179     for (int i = 0 ; i < iOccurs ; i++)
180     {
181         pdblStart[i] = piStart[i] + 1; //one indexed
182     }
183
184     out.push_back(pStart);
185
186     if (_iRetCount > 1)
187     {
188         Double* pEnd = new Double(1, iOccurs);
189         double* pdblEnd = pEnd->getReal();
190         for (int i = 0 ; i < iOccurs ; i++)
191         {
192             pdblEnd[i]   = piEnd[i];
193         }
194         out.push_back(pEnd);
195     }
196
197     if (_iRetCount > 2)
198     {
199         String *pS = NULL;
200         if (iOccurs == 0)
201         {
202             pS = new String(1, 1);
203             pS->set(0, L"");
204         }
205         else
206         {
207             pS = new String(iOccurs, 1);
208             for (int i = 0 ; i < iOccurs ; i++)
209             {
210                 wchar_t* pwstTemp = new wchar_t[piEnd[i] - piStart[i] + 1];
211                 wcsncpy(pwstTemp, pwstInput + piStart[i], piEnd[i] - piStart[i]);
212                 pwstTemp[piEnd[i] - piStart[i]] = 0;
213                 pS->set(i, 0, pwstTemp);
214                 delete[] pwstTemp;
215             }
216         }
217         out.push_back(pS);
218     }
219
220     if (_iRetCount > 3)
221     {
222         //find max occurrences
223         int iMax = 0;
224         for (int i = 0 ; i < iOccurs ; i++)
225         {
226             iMax = Max(iMax, piCapturedStringCount[i]);
227         }
228
229         String* pS = NULL;
230         if (iOccurs == 0 || iMax == 0)
231         {
232             pS = new String(L"");
233         }
234         else
235         {
236             int index = 0;
237             pS = new String(iOccurs, iMax);
238             for (int i = 0 ; i < iMax ; i++)
239             {
240                 for (int j = 0 ; j < iOccurs ; j++)
241                 {
242                     if (i < piCapturedStringCount[j])
243                     {
244                         pS->set(index, pwstCapturedString[j][i]);
245                     }
246                     else
247                     {
248                         pS->set(index, L"");
249                     }
250
251                     index++;
252                 }
253             }
254
255         }
256         out.push_back(pS);
257
258         for (int i = 0 ; i < iOccurs ; i++)
259         {
260             freeArrayOfWideString(pwstCapturedString[i], piCapturedStringCount[i]);
261         }
262
263         FREE(pwstCapturedString);
264         FREE(piCapturedStringCount);
265     }
266
267     delete[] piStart;
268     delete[] piEnd;
269     return Function::OK;
270 }
271 /*-----------------------------------------------------------------------------------*/