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