The R Project SVN R

Rev

Rev 84952 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4394 ripley 1
/*
6098 pd 2
 *  R : A Computer Language for Statistical Data Analysis
90103 maechler 3
 *  Copyright (C) 1997-2026 The R Core Team
6098 pd 4
 *  Copyright (C) 1995-1996 Robert Gentleman and Ross Ihaka
4394 ripley 5
 *
6
 *  This program is free software; you can redistribute it and/or modify
7
 *  it under the terms of the GNU General Public License as published by
8
 *  the Free Software Foundation; either version 2 of the License, or
9
 *  (at your option) any later version.
10
 *
11
 *  This program is distributed in the hope that it will be useful,
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *  GNU General Public License for more details.
15
 *
16
 *  You should have received a copy of the GNU General Public License
42300 ripley 17
 *  along with this program; if not, a copy is available at
68956 ripley 18
 *  https://www.R-project.org/Licenses/
4394 ripley 19
 */
20
 
22312 duncan 21
/*  Dynamic Loading Support: See ../main/Rdynload.c and ../include/Rdynpriv.h
4394 ripley 22
 */
23
 
5222 ripley 24
#ifdef HAVE_CONFIG_H
10986 ripley 25
# include <config.h>
5222 ripley 26
#endif
27
 
10986 ripley 28
#include <string.h>
29
#include <stdlib.h>
11499 ripley 30
#include <Defn.h>
31
#include <Rmath.h>
83696 kalibera 32
#define WIN32_LEAN_AND_MEAN 1
33
 
4394 ripley 34
#include <direct.h>
35
#include <windows.h>
36
 
83696 kalibera 37
/* If called with a non-NULL argument it sets the argument to be
43904 ripley 38
   the second item on the DLL search path (after the application
39
   launch directory).  This is removed if called with NULL.
40
 */
41
 
42
int setDLLSearchPath(const char *path)
43
{
83696 kalibera 44
    return SetDllDirectory(path);
43904 ripley 45
}
46
 
15776 hornik 47
#include <R_ext/Rdynload.h>
48
#include <Rdynpriv.h>
4394 ripley 49
 
50
 
45070 ripley 51
	/* Inserts the specified DLL at the head of the DLL list */
52
	/* Returns 1 if the library was successfully added */
53
	/* and returns 0 if the library table is full or */
54
	/* or if LoadLibrary fails for some reason. */
14077 duncan 55
 
56
static void fixPath(char *path)
4394 ripley 57
{
14080 ripley 58
    char *p;
14077 duncan 59
    for(p = path; *p != '\0'; p++) if(*p == '\\') *p = '/';
4394 ripley 60
}
61
 
45070 ripley 62
static HINSTANCE R_loadLibrary(const char *path, int asLocal, int now,
43904 ripley 63
			       const char *search);
14077 duncan 64
static DL_FUNC getRoutine(DllInfo *info, char const *name);
4394 ripley 65
 
14077 duncan 66
static void R_getDLLError(char *buf, int len);
83696 kalibera 67
static size_t
68
GetFullDLLPath(SEXP call, char *buf, size_t bufsize, const char *path);
4394 ripley 69
 
14077 duncan 70
static void closeLibrary(HINSTANCE handle)
71
{
14080 ripley 72
    FreeLibrary(handle);
14077 duncan 73
}
4394 ripley 74
 
84952 kalibera 75
void InitFunctionHashing(void)
14077 duncan 76
{
77
    R_osDynSymbol->loadLibrary = R_loadLibrary;
78
    R_osDynSymbol->dlsym = getRoutine;
79
    R_osDynSymbol->closeLibrary = closeLibrary;
80
    R_osDynSymbol->getError = R_getDLLError;
4394 ripley 81
 
60604 ripley 82
#ifdef CACHE_DLL_SYM
80285 kalibera 83
    R_osDynSymbol->deleteCachedSymbols = Rf_deleteCachedSymbols;
14077 duncan 84
    R_osDynSymbol->lookupCachedSymbol = Rf_lookupCachedSymbol;
60604 ripley 85
#endif
14077 duncan 86
 
87
    R_osDynSymbol->fixPath = fixPath;
88
    R_osDynSymbol->getFullDLLPath = GetFullDLLPath;
89
}
90
 
38811 ripley 91
#ifndef _MCW_EM
45070 ripley 92
_CRTIMP unsigned int __cdecl
38811 ripley 93
_controlfp (unsigned int unNew, unsigned int unMask);
94
_CRTIMP unsigned int __cdecl _clearfp (void);
95
/* Control word masks for unMask */
96
#define	_MCW_EM		0x0008001F	/* Error masks */
97
#define	_MCW_IC		0x00040000	/* Infinity */
98
#define	_MCW_RC		0x00000300	/* Rounding */
99
#define	_MCW_PC		0x00030000	/* Precision */
100
#endif
101
 
45070 ripley 102
HINSTANCE R_loadLibrary(const char *path, int asLocal, int now,
43904 ripley 103
			const char *search)
14077 duncan 104
{
14080 ripley 105
    HINSTANCE tdlh;
22138 murdoch 106
    unsigned int dllcw, rcw;
43904 ripley 107
    int useSearch = search && search[0];
14080 ripley 108
 
23382 murdoch 109
    rcw = _controlfp(0,0) & ~_MCW_IC;  /* Infinity control is ignored */
22166 murdoch 110
    _clearfp();
43904 ripley 111
    if(useSearch) setDLLSearchPath(search);
14077 duncan 112
    tdlh = LoadLibrary(path);
43904 ripley 113
    if(useSearch) setDLLSearchPath(NULL);
22614 ripley 114
    dllcw = _controlfp(0,0) & ~_MCW_IC;
22138 murdoch 115
    if (dllcw != rcw) {
43904 ripley 116
	_controlfp(rcw, _MCW_EM | _MCW_IC | _MCW_RC | _MCW_PC);
54049 ripley 117
	if (LOGICAL(GetOption1(install("warn.FPU")))[0])
43904 ripley 118
	    warning(_("DLL attempted to change FPU control word from %x to %x"),
119
		    rcw,dllcw);
120
    }
14080 ripley 121
    return(tdlh);
14077 duncan 122
}
4394 ripley 123
 
14077 duncan 124
static DL_FUNC getRoutine(DllInfo *info, char const *name)
4394 ripley 125
{
14080 ripley 126
    DL_FUNC f;
127
    f = (DL_FUNC) GetProcAddress(info->handle, name);
128
    return(f);
14077 duncan 129
}
4394 ripley 130
 
14077 duncan 131
static void R_getDLLError(char *buf, int len)
132
{
90103 maechler 133
    LPSTR lpMsgBuf;
14080 ripley 134
    FormatMessage(
135
	FORMAT_MESSAGE_ALLOCATE_BUFFER |
136
	FORMAT_MESSAGE_FROM_SYSTEM |
137
	FORMAT_MESSAGE_IGNORE_INSERTS,
138
	NULL,
139
	GetLastError(),
140
	MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
53443 ripley 141
	(LPSTR) &lpMsgBuf,
14080 ripley 142
	0,
143
	NULL
144
	);
145
    strcpy(buf, "LoadLibrary failure:  ");
90103 maechler 146
    char
147
	*q = buf + strlen(buf),
148
	*e = buf + len - 1;
53423 ripley 149
    /* It seems that Win 7 returns error messages with CRLF terminators */
90103 maechler 150
    for (LPSTR p = lpMsgBuf; *p && q < e; p++) if (*p != '\r') *q++ = *p;
14080 ripley 151
    LocalFree(lpMsgBuf);
90103 maechler 152
    *e = '\0';
4394 ripley 153
}
154
 
90103 maechler 155
/* Returns the number of bytes (excluding the terminator) needed in buf.
83696 kalibera 156
   When bufsize is at least that + 1, buf contains the result
157
   with terminator. */
158
static size_t
159
GetFullDLLPath(SEXP call, char *buf, size_t bufsize, const char *path)
4394 ripley 160
{
83696 kalibera 161
    /* NOTE: Unix version also expands ~ */
10557 ripley 162
 
83696 kalibera 163
    size_t needed = strlen(path);
4394 ripley 164
    if ((path[0] != '/') && (path[0] != '\\') && (path[1] != ':')) {
83696 kalibera 165
	needed ++; /* for separator */
166
	DWORD res = GetCurrentDirectory(bufsize, buf);
167
	if (!res)
32888 ripley 168
	    errorcall(call, _("cannot get working directory"));
83696 kalibera 169
	needed += res;
170
	if (res >= bufsize)
171
	    return needed - 1; /* res here includes terminator */
172
 
173
	if (bufsize >= needed + 1) {
174
	    strcat(buf, "/");
175
	    strcat(buf, path);
176
	    /* fix slashes to allow inconsistent usage later */
177
	    fixPath(buf);
178
	}
179
    } else {
180
	if (bufsize >= needed + 1) {
181
	    strcpy(buf, path);
182
	    /* fix slashes to allow inconsistent usage later */
183
	    fixPath(buf);
184
	}
185
    }
186
    return needed;
4394 ripley 187
}
83696 kalibera 188