1 /*!
2 \file lib/gis/env.c
3
4 \brief GIS library - environment routines
5
6 (C) 2001-2014 by the GRASS Development Team
7
8 This program is free software under the GNU General Public License
9 (>=v2). Read the file COPYING that comes with GRASS for details.
10
11 \author Original author CERL
12 \author Updated for GRASS7 by Glynn Clements
13 */
14
15 #include <signal.h>
16 #include <unistd.h>
17 #include <stdlib.h>
18 #include <unistd.h> /* for sleep() */
19 #include <string.h>
20 #include <grass/gis.h>
21 #include <grass/glocale.h>
22
23 struct bind {
24 int loc;
25 char *name;
26 char *value;
27 };
28
29 struct env {
30 struct bind *binds;
31 int count;
32 int size;
33 };
34
35 static struct state {
36 struct env env;
37 struct env env2;
38 char *gisrc;
39 int varmode;
40 int init[2];
41 } state;
42
43 static struct state *st = &state;
44
45 static int read_env(int);
46 static int set_env(const char *, const char *, int);
47 static int unset_env(const char *, int);
48 static const char *get_env(const char *, int);
49 static void write_env(int);
50 static void parse_env(FILE *, int);
51 static void force_read_env(int);
52 static FILE *open_env(const char *, int);
53
54 /*!
55 \brief Set where to find/store variables
56
57 Modes:
58 - G_GISRC_MODE_FILE
59 - G_GISRC_MODE_MEMORY
60
61 \param mode mode to find/store variables (G_GISRC_MODE_FILE by default)
62 */
G_set_gisrc_mode(int mode)63 void G_set_gisrc_mode(int mode)
64 {
65 st->varmode = mode;
66 }
67
68 /*!
69 \brief Get info where variables are stored
70
71 \return mode
72 */
G_get_gisrc_mode(void)73 int G_get_gisrc_mode(void)
74 {
75 return (st->varmode);
76 }
77
78 /*!
79 \brief Initialize variables
80
81 \return
82 */
G_init_env(void)83 void G_init_env(void)
84 {
85 read_env(G_VAR_GISRC);
86 read_env(G_VAR_MAPSET);
87 }
88
89 /*!
90 * \brief Force to read the mapset environment file VAR
91 *
92 * The mapset specific VAR file of the mapset set with G_setenv()
93 * will be read into memory, ignoring if it was readed before.
94 * Existing values will be overwritten, new values appended.
95 *
96 * \return
97 */
G__read_mapset_env(void)98 void G__read_mapset_env(void)
99 {
100 force_read_env(G_VAR_MAPSET);
101 }
102
103 /*!
104 * \brief Force to read the GISRC environment file
105 *
106 * The GISRC file
107 * will be read into memory, ignoring if it was readed before.
108 * Existing values will be overwritten, new values appended.
109 *
110 * \return
111 */
G__read_gisrc_env(void)112 void G__read_gisrc_env(void)
113 {
114 force_read_env(G_VAR_GISRC);
115 }
116
parse_env(FILE * fd,int loc)117 static void parse_env(FILE *fd, int loc)
118 {
119 /* Account for long lines up to GPATH_MAX.
120 E.g. "GISDBASE: GPATH_MAX\n\0" */
121 char buf[GPATH_MAX + 16];
122 char *name;
123 char *value;
124
125 while (G_getl2(buf, sizeof buf, fd)) {
126 for (name = value = buf; *value; value++)
127 if (*value == ':')
128 break;
129 if (*value == 0)
130 continue;
131
132 *value++ = 0;
133 G_strip(name);
134 G_strip(value);
135 if (*name && *value)
136 set_env(name, value, loc);
137 }
138 }
139
read_env(int loc)140 static int read_env(int loc)
141 {
142
143 FILE *fd;
144
145 if (loc == G_VAR_GISRC && st->varmode == G_GISRC_MODE_MEMORY)
146 return 0; /* don't use file for GISRC */
147
148 if (G_is_initialized(&st->init[loc]))
149 return 1;
150
151 if ((fd = open_env("r", loc))) {
152 parse_env(fd, loc);
153 fclose(fd);
154 }
155
156 G_initialize_done(&st->init[loc]);
157 return 0;
158 }
159
160 /*!
161 * \brief Force the reading or the GISRC or MAPSET/VAR files
162 * and overwrite/append the specified variables
163 *
164 */
force_read_env(int loc)165 static void force_read_env(int loc)
166 {
167 FILE *fd;
168 if ((fd = open_env("r", loc))) {
169 parse_env(fd, loc);
170 fclose(fd);
171 }
172 }
173
174
set_env(const char * name,const char * value,int loc)175 static int set_env(const char *name, const char *value, int loc)
176 {
177 int n;
178 int empty;
179 char *tv;
180
181 /* if value is NULL or empty string, convert into an unsetenv() */
182 if (!value || !strlen(value)) {
183 unset_env(name, loc);
184 return 0;
185 }
186
187 tv = G_store(value);
188 G_strip(tv);
189 if (*tv == 0) {
190 G_free(tv);
191 unset_env(name, loc);
192 return 1;
193 }
194
195 /*
196 * search the array
197 * keep track of first empty slot
198 * and look for name in the environment
199 */
200 empty = -1;
201 for (n = 0; n < st->env.count; n++) {
202 struct bind *b = &st->env.binds[n];
203 if (!b->name) /* mark empty slot found */
204 empty = n;
205 else if (strcmp(b->name, name) == 0 && b->loc == loc) {
206 b->value = tv;
207 return 1;
208 }
209 }
210
211 /* add name to env: to empty slot if any */
212 if (empty >= 0) {
213 struct bind *b = &st->env.binds[empty];
214 b->loc = loc;
215 b->name = G_store(name);
216 b->value = tv;
217 return 0;
218 }
219
220 /* must increase the env list and add in */
221 if (st->env.count >= st->env.size) {
222 st->env.size += 20;
223 st->env.binds = G_realloc(st->env.binds, st->env.size * sizeof(struct bind));
224 }
225
226 {
227 struct bind *b = &st->env.binds[st->env.count++];
228
229 b->loc = loc;
230 b->name = G_store(name);
231 b->value = tv;
232 }
233
234 return 0;
235 }
236
unset_env(const char * name,int loc)237 static int unset_env(const char *name, int loc)
238 {
239 int n;
240
241 for (n = 0; n < st->env.count; n++) {
242 struct bind *b = &st->env.binds[n];
243 if (b->name && strcmp(b->name, name) == 0 && b->loc == loc) {
244 G_free(b->name);
245 b->name = 0;
246 return 1;
247 }
248 }
249
250 return 0;
251 }
252
get_env(const char * name,int loc)253 static const char *get_env(const char *name, int loc)
254 {
255 int n;
256
257 for (n = 0; n < st->env.count; n++) {
258 struct bind *b = &st->env.binds[n];
259 if (b->name && (strcmp(b->name, name) == 0) &&
260 b->loc == loc)
261 return b->value;
262 }
263
264 return NULL;
265 }
266
write_env(int loc)267 static void write_env(int loc)
268 {
269 FILE *fd;
270 int n;
271 char dummy[2];
272 void (*sigint)(int);
273 #ifdef SIGQUIT
274 void (*sigquit)(int);
275 #endif
276
277 if (loc == G_VAR_GISRC && st->varmode == G_GISRC_MODE_MEMORY)
278 return; /* don't use file for GISRC */
279
280 /*
281 * THIS CODE NEEDS TO BE PROTECTED FROM INTERRUPTS
282 * If interrupted, it can wipe out the GISRC file
283 */
284 sigint = signal(SIGINT, SIG_IGN);
285 #ifdef SIGQUIT
286 sigquit = signal(SIGQUIT, SIG_IGN);
287 #endif
288 if ((fd = open_env("w", loc))) {
289 for (n = 0; n < st->env.count; n++) {
290 struct bind *b = &st->env.binds[n];
291 if (b->name && b->value && b->loc == loc
292 && (sscanf(b->value, "%1s", dummy) == 1))
293 fprintf(fd, "%s: %s\n", b->name, b->value);
294 }
295 fclose(fd);
296 }
297
298 signal(SIGINT, sigint);
299 #ifdef SIGQUIT
300 signal(SIGQUIT, sigquit);
301 #endif
302 }
303
open_env(const char * mode,int loc)304 static FILE *open_env(const char *mode, int loc)
305 {
306 char buf[GPATH_MAX];
307
308 if (loc == G_VAR_GISRC) {
309 if (!st->gisrc)
310 st->gisrc = getenv("GISRC");
311
312 if (!st->gisrc) {
313 G_fatal_error(_("GISRC - variable not set"));
314 return NULL;
315 }
316 strcpy(buf, st->gisrc);
317 }
318 else if (loc == G_VAR_MAPSET) {
319 /* Warning: G_VAR_GISRC must be previously read -> */
320 /* TODO: better place ? */
321 read_env(G_VAR_GISRC);
322
323 sprintf(buf, "%s/%s/VAR", G_location_path(), G_mapset());
324 }
325
326 return fopen(buf, mode);
327 }
328
329 /*!
330 \brief Get environment variable
331
332 G_fatal_error() is called when variable is not found.
333
334 \param name variable name
335
336 \return char pointer to value for name
337 */
G_getenv(const char * name)338 const char *G_getenv(const char *name)
339 {
340 const char *value = G_getenv_nofatal(name);
341
342 if (value)
343 return value;
344
345 G_fatal_error(_("Variable '%s' not set"), name);
346 return NULL;
347 }
348
349 /*!
350 \brief Get variable from specific place
351
352 Locations:
353 - G_VAR_GISRC
354 - G_VAR_MAPSET
355
356 G_fatal_error() is called when variable is not found.
357
358 \param name variable name
359 \param loc location (G_VAR_GISRC, G_VAR_MAPSET)
360
361 \return variable value
362 \return NULL if not found
363 */
G_getenv2(const char * name,int loc)364 const char *G_getenv2(const char *name, int loc)
365 {
366 const char *value = G_getenv_nofatal2(name, loc);
367
368 if (value)
369 return value;
370
371 G_fatal_error(_("Variable '%s' not set"), name);
372 return NULL;
373 }
374
375 /*!
376 \brief Get environment variable
377
378 \param name variable name
379
380 \return char pointer to value for name
381 \return NULL if name not set
382 */
G_getenv_nofatal(const char * name)383 const char *G_getenv_nofatal(const char *name)
384 {
385 if (strcmp(name, "GISBASE") == 0)
386 return getenv(name);
387
388 read_env(G_VAR_GISRC);
389
390 return get_env(name, G_VAR_GISRC);
391 }
392
393 /*!
394 \brief Get environment variable from specific place
395
396 \param name variable name
397 \param loc location (G_VAR_GISRC, G_VAR_MAPSET)
398
399 \return char pointer to value for name
400 \return NULL if name not set
401 */
G_getenv_nofatal2(const char * name,int loc)402 const char *G_getenv_nofatal2(const char *name, int loc)
403 {
404 if (strcmp(name, "GISBASE") == 0)
405 return getenv(name);
406
407 read_env(loc);
408
409 return get_env(name, loc);
410 }
411
412 /*!
413 \brief Set environment variable (updates .gisrc)
414
415 If value is NULL, becomes an G_unsetenv().
416
417 \param name variable name
418 \param value variable value
419 */
G_setenv(const char * name,const char * value)420 void G_setenv(const char *name, const char *value)
421 {
422 read_env(G_VAR_GISRC);
423 set_env(name, value, G_VAR_GISRC);
424 write_env(G_VAR_GISRC);
425 }
426
427 /*!
428 \brief Set environment variable from specific place (updates .gisrc)
429
430 If value is NULL, becomes an G_unsetenv().
431
432 \param name variable name
433 \param value variable value
434 \param loc location (G_VAR_GISRC, G_VAR_MAPSET)
435
436 */
G_setenv2(const char * name,const char * value,int loc)437 void G_setenv2(const char *name, const char *value, int loc)
438 {
439 read_env(loc);
440 set_env(name, value, loc);
441 write_env(loc);
442 }
443
444 /*!
445 \brief Set environment name to value (doesn't update .gisrc)
446
447 \param name variable name
448 \param value variable value
449 */
G_setenv_nogisrc(const char * name,const char * value)450 void G_setenv_nogisrc(const char *name, const char *value)
451 {
452 read_env(G_VAR_GISRC);
453 set_env(name, value, G_VAR_GISRC);
454 }
455
456 /*!
457 \brief Set environment name to value from specific place (doesn't update .gisrc)
458
459 \param name variable name
460 \param value variable value
461 \param loc location (G_VAR_GISRC, G_VAR_MAPSET)
462 */
G_setenv_nogisrc2(const char * name,const char * value,int loc)463 void G_setenv_nogisrc2(const char *name, const char *value, int loc)
464 {
465 read_env(loc);
466 set_env(name, value, loc);
467 }
468
469 /*!
470 \brief Remove name from environment
471
472 Updates .gisrc
473
474 \param name variable name
475 */
G_unsetenv(const char * name)476 void G_unsetenv(const char *name)
477 {
478 read_env(G_VAR_GISRC);
479 unset_env(name, G_VAR_GISRC);
480 write_env(G_VAR_GISRC);
481 }
482
483 /*!
484 \brief Remove name from environment from specific place
485
486 Updates .gisrc
487
488 \param name variable name
489 \param loc location (G_VAR_GISRC, G_VAR_MAPSET)
490 */
G_unsetenv2(const char * name,int loc)491 void G_unsetenv2(const char *name, int loc)
492 {
493 read_env(loc);
494 unset_env(name, loc);
495 write_env(loc);
496 }
497
498 /*!
499 \brief Writes current environment to .gisrc
500 */
G__write_env(void)501 void G__write_env(void)
502 {
503 if (st->init[G_VAR_GISRC])
504 write_env(G_VAR_GISRC);
505 }
506
507 /*!
508 \brief Get variable name for index n.
509
510 For example:
511
512 \code
513 for (n = 0; ; n++)
514 if ((name = G_get_env_name(n)) == NULL)
515 break;
516 \endcode
517
518 \param n index of variable
519
520 \return pointer to variable name
521 \return NULL not found
522 */
G_get_env_name(int n)523 const char *G_get_env_name(int n)
524 {
525 int i;
526
527 read_env(G_VAR_GISRC);
528 if (n >= 0)
529 for (i = 0; i < st->env.count; i++)
530 if (st->env.binds[i].name && *st->env.binds[i].name && (n-- == 0))
531 return st->env.binds[i].name;
532 return NULL;
533 }
534
535 /*!
536 \brief Initialize init array for G_VAR_GISRC.
537 */
G__read_env(void)538 void G__read_env(void)
539 {
540 st->init[G_VAR_GISRC] = 0;
541 }
542
543 /*!
544 \brief Set up alternative environment variables
545 */
G_create_alt_env(void)546 void G_create_alt_env(void)
547 {
548 int i;
549
550 /* copy env to env2 */
551 st->env2 = st->env;
552
553 st->env.count = 0;
554 st->env.size = 0;
555 st->env.binds = NULL;
556
557 for (i = 0; i < st->env2.count; i++) {
558 struct bind *b = &st->env2.binds[i];
559 if (b->name)
560 set_env(b->name, b->value, G_VAR_GISRC);
561 }
562 }
563
564 /*!
565 \brief Switch environments
566 */
G_switch_env(void)567 void G_switch_env(void)
568 {
569 struct env tmp;
570
571 tmp = st->env;
572 st->env = st->env2;
573 st->env2 = tmp;
574 }
575