aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2019-06-02 07:40:11 +0300
committerSergey Poznyakoff <gray@gnu.org>2019-06-02 08:03:16 +0300
commitcc298a11a131b162f291d6ee27ba1d7598a1b6c4 (patch)
tree4d82a9a5da05fbfdce0c9bf03e605ecf00baa07a
parent1f28935841a69aa8be7eb2e88f580df9c95206d2 (diff)
downloadpies-cc298a11a131b162f291d6ee27ba1d7598a1b6c4.tar.gz
pies-cc298a11a131b162f291d6ee27ba1d7598a1b6c4.tar.bz2
New configuration statement for manipulating the environment.
The "env" statement is now a compound statement. It can contain four substatements: "clear" to clear the environment, "keep" to retain certain variable while clearing it, "set" to set a variable, and "unset" to unset a variable or variables. Both "keep" and "unset" can take globbing pattern as their argument, in which case they affect all variable matching that pattern. The value part in the "set" statement is subject to variable expansion, e.g. set "MANPATH=$MANPATH${MANPATH:+:}/usr/local/man" The support for the old one-line syntax of "env" is retained for backward compatibility. This commit also fixes redirection to a file: new data are appended to the file, instead of overwriting it. * lib/Makefile.am: Add new files. * lib/envop.c: New file. * lib/envop.h: New file. * lib/wildmatch.c: New file. * src/comp.c (component_free): Update. * src/pies.c (argv_free): New function. (parse_legacy_env): New function. (_cb_env): Remove. (cb_env_section_parser): New function. (cb_env_keywords): New keywords for the "env" block statement: clear, keep, set, unset. (component_keywords): New compount statement: env. Old usage retained for backward compatibility. * src/pies.h: Include "envop.h" (component)<env>: Remove. <envop>: New field. * src/prog.h (prog)<env>: New field. * src/progman.c (redirect_to_file): Position to the end of file. (DEBUG_ENVIRON): Remove macro. (debug_environ): New function. (environ_setup): Remove. (prog_sockenv): Use environ_set to modify local copy of environment. (prog_start_prologue): Use environ_create + envop_exec to create and modify the environment. (prog_execute): Set environment to prog-local copy. * tests/.gitignore: Build envtest * tests/Makefile.am: Add new tests. * tests/testsuite.at: Add environment tests. * tests/envop.at: New file. * tests/envtest.c: New file. * tests/env.at: New file. * tests/redirect.at: Check first two lines of the output file.
-rw-r--r--lib/Makefile.am5
-rw-r--r--lib/envop.c484
-rw-r--r--lib/envop.h68
-rw-r--r--lib/wildmatch.c140
-rw-r--r--src/comp.c16
-rw-r--r--src/pies.c278
-rw-r--r--src/pies.h5
-rw-r--r--src/prog.h1
-rw-r--r--src/progman.c310
-rw-r--r--tests/.gitignore1
-rw-r--r--tests/Makefile.am11
-rw-r--r--tests/env.at65
-rw-r--r--tests/envop.at101
-rw-r--r--tests/envtest.c209
-rw-r--r--tests/redirect.at2
-rw-r--r--tests/testsuite.at3
16 files changed, 1410 insertions, 289 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 4aa9d3e..7b4eb42 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -21,6 +21,8 @@ noinst_HEADERS = libpies.h grecsasrt.h
21libpies_a_SOURCES=\ 21libpies_a_SOURCES=\
22 addrfmt.c\ 22 addrfmt.c\
23 arraymember.c\ 23 arraymember.c\
24 envop.c\
25 envop.h\
24 grecsasrt.c\ 26 grecsasrt.c\
25 mkfilename.c\ 27 mkfilename.c\
26 netrc.c\ 28 netrc.c\
@@ -30,7 +32,8 @@ libpies_a_SOURCES=\
30 safe_strcmp.c\ 32 safe_strcmp.c\
31 split3.c\ 33 split3.c\
32 strtotok.c\ 34 strtotok.c\
33 url.c 35 url.c\
36 wildmatch.c
34 37
35libpies_a_LIBADD=\ 38libpies_a_LIBADD=\
36 $(LIBOBJS)\ 39 $(LIBOBJS)\
diff --git a/lib/envop.c b/lib/envop.c
new file mode 100644
index 0000000..79083f7
--- /dev/null
+++ b/lib/envop.c
@@ -0,0 +1,484 @@
1/* Environment modification functions for GNU Pies.
2 Copyright (C) 2019 Sergey Poznyakoff
3
4 GNU Pies is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 GNU Pies is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with GNU Pies. If not, see <http://www.gnu.org/licenses/>. */
16
17#ifdef HAVE_CONFIG_H
18# include <config.h>
19#endif
20#include <stdlib.h>
21#include <string.h>
22#include <errno.h>
23#include <ctype.h>
24#include "envop.h"
25#include "wordsplit.h"
26
27environ_t *
28environ_create (char **def)
29{
30 size_t i;
31 environ_t *env = malloc (sizeof (*env));
32
33 if (!env)
34 return NULL;
35
36 if (!def)
37 {
38 static char *nullenv[] = { NULL };
39 def = nullenv;
40 }
41
42 for (i = 0; def[i]; i++)
43 ;
44 env->env_count = 0;
45 env->env_max = i + 1;
46 env->env_base = calloc (env->env_max, sizeof (env->env_base[0]));
47 if (!env->env_base)
48 {
49 free (env);
50 return NULL;
51 }
52
53 for (i = 0; def[i]; i++)
54 {
55 if (!(env->env_base[i] = strdup (def[i])))
56 {
57 environ_free (env);
58 return NULL;
59 }
60 env->env_count++;
61 }
62 env->env_base[i] = NULL;
63 return env;
64}
65
66void
67environ_free (environ_t *env)
68{
69 size_t i;
70 for (i = 0; i < env->env_count; i++)
71 free (env->env_base[i]);
72 free (env->env_base);
73}
74
75static ssize_t
76getenvind (environ_t *env, char const *name, char **pval)
77{
78 size_t i;
79
80 for (i = 0; i < env->env_count; i++)
81 {
82 char const *p;
83 char *q;
84
85 for (p = name, q = env->env_base[i]; *p == *q; p++, q++)
86 if (*p == '=')
87 break;
88 if ((*p == 0 || *p == '=') && *q == '=')
89 {
90 if (pval)
91 *pval = q + 1;
92 return i;
93 }
94 }
95 return -1;
96}
97
98static ssize_t
99environ_alloc (environ_t *env)
100{
101 size_t n;
102 if (env->env_count + 1 >= env->env_max)
103 {
104 char **p;
105 if (env->env_base == NULL)
106 {
107 n = 64;
108 p = calloc (n, sizeof (p[0]));
109 if (!p)
110 return -1;
111 }
112 else
113 {
114 n = env->env_max;
115 if ((size_t) -1 / 3 * 2 / sizeof (p[0]) <= n)
116 {
117 errno = ENOMEM;
118 return -1;
119 }
120 n += (n + 1) / 2;
121 p = realloc (env->env_base, n * sizeof (p[0]));
122 if (!p)
123 return -1;
124 }
125 env->env_base = p;
126 env->env_max = n;
127 }
128 n = env->env_count++;
129 env->env_base[env->env_count] = NULL;
130 return n;
131}
132
133static int
134environ_add_alloced (environ_t *env, char *def)
135{
136 ssize_t n;
137 n = getenvind (env, def, NULL);
138 if (n == -1)
139 {
140 n = environ_alloc (env);
141 if (n == -1)
142 return -1;
143 }
144 free (env->env_base[n]);
145 env->env_base[n] = def;
146 return 0;
147}
148
149int
150environ_add (environ_t *env, char const *def)
151{
152 char *defcp = strdup (def);
153 if (!defcp)
154 return -1;
155 if (environ_add_alloced (env, defcp))
156 {
157 free (defcp);
158 return -1;
159 }
160 return 0;
161}
162
163int
164environ_set (environ_t *env, char const *name, char const *value)
165{
166 size_t len;
167 char *def;
168 struct wordsplit ws;
169
170 if (!name)
171 {
172 errno = EINVAL;
173 return -1;
174 }
175 if (!value)
176 return environ_unset (env, name);
177
178 ws.ws_env = (char const **) env->env_base;
179 if (wordsplit (value, &ws,
180 WRDSF_NOSPLIT
181 | WRDSF_QUOTE
182 | WRDSF_NOCMD /* FIXME */
183 | WRDSF_SQUEEZE_DELIMS
184 | WRDSF_CESCAPES
185 | WRDSF_ENV
186 | WRDSF_PATHEXPAND))
187 {
188 int ec = errno;
189 if (ws.ws_errno != WRDSE_USAGE) /* FIXME */
190 wordsplit_free (&ws);
191 errno = ec;
192 return -1;
193 }
194
195 if (strcmp (name, ":") == 0)
196 {
197 wordsplit_free (&ws);
198 return 0;
199 }