diff options
-rw-r--r-- | NEWS | 8 | ||||
-rw-r--r-- | doc/pies.texi | 15 | ||||
-rw-r--r-- | lib/envop.c | 51 | ||||
-rw-r--r-- | src/pies.c | 22 |
4 files changed, 77 insertions, 19 deletions
@@ -1,4 +1,4 @@ | |||
1 | GNU Pies NEWS -- history of user-visible changes. 2019-06-06 | 1 | GNU Pies NEWS -- history of user-visible changes. 2019-06-07 |
2 | See the end of file for copying conditions. | 2 | See the end of file for copying conditions. |
3 | 3 | ||
4 | Please send Pies bug reports to <bug-pies@gnu.org> or | 4 | Please send Pies bug reports to <bug-pies@gnu.org> or |
@@ -55,6 +55,12 @@ variables matching the pattern are retained. | |||
55 | Sets the environment variable for the component. VALUE is subject | 55 | Sets the environment variable for the component. VALUE is subject |
56 | to variable expansion. | 56 | to variable expansion. |
57 | 57 | ||
58 | ** eval "VALUE" | ||
59 | Perform variable expansion on VALUE and discard the result (similar | ||
60 | to the shell ":" command). Useful for side effects, e.g.: | ||
61 | |||
62 | eval ${HOME:=/home/t} | ||
63 | |||
58 | ** unset NAME | 64 | ** unset NAME |
59 | Unsets the variable. NAME can be a globbing pattern, in which case all | 65 | Unsets the variable. NAME can be a globbing pattern, in which case all |
60 | variables matching the pattern are unset. | 66 | variables matching the pattern are unset. |
diff --git a/doc/pies.texi b/doc/pies.texi index 63064e5..4bd2f8f 100644 --- a/doc/pies.texi +++ b/doc/pies.texi | |||
@@ -1064,6 +1064,7 @@ env @{ | |||
1064 | clear; | 1064 | clear; |
1065 | keep @var{pattern}; | 1065 | keep @var{pattern}; |
1066 | set "@var{name}=@var{value}"; | 1066 | set "@var{name}=@var{value}"; |
1067 | eval "@var{value}"; | ||
1067 | unset @var{pattern}; | 1068 | unset @var{pattern}; |
1068 | @} | 1069 | @} |
1069 | @end group | 1070 | @end group |
@@ -1123,6 +1124,20 @@ env @{ | |||
1123 | @end example | 1124 | @end example |
1124 | @end deffn | 1125 | @end deffn |
1125 | 1126 | ||
1127 | @deffn {env} eval "@var{value}" | ||
1128 | Perform variable expansion on @var{value} and discard the result. This | ||
1129 | is useful for side-effects. For example, to provide default value for | ||
1130 | the @env{LD_LIBRARY_PATH} variable, one may write: | ||
1131 | |||
1132 | @example | ||
1133 | @group | ||
1134 | env @{ | ||
1135 | eval "$@{LD_LIBRARY_PATH:=/usr/local/lib@}"; | ||
1136 | @} | ||
1137 | @end group | ||
1138 | @end example | ||
1139 | @end deffn | ||
1140 | |||
1126 | @deffn {env} unset @var{pattern} | 1141 | @deffn {env} unset @var{pattern} |
1127 | Unset environment variables matching @var{pattern}. The following | 1142 | Unset environment variables matching @var{pattern}. The following |
1128 | will unset the @env{LOGIN} variable: | 1143 | will unset the @env{LOGIN} variable: |
diff --git a/lib/envop.c b/lib/envop.c index ce24b92..93bd425 100644 --- a/lib/envop.c +++ b/lib/envop.c | |||
@@ -167,13 +167,15 @@ environ_set (environ_t *env, char const *name, char const *value) | |||
167 | char *def; | 167 | char *def; |
168 | struct wordsplit ws; | 168 | struct wordsplit ws; |
169 | 169 | ||
170 | if (!name) | 170 | if (!value) |
171 | { | 171 | { |
172 | errno = EINVAL; | 172 | if (!name) |
173 | return -1; | 173 | { |
174 | errno = EINVAL; | ||
175 | return -1; | ||
176 | } | ||
177 | return environ_unset (env, name, value); | ||
174 | } | 178 | } |
175 | if (!value) | ||
176 | return environ_unset (env, name, value); | ||
177 | 179 | ||
178 | ws.ws_env = (char const **) env->env_base; | 180 | ws.ws_env = (char const **) env->env_base; |
179 | if (wordsplit (value, &ws, | 181 | if (wordsplit (value, &ws, |
@@ -191,7 +193,18 @@ environ_set (environ_t *env, char const *name, char const *value) | |||
191 | return -1; | 193 | return -1; |
192 | } | 194 | } |
193 | 195 | ||
194 | if (strcmp (name, ":") == 0) | 196 | if (ws.ws_envbuf) |
197 | { | ||
198 | free (env->env_base); | ||
199 | env->env_base = ws.ws_envbuf; | ||
200 | env->env_count = ws.ws_envidx; | ||
201 | env->env_max = ws.ws_envsiz; | ||
202 | ws.ws_envbuf = NULL; | ||
203 | ws.ws_envidx = 0; | ||
204 | ws.ws_envsiz = 0; | ||
205 | } | ||
206 | |||
207 | if (name == NULL || strcmp (name, ":") == 0) | ||
195 | { | 208 | { |
196 | wordsplit_free (&ws); | 209 | wordsplit_free (&ws); |
197 | return 0; | 210 | return 0; |
@@ -334,6 +347,7 @@ envop_entry_add (struct envop_entry **head, | |||
334 | { | 347 | { |
335 | struct envop_entry *op; | 348 | struct envop_entry *op; |
336 | size_t s; | 349 | size_t s; |
350 | char *p; | ||
337 | 351 | ||
338 | switch (code) | 352 | switch (code) |
339 | { | 353 | { |
@@ -341,7 +355,7 @@ envop_entry_add (struct envop_entry **head, | |||
341 | break; | 355 | break; |
342 | 356 | ||
343 | case envop_set: | 357 | case envop_set: |
344 | if (!name || !(*name == ':' || valid_envar_name (name))) | 358 | if (name && !(*name == ':' || valid_envar_name (name))) |
345 | { | 359 | { |
346 | errno = EINVAL; | 360 | errno = EINVAL; |
347 | return -1; | 361 | return -1; |
@@ -359,11 +373,9 @@ envop_entry_add (struct envop_entry **head, | |||
359 | 373 | ||
360 | s = sizeof (op[0]); | 374 | s = sizeof (op[0]); |
361 | if (name) | 375 | if (name) |
362 | { | 376 | s += strlen (name) + 1; |
363 | s += strlen (name) + 1; | 377 | if (value) |
364 | if (value) | 378 | s += strlen (value) + 1; |
365 | s += strlen (value) + 1; | ||
366 | } | ||
367 | op = malloc (s); | 379 | op = malloc (s); |
368 | if (!op) | 380 | if (!op) |
369 | return -1; | 381 | return -1; |
@@ -371,15 +383,18 @@ envop_entry_add (struct envop_entry **head, | |||
371 | op->code = code; | 383 | op->code = code; |
372 | op->name = NULL; | 384 | op->name = NULL; |
373 | op->value = NULL; | 385 | op->value = NULL; |
386 | |||
387 | p = (char*)(op + 1); | ||
374 | if (name) | 388 | if (name) |
375 | { | 389 | { |
376 | op->name = (char*)(op + 1); | 390 | op->name = p; |
377 | strcpy (op->name, name); | 391 | strcpy (op->name, name); |
378 | if (value) | 392 | p += strlen (name) + 1; |
379 | { | 393 | } |
380 | op->value = op->name + strlen (name) + 1; | 394 | if (value) |
381 | strcpy (op->value, value); | 395 | { |
382 | } | 396 | op->value = p; |
397 | strcpy (op->value, value); | ||
383 | } | 398 | } |
384 | envop_entry_insert (head, op); | 399 | envop_entry_insert (head, op); |
385 | return 0; | 400 | return 0; |
@@ -786,6 +786,22 @@ _cb_env_set (enum grecs_callback_command cmd, | |||
786 | } | 786 | } |
787 | 787 | ||
788 | static int | 788 | static int |
789 | _cb_env_eval (enum grecs_callback_command cmd, | ||
790 | grecs_node_t *node, | ||
791 | void *varptr, void *cb_data) | ||
792 | { | ||
793 | grecs_locus_t *locus = &node->locus; | ||
794 | grecs_value_t *value = node->v.value; | ||
795 | struct component *comp = varptr; | ||
796 | |||
797 | if (grecs_assert_node_value_type (cmd, node, GRECS_TYPE_STRING)) | ||
798 | return 1; | ||
799 | if (envop_entry_add (&comp->envop, envop_set, NULL, value->v.string)) | ||
800 | grecs_error (locus, errno, "envop_entry_add"); | ||
801 | return 0; | ||
802 | } | ||
803 | |||
804 | static int | ||
789 | _cb_env_unset (enum grecs_callback_command cmd, | 805 | _cb_env_unset (enum grecs_callback_command cmd, |
790 | grecs_node_t *node, | 806 | grecs_node_t *node, |
791 | void *varptr, void *cb_data) | 807 | void *varptr, void *cb_data) |
@@ -825,6 +841,12 @@ struct grecs_keyword cb_env_keywords[] = { | |||
825 | grecs_type_string, GRECS_DFLT, | 841 | grecs_type_string, GRECS_DFLT, |
826 | NULL, 0, | 842 | NULL, 0, |
827 | _cb_env_set }, | 843 | _cb_env_set }, |
844 | { "eval", | ||
845 | N_("string"), | ||
846 | N_("Evaluate string. Useful for side-effects, e.g. eval ${X:=2}."), | ||
847 | grecs_type_string, GRECS_DFLT, | ||
848 | NULL, 0, | ||
849 | _cb_env_eval }, | ||
828 | { "unset", | 850 | { "unset", |
829 | N_("name"), | 851 | N_("name"), |
830 | N_("Unset environment variable. Name can contain wildcards."), | 852 | N_("Unset environment variable. Name can contain wildcards."), |