Merge remote-tracking branch 'origin/master' into windows
[scilab.git] / scilab / modules / core / sci_gateway / cpp / sci_newfun.cpp
1 /*
2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2014 - Scilab Enterprises - Antoine ELIAS
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 #include "core_gw.hxx"
17 #include "configvariable.hxx"
18 #include "double.hxx"
19 #include "string.hxx"
20 #include "function.hxx"
21 #include "context.hxx"
22
23 extern "C"
24 {
25 #include "Scierror.h"
26 #include "localization.h"
27 }
28
29 /*--------------------------------------------------------------------------*/
30 bool isValidName(const char* _pstName)
31 {
32     if (_pstName == NULL)
33     {
34         return false;
35     }
36
37     if (isdigit(_pstName[0]))
38     {
39         return false;
40     }
41
42     int size = (int)strlen(_pstName);
43     for (int i = 1 ; i < size ; ++i)
44     {
45         char c = _pstName[i];
46         if (c != '_' && c != '?' && c != '!' && isalnum(c) == false)
47         {
48             return false;
49         }
50
51     }
52     return true;
53 }
54 /*--------------------------------------------------------------------------*/
55 types::Function::ReturnValue sci_newfun(types::typed_list &in, int _iRetCount, types::typed_list &out)
56 {
57     if (in.size() != 2)
58     {
59         Scierror(999, _("%s: Wrong number of input arguments: %d expected.\n"), "newfun" , 2);
60         return types::Function::Error;
61     }
62
63     types::InternalType* pIT1 = in[0];
64     types::InternalType* pIT2 = in[1];
65
66     if (pIT1->isString() == false)
67     {
68         Scierror(999, _("%s: Wrong type for input argument #%d: String expected.\n"), "newfun", 1);
69         return types::Function::Error;
70     }
71
72     types::String* pS1 = pIT1->getAs<types::String>();
73     if (pS1->isScalar() == false)
74     {
75         Scierror(999, _("%s: Wrong size for input argument #%d: string expected.\n"), "newfun", 1);
76         return types::Function::Error;
77     }
78
79     char* pcsNewName = pS1->get(0);
80
81     //check is a valid name
82     if (isValidName(pcsNewName) == false)
83     {
84         Scierror(999, _("%s: Wrong value for input argument #%d: Valid function name expected.\n"), "newfun", 1);
85         return types::Function::Error;
86     }
87
88     if (pIT2->isString() == false)
89     {
90         Scierror(999, _("%s: Wrong type for input argument #%d: String expected.\n"), "newfun", 2);
91         return types::Function::Error;
92     }
93
94     types::String* pS2 = pIT2->getAs<types::String>();
95     if (pS2->isScalar() == false)
96     {
97         Scierror(999, _("%s: Wrong size for input argument #%d: string expected.\n"), "newfun", 2);
98         return types::Function::Error;
99     }
100
101     char* pcsName = pS2->get(0);
102
103     types::Function* pFunc = NULL;
104     symbol::Context* pCtx = symbol::Context::getInstance();
105
106     symbol::Variable* pVar = pCtx->getOrCreate(symbol::Symbol(pcsName));
107     symbol::Variable::StackVar stack;
108
109     //get original function
110
111     //unstack all elements and stack them in new stack ( reverse order )
112     while (pVar->empty() == false)
113     {
114         stack.push(pVar->top());
115         pVar->pop();
116     }
117
118     if (stack.empty() == false)
119     {
120         symbol::ScopedVariable* pSV = stack.top();
121         if (pSV->m_iLevel == 0 && pSV->m_pIT->isFunction())
122         {
123             pFunc = pSV->m_pIT->getAs<types::Function>();
124         }
125
126         //move all elements at orginal place and order
127         while (stack.empty() == false)
128         {
129             pSV = stack.top();
130             stack.pop();
131             //pSV->m_pIT->DecreaseRef();
132             pVar->put(pSV);
133         }
134     }
135
136     if (pFunc == NULL)
137     {
138         Scierror(999, _("%s: function-name is incorrect.\n"), "newfun");
139         return types::Function::Error;
140     }
141
142     //new function
143     pVar = pCtx->getOrCreate(symbol::Symbol(pcsNewName));
144     if (pVar->empty())
145     {
146         pVar->put(pFunc, 0);
147     }
148     else
149     {
150         //unstack all elements and stack them in new stack ( reverse order )
151         while (pVar->empty() == false)
152         {
153             stack.push(pVar->top());
154             pVar->pop();
155         }
156
157         symbol::ScopedVariable* pSV = stack.top();
158         if (pSV->m_iLevel == 0)
159         {
160             stack.pop();
161             //clear current var and insert new one
162             types::InternalType* pIT = pSV->m_pIT;
163             pIT->DecreaseRef();
164             pIT->killMe();
165         }
166
167         pVar->put(pFunc, 0);
168
169         //move all elements at orginal place and order
170         while (stack.empty() == false)
171         {
172             pSV = stack.top();
173             stack.pop();
174             //pSV->m_pIT->DecreaseRef();
175             pVar->put(pSV);
176         }
177     }
178
179     return types::Function::OK;
180 }
181 /*--------------------------------------------------------------------------*/