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