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