GRASS GIS 8 Programmer's Manual  8.2.2dev(2023)-3d2c704037
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-2023 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 */
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 */
74 {
75  return (st->varmode);
76 }
77 
78 /*!
79  \brief Initialize variables
80 
81  \return
82 */
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  */
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 
133 static 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 
156 static 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  */
181 static 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 
191 static 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 
253 static 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 
269 static 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 
283 static 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 
320 static 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 */
353 const 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 */
379 const 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 */
398 const 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 */
417 const 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 */
435 void 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 */
452 void 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 */
465 void 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 */
478 void 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 */
491 void 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 */
506 void 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 */
516 void 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 */
538 const 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 */
553 void 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 */
582 void G_switch_env(void)
583 {
584  struct env tmp;
585 
586  tmp = st->env;
587  st->env = st->env2;
588  st->env2 = tmp;
589 }
int G_getl2(char *, int, FILE *)
Gets a line of text from a file of any pedigree.
Definition: getl.c:64
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
#define G_VAR_GISRC
Definition: gis.h:162
void G__read_gisrc_path()
Read or read again the GISRC (session) environment variable.
Definition: env.c:125
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:149
int count
char * G_location_path(void)
Get current location UNIX-like path.
Definition: location.c:54
void G_strip(char *)
Removes all leading and trailing white space from string.
Definition: strings.c:300
#define NULL
Definition: ccmath.h:32
void G_create_alt_env(void)
Set up alternative environment variables.
Definition: env.c:561
const char * G_get_env_name(int n)
Get variable name for index n.
Definition: env.c:538
void G__read_gisrc_env(void)
Force to read the GISRC environment file.
Definition: env.c:112
void G_initialize_done(int *)
Definition: counter.c:76
void G_setenv2(const char *name, const char *value, int loc)
Set environment variable from specific place (updates .gisrc)
Definition: env.c:452
struct state * st
Definition: parser.c:104
double b
Definition: r_raster.c:39
int G_get_gisrc_mode(void)
Get info where variables are stored.
Definition: env.c:73
void G_unsetenv(const char *name)
Remove name from environment.
Definition: env.c:491
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_setenv_nogisrc(const char *name, const char *value)
Set environment name to value (doesn&#39;t update .gisrc)
Definition: env.c:465
#define GPATH_MAX
Definition: gis.h:180
const char * G_getenv_nofatal2(const char *name, int loc)
Get environment variable from specific place.
Definition: env.c:417
void G_setenv(const char *name, const char *value)
Set environment variable (updates .gisrc)
Definition: env.c:435
int G_is_initialized(int *)
Definition: counter.c:59
const char * G_getenv2(const char *name, int loc)
Get variable from specific place.
Definition: env.c:379
const char * G_mapset(void)
Get current mapset name.
Definition: gis/mapset.c:33
void G_unsetenv2(const char *name, int loc)
Remove name from environment from specific place.
Definition: env.c:506
void G__read_mapset_env(void)
Force to read the mapset environment file VAR.
Definition: env.c:98
void G_init_env(void)
Initialize variables.
Definition: env.c:83
#define G_realloc(p, n)
Definition: defs/gis.h:114
#define _(str)
Definition: glocale.h:10
#define G_GISRC_MODE_MEMORY
Definition: gis.h:167
void G__write_env(void)
Writes current environment to .gisrc.
Definition: env.c:516
char * G_store(const char *)
Copy string to allocated memory.
Definition: strings.c:87
#define G_VAR_MAPSET
Definition: gis.h:163
void G_switch_env(void)
Switch environments.
Definition: env.c:582
const char * name
Definition: named_colr.c:7
char * getenv()
struct state state
Definition: parser.c:103
const char * G_getenv(const char *name)
Get environment variable.
Definition: env.c:353
void init(double work[])
Definition: as177.c:65
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&#39;t update .gisrc)
Definition: env.c:478