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