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