The R Project SVN R

Rev

Rev 80571 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 80571 Rev 83755
Line 1... Line 1...
1
/*
1
/*
2
 *  R : A Computer Language for Statistical Data Analysis
2
 *  R : A Computer Language for Statistical Data Analysis
3
 *  Copyright (C) 1999--2010  Guido Masarotto and Brian Ripley
3
 *  Copyright (C) 1999--2010  Guido Masarotto and Brian Ripley
4
 *  Copyright (C) 2021        The R Core Team
4
 *  Copyright (C) 2021--2023  The R Core Team
5
 *
5
 *
6
 *  This program is free software; you can redistribute it and/or modify
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
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
8
 *  the Free Software Foundation; either version 2 of the License, or
9
 *  (at your option) any later version.
9
 *  (at your option) any later version.
Line 29... Line 29...
29
#include <string.h>		/* for strrchr(...) */
29
#include <string.h>		/* for strrchr(...) */
30
#include <stdio.h>
30
#include <stdio.h>
31
#include <ctype.h>
31
#include <ctype.h>
32
#include <stdlib.h>		/* for exit */
32
#include <stdlib.h>		/* for exit */
33
 
33
 
34
static char rhomebuf[MAX_PATH];
34
extern void R_Suicide(char *s);
35
 
-
 
36
/* <MBCS-FIXME> We can't just use Rf_strchr as this is called
-
 
37
   from front-ends */
-
 
38
#define GOBACKONESLASH \
-
 
39
    p = strrchr(rhomebuf,'\\'); \
-
 
40
    if (!p) { \
-
 
41
	MessageBox(NULL, "Installation problem", "Terminating", \
-
 
42
		   MB_TASKMODAL | MB_ICONSTOP | MB_OK);\
-
 
43
	exit(1); \
-
 
44
    } \
-
 
45
    *p = '\0'
-
 
46
 
35
 
47
/* get R_HOME from the module path: used in RSetReg */
36
/* get R_HOME from the module path: used in RSetReg */
-
 
37
/* Returns a result to be freed by freeRHOMElong(). */
48
char *getRHOMElong(int m)
38
char *getRHOMElong(int m)
49
{
39
{
-
 
40
    DWORD size = 1;
-
 
41
    char *buf = NULL;
-
 
42
    
-
 
43
    /* GetModuleFileName doesn't return the needed buffer size. */
-
 
44
    for(;;) {
-
 
45
	buf = (char *)malloc(size);
-
 
46
	if (!buf)
-
 
47
	    return NULL;
-
 
48
	DWORD res = GetModuleFileName(NULL, buf, size);
-
 
49
	if (res > 0 && res < size) /* success */
-
 
50
	    break;
-
 
51
	free(buf);
-
 
52
	if (res != size) /* error */
-
 
53
	    return NULL;
-
 
54
	size *= 2; /* try again with 2x larger buffer */
-
 
55
    }
-
 
56
    for(int i=0; i < m; i++) {
-
 
57
	/* drop suffix starting with last backslash */
-
 
58
	/* <MBCS-FIXME> We can't just use Rf_strchr as this is called
-
 
59
	   from front-ends */
-
 
60
	char *p = strrchr(buf, '\\');
-
 
61
	if (!p) {
-
 
62
	    MessageBox(NULL, "Installation problem", "Terminating",
-
 
63
	               MB_TASKMODAL | MB_ICONSTOP | MB_OK);
-
 
64
	    free(buf);
-
 
65
	    exit(1);
-
 
66
	}
-
 
67
	*p = '\0';
-
 
68
    }
50
    char *p;
69
    return buf;
-
 
70
}
51
 
71
 
52
    GetModuleFileName(NULL, rhomebuf, MAX_PATH);
72
void freeRHOMElong(char *s)
-
 
73
{
53
    for(int i=0; i < m; i++) {GOBACKONESLASH;}
74
    if (s)
54
    return (rhomebuf);
75
	free(s);
55
}
76
}
56
 
77
 
57
/* get no-spaces version of R_HOME from the module path: 
78
/* get no-spaces version of R_HOME from the module path: 
58
   used in Rgui, Rterm and Rcmd
79
   used in Rgui, Rterm and Rcmd
59
*/
80
*/
-
 
81
/* Returns a result to be freed by freeRHOME(). Previously, pointer to a static
-
 
82
   fixed-size buffer has been returned, so older embedding applications would
-
 
83
   not know to free the result, but they would probably call this function
-
 
84
   only once. */
60
char *getRHOME(int m)
85
char *getRHOME(int m)
61
{
86
{
62
    char *p;
87
    char *p;
63
    int hasspace = 0;
88
    int hasspace = 0;
-
 
89
    char *rhome = getRHOMElong(m);
-
 
90
 
-
 
91
    if (!rhome)
-
 
92
	return NULL;
64
 
93
 
65
    getRHOMElong(m);
-
 
66
    /* make sure no spaces in path */
94
    /* try removing spaces from path */
67
    for (p = rhomebuf; *p; p++)
95
    for (p = rhome; *p; p++)
68
	if (isspace(*p)) { hasspace = 1; break; }
96
	if (isspace(*p)) { hasspace = 1; break; }
69
    if (hasspace)
97
    if (hasspace) {
70
	/* NOTE: this fails when short names are not enabled */
98
	/* NOTE: this fails when short names are not enabled */
-
 
99
	DWORD res = GetShortPathName(rhome, NULL, 0);
-
 
100
	if (res > 0) {
-
 
101
	    char *shome = (char*) malloc(res);
-
 
102
	    if (shome) {
71
	GetShortPathName(rhomebuf, rhomebuf, MAX_PATH);
103
		DWORD res1 = GetShortPathName(rhome, shome, res);
-
 
104
		if (res1 > 0 && res1 < res) {
-
 
105
		    free(rhome);
-
 
106
		    return shome;
-
 
107
		}
-
 
108
	    }
-
 
109
	}
-
 
110
    }
72
    return (rhomebuf);
111
    return rhome;
73
}
112
}
74
 
113
 
-
 
114
void freeRHOME(char *s)
-
 
115
{
-
 
116
    if (s)
-
 
117
	free(s);
-
 
118
}
75
 
119
 
76
/* get R_HOME from environment or registry: used in embedded apps */
120
static char *rhome_from_registry(HKEY key, int *key_found)
77
char *get_R_HOME(void)
-
 
78
{
121
{
79
    LONG rc;
122
    LONG rc;
80
    HKEY hkey;
123
    HKEY hkey;
81
    DWORD keytype = REG_SZ, cbData = sizeof(rhomebuf);
124
    DWORD keytype = REG_SZ, cbData;
-
 
125
    rc = RegOpenKeyEx(key, "Software\\R-core\\R", 0,
-
 
126
                      KEY_READ, &hkey);
-
 
127
    if (rc == ERROR_SUCCESS) {
-
 
128
	*key_found = 1;
-
 
129
	char *rhome = NULL;
-
 
130
	cbData = 0;
-
 
131
	rc = RegQueryValueEx(hkey, "InstallPath", 0, &keytype,
-
 
132
                             NULL, &cbData);
-
 
133
	if (rc == ERROR_MORE_DATA) {
-
 
134
	    rhome = (char *)malloc(cbData);
-
 
135
	    if (!rhome)
-
 
136
		return NULL;
-
 
137
	    rc = RegQueryValueEx(hkey, "InstallPath", 0, &keytype,
-
 
138
	                         (LPBYTE) rhome, &cbData);
-
 
139
	}
-
 
140
	RegCloseKey (hkey);
-
 
141
	if (rc == ERROR_SUCCESS)
-
 
142
	    return rhome;
-
 
143
	else if (rhome)
-
 
144
	    free(rhome);
-
 
145
    } else
-
 
146
	*key_found = 0;
-
 
147
    return NULL;
-
 
148
}
-
 
149
 
-
 
150
/* get R_HOME from environment or registry: used in embedded apps */
-
 
151
/* Returns a result to be freed by free_R_HOME(). */
-
 
152
char *get_R_HOME(void)
-
 
153
{
-
 
154
    char *rhome;
82
 
155
 
83
    /* First try the C environment space */
156
    /* First try the C environment space */
84
    if(getenv("R_HOME")) {
157
    char *env = getenv("R_HOME");
-
 
158
    if(env) {
85
	strncpy(rhomebuf, getenv("R_HOME"), MAX_PATH - 1);
159
	rhome = (char *)malloc(strlen(env) + 1);
-
 
160
	if (rhome)
86
	rhomebuf[MAX_PATH - 1] = '\0';
161
	    strcpy(rhome, env);
87
	return (rhomebuf);
162
	return rhome;
88
    }
163
    }
89
 
164
 
90
    /* Then the Windows API environment space */
165
    /* Then the Windows API environment space */
-
 
166
    DWORD res = GetEnvironmentVariable("R_HOME", NULL, 0);
-
 
167
    if (res) {
-
 
168
	rhome = (char *)malloc(res);
-
 
169
	if (!rhome)
-
 
170
	    return NULL;
91
    if (GetEnvironmentVariable ("R_HOME", rhomebuf, sizeof (rhomebuf)) > 0)
171
	DWORD res1 = GetEnvironmentVariable("R_HOME", rhome, res);
-
 
172
	if (res1 > 0 && res1 < res)
92
	return (rhomebuf);
173
	    return rhome;
-
 
174
	free(rhome);
-
 
175
    }
93
 
176
 
94
    /* And then the registry */
177
    /* And then the registry */
95
    rc = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\R-core\\R", 0,
-
 
96
                      KEY_READ, &hkey);
-
 
97
    if (rc == ERROR_SUCCESS) {
178
    int key_found = 0; 
98
	rc = RegQueryValueEx(hkey, "InstallPath", 0, &keytype,
-
 
99
                             (LPBYTE) rhomebuf, &cbData);
179
    rhome = rhome_from_registry(HKEY_CURRENT_USER, &key_found);
100
	RegCloseKey (hkey);
180
    if (key_found) {
101
	return (rc == ERROR_SUCCESS) ? rhomebuf : NULL;
-
 
102
	/* Do not look into the machine registry when there are any
181
	/* Do not look into the machine registry when there are any
103
	   versions of R installed for the current user. Any installation
182
	   versions of R installed for the current user. Any installation
104
	   of R updates the path in the registry (user or machine) and any
183
	   of R updates the path in the registry (user or machine) and any
105
	   uninstallation clears it, so the entry may be unset even when
184
	   uninstallation clears it, so the entry may be unset even when
106
	   some versions of R are installed. One should use R_HOME
185
	   some versions of R are installed. One should use R_HOME
107
	   environment variable to avoid surprise.
186
	   environment variable to avoid surprise.
108
	*/
187
	*/
-
 
188
	return rhome;
109
    }
189
    }
-
 
190
    return rhome_from_registry(HKEY_LOCAL_MACHINE, &key_found);
-
 
191
}
110
 
192
 
111
    rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\R-core\\R", 0,
-
 
112
                      KEY_READ, &hkey);
-
 
113
    if (rc == ERROR_SUCCESS) {
193
void free_R_HOME(char *s)
114
	rc = RegQueryValueEx(hkey, "InstallPath", 0, &keytype,
-
 
115
                             (LPBYTE) rhomebuf, &cbData);
-
 
116
	RegCloseKey (hkey);
-
 
117
	return (rc == ERROR_SUCCESS) ? rhomebuf : NULL;
-
 
-
 
194
{
118
    }
195
    if (s)
119
    return NULL;
196
	free(s);
120
}
197
}
-
 
198
 
-
 
199
void R_putenv_path_cpy(char *varname, char *value, int fixslash)
-
 
200
{
-
 
201
    size_t needed = strlen(varname) + 1 + strlen(value) + 1;
-
 
202
    char *buf = (char *)malloc(needed);
-
 
203
    if (!buf)
-
 
204
	R_Suicide("Allocation error");
-
 
205
    snprintf(buf, needed, "%s=%s", varname, value);
-
 
206
    if (fixslash)
-
 
207
	for (char *p = buf; *p; p++) if (*p == '\\') *p = '/';
-
 
208
    putenv(buf);
-
 
209
    /* no free here: storage remains in use */
-
 
210
}
-
 
211