Project

General

Profile

Statistics
| Branch: | Tag: | Revision:

klish / clish / shell / shell_parse.c @ b683ac25

History | View | Annotate | Download (8.37 KB)

1
/*
2
 * shell_parse.c
3
 */
4

    
5
#include <string.h>
6
#include <assert.h>
7

    
8
#include "lub/string.h"
9
#include "lub/system.h"
10
#include "private.h"
11

    
12
/*----------------------------------------------------------- */
13
clish_pargv_status_t clish_shell_parse(
14
        clish_shell_t *this, const char *line,
15
        const clish_command_t **ret_cmd, clish_pargv_t **pargv)
16
{
17
        clish_pargv_status_t result = CLISH_BAD_CMD;
18
        clish_context_t context;
19
        const clish_command_t *cmd;
20
        lub_argv_t *argv = NULL;
21
        unsigned int idx;
22

    
23
        *ret_cmd = cmd = clish_shell_resolve_command(this, line);
24
        if (!cmd)
25
                return result;
26

    
27
        /* Now construct the parameters for the command */
28
        /* Prepare context */
29
        *pargv = clish_pargv_new();
30
        clish_context_init(&context, this);
31
        clish_context__set_cmd(&context, cmd);
32
        clish_context__set_pargv(&context, *pargv);
33

    
34
        idx = lub_string_wordcount(clish_command__get_name(cmd));
35
        argv = lub_argv_new(line, 0);
36
        result = clish_shell_parse_pargv(*pargv, cmd, &context,
37
                clish_command__get_paramv(cmd),
38
                argv, &idx, NULL, 0);
39
        lub_argv_delete(argv);
40
        if (CLISH_LINE_OK != result) {
41
                clish_pargv_delete(*pargv);
42
                *pargv = NULL;
43
        }
44

    
45
        return result;
46
}
47

    
48
/*--------------------------------------------------------- */
49
static bool_t line_test(const clish_param_t *param, void *context)
50
{
51
        char *str = NULL;
52
        char *teststr = NULL;
53
        bool_t res;
54

    
55
        if (!param)
56
                return BOOL_FALSE;
57
        teststr = clish_param__get_test(param);
58
        if (!teststr)
59
                return BOOL_TRUE;
60
        str = clish_shell_expand(teststr, SHELL_VAR_ACTION, context);
61
        if (!str)
62
                return BOOL_FALSE;
63
        res = lub_system_line_test(str);
64
        lub_string_free(str);
65

    
66
        return res;
67
}
68

    
69
/*--------------------------------------------------------- */
70
clish_pargv_status_t clish_shell_parse_pargv(clish_pargv_t *pargv,
71
        const clish_command_t *cmd,
72
        void *context,
73
        clish_paramv_t *paramv,
74
        const lub_argv_t *argv,
75
        unsigned *idx, clish_pargv_t *last, unsigned need_index)
76
{
77
        unsigned argc = lub_argv__get_count(argv);
78
        unsigned index = 0;
79
        unsigned nopt_index = 0;
80
        clish_param_t *nopt_param = NULL;
81
        unsigned i;
82
        clish_pargv_status_t retval;
83
        unsigned paramc = clish_paramv__get_count(paramv);
84
        int up_level = 0; /* Is it a first level of param nesting? */
85

    
86
        assert(pargv);
87
        assert(cmd);
88

    
89
        /* Check is it a first level of PARAM nesting. */
90
        if (paramv == clish_command__get_paramv(cmd))
91
                up_level = 1;
92

    
93
        while (index < paramc) {
94
                const char *arg = NULL;
95
                clish_param_t *param = clish_paramv__get_param(paramv, index);
96
                clish_param_t *cparam = NULL;
97
                int is_switch = 0;
98

    
99
                if (!param)
100
                        return CLISH_BAD_PARAM;
101

    
102
                /* Use real arg or PARAM's default value as argument */
103
                if (*idx < argc)
104
                        arg = lub_argv__get_arg(argv, *idx);
105

    
106
                /* Is parameter in "switch" mode? */
107
                if (CLISH_PARAM_SWITCH == clish_param__get_mode(param))
108
                        is_switch = 1;
109

    
110
                /* Check the 'test' conditions */
111
                if (!line_test(param, context)) {
112
                        index++;
113
                        continue;
114
                }
115

    
116
                /* Add param for help and completion */
117
                if (last && (*idx == need_index) &&
118
                        (NULL == clish_pargv_find_arg(pargv, clish_param__get_name(param)))) {
119
                        if (is_switch) {
120
                                unsigned rec_paramc = clish_param__get_param_count(param);
121
                                for (i = 0; i < rec_paramc; i++) {
122
                                        cparam = clish_param__get_param(param, i);
123
                                        if (!cparam)
124
                                                break;
125
                                        if (!line_test(cparam, context))
126
                                                continue;
127
                                        if (CLISH_PARAM_SUBCOMMAND ==
128
                                                clish_param__get_mode(cparam)) {
129
                                                const char *pname =
130
                                                        clish_param__get_value(cparam);
131
                                                if (!arg || (arg && 
132
                                                        (pname == lub_string_nocasestr(pname,
133
                                                        arg))))
134
                                                        clish_pargv_insert(last,
135
                                                                cparam, arg);
136
                                        } else {
137
                                                clish_pargv_insert(last,
138
                                                        cparam, arg);
139
                                        }
140
                                }
141
                        } else {
142
                                if (CLISH_PARAM_SUBCOMMAND ==
143
                                        clish_param__get_mode(param)) {
144
                                        const char *pname =
145
                                            clish_param__get_value(param);
146
                                        if (!arg || (arg &&
147
                                                (pname == lub_string_nocasestr(pname, arg))))
148
                                                clish_pargv_insert(last, param, arg);
149
                                } else {
150
                                        clish_pargv_insert(last, param, arg);
151
                                }
152
                        }
153
                }
154

    
155
                /* Set parameter value */
156
                {
157
                        char *validated = NULL;
158
                        clish_paramv_t *rec_paramv =
159
                            clish_param__get_paramv(param);
160
                        unsigned rec_paramc =
161
                            clish_param__get_param_count(param);
162

    
163
                        /* Save the index of last non-option parameter
164
                         * to restore index if the optional parameters
165
                         * will be used.
166
                         */
167
                        if (!clish_param__get_optional(param)) {
168
                                nopt_param = param;
169
                                nopt_index = index;
170
                        }
171

    
172
                        /* Validate the current parameter. */
173
                        if (clish_pargv_find_arg(pargv, clish_param__get_name(param))) {
174
                                /* Duplicated parameter */
175
                                validated = NULL;
176
                        } else if (is_switch) {
177
                                for (i = 0; i < rec_paramc; i++) {
178
                                        cparam = clish_param__get_param(param, i);
179
                                        if (!cparam)
180
                                                break;
181
                                        if (!line_test(cparam, context))
182
                                                continue;
183
                                        if ((validated = arg ?
184
                                                clish_param_validate(cparam, arg) : NULL)) {
185
                                                rec_paramv = clish_param__get_paramv(cparam);
186
                                                rec_paramc = clish_param__get_param_count(cparam);
187
                                                break;
188
                                        }
189
                                }
190
                        } else {
191
                                validated = arg ?
192
                                        clish_param_validate(param, arg) : NULL;
193
                        }
194

    
195
                        if (validated) {
196
                                /* add (or update) this parameter */
197
                                if (is_switch) {
198
                                        clish_pargv_insert(pargv, param,
199
                                                clish_param__get_name(cparam));
200
                                        clish_pargv_insert(pargv, cparam,
201
                                                validated);
202
                                } else {
203
                                        clish_pargv_insert(pargv, param,
204
                                                validated);
205
                                }
206
                                lub_string_free(validated);
207

    
208
                                /* Next command line argument */
209
                                /* Don't change idx if this is the last
210
                                   unfinished optional argument.
211
                                 */
212
                                if (!(clish_param__get_optional(param) &&
213
                                        (*idx == need_index) &&
214
                                        (need_index == (argc - 1)))) {
215
                                        (*idx)++;
216
                                        /* Walk through the nested parameters */
217
                                        if (rec_paramc) {
218
                                                retval = clish_shell_parse_pargv(pargv, cmd,
219
                                                        context, rec_paramv,
220
                                                        argv, idx, last, need_index);
221
                                                if (CLISH_LINE_OK != retval)
222
                                                        return retval;
223
                                        }
224
                                }
225

    
226
                                /* Choose the next parameter */
227
                                if (clish_param__get_optional(param) &&
228
                                        !clish_param__get_order(param)) {
229
                                        if (nopt_param)
230
                                                index = nopt_index + 1;
231
                                        else
232
                                                index = 0;
233
                                } else {
234
                                        /* Save non-option position in
235
                                           case of ordered optional param */
236
                                        nopt_param = param;
237
                                        nopt_index = index;
238
                                        index++;
239
                                }
240

    
241
                        } else {
242
                                /* Choose the next parameter if current
243
                                 * is not validated.
244
                                 */
245
                                if (clish_param__get_optional(param))
246
                                        index++;
247
                                else {
248
                                        if (!arg)
249
                                                break;
250
                                        else
251
                                                return CLISH_BAD_PARAM;
252
                                }
253
                        }
254
                }
255
        }
256

    
257
        /* Check for non-optional parameters without values */
258
        if ((*idx >= argc) && (index < paramc)) {
259
                unsigned j = index;
260
                const clish_param_t *param;
261
                while (j < paramc) {
262
                        param = clish_paramv__get_param(paramv, j++);
263
                        if (BOOL_TRUE != clish_param__get_optional(param))
264
                                return CLISH_LINE_PARTIAL;
265
                }
266
        }
267

    
268
        /* If the number of arguments is bigger than number of
269
         * params than it's a args. So generate the args entry
270
         * in the list of completions.
271
         */
272
        if (last && up_level &&
273
                        clish_command__get_args(cmd) &&
274
                        (clish_pargv__get_count(last) == 0) &&
275
                        (*idx <= argc) && (index >= paramc)) {
276
                clish_pargv_insert(last, clish_command__get_args(cmd), "");
277
        }
278

    
279
        /*
280
         * if we've satisfied all the parameters we can now construct
281
         * an 'args' parameter if one exists
282
         */
283
        if (up_level && (*idx < argc) && (index >= paramc)) {
284
                const char *arg = lub_argv__get_arg(argv, *idx);
285
                const clish_param_t *param = clish_command__get_args(cmd);
286
                char *args = NULL;
287

    
288
                if (!param)
289
                        return CLISH_BAD_CMD;
290

    
291
                /*
292
                 * put all the argument into a single string
293
                 */
294
                while (NULL != arg) {
295
                        bool_t quoted = lub_argv__get_quoted(argv, *idx);
296
                        if (BOOL_TRUE == quoted) {
297
                                lub_string_cat(&args, "\"");
298
                        }
299
                        /* place the current argument in the string */
300
                        lub_string_cat(&args, arg);
301
                        if (BOOL_TRUE == quoted) {
302
                                lub_string_cat(&args, "\"");
303
                        }
304
                        (*idx)++;
305
                        arg = lub_argv__get_arg(argv, *idx);
306
                        if (NULL != arg) {
307
                                /* add a space if there are more arguments */
308
                                lub_string_cat(&args, " ");
309
                        }
310
                }
311
                /* add (or update) this parameter */
312
                clish_pargv_insert(pargv, param, args);
313
                lub_string_free(args);
314
        }
315

    
316
        return CLISH_LINE_OK;
317
}
318

    
319
/*----------------------------------------------------------- */
320
clish_shell_state_e clish_shell__get_state(const clish_shell_t *this)
321
{
322
        return this->state;
323
}
324

    
325
/*----------------------------------------------------------- */
326
void clish_shell__set_state(clish_shell_t *this,
327
        clish_shell_state_e state)
328
{
329
        assert(this);
330
        this->state = state;
331
}
332

    
333
/*----------------------------------------------------------- */