utf: module string 2
[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  * 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-en.txt
10  *
11  */
12
13 /* desc : search position of a character string in an other string        */
14 /*        using regular expression .                                      */
15 /*------------------------------------------------------------------------*/
16 #include "funcmanager.hxx"
17 #include "string_gw.hxx"
18 #include "function.hxx"
19 #include "string.hxx"
20 #include "double.hxx"
21
22 extern "C"
23 {
24 #include <string.h>
25 #include <stdio.h>
26 #include "pcre.h"
27 #include "localization.h"
28 #include "pcre_private.h"
29 #include "pcre_error.h"
30 #include "Scierror.h"
31 }
32 /*------------------------------------------------------------------------*/
33 #define WCHAR_S L's'
34 #define WCHAR_R L'r'
35 /*------------------------------------------------------------------------*/
36 struct In
37 {
38     int data;
39     int position;
40 };
41 /*------------------------------------------------------------------------*/
42 int ComparaisonCallback( const void *in1 , const void *in2)
43 {
44     In* data1 = (In*)in1;
45     In* data2 = (In*)in2;
46     
47     if(data1->data == data2->data)
48     {
49         return data1->position > data2->position ? 1 : -1;
50     }
51     
52     return data1->data > data2->data ? 1 : -1;
53 }
54 /*------------------------------------------------------------------------*/
55 types::Function::ReturnValue sci_strindex(types::typed_list &in, int _iRetCount, types::typed_list &out)
56 {
57     bool bRegExp = false;
58     if (in.size() < 2 || in.size() > 3)
59     {
60         Scierror(77, _("%s: Wrong number of input argument(s): %d to %d expected.\n"), "strindex", 2, 3);
61         return types::Function::Error;
62     }
63
64     if (in.size() > 2)
65     {
66         if (in[2]->isString() == false && in[2]->getAs<types::String>()->getSize() != 1)
67         {
68             Scierror(999, _("%s: Wrong type for input argument #%d: string expected.\n"), "strindex", 3);
69             return types::Function::Error;
70         }
71
72         if (in[2]->getAs<types::String>()->get(0)[0] == WCHAR_R)
73         {
74             bRegExp = true;
75         }
76         else if (in[2]->getAs<types::String>()->get(0)[0] == WCHAR_S)
77         {
78             bRegExp = false;
79         }
80         else
81         {
82             Scierror(999, _("%s: Wrong value for input argument #%d: 's' or 'r' expected.\n"), "strindex", 3);
83             return types::Function::Error;
84         }
85     }
86
87     if (in[1]->isString() == false || (in[1]->getAs<types::String>()->getRows() != 1 && in[1]->getAs<types::String>()->getCols() != 1))
88     {
89         Scierror(999, _("%s: Wrong type for input argument #%d: string or string vector expected.\n"), "strindex", 2);
90         return types::Function::Error;
91     }
92
93     types::String* pS = in[1]->getAs<types::String>();
94     char** pstSearch = pS->get();
95
96     if (in[0]->isDouble() && in[0]->getAs<types::Double>()->isEmpty())
97     {
98         out.push_back(types::Double::Empty());
99         return types::Function::OK;
100     }
101
102     if (in[0]->isString() == false || in[0]->getAs<types::String>()->getSize() != 1)
103     {
104         Scierror(999, _("%s: Wrong type for input argument #%d: string expected.\n"), "strindex", 1);
105         return types::Function::Error;
106     }
107
108     char* pstData = in[0]->getAs<types::String>()->get()[0];
109     if (strlen(pstData) == 0)
110     {
111         out.push_back(types::Double::Empty());
112         if (_iRetCount == 2)
113         {
114             out.push_back(types::Double::Empty());
115         }
116
117         return types::Function::OK;
118     }
119
120     In* pstrResult = new In[strlen(pstData)];
121
122     //number of occurances
123     int iValues = 0;
124     if (bRegExp)
125     {
126         //pcre
127         pcre_error_code iPcreStatus = PCRE_FINISHED_OK;
128         for (int i = 0; i < pS->getSize(); i++)
129         {
130             int iStart = 0;
131             int iEnd = 0;
132             int iStep = 0;
133             int iwStep = 0;
134
135             do
136             {
137                 iPcreStatus = pcre_private(pstData + iStep, pstSearch[i], &iStart, &iEnd, NULL, NULL);
138                 if (iPcreStatus == PCRE_FINISHED_OK)
139                 {
140                     //convert strat and end to codepoint value
141                     char* pstTempStart = NULL;
142                     char* pstTempEnd = NULL;
143                     wchar_t* pwstTempStart = NULL;
144                     wchar_t* pwstTempEnd = NULL;
145
146                     pstTempStart = os_strdup(pstData + iStep);
147                     pstTempEnd = os_strdup(pstData + iStep);
148                     pstTempEnd[iEnd] = 0;
149                     pstTempStart[iStart] = 0;
150
151
152                     pwstTempStart = to_wide_string(pstTempStart);
153                     pwstTempEnd = to_wide_string(pstTempEnd);
154
155                     int iwStart = (int)wcslen(pwstTempStart);
156                     int iwEnd = (int)wcslen(pwstTempEnd);
157
158                     pstrResult[iValues].data = iwStart + iwStep + 1;
159                     pstrResult[iValues].position = i + 1;
160                     iStep += iEnd;
161                     iwStep += iwEnd;
162                     iValues++;
163                 }
164                 else
165                 {
166                     if (iPcreStatus != NO_MATCH)
167                     {
168                         pcre_error("strindex", iPcreStatus);
169                         delete[] pstrResult;
170                         return types::Function::Error;
171                     }
172                     break;
173                 }
174             } while (iPcreStatus == PCRE_FINISHED_OK && iStart != iEnd);
175         }
176     }
177     else
178     {
179         for (int i = 0 ; i < pS->getSize() ; i++)
180         {
181             wchar_t* pwstData = to_wide_string(pstData);
182             wchar_t* pCur = pwstData;
183             wchar_t* pwstSearch = to_wide_string(pstSearch[i]);
184             do
185             {
186                 pCur = wcsstr(pCur, pwstSearch);
187                 if (pCur != NULL)
188                 {
189                     pstrResult[iValues].data      = (int)(pCur - pwstData + 1);
190                     pstrResult[iValues].position  = i + 1;
191                     pCur++;
192                     iValues++;
193                 }
194             } while (pCur != NULL && pCur[0] != L'\0');
195
196             FREE(pwstSearch);
197             FREE(pwstData);
198         }
199     }
200
201     qsort(pstrResult, iValues, sizeof(In), ComparaisonCallback);
202
203     types::Double* pIndex = NULL;
204     if (iValues == 0)
205     {
206         pIndex = types::Double::Empty();
207     }
208     else
209     {
210         pIndex = new types::Double(1, iValues);
211         for (int i = 0 ; i < iValues ; i++)
212         {
213             pIndex->set(0, i, pstrResult[i].data);
214         }
215     }
216     out.push_back(pIndex);
217
218     if (_iRetCount == 2)
219     {
220         types::Double* pPos = NULL;
221         if (iValues == 0)
222         {
223             pPos = types::Double::Empty();
224         }
225         else
226         {
227             pPos = new types::Double(1, iValues);
228             for (int i = 0 ; i < iValues ; i++)
229             {
230                 pPos->set(0, i, pstrResult[i].position);
231             }
232         }
233         out.push_back(pPos);
234     }
235
236     delete[] pstrResult;
237     return types::Function::OK;
238 }
239