-
Notifications
You must be signed in to change notification settings - Fork 25
/
Rdynload.c
1445 lines (1232 loc) · 40.6 KB
/
Rdynload.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* R : A Computer Language for Statistical Data Analysis
* Copyright (C) 1995-1996 Robert Gentleman and Ross Ihaka
* Copyright (C) 1997-2015 The R Core Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, a copy is available at
* http://www.r-project.org/Licenses/
*/
/*
This is an effort to merge the 3 different dynload.c files in the
distribution from the unix/, macintosh/dll/ and gnuwin32/ directories.
The aim is to consolidate these different implementations into
i) a generic or platform-independent common core
ii) platform-dependent routines that are registered
as function pointers.
The reason for using function pointers rather than explicit
linking of symbols is
a) to avoid confusion in the linking
b) to allow for easily overriding these in embedded applications
in which a host application needs to control how R finds
symbols. This may be necessary for security reasons.
*/
/* Dynamic Loading Support
*
* This module provides support for run-time loading of shared objects
* access to symbols within such objects via .C and .Fortran. This is
* done under Unix with dlopen, dlclose and dlsym (the exception is
* hpux, where we use compatibility code provided by Luke Tierney).
* There are two cases:
*
*
* 1. The dlopen interface is available.
*
* In this case all symbol location in packages is done using the
* dlopen routines. We maintain a list of currently loaded shared
* objects in an array called "LoadedDLL" with the number of currently
* loaded objects being "CountDLL". To locate a symbol, we probe
* the loaded objects in order until the symbol is located. If we
* do not find a symbol in the loaded objects, we search the
* executable itself. This search is not very efficient, but this
* probably pales into insignificance when compared with the
* inefficiencies in the R interpreter.
*
* Loading and unloading of shared objects is done via the routines
* AddDLL and DeleteDLL. These routines maintain the list of
* currently loaded objects. When an object is added, any existing
* reference to that object is deleted and then the object is
* inserted at the start of the search list. This way, symbols in
* more recently loaded objects are found first.
*
*
* Accessing native routines in base (the R executable).
*
* In this case, we use the registration mechanism and the DllInfo array
* in ../main/Rdynload.c to locate functions in the executable. We do this
* by straight linear search through the table.
* Note that the base routines registered are listed in
* ../main/registration.c
* and are registered during the initialization of the R engine.
* (This replaces the previous mechanism that built a table
* from ../appl/ROUTINES using Perl/sed).
*
*
* If speed is ever an issue in the lookup of registered symbols, we can
* store the registered routines in a hashtable or binary tree as they
* are being registered.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <Defn.h>
#include <Internal.h>
#include <string.h>
#include <stdlib.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <Rmath.h>
#include <Rdynpriv.h>
#ifdef Unix
/* HP-UX 11.0 has dlfcn.h, but according to libtool as of Dec 2001
this support is broken. So we force use of shlib even when dlfcn.h
is available */
# ifdef __hpux
# ifdef HAVE_DL_H
# define HAVE_DYNAMIC_LOADING
# endif
# else
# ifdef HAVE_DLFCN_H
# define HAVE_DYNAMIC_LOADING
# endif
# endif /* __hpux */
# ifndef HAVE_NO_SYMBOL_UNDERSCORE
# ifdef HAVE_ELF_H
# define HAVE_NO_SYMBOL_UNDERSCORE
# endif /* HAVE_ELF_H */
# endif /* HAVE_NO_SYMBOL_UNDERSCORE */
#endif
#ifdef Win32
# define HAVE_DYNAMIC_LOADING
#endif
#ifdef CACHE_DLL_SYM /* Used on Windows */
#define MAX_CACHE 100
/* keep a record of symbols that have been found, about 70 bytes each */
R_CPFun CPFun[MAX_CACHE];
int nCPFun = 0;
#endif
#define MAX_NUM_DLLS 100
static int CountDLL = 0;
#include <R_ext/Rdynload.h>
static DllInfo LoadedDLL[MAX_NUM_DLLS];
static int addDLL(char *dpath, char *name, HINSTANCE handle);
static SEXP Rf_MakeDLLInfo(DllInfo *info);
static SEXP createRSymbolObject(SEXP sname, DL_FUNC f,
R_RegisteredNativeSymbol *symbol,
Rboolean withRegistrationInfo);
static DllInfo *R_RegisterDLL(HINSTANCE handle, const char *path);
attribute_hidden OSDynSymbol Rf_osDynSymbol;
attribute_hidden OSDynSymbol *R_osDynSymbol = &Rf_osDynSymbol;
void R_init_base(DllInfo *); /* In Registration.c */
DL_FUNC R_dlsym(DllInfo *dll, char const *name,
R_RegisteredNativeSymbol *symbol);
void attribute_hidden
InitDynload()
{
DllInfo *dll;
int which = addDLL(strdup("base"), "base", NULL);
dll = &LoadedDLL[which];
R_init_base(dll);
InitFunctionHashing();
}
/* returns DllInfo used by the embedding application.
the underlying "(embedding)" entry is created if not present */
DllInfo *R_getEmbeddingDllInfo()
{
DllInfo *dll = R_getDllInfo("(embedding)");
if (dll == NULL) {
int which = addDLL(strdup("(embedding)"), "(embedding)", NULL);
dll = &LoadedDLL[which];
/* make sure we don't attempt dynamic lookup */
R_useDynamicSymbols(dll, FALSE);
}
return dll;
}
Rboolean R_useDynamicSymbols(DllInfo *info, Rboolean value)
{
Rboolean old;
old = info->useDynamicLookup;
info->useDynamicLookup = value;
return old;
}
Rboolean R_forceSymbols(DllInfo *info, Rboolean value)
{
Rboolean old;
old = info->forceSymbols;
info->forceSymbols = value;
return old;
}
static void
R_addCRoutine(DllInfo *info, const R_CMethodDef * const croutine,
Rf_DotCSymbol *sym);
static void
R_addCallRoutine(DllInfo *info,
const R_CallMethodDef * const croutine,
Rf_DotCallSymbol *sym);
static void
R_addFortranRoutine(DllInfo *info,
const R_FortranMethodDef * const croutine,
Rf_DotFortranSymbol *sym);
static void
R_addExternalRoutine(DllInfo *info,
const R_ExternalMethodDef * const croutine,
Rf_DotExternalSymbol *sym);
/*
Returns a reference to the DllInfo object associated with the shared object
with the path name `path'. This ensures uniqueness rather than having the
undesirable situation of two object with the same name but in different
directories.
This is available so that it can be called from arbitrary C routines
that need to call R_registerRoutines(). The initialization routine
R_init_<object name> is passed the DllInfo reference as an argument.
Other routines must explicitly request it using this routine.
*/
DllInfo *
R_getDllInfo(const char *path)
{
int i;
for(i = 0; i < CountDLL; i++) {
if(strcmp(LoadedDLL[i].path, path) == 0) return(&LoadedDLL[i]);
}
return (DllInfo*) NULL;
}
/*
Explicitly register the native routines for use in .Call(), .C() and
.Fortran() functions. These registered values are used to resolve
symbols in an object that makes a call to this routine, rather than
the usual dynamic resolution done by dlsym() or the equivalent on
the different platforms.
*/
int
R_registerRoutines(DllInfo *info, const R_CMethodDef * const croutines,
const R_CallMethodDef * const callRoutines,
const R_FortranMethodDef * const fortranRoutines,
const R_ExternalMethodDef * const externalRoutines)
{
int i, num;
if(info == NULL)
error(_("R_RegisterRoutines called with invalid DllInfo object."));
/* Default is to look in registered and then dynamic (unless
the is no handle such as in "base" or "embedded")
Potentially change in the future to be only registered
if there are any registered values.
*/
info->useDynamicLookup = (info->handle) ? TRUE : FALSE;
info->forceSymbols = FALSE;
if(croutines) {
for(num = 0; croutines[num].name != NULL; num++) {;}
info->CSymbols = (Rf_DotCSymbol*)calloc((size_t) num,
sizeof(Rf_DotCSymbol));
info->numCSymbols = num;
for(i = 0; i < num; i++) {
R_addCRoutine(info, croutines+i, info->CSymbols + i);
}
}
if(fortranRoutines) {
for(num = 0; fortranRoutines[num].name != NULL; num++) {;}
info->FortranSymbols =
(Rf_DotFortranSymbol*)calloc((size_t) num,
sizeof(Rf_DotFortranSymbol));
info->numFortranSymbols = num;
for(i = 0; i < num; i++)
R_addFortranRoutine(info, fortranRoutines+i,
info->FortranSymbols + i);
}
if(callRoutines) {
for(num = 0; callRoutines[num].name != NULL; num++) {;}
info->CallSymbols =
(Rf_DotCallSymbol*)calloc((size_t) num, sizeof(Rf_DotCallSymbol));
info->numCallSymbols = num;
for(i = 0; i < num; i++)
R_addCallRoutine(info, callRoutines+i, info->CallSymbols + i);
}
if(externalRoutines) {
for(num = 0; externalRoutines[num].name != NULL; num++) {;}
info->ExternalSymbols =
(Rf_DotExternalSymbol*)calloc((size_t) num,
sizeof(Rf_DotExternalSymbol));
info->numExternalSymbols = num;
for(i = 0; i < num; i++)
R_addExternalRoutine(info, externalRoutines+i,
info->ExternalSymbols + i);
}
return(1);
}
static void
R_setPrimitiveArgTypes(const R_FortranMethodDef * const croutine,
Rf_DotFortranSymbol *sym)
{
sym->types = (R_NativePrimitiveArgType *)
malloc(sizeof(R_NativePrimitiveArgType) * (size_t) croutine->numArgs);
if(!sym->types)
error("allocation failure in R_setPrimitiveArgTypes");
if(sym->types)
memcpy(sym->types, croutine->types,
sizeof(R_NativePrimitiveArgType) * (size_t) croutine->numArgs);
}
static void
R_setArgStyles(const R_FortranMethodDef * const croutine,
Rf_DotFortranSymbol *sym)
{
sym->styles = (R_NativeArgStyle *)
malloc(sizeof(R_NativeArgStyle) * (size_t) croutine->numArgs);
if(!sym->styles)
error("allocation failure in R_setArgStyles");
if(sym->styles)
memcpy(sym->styles, croutine->styles,
sizeof(R_NativeArgStyle) * (size_t) croutine->numArgs);
}
static void
R_addFortranRoutine(DllInfo *info,
const R_FortranMethodDef * const croutine,
Rf_DotFortranSymbol *sym)
{
sym->name = strdup(croutine->name);
sym->fun = croutine->fun;
sym->numArgs = croutine->numArgs > -1 ? croutine->numArgs : -1;
if(croutine->types)
R_setPrimitiveArgTypes(croutine, sym);
if(croutine->styles)
R_setArgStyles(croutine, sym);
}
static void
R_addExternalRoutine(DllInfo *info,
const R_ExternalMethodDef * const croutine,
Rf_DotExternalSymbol *sym)
{
sym->name = strdup(croutine->name);
sym->fun = croutine->fun;
sym->numArgs = croutine->numArgs > -1 ? croutine->numArgs : -1;
}
static void
R_addCRoutine(DllInfo *info, const R_CMethodDef * const croutine,
Rf_DotCSymbol *sym)
{
sym->name = strdup(croutine->name);
sym->fun = croutine->fun;
sym->numArgs = croutine->numArgs > -1 ? croutine->numArgs : -1;
if(croutine->types)
R_setPrimitiveArgTypes(croutine, sym);
if(croutine->styles)
R_setArgStyles(croutine, sym);
}
static void
R_addCallRoutine(DllInfo *info, const R_CallMethodDef * const croutine,
Rf_DotCallSymbol *sym)
{
sym->name = strdup(croutine->name);
sym->fun = croutine->fun;
sym->numArgs = croutine->numArgs > -1 ? croutine->numArgs : -1;
}
static void
Rf_freeCSymbol(Rf_DotCSymbol *sym)
{
free(sym->name);
}
static void
Rf_freeCallSymbol(Rf_DotCallSymbol *sym)
{
free(sym->name);
}
static void
Rf_freeExternalSymbol(Rf_DotCallSymbol *sym)
{
free(sym->name);
}
static void
Rf_freeFortranSymbol(Rf_DotFortranSymbol *sym)
{
free(sym->name);
}
static void
Rf_freeDllInfo(DllInfo *info)
{
int i;
free(info->name);
free(info->path);
if(info->CSymbols) {
for(i = 0; i < info->numCSymbols; i++)
Rf_freeCSymbol(info->CSymbols+i);
free(info->CSymbols);
}
if(info->CallSymbols) {
for(i = 0; i < info->numCallSymbols; i++)
Rf_freeCallSymbol(info->CallSymbols+i);
free(info->CallSymbols);
}
if(info->ExternalSymbols) {
for(i = 0; i < info->numExternalSymbols; i++)
Rf_freeExternalSymbol(info->ExternalSymbols+i);
free(info->ExternalSymbols);
}
if(info->FortranSymbols) {
for(i = 0; i < info->numFortranSymbols; i++)
Rf_freeFortranSymbol(info->FortranSymbols+i);
free(info->FortranSymbols);
}
}
typedef void (*DllInfoUnloadCall)(DllInfo *);
typedef DllInfoUnloadCall DllInfoInitCall;
static Rboolean
R_callDLLUnload(DllInfo *dllInfo)
{
char buf[1024];
DllInfoUnloadCall f;
R_RegisteredNativeSymbol symbol;
symbol.type = R_ANY_SYM;
snprintf(buf, 1024, "R_unload_%s", dllInfo->name);
f = (DllInfoUnloadCall) R_dlsym(dllInfo, buf, &symbol);
if(f) f(dllInfo);
return(TRUE);
}
/* Remove the specified DLL from the current DLL list */
/* Returns 1 if the DLL was found and removed from */
/* the list and returns 0 otherwise. */
static int DeleteDLL(const char *path)
{
int i, loc;
for (i = 0; i < CountDLL; i++) {
if (!strcmp(path, LoadedDLL[i].path)) {
loc = i;
goto found;
}
}
return 0;
found:
#ifdef CACHE_DLL_SYM
if(R_osDynSymbol->deleteCachedSymbols)
R_osDynSymbol->deleteCachedSymbols(&LoadedDLL[loc]);
#endif
R_callDLLUnload(&LoadedDLL[loc]);
R_osDynSymbol->closeLibrary(LoadedDLL[loc].handle);
Rf_freeDllInfo(LoadedDLL+loc);
/* FIXME: why not use memcpy here? */
for(i = loc + 1 ; i < CountDLL ; i++) {
LoadedDLL[i - 1].path = LoadedDLL[i].path;
LoadedDLL[i - 1].name = LoadedDLL[i].name;
LoadedDLL[i - 1].handle = LoadedDLL[i].handle;
LoadedDLL[i - 1].useDynamicLookup = LoadedDLL[i].useDynamicLookup;
LoadedDLL[i - 1].numCSymbols = LoadedDLL[i].numCSymbols;
LoadedDLL[i - 1].numCallSymbols = LoadedDLL[i].numCallSymbols;
LoadedDLL[i - 1].numFortranSymbols = LoadedDLL[i].numFortranSymbols;
LoadedDLL[i - 1].numExternalSymbols = LoadedDLL[i].numExternalSymbols;
LoadedDLL[i - 1].CSymbols = LoadedDLL[i].CSymbols;
LoadedDLL[i - 1].CallSymbols = LoadedDLL[i].CallSymbols;
LoadedDLL[i - 1].FortranSymbols = LoadedDLL[i].FortranSymbols;
LoadedDLL[i - 1].ExternalSymbols = LoadedDLL[i].ExternalSymbols;
LoadedDLL[i - 1].forceSymbols = LoadedDLL[i].forceSymbols;
}
CountDLL--;
return 1;
}
attribute_hidden
DL_FUNC Rf_lookupCachedSymbol(const char *name, const char *pkg, int all)
{
#ifdef CACHE_DLL_SYM
int i;
for (i = 0; i < nCPFun; i++)
if (!strcmp(name, CPFun[i].name) &&
(all || !strcmp(pkg, CPFun[i].pkg)))
return CPFun[i].func;
#endif
return((DL_FUNC) NULL);
}
#ifdef Win32
#define DLLerrBUFSIZE 4000
#else /* Not Windows */
#define DLLerrBUFSIZE 1000
#endif
static char DLLerror[DLLerrBUFSIZE] = "";
/* the error message; length taken from ERRBUFSIZE in ./hpdlfcn.c */
/* Inserts the specified DLL at the head of the DLL list */
/* Returns 1 if the DLL was successfully added */
/* and returns 0 if the DLL table is full or */
/* or if dlopen fails for some reason. */
static DllInfo* AddDLL(const char *path, int asLocal, int now,
const char *DLLsearchpath)
{
HINSTANCE handle;
DllInfo *info = NULL;
DeleteDLL(path);
if(CountDLL == MAX_NUM_DLLS) {
strcpy(DLLerror, _("`maximal number of DLLs reached..."));
return NULL;
}
handle = R_osDynSymbol->loadLibrary(path, asLocal, now, DLLsearchpath);
if(handle == NULL) {
R_osDynSymbol->getError(DLLerror, DLLerrBUFSIZE);
return NULL;
}
info = R_RegisterDLL(handle, path);
/* Now look for an initializing routine named R_init_<object name>.
If it is present, we call it. It should take a reference to the
DllInfo object currently being initialized.
*/
if(info) {
const char *nm = info->name;
size_t len = strlen(nm) + 9;
char tmp[len]; // R_init_ + underscore + null
DllInfoInitCall f;
#ifdef HAVE_NO_SYMBOL_UNDERSCORE
snprintf(tmp, len, "%s%s","R_init_", info->name);
#else
snprintf(tmp, len, "_%s%s","R_init_", info->name);
#endif
f = (DllInfoInitCall) R_osDynSymbol->dlsym(info, tmp);
/* If that failed, might have used the package name with
. replaced by _ (as . it not valid in symbol names). */
if(!f) {
/* This is potentially unsafe in MBCSs, as '.' might be
part of a character: but is not in UTF-8 */
for(char *p = tmp; *p; p++) if(*p == '.') *p = '_';
f = (DllInfoInitCall) R_osDynSymbol->dlsym(info, tmp);
}
if(f) f(info);
}
return info;
}
static DllInfo *R_RegisterDLL(HINSTANCE handle, const char *path)
{
char *dpath, DLLname[PATH_MAX], *p;
DllInfo *info;
info = &LoadedDLL[CountDLL];
/* default is to use old-style dynamic lookup. The object's
initialization routine can limit access by setting this to FALSE.
*/
info->useDynamicLookup = TRUE;
info->forceSymbols = FALSE;
dpath = (char *) malloc(strlen(path)+1);
if(dpath == NULL) {
strcpy(DLLerror, _("could not allocate space for 'path'"));
R_osDynSymbol->closeLibrary(handle);
return 0;
}
strcpy(dpath, path);
if(R_osDynSymbol->fixPath) R_osDynSymbol->fixPath(dpath);
/* keep only basename from path */
p = Rf_strrchr(dpath, FILESEP[0]);
if(!p) p = dpath; else p++;
if(strlen(p) < PATH_MAX) strcpy(DLLname, p);
else error(_("DLLname '%s' is too long"), p);
/* remove SHLIB_EXT if present */
p = DLLname + strlen(DLLname) - strlen(SHLIB_EXT);
#ifdef Win32 /* case-insensitive file system */
if(p > DLLname && stricmp(p, SHLIB_EXT) == 0) *p = '\0';
#else
if(p > DLLname && strcmp(p, SHLIB_EXT) == 0) *p = '\0';
#endif
addDLL(dpath, DLLname, handle);
return(info);
}
static int
addDLL(char *dpath, char *DLLname, HINSTANCE handle)
{
int ans = CountDLL;
char *name = (char *) malloc(strlen(DLLname)+1);
if(name == NULL) {
strcpy(DLLerror, _("could not allocate space for 'name'"));
if(handle)
R_osDynSymbol->closeLibrary(handle);
free(dpath);
return 0;
}
strcpy(name, DLLname);
LoadedDLL[CountDLL].path = dpath;
LoadedDLL[CountDLL].name = name;
LoadedDLL[CountDLL].handle = handle;
LoadedDLL[CountDLL].numCSymbols = 0;
LoadedDLL[CountDLL].numCallSymbols = 0;
LoadedDLL[CountDLL].numFortranSymbols = 0;
LoadedDLL[CountDLL].numExternalSymbols = 0;
LoadedDLL[CountDLL].CSymbols = NULL;
LoadedDLL[CountDLL].CallSymbols = NULL;
LoadedDLL[CountDLL].FortranSymbols = NULL;
LoadedDLL[CountDLL].ExternalSymbols = NULL;
CountDLL++;
return(ans);
}
static Rf_DotCSymbol *
Rf_lookupRegisteredCSymbol(DllInfo *info, const char *name)
{
for(int i = 0; i < info->numCSymbols; i++) {
if(strcmp(name, info->CSymbols[i].name) == 0)
return(&(info->CSymbols[i]));
}
return NULL;
}
static Rf_DotFortranSymbol *
Rf_lookupRegisteredFortranSymbol(DllInfo *info, const char *name)
{
for(int i = 0; i < info->numFortranSymbols; i++) {
if(strcmp(name, info->FortranSymbols[i].name) == 0)
return(&(info->FortranSymbols[i]));
}
return (Rf_DotFortranSymbol*) NULL;
}
static Rf_DotCallSymbol *
Rf_lookupRegisteredCallSymbol(DllInfo *info, const char *name)
{
for(int i = 0; i < info->numCallSymbols; i++) {
if(strcmp(name, info->CallSymbols[i].name) == 0)
return(&(info->CallSymbols[i]));
}
return (Rf_DotCallSymbol*) NULL;
}
static Rf_DotExternalSymbol *
Rf_lookupRegisteredExternalSymbol(DllInfo *info, const char *name)
{
for(int i = 0; i < info->numExternalSymbols; i++) {
if(strcmp(name, info->ExternalSymbols[i].name) == 0)
return(&(info->ExternalSymbols[i]));
}
return (Rf_DotExternalSymbol*) NULL;
}
static DL_FUNC
R_getDLLRegisteredSymbol(DllInfo *info, const char *name,
R_RegisteredNativeSymbol *symbol)
{
NativeSymbolType purpose = R_ANY_SYM;
if(symbol)
purpose = symbol->type;
if((purpose == R_ANY_SYM || purpose == R_C_SYM) &&
info->numCSymbols > 0) {
Rf_DotCSymbol *sym;
sym = Rf_lookupRegisteredCSymbol(info, name);
if(sym) {
if(symbol) {
symbol->type = R_C_SYM;
symbol->symbol.c = sym;
symbol->dll = info;
}
return((DL_FUNC) sym->fun);
}
}
if((purpose == R_ANY_SYM || purpose == R_CALL_SYM) &&
info->numCallSymbols > 0) {
Rf_DotCallSymbol *sym;
sym = Rf_lookupRegisteredCallSymbol(info, name);
if(sym) {
if(symbol) {
symbol->type = R_CALL_SYM;
symbol->symbol.call = sym;
symbol->dll = info;
}
return((DL_FUNC) sym->fun);
}
}
if((purpose == R_ANY_SYM || purpose == R_FORTRAN_SYM) &&
info->numFortranSymbols > 0) {
Rf_DotFortranSymbol *sym;
sym = Rf_lookupRegisteredFortranSymbol(info, name);
if(sym) {
if(symbol) {
symbol->type = R_FORTRAN_SYM;
symbol->symbol.fortran = sym;
symbol->dll = info;
}
return((DL_FUNC) sym->fun);
}
}
if((purpose == R_ANY_SYM || purpose == R_EXTERNAL_SYM) &&
info->numExternalSymbols > 0) {
Rf_DotExternalSymbol *sym;
sym = Rf_lookupRegisteredExternalSymbol(info, name);
if(sym) {
if(symbol) {
symbol->type = R_EXTERNAL_SYM;
symbol->symbol.external = sym;
symbol->dll = info;
}
return((DL_FUNC) sym->fun);
}
}
return((DL_FUNC) NULL);
}
DL_FUNC attribute_hidden
R_dlsym(DllInfo *info, char const *name,
R_RegisteredNativeSymbol *symbol)
{
size_t len = strlen(name) + 4;
char buf[len]; /* up to 3 additional underscores */
DL_FUNC f;
f = R_getDLLRegisteredSymbol(info, name, symbol);
if(f) return(f);
if(info->useDynamicLookup == FALSE) return(NULL);
#ifdef HAVE_NO_SYMBOL_UNDERSCORE
snprintf(buf, len, "%s", name);
#else
snprintf(buf, len, "_%s", name);
#endif
#ifdef HAVE_F77_UNDERSCORE
if(symbol && symbol->type == R_FORTRAN_SYM) {
strcat(buf, "_");
# ifdef HAVE_F77_EXTRA_UNDERSCORE
if(strchr(name, '_')) strcat(buf, "_");
# endif
}
#endif
f = (DL_FUNC) R_osDynSymbol->dlsym(info, buf);
#ifdef HAVE_F77_UNDERSCORE
if (!f && symbol && symbol->type == R_ANY_SYM) {
strcat(buf, "_");
# ifdef HAVE_F77_EXTRA_UNDERSCORE
if(strchr(name, '_')) strcat(buf, "_");
# endif
f = (DL_FUNC) R_osDynSymbol->dlsym(info, buf);
}
#endif
return f;
}
/* R_FindSymbol checks whether one of the objects that have been
loaded contains the symbol name and returns a pointer to that
symbol upon success.
*/
DL_FUNC R_FindSymbol(char const *name, char const *pkg,
R_RegisteredNativeSymbol *symbol)
{
DL_FUNC fcnptr = (DL_FUNC) NULL;
int i, all = (strlen(pkg) == 0), doit;
if(R_osDynSymbol->lookupCachedSymbol)
fcnptr = R_osDynSymbol->lookupCachedSymbol(name, pkg, all);
if(fcnptr) return(fcnptr);
/* The following is not legal ANSI C. */
/* It is only meant to be used in systems supporting */
/* the dlopen() interface, in which systems data and */
/* function pointers _are_ the same size and _can_ */
/* be cast without loss of information. */
for (i = CountDLL - 1; i >= 0; i--) {
doit = all;
if(!doit && !strcmp(pkg, LoadedDLL[i].name)) doit = 2;
if(doit && LoadedDLL[i].forceSymbols) doit = 0;
if(doit) {
fcnptr = R_dlsym(&LoadedDLL[i], name, symbol); /* R_osDynSymbol->dlsym */
if (fcnptr != (DL_FUNC) NULL) {
if(symbol)
symbol->dll = LoadedDLL+i;
#ifdef CACHE_DLL_SYM
if(strlen(pkg) <= 20 && strlen(name) <= 40 && nCPFun < MAX_CACHE
&& (!symbol || !symbol->symbol.c)) {
strcpy(CPFun[nCPFun].pkg, LoadedDLL[i].name);
strcpy(CPFun[nCPFun].name, name);
CPFun[nCPFun++].func = fcnptr;
}
#endif
return fcnptr;
}
}
if(doit > 1) return (DL_FUNC) NULL; /* Only look in the first-matching DLL */
}
return (DL_FUNC) NULL;
}
static void GetFullDLLPath(SEXP call, char *buf, const char *const path)
{
R_osDynSymbol->getFullDLLPath(call, buf, path);
}
/* do_dynload implements the R-Interface for the */
/* loading of shared objects */
/*
Extended to support 2 additional arguments (3 in total).
First argument is the name of the DLL.
Second argument is a logical indicating whether we
want the symbols to be kept in their own local symbol table
or added to the global symbol table of the application.
Third argument is a logical indicating whether the
dynamic loading should relocate all routine symbols
now and signal any errors immediately or lazily relocate
the symbols as they are invoked. This is useful for
developers so that they can ensure that all the symbols
are available before they release, and allows users to
call routines from "incomplete" DLLs.
*/
SEXP attribute_hidden do_dynload(SEXP call, SEXP op, SEXP args, SEXP env)
{
char buf[2 * PATH_MAX];
DllInfo *info;
checkArity(op,args);
if (!isString(CAR(args)) || LENGTH(CAR(args)) != 1)
error(_("character argument expected"));
GetFullDLLPath(call, buf, translateChar(STRING_ELT(CAR(args), 0)));
/* AddDLL does this DeleteDLL(buf); */
info = AddDLL(buf, LOGICAL(CADR(args))[0], LOGICAL(CADDR(args))[0],
translateChar(STRING_ELT(CADDDR(args), 0)));
if(!info)
error(_("unable to load shared object '%s':\n %s"), buf, DLLerror);
return(Rf_MakeDLLInfo(info));
}
SEXP attribute_hidden do_dynunload(SEXP call, SEXP op, SEXP args, SEXP env)
{
char buf[2 * PATH_MAX];
checkArity(op,args);
if (!isString(CAR(args)) || LENGTH(CAR(args)) != 1)
error(_("character argument expected"));
GetFullDLLPath(call, buf, translateChar(STRING_ELT(CAR(args), 0)));
if(!DeleteDLL(buf))
error(_("shared object '%s\' was not loaded"), buf);
return R_NilValue;
}
int R_moduleCdynload(const char *module, int local, int now)
{
char dllpath[PATH_MAX], *p = getenv("R_HOME");
DllInfo *res;
if(!p) return 0;
#ifdef R_ARCH
snprintf(dllpath, PATH_MAX, "%s%smodules%s%s%s%s%s", p, FILESEP, FILESEP,
R_ARCH, FILESEP, module, SHLIB_EXT);
#else
snprintf(dllpath, PATH_MAX, "%s%smodules%s%s%s", p, FILESEP, FILESEP,
module, SHLIB_EXT);
#endif
res = AddDLL(dllpath, local, now, "");
if(!res)
warning(_("unable to load shared object '%s':\n %s"),
dllpath, DLLerror);
return res != NULL ? 1 : 0;
}
int R_cairoCdynload(int local, int now)
{
char dllpath[PATH_MAX], *p = getenv("R_HOME"), *module = "cairo";
DllInfo *res;
if(!p) return 0;
#ifdef R_ARCH
snprintf(dllpath, PATH_MAX, "%s/library/grDevices/libs/%s/%s%s",
p, R_ARCH, module, SHLIB_EXT);
#else
snprintf(dllpath, PATH_MAX, "%s/library/grDevices/libs/%s%s",
p, module, SHLIB_EXT);
#endif
res = AddDLL(dllpath, local, now, "");
if(!res)
warning(_("unable to load shared object '%s':\n %s"),
dllpath, DLLerror);
return res != NULL ? 1 : 0;
}
/**
Creates an R object representing the value of the
function pointer given by `f'. This object has class
NativeSymbol and can be used to relay symbols from
one DLL to another.
*/
static SEXP
Rf_MakeNativeSymbolRef(DL_FUNC f)
{
SEXP ref, klass;
PROTECT(ref = R_MakeExternalPtrFn(f, install("native symbol"),
R_NilValue));
PROTECT(klass = mkString("NativeSymbol"));
setAttrib(ref, R_ClassSymbol, klass);
UNPROTECT(2);
return(ref);
}
static void
freeRegisteredNativeSymbolCopy(SEXP ref)
{
void *ptr;
ptr = R_ExternalPtrAddr(ref);
if (ptr)
free(ptr);
}
static SEXP
Rf_MakeRegisteredNativeSymbol(R_RegisteredNativeSymbol *symbol)
{
SEXP ref, klass;
R_RegisteredNativeSymbol *copy;
copy = (R_RegisteredNativeSymbol *) malloc(1 * sizeof(R_RegisteredNativeSymbol));
if(!copy) {
error(ngettext("cannot allocate memory for registered native symbol (%d byte)",
"cannot allocate memory for registered native symbol (%d bytes)",
(int) sizeof(R_RegisteredNativeSymbol)),
(int) sizeof(R_RegisteredNativeSymbol));
}
*copy = *symbol;
PROTECT(ref = R_MakeExternalPtr(copy,
install("registered native symbol"),
R_NilValue));
R_RegisterCFinalizer(ref, freeRegisteredNativeSymbolCopy);
PROTECT(klass = mkString("RegisteredNativeSymbol"));
setAttrib(ref, R_ClassSymbol, klass);
UNPROTECT(2);
return(ref);
}
static SEXP
Rf_makeDllObject(HINSTANCE inst)