1*99a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
2*99a2dd95SBruce Richardson * Copyright(c) 2010-2014 Intel Corporation.
3*99a2dd95SBruce Richardson * Copyright (c) 2009, Olivier MATZ <[email protected]>
4*99a2dd95SBruce Richardson * All rights reserved.
5*99a2dd95SBruce Richardson */
6*99a2dd95SBruce Richardson
7*99a2dd95SBruce Richardson #include <stdio.h>
8*99a2dd95SBruce Richardson #include <errno.h>
9*99a2dd95SBruce Richardson #include <string.h>
10*99a2dd95SBruce Richardson
11*99a2dd95SBruce Richardson #include <rte_string_fns.h>
12*99a2dd95SBruce Richardson
13*99a2dd95SBruce Richardson #include "cmdline_private.h"
14*99a2dd95SBruce Richardson
15*99a2dd95SBruce Richardson #ifdef RTE_LIBRTE_CMDLINE_DEBUG
16*99a2dd95SBruce Richardson #define debug_printf printf
17*99a2dd95SBruce Richardson #else
18*99a2dd95SBruce Richardson #define debug_printf(args...) do {} while(0)
19*99a2dd95SBruce Richardson #endif
20*99a2dd95SBruce Richardson
21*99a2dd95SBruce Richardson #define CMDLINE_BUFFER_SIZE 64
22*99a2dd95SBruce Richardson
23*99a2dd95SBruce Richardson /* isblank() needs _XOPEN_SOURCE >= 600 || _ISOC99_SOURCE, so use our
24*99a2dd95SBruce Richardson * own. */
25*99a2dd95SBruce Richardson static int
isblank2(char c)26*99a2dd95SBruce Richardson isblank2(char c)
27*99a2dd95SBruce Richardson {
28*99a2dd95SBruce Richardson if (c == ' ' ||
29*99a2dd95SBruce Richardson c == '\t' )
30*99a2dd95SBruce Richardson return 1;
31*99a2dd95SBruce Richardson return 0;
32*99a2dd95SBruce Richardson }
33*99a2dd95SBruce Richardson
34*99a2dd95SBruce Richardson static int
isendofline(char c)35*99a2dd95SBruce Richardson isendofline(char c)
36*99a2dd95SBruce Richardson {
37*99a2dd95SBruce Richardson if (c == '\n' ||
38*99a2dd95SBruce Richardson c == '\r' )
39*99a2dd95SBruce Richardson return 1;
40*99a2dd95SBruce Richardson return 0;
41*99a2dd95SBruce Richardson }
42*99a2dd95SBruce Richardson
43*99a2dd95SBruce Richardson static int
iscomment(char c)44*99a2dd95SBruce Richardson iscomment(char c)
45*99a2dd95SBruce Richardson {
46*99a2dd95SBruce Richardson if (c == '#')
47*99a2dd95SBruce Richardson return 1;
48*99a2dd95SBruce Richardson return 0;
49*99a2dd95SBruce Richardson }
50*99a2dd95SBruce Richardson
51*99a2dd95SBruce Richardson int
cmdline_isendoftoken(char c)52*99a2dd95SBruce Richardson cmdline_isendoftoken(char c)
53*99a2dd95SBruce Richardson {
54*99a2dd95SBruce Richardson if (!c || iscomment(c) || isblank2(c) || isendofline(c))
55*99a2dd95SBruce Richardson return 1;
56*99a2dd95SBruce Richardson return 0;
57*99a2dd95SBruce Richardson }
58*99a2dd95SBruce Richardson
59*99a2dd95SBruce Richardson int
cmdline_isendofcommand(char c)60*99a2dd95SBruce Richardson cmdline_isendofcommand(char c)
61*99a2dd95SBruce Richardson {
62*99a2dd95SBruce Richardson if (!c || iscomment(c) || isendofline(c))
63*99a2dd95SBruce Richardson return 1;
64*99a2dd95SBruce Richardson return 0;
65*99a2dd95SBruce Richardson }
66*99a2dd95SBruce Richardson
67*99a2dd95SBruce Richardson static unsigned int
nb_common_chars(const char * s1,const char * s2)68*99a2dd95SBruce Richardson nb_common_chars(const char * s1, const char * s2)
69*99a2dd95SBruce Richardson {
70*99a2dd95SBruce Richardson unsigned int i=0;
71*99a2dd95SBruce Richardson
72*99a2dd95SBruce Richardson while (*s1==*s2 && *s1) {
73*99a2dd95SBruce Richardson s1++;
74*99a2dd95SBruce Richardson s2++;
75*99a2dd95SBruce Richardson i++;
76*99a2dd95SBruce Richardson }
77*99a2dd95SBruce Richardson return i;
78*99a2dd95SBruce Richardson }
79*99a2dd95SBruce Richardson
80*99a2dd95SBruce Richardson /** Retrieve either static or dynamic token at a given index. */
81*99a2dd95SBruce Richardson static cmdline_parse_token_hdr_t *
get_token(cmdline_parse_inst_t * inst,unsigned int index)82*99a2dd95SBruce Richardson get_token(cmdline_parse_inst_t *inst, unsigned int index)
83*99a2dd95SBruce Richardson {
84*99a2dd95SBruce Richardson cmdline_parse_token_hdr_t *token_p;
85*99a2dd95SBruce Richardson
86*99a2dd95SBruce Richardson /* check presence of static tokens first */
87*99a2dd95SBruce Richardson if (inst->tokens[0] || !inst->f)
88*99a2dd95SBruce Richardson return inst->tokens[index];
89*99a2dd95SBruce Richardson /* generate dynamic token */
90*99a2dd95SBruce Richardson token_p = NULL;
91*99a2dd95SBruce Richardson inst->f(&token_p, NULL, &inst->tokens[index]);
92*99a2dd95SBruce Richardson return token_p;
93*99a2dd95SBruce Richardson }
94*99a2dd95SBruce Richardson
95*99a2dd95SBruce Richardson /**
96*99a2dd95SBruce Richardson * try to match the buffer with an instruction (only the first
97*99a2dd95SBruce Richardson * nb_match_token tokens if != 0). Return 0 if we match all the
98*99a2dd95SBruce Richardson * tokens, else the number of matched tokens, else -1.
99*99a2dd95SBruce Richardson */
100*99a2dd95SBruce Richardson static int
match_inst(cmdline_parse_inst_t * inst,const char * buf,unsigned int nb_match_token,void * resbuf,unsigned resbuf_size)101*99a2dd95SBruce Richardson match_inst(cmdline_parse_inst_t *inst, const char *buf,
102*99a2dd95SBruce Richardson unsigned int nb_match_token, void *resbuf, unsigned resbuf_size)
103*99a2dd95SBruce Richardson {
104*99a2dd95SBruce Richardson cmdline_parse_token_hdr_t *token_p = NULL;
105*99a2dd95SBruce Richardson unsigned int i=0;
106*99a2dd95SBruce Richardson int n = 0;
107*99a2dd95SBruce Richardson struct cmdline_token_hdr token_hdr;
108*99a2dd95SBruce Richardson
109*99a2dd95SBruce Richardson if (resbuf != NULL)
110*99a2dd95SBruce Richardson memset(resbuf, 0, resbuf_size);
111*99a2dd95SBruce Richardson /* check if we match all tokens of inst */
112*99a2dd95SBruce Richardson while (!nb_match_token || i < nb_match_token) {
113*99a2dd95SBruce Richardson token_p = get_token(inst, i);
114*99a2dd95SBruce Richardson if (!token_p)
115*99a2dd95SBruce Richardson break;
116*99a2dd95SBruce Richardson memcpy(&token_hdr, token_p, sizeof(token_hdr));
117*99a2dd95SBruce Richardson
118*99a2dd95SBruce Richardson debug_printf("TK\n");
119*99a2dd95SBruce Richardson /* skip spaces */
120*99a2dd95SBruce Richardson while (isblank2(*buf)) {
121*99a2dd95SBruce Richardson buf++;
122*99a2dd95SBruce Richardson }
123*99a2dd95SBruce Richardson
124*99a2dd95SBruce Richardson /* end of buf */
125*99a2dd95SBruce Richardson if ( isendofline(*buf) || iscomment(*buf) )
126*99a2dd95SBruce Richardson break;
127*99a2dd95SBruce Richardson
128*99a2dd95SBruce Richardson if (resbuf == NULL) {
129*99a2dd95SBruce Richardson n = token_hdr.ops->parse(token_p, buf, NULL, 0);
130*99a2dd95SBruce Richardson } else {
131*99a2dd95SBruce Richardson unsigned rb_sz;
132*99a2dd95SBruce Richardson
133*99a2dd95SBruce Richardson if (token_hdr.offset > resbuf_size) {
134*99a2dd95SBruce Richardson printf("Parse error(%s:%d): Token offset(%u) "
135*99a2dd95SBruce Richardson "exceeds maximum size(%u)\n",
136*99a2dd95SBruce Richardson __FILE__, __LINE__,
137*99a2dd95SBruce Richardson token_hdr.offset, resbuf_size);
138*99a2dd95SBruce Richardson return -ENOBUFS;
139*99a2dd95SBruce Richardson }
140*99a2dd95SBruce Richardson rb_sz = resbuf_size - token_hdr.offset;
141*99a2dd95SBruce Richardson
142*99a2dd95SBruce Richardson n = token_hdr.ops->parse(token_p, buf, (char *)resbuf +
143*99a2dd95SBruce Richardson token_hdr.offset, rb_sz);
144*99a2dd95SBruce Richardson }
145*99a2dd95SBruce Richardson
146*99a2dd95SBruce Richardson if (n < 0)
147*99a2dd95SBruce Richardson break;
148*99a2dd95SBruce Richardson
149*99a2dd95SBruce Richardson debug_printf("TK parsed (len=%d)\n", n);
150*99a2dd95SBruce Richardson i++;
151*99a2dd95SBruce Richardson buf += n;
152*99a2dd95SBruce Richardson }
153*99a2dd95SBruce Richardson
154*99a2dd95SBruce Richardson /* does not match */
155*99a2dd95SBruce Richardson if (i==0)
156*99a2dd95SBruce Richardson return -1;
157*99a2dd95SBruce Richardson
158*99a2dd95SBruce Richardson /* in case we want to match a specific num of token */
159*99a2dd95SBruce Richardson if (nb_match_token) {
160*99a2dd95SBruce Richardson if (i == nb_match_token) {
161*99a2dd95SBruce Richardson return 0;
162*99a2dd95SBruce Richardson }
163*99a2dd95SBruce Richardson return i;
164*99a2dd95SBruce Richardson }
165*99a2dd95SBruce Richardson
166*99a2dd95SBruce Richardson /* we don't match all the tokens */
167*99a2dd95SBruce Richardson if (token_p) {
168*99a2dd95SBruce Richardson return i;
169*99a2dd95SBruce Richardson }
170*99a2dd95SBruce Richardson
171*99a2dd95SBruce Richardson /* are there are some tokens more */
172*99a2dd95SBruce Richardson while (isblank2(*buf)) {
173*99a2dd95SBruce Richardson buf++;
174*99a2dd95SBruce Richardson }
175*99a2dd95SBruce Richardson
176*99a2dd95SBruce Richardson /* end of buf */
177*99a2dd95SBruce Richardson if ( isendofline(*buf) || iscomment(*buf) )
178*99a2dd95SBruce Richardson return 0;
179*99a2dd95SBruce Richardson
180*99a2dd95SBruce Richardson /* garbage after inst */
181*99a2dd95SBruce Richardson return i;
182*99a2dd95SBruce Richardson }
183*99a2dd95SBruce Richardson
184*99a2dd95SBruce Richardson
185*99a2dd95SBruce Richardson int
cmdline_parse(struct cmdline * cl,const char * buf)186*99a2dd95SBruce Richardson cmdline_parse(struct cmdline *cl, const char * buf)
187*99a2dd95SBruce Richardson {
188*99a2dd95SBruce Richardson unsigned int inst_num=0;
189*99a2dd95SBruce Richardson cmdline_parse_inst_t *inst;
190*99a2dd95SBruce Richardson const char *curbuf;
191*99a2dd95SBruce Richardson union {
192*99a2dd95SBruce Richardson char buf[CMDLINE_PARSE_RESULT_BUFSIZE];
193*99a2dd95SBruce Richardson long double align; /* strong alignment constraint for buf */
194*99a2dd95SBruce Richardson } result, tmp_result;
195*99a2dd95SBruce Richardson void (*f)(void *, struct cmdline *, void *) = NULL;
196*99a2dd95SBruce Richardson void *data = NULL;
197*99a2dd95SBruce Richardson int comment = 0;
198*99a2dd95SBruce Richardson int linelen = 0;
199*99a2dd95SBruce Richardson int parse_it = 0;
200*99a2dd95SBruce Richardson int err = CMDLINE_PARSE_NOMATCH;
201*99a2dd95SBruce Richardson int tok;
202*99a2dd95SBruce Richardson cmdline_parse_ctx_t *ctx;
203*99a2dd95SBruce Richardson char *result_buf = result.buf;
204*99a2dd95SBruce Richardson
205*99a2dd95SBruce Richardson if (!cl || !buf)
206*99a2dd95SBruce Richardson return CMDLINE_PARSE_BAD_ARGS;
207*99a2dd95SBruce Richardson
208*99a2dd95SBruce Richardson ctx = cl->ctx;
209*99a2dd95SBruce Richardson
210*99a2dd95SBruce Richardson /*
211*99a2dd95SBruce Richardson * - look if the buffer contains at least one line
212*99a2dd95SBruce Richardson * - look if line contains only spaces or comments
213*99a2dd95SBruce Richardson * - count line length
214*99a2dd95SBruce Richardson */
215*99a2dd95SBruce Richardson curbuf = buf;
216*99a2dd95SBruce Richardson while (! isendofline(*curbuf)) {
217*99a2dd95SBruce Richardson if ( *curbuf == '\0' ) {
218*99a2dd95SBruce Richardson debug_printf("Incomplete buf (len=%d)\n", linelen);
219*99a2dd95SBruce Richardson return 0;
220*99a2dd95SBruce Richardson }
221*99a2dd95SBruce Richardson if ( iscomment(*curbuf) ) {
222*99a2dd95SBruce Richardson comment = 1;
223*99a2dd95SBruce Richardson }
224*99a2dd95SBruce Richardson if ( ! isblank2(*curbuf) && ! comment) {
225*99a2dd95SBruce Richardson parse_it = 1;
226*99a2dd95SBruce Richardson }
227*99a2dd95SBruce Richardson curbuf++;
228*99a2dd95SBruce Richardson linelen++;
229*99a2dd95SBruce Richardson }
230*99a2dd95SBruce Richardson
231*99a2dd95SBruce Richardson /* skip all endofline chars */
232*99a2dd95SBruce Richardson while (isendofline(buf[linelen])) {
233*99a2dd95SBruce Richardson linelen++;
234*99a2dd95SBruce Richardson }
235*99a2dd95SBruce Richardson
236*99a2dd95SBruce Richardson /* empty line */
237*99a2dd95SBruce Richardson if ( parse_it == 0 ) {
238*99a2dd95SBruce Richardson debug_printf("Empty line (len=%d)\n", linelen);
239*99a2dd95SBruce Richardson return linelen;
240*99a2dd95SBruce Richardson }
241*99a2dd95SBruce Richardson
242*99a2dd95SBruce Richardson debug_printf("Parse line : len=%d, <%.*s>\n",
243*99a2dd95SBruce Richardson linelen, linelen > 64 ? 64 : linelen, buf);
244*99a2dd95SBruce Richardson
245*99a2dd95SBruce Richardson /* parse it !! */
246*99a2dd95SBruce Richardson inst = ctx[inst_num];
247*99a2dd95SBruce Richardson while (inst) {
248*99a2dd95SBruce Richardson debug_printf("INST %d\n", inst_num);
249*99a2dd95SBruce Richardson
250*99a2dd95SBruce Richardson /* fully parsed */
251*99a2dd95SBruce Richardson tok = match_inst(inst, buf, 0, result_buf,
252*99a2dd95SBruce Richardson CMDLINE_PARSE_RESULT_BUFSIZE);
253*99a2dd95SBruce Richardson
254*99a2dd95SBruce Richardson if (tok > 0) /* we matched at least one token */
255*99a2dd95SBruce Richardson err = CMDLINE_PARSE_BAD_ARGS;
256*99a2dd95SBruce Richardson
257*99a2dd95SBruce Richardson else if (!tok) {
258*99a2dd95SBruce Richardson debug_printf("INST fully parsed\n");
259*99a2dd95SBruce Richardson /* skip spaces */
260*99a2dd95SBruce Richardson while (isblank2(*curbuf)) {
261*99a2dd95SBruce Richardson curbuf++;
262*99a2dd95SBruce Richardson }
263*99a2dd95SBruce Richardson
264*99a2dd95SBruce Richardson /* if end of buf -> there is no garbage after inst */
265*99a2dd95SBruce Richardson if (isendofline(*curbuf) || iscomment(*curbuf)) {
266*99a2dd95SBruce Richardson if (!f) {
267*99a2dd95SBruce Richardson memcpy(&f, &inst->f, sizeof(f));
268*99a2dd95SBruce Richardson memcpy(&data, &inst->data, sizeof(data));
269*99a2dd95SBruce Richardson result_buf = tmp_result.buf;
270*99a2dd95SBruce Richardson }
271*99a2dd95SBruce Richardson else {
272*99a2dd95SBruce Richardson /* more than 1 inst matches */
273*99a2dd95SBruce Richardson err = CMDLINE_PARSE_AMBIGUOUS;
274*99a2dd95SBruce Richardson f=NULL;
275*99a2dd95SBruce Richardson debug_printf("Ambiguous cmd\n");
276*99a2dd95SBruce Richardson break;
277*99a2dd95SBruce Richardson }
278*99a2dd95SBruce Richardson }
279*99a2dd95SBruce Richardson }
280*99a2dd95SBruce Richardson
281*99a2dd95SBruce Richardson inst_num ++;
282*99a2dd95SBruce Richardson inst = ctx[inst_num];
283*99a2dd95SBruce Richardson }
284*99a2dd95SBruce Richardson
285*99a2dd95SBruce Richardson /* call func */
286*99a2dd95SBruce Richardson if (f) {
287*99a2dd95SBruce Richardson f(result.buf, cl, data);
288*99a2dd95SBruce Richardson }
289*99a2dd95SBruce Richardson
290*99a2dd95SBruce Richardson /* no match */
291*99a2dd95SBruce Richardson else {
292*99a2dd95SBruce Richardson debug_printf("No match err=%d\n", err);
293*99a2dd95SBruce Richardson return err;
294*99a2dd95SBruce Richardson }
295*99a2dd95SBruce Richardson
296*99a2dd95SBruce Richardson return linelen;
297*99a2dd95SBruce Richardson }
298*99a2dd95SBruce Richardson
299*99a2dd95SBruce Richardson int
cmdline_complete(struct cmdline * cl,const char * buf,int * state,char * dst,unsigned int size)300*99a2dd95SBruce Richardson cmdline_complete(struct cmdline *cl, const char *buf, int *state,
301*99a2dd95SBruce Richardson char *dst, unsigned int size)
302*99a2dd95SBruce Richardson {
303*99a2dd95SBruce Richardson const char *partial_tok = buf;
304*99a2dd95SBruce Richardson unsigned int inst_num = 0;
305*99a2dd95SBruce Richardson cmdline_parse_inst_t *inst;
306*99a2dd95SBruce Richardson cmdline_parse_token_hdr_t *token_p;
307*99a2dd95SBruce Richardson struct cmdline_token_hdr token_hdr;
308*99a2dd95SBruce Richardson char tmpbuf[CMDLINE_BUFFER_SIZE], comp_buf[CMDLINE_BUFFER_SIZE];
309*99a2dd95SBruce Richardson unsigned int partial_tok_len;
310*99a2dd95SBruce Richardson int comp_len = -1;
311*99a2dd95SBruce Richardson int tmp_len = -1;
312*99a2dd95SBruce Richardson int nb_token = 0;
313*99a2dd95SBruce Richardson unsigned int i, n;
314*99a2dd95SBruce Richardson int l;
315*99a2dd95SBruce Richardson unsigned int nb_completable;
316*99a2dd95SBruce Richardson unsigned int nb_non_completable;
317*99a2dd95SBruce Richardson int local_state = 0;
318*99a2dd95SBruce Richardson const char *help_str;
319*99a2dd95SBruce Richardson cmdline_parse_ctx_t *ctx;
320*99a2dd95SBruce Richardson
321*99a2dd95SBruce Richardson if (!cl || !buf || !state || !dst)
322*99a2dd95SBruce Richardson return -1;
323*99a2dd95SBruce Richardson
324*99a2dd95SBruce Richardson ctx = cl->ctx;
325*99a2dd95SBruce Richardson
326*99a2dd95SBruce Richardson debug_printf("%s called\n", __func__);
327*99a2dd95SBruce Richardson memset(&token_hdr, 0, sizeof(token_hdr));
328*99a2dd95SBruce Richardson
329*99a2dd95SBruce Richardson /* count the number of complete token to parse */
330*99a2dd95SBruce Richardson for (i=0 ; buf[i] ; i++) {
331*99a2dd95SBruce Richardson if (!isblank2(buf[i]) && isblank2(buf[i+1]))
332*99a2dd95SBruce Richardson nb_token++;
333*99a2dd95SBruce Richardson if (isblank2(buf[i]) && !isblank2(buf[i+1]))
334*99a2dd95SBruce Richardson partial_tok = buf+i+1;
335*99a2dd95SBruce Richardson }
336*99a2dd95SBruce Richardson partial_tok_len = strnlen(partial_tok, RDLINE_BUF_SIZE);
337*99a2dd95SBruce Richardson
338*99a2dd95SBruce Richardson /* first call -> do a first pass */
339*99a2dd95SBruce Richardson if (*state <= 0) {
340*99a2dd95SBruce Richardson debug_printf("try complete <%s>\n", buf);
341*99a2dd95SBruce Richardson debug_printf("there is %d complete tokens, <%s> is incomplete\n",
342*99a2dd95SBruce Richardson nb_token, partial_tok);
343*99a2dd95SBruce Richardson
344*99a2dd95SBruce Richardson nb_completable = 0;
345*99a2dd95SBruce Richardson nb_non_completable = 0;
346*99a2dd95SBruce Richardson
347*99a2dd95SBruce Richardson inst = ctx[inst_num];
348*99a2dd95SBruce Richardson while (inst) {
349*99a2dd95SBruce Richardson /* parse the first tokens of the inst */
350*99a2dd95SBruce Richardson if (nb_token &&
351*99a2dd95SBruce Richardson match_inst(inst, buf, nb_token, NULL, 0))
352*99a2dd95SBruce Richardson goto next;
353*99a2dd95SBruce Richardson
354*99a2dd95SBruce Richardson debug_printf("instruction match\n");
355*99a2dd95SBruce Richardson token_p = get_token(inst, nb_token);
356*99a2dd95SBruce Richardson if (token_p)
357*99a2dd95SBruce Richardson memcpy(&token_hdr, token_p, sizeof(token_hdr));
358*99a2dd95SBruce Richardson
359*99a2dd95SBruce Richardson /* non completable */
360*99a2dd95SBruce Richardson if (!token_p ||
361*99a2dd95SBruce Richardson !token_hdr.ops->complete_get_nb ||
362*99a2dd95SBruce Richardson !token_hdr.ops->complete_get_elt ||
363*99a2dd95SBruce Richardson (n = token_hdr.ops->complete_get_nb(token_p)) == 0) {
364*99a2dd95SBruce Richardson nb_non_completable++;
365*99a2dd95SBruce Richardson goto next;
366*99a2dd95SBruce Richardson }
367*99a2dd95SBruce Richardson
368*99a2dd95SBruce Richardson debug_printf("%d choices for this token\n", n);
369*99a2dd95SBruce Richardson for (i=0 ; i<n ; i++) {
370*99a2dd95SBruce Richardson if (token_hdr.ops->complete_get_elt(token_p, i,
371*99a2dd95SBruce Richardson tmpbuf,
372*99a2dd95SBruce Richardson sizeof(tmpbuf)) < 0)
373*99a2dd95SBruce Richardson continue;
374*99a2dd95SBruce Richardson
375*99a2dd95SBruce Richardson /* we have at least room for one char */
376*99a2dd95SBruce Richardson tmp_len = strnlen(tmpbuf, sizeof(tmpbuf));
377*99a2dd95SBruce Richardson if (tmp_len < CMDLINE_BUFFER_SIZE - 1) {
378*99a2dd95SBruce Richardson tmpbuf[tmp_len] = ' ';
379*99a2dd95SBruce Richardson tmpbuf[tmp_len+1] = 0;
380*99a2dd95SBruce Richardson }
381*99a2dd95SBruce Richardson
382*99a2dd95SBruce Richardson debug_printf(" choice <%s>\n", tmpbuf);
383*99a2dd95SBruce Richardson
384*99a2dd95SBruce Richardson /* does the completion match the
385*99a2dd95SBruce Richardson * beginning of the word ? */
386*99a2dd95SBruce Richardson if (!strncmp(partial_tok, tmpbuf,
387*99a2dd95SBruce Richardson partial_tok_len)) {
388*99a2dd95SBruce Richardson if (comp_len == -1) {
389*99a2dd95SBruce Richardson strlcpy(comp_buf,
390*99a2dd95SBruce Richardson tmpbuf + partial_tok_len,
391*99a2dd95SBruce Richardson sizeof(comp_buf));
392*99a2dd95SBruce Richardson comp_len =
393*99a2dd95SBruce Richardson strnlen(tmpbuf + partial_tok_len,
394*99a2dd95SBruce Richardson sizeof(tmpbuf) - partial_tok_len);
395*99a2dd95SBruce Richardson
396*99a2dd95SBruce Richardson }
397*99a2dd95SBruce Richardson else {
398*99a2dd95SBruce Richardson comp_len =
399*99a2dd95SBruce Richardson nb_common_chars(comp_buf,
400*99a2dd95SBruce Richardson tmpbuf+partial_tok_len);
401*99a2dd95SBruce Richardson comp_buf[comp_len] = 0;
402*99a2dd95SBruce Richardson }
403*99a2dd95SBruce Richardson nb_completable++;
404*99a2dd95SBruce Richardson }
405*99a2dd95SBruce Richardson }
406*99a2dd95SBruce Richardson next:
407*99a2dd95SBruce Richardson debug_printf("next\n");
408*99a2dd95SBruce Richardson inst_num ++;
409*99a2dd95SBruce Richardson inst = ctx[inst_num];
410*99a2dd95SBruce Richardson }
411*99a2dd95SBruce Richardson
412*99a2dd95SBruce Richardson debug_printf("total choices %d for this completion\n",
413*99a2dd95SBruce Richardson nb_completable);
414*99a2dd95SBruce Richardson
415*99a2dd95SBruce Richardson /* no possible completion */
416*99a2dd95SBruce Richardson if (nb_completable == 0 && nb_non_completable == 0)
417*99a2dd95SBruce Richardson return 0;
418*99a2dd95SBruce Richardson
419*99a2dd95SBruce Richardson /* if multichoice is not required */
420*99a2dd95SBruce Richardson if (*state == 0 && partial_tok_len > 0) {
421*99a2dd95SBruce Richardson /* one or several choices starting with the
422*99a2dd95SBruce Richardson same chars */
423*99a2dd95SBruce Richardson if (comp_len > 0) {
424*99a2dd95SBruce Richardson if ((unsigned)(comp_len + 1) > size)
425*99a2dd95SBruce Richardson return 0;
426*99a2dd95SBruce Richardson
427*99a2dd95SBruce Richardson strlcpy(dst, comp_buf, size);
428*99a2dd95SBruce Richardson dst[comp_len] = 0;
429*99a2dd95SBruce Richardson return 2;
430*99a2dd95SBruce Richardson }
431*99a2dd95SBruce Richardson }
432*99a2dd95SBruce Richardson }
433*99a2dd95SBruce Richardson
434*99a2dd95SBruce Richardson /* init state correctly */
435*99a2dd95SBruce Richardson if (*state == -1)
436*99a2dd95SBruce Richardson *state = 0;
437*99a2dd95SBruce Richardson
438*99a2dd95SBruce Richardson debug_printf("Multiple choice STATE=%d\n", *state);
439*99a2dd95SBruce Richardson
440*99a2dd95SBruce Richardson inst_num = 0;
441*99a2dd95SBruce Richardson inst = ctx[inst_num];
442*99a2dd95SBruce Richardson while (inst) {
443*99a2dd95SBruce Richardson /* we need to redo it */
444*99a2dd95SBruce Richardson inst = ctx[inst_num];
445*99a2dd95SBruce Richardson
446*99a2dd95SBruce Richardson if (nb_token &&
447*99a2dd95SBruce Richardson match_inst(inst, buf, nb_token, NULL, 0))
448*99a2dd95SBruce Richardson goto next2;
449*99a2dd95SBruce Richardson
450*99a2dd95SBruce Richardson token_p = get_token(inst, nb_token);
451*99a2dd95SBruce Richardson if (token_p)
452*99a2dd95SBruce Richardson memcpy(&token_hdr, token_p, sizeof(token_hdr));
453*99a2dd95SBruce Richardson
454*99a2dd95SBruce Richardson /* one choice for this token */
455*99a2dd95SBruce Richardson if (!token_p ||
456*99a2dd95SBruce Richardson !token_hdr.ops->complete_get_nb ||
457*99a2dd95SBruce Richardson !token_hdr.ops->complete_get_elt ||
458*99a2dd95SBruce Richardson (n = token_hdr.ops->complete_get_nb(token_p)) == 0) {
459*99a2dd95SBruce Richardson if (local_state < *state) {
460*99a2dd95SBruce Richardson local_state++;
461*99a2dd95SBruce Richardson goto next2;
462*99a2dd95SBruce Richardson }
463*99a2dd95SBruce Richardson (*state)++;
464*99a2dd95SBruce Richardson if (token_p && token_hdr.ops->get_help) {
465*99a2dd95SBruce Richardson token_hdr.ops->get_help(token_p, tmpbuf,
466*99a2dd95SBruce Richardson sizeof(tmpbuf));
467*99a2dd95SBruce Richardson help_str = inst->help_str;
468*99a2dd95SBruce Richardson if (help_str)
469*99a2dd95SBruce Richardson snprintf(dst, size, "[%s]: %s", tmpbuf,
470*99a2dd95SBruce Richardson help_str);
471*99a2dd95SBruce Richardson else
472*99a2dd95SBruce Richardson snprintf(dst, size, "[%s]: No help",
473*99a2dd95SBruce Richardson tmpbuf);
474*99a2dd95SBruce Richardson }
475*99a2dd95SBruce Richardson else {
476*99a2dd95SBruce Richardson snprintf(dst, size, "[RETURN]");
477*99a2dd95SBruce Richardson }
478*99a2dd95SBruce Richardson return 1;
479*99a2dd95SBruce Richardson }
480*99a2dd95SBruce Richardson
481*99a2dd95SBruce Richardson /* several choices */
482*99a2dd95SBruce Richardson for (i=0 ; i<n ; i++) {
483*99a2dd95SBruce Richardson if (token_hdr.ops->complete_get_elt(token_p, i, tmpbuf,
484*99a2dd95SBruce Richardson sizeof(tmpbuf)) < 0)
485*99a2dd95SBruce Richardson continue;
486*99a2dd95SBruce Richardson /* we have at least room for one char */
487*99a2dd95SBruce Richardson tmp_len = strnlen(tmpbuf, sizeof(tmpbuf));
488*99a2dd95SBruce Richardson if (tmp_len < CMDLINE_BUFFER_SIZE - 1) {
489*99a2dd95SBruce Richardson tmpbuf[tmp_len] = ' ';
490*99a2dd95SBruce Richardson tmpbuf[tmp_len + 1] = 0;
491*99a2dd95SBruce Richardson }
492*99a2dd95SBruce Richardson
493*99a2dd95SBruce Richardson debug_printf(" choice <%s>\n", tmpbuf);
494*99a2dd95SBruce Richardson
495*99a2dd95SBruce Richardson /* does the completion match the beginning of
496*99a2dd95SBruce Richardson * the word ? */
497*99a2dd95SBruce Richardson if (!strncmp(partial_tok, tmpbuf,
498*99a2dd95SBruce Richardson partial_tok_len)) {
499*99a2dd95SBruce Richardson if (local_state < *state) {
500*99a2dd95SBruce Richardson local_state++;
501*99a2dd95SBruce Richardson continue;
502*99a2dd95SBruce Richardson }
503*99a2dd95SBruce Richardson (*state)++;
504*99a2dd95SBruce Richardson l=strlcpy(dst, tmpbuf, size);
505*99a2dd95SBruce Richardson if (l>=0 && token_hdr.ops->get_help) {
506*99a2dd95SBruce Richardson token_hdr.ops->get_help(token_p, tmpbuf,
507*99a2dd95SBruce Richardson sizeof(tmpbuf));
508*99a2dd95SBruce Richardson help_str = inst->help_str;
509*99a2dd95SBruce Richardson if (help_str)
510*99a2dd95SBruce Richardson snprintf(dst+l, size-l, "[%s]: %s",
511*99a2dd95SBruce Richardson tmpbuf, help_str);
512*99a2dd95SBruce Richardson else
513*99a2dd95SBruce Richardson snprintf(dst+l, size-l,
514*99a2dd95SBruce Richardson "[%s]: No help", tmpbuf);
515*99a2dd95SBruce Richardson }
516*99a2dd95SBruce Richardson
517*99a2dd95SBruce Richardson return 1;
518*99a2dd95SBruce Richardson }
519*99a2dd95SBruce Richardson }
520*99a2dd95SBruce Richardson next2:
521*99a2dd95SBruce Richardson inst_num ++;
522*99a2dd95SBruce Richardson inst = ctx[inst_num];
523*99a2dd95SBruce Richardson }
524*99a2dd95SBruce Richardson return 0;
525*99a2dd95SBruce Richardson }
526