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