The R Project SVN R

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
45328 ripley 1
/*
2
 *   R : A Computer Language for Statistical Data Analysis
58977 ripley 3
 *   Copyright (C) 1997-2008   The R Core Team
45328 ripley 4
 *
5
 *  This program is free software; you can redistribute it and/or modify
6
 *  it under the terms of the GNU General Public License as published by
7
 *  the Free Software Foundation; either version 2 of the License, or
8
 *  (at your option) any later version.
9
 *
10
 *  This program is distributed in the hope that it will be useful,
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 *  GNU General Public License for more details.
14
 *
15
 *  You should have received a copy of the GNU General Public License
16
 *  along with this program; if not, a copy is available at
68956 ripley 17
 *  https://www.R-project.org/Licenses/
45328 ripley 18
 */
19
 
20
#include <stdlib.h> /* for setenv or putenv */
21
#define alloca(x) __builtin_alloca((x))
22
#include <stdio.h>
23
#include <string.h>
24
#include <ctype.h>
25
 
26
/* remove leading and trailing space */
27
static char *rmspace(char *s)
28
{
29
    int   i;
30
 
31
    for (i = strlen(s) - 1; i >= 0 && isspace((int)s[i]); i--) s[i] = '\0';
32
    for (i = 0; isspace((int)s[i]); i++);
33
    return s + i;
34
}
35
 
36
/* look for ${FOO-bar} or ${FOO:-bar} constructs, recursively.
37
   return "" on an error condition.
38
 */
39
 
40
static char *subterm(char *s)
41
{
42
    char *p, *q;
43
 
44
    if(strncmp(s, "${", 2)) return s;
45
    if(s[strlen(s) - 1] != '}') return s;
46
    /*  remove leading ${ and final } */
47
    s[strlen(s) - 1] = '\0';
48
    s += 2;
49
    s = rmspace(s);
50
    if(!strlen(s)) return "";
51
    p = strchr(s, '-');
52
    if(p) {
53
	q = p + 1; /* start of value */
54
	if(p - s > 1 && *(p-1) == ':') *(p-1) = '\0'; else *p = '\0';
55
    } else q = NULL;
56
    p = getenv(s);
57
    if(p && strlen(p)) return p; /* variable was set and non-empty */
58
    return q ? subterm(q) : (char *) "";
59
}
60
 
61
/* skip along until we find an unmatched right brace */
62
static char *findRbrace(char *s)
63
{
64
    char *p = s, *pl, *pr;
65
    int nl = 0, nr = 0;
66
 
67
    while(nr <= nl) {
68
	pl = strchr(p, '{');
69
	pr = strchr(p, '}');
70
	if(!pr) return NULL;
71
	if(!pl || pr < pl) {
72
	    p = pr+1; nr++;
73
	} else {
74
	    p = pl+1; nl++;
75
	}
76
    }
77
    return pr;
78
}
79
 
80
 
81
static char *findterm(char *s)
82
{
83
    char *p, *q, *r, *r2, *ss=s;
84
    static char ans[1000];
85
    int nans;
86
 
87
    if(!strlen(s)) return "";
88
    ans[0] = '\0';
89
    while(1) {
90
	/* Look for ${...}, taking care to look for inner matches */
91
	p = strchr(s, '$');
92
	if(!p || p[1] != '{') break;
93
	q = findRbrace(p+2);
94
	if(!q) break;
95
	/* copy over leading part */
96
	nans = strlen(ans);
97
	strncat(ans, s, p-s); ans[nans + p - s] = '\0';
98
	r = (char *) alloca(q - p + 2);
99
	strncpy(r, p, q - p + 1);
100
	r[q - p + 1] = '\0';
101
	r2 = subterm(r);
102
	if(strlen(ans) + strlen(r2) < 1000) strcat(ans, r2); else return ss;
103
	/* now repeat on the tail */
104
	s = q+1;
105
    }
106
    if(strlen(ans) + strlen(s) < 1000) strcat(ans, s); else return ss;
107
    return ans;
108
}
109
 
110
static void Putenv(char *a, char *b)
111
{
112
    char *buf, *value, *p, *q, quote='\0';
113
    int inquote = 0;
114
 
115
    buf = (char *) malloc((strlen(a) + strlen(b) + 2) * sizeof(char));
116
    if(!buf) {
117
	fprintf(stderr, "allocation failure in reading Renviron");
118
	return;
119
    }
120
    strcpy(buf, a); strcat(buf, "=");
121
    value = buf+strlen(buf);
122
 
123
    /* now process the value */
124
    for(p = b, q = value; *p; p++) {
125
	/* remove quotes around sections, preserve \ inside quotes */
126
	if(!inquote && (*p == '"' || *p == '\'')) {
127
	    inquote = 1;
128
	    quote = *p;
129
	    continue;
130
	}
131
	if(inquote && *p == quote && *(p-1) != '\\') {
132
	    inquote = 0;
133
	    continue;
134
	}
135
	if(!inquote && *p == '\\') {
136
	    if(*(p+1) == '\n') p++;
137
	    else if(*(p+1) == '\\') *q++ = *p;
138
	    continue;
139
	}
140
	if(inquote && *p == '\\' && *(p+1) == quote) continue;
141
	*q++ = *p;
142
    }
143
    *q = '\0';
144
    if(putenv(buf))
46444 murdoch 145
	fprintf(stderr, "Problem in setting variable '%s' in Renviron", a);
45328 ripley 146
    /* no free here: storage remains in use */
147
}
148
 
149
 
150
#define BUF_SIZE 255
151
#define MSG_SIZE 2000
152
int process_Renviron(const char *filename)
153
{
154
    FILE *fp;
155
    char *s, *p, sm[BUF_SIZE], *lhs, *rhs, msg[MSG_SIZE+50];
156
    int errs = 0;
157
 
158
    if (!filename || !(fp = fopen(filename, "r"))) return 0;
159
    snprintf(msg, MSG_SIZE+50,
160
	     "\n   File %s contains invalid line(s)", filename);
161
 
162
    while(fgets(sm, BUF_SIZE, fp)) {
163
        sm[BUF_SIZE-1] = '\0';
164
	s = rmspace(sm);
165
	if(strlen(s) == 0 || s[0] == '#') continue;
166
	if(!(p = strchr(s, '='))) {
167
	    errs++;
168
	    if(strlen(msg) < MSG_SIZE) {
169
		strcat(msg, "\n      "); strcat(msg, s);
170
	    }
171
	    continue;
172
	}
173
	*p = '\0';
174
	lhs = rmspace(s);
175
	rhs = findterm(rmspace(p+1));
176
	/* set lhs = rhs */
177
	if(strlen(lhs) && strlen(rhs)) Putenv(lhs, rhs);
178
    }
179
    fclose(fp);
180
    if (errs) {
181
	strcat(msg, "\n   They were ignored\n");
182
	fprintf(stderr, "%s", msg);
183
    }
184
    return 1;
185
}