OSDN Git Service

docs/system: clarify limits of using gdbstub in system emulation
[qmiga/qemu.git] / util / envlist.c
1 #include "qemu/osdep.h"
2 #include "qemu/queue.h"
3 #include "qemu/envlist.h"
4
5 struct envlist_entry {
6     const char *ev_var;            /* actual env value */
7     QLIST_ENTRY(envlist_entry) ev_link;
8 };
9
10 struct envlist {
11     QLIST_HEAD(, envlist_entry) el_entries; /* actual entries */
12     size_t el_count;                        /* number of entries */
13 };
14
15 static int envlist_parse(envlist_t *envlist,
16     const char *env, int (*)(envlist_t *, const char *));
17
18 /*
19  * Allocates new envlist and returns pointer to it.
20  */
21 envlist_t *
22 envlist_create(void)
23 {
24     envlist_t *envlist;
25
26     envlist = g_malloc(sizeof(*envlist));
27
28     QLIST_INIT(&envlist->el_entries);
29     envlist->el_count = 0;
30
31     return (envlist);
32 }
33
34 /*
35  * Releases given envlist and its entries.
36  */
37 void
38 envlist_free(envlist_t *envlist)
39 {
40     struct envlist_entry *entry;
41
42     assert(envlist != NULL);
43
44     while (envlist->el_entries.lh_first != NULL) {
45         entry = envlist->el_entries.lh_first;
46         QLIST_REMOVE(entry, ev_link);
47
48         g_free((char *)entry->ev_var);
49         g_free(entry);
50     }
51     g_free(envlist);
52 }
53
54 /*
55  * Parses comma separated list of set/modify environment
56  * variable entries and updates given enlist accordingly.
57  *
58  * For example:
59  *     envlist_parse(el, "HOME=foo,SHELL=/bin/sh");
60  *
61  * inserts/sets environment variables HOME and SHELL.
62  *
63  * Returns 0 on success, errno otherwise.
64  */
65 int
66 envlist_parse_set(envlist_t *envlist, const char *env)
67 {
68     return (envlist_parse(envlist, env, &envlist_setenv));
69 }
70
71 /*
72  * Parses comma separated list of unset environment variable
73  * entries and removes given variables from given envlist.
74  *
75  * Returns 0 on success, errno otherwise.
76  */
77 int
78 envlist_parse_unset(envlist_t *envlist, const char *env)
79 {
80     return (envlist_parse(envlist, env, &envlist_unsetenv));
81 }
82
83 /*
84  * Parses comma separated list of set, modify or unset entries
85  * and calls given callback for each entry.
86  *
87  * Returns 0 in case of success, errno otherwise.
88  */
89 static int
90 envlist_parse(envlist_t *envlist, const char *env,
91     int (*callback)(envlist_t *, const char *))
92 {
93     char *tmpenv, *envvar;
94     char *envsave = NULL;
95     int ret = 0;
96     assert(callback != NULL);
97
98     if ((envlist == NULL) || (env == NULL))
99         return (EINVAL);
100
101     tmpenv = g_strdup(env);
102     envsave = tmpenv;
103
104     do {
105         envvar = strchr(tmpenv, ',');
106         if (envvar != NULL) {
107             *envvar = '\0';
108         }
109         if ((*callback)(envlist, tmpenv) != 0) {
110             ret = errno;
111             break;
112         }
113         tmpenv = envvar + 1;
114     } while (envvar != NULL);
115
116     g_free(envsave);
117     return ret;
118 }
119
120 /*
121  * Sets environment value to envlist in similar manner
122  * than putenv(3).
123  *
124  * Returns 0 in success, errno otherwise.
125  */
126 int
127 envlist_setenv(envlist_t *envlist, const char *env)
128 {
129     struct envlist_entry *entry = NULL;
130     const char *eq_sign;
131     size_t envname_len;
132
133     if ((envlist == NULL) || (env == NULL))
134         return (EINVAL);
135
136     /* find out first equals sign in given env */
137     if ((eq_sign = strchr(env, '=')) == NULL)
138         return (EINVAL);
139     envname_len = eq_sign - env + 1;
140
141     /*
142      * If there already exists variable with given name
143      * we remove and release it before allocating a whole
144      * new entry.
145      */
146     for (entry = envlist->el_entries.lh_first; entry != NULL;
147         entry = entry->ev_link.le_next) {
148         if (strncmp(entry->ev_var, env, envname_len) == 0)
149             break;
150     }
151
152     if (entry != NULL) {
153         QLIST_REMOVE(entry, ev_link);
154         g_free((char *)entry->ev_var);
155         g_free(entry);
156     } else {
157         envlist->el_count++;
158     }
159
160     entry = g_malloc(sizeof(*entry));
161     entry->ev_var = g_strdup(env);
162     QLIST_INSERT_HEAD(&envlist->el_entries, entry, ev_link);
163
164     return (0);
165 }
166
167 /*
168  * Removes given env value from envlist in similar manner
169  * than unsetenv(3).  Returns 0 in success, errno otherwise.
170  */
171 int
172 envlist_unsetenv(envlist_t *envlist, const char *env)
173 {
174     struct envlist_entry *entry;
175     size_t envname_len;
176
177     if ((envlist == NULL) || (env == NULL))
178         return (EINVAL);
179
180     /* env is not allowed to contain '=' */
181     if (strchr(env, '=') != NULL)
182         return (EINVAL);
183
184     /*
185      * Find out the requested entry and remove
186      * it from the list.
187      */
188     envname_len = strlen(env);
189     for (entry = envlist->el_entries.lh_first; entry != NULL;
190         entry = entry->ev_link.le_next) {
191         if (strncmp(entry->ev_var, env, envname_len) == 0)
192             break;
193     }
194     if (entry != NULL) {
195         QLIST_REMOVE(entry, ev_link);
196         g_free((char *)entry->ev_var);
197         g_free(entry);
198
199         envlist->el_count--;
200     }
201     return (0);
202 }
203
204 /*
205  * Returns given envlist as array of strings (in same form that
206  * global variable environ is).  Caller must free returned memory
207  * by calling g_free for each element and the array.
208  * Returned array and given envlist are not related (no common
209  * references).
210  *
211  * If caller provides count pointer, number of items in array is
212  * stored there.
213  */
214 char **
215 envlist_to_environ(const envlist_t *envlist, size_t *count)
216 {
217     struct envlist_entry *entry;
218     char **env, **penv;
219
220     penv = env = g_new(char *, envlist->el_count + 1);
221
222     for (entry = envlist->el_entries.lh_first; entry != NULL;
223         entry = entry->ev_link.le_next) {
224         *(penv++) = g_strdup(entry->ev_var);
225     }
226     *penv = NULL; /* NULL terminate the list */
227
228     if (count != NULL)
229         *count = envlist->el_count;
230
231     return (env);
232 }