1 |
/* |
2 |
* Ascend Environment Variable Imitation |
3 |
* by Ben Allan |
4 |
* Created: 6/3/97 |
5 |
* Version: $Revision: 1.5 $ |
6 |
* Version control file: $RCSfile: ascEnvVar.c,v $ |
7 |
* Date last modified: $Date: 1997/07/18 12:04:07 $ |
8 |
* Last modified by: $Author: mthomas $ |
9 |
* |
10 |
* This file is part of the Ascend Language Interpreter. |
11 |
* |
12 |
* Copyright (C) 1997 Benjamin Andrew Allan |
13 |
* |
14 |
* The Ascend Language Interpreter is free software; you can redistribute |
15 |
* it and/or modify it under the terms of the GNU General Public License as |
16 |
* published by the Free Software Foundation; either version 2 of the |
17 |
* License, or (at your option) any later version. |
18 |
* |
19 |
* The Ascend Language Interpreter is distributed in hope that it will be |
20 |
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of |
21 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
22 |
* General Public License for more details. |
23 |
* |
24 |
* You should have received a copy of the GNU General Public License |
25 |
* along with the program; if not, write to the Free Software Foundation, |
26 |
* Inc., 675 Mass Ave, Cambridge, MA 02139 USA. Check the file named |
27 |
* COPYING. |
28 |
* |
29 |
* This file exists because win32, among others, can't keep their |
30 |
* POSIX compliance up. In particular, getting and setting |
31 |
* environment vars is exceedingly unreliable. |
32 |
* This file implements a general way to store and fetch multiple |
33 |
* paths. |
34 |
*/ |
35 |
|
36 |
#include <ctype.h> |
37 |
#include "ascConfig.h" |
38 |
#include "ascPanic.h" |
39 |
#include "ascMalloc.h" |
40 |
#include "ascEnvVar.h" |
41 |
#include <general/list.h> |
42 |
|
43 |
#ifndef lint |
44 |
static CONST char ascEnvVarid[] = "$Id: ascEnvVar.c,v 1.5 1997/07/18 12:04:07 mthomas Exp $"; |
45 |
#endif /* RCS ID keyword */ |
46 |
|
47 |
|
48 |
#ifdef __WIN32__ |
49 |
#define SLASH '\\' |
50 |
#define PATHDIV ';' |
51 |
#else /* ! __WIN32__ */ |
52 |
#define SLASH '/' |
53 |
#define PATHDIV ':' |
54 |
#endif |
55 |
|
56 |
/* |
57 |
* structure we have for each envvar. |
58 |
* each contains a list with pointers to strings. |
59 |
*/ |
60 |
struct asc_env_t { |
61 |
const char *name; |
62 |
struct gl_list_t *data; |
63 |
}; |
64 |
|
65 |
/* |
66 |
* This list is a list of pointer to struct asc_env_t's |
67 |
* that constitute the environment. |
68 |
*/ |
69 |
|
70 |
static |
71 |
struct gl_list_t *g_env_list = NULL; |
72 |
|
73 |
/* |
74 |
* ev = CreateEnvVar(envvar_name_we_own); |
75 |
* Returns NULL, or the asc_env_t requested. |
76 |
* The requested has an empty gl_list. |
77 |
* The name sent is the user's responsibility if we |
78 |
* return NULL, OTHERWISE it is henceforth ours. |
79 |
* We do not append the requested to the global list; that is the |
80 |
* caller's job. |
81 |
*/ |
82 |
static |
83 |
struct asc_env_t *CreateEnvVar(char *keepname) |
84 |
{ |
85 |
struct asc_env_t *ev; |
86 |
ev = ASC_NEW(struct asc_env_t); |
87 |
if (ev == NULL) { |
88 |
return NULL; |
89 |
} |
90 |
ev->data = gl_create(4); |
91 |
ev->name = keepname; |
92 |
return ev; |
93 |
} |
94 |
|
95 |
/* |
96 |
* clear out a env variable data blob. |
97 |
*/ |
98 |
static |
99 |
void DestroyEnvVar(struct asc_env_t *ev) |
100 |
{ |
101 |
if (ev==NULL) { |
102 |
return; |
103 |
} |
104 |
ascfree((char *)ev->name); |
105 |
gl_free_and_destroy(ev->data); |
106 |
ascfree(ev); |
107 |
} |
108 |
|
109 |
/* |
110 |
* compare two env variable data blobs by name. |
111 |
*/ |
112 |
|
113 |
CmpFunc CmpEv; |
114 |
|
115 |
static |
116 |
int CmpEV(struct asc_env_t *ev1, struct asc_env_t *ev2) |
117 |
{ |
118 |
if (ev1==ev2) { |
119 |
return 0; |
120 |
} |
121 |
if (ev1==NULL || ev1->name == NULL) { |
122 |
return 1; |
123 |
} |
124 |
if (ev2==NULL || ev2->name == NULL) { |
125 |
return -1; |
126 |
} |
127 |
return strcmp(ev1->name,ev2->name); |
128 |
} |
129 |
|
130 |
/* |
131 |
* returns the envvar with the name specified. |
132 |
*/ |
133 |
static |
134 |
struct asc_env_t *FindEnvVar(const char *name) |
135 |
{ |
136 |
unsigned long pos; |
137 |
struct asc_env_t dummy; |
138 |
|
139 |
dummy.name = name; |
140 |
pos = gl_search(g_env_list,&dummy,(CmpFunc)CmpEV); |
141 |
if (pos==0) { |
142 |
#if 0 |
143 |
FPRINTF(ASCERR,"ENV VAR '%s' NOT FOUND\n",name); |
144 |
#endif |
145 |
return NULL; |
146 |
} |
147 |
return (struct asc_env_t *)gl_fetch(g_env_list,pos); |
148 |
} |
149 |
|
150 |
/* |
151 |
* add a var to the global sorted list. |
152 |
*/ |
153 |
static |
154 |
void AppendEnvVar(struct gl_list_t *env, struct asc_env_t *ev) |
155 |
{ |
156 |
gl_insert_sorted(env,ev,(CmpFunc)CmpEV); |
157 |
} |
158 |
|
159 |
/* |
160 |
* removes and destroys a var in the environment, if it exists. |
161 |
*/ |
162 |
static |
163 |
void DeleteEnvVar(char *name) |
164 |
{ |
165 |
unsigned long pos; |
166 |
struct asc_env_t *ev; |
167 |
struct asc_env_t dummy; |
168 |
|
169 |
dummy.name = name; |
170 |
|
171 |
if (name == NULL || g_env_list == NULL) { |
172 |
return; |
173 |
} |
174 |
pos = gl_search(g_env_list,&dummy,(CmpFunc)CmpEV); |
175 |
ev = (struct asc_env_t *)gl_fetch(g_env_list,pos); |
176 |
gl_delete(g_env_list,pos,0); |
177 |
DestroyEnvVar(ev); |
178 |
} |
179 |
|
180 |
int Asc_InitEnvironment(unsigned long len) |
181 |
{ |
182 |
if (g_env_list != NULL) { |
183 |
return 1; |
184 |
} |
185 |
g_env_list = gl_create(len); |
186 |
if (g_env_list == NULL) { |
187 |
return 1; |
188 |
} |
189 |
return 0; |
190 |
} |
191 |
|
192 |
|
193 |
void Asc_DestroyEnvironment(void) |
194 |
{ |
195 |
if (g_env_list == NULL) { |
196 |
return; |
197 |
} |
198 |
gl_iterate(g_env_list,(void (*)(VOIDPTR))DestroyEnvVar); |
199 |
gl_destroy(g_env_list); |
200 |
g_env_list = NULL; |
201 |
} |
202 |
|
203 |
|
204 |
int Asc_SetPathList(CONST char *envvar, CONST char *pathstring) |
205 |
{ |
206 |
char g_path_var[MAX_ENV_VAR_LENGTH]; |
207 |
unsigned int c, length, spcseen=0; |
208 |
struct asc_env_t *ev; |
209 |
char *keepname; |
210 |
CONST char *path; |
211 |
char *putenvstring; |
212 |
|
213 |
if ((g_env_list == NULL) || |
214 |
(envvar == NULL) || |
215 |
(strlen(envvar) == 0) || |
216 |
(pathstring == NULL) || |
217 |
(strlen(pathstring) == 0) || |
218 |
(strlen(envvar) >= MAX_ENV_VAR_LENGTH)) { |
219 |
return 1; |
220 |
} |
221 |
/* |
222 |
* transform envvar into a string w/out lead/trail blanks and copy. |
223 |
*/ |
224 |
putenvstring = g_path_var; |
225 |
snprintf(putenvstring, MAX_ENV_VAR_LENGTH, "%s", envvar); |
226 |
/* trim leading whitespace */ |
227 |
while (isspace(putenvstring[0])) { |
228 |
putenvstring++; |
229 |
} |
230 |
for (c = 0; putenvstring[c] !='\0'; c++) { |
231 |
if (isspace(putenvstring[c])) { |
232 |
spcseen++; |
233 |
} |
234 |
} |
235 |
/* backup to before last trailing space */ |
236 |
while (isspace(putenvstring[c-1])) { |
237 |
c--; |
238 |
spcseen--; |
239 |
} |
240 |
/* check for no spaces in keepname */ |
241 |
if (spcseen) { |
242 |
return 1; |
243 |
} |
244 |
keepname = ASC_NEW_ARRAY(char,c+1); |
245 |
if (keepname == NULL) { |
246 |
return 1; |
247 |
} |
248 |
strncpy(keepname, putenvstring, c); |
249 |
keepname[c] = '\0'; |
250 |
/* delete the old variable if it was already assigned */ |
251 |
ev = FindEnvVar(keepname); |
252 |
if (ev!=NULL) { |
253 |
DeleteEnvVar(keepname); |
254 |
} |
255 |
ev = CreateEnvVar(keepname); |
256 |
if (ev == NULL) { |
257 |
ascfree(keepname); |
258 |
return 1; |
259 |
} |
260 |
AppendEnvVar(g_env_list, ev); |
261 |
|
262 |
/* |
263 |
* copy/split the pathstring |
264 |
*/ |
265 |
path = pathstring; |
266 |
|
267 |
/* strip any leading whitespace */ |
268 |
while( isspace( *path ) ) { |
269 |
path++; |
270 |
} |
271 |
while( *path != '\0' ) { |
272 |
length = 0; |
273 |
/* copy the directory from path to the g_path_var */ |
274 |
while(( *path != PATHDIV ) && |
275 |
( *path != '\0' ) && |
276 |
( length < (MAX_ENV_VAR_LENGTH - 1) )) { |
277 |
g_path_var[length++] = *(path++); |
278 |
} |
279 |
/* if we didn't run out of room, strip trailing whitespace */ |
280 |
if (( length > 0) && ( length < (MAX_ENV_VAR_LENGTH - 1) )) { |
281 |
while (isspace(g_path_var[length-1])) { |
282 |
length--; |
283 |
} |
284 |
} |
285 |
/* otherwise advance to the next substring in path */ |
286 |
else { |
287 |
while(( *path != PATHDIV ) && ( *path != '\0' )) { |
288 |
path++; |
289 |
} |
290 |
} |
291 |
/* append the value if not empty */ |
292 |
if ( length > 0 ) { |
293 |
g_path_var[length++] = '\0'; |
294 |
if ( Asc_AppendPath(keepname,g_path_var) != 0 ) { |
295 |
return 1; |
296 |
} |
297 |
} |
298 |
/* advance path past any whitespace & delimiters */ |
299 |
while( isspace(*path) || ( *path == PATHDIV ) ) path++; |
300 |
} |
301 |
return 0; |
302 |
} |
303 |
|
304 |
|
305 |
int Asc_PutEnv(CONST char *envstring) |
306 |
{ |
307 |
char g_path_var[MAX_ENV_VAR_LENGTH]; |
308 |
unsigned int c, length, spcseen=0, rhs; |
309 |
struct asc_env_t *ev; |
310 |
char *keepname, *path, *putenvstring; |
311 |
|
312 |
if ((g_env_list == NULL) || |
313 |
(envstring == NULL) || |
314 |
(strlen(envstring) == 0) || |
315 |
(strlen(envstring) >= MAX_ENV_VAR_LENGTH)) { |
316 |
return 1; |
317 |
} |
318 |
|
319 |
putenvstring = g_path_var; |
320 |
snprintf(putenvstring, MAX_ENV_VAR_LENGTH, "%s", envstring); |
321 |
/* trim leading whitespace */ |
322 |
while (isspace(putenvstring[0])) { |
323 |
putenvstring++; |
324 |
} |
325 |
/* locate '=' or EOS, counting whitespace along the way */ |
326 |
for (c = 0; putenvstring[c] !='\0' && putenvstring[c] != '='; c++) { |
327 |
if (isspace(putenvstring[c])) { |
328 |
spcseen++; |
329 |
} |
330 |
} |
331 |
/* check for empty rhs */ |
332 |
if (putenvstring[c] == '\0') { |
333 |
return 1; |
334 |
} |
335 |
rhs = c; |
336 |
/* backup space before = */ |
337 |
while (isspace(putenvstring[c-1])) { |
338 |
c--; |
339 |
spcseen--; |
340 |
} |
341 |
/* check for no spaces in keepname */ |
342 |
if (spcseen) { |
343 |
return 1; |
344 |
} |
345 |
keepname = ASC_NEW_ARRAY(char,c+1); |
346 |
if (keepname == NULL) { |
347 |
return 1; |
348 |
} |
349 |
strncpy(keepname,putenvstring,c); |
350 |
keepname[c] = '\0'; |
351 |
/* delete the old variable if it was already assigned */ |
352 |
ev = FindEnvVar(keepname); |
353 |
if (ev!=NULL) { |
354 |
DeleteEnvVar(keepname); |
355 |
} |
356 |
ev = CreateEnvVar(keepname); |
357 |
if (ev == NULL) { |
358 |
ascfree(keepname); |
359 |
return 1; |
360 |
} |
361 |
|
362 |
AppendEnvVar(g_env_list,ev); |
363 |
path = putenvstring + rhs + 1; /* got past the '=' */ |
364 |
|
365 |
while( isspace( *path ) ) { |
366 |
path++; |
367 |
} |
368 |
while( *path != '\0' ) { |
369 |
length = 0; |
370 |
/* copy the directory from path to the g_path_var */ |
371 |
while(( *path != PATHDIV ) && ( *path != '\0' )) { |
372 |
g_path_var[length++] = *(path++); |
373 |
} |
374 |
while (( length > 0 ) && isspace(g_path_var[length-1])) { |
375 |
length--; |
376 |
} |
377 |
if ( length > 0) { |
378 |
g_path_var[length++] = '\0'; |
379 |
if (Asc_AppendPath(keepname,g_path_var)!=0) { |
380 |
return 1; |
381 |
} |
382 |
} |
383 |
while( isspace(*path) || ( *path == PATHDIV ) ) path++; |
384 |
} |
385 |
return 0; |
386 |
} |
387 |
|
388 |
|
389 |
int Asc_ImportPathList(CONST char *envvar) |
390 |
{ |
391 |
char *rhs; |
392 |
|
393 |
if (( g_env_list == NULL ) || |
394 |
( envvar == NULL ) || |
395 |
( strlen(envvar) == 0 )) { |
396 |
return 1; |
397 |
} |
398 |
rhs = getenv(envvar); |
399 |
if (( rhs == NULL ) || ( strlen(rhs) == 0 )) { |
400 |
return 1; |
401 |
} |
402 |
return Asc_SetPathList(envvar, rhs); |
403 |
} |
404 |
|
405 |
|
406 |
int Asc_AppendPath(char *envvar, char *newelement) |
407 |
{ |
408 |
struct asc_env_t *ev; |
409 |
char *keepname, *keepval; |
410 |
|
411 |
if ((g_env_list == NULL) || |
412 |
(envvar == NULL) || |
413 |
(newelement == NULL) || |
414 |
(strlen(envvar) == 0) || |
415 |
(strlen(newelement) == 0)) { |
416 |
return 1; |
417 |
} |
418 |
ev = FindEnvVar(envvar); |
419 |
if (ev == NULL) { |
420 |
keepname = ascstrdup(envvar); |
421 |
if (keepname == NULL) { |
422 |
return 1; |
423 |
} |
424 |
ev = CreateEnvVar(keepname); |
425 |
if (ev == NULL) { |
426 |
ascfree(keepname); |
427 |
return 1; |
428 |
} |
429 |
AppendEnvVar(g_env_list, ev); |
430 |
} |
431 |
keepval = ascstrdup(newelement); |
432 |
|
433 |
if (keepval == NULL) { |
434 |
return 1; |
435 |
} |
436 |
gl_append_ptr(ev->data, keepval); |
437 |
return 0; |
438 |
} |
439 |
|
440 |
|
441 |
CONST char **Asc_GetPathList(CONST char *envvar, int *argc) |
442 |
{ |
443 |
struct asc_env_t *ev; |
444 |
CONST char **argv; |
445 |
char *tmppos, *val; |
446 |
unsigned long len, c, slen; |
447 |
|
448 |
if ( argc == NULL ) { |
449 |
return NULL; |
450 |
} |
451 |
if (( g_env_list == NULL ) || |
452 |
( envvar == NULL )) { |
453 |
FPRINTF(ASCERR,"G_ENV_LIST IS NULL LOOKING FOR %s\n",envvar); |
454 |
*argc = -1; |
455 |
return NULL; |
456 |
} |
457 |
if ( strlen(envvar) == 0 ) { |
458 |
*argc = 0; |
459 |
return NULL; |
460 |
} |
461 |
ev = FindEnvVar(envvar); |
462 |
if (ev==NULL ) { |
463 |
FPRINTF(ASCERR,"UNABLE TO FINDENVVAR %s\n",envvar); |
464 |
|
465 |
*argc = 0; |
466 |
return NULL; |
467 |
} |
468 |
len = gl_length(ev->data); |
469 |
slen = (len+1)*sizeof(char *); /* space for argv pointers */ |
470 |
for (c = 1; c <= len; c++) { |
471 |
/* space for the values */ |
472 |
slen += (strlen((char *)gl_fetch(ev->data,(unsigned long)c)) +1 ); |
473 |
} |
474 |
argv = ASC_NEW_ARRAY(CONST char *,slen); |
475 |
if ( argv == NULL ) { |
476 |
*argc = -1; |
477 |
return NULL; |
478 |
} |
479 |
tmppos = (char *)argv; |
480 |
tmppos += (len+1)*sizeof(char *); |
481 |
for (c = 1 ; c <= len ; c++) { |
482 |
val = (char *)gl_fetch(ev->data,(unsigned long)c); |
483 |
argv[c-1] = tmppos; |
484 |
while ( *val != '\0' ) { |
485 |
*tmppos++ = *val++; |
486 |
} |
487 |
*tmppos++ = *val; /* include trailing '\0' */ |
488 |
} |
489 |
argv[len] = NULL; |
490 |
*argc = (int)len; |
491 |
return argv; |
492 |
} |
493 |
|
494 |
|
495 |
char *Asc_GetEnv(const char *envvar) |
496 |
{ |
497 |
struct asc_env_t *ev; |
498 |
char *result, *val, *tmppos; |
499 |
unsigned long slen, c, llen; |
500 |
|
501 |
if ((g_env_list == NULL) || |
502 |
(envvar == NULL) || |
503 |
(strlen(envvar) == 0)) { |
504 |
return NULL; |
505 |
} |
506 |
ev = FindEnvVar(envvar); |
507 |
if (ev==NULL ) { |
508 |
return NULL; |
509 |
} |
510 |
slen = 0; |
511 |
llen = gl_length(ev->data); |
512 |
for (c = 1; c <= llen; c++) { |
513 |
slen += (strlen((char *)gl_fetch(ev->data,(unsigned long)c)) +1 ); |
514 |
} |
515 |
result = ASC_NEW_ARRAY(char,slen+1); |
516 |
if (result == NULL) { |
517 |
return NULL; |
518 |
} |
519 |
tmppos = result; |
520 |
for (c = 1; c <= llen; c++) { |
521 |
val = (char *)gl_fetch(ev->data,(unsigned long)c); |
522 |
while (*val != '\0') { |
523 |
*tmppos++ = *val++; |
524 |
} |
525 |
*tmppos++ = PATHDIV; /* include delimiter */ |
526 |
} |
527 |
result[slen-1] = '\0'; /* overwrite final trailing delimiter */ |
528 |
return result; |
529 |
} |
530 |
|
531 |
|
532 |
const char **Asc_EnvNames(int *argc) |
533 |
{ |
534 |
const char **argv; |
535 |
unsigned long c, len; |
536 |
|
537 |
if (g_env_list == NULL) { |
538 |
*argc = -1; |
539 |
return NULL; |
540 |
} |
541 |
len = gl_length(g_env_list); |
542 |
*argc = (int)len; |
543 |
argv = ASC_NEW_ARRAY(CONST char *,*argc + 1); |
544 |
if (argv==NULL) { |
545 |
*argc = -1; |
546 |
return NULL; |
547 |
} |
548 |
for (c = 1; c <= len; c++) { |
549 |
argv[c-1] = ((struct asc_env_t *)gl_fetch(g_env_list,c))->name; |
550 |
} |
551 |
argv[len] = NULL; |
552 |
return argv; |
553 |
} |