]> git.proxmox.com Git - ceph.git/blob - ceph/src/seastar/dpdk/test/test/test_cmdline_num.c
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / seastar / dpdk / test / test / test_cmdline_num.c
1 /*-
2 * BSD LICENSE
3 *
4 * Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include <stdio.h>
35 #include <string.h>
36 #include <inttypes.h>
37
38 #include <rte_string_fns.h>
39
40 #include <cmdline_parse.h>
41 #include <cmdline_parse_num.h>
42
43 #include "test_cmdline.h"
44
45 struct num_unsigned_str {
46 const char * str;
47 uint64_t result;
48 };
49
50 struct num_signed_str {
51 const char * str;
52 int64_t result;
53 };
54
55 const struct num_unsigned_str num_valid_positive_strs[] = {
56 /* decimal positive */
57 {"0", 0 },
58 {"127", INT8_MAX },
59 {"128", INT8_MAX + 1 },
60 {"255", UINT8_MAX },
61 {"256", UINT8_MAX + 1 },
62 {"32767", INT16_MAX },
63 {"32768", INT16_MAX + 1 },
64 {"65535", UINT16_MAX },
65 {"65536", UINT16_MAX + 1 },
66 {"2147483647", INT32_MAX },
67 {"2147483648", INT32_MAX + 1U },
68 {"4294967295", UINT32_MAX },
69 {"4294967296", UINT32_MAX + 1ULL },
70 {"9223372036854775807", INT64_MAX },
71 {"9223372036854775808", INT64_MAX + 1ULL},
72 {"18446744073709551615", UINT64_MAX },
73 /* hexadecimal (no leading zeroes) */
74 {"0x0", 0 },
75 {"0x7F", INT8_MAX },
76 {"0x80", INT8_MAX + 1 },
77 {"0xFF", UINT8_MAX },
78 {"0x100", UINT8_MAX + 1 },
79 {"0x7FFF", INT16_MAX },
80 {"0x8000", INT16_MAX + 1 },
81 {"0xFFFF", UINT16_MAX },
82 {"0x10000", UINT16_MAX + 1 },
83 {"0x7FFFFFFF", INT32_MAX },
84 {"0x80000000", INT32_MAX + 1U },
85 {"0xFFFFFFFF", UINT32_MAX },
86 {"0x100000000", UINT32_MAX + 1ULL },
87 {"0x7FFFFFFFFFFFFFFF", INT64_MAX },
88 {"0x8000000000000000", INT64_MAX + 1ULL},
89 {"0xFFFFFFFFFFFFFFFF", UINT64_MAX },
90 /* hexadecimal (with leading zeroes) */
91 {"0x00", 0 },
92 {"0x7F", INT8_MAX },
93 {"0x80", INT8_MAX + 1 },
94 {"0xFF", UINT8_MAX },
95 {"0x0100", UINT8_MAX + 1 },
96 {"0x7FFF", INT16_MAX },
97 {"0x8000", INT16_MAX + 1 },
98 {"0xFFFF", UINT16_MAX },
99 {"0x00010000", UINT16_MAX + 1 },
100 {"0x7FFFFFFF", INT32_MAX },
101 {"0x80000000", INT32_MAX + 1U },
102 {"0xFFFFFFFF", UINT32_MAX },
103 {"0x0000000100000000", UINT32_MAX + 1ULL },
104 {"0x7FFFFFFFFFFFFFFF", INT64_MAX },
105 {"0x8000000000000000", INT64_MAX + 1ULL},
106 {"0xFFFFFFFFFFFFFFFF", UINT64_MAX },
107 /* check all characters */
108 {"0x1234567890ABCDEF", 0x1234567890ABCDEFULL },
109 {"0x1234567890abcdef", 0x1234567890ABCDEFULL },
110 /* binary (no leading zeroes) */
111 {"0b0", 0 },
112 {"0b1111111", INT8_MAX },
113 {"0b10000000", INT8_MAX + 1 },
114 {"0b11111111", UINT8_MAX },
115 {"0b100000000", UINT8_MAX + 1 },
116 {"0b111111111111111", INT16_MAX },
117 {"0b1000000000000000", INT16_MAX + 1 },
118 {"0b1111111111111111", UINT16_MAX },
119 {"0b10000000000000000", UINT16_MAX + 1 },
120 {"0b1111111111111111111111111111111", INT32_MAX },
121 {"0b10000000000000000000000000000000", INT32_MAX + 1U },
122 {"0b11111111111111111111111111111111", UINT32_MAX },
123 {"0b100000000000000000000000000000000", UINT32_MAX + 1ULL },
124 {"0b111111111111111111111111111111111111111111111111111111111111111",
125 INT64_MAX },
126 {"0b1000000000000000000000000000000000000000000000000000000000000000",
127 INT64_MAX + 1ULL},
128 {"0b1111111111111111111111111111111111111111111111111111111111111111",
129 UINT64_MAX },
130 /* binary (with leading zeroes) */
131 {"0b01111111", INT8_MAX },
132 {"0b0000000100000000", UINT8_MAX + 1 },
133 {"0b0111111111111111", INT16_MAX },
134 {"0b00000000000000010000000000000000", UINT16_MAX + 1 },
135 {"0b01111111111111111111111111111111", INT32_MAX },
136 {"0b0000000000000000000000000000000100000000000000000000000000000000",
137 UINT32_MAX + 1ULL },
138 {"0b0111111111111111111111111111111111111111111111111111111111111111",
139 INT64_MAX },
140 /* octal */
141 {"00", 0 },
142 {"0177", INT8_MAX },
143 {"0200", INT8_MAX + 1 },
144 {"0377", UINT8_MAX },
145 {"0400", UINT8_MAX + 1 },
146 {"077777", INT16_MAX },
147 {"0100000", INT16_MAX + 1 },
148 {"0177777", UINT16_MAX },
149 {"0200000", UINT16_MAX + 1 },
150 {"017777777777", INT32_MAX },
151 {"020000000000", INT32_MAX + 1U },
152 {"037777777777", UINT32_MAX },
153 {"040000000000", UINT32_MAX + 1ULL },
154 {"0777777777777777777777", INT64_MAX },
155 {"01000000000000000000000", INT64_MAX + 1ULL},
156 {"01777777777777777777777", UINT64_MAX },
157 /* check all numbers */
158 {"012345670", 012345670 },
159 {"076543210", 076543210 },
160 };
161
162 const struct num_signed_str num_valid_negative_strs[] = {
163 /* deciman negative */
164 {"-128", INT8_MIN },
165 {"-129", INT8_MIN - 1 },
166 {"-32768", INT16_MIN },
167 {"-32769", INT16_MIN - 1 },
168 {"-2147483648", INT32_MIN },
169 {"-2147483649", INT32_MIN - 1LL },
170 {"-9223372036854775808", INT64_MIN },
171 };
172
173 const struct num_unsigned_str num_garbage_positive_strs[] = {
174 /* valid strings with garbage on the end, should still be valid */
175 /* decimal */
176 {"9223372036854775807\0garbage", INT64_MAX },
177 {"9223372036854775807\tgarbage", INT64_MAX },
178 {"9223372036854775807\rgarbage", INT64_MAX },
179 {"9223372036854775807\ngarbage", INT64_MAX },
180 {"9223372036854775807#garbage", INT64_MAX },
181 {"9223372036854775807 garbage", INT64_MAX },
182 /* hex */
183 {"0x7FFFFFFFFFFFFFFF\0garbage", INT64_MAX },
184 {"0x7FFFFFFFFFFFFFFF\tgarbage", INT64_MAX },
185 {"0x7FFFFFFFFFFFFFFF\rgarbage", INT64_MAX },
186 {"0x7FFFFFFFFFFFFFFF\ngarbage", INT64_MAX },
187 {"0x7FFFFFFFFFFFFFFF#garbage", INT64_MAX },
188 {"0x7FFFFFFFFFFFFFFF garbage", INT64_MAX },
189 /* binary */
190 {"0b1111111111111111111111111111111\0garbage", INT32_MAX },
191 {"0b1111111111111111111111111111111\rgarbage", INT32_MAX },
192 {"0b1111111111111111111111111111111\tgarbage", INT32_MAX },
193 {"0b1111111111111111111111111111111\ngarbage", INT32_MAX },
194 {"0b1111111111111111111111111111111#garbage", INT32_MAX },
195 {"0b1111111111111111111111111111111 garbage", INT32_MAX },
196 /* octal */
197 {"01777777777777777777777\0garbage", UINT64_MAX },
198 {"01777777777777777777777\rgarbage", UINT64_MAX },
199 {"01777777777777777777777\tgarbage", UINT64_MAX },
200 {"01777777777777777777777\ngarbage", UINT64_MAX },
201 {"01777777777777777777777#garbage", UINT64_MAX },
202 {"01777777777777777777777 garbage", UINT64_MAX },
203 };
204
205 const struct num_signed_str num_garbage_negative_strs[] = {
206 /* valid strings with garbage on the end, should still be valid */
207 {"-9223372036854775808\0garbage", INT64_MIN },
208 {"-9223372036854775808\rgarbage", INT64_MIN },
209 {"-9223372036854775808\tgarbage", INT64_MIN },
210 {"-9223372036854775808\ngarbage", INT64_MIN },
211 {"-9223372036854775808#garbage", INT64_MIN },
212 {"-9223372036854775808 garbage", INT64_MIN },
213 };
214
215 const char * num_invalid_strs[] = {
216 "18446744073709551616", /* out of range unsigned */
217 "-9223372036854775809", /* out of range negative signed */
218 "0x10000000000000000", /* out of range hex */
219 /* out of range binary */
220 "0b10000000000000000000000000000000000000000000000000000000000000000",
221 "020000000000000000000000", /* out of range octal */
222 /* wrong chars */
223 "0123456239",
224 "0x1234580AGE",
225 "0b0111010101g001",
226 "0b01110101017001",
227 /* false negative numbers */
228 "-12345F623",
229 "-0x1234580A",
230 "-0b0111010101",
231 /* too long (128+ chars) */
232 "0b1111000011110000111100001111000011110000111100001111000011110000"
233 "1111000011110000111100001111000011110000111100001111000011110000",
234 "1E3",
235 "0A",
236 "-B",
237 "+4",
238 "1.23G",
239 "",
240 " ",
241 "#",
242 "\r",
243 "\t",
244 "\n",
245 "\0",
246 };
247
248 #define NUM_POSITIVE_STRS_SIZE \
249 (sizeof(num_valid_positive_strs) / sizeof(num_valid_positive_strs[0]))
250 #define NUM_NEGATIVE_STRS_SIZE \
251 (sizeof(num_valid_negative_strs) / sizeof(num_valid_negative_strs[0]))
252 #define NUM_POSITIVE_GARBAGE_STRS_SIZE \
253 (sizeof(num_garbage_positive_strs) / sizeof(num_garbage_positive_strs[0]))
254 #define NUM_NEGATIVE_GARBAGE_STRS_SIZE \
255 (sizeof(num_garbage_negative_strs) / sizeof(num_garbage_negative_strs[0]))
256 #define NUM_INVALID_STRS_SIZE \
257 (sizeof(num_invalid_strs) / sizeof(num_invalid_strs[0]))
258
259
260
261 static int
262 can_parse_unsigned(uint64_t expected_result, enum cmdline_numtype type)
263 {
264 switch (type) {
265 case UINT8:
266 if (expected_result > UINT8_MAX)
267 return 0;
268 break;
269 case UINT16:
270 if (expected_result > UINT16_MAX)
271 return 0;
272 break;
273 case UINT32:
274 if (expected_result > UINT32_MAX)
275 return 0;
276 break;
277 case INT8:
278 if (expected_result > INT8_MAX)
279 return 0;
280 break;
281 case INT16:
282 if (expected_result > INT16_MAX)
283 return 0;
284 break;
285 case INT32:
286 if (expected_result > INT32_MAX)
287 return 0;
288 break;
289 case INT64:
290 if (expected_result > INT64_MAX)
291 return 0;
292 break;
293 default:
294 return 1;
295 }
296 return 1;
297 }
298
299 static int
300 can_parse_signed(int64_t expected_result, enum cmdline_numtype type)
301 {
302 switch (type) {
303 case UINT8:
304 if (expected_result > UINT8_MAX || expected_result < 0)
305 return 0;
306 break;
307 case UINT16:
308 if (expected_result > UINT16_MAX || expected_result < 0)
309 return 0;
310 break;
311 case UINT32:
312 if (expected_result > UINT32_MAX || expected_result < 0)
313 return 0;
314 break;
315 case UINT64:
316 if (expected_result < 0)
317 return 0;
318 break;
319 case INT8:
320 if (expected_result > INT8_MAX || expected_result < INT8_MIN)
321 return 0;
322 break;
323 case INT16:
324 if (expected_result > INT16_MAX || expected_result < INT16_MIN)
325 return 0;
326 break;
327 case INT32:
328 if (expected_result > INT32_MAX || expected_result < INT32_MIN)
329 return 0;
330 break;
331 default:
332 return 1;
333 }
334 return 1;
335 }
336
337 /* test invalid parameters */
338 int
339 test_parse_num_invalid_param(void)
340 {
341 char buf[CMDLINE_TEST_BUFSIZE];
342 uint32_t result;
343 cmdline_parse_token_num_t token;
344 int ret = 0;
345
346 /* set up a token */
347 token.num_data.type = UINT32;
348
349 /* copy string to buffer */
350 snprintf(buf, sizeof(buf), "%s",
351 num_valid_positive_strs[0].str);
352
353 /* try all null */
354 ret = cmdline_parse_num(NULL, NULL, NULL, 0);
355 if (ret != -1) {
356 printf("Error: parser accepted null parameters!\n");
357 return -1;
358 }
359
360 /* try null token */
361 ret = cmdline_parse_num(NULL, buf, (void*)&result, sizeof(result));
362 if (ret != -1) {
363 printf("Error: parser accepted null token!\n");
364 return -1;
365 }
366
367 /* try null buf */
368 ret = cmdline_parse_num((cmdline_parse_token_hdr_t*)&token, NULL,
369 (void*)&result, sizeof(result));
370 if (ret != -1) {
371 printf("Error: parser accepted null string!\n");
372 return -1;
373 }
374
375 /* try null result */
376 ret = cmdline_parse_num((cmdline_parse_token_hdr_t*)&token, buf,
377 NULL, 0);
378 if (ret == -1) {
379 printf("Error: parser rejected null result!\n");
380 return -1;
381 }
382
383 /* test help function */
384 memset(&buf, 0, sizeof(buf));
385
386 /* try all null */
387 ret = cmdline_get_help_num(NULL, NULL, 0);
388 if (ret != -1) {
389 printf("Error: help function accepted null parameters!\n");
390 return -1;
391 }
392
393 /* try null token */
394 ret = cmdline_get_help_num(NULL, buf, sizeof(buf));
395 if (ret != -1) {
396 printf("Error: help function accepted null token!\n");
397 return -1;
398 }
399
400 /* coverage! */
401 ret = cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token, buf, sizeof(buf));
402 if (ret < 0) {
403 printf("Error: help function failed with valid parameters!\n");
404 return -1;
405 }
406
407 return 0;
408 }
409 /* test valid parameters but invalid data */
410 int
411 test_parse_num_invalid_data(void)
412 {
413 enum cmdline_numtype type;
414 int ret = 0;
415 unsigned i;
416 char buf[CMDLINE_TEST_BUFSIZE];
417 uint64_t result; /* pick largest buffer */
418 cmdline_parse_token_num_t token;
419
420 /* cycle through all possible parsed types */
421 for (type = UINT8; type <= INT64; type++) {
422 token.num_data.type = type;
423
424 /* test full strings */
425 for (i = 0; i < NUM_INVALID_STRS_SIZE; i++) {
426
427 memset(&result, 0, sizeof(uint64_t));
428 memset(&buf, 0, sizeof(buf));
429
430 ret = cmdline_parse_num((cmdline_parse_token_hdr_t*)&token,
431 num_invalid_strs[i], (void*)&result, sizeof(result));
432 if (ret != -1) {
433 /* get some info about what we are trying to parse */
434 cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token,
435 buf, sizeof(buf));
436
437 printf("Error: parsing %s as %s succeeded!\n",
438 num_invalid_strs[i], buf);
439 return -1;
440 }
441 }
442 }
443 return 0;
444 }
445
446 /* test valid parameters and data */
447 int
448 test_parse_num_valid(void)
449 {
450 int ret = 0;
451 enum cmdline_numtype type;
452 unsigned i;
453 char buf[CMDLINE_TEST_BUFSIZE];
454 uint64_t result;
455 cmdline_parse_token_num_t token;
456
457 /** valid strings **/
458
459 /* cycle through all possible parsed types */
460 for (type = UINT8; type <= INT64; type++) {
461 token.num_data.type = type;
462
463 /* test positive strings */
464 for (i = 0; i < NUM_POSITIVE_STRS_SIZE; i++) {
465 result = 0;
466 memset(&buf, 0, sizeof(buf));
467
468 cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token,
469 buf, sizeof(buf));
470
471 ret = cmdline_parse_num((cmdline_parse_token_hdr_t*) &token,
472 num_valid_positive_strs[i].str,
473 (void*)&result, sizeof(result));
474
475 /* if it should have passed but didn't, or if it should have failed but didn't */
476 if ((ret < 0) == (can_parse_unsigned(num_valid_positive_strs[i].result, type) > 0)) {
477 printf("Error: parser behaves unexpectedly when parsing %s as %s!\n",
478 num_valid_positive_strs[i].str, buf);
479 return -1;
480 }
481 /* check if result matches what it should have matched
482 * since unsigned numbers don't care about number of bits, we can just convert
483 * everything to uint64_t without any worries. */
484 if (ret > 0 && num_valid_positive_strs[i].result != result) {
485 printf("Error: parsing %s as %s failed: result mismatch!\n",
486 num_valid_positive_strs[i].str, buf);
487 return -1;
488 }
489 }
490
491 /* test negative strings */
492 for (i = 0; i < NUM_NEGATIVE_STRS_SIZE; i++) {
493 result = 0;
494 memset(&buf, 0, sizeof(buf));
495
496 cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token,
497 buf, sizeof(buf));
498
499 ret = cmdline_parse_num((cmdline_parse_token_hdr_t*) &token,
500 num_valid_negative_strs[i].str,
501 (void*)&result, sizeof(result));
502
503 /* if it should have passed but didn't, or if it should have failed but didn't */
504 if ((ret < 0) == (can_parse_signed(num_valid_negative_strs[i].result, type) > 0)) {
505 printf("Error: parser behaves unexpectedly when parsing %s as %s!\n",
506 num_valid_negative_strs[i].str, buf);
507 return -1;
508 }
509 /* check if result matches what it should have matched
510 * the result is signed in this case, so we have to account for that */
511 if (ret > 0) {
512 /* detect negative */
513 switch (type) {
514 case INT8:
515 result = (int8_t) result;
516 break;
517 case INT16:
518 result = (int16_t) result;
519 break;
520 case INT32:
521 result = (int32_t) result;
522 break;
523 default:
524 break;
525 }
526 if (num_valid_negative_strs[i].result == (int64_t) result)
527 continue;
528 printf("Error: parsing %s as %s failed: result mismatch!\n",
529 num_valid_negative_strs[i].str, buf);
530 return -1;
531 }
532 }
533 }
534
535 /** garbage strings **/
536
537 /* cycle through all possible parsed types */
538 for (type = UINT8; type <= INT64; type++) {
539 token.num_data.type = type;
540
541 /* test positive garbage strings */
542 for (i = 0; i < NUM_POSITIVE_GARBAGE_STRS_SIZE; i++) {
543 result = 0;
544 memset(&buf, 0, sizeof(buf));
545
546 cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token,
547 buf, sizeof(buf));
548
549 ret = cmdline_parse_num((cmdline_parse_token_hdr_t*) &token,
550 num_garbage_positive_strs[i].str,
551 (void*)&result, sizeof(result));
552
553 /* if it should have passed but didn't, or if it should have failed but didn't */
554 if ((ret < 0) == (can_parse_unsigned(num_garbage_positive_strs[i].result, type) > 0)) {
555 printf("Error: parser behaves unexpectedly when parsing %s as %s!\n",
556 num_garbage_positive_strs[i].str, buf);
557 return -1;
558 }
559 /* check if result matches what it should have matched
560 * since unsigned numbers don't care about number of bits, we can just convert
561 * everything to uint64_t without any worries. */
562 if (ret > 0 && num_garbage_positive_strs[i].result != result) {
563 printf("Error: parsing %s as %s failed: result mismatch!\n",
564 num_garbage_positive_strs[i].str, buf);
565 return -1;
566 }
567 }
568
569 /* test negative strings */
570 for (i = 0; i < NUM_NEGATIVE_GARBAGE_STRS_SIZE; i++) {
571 result = 0;
572 memset(&buf, 0, sizeof(buf));
573
574 cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token,
575 buf, sizeof(buf));
576
577 ret = cmdline_parse_num((cmdline_parse_token_hdr_t*) &token,
578 num_garbage_negative_strs[i].str,
579 (void*)&result, sizeof(result));
580
581 /* if it should have passed but didn't, or if it should have failed but didn't */
582 if ((ret < 0) == (can_parse_signed(num_garbage_negative_strs[i].result, type) > 0)) {
583 printf("Error: parser behaves unexpectedly when parsing %s as %s!\n",
584 num_garbage_negative_strs[i].str, buf);
585 return -1;
586 }
587 /* check if result matches what it should have matched
588 * the result is signed in this case, so we have to account for that */
589 if (ret > 0) {
590 /* detect negative */
591 switch (type) {
592 case INT8:
593 if (result & (INT8_MAX + 1))
594 result |= 0xFFFFFFFFFFFFFF00ULL;
595 break;
596 case INT16:
597 if (result & (INT16_MAX + 1))
598 result |= 0xFFFFFFFFFFFF0000ULL;
599 break;
600 case INT32:
601 if (result & (INT32_MAX + 1ULL))
602 result |= 0xFFFFFFFF00000000ULL;
603 break;
604 default:
605 break;
606 }
607 if (num_garbage_negative_strs[i].result == (int64_t) result)
608 continue;
609 printf("Error: parsing %s as %s failed: result mismatch!\n",
610 num_garbage_negative_strs[i].str, buf);
611 return -1;
612 }
613 }
614 }
615
616 memset(&buf, 0, sizeof(buf));
617
618 /* coverage! */
619 cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token,
620 buf, sizeof(buf));
621
622 return 0;
623 }