xref: /aosp_15_r20/external/curl/src/var.c (revision 6236dae45794135f37c4eb022389c904c8b0090d)
1*6236dae4SAndroid Build Coastguard Worker /***************************************************************************
2*6236dae4SAndroid Build Coastguard Worker  *                                  _   _ ____  _
3*6236dae4SAndroid Build Coastguard Worker  *  Project                     ___| | | |  _ \| |
4*6236dae4SAndroid Build Coastguard Worker  *                             / __| | | | |_) | |
5*6236dae4SAndroid Build Coastguard Worker  *                            | (__| |_| |  _ <| |___
6*6236dae4SAndroid Build Coastguard Worker  *                             \___|\___/|_| \_\_____|
7*6236dae4SAndroid Build Coastguard Worker  *
8*6236dae4SAndroid Build Coastguard Worker  * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9*6236dae4SAndroid Build Coastguard Worker  *
10*6236dae4SAndroid Build Coastguard Worker  * This software is licensed as described in the file COPYING, which
11*6236dae4SAndroid Build Coastguard Worker  * you should have received as part of this distribution. The terms
12*6236dae4SAndroid Build Coastguard Worker  * are also available at https://curl.se/docs/copyright.html.
13*6236dae4SAndroid Build Coastguard Worker  *
14*6236dae4SAndroid Build Coastguard Worker  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15*6236dae4SAndroid Build Coastguard Worker  * copies of the Software, and permit persons to whom the Software is
16*6236dae4SAndroid Build Coastguard Worker  * furnished to do so, under the terms of the COPYING file.
17*6236dae4SAndroid Build Coastguard Worker  *
18*6236dae4SAndroid Build Coastguard Worker  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19*6236dae4SAndroid Build Coastguard Worker  * KIND, either express or implied.
20*6236dae4SAndroid Build Coastguard Worker  *
21*6236dae4SAndroid Build Coastguard Worker  * SPDX-License-Identifier: curl
22*6236dae4SAndroid Build Coastguard Worker  *
23*6236dae4SAndroid Build Coastguard Worker  ***************************************************************************/
24*6236dae4SAndroid Build Coastguard Worker #include "tool_setup.h"
25*6236dae4SAndroid Build Coastguard Worker 
26*6236dae4SAndroid Build Coastguard Worker #include "curlx.h"
27*6236dae4SAndroid Build Coastguard Worker 
28*6236dae4SAndroid Build Coastguard Worker #include "tool_cfgable.h"
29*6236dae4SAndroid Build Coastguard Worker #include "tool_getparam.h"
30*6236dae4SAndroid Build Coastguard Worker #include "tool_helpers.h"
31*6236dae4SAndroid Build Coastguard Worker #include "tool_findfile.h"
32*6236dae4SAndroid Build Coastguard Worker #include "tool_msgs.h"
33*6236dae4SAndroid Build Coastguard Worker #include "tool_parsecfg.h"
34*6236dae4SAndroid Build Coastguard Worker #include "dynbuf.h"
35*6236dae4SAndroid Build Coastguard Worker #include "curl_base64.h"
36*6236dae4SAndroid Build Coastguard Worker #include "tool_paramhlp.h"
37*6236dae4SAndroid Build Coastguard Worker #include "tool_writeout_json.h"
38*6236dae4SAndroid Build Coastguard Worker #include "var.h"
39*6236dae4SAndroid Build Coastguard Worker 
40*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h" /* keep this as LAST include */
41*6236dae4SAndroid Build Coastguard Worker 
42*6236dae4SAndroid Build Coastguard Worker #define MAX_EXPAND_CONTENT 10000000
43*6236dae4SAndroid Build Coastguard Worker #define MAX_VAR_LEN 128 /* max length of a name */
44*6236dae4SAndroid Build Coastguard Worker 
Memdup(const char * data,size_t len)45*6236dae4SAndroid Build Coastguard Worker static char *Memdup(const char *data, size_t len)
46*6236dae4SAndroid Build Coastguard Worker {
47*6236dae4SAndroid Build Coastguard Worker   char *p = malloc(len + 1);
48*6236dae4SAndroid Build Coastguard Worker   if(!p)
49*6236dae4SAndroid Build Coastguard Worker     return NULL;
50*6236dae4SAndroid Build Coastguard Worker   if(len)
51*6236dae4SAndroid Build Coastguard Worker     memcpy(p, data, len);
52*6236dae4SAndroid Build Coastguard Worker   p[len] = 0;
53*6236dae4SAndroid Build Coastguard Worker   return p;
54*6236dae4SAndroid Build Coastguard Worker }
55*6236dae4SAndroid Build Coastguard Worker 
56*6236dae4SAndroid Build Coastguard Worker /* free everything */
varcleanup(struct GlobalConfig * global)57*6236dae4SAndroid Build Coastguard Worker void varcleanup(struct GlobalConfig *global)
58*6236dae4SAndroid Build Coastguard Worker {
59*6236dae4SAndroid Build Coastguard Worker   struct var *list = global->variables;
60*6236dae4SAndroid Build Coastguard Worker   while(list) {
61*6236dae4SAndroid Build Coastguard Worker     struct var *t = list;
62*6236dae4SAndroid Build Coastguard Worker     list = list->next;
63*6236dae4SAndroid Build Coastguard Worker     free((char *)t->content);
64*6236dae4SAndroid Build Coastguard Worker     free(t);
65*6236dae4SAndroid Build Coastguard Worker   }
66*6236dae4SAndroid Build Coastguard Worker }
67*6236dae4SAndroid Build Coastguard Worker 
varcontent(struct GlobalConfig * global,const char * name,size_t nlen)68*6236dae4SAndroid Build Coastguard Worker static const struct var *varcontent(struct GlobalConfig *global,
69*6236dae4SAndroid Build Coastguard Worker                                     const char *name, size_t nlen)
70*6236dae4SAndroid Build Coastguard Worker {
71*6236dae4SAndroid Build Coastguard Worker   struct var *list = global->variables;
72*6236dae4SAndroid Build Coastguard Worker   while(list) {
73*6236dae4SAndroid Build Coastguard Worker     if((strlen(list->name) == nlen) &&
74*6236dae4SAndroid Build Coastguard Worker        !strncmp(name, list->name, nlen)) {
75*6236dae4SAndroid Build Coastguard Worker       return list;
76*6236dae4SAndroid Build Coastguard Worker     }
77*6236dae4SAndroid Build Coastguard Worker     list = list->next;
78*6236dae4SAndroid Build Coastguard Worker   }
79*6236dae4SAndroid Build Coastguard Worker   return NULL;
80*6236dae4SAndroid Build Coastguard Worker }
81*6236dae4SAndroid Build Coastguard Worker 
82*6236dae4SAndroid Build Coastguard Worker #define ENDOFFUNC(x) (((x) == '}') || ((x) == ':'))
83*6236dae4SAndroid Build Coastguard Worker #define FUNCMATCH(ptr,name,len)                         \
84*6236dae4SAndroid Build Coastguard Worker   (!strncmp(ptr, name, len) && ENDOFFUNC(ptr[len]))
85*6236dae4SAndroid Build Coastguard Worker 
86*6236dae4SAndroid Build Coastguard Worker #define FUNC_TRIM "trim"
87*6236dae4SAndroid Build Coastguard Worker #define FUNC_TRIM_LEN (sizeof(FUNC_TRIM) - 1)
88*6236dae4SAndroid Build Coastguard Worker #define FUNC_JSON "json"
89*6236dae4SAndroid Build Coastguard Worker #define FUNC_JSON_LEN (sizeof(FUNC_JSON) - 1)
90*6236dae4SAndroid Build Coastguard Worker #define FUNC_URL "url"
91*6236dae4SAndroid Build Coastguard Worker #define FUNC_URL_LEN (sizeof(FUNC_URL) - 1)
92*6236dae4SAndroid Build Coastguard Worker #define FUNC_B64 "b64"
93*6236dae4SAndroid Build Coastguard Worker #define FUNC_B64_LEN (sizeof(FUNC_B64) - 1)
94*6236dae4SAndroid Build Coastguard Worker 
varfunc(struct GlobalConfig * global,char * c,size_t clen,char * f,size_t flen,struct curlx_dynbuf * out)95*6236dae4SAndroid Build Coastguard Worker static ParameterError varfunc(struct GlobalConfig *global,
96*6236dae4SAndroid Build Coastguard Worker                               char *c, /* content */
97*6236dae4SAndroid Build Coastguard Worker                               size_t clen, /* content length */
98*6236dae4SAndroid Build Coastguard Worker                               char *f, /* functions */
99*6236dae4SAndroid Build Coastguard Worker                               size_t flen, /* function string length */
100*6236dae4SAndroid Build Coastguard Worker                               struct curlx_dynbuf *out)
101*6236dae4SAndroid Build Coastguard Worker {
102*6236dae4SAndroid Build Coastguard Worker   bool alloc = FALSE;
103*6236dae4SAndroid Build Coastguard Worker   ParameterError err = PARAM_OK;
104*6236dae4SAndroid Build Coastguard Worker   const char *finput = f;
105*6236dae4SAndroid Build Coastguard Worker 
106*6236dae4SAndroid Build Coastguard Worker   /* The functions are independent and runs left to right */
107*6236dae4SAndroid Build Coastguard Worker   while(*f && !err) {
108*6236dae4SAndroid Build Coastguard Worker     if(*f == '}')
109*6236dae4SAndroid Build Coastguard Worker       /* end of functions */
110*6236dae4SAndroid Build Coastguard Worker       break;
111*6236dae4SAndroid Build Coastguard Worker     /* On entry, this is known to be a colon already. In subsequent laps, it
112*6236dae4SAndroid Build Coastguard Worker        is also known to be a colon since that is part of the FUNCMATCH()
113*6236dae4SAndroid Build Coastguard Worker        checks */
114*6236dae4SAndroid Build Coastguard Worker     f++;
115*6236dae4SAndroid Build Coastguard Worker     if(FUNCMATCH(f, FUNC_TRIM, FUNC_TRIM_LEN)) {
116*6236dae4SAndroid Build Coastguard Worker       size_t len = clen;
117*6236dae4SAndroid Build Coastguard Worker       f += FUNC_TRIM_LEN;
118*6236dae4SAndroid Build Coastguard Worker       if(clen) {
119*6236dae4SAndroid Build Coastguard Worker         /* skip leading white space, including CRLF */
120*6236dae4SAndroid Build Coastguard Worker         while(*c && ISSPACE(*c)) {
121*6236dae4SAndroid Build Coastguard Worker           c++;
122*6236dae4SAndroid Build Coastguard Worker           len--;
123*6236dae4SAndroid Build Coastguard Worker         }
124*6236dae4SAndroid Build Coastguard Worker         while(len && ISSPACE(c[len-1]))
125*6236dae4SAndroid Build Coastguard Worker           len--;
126*6236dae4SAndroid Build Coastguard Worker       }
127*6236dae4SAndroid Build Coastguard Worker       /* put it in the output */
128*6236dae4SAndroid Build Coastguard Worker       curlx_dyn_reset(out);
129*6236dae4SAndroid Build Coastguard Worker       if(curlx_dyn_addn(out, c, len)) {
130*6236dae4SAndroid Build Coastguard Worker         err = PARAM_NO_MEM;
131*6236dae4SAndroid Build Coastguard Worker         break;
132*6236dae4SAndroid Build Coastguard Worker       }
133*6236dae4SAndroid Build Coastguard Worker     }
134*6236dae4SAndroid Build Coastguard Worker     else if(FUNCMATCH(f, FUNC_JSON, FUNC_JSON_LEN)) {
135*6236dae4SAndroid Build Coastguard Worker       f += FUNC_JSON_LEN;
136*6236dae4SAndroid Build Coastguard Worker       curlx_dyn_reset(out);
137*6236dae4SAndroid Build Coastguard Worker       if(clen) {
138*6236dae4SAndroid Build Coastguard Worker         if(jsonquoted(c, clen, out, FALSE)) {
139*6236dae4SAndroid Build Coastguard Worker           err = PARAM_NO_MEM;
140*6236dae4SAndroid Build Coastguard Worker           break;
141*6236dae4SAndroid Build Coastguard Worker         }
142*6236dae4SAndroid Build Coastguard Worker       }
143*6236dae4SAndroid Build Coastguard Worker     }
144*6236dae4SAndroid Build Coastguard Worker     else if(FUNCMATCH(f, FUNC_URL, FUNC_URL_LEN)) {
145*6236dae4SAndroid Build Coastguard Worker       f += FUNC_URL_LEN;
146*6236dae4SAndroid Build Coastguard Worker       curlx_dyn_reset(out);
147*6236dae4SAndroid Build Coastguard Worker       if(clen) {
148*6236dae4SAndroid Build Coastguard Worker         char *enc = curl_easy_escape(NULL, c, (int)clen);
149*6236dae4SAndroid Build Coastguard Worker         if(!enc) {
150*6236dae4SAndroid Build Coastguard Worker           err = PARAM_NO_MEM;
151*6236dae4SAndroid Build Coastguard Worker           break;
152*6236dae4SAndroid Build Coastguard Worker         }
153*6236dae4SAndroid Build Coastguard Worker 
154*6236dae4SAndroid Build Coastguard Worker         /* put it in the output */
155*6236dae4SAndroid Build Coastguard Worker         if(curlx_dyn_add(out, enc))
156*6236dae4SAndroid Build Coastguard Worker           err = PARAM_NO_MEM;
157*6236dae4SAndroid Build Coastguard Worker         curl_free(enc);
158*6236dae4SAndroid Build Coastguard Worker         if(err)
159*6236dae4SAndroid Build Coastguard Worker           break;
160*6236dae4SAndroid Build Coastguard Worker       }
161*6236dae4SAndroid Build Coastguard Worker     }
162*6236dae4SAndroid Build Coastguard Worker     else if(FUNCMATCH(f, FUNC_B64, FUNC_B64_LEN)) {
163*6236dae4SAndroid Build Coastguard Worker       f += FUNC_B64_LEN;
164*6236dae4SAndroid Build Coastguard Worker       curlx_dyn_reset(out);
165*6236dae4SAndroid Build Coastguard Worker       if(clen) {
166*6236dae4SAndroid Build Coastguard Worker         char *enc;
167*6236dae4SAndroid Build Coastguard Worker         size_t elen;
168*6236dae4SAndroid Build Coastguard Worker         CURLcode result = curlx_base64_encode(c, clen, &enc, &elen);
169*6236dae4SAndroid Build Coastguard Worker         if(result) {
170*6236dae4SAndroid Build Coastguard Worker           err = PARAM_NO_MEM;
171*6236dae4SAndroid Build Coastguard Worker           break;
172*6236dae4SAndroid Build Coastguard Worker         }
173*6236dae4SAndroid Build Coastguard Worker 
174*6236dae4SAndroid Build Coastguard Worker         /* put it in the output */
175*6236dae4SAndroid Build Coastguard Worker         if(curlx_dyn_addn(out, enc, elen))
176*6236dae4SAndroid Build Coastguard Worker           err = PARAM_NO_MEM;
177*6236dae4SAndroid Build Coastguard Worker         curl_free(enc);
178*6236dae4SAndroid Build Coastguard Worker         if(err)
179*6236dae4SAndroid Build Coastguard Worker           break;
180*6236dae4SAndroid Build Coastguard Worker       }
181*6236dae4SAndroid Build Coastguard Worker     }
182*6236dae4SAndroid Build Coastguard Worker     else {
183*6236dae4SAndroid Build Coastguard Worker       /* unsupported function */
184*6236dae4SAndroid Build Coastguard Worker       errorf(global, "unknown variable function in '%.*s'",
185*6236dae4SAndroid Build Coastguard Worker              (int)flen, finput);
186*6236dae4SAndroid Build Coastguard Worker       err = PARAM_EXPAND_ERROR;
187*6236dae4SAndroid Build Coastguard Worker       break;
188*6236dae4SAndroid Build Coastguard Worker     }
189*6236dae4SAndroid Build Coastguard Worker     if(alloc)
190*6236dae4SAndroid Build Coastguard Worker       free(c);
191*6236dae4SAndroid Build Coastguard Worker 
192*6236dae4SAndroid Build Coastguard Worker     clen = curlx_dyn_len(out);
193*6236dae4SAndroid Build Coastguard Worker     c = Memdup(curlx_dyn_ptr(out), clen);
194*6236dae4SAndroid Build Coastguard Worker     if(!c) {
195*6236dae4SAndroid Build Coastguard Worker       err = PARAM_NO_MEM;
196*6236dae4SAndroid Build Coastguard Worker       break;
197*6236dae4SAndroid Build Coastguard Worker     }
198*6236dae4SAndroid Build Coastguard Worker     alloc = TRUE;
199*6236dae4SAndroid Build Coastguard Worker   }
200*6236dae4SAndroid Build Coastguard Worker   if(alloc)
201*6236dae4SAndroid Build Coastguard Worker     free(c);
202*6236dae4SAndroid Build Coastguard Worker   if(err)
203*6236dae4SAndroid Build Coastguard Worker     curlx_dyn_free(out);
204*6236dae4SAndroid Build Coastguard Worker   return err;
205*6236dae4SAndroid Build Coastguard Worker }
206*6236dae4SAndroid Build Coastguard Worker 
varexpand(struct GlobalConfig * global,const char * line,struct curlx_dynbuf * out,bool * replaced)207*6236dae4SAndroid Build Coastguard Worker ParameterError varexpand(struct GlobalConfig *global,
208*6236dae4SAndroid Build Coastguard Worker                          const char *line, struct curlx_dynbuf *out,
209*6236dae4SAndroid Build Coastguard Worker                          bool *replaced)
210*6236dae4SAndroid Build Coastguard Worker {
211*6236dae4SAndroid Build Coastguard Worker   CURLcode result;
212*6236dae4SAndroid Build Coastguard Worker   char *envp;
213*6236dae4SAndroid Build Coastguard Worker   bool added = FALSE;
214*6236dae4SAndroid Build Coastguard Worker   const char *input = line;
215*6236dae4SAndroid Build Coastguard Worker   *replaced = FALSE;
216*6236dae4SAndroid Build Coastguard Worker   curlx_dyn_init(out, MAX_EXPAND_CONTENT);
217*6236dae4SAndroid Build Coastguard Worker   do {
218*6236dae4SAndroid Build Coastguard Worker     envp = strstr(line, "{{");
219*6236dae4SAndroid Build Coastguard Worker     if((envp > line) && envp[-1] == '\\') {
220*6236dae4SAndroid Build Coastguard Worker       /* preceding backslash, we want this verbatim */
221*6236dae4SAndroid Build Coastguard Worker 
222*6236dae4SAndroid Build Coastguard Worker       /* insert the text up to this point, minus the backslash */
223*6236dae4SAndroid Build Coastguard Worker       result = curlx_dyn_addn(out, line, envp - line - 1);
224*6236dae4SAndroid Build Coastguard Worker       if(result)
225*6236dae4SAndroid Build Coastguard Worker         return PARAM_NO_MEM;
226*6236dae4SAndroid Build Coastguard Worker 
227*6236dae4SAndroid Build Coastguard Worker       /* output '{{' then continue from here */
228*6236dae4SAndroid Build Coastguard Worker       result = curlx_dyn_addn(out, "{{", 2);
229*6236dae4SAndroid Build Coastguard Worker       if(result)
230*6236dae4SAndroid Build Coastguard Worker         return PARAM_NO_MEM;
231*6236dae4SAndroid Build Coastguard Worker       line = &envp[2];
232*6236dae4SAndroid Build Coastguard Worker     }
233*6236dae4SAndroid Build Coastguard Worker     else if(envp) {
234*6236dae4SAndroid Build Coastguard Worker       char name[MAX_VAR_LEN];
235*6236dae4SAndroid Build Coastguard Worker       size_t nlen;
236*6236dae4SAndroid Build Coastguard Worker       size_t i;
237*6236dae4SAndroid Build Coastguard Worker       char *funcp;
238*6236dae4SAndroid Build Coastguard Worker       char *clp = strstr(envp, "}}");
239*6236dae4SAndroid Build Coastguard Worker       size_t prefix;
240*6236dae4SAndroid Build Coastguard Worker 
241*6236dae4SAndroid Build Coastguard Worker       if(!clp) {
242*6236dae4SAndroid Build Coastguard Worker         /* uneven braces */
243*6236dae4SAndroid Build Coastguard Worker         warnf(global, "missing close '}}' in '%s'", input);
244*6236dae4SAndroid Build Coastguard Worker         break;
245*6236dae4SAndroid Build Coastguard Worker       }
246*6236dae4SAndroid Build Coastguard Worker 
247*6236dae4SAndroid Build Coastguard Worker       prefix = 2;
248*6236dae4SAndroid Build Coastguard Worker       envp += 2; /* move over the {{ */
249*6236dae4SAndroid Build Coastguard Worker 
250*6236dae4SAndroid Build Coastguard Worker       /* if there is a function, it ends the name with a colon */
251*6236dae4SAndroid Build Coastguard Worker       funcp = memchr(envp, ':', clp - envp);
252*6236dae4SAndroid Build Coastguard Worker       if(funcp)
253*6236dae4SAndroid Build Coastguard Worker         nlen = funcp - envp;
254*6236dae4SAndroid Build Coastguard Worker       else
255*6236dae4SAndroid Build Coastguard Worker         nlen = clp - envp;
256*6236dae4SAndroid Build Coastguard Worker       if(!nlen || (nlen >= sizeof(name))) {
257*6236dae4SAndroid Build Coastguard Worker         warnf(global, "bad variable name length '%s'", input);
258*6236dae4SAndroid Build Coastguard Worker         /* insert the text as-is since this is not an env variable */
259*6236dae4SAndroid Build Coastguard Worker         result = curlx_dyn_addn(out, line, clp - line + prefix);
260*6236dae4SAndroid Build Coastguard Worker         if(result)
261*6236dae4SAndroid Build Coastguard Worker           return PARAM_NO_MEM;
262*6236dae4SAndroid Build Coastguard Worker       }
263*6236dae4SAndroid Build Coastguard Worker       else {
264*6236dae4SAndroid Build Coastguard Worker         /* insert the text up to this point */
265*6236dae4SAndroid Build Coastguard Worker         result = curlx_dyn_addn(out, line, envp - prefix - line);
266*6236dae4SAndroid Build Coastguard Worker         if(result)
267*6236dae4SAndroid Build Coastguard Worker           return PARAM_NO_MEM;
268*6236dae4SAndroid Build Coastguard Worker 
269*6236dae4SAndroid Build Coastguard Worker         /* copy the name to separate buffer */
270*6236dae4SAndroid Build Coastguard Worker         memcpy(name, envp, nlen);
271*6236dae4SAndroid Build Coastguard Worker         name[nlen] = 0;
272*6236dae4SAndroid Build Coastguard Worker 
273*6236dae4SAndroid Build Coastguard Worker         /* verify that the name looks sensible */
274*6236dae4SAndroid Build Coastguard Worker         for(i = 0; (i < nlen) &&
275*6236dae4SAndroid Build Coastguard Worker               (ISALNUM(name[i]) || (name[i] == '_')); i++);
276*6236dae4SAndroid Build Coastguard Worker         if(i != nlen) {
277*6236dae4SAndroid Build Coastguard Worker           warnf(global, "bad variable name: %s", name);
278*6236dae4SAndroid Build Coastguard Worker           /* insert the text as-is since this is not an env variable */
279*6236dae4SAndroid Build Coastguard Worker           result = curlx_dyn_addn(out, envp - prefix,
280*6236dae4SAndroid Build Coastguard Worker                                   clp - envp + prefix + 2);
281*6236dae4SAndroid Build Coastguard Worker           if(result)
282*6236dae4SAndroid Build Coastguard Worker             return PARAM_NO_MEM;
283*6236dae4SAndroid Build Coastguard Worker         }
284*6236dae4SAndroid Build Coastguard Worker         else {
285*6236dae4SAndroid Build Coastguard Worker           char *value;
286*6236dae4SAndroid Build Coastguard Worker           size_t vlen = 0;
287*6236dae4SAndroid Build Coastguard Worker           struct curlx_dynbuf buf;
288*6236dae4SAndroid Build Coastguard Worker           const struct var *v = varcontent(global, name, nlen);
289*6236dae4SAndroid Build Coastguard Worker           if(v) {
290*6236dae4SAndroid Build Coastguard Worker             value = (char *)v->content;
291*6236dae4SAndroid Build Coastguard Worker             vlen = v->clen;
292*6236dae4SAndroid Build Coastguard Worker           }
293*6236dae4SAndroid Build Coastguard Worker           else
294*6236dae4SAndroid Build Coastguard Worker             value = NULL;
295*6236dae4SAndroid Build Coastguard Worker 
296*6236dae4SAndroid Build Coastguard Worker           curlx_dyn_init(&buf, MAX_EXPAND_CONTENT);
297*6236dae4SAndroid Build Coastguard Worker           if(funcp) {
298*6236dae4SAndroid Build Coastguard Worker             /* apply the list of functions on the value */
299*6236dae4SAndroid Build Coastguard Worker             size_t flen = clp - funcp;
300*6236dae4SAndroid Build Coastguard Worker             ParameterError err = varfunc(global, value, vlen, funcp, flen,
301*6236dae4SAndroid Build Coastguard Worker                                          &buf);
302*6236dae4SAndroid Build Coastguard Worker             if(err)
303*6236dae4SAndroid Build Coastguard Worker               return err;
304*6236dae4SAndroid Build Coastguard Worker             value = curlx_dyn_ptr(&buf);
305*6236dae4SAndroid Build Coastguard Worker             vlen = curlx_dyn_len(&buf);
306*6236dae4SAndroid Build Coastguard Worker           }
307*6236dae4SAndroid Build Coastguard Worker 
308*6236dae4SAndroid Build Coastguard Worker           if(value && vlen > 0) {
309*6236dae4SAndroid Build Coastguard Worker             /* A variable might contain null bytes. Such bytes cannot be shown
310*6236dae4SAndroid Build Coastguard Worker                using normal means, this is an error. */
311*6236dae4SAndroid Build Coastguard Worker             char *nb = memchr(value, '\0', vlen);
312*6236dae4SAndroid Build Coastguard Worker             if(nb) {
313*6236dae4SAndroid Build Coastguard Worker               errorf(global, "variable contains null byte");
314*6236dae4SAndroid Build Coastguard Worker               return PARAM_EXPAND_ERROR;
315*6236dae4SAndroid Build Coastguard Worker             }
316*6236dae4SAndroid Build Coastguard Worker           }
317*6236dae4SAndroid Build Coastguard Worker           /* insert the value */
318*6236dae4SAndroid Build Coastguard Worker           result = curlx_dyn_addn(out, value, vlen);
319*6236dae4SAndroid Build Coastguard Worker           curlx_dyn_free(&buf);
320*6236dae4SAndroid Build Coastguard Worker           if(result)
321*6236dae4SAndroid Build Coastguard Worker             return PARAM_NO_MEM;
322*6236dae4SAndroid Build Coastguard Worker 
323*6236dae4SAndroid Build Coastguard Worker           added = true;
324*6236dae4SAndroid Build Coastguard Worker         }
325*6236dae4SAndroid Build Coastguard Worker       }
326*6236dae4SAndroid Build Coastguard Worker       line = &clp[2];
327*6236dae4SAndroid Build Coastguard Worker     }
328*6236dae4SAndroid Build Coastguard Worker 
329*6236dae4SAndroid Build Coastguard Worker   } while(envp);
330*6236dae4SAndroid Build Coastguard Worker   if(added && *line) {
331*6236dae4SAndroid Build Coastguard Worker     /* add the "suffix" as well */
332*6236dae4SAndroid Build Coastguard Worker     result = curlx_dyn_add(out, line);
333*6236dae4SAndroid Build Coastguard Worker     if(result)
334*6236dae4SAndroid Build Coastguard Worker       return PARAM_NO_MEM;
335*6236dae4SAndroid Build Coastguard Worker   }
336*6236dae4SAndroid Build Coastguard Worker   *replaced = added;
337*6236dae4SAndroid Build Coastguard Worker   if(!added)
338*6236dae4SAndroid Build Coastguard Worker     curlx_dyn_free(out);
339*6236dae4SAndroid Build Coastguard Worker   return PARAM_OK;
340*6236dae4SAndroid Build Coastguard Worker }
341*6236dae4SAndroid Build Coastguard Worker 
342*6236dae4SAndroid Build Coastguard Worker /*
343*6236dae4SAndroid Build Coastguard Worker  * Created in a way that is not revealing how variables are actually stored so
344*6236dae4SAndroid Build Coastguard Worker  * that we can improve this if we want better performance when managing many
345*6236dae4SAndroid Build Coastguard Worker  * at a later point.
346*6236dae4SAndroid Build Coastguard Worker  */
addvariable(struct GlobalConfig * global,const char * name,size_t nlen,const char * content,size_t clen,bool contalloc)347*6236dae4SAndroid Build Coastguard Worker static ParameterError addvariable(struct GlobalConfig *global,
348*6236dae4SAndroid Build Coastguard Worker                                   const char *name,
349*6236dae4SAndroid Build Coastguard Worker                                   size_t nlen,
350*6236dae4SAndroid Build Coastguard Worker                                   const char *content,
351*6236dae4SAndroid Build Coastguard Worker                                   size_t clen,
352*6236dae4SAndroid Build Coastguard Worker                                   bool contalloc)
353*6236dae4SAndroid Build Coastguard Worker {
354*6236dae4SAndroid Build Coastguard Worker   struct var *p;
355*6236dae4SAndroid Build Coastguard Worker   const struct var *check = varcontent(global, name, nlen);
356*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(nlen);
357*6236dae4SAndroid Build Coastguard Worker   if(check)
358*6236dae4SAndroid Build Coastguard Worker     notef(global, "Overwriting variable '%s'", check->name);
359*6236dae4SAndroid Build Coastguard Worker 
360*6236dae4SAndroid Build Coastguard Worker   p = calloc(1, sizeof(struct var) + nlen);
361*6236dae4SAndroid Build Coastguard Worker   if(p) {
362*6236dae4SAndroid Build Coastguard Worker     memcpy(p->name, name, nlen);
363*6236dae4SAndroid Build Coastguard Worker 
364*6236dae4SAndroid Build Coastguard Worker     p->content = contalloc ? content : Memdup(content, clen);
365*6236dae4SAndroid Build Coastguard Worker     if(p->content) {
366*6236dae4SAndroid Build Coastguard Worker       p->clen = clen;
367*6236dae4SAndroid Build Coastguard Worker 
368*6236dae4SAndroid Build Coastguard Worker       p->next = global->variables;
369*6236dae4SAndroid Build Coastguard Worker       global->variables = p;
370*6236dae4SAndroid Build Coastguard Worker       return PARAM_OK;
371*6236dae4SAndroid Build Coastguard Worker     }
372*6236dae4SAndroid Build Coastguard Worker     free(p);
373*6236dae4SAndroid Build Coastguard Worker   }
374*6236dae4SAndroid Build Coastguard Worker   return PARAM_NO_MEM;
375*6236dae4SAndroid Build Coastguard Worker }
376*6236dae4SAndroid Build Coastguard Worker 
setvariable(struct GlobalConfig * global,const char * input)377*6236dae4SAndroid Build Coastguard Worker ParameterError setvariable(struct GlobalConfig *global,
378*6236dae4SAndroid Build Coastguard Worker                            const char *input)
379*6236dae4SAndroid Build Coastguard Worker {
380*6236dae4SAndroid Build Coastguard Worker   const char *name;
381*6236dae4SAndroid Build Coastguard Worker   size_t nlen;
382*6236dae4SAndroid Build Coastguard Worker   char *content = NULL;
383*6236dae4SAndroid Build Coastguard Worker   size_t clen = 0;
384*6236dae4SAndroid Build Coastguard Worker   bool contalloc = FALSE;
385*6236dae4SAndroid Build Coastguard Worker   const char *line = input;
386*6236dae4SAndroid Build Coastguard Worker   ParameterError err = PARAM_OK;
387*6236dae4SAndroid Build Coastguard Worker   bool import = FALSE;
388*6236dae4SAndroid Build Coastguard Worker   char *ge = NULL;
389*6236dae4SAndroid Build Coastguard Worker   char buf[MAX_VAR_LEN];
390*6236dae4SAndroid Build Coastguard Worker 
391*6236dae4SAndroid Build Coastguard Worker   if(*input == '%') {
392*6236dae4SAndroid Build Coastguard Worker     import = TRUE;
393*6236dae4SAndroid Build Coastguard Worker     line++;
394*6236dae4SAndroid Build Coastguard Worker   }
395*6236dae4SAndroid Build Coastguard Worker   name = line;
396*6236dae4SAndroid Build Coastguard Worker   while(*line && (ISALNUM(*line) || (*line == '_')))
397*6236dae4SAndroid Build Coastguard Worker     line++;
398*6236dae4SAndroid Build Coastguard Worker   nlen = line - name;
399*6236dae4SAndroid Build Coastguard Worker   if(!nlen || (nlen >= MAX_VAR_LEN)) {
400*6236dae4SAndroid Build Coastguard Worker     warnf(global, "Bad variable name length (%zd), skipping", nlen);
401*6236dae4SAndroid Build Coastguard Worker     return PARAM_OK;
402*6236dae4SAndroid Build Coastguard Worker   }
403*6236dae4SAndroid Build Coastguard Worker   if(import) {
404*6236dae4SAndroid Build Coastguard Worker     /* this does not use curl_getenv() because we want "" support for blank
405*6236dae4SAndroid Build Coastguard Worker        content */
406*6236dae4SAndroid Build Coastguard Worker     if(*line) {
407*6236dae4SAndroid Build Coastguard Worker       /* if there is a default action, we need to copy the name */
408*6236dae4SAndroid Build Coastguard Worker       memcpy(buf, name, nlen);
409*6236dae4SAndroid Build Coastguard Worker       buf[nlen] = 0;
410*6236dae4SAndroid Build Coastguard Worker       name = buf;
411*6236dae4SAndroid Build Coastguard Worker     }
412*6236dae4SAndroid Build Coastguard Worker     ge = getenv(name);
413*6236dae4SAndroid Build Coastguard Worker     if(!*line && !ge) {
414*6236dae4SAndroid Build Coastguard Worker       /* no assign, no variable, fail */
415*6236dae4SAndroid Build Coastguard Worker       errorf(global, "Variable '%s' import fail, not set", name);
416*6236dae4SAndroid Build Coastguard Worker       return PARAM_EXPAND_ERROR;
417*6236dae4SAndroid Build Coastguard Worker     }
418*6236dae4SAndroid Build Coastguard Worker     else if(ge) {
419*6236dae4SAndroid Build Coastguard Worker       /* there is a value to use */
420*6236dae4SAndroid Build Coastguard Worker       content = ge;
421*6236dae4SAndroid Build Coastguard Worker       clen = strlen(ge);
422*6236dae4SAndroid Build Coastguard Worker     }
423*6236dae4SAndroid Build Coastguard Worker   }
424*6236dae4SAndroid Build Coastguard Worker   if(content)
425*6236dae4SAndroid Build Coastguard Worker     ;
426*6236dae4SAndroid Build Coastguard Worker   else if(*line == '@') {
427*6236dae4SAndroid Build Coastguard Worker     /* read from file or stdin */
428*6236dae4SAndroid Build Coastguard Worker     FILE *file;
429*6236dae4SAndroid Build Coastguard Worker     bool use_stdin;
430*6236dae4SAndroid Build Coastguard Worker     line++;
431*6236dae4SAndroid Build Coastguard Worker     use_stdin = !strcmp(line, "-");
432*6236dae4SAndroid Build Coastguard Worker     if(use_stdin)
433*6236dae4SAndroid Build Coastguard Worker       file = stdin;
434*6236dae4SAndroid Build Coastguard Worker     else {
435*6236dae4SAndroid Build Coastguard Worker       file = fopen(line, "rb");
436*6236dae4SAndroid Build Coastguard Worker       if(!file) {
437*6236dae4SAndroid Build Coastguard Worker         errorf(global, "Failed to open %s", line);
438*6236dae4SAndroid Build Coastguard Worker         return PARAM_READ_ERROR;
439*6236dae4SAndroid Build Coastguard Worker       }
440*6236dae4SAndroid Build Coastguard Worker     }
441*6236dae4SAndroid Build Coastguard Worker     err = file2memory(&content, &clen, file);
442*6236dae4SAndroid Build Coastguard Worker     /* in case of out of memory, this should fail the entire operation */
443*6236dae4SAndroid Build Coastguard Worker     contalloc = TRUE;
444*6236dae4SAndroid Build Coastguard Worker     if(!use_stdin)
445*6236dae4SAndroid Build Coastguard Worker       fclose(file);
446*6236dae4SAndroid Build Coastguard Worker     if(err)
447*6236dae4SAndroid Build Coastguard Worker       return err;
448*6236dae4SAndroid Build Coastguard Worker   }
449*6236dae4SAndroid Build Coastguard Worker   else if(*line == '=') {
450*6236dae4SAndroid Build Coastguard Worker     line++;
451*6236dae4SAndroid Build Coastguard Worker     /* this is the exact content */
452*6236dae4SAndroid Build Coastguard Worker     content = (char *)line;
453*6236dae4SAndroid Build Coastguard Worker     clen = strlen(line);
454*6236dae4SAndroid Build Coastguard Worker   }
455*6236dae4SAndroid Build Coastguard Worker   else {
456*6236dae4SAndroid Build Coastguard Worker     warnf(global, "Bad --variable syntax, skipping: %s", input);
457*6236dae4SAndroid Build Coastguard Worker     return PARAM_OK;
458*6236dae4SAndroid Build Coastguard Worker   }
459*6236dae4SAndroid Build Coastguard Worker   err = addvariable(global, name, nlen, content, clen, contalloc);
460*6236dae4SAndroid Build Coastguard Worker   if(err) {
461*6236dae4SAndroid Build Coastguard Worker     if(contalloc)
462*6236dae4SAndroid Build Coastguard Worker       free(content);
463*6236dae4SAndroid Build Coastguard Worker   }
464*6236dae4SAndroid Build Coastguard Worker   return err;
465*6236dae4SAndroid Build Coastguard Worker }
466