10
10
11
11
#include "list.h"
12
12
13
+ #define ARRAY_SIZE (arr ) (sizeof(arr) / sizeof((arr)[0]))
14
+
15
+ static char * expand_string_with_args (const char * in , int argc , char * argv []);
16
+
13
17
static void __attribute__((noreturn )) pperror (const char * format , ...)
14
18
{
15
19
va_list ap ;
@@ -92,20 +96,123 @@ void env_write_dep(FILE *f, const char *autoconfig_name)
92
96
}
93
97
}
94
98
95
- static char * eval_clause (const char * str , size_t len )
99
+ /*
100
+ * Built-in functions
101
+ */
102
+ struct function {
103
+ const char * name ;
104
+ unsigned int min_args ;
105
+ unsigned int max_args ;
106
+ char * (* func )(int argc , char * argv []);
107
+ };
108
+
109
+ static const struct function function_table [] = {
110
+ /* Name MIN MAX Function */
111
+ };
112
+
113
+ #define FUNCTION_MAX_ARGS 16
114
+
115
+ static char * function_expand (const char * name , int argc , char * argv [])
96
116
{
97
- char * tmp , * name , * res ;
117
+ const struct function * f ;
118
+ int i ;
119
+
120
+ for (i = 0 ; i < ARRAY_SIZE (function_table ); i ++ ) {
121
+ f = & function_table [i ];
122
+ if (strcmp (f -> name , name ))
123
+ continue ;
124
+
125
+ if (argc < f -> min_args )
126
+ pperror ("too few function arguments passed to '%s'" ,
127
+ name );
128
+
129
+ if (argc > f -> max_args )
130
+ pperror ("too many function arguments passed to '%s'" ,
131
+ name );
132
+
133
+ return f -> func (argc , argv );
134
+ }
135
+
136
+ return NULL ;
137
+ }
138
+
139
+ /*
140
+ * Evaluate a clause with arguments. argc/argv are arguments from the upper
141
+ * function call.
142
+ *
143
+ * Returned string must be freed when done
144
+ */
145
+ static char * eval_clause (const char * str , size_t len , int argc , char * argv [])
146
+ {
147
+ char * tmp , * name , * res , * prev , * p ;
148
+ int new_argc = 0 ;
149
+ char * new_argv [FUNCTION_MAX_ARGS ];
150
+ int nest = 0 ;
151
+ int i ;
98
152
99
153
tmp = xstrndup (str , len );
100
154
101
- name = expand_string (tmp );
155
+ prev = p = tmp ;
156
+
157
+ /*
158
+ * Split into tokens
159
+ * The function name and arguments are separated by a comma.
160
+ * For example, if the function call is like this:
161
+ * $(foo,$(x),$(y))
162
+ *
163
+ * The input string for this helper should be:
164
+ * foo,$(x),$(y)
165
+ *
166
+ * and split into:
167
+ * new_argv[0] = 'foo'
168
+ * new_argv[1] = '$(x)'
169
+ * new_argv[2] = '$(y)'
170
+ */
171
+ while (* p ) {
172
+ if (nest == 0 && * p == ',' ) {
173
+ * p = 0 ;
174
+ if (new_argc >= FUNCTION_MAX_ARGS )
175
+ pperror ("too many function arguments" );
176
+ new_argv [new_argc ++ ] = prev ;
177
+ prev = p + 1 ;
178
+ } else if (* p == '(' ) {
179
+ nest ++ ;
180
+ } else if (* p == ')' ) {
181
+ nest -- ;
182
+ }
102
183
103
- res = env_expand (name );
184
+ p ++ ;
185
+ }
186
+ new_argv [new_argc ++ ] = prev ;
187
+
188
+ /*
189
+ * Shift arguments
190
+ * new_argv[0] represents a function name or a variable name. Put it
191
+ * into 'name', then shift the rest of the arguments. This simplifies
192
+ * 'const' handling.
193
+ */
194
+ name = expand_string_with_args (new_argv [0 ], argc , argv );
195
+ new_argc -- ;
196
+ for (i = 0 ; i < new_argc ; i ++ )
197
+ new_argv [i ] = expand_string_with_args (new_argv [i + 1 ],
198
+ argc , argv );
199
+
200
+ /* Look for built-in functions */
201
+ res = function_expand (name , new_argc , new_argv );
104
202
if (res )
105
203
goto free ;
106
204
205
+ /* Last, try environment variable */
206
+ if (new_argc == 0 ) {
207
+ res = env_expand (name );
208
+ if (res )
209
+ goto free ;
210
+ }
211
+
107
212
res = xstrdup ("" );
108
213
free :
214
+ for (i = 0 ; i < new_argc ; i ++ )
215
+ free (new_argv [i ]);
109
216
free (name );
110
217
free (tmp );
111
218
@@ -124,14 +231,14 @@ static char *eval_clause(const char *str, size_t len)
124
231
* after the corresponding closing parenthesis, in this case, *str will be
125
232
* $(BAR)
126
233
*/
127
- char * expand_dollar (const char * * str )
234
+ static char * expand_dollar_with_args (const char * * str , int argc , char * argv [] )
128
235
{
129
236
const char * p = * str ;
130
237
const char * q ;
131
238
int nest = 0 ;
132
239
133
240
/*
134
- * In Kconfig, variable references always start with "$(".
241
+ * In Kconfig, variable/function references always start with "$(".
135
242
* Neither single-letter variables as in $A nor curly braces as in ${CC}
136
243
* are supported. '$' not followed by '(' loses its special meaning.
137
244
*/
@@ -158,10 +265,16 @@ char *expand_dollar(const char **str)
158
265
/* Advance 'str' to after the expanded initial portion of the string */
159
266
* str = q + 1 ;
160
267
161
- return eval_clause (p , q - p );
268
+ return eval_clause (p , q - p , argc , argv );
269
+ }
270
+
271
+ char * expand_dollar (const char * * str )
272
+ {
273
+ return expand_dollar_with_args (str , 0 , NULL );
162
274
}
163
275
164
- static char * __expand_string (const char * * str , bool (* is_end )(char c ))
276
+ static char * __expand_string (const char * * str , bool (* is_end )(char c ),
277
+ int argc , char * argv [])
165
278
{
166
279
const char * in , * p ;
167
280
char * expansion , * out ;
@@ -177,7 +290,7 @@ static char *__expand_string(const char **str, bool (*is_end)(char c))
177
290
if (* p == '$' ) {
178
291
in_len = p - in ;
179
292
p ++ ;
180
- expansion = expand_dollar (& p );
293
+ expansion = expand_dollar_with_args (& p , argc , argv );
181
294
out_len += in_len + strlen (expansion );
182
295
out = xrealloc (out , out_len );
183
296
strncat (out , in , in_len );
@@ -210,13 +323,18 @@ static bool is_end_of_str(char c)
210
323
}
211
324
212
325
/*
213
- * Expand variables in the given string. Undefined variables
326
+ * Expand variables and functions in the given string. Undefined variables
214
327
* expand to an empty string.
215
328
* The returned string must be freed when done.
216
329
*/
330
+ static char * expand_string_with_args (const char * in , int argc , char * argv [])
331
+ {
332
+ return __expand_string (& in , is_end_of_str , argc , argv );
333
+ }
334
+
217
335
char * expand_string (const char * in )
218
336
{
219
- return __expand_string ( & in , is_end_of_str );
337
+ return expand_string_with_args ( in , 0 , NULL );
220
338
}
221
339
222
340
static bool is_end_of_token (char c )
@@ -234,5 +352,5 @@ static bool is_end_of_token(char c)
234
352
*/
235
353
char * expand_one_token (const char * * str )
236
354
{
237
- return __expand_string (str , is_end_of_token );
355
+ return __expand_string (str , is_end_of_token , 0 , NULL );
238
356
}
0 commit comments