57515f314dec0f1e2df84a611da0ce0921db31f2
[scilab.git] / scilab / modules / dynamic_link / src / cpp / dynamic_link.cpp
1 /*
2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) INRIA/ENPC
4 * Copyright (C) DIGITEO - 2011 - 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 /*---------------------------------------------------------------------------*/
15
16 #include "configvariable.hxx"
17
18 extern "C"
19 {
20 #include <string.h> 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include "dynamic_link.h"
24 #include "dynamiclibrary.h"
25 #include "men_Sutils.h"
26 #include "MALLOC.h" /* MALLOC */
27 #include "sci_warning.h"
28 #include "sciprint.h"
29 #include "stack-c.h"
30 #include "addinter.h"
31 #include "localization.h"
32 #include "Scierror.h"
33 #include "FileExist.h"
34 #include "ilib_verbose.h"
35 #ifdef _MSC_VER
36 #include "getenvc.h"
37 #include "dllinfo.h"
38 #endif
39 #include "getshortpathname.h"
40 #include "BOOL.h"
41 #include "charEncoding.h"
42 }
43 /*---------------------------------------------------------------------------*/
44 static void Underscores(BOOL _bFortran, wchar_t* _pwstEntryPointName, wchar_t* _pwstTrailingName);
45 static int SearchFandS(char *op, int ilib);
46 /*---------------------------------------------------------------------------*/
47 #define MAXNAME  256 
48 #define TMPL 256
49 #define debug C2F(iop).ddt==1
50 /*---------------------------------------------------------------------------*/
51 #ifdef _MSC_VER
52 /* struct used by fortran (F2C) */
53 /* required to be defined in C */
54
55 typedef struct {
56     char name[nlgh+1];
57 } CINTER_struct;
58
59 __declspec (dllexport) CINTER_struct C2F(cinter);
60
61 /* struct used by fortran (F2C) */
62 /* required to be defined in C */
63 typedef struct {
64     int ibuf[lsiz];
65 } IBFU_struct;
66 __declspec (dllexport) CINTER_struct C2F(ibfu);
67
68 #endif
69 /*---------------------------------------------------------------------------*/
70 typedef char Name[MAXNAME];   /* could be changed to dynamic structure */
71
72 typedef void (*function) (wchar_t*);
73
74 typedef struct 
75
76     function epoint;            /* the entry point */ 
77     Name     name;              /* entry point name */
78     int      Nshared;           /* number of the shared file */
79 } Epoints;
80
81 typedef struct 
82 {
83     int ok;
84     char tmp_file[TMPL];
85     unsigned long  shl;
86 } Hd;
87
88 static Hd  hd[ENTRYMAX]; /* shared libs handler */
89 static int Nshared = 0;
90 static int NEpoints = 0; /* Number of Linked names */
91 static Epoints EP[ENTRYMAX];  /* entryPoints */
92 /*---------------------------------------------------------------------------*/
93 int scilabLink(int _iLibID, wchar_t* _pwstLibraryName, wchar_t** _pwstEntryPointName, int _iEntryPointSize, BOOL _bFortran ,int *_piErr)
94 {
95     int iLibID = -1; 
96
97     if(_iLibID == -1) 
98     {
99         iLibID = Sci_dlopen(_pwstLibraryName);
100     } 
101     else 
102     {
103         iLibID = _iLibID;
104     }
105
106     if(iLibID == -1) 
107     {
108         if( getWarningMode() ) 
109         {
110 #ifdef _MSC_VER
111             if(isDllW(_pwstLibraryName))
112             {
113 #ifdef _WIN64
114                 if(isX86DllW(_pwstLibraryName))
115                 {
116                     if(getIlibVerboseLevel() != ILIB_VERBOSE_NO_OUTPUT)
117                     {
118                         sciprint(_("%s: can not to load a x86 dll in a x64 environment.\n" ), "link");
119                     }
120                     SetLastError(ERROR_DLL_INIT_FAILED);
121                 }
122 #else
123                 if(isX64DllW(_pwstLibraryName))
124                 {
125                     if(getIlibVerboseLevel() != ILIB_VERBOSE_NO_OUTPUT)
126                     {
127                         sciprint(_("%s: can not load a x64 dll in a x86 environment.\n" ), "link");
128                     }
129                     SetLastError(ERROR_DLL_INIT_FAILED);
130                 }
131 #endif
132             }
133             else
134             {
135                 wchar_t* pwstPathSearch = searchEnvW(_pwstLibraryName, L"PATH");
136                 if(pwstPathSearch == NULL)
137                 {
138                     if(getIlibVerboseLevel() != ILIB_VERBOSE_NO_OUTPUT)
139                     {
140                         sciprintW(_W("%ls: The file %ls does not exist in PATH environment.\n" ), L"link", _pwstLibraryName);
141                     }
142                 }
143             }
144 #else
145             if(getIlibVerboseLevel() != ILIB_VERBOSE_NO_OUTPUT)
146             {
147                 sciprintW(_W("Link failed for dynamic library '%ls'.\n"), _pwstLibraryName);
148                 sciprint(_("An error occurred: %s\n"), GetLastDynLibError());
149             }
150 #endif
151         }
152         *_piErr = -1;
153         return iLibID;
154     }
155
156     if( (_iLibID == -1) && (getIlibVerboseLevel() != ILIB_VERBOSE_NO_OUTPUT)) 
157     {
158         sciprint(_("Shared archive loaded.\n"));
159         sciprint(_("Link done.\n"));
160     }
161
162     for(int i = 0 ; i < _iEntryPointSize ; i++)
163     {
164         *_piErr = Sci_dlsym(_pwstEntryPointName[i], iLibID, _bFortran);
165     }
166
167     return iLibID;
168 }
169 /*---------------------------------------------------------------------------*/
170 char **getNamesOfFunctionsInSharedLibraries(int *sizearray)
171 {
172     char **NamesOfFunctions = NULL;
173     *sizearray = 0;
174
175     if( (NEpoints) && (NEpoints > 0) )
176     {
177         int i = 0;
178         NamesOfFunctions = (char **) MALLOC((NEpoints)*sizeof(char *));
179         if(NamesOfFunctions)
180         {
181             for ( i = NEpoints-1 ; i >= 0 ; i--) 
182             {
183                 if(EP[i].name)
184                 {
185                     char *EntryName = (char *)MALLOC(((int)strlen(EP[i].name)+1)*sizeof(char));
186
187                     if(EntryName)
188                     {
189                         (*sizearray)++;
190                         strcpy(EntryName , EP[i].name);
191                         NamesOfFunctions[(*sizearray)-1] = EntryName;
192                     }
193                 }
194             }
195         }
196     }
197     return NamesOfFunctions;
198 }
199 /*---------------------------------------------------------------------------*/
200 /**
201 * Underscores : deals with the trailing _ 
202 * in entry names 
203 */
204 static void Underscores(BOOL _bFortran, wchar_t* _pwstEntryPointName, wchar_t* _pwstTrailingName)
205 {
206 #ifdef WLU1
207     *_pwstTrailingName = L'_';
208     _pwstTrailingName++;
209 #endif
210     wcscpy(_pwstTrailingName, _pwstEntryPointName);
211 #ifdef WTU
212     if(_bFortran)
213     {
214         wcscat(_pwstTrailingName, L"_");
215     }
216 #endif
217     return;
218 }
219 /*---------------------------------------------------------------------------*/
220 BOOL c_link(char *routinename,int *ilib)
221 {
222     void (*loc)();
223     if( *ilib != -1 ) *ilib = SearchFandS(routinename,*ilib);
224     else *ilib = SearchInDynLinks(routinename,&loc);
225
226     if(*ilib == -1) return FALSE;
227     return TRUE;
228 }
229 /*---------------------------------------------------------------------------*/
230 void C2F(iislink)(char *routinename, int *ilib)
231 {
232     c_link(routinename,ilib);
233 }
234 /*---------------------------------------------------------------------------*/
235 void GetDynFunc(int ii, void (**realop) ())
236 {
237     //if( EP[ii].Nshared != -1 ) *realop = EP[ii].epoint;
238     //else *realop = (function) 0;
239 }
240 /*---------------------------------------------------------------------------*/
241 int SearchInDynLinks(char *op, void (**realop) ())
242 {
243     //int i=0;
244     //for ( i = NEpoints-1 ; i >=0 ; i--) 
245     //{
246     //    if( strcmp(op,EP[i].name) == 0) 
247     //    {
248     //        *realop = EP[i].epoint;
249     //        return(EP[i].Nshared );
250     //    }
251     //}
252     return(-1);
253 }
254 /*---------------------------------------------------------------------------*/
255 /**
256 * Search a (function,libid) in the table 
257 * Search from end to top 
258 */
259 static int SearchFandS(char *op, int ilib)
260 {
261     int i = 0;
262     for ( i = NEpoints-1 ; i >=0 ; i--) 
263     {
264         if( strcmp(op,EP[i].name) == 0 && EP[i].Nshared == ilib)
265         {
266             return(i);
267         }
268     }
269     return(-1);
270 }
271 /*---------------------------------------------------------------------------*/
272 /*---------------------------------------------------------------------------*/
273 void unlinkallsharedlib(void)
274 {
275     int i=0;
276     for ( i = 0 ; i < Nshared ; i++) 
277     {
278         unlinksharedlib(&i);
279     }
280 }
281 /*---------------------------------------------------------------------------*/
282 void unlinksharedlib(int *i) 
283 {
284     /* delete entry points in shared lib *i */
285     Sci_Delsym(*i);
286     /* delete entry points used in addinter in shared lib *i */
287     RemoveInterf(*i);
288 }
289 /*---------------------------------------------------------------------------*/
290 int Sci_dlclose(unsigned long _hLib)
291 {
292 #ifdef _MSC_VER
293         return FreeDynLibrary ((DynLibHandle) ULongToHandle(_hLib));
294 #else
295         return FreeDynLibrary ((DynLibHandle) _hLib);
296 #endif
297 }
298 /*---------------------------------------------------------------------------*/
299 int Sci_dlopen(wchar_t* _pwstDynLibPath)
300 {
301     static DynLibHandle hLib = NULL;
302     int i = 0;
303
304 #ifdef _MSC_VER
305     {
306         hLib = LoadDynLibraryW(_pwstDynLibPath);
307     }
308 #else
309     {
310         char* pstDynLibPath = wide_string_to_UTF8(_pwstDynLibPath);
311         hLib = LoadDynLibrary (pstDynLibPath);
312         FREE(pstDynLibPath);
313     }
314 #endif
315
316     if(hLib == NULL)
317     {
318         return -1 ; /* the shared archive was not loaded. */
319     }
320
321     /* Warning x64 windows */
322
323     ConfigVariable::DynamicLibraryStr* pDL = ConfigVariable::getNewDynamicLibraryStr();
324     ConfigVariable::setLibraryName(pDL, _pwstDynLibPath);
325 #ifdef _MSC_VER
326     pDL->hLib =   PtrToUlong(hLib);
327 #else
328     pDL->hLib = (unsigned long)hLib;
329 #endif
330
331     
332     return ConfigVariable::addDynamicLibrary(pDL);
333 }
334 /*---------------------------------------------------------------------------*/
335 int Sci_dlsym(wchar_t* _pwstEntryPointName, int _iLibID, BOOL _bFortran)
336 {
337     DynLibHandle hDynLib = NULL;
338     ConfigVariable::EntryPointStr* pEP = ConfigVariable::getNewEntryPointStr();
339     //+3 : 1 for '\0', 1 for prefix _, 1 for suffix _
340     wchar_t* pwstEntryPointName = (wchar_t*)MALLOC(sizeof(wchar_t) * (wcslen(_pwstEntryPointName) + 3));
341     memset(pwstEntryPointName, 0x00, (wcslen(_pwstEntryPointName) + 3));
342
343     Underscores(_bFortran, _pwstEntryPointName, pwstEntryPointName);
344
345     
346     if(_iLibID < 0 || ConfigVariable::isDynamicLibrary(_iLibID) == false)
347     {//no valid library at this ID
348         return -3;
349     }
350
351     /** entry was previously loaded **/
352     if(ConfigVariable::getEntryPoint(_pwstEntryPointName, _iLibID) != NULL)
353     {
354         sciprintW(_W("Entry name %ls.\n"), _pwstEntryPointName);
355         return -4;
356     }
357
358     /* Warning x64 windows */
359     pEP->iLibIndex = _iLibID;
360 #ifdef _MSC_VER
361     hDynLib = (DynLibHandle)  ULongToHandle(ConfigVariable::getDynamicLibrary(_iLibID)->hLib);
362 #else
363     hDynLib = (DynLibHandle)  ConfigVariable::getDynamicLibrary(_iLibID)->hLib;
364 #endif
365 #ifdef _MCS_VER
366     pEP->functionPtr = (function) GetDynLibFuncPtrW(hDynLib, pwstEntryPointName);
367 #else
368     char* pstEntryPointName = wide_string_to_UTF8(pwstEntryPointName);
369     pEP->functionPtr = (function) GetDynLibFuncPtr(hDynLib, pstEntryPointName);
370     FREE(pstEntryPointName);
371 #endif    
372     if(pEP->functionPtr == NULL)
373     {
374         if(getIlibVerboseLevel() != ILIB_VERBOSE_NO_OUTPUT)
375         {
376             sciprintW(_W("%ls is not an entry point.\n"), _pwstEntryPointName);
377         }
378         return -5;
379     }
380
381     /* we don't add the _ in the table */
382     if(debug)
383     {
384         sciprintW(_W("Linking %ls.\n"), _pwstEntryPointName);
385     }
386
387     ConfigVariable::setEntryPointName(pEP, _pwstEntryPointName);
388     ConfigVariable::addEntryPoint(pEP);
389     FREE(pwstEntryPointName);
390     return 0;  
391 }
392 /*---------------------------------------------------------------------------*/
393 void Sci_Delsym(int ishared) 
394 {
395     int ish = Min(Max(0,ishared),ENTRYMAX-1);
396     int i=0;
397     for ( i = NEpoints-1 ; i >=0 ; i--) 
398     {
399         if( EP[i].Nshared == ish )
400         {
401             int j;
402             for ( j = i ; j <= NEpoints - 2 ; j++ )
403             {
404                 EP[j].epoint = EP[j+1].epoint;
405                 EP[j].Nshared = EP[j+1].Nshared;
406                 strcpy(EP[j].name,EP[j+1].name);
407             }
408             NEpoints--;
409         }
410     }
411     if( hd[ish].ok != FALSE)
412     {
413         /* Warning x64 windows */
414 #ifdef _MSC_VER
415         FreeDynLibrary ((DynLibHandle) ULongToHandle(hd[ish].shl));
416 #else
417         FreeDynLibrary ((DynLibHandle) hd[ish].shl);
418 #endif
419         hd[ish].ok = FALSE;
420     }
421 }
422 /*---------------------------------------------------------------------------*/