GRASS GIS 8 Programmer's Manual  8.4.0dev(2024)-f13a4924e1
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-2024 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 {
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 
134 static 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 
157 static 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  */
182 static 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 
192 static 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 
257 static 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 
274 static 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 
288 static 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 
327 static 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  */
360 const 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  */
386 const 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  */
405 const 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  */
424 const 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  */
442 void 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  */
459 void 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  */
472 void 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  */
486 void 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  */
499 void 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  */
514 void 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  */
524 void 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  */
546 const 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  */
561 void 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  */
591 void 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 init(double work[])
Definition: as177.c:61
#define NULL
Definition: ccmath.h:32
int G_getl2(char *, int, FILE *)
Gets a line of text from a file of any pedigree.
Definition: getl.c:65
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:150
#define G_realloc(p, n)
Definition: defs/gis.h:96
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
const char * G_mapset(void)
Get current mapset name.
Definition: gis/mapset.c:33
void G_strip(char *)
Removes all leading and trailing white space from string.
Definition: strings.c:300
char * G_location_path(void)
Get current location UNIX-like path.
Definition: location.c:54
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:87
void G_setenv(const char *name, const char *value)
Set environment variable (updates .gisrc)
Definition: env.c:442
void G_switch_env(void)
Switch environments.
Definition: env.c:591
const char * G_get_env_name(int n)
Get variable name for index n.
Definition: env.c:546
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_nofatal2(const char *name, int loc)
Get environment variable from specific place.
Definition: env.c:424
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
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
void G__read_gisrc_path(void)
Read or read again the GISRC (session) environment variable.
Definition: env.c:125
const char * G_getenv_nofatal(const char *name)
Get environment variable.
Definition: env.c:405
void G_init_env(void)
Initialize variables.
Definition: env.c:83
const char * G_getenv2(const char *name, int loc)
Get variable from specific place.
Definition: env.c:386
const char * G_getenv(const char *name)
Get environment variable.
Definition: env.c:360
#define G_VAR_GISRC
Definition: gis.h:176
#define G_VAR_MAPSET
Definition: gis.h:177
#define GPATH_MAX
Definition: gis.h:194
#define G_GISRC_MODE_MEMORY
Definition: gis.h:181
#define _(str)
Definition: glocale.h:10
int count
const char * name
Definition: named_colr.c:6
struct state state
Definition: parser.c:103
struct state * st
Definition: parser.c:104
#define strcpy
Definition: parson.c:62
double b
Definition: r_raster.c:39