5b2b46e849fad55d2c0230a0110e233d065e273e
[scilab.git] / scilab / modules / dynamic_link / src / c / dynamic_link.c
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.1-en.txt
11 *
12 */
13
14 /*---------------------------------------------------------------------------*/
15 #include <string.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include "dynamic_link.h"
19 #include "dynamiclibrary.h"
20 #include "men_Sutils.h"
21 #include "MALLOC.h" /* MALLOC */
22 #include "warningmode.h"
23 #include "sciprint.h"
24 #include "stack-c.h"
25 #include "addinter.h"
26 #include "localization.h"
27 #include "Scierror.h"
28 #include "FileExist.h"
29 #include "ilib_verbose.h"
30 #ifdef _MSC_VER
31 #include "getenvc.h"
32 #include "dllinfo.h"
33 #endif
34 #include "getshortpathname.h"
35 #include "BOOL.h"
36 #include "charEncoding.h"
37 /*---------------------------------------------------------------------------*/
38 static void Underscores(int isfor, char *ename, char *ename1);
39 static int SearchFandS(char *op, int ilib);
40 /*---------------------------------------------------------------------------*/
41 #define MAXNAME  256
42 #define TMPL 256
43 #define debug C2F(iop).ddt==1
44 /*---------------------------------------------------------------------------*/
45 #ifdef _MSC_VER
46 /* struct used by fortran (F2C) */
47 /* required to be defined in C */
48
49 typedef struct
50 {
51     char name[nlgh + 1];
52 } CINTER_struct;
53
54 __declspec (dllexport) CINTER_struct C2F(cinter);
55
56 /* struct used by fortran (F2C) */
57 /* required to be defined in C */
58 typedef struct
59 {
60     int ibuf[lsiz];
61 } IBFU_struct;
62 __declspec (dllexport) CINTER_struct C2F(ibfu);
63
64 #endif
65 /*---------------------------------------------------------------------------*/
66 typedef char Name[MAXNAME];   /* could be changed to dynamic structure */
67
68 typedef void (*function) ();
69
70 typedef struct
71 {
72     function epoint;            /* the entry point */
73     Name     name;              /* entry point name */
74     int      Nshared;           /* number of the shared file */
75 } Epoints;
76
77 typedef struct
78 {
79     int ok;
80     char tmp_file[TMPL];
81     unsigned long long  shl;
82 } Hd;
83
84 static Hd  hd[ENTRYMAX]; /* shared libs handler */
85 static int Nshared = 0;
86 static int NEpoints = 0; /* Number of Linked names */
87 static Epoints EP[ENTRYMAX];  /* entryPoints */
88 /*---------------------------------------------------------------------------*/
89 int scilabLink(int idsharedlibrary,
90                char *filename,
91                char **subnamesarray, int sizesubnamesarray,
92                BOOL fflag, int *ierr)
93 {
94     int IdSharedLib = -1;
95
96     initializeLink();
97
98     if (idsharedlibrary == -1)
99     {
100         IdSharedLib = Sci_dlopen(filename);
101     }
102     else
103     {
104         IdSharedLib = idsharedlibrary;
105     }
106
107     if (IdSharedLib == -1 )
108     {
109         if ( getWarningMode() )
110         {
111 #ifdef _MSC_VER
112             if (isDll(filename))
113             {
114 #ifdef _WIN64
115                 if (isX86Dll(filename))
116                 {
117                     if (getIlibVerboseLevel() != ILIB_VERBOSE_NO_OUTPUT)
118                     {
119                         sciprint(_("%s: can not to load a x86 dll in a x64 environment.\n" ), "link");
120                     }
121                     SetLastError(ERROR_DLL_INIT_FAILED);
122                 }
123 #else
124                 if (isX64Dll(filename))
125                 {
126                     if (getIlibVerboseLevel() != ILIB_VERBOSE_NO_OUTPUT)
127                     {
128                         sciprint(_("%s: can not load a x64 dll in a x86 environment.\n" ), "link");
129                     }
130                     SetLastError(ERROR_DLL_INIT_FAILED);
131                 }
132 #endif
133             }
134             else
135             {
136                 char *pathSearch = searchEnv(filename, "PATH");
137                 if (pathSearch == NULL)
138                 {
139                     if (getIlibVerboseLevel() != ILIB_VERBOSE_NO_OUTPUT)
140                     {
141                         sciprint(_("%s: The file %s does not exist in PATH environment.\n" ), "link", filename);
142                     }
143                 }
144             }
145 #else
146             if (getIlibVerboseLevel() != ILIB_VERBOSE_NO_OUTPUT)
147             {
148                 sciprint(_("Link failed for dynamic library '%s'.\n"), filename);
149                 sciprint(_("An error occurred: %s\n"), GetLastDynLibError());
150             }
151 #endif
152         }
153         *ierr = -1;
154         return IdSharedLib;
155     }
156
157     if ( (idsharedlibrary == -1) && (getIlibVerboseLevel() != ILIB_VERBOSE_NO_OUTPUT))
158     {
159         sciprint(_("Shared archive loaded.\n"));
160         sciprint(_("Link done.\n"));
161     }
162
163     if (sizesubnamesarray > 0)
164     {
165         int errorcode = 0;
166         int i = 0;
167         for (i = 0; i < sizesubnamesarray ; i++)
168         {
169             if (fflag)
170             {
171                 errorcode = Sci_dlsym(subnamesarray[i], IdSharedLib, "f");
172             }
173             else
174             {
175                 errorcode = Sci_dlsym(subnamesarray[i], IdSharedLib, "c");
176             }
177
178             if (errorcode < 0)
179             {
180                 *ierr = errorcode;
181             }
182         }
183     }
184     return IdSharedLib;
185 }
186 /*---------------------------------------------------------------------------*/
187 int *getAllIdSharedLib(int *sizeList)
188 {
189     int *ListId = NULL;
190     int i = 0;
191
192     *sizeList = 0;
193     for ( i = 0 ; i < Nshared ; i++)
194     {
195         if ( hd[i].ok == TRUE)
196         {
197             (*sizeList)++;
198             if (ListId)
199             {
200                 ListId = (int *)REALLOC(ListId, (*sizeList) * sizeof(int));
201                 ListId[(*sizeList) - 1] = i;
202             }
203             else
204             {
205                 ListId = (int *)MALLOC((*sizeList) * sizeof(int));
206                 ListId[(*sizeList) - 1] = i;
207             }
208         }
209     }
210     return ListId;
211 }
212 /*---------------------------------------------------------------------------*/
213 char **getNamesOfFunctionsInSharedLibraries(int *sizearray)
214 {
215     char **NamesOfFunctions = NULL;
216     *sizearray = 0;
217
218     if ( (NEpoints) && (NEpoints > 0) )
219     {
220         int i = 0;
221         NamesOfFunctions = (char **) MALLOC((NEpoints) * sizeof(char *));
222         if (NamesOfFunctions)
223         {
224             for ( i = NEpoints - 1 ; i >= 0 ; i--)
225             {
226                 if (EP[i].name)
227                 {
228                     char *EntryName = (char *)MALLOC(((int)strlen(EP[i].name) + 1) * sizeof(char));
229
230                     if (EntryName)
231                     {
232                         (*sizearray)++;
233                         strcpy(EntryName , EP[i].name);
234                         NamesOfFunctions[(*sizearray) - 1] = EntryName;
235                     }
236                 }
237             }
238         }
239     }
240     return NamesOfFunctions;
241 }
242 /*---------------------------------------------------------------------------*/
243 /**
244 * Underscores : deals with the trailing _
245 * in entry names
246 */
247 static void Underscores(int isfor, char *ename, char *ename1)
248 {
249 #ifdef WLU1
250     *ename1 = '_';
251     ename1++;
252 #endif
253     strcpy(ename1, ename);
254 #ifdef WTU
255     if (isfor == 1)
256     {
257         strcat(ename1, "_");
258     }
259 #endif
260     return;
261 }
262 /*---------------------------------------------------------------------------*/
263 void initializeLink(void)
264 {
265     static int first_entry = 0;
266     int i;
267     if ( first_entry == 0)
268     {
269         for ( i = 0 ; i < ENTRYMAX ; i++)
270         {
271             hd[i].ok = FALSE;
272             hd[i].shl = EP[i].Nshared = -1;
273         }
274         first_entry++;
275     }
276 }
277 /*---------------------------------------------------------------------------*/
278 BOOL c_link(char *routinename, int *ilib)
279 {
280     void (*loc)();
281     if ( *ilib != -1 )
282     {
283         *ilib = SearchFandS(routinename, *ilib);
284     }
285     else
286     {
287         *ilib = SearchInDynLinks(routinename, &loc);
288     }
289
290     if (*ilib == -1)
291     {
292         return FALSE;
293     }
294     return TRUE;
295 }
296 /*---------------------------------------------------------------------------*/
297 void C2F(iislink)(char *routinename, int *ilib)
298 {
299     c_link(routinename, ilib);
300 }
301 /*---------------------------------------------------------------------------*/
302 void GetDynFunc(int ii, void (**realop) ())
303 {
304     if ( EP[ii].Nshared != -1 )
305     {
306         *realop = EP[ii].epoint;
307     }
308     else
309     {
310         *realop = (function) 0;
311     }
312 }
313 /*---------------------------------------------------------------------------*/
314 int SearchInDynLinks(char *op, void (**realop) ())
315 {
316     int i = 0;
317     for ( i = NEpoints - 1 ; i >= 0 ; i--)
318     {
319         if ( strcmp(op, EP[i].name) == 0)
320         {
321             *realop = EP[i].epoint;
322             return(EP[i].Nshared );
323         }
324     }
325     return(-1);
326 }
327 /*---------------------------------------------------------------------------*/
328 /**
329 * Search a (function,libid) in the table
330 * Search from end to top
331 */
332 static int SearchFandS(char *op, int ilib)
333 {
334     int i = 0;
335     for ( i = NEpoints - 1 ; i >= 0 ; i--)
336     {
337         if ( strcmp(op, EP[i].name) == 0 && EP[i].Nshared == ilib)
338         {
339             return(i);
340         }
341     }
342     return(-1);
343 }
344 /*---------------------------------------------------------------------------*/
345 void ShowDynLinks(void)
346 {
347     int i = 0, count = 0;
348     if (getIlibVerboseLevel() != ILIB_VERBOSE_NO_OUTPUT)
349     {
350         sciprint(_("Number of entry points %d.\nShared libraries :\n"), NEpoints);
351     }
352     if (getIlibVerboseLevel() != ILIB_VERBOSE_NO_OUTPUT)
353     {
354         sciprint("[ ");
355     }
356     for ( i = 0 ; i < Nshared ; i++)
357     {
358         if ( hd[i].ok == TRUE)
359         {
360             if (getIlibVerboseLevel() != ILIB_VERBOSE_NO_OUTPUT)
361             {
362                 sciprint("%d ", i);
363                 count++;
364             }
365         }
366     }
367
368     if (getIlibVerboseLevel() != ILIB_VERBOSE_NO_OUTPUT)
369     {
370         if ( (count == 1) || (count == 0) )
371         {
372             sciprint(_("] : %d library.\n"), count);
373         }
374         else
375         {
376             sciprint(_("] : %d libraries.\n"), count);
377         }
378     }
379
380     for ( i = NEpoints - 1 ; i >= 0 ; i--)
381     {
382         if (getIlibVerboseLevel() != ILIB_VERBOSE_NO_OUTPUT)
383         {
384             sciprint(_("Entry point %s in shared library %d.\n"), EP[i].name, EP[i].Nshared);
385         }
386     }
387 }
388 /*---------------------------------------------------------------------------*/
389 void unlinkallsharedlib(void)
390 {
391     int i = 0;
392     for ( i = 0 ; i < Nshared ; i++)
393     {
394         unlinksharedlib(&i);
395     }
396 }
397 /*---------------------------------------------------------------------------*/
398 void unlinksharedlib(int *i)
399 {
400     /* delete entry points in shared lib *i */
401     Sci_Delsym(*i);
402     /* delete entry points used in addinter in shared lib *i */
403     RemoveInterf(*i);
404 }
405 /*---------------------------------------------------------------------------*/
406 int Sci_dlopen( char *loaded_file)
407 {
408     static DynLibHandle  hd1 = NULL;
409     int i = 0;
410
411
412 #ifdef _MSC_VER
413     {
414         wchar_t *wcfilename = to_wide_string(loaded_file);
415         if (wcfilename)
416         {
417             hd1 = LoadDynLibraryW(wcfilename);
418             FREE(wcfilename);
419             wcfilename = NULL;
420         }
421     }
422 #else
423     hd1 = LoadDynLibrary (loaded_file);
424 #endif
425
426     if ( hd1 == NULL )
427     {
428         return -1 ;    /* the shared archive was not loaded. */
429     }
430
431     for ( i = 0 ; i < Nshared ; i++ )
432     {
433         if ( hd[i].ok == FALSE)
434         {
435             hd[i].shl =  (unsigned long long)hd1;
436             hd[i].ok = TRUE;
437             return(i);
438         }
439     }
440
441     if ( Nshared == ENTRYMAX )
442     {
443         if (getIlibVerboseLevel() != ILIB_VERBOSE_NO_OUTPUT)
444         {
445             sciprint(_("Cannot open shared files max entry %d reached.\n"), ENTRYMAX);
446         }
447         return(FALSE);
448     }
449
450     hd[Nshared].shl = (unsigned long long)hd1;
451     hd[Nshared].ok = TRUE;
452     Nshared ++;
453
454     return Nshared - 1;
455 }
456 /*---------------------------------------------------------------------------*/
457 int Sci_dlsym(char *ename, int ishared, char *strf)
458 {
459     DynLibHandle hd1 = NULL;
460     int ish = Min(Max(0, ishared), ENTRYMAX - 1);
461     char enamebuf[MAXNAME];
462
463     if ( strf[0] == 'f' )
464     {
465         Underscores(1, ename, enamebuf);
466     }
467     else
468     {
469         Underscores(0, ename, enamebuf);
470     }
471
472     /* lookup the address of the function to be called */
473     if ( NEpoints == ENTRYMAX )
474     {
475         return -1;
476     }
477     if ( hd[ish].ok == FALSE )
478     {
479         return -3;
480     }
481     /** entry was previously loaded **/
482     if ( SearchFandS(ename, ish) >= 0 )
483     {
484         sciprint(_("Entry name %s.\n"), ename);
485         return -4;
486     }
487     else
488     {
489         hd1 = (DynLibHandle)hd[ish].shl;
490         EP[NEpoints].epoint = (function) GetDynLibFuncPtr (hd1, enamebuf);
491         if ( EP[NEpoints].epoint == NULL )
492         {
493             if (getIlibVerboseLevel() != ILIB_VERBOSE_NO_OUTPUT)
494             {
495                 sciprint(_("%s is not an entry point.\n"), enamebuf);
496             }
497             return -5;
498         }
499         else
500         {
501             /* we don't add the _ in the table */
502             if (debug)
503             {
504                 sciprint(_("Linking %s.\n"), ename);
505             }
506             strncpy(EP[NEpoints].name, ename, MAXNAME);
507             EP[NEpoints].Nshared = ish;
508             NEpoints++;
509         }
510     }
511     return 0;
512 }
513 /*---------------------------------------------------------------------------*/
514 void Sci_Delsym(int ishared)
515 {
516     int ish = Min(Max(0, ishared), ENTRYMAX - 1);
517     int i = 0;
518     for ( i = NEpoints - 1 ; i >= 0 ; i--)
519     {
520         if ( EP[i].Nshared == ish )
521         {
522             int j;
523             for ( j = i ; j <= NEpoints - 2 ; j++ )
524             {
525                 EP[j].epoint = EP[j + 1].epoint;
526                 EP[j].Nshared = EP[j + 1].Nshared;
527                 strcpy(EP[j].name, EP[j + 1].name);
528             }
529             NEpoints--;
530         }
531     }
532     if ( hd[ish].ok != FALSE)
533     {
534         FreeDynLibrary ((DynLibHandle)hd[ish].shl);
535         hd[ish].ok = FALSE;
536     }
537 }
538 /*---------------------------------------------------------------------------*/