* Bug 16365 fixed: median(m,'r'|'c') was wrong after 5dc990
[scilab.git] / scilab / modules / string / sci_gateway / cpp / sci_strindex.cpp
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2008 - INRIA - Cong WU
4  *
5  * Copyright (C) 2012 - 2016 - Scilab Enterprises
6  *
7  * This file is hereby licensed under the terms of the GNU GPL v2.0,
8  * pursuant to article 5.3.4 of the CeCILL v.2.1.
9  * This file was originally licensed under the terms of the CeCILL v2.1,
10  * and continues to be available under such terms.
11  * For more information, see the COPYING file which you should have received
12  * along with this program.
13  *
14  */
15
16 /* desc : search position of a character string in another string        */
17 /*        using regular expression .                                      */
18 /*------------------------------------------------------------------------*/
19 #include "funcmanager.hxx"
20 #include "string_gw.hxx"
21 #include "function.hxx"
22 #include "string.hxx"
23 #include "double.hxx"
24
25 extern "C"
26 {
27 #include <string.h>
28 #include <stdio.h>
29 #include "pcre.h"
30 #include "localization.h"
31 #include "pcre_private.h"
32 #include "pcre_error.h"
33 #include "Scierror.h"
34 }
35 /*------------------------------------------------------------------------*/
36 #define WCHAR_S L's'
37 #define WCHAR_R L'r'
38 /*------------------------------------------------------------------------*/
39 struct In
40 {
41     int data;
42     int position;
43 };
44 /*------------------------------------------------------------------------*/
45 int ComparaisonCallback( const void *in1 , const void *in2)
46 {
47     In* data1 = (In*)in1;
48     In* data2 = (In*)in2;
49
50     if (data1->data == data2->data)
51     {
52         return data1->position > data2->position ? 1 : -1;
53     }
54
55     return data1->data > data2->data ? 1 : -1;
56 }
57 /*------------------------------------------------------------------------*/
58 types::Function::ReturnValue sci_strindex(types::typed_list &in, int _iRetCount, types::typed_list &out)
59 {
60     bool bRegExp = false;
61     if (in.size() < 2 || in.size() > 3)
62     {
63         Scierror(77, _("%s: Wrong number of input argument(s): %d to %d expected.\n"), "strindex", 2, 3);
64         return types::Function::Error;
65     }
66
67     if (in.size() > 2)
68     {
69         if (in[2]->isString() == false && in[2]->getAs<types::String>()->getSize() != 1)
70         {
71             Scierror(999, _("%s: Wrong type for input argument #%d: string expected.\n"), "strindex", 3);
72             return types::Function::Error;
73         }
74
75         if (in[2]->getAs<types::String>()->get(0)[0] == WCHAR_R)
76         {
77             bRegExp = true;
78         }
79         else if (in[2]->getAs<types::String>()->get(0)[0] == WCHAR_S)
80         {
81             bRegExp = false;
82         }
83         else
84         {
85             Scierror(999, _("%s: Wrong value for input argument #%d: 's' or 'r' expected.\n"), "strindex", 3);
86             return types::Function::Error;
87         }
88     }
89
90     if (in[1]->isString() == false || (in[1]->getAs<types::String>()->getRows() != 1 && in[1]->getAs<types::String>()->getCols() != 1))
91     {
92         Scierror(999, _("%s: Wrong type for input argument #%d: string or string vector expected.\n"), "strindex", 2);
93         return types::Function::Error;
94     }
95
96     types::String* pS = in[1]->getAs<types::String>();
97     wchar_t** pwstSearch = pS->get();
98
99     if (in[0]->isDouble() && in[0]->getAs<types::Double>()->isEmpty())
100     {
101         out.push_back(types::Double::Empty());
102         return types::Function::OK;
103     }
104
105     if (in[0]->isString() == false || in[0]->getAs<types::String>()->getSize() != 1)
106     {
107         Scierror(999, _("%s: Wrong type for input argument #%d: string expected.\n"), "strindex", 1);
108         return types::Function::Error;
109     }
110
111     wchar_t* pwstData = in[0]->getAs<types::String>()->get()[0];
112     if (wcslen(pwstData) == 0)
113     {
114         out.push_back(types::Double::Empty());
115         if (_iRetCount == 2)
116         {
117             out.push_back(types::Double::Empty());
118         }
119
120         return types::Function::OK;
121     }
122
123     In* pstrResult = new In[wcslen(pwstData)];
124
125     //number of occurances
126     int iValues = 0;
127     if (bRegExp)
128     {
129         //pcre
130         pcre_error_code iPcreStatus = PCRE_FINISHED_OK;
131         for (int i = 0 ; i < pS->getSize() ; i++)
132         {
133             int iStart      = 0;
134             int iEnd        = 0;
135             int iStep       = 0;
136
137             do
138             {
139                 iPcreStatus = wide_pcre_private(pwstData + iStep, pwstSearch[i], &iStart, &iEnd, NULL, NULL);
140                 if (iPcreStatus == PCRE_FINISHED_OK)
141                 {
142                     pstrResult[iValues].data        = iStart + iStep + 1;
143                     pstrResult[iValues].position    = i + 1;
144                     iStep                           += iEnd;
145                     iValues++;
146                 }
147                 else
148                 {
149                     if (iPcreStatus != NO_MATCH)
150                     {
151                         pcre_error("strindex", iPcreStatus);
152                         delete[] pstrResult;
153                         return types::Function::Error;
154                     }
155                     break;
156                 }
157             }
158             while (iPcreStatus == PCRE_FINISHED_OK && iStart != iEnd);
159         }
160     }
161     else
162     {
163         for (int i = 0 ; i < pS->getSize() ; i++)
164         {
165             wchar_t* pCur = pwstData;
166             do
167             {
168                 pCur = wcsstr(pCur, pwstSearch[i]);
169                 if (pCur != NULL)
170                 {
171                     pstrResult[iValues].data      = (int)(pCur - pwstData + 1);
172                     pstrResult[iValues].position  = i + 1;
173                     pCur++;
174                     iValues++;
175                 }
176             }
177             while (pCur != NULL && pCur[0] != L'\0');
178         }
179     }
180
181     qsort(pstrResult, iValues, sizeof(In), ComparaisonCallback);
182
183     types::Double* pIndex = NULL;
184     if (iValues == 0)
185     {
186         pIndex = types::Double::Empty();
187     }
188     else
189     {
190         pIndex = new types::Double(1, iValues);
191         for (int i = 0 ; i < iValues ; i++)
192         {
193             pIndex->set(0, i, pstrResult[i].data);
194         }
195     }
196     out.push_back(pIndex);
197
198     if (_iRetCount == 2)
199     {
200         types::Double* pPos = NULL;
201         if (iValues == 0)
202         {
203             pPos = types::Double::Empty();
204         }
205         else
206         {
207             pPos = new types::Double(1, iValues);
208             for (int i = 0 ; i < iValues ; i++)
209             {
210                 pPos->set(0, i, pstrResult[i].position);
211             }
212         }
213         out.push_back(pPos);
214     }
215
216     delete[] pstrResult;
217     return types::Function::OK;
218 }
219