get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/17029/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 17029,
    "url": "https://patches.dpdk.org/api/patches/17029/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/51cc142908d82d3f5fd8faddeee55759c7282a17.1479309720.git.adrien.mazarguil@6wind.com/",
    "project": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<51cc142908d82d3f5fd8faddeee55759c7282a17.1479309720.git.adrien.mazarguil@6wind.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/51cc142908d82d3f5fd8faddeee55759c7282a17.1479309720.git.adrien.mazarguil@6wind.com",
    "date": "2016-11-16T16:23:31",
    "name": "[dpdk-dev,05/22] app/testpmd: add flow command",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "b53f962c4c6afbdb0201940b72afc51cbfe26540",
    "submitter": {
        "id": 165,
        "url": "https://patches.dpdk.org/api/people/165/?format=api",
        "name": "Adrien Mazarguil",
        "email": "adrien.mazarguil@6wind.com"
    },
    "delegate": null,
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/51cc142908d82d3f5fd8faddeee55759c7282a17.1479309720.git.adrien.mazarguil@6wind.com/mbox/",
    "series": [],
    "comments": "https://patches.dpdk.org/api/patches/17029/comments/",
    "check": "warning",
    "checks": "https://patches.dpdk.org/api/patches/17029/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [IPv6:::1])\n\tby dpdk.org (Postfix) with ESMTP id 115BE590E;\n\tWed, 16 Nov 2016 17:25:07 +0100 (CET)",
            "from mail-wm0-f41.google.com (mail-wm0-f41.google.com\n\t[74.125.82.41]) by dpdk.org (Postfix) with ESMTP id 5D9E9559A\n\tfor <dev@dpdk.org>; Wed, 16 Nov 2016 17:24:16 +0100 (CET)",
            "by mail-wm0-f41.google.com with SMTP id u144so33856125wmu.1\n\tfor <dev@dpdk.org>; Wed, 16 Nov 2016 08:24:16 -0800 (PST)",
            "from 6wind.com (guy78-3-82-239-227-177.fbx.proxad.net.\n\t[82.239.227.177]) by smtp.gmail.com with ESMTPSA id\n\tdi9sm41311992wjc.37.2016.11.16.08.24.11\n\t(version=TLS1_2 cipher=AES128-SHA bits=128/128);\n\tWed, 16 Nov 2016 08:24:14 -0800 (PST)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=6wind-com.20150623.gappssmtp.com; s=20150623;\n\th=from:to:cc:subject:date:message-id:in-reply-to:references;\n\tbh=5y1AdcFfZhCnEnEf8n5Yp722FBB2BCbKBbtI/UenOHA=;\n\tb=e2uiabpr3nI3HOJhI0eP21lfsoJ+7Ohma5iC4u+MIwg9ioL7mVBwKX6+PmQYvZDpNb\n\t7SYSI6JMsnOq5l6xwR1+IFmr7YA5LwFtV5nXswNUSH7Y/wGGa6NvuYmlVS/I9Q/jSr97\n\t7/CbD9Sac5eGbKUWc6x4dKRfL3Lo2Fu6Mb3MCJj/vsXaMWhO4e4c7gDpyws2UjtqObTe\n\tvt196T0VpS1QyNPRdQecG1ipX+wwmv87ysQ1WKBOeKKmj9W6m5vJ+YJr8btvUURGeHPX\n\t03NIf/2hFH+XwLXad7lWtgwWQcH7aJu/4HtWMjJ4Jb1lmjAW9zlhvd3iIwtDMTUqcgFS\n\tMI1A==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20130820;\n\th=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\n\t:references;\n\tbh=5y1AdcFfZhCnEnEf8n5Yp722FBB2BCbKBbtI/UenOHA=;\n\tb=FBobT86sjLhtaaqS62XounXdSF2zr+ErtsesNXOcigzAamS3yqQyS2xHMZ/yo+xFcm\n\tlO+yH4rMHFeeJdUOuiqRdHZKVZ9uzrth0lGGNYwOVZWqeCp2Uky/ErXKHbF6hVuxw5J7\n\tzMXmrEpBi3O1AkKHgu8Fwdg6nDuSMsbW5MhJgFZjkbOIkrYTHK15O5ottFJbCWQ1sisO\n\tQQ8mrqNdYULOQyez9MEQBD2vVpoVObYJks75DeAXX8jQQGuM+Zj2coyZKR75NcKNEJSr\n\tk9fqHvEqAJtVwZVOeKtC+13JyNsME49VLc/fd5E6pDFImPxA6eiZjcBJw//O7blbivzq\n\tGUBQ==",
        "X-Gm-Message-State": "ABUngvePLwKh5UsRZ/3QhXEOlnsef3C9mUJyKs3rdYlqTue4D+ft+M0QvAKRSlJxxFOpzSGr",
        "X-Received": "by 10.194.191.161 with SMTP id gz1mr2529737wjc.22.1479313455546; \n\tWed, 16 Nov 2016 08:24:15 -0800 (PST)",
        "From": "Adrien Mazarguil <adrien.mazarguil@6wind.com>",
        "To": "dev@dpdk.org",
        "Cc": "Thomas Monjalon <thomas.monjalon@6wind.com>,\n\tPablo de Lara <pablo.de.lara.guarch@intel.com>,\n\tOlivier Matz <olivier.matz@6wind.com>",
        "Date": "Wed, 16 Nov 2016 17:23:31 +0100",
        "Message-Id": "<51cc142908d82d3f5fd8faddeee55759c7282a17.1479309720.git.adrien.mazarguil@6wind.com>",
        "X-Mailer": "git-send-email 2.1.4",
        "In-Reply-To": "<cover.1479309719.git.adrien.mazarguil@6wind.com>",
        "References": "<cover.1471632644.git.adrien.mazarguil@6wind.com>\n\t<cover.1479309719.git.adrien.mazarguil@6wind.com>",
        "Subject": "[dpdk-dev] [PATCH 05/22] app/testpmd: add flow command",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "patches and discussions about DPDK <dev.dpdk.org>",
        "List-Unsubscribe": "<http://dpdk.org/ml/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://dpdk.org/ml/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<http://dpdk.org/ml/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "Managing generic flow API functions from command line requires the use of\ndynamic tokens for convenience as flow rules are not fixed and cannot be\ndefined statically.\n\nThis commit adds specific flexible parser code and object for a new \"flow\"\ncommand in separate file.\n\nSigned-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>\n---\n app/test-pmd/Makefile       |   1 +\n app/test-pmd/cmdline.c      |   4 +\n app/test-pmd/cmdline_flow.c | 439 +++++++++++++++++++++++++++++++++++++++\n 3 files changed, 444 insertions(+)",
    "diff": "diff --git a/app/test-pmd/Makefile b/app/test-pmd/Makefile\nindex 891b85a..5988c3e 100644\n--- a/app/test-pmd/Makefile\n+++ b/app/test-pmd/Makefile\n@@ -47,6 +47,7 @@ CFLAGS += $(WERROR_FLAGS)\n SRCS-y := testpmd.c\n SRCS-y += parameters.c\n SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline.c\n+SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline_flow.c\n SRCS-y += config.c\n SRCS-y += iofwd.c\n SRCS-y += macfwd.c\ndiff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c\nindex c5b015c..b7d10b3 100644\n--- a/app/test-pmd/cmdline.c\n+++ b/app/test-pmd/cmdline.c\n@@ -9520,6 +9520,9 @@ cmdline_parse_inst_t cmd_set_flow_director_flex_payload = {\n \t},\n };\n \n+/* Generic flow interface command. */\n+extern cmdline_parse_inst_t cmd_flow;\n+\n /* *** Classification Filters Control *** */\n /* *** Get symmetric hash enable per port *** */\n struct cmd_get_sym_hash_ena_per_port_result {\n@@ -11557,6 +11560,7 @@ cmdline_parse_ctx_t main_ctx[] = {\n \t(cmdline_parse_inst_t *)&cmd_set_hash_global_config,\n \t(cmdline_parse_inst_t *)&cmd_set_hash_input_set,\n \t(cmdline_parse_inst_t *)&cmd_set_fdir_input_set,\n+\t(cmdline_parse_inst_t *)&cmd_flow,\n \t(cmdline_parse_inst_t *)&cmd_mcast_addr,\n \t(cmdline_parse_inst_t *)&cmd_config_l2_tunnel_eth_type_all,\n \t(cmdline_parse_inst_t *)&cmd_config_l2_tunnel_eth_type_specific,\ndiff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c\nnew file mode 100644\nindex 0000000..7dbda84\n--- /dev/null\n+++ b/app/test-pmd/cmdline_flow.c\n@@ -0,0 +1,439 @@\n+/*-\n+ *   BSD LICENSE\n+ *\n+ *   Copyright 2016 6WIND S.A.\n+ *   Copyright 2016 Mellanox.\n+ *\n+ *   Redistribution and use in source and binary forms, with or without\n+ *   modification, are permitted provided that the following conditions\n+ *   are met:\n+ *\n+ *     * Redistributions of source code must retain the above copyright\n+ *       notice, this list of conditions and the following disclaimer.\n+ *     * Redistributions in binary form must reproduce the above copyright\n+ *       notice, this list of conditions and the following disclaimer in\n+ *       the documentation and/or other materials provided with the\n+ *       distribution.\n+ *     * Neither the name of 6WIND S.A. nor the names of its\n+ *       contributors may be used to endorse or promote products derived\n+ *       from this software without specific prior written permission.\n+ *\n+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+ *   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+#include <stddef.h>\n+#include <stdint.h>\n+#include <stdio.h>\n+#include <ctype.h>\n+#include <string.h>\n+\n+#include <rte_common.h>\n+#include <rte_ethdev.h>\n+#include <cmdline_parse.h>\n+#include <rte_flow.h>\n+\n+#include \"testpmd.h\"\n+\n+/** Parser token indices. */\n+enum index {\n+\t/* Special tokens. */\n+\tZERO = 0,\n+\tEND,\n+\n+\t/* Top-level command. */\n+\tFLOW,\n+};\n+\n+/** Maximum number of subsequent tokens and arguments on the stack. */\n+#define CTX_STACK_SIZE 16\n+\n+/** Parser context. */\n+struct context {\n+\t/** Stack of subsequent token lists to process. */\n+\tconst enum index *next[CTX_STACK_SIZE];\n+\tenum index curr; /**< Current token index. */\n+\tenum index prev; /**< Index of the last token seen. */\n+\tint next_num; /**< Number of entries in next[]. */\n+\tuint32_t reparse:1; /**< Start over from the beginning. */\n+\tuint32_t eol:1; /**< EOL has been detected. */\n+\tuint32_t last:1; /**< No more arguments. */\n+};\n+\n+/** Parser token definition. */\n+struct token {\n+\t/** Type displayed during completion (defaults to \"TOKEN\"). */\n+\tconst char *type;\n+\t/** Help displayed during completion (defaults to token name). */\n+\tconst char *help;\n+\t/**\n+\t * Lists of subsequent tokens to push on the stack. Each call to the\n+\t * parser consumes the last entry of that stack.\n+\t */\n+\tconst enum index *const *next;\n+\t/**\n+\t * Token-processing callback, returns -1 in case of error, the\n+\t * length of the matched string otherwise. If NULL, attempts to\n+\t * match the token name.\n+\t *\n+\t * If buf is not NULL, the result should be stored in it according\n+\t * to context. An error is returned if not large enough.\n+\t */\n+\tint (*call)(struct context *ctx, const struct token *token,\n+\t\t    const char *str, unsigned int len,\n+\t\t    void *buf, unsigned int size);\n+\t/**\n+\t * Callback that provides possible values for this token, used for\n+\t * completion. Returns -1 in case of error, the number of possible\n+\t * values otherwise. If NULL, the token name is used.\n+\t *\n+\t * If buf is not NULL, entry index ent is written to buf and the\n+\t * full length of the entry is returned (same behavior as\n+\t * snprintf()).\n+\t */\n+\tint (*comp)(struct context *ctx, const struct token *token,\n+\t\t    unsigned int ent, char *buf, unsigned int size);\n+\t/** Mandatory token name, no default value. */\n+\tconst char *name;\n+};\n+\n+/** Static initializer for the next field. */\n+#define NEXT(...) (const enum index *const []){ __VA_ARGS__, NULL, }\n+\n+/** Static initializer for a NEXT() entry. */\n+#define NEXT_ENTRY(...) (const enum index []){ __VA_ARGS__, 0, }\n+\n+/** Parser output buffer layout expected by cmd_flow_parsed(). */\n+struct buffer {\n+\tenum index command; /**< Flow command. */\n+\tuint16_t port; /**< Affected port ID. */\n+};\n+\n+static int parse_init(struct context *, const struct token *,\n+\t\t      const char *, unsigned int,\n+\t\t      void *, unsigned int);\n+\n+/** Token definitions. */\n+static const struct token token_list[] = {\n+\t/* Special tokens. */\n+\t[ZERO] = {\n+\t\t.name = \"ZERO\",\n+\t\t.help = \"null entry, abused as the entry point\",\n+\t\t.next = NEXT(NEXT_ENTRY(FLOW)),\n+\t},\n+\t[END] = {\n+\t\t.name = \"\",\n+\t\t.type = \"RETURN\",\n+\t\t.help = \"command may end here\",\n+\t},\n+\t/* Top-level command. */\n+\t[FLOW] = {\n+\t\t.name = \"flow\",\n+\t\t.type = \"{command} {port_id} [{arg} [...]]\",\n+\t\t.help = \"manage ingress/egress flow rules\",\n+\t\t.call = parse_init,\n+\t},\n+};\n+\n+/** Default parsing function for token name matching. */\n+static int\n+parse_default(struct context *ctx, const struct token *token,\n+\t      const char *str, unsigned int len,\n+\t      void *buf, unsigned int size)\n+{\n+\t(void)ctx;\n+\t(void)buf;\n+\t(void)size;\n+\tif (strncmp(str, token->name, len))\n+\t\treturn -1;\n+\treturn len;\n+}\n+\n+/** Parse flow command, initialize output buffer for subsequent tokens. */\n+static int\n+parse_init(struct context *ctx, const struct token *token,\n+\t   const char *str, unsigned int len,\n+\t   void *buf, unsigned int size)\n+{\n+\tstruct buffer *out = buf;\n+\n+\t/* Token name must match. */\n+\tif (parse_default(ctx, token, str, len, NULL, 0) < 0)\n+\t\treturn -1;\n+\t/* Nothing else to do if there is no buffer. */\n+\tif (!out)\n+\t\treturn len;\n+\t/* Make sure buffer is large enough. */\n+\tif (size < sizeof(*out))\n+\t\treturn -1;\n+\t/* Initialize buffer. */\n+\tmemset(out, 0x00, sizeof(*out));\n+\tmemset((uint8_t *)out + sizeof(*out), 0x22, size - sizeof(*out));\n+\treturn len;\n+}\n+\n+/** Internal context. */\n+static struct context cmd_flow_context;\n+\n+/** Global parser instance (cmdline API). */\n+cmdline_parse_inst_t cmd_flow;\n+\n+/** Initialize context. */\n+static void\n+cmd_flow_context_init(struct context *ctx)\n+{\n+\t/* A full memset() is not necessary. */\n+\tctx->curr = 0;\n+\tctx->prev = 0;\n+\tctx->next_num = 0;\n+\tctx->reparse = 0;\n+\tctx->eol = 0;\n+\tctx->last = 0;\n+}\n+\n+/** Parse a token (cmdline API). */\n+static int\n+cmd_flow_parse(cmdline_parse_token_hdr_t *hdr, const char *src, void *result,\n+\t       unsigned int size)\n+{\n+\tstruct context *ctx = &cmd_flow_context;\n+\tconst struct token *token;\n+\tconst enum index *list;\n+\tint len;\n+\tint i;\n+\n+\t(void)hdr;\n+\t/* Restart as requested. */\n+\tif (ctx->reparse)\n+\t\tcmd_flow_context_init(ctx);\n+\ttoken = &token_list[ctx->curr];\n+\t/* Check argument length. */\n+\tctx->eol = 0;\n+\tctx->last = 1;\n+\tfor (len = 0; src[len]; ++len)\n+\t\tif (src[len] == '#' || isspace(src[len]))\n+\t\t\tbreak;\n+\tif (!len)\n+\t\treturn -1;\n+\t/* Last argument and EOL detection. */\n+\tfor (i = len; src[i]; ++i)\n+\t\tif (src[i] == '#' || src[i] == '\\r' || src[i] == '\\n')\n+\t\t\tbreak;\n+\t\telse if (!isspace(src[i])) {\n+\t\t\tctx->last = 0;\n+\t\t\tbreak;\n+\t\t}\n+\tfor (; src[i]; ++i)\n+\t\tif (src[i] == '\\r' || src[i] == '\\n') {\n+\t\t\tctx->eol = 1;\n+\t\t\tbreak;\n+\t\t}\n+\t/* Initialize context if necessary. */\n+\tif (!ctx->next_num) {\n+\t\tif (!token->next)\n+\t\t\treturn 0;\n+\t\tctx->next[ctx->next_num++] = token->next[0];\n+\t}\n+\t/* Process argument through candidates. */\n+\tctx->prev = ctx->curr;\n+\tlist = ctx->next[ctx->next_num - 1];\n+\tfor (i = 0; list[i]; ++i) {\n+\t\tconst struct token *next = &token_list[list[i]];\n+\t\tint tmp;\n+\n+\t\tctx->curr = list[i];\n+\t\tif (next->call)\n+\t\t\ttmp = next->call(ctx, next, src, len, result, size);\n+\t\telse\n+\t\t\ttmp = parse_default(ctx, next, src, len, result, size);\n+\t\tif (tmp == -1 || tmp != len)\n+\t\t\tcontinue;\n+\t\ttoken = next;\n+\t\tbreak;\n+\t}\n+\tif (!list[i])\n+\t\treturn -1;\n+\t--ctx->next_num;\n+\t/* Push subsequent tokens if any. */\n+\tif (token->next)\n+\t\tfor (i = 0; token->next[i]; ++i) {\n+\t\t\tif (ctx->next_num == RTE_DIM(ctx->next))\n+\t\t\t\treturn -1;\n+\t\t\tctx->next[ctx->next_num++] = token->next[i];\n+\t\t}\n+\treturn len;\n+}\n+\n+/** Return number of completion entries (cmdline API). */\n+static int\n+cmd_flow_complete_get_nb(cmdline_parse_token_hdr_t *hdr)\n+{\n+\tstruct context *ctx = &cmd_flow_context;\n+\tconst struct token *token = &token_list[ctx->curr];\n+\tconst enum index *list;\n+\tint i;\n+\n+\t(void)hdr;\n+\t/* Tell cmd_flow_parse() that context must be reinitialized. */\n+\tctx->reparse = 1;\n+\t/* Count number of tokens in current list. */\n+\tif (ctx->next_num)\n+\t\tlist = ctx->next[ctx->next_num - 1];\n+\telse\n+\t\tlist = token->next[0];\n+\tfor (i = 0; list[i]; ++i)\n+\t\t;\n+\tif (!i)\n+\t\treturn 0;\n+\t/*\n+\t * If there is a single token, use its completion callback, otherwise\n+\t * return the number of entries.\n+\t */\n+\ttoken = &token_list[list[0]];\n+\tif (i == 1 && token->comp) {\n+\t\t/* Save index for cmd_flow_get_help(). */\n+\t\tctx->prev = list[0];\n+\t\treturn token->comp(ctx, token, 0, NULL, 0);\n+\t}\n+\treturn i;\n+}\n+\n+/** Return a completion entry (cmdline API). */\n+static int\n+cmd_flow_complete_get_elt(cmdline_parse_token_hdr_t *hdr, int index,\n+\t\t\t  char *dst, unsigned int size)\n+{\n+\tstruct context *ctx = &cmd_flow_context;\n+\tconst struct token *token = &token_list[ctx->curr];\n+\tconst enum index *list;\n+\tint i;\n+\n+\t(void)hdr;\n+\t/* Tell cmd_flow_parse() that context must be reinitialized. */\n+\tctx->reparse = 1;\n+\t/* Count number of tokens in current list. */\n+\tif (ctx->next_num)\n+\t\tlist = ctx->next[ctx->next_num - 1];\n+\telse\n+\t\tlist = token->next[0];\n+\tfor (i = 0; list[i]; ++i)\n+\t\t;\n+\tif (!i)\n+\t\treturn -1;\n+\t/* If there is a single token, use its completion callback. */\n+\ttoken = &token_list[list[0]];\n+\tif (i == 1 && token->comp) {\n+\t\t/* Save index for cmd_flow_get_help(). */\n+\t\tctx->prev = list[0];\n+\t\treturn token->comp(ctx, token, index, dst, size) < 0 ? -1 : 0;\n+\t}\n+\t/* Otherwise make sure the index is valid and use defaults. */\n+\tif (index >= i)\n+\t\treturn -1;\n+\ttoken = &token_list[list[index]];\n+\tsnprintf(dst, size, \"%s\", token->name);\n+\t/* Save index for cmd_flow_get_help(). */\n+\tctx->prev = list[index];\n+\treturn 0;\n+}\n+\n+/** Populate help strings for current token (cmdline API). */\n+static int\n+cmd_flow_get_help(cmdline_parse_token_hdr_t *hdr, char *dst, unsigned int size)\n+{\n+\tstruct context *ctx = &cmd_flow_context;\n+\tconst struct token *token = &token_list[ctx->prev];\n+\n+\t(void)hdr;\n+\t/* Tell cmd_flow_parse() that context must be reinitialized. */\n+\tctx->reparse = 1;\n+\tif (!size)\n+\t\treturn -1;\n+\t/* Set token type and update global help with details. */\n+\tsnprintf(dst, size, \"%s\", (token->type ? token->type : \"TOKEN\"));\n+\tif (token->help)\n+\t\tcmd_flow.help_str = token->help;\n+\telse\n+\t\tcmd_flow.help_str = token->name;\n+\treturn 0;\n+}\n+\n+/** Token definition template (cmdline API). */\n+static struct cmdline_token_hdr cmd_flow_token_hdr = {\n+\t.ops = &(struct cmdline_token_ops){\n+\t\t.parse = cmd_flow_parse,\n+\t\t.complete_get_nb = cmd_flow_complete_get_nb,\n+\t\t.complete_get_elt = cmd_flow_complete_get_elt,\n+\t\t.get_help = cmd_flow_get_help,\n+\t},\n+\t.offset = 0,\n+};\n+\n+/** Populate the next dynamic token. */\n+static void\n+cmd_flow_tok(cmdline_parse_token_hdr_t **hdr,\n+\t     cmdline_parse_token_hdr_t *(*hdrs)[])\n+{\n+\tstruct context *ctx = &cmd_flow_context;\n+\n+\t/* Always reinitialize context before requesting the first token. */\n+\tif (!(hdr - *hdrs))\n+\t\tcmd_flow_context_init(ctx);\n+\t/* Return NULL when no more tokens are expected. */\n+\tif (!ctx->next_num && ctx->curr) {\n+\t\t*hdr = NULL;\n+\t\treturn;\n+\t}\n+\t/* Determine if command should end here. */\n+\tif (ctx->eol && ctx->last && ctx->next_num) {\n+\t\tconst enum index *list = ctx->next[ctx->next_num - 1];\n+\t\tint i;\n+\n+\t\tfor (i = 0; list[i]; ++i) {\n+\t\t\tif (list[i] != END)\n+\t\t\t\tcontinue;\n+\t\t\t*hdr = NULL;\n+\t\t\treturn;\n+\t\t}\n+\t}\n+\t*hdr = &cmd_flow_token_hdr;\n+}\n+\n+/** Dispatch parsed buffer to function calls. */\n+static void\n+cmd_flow_parsed(const struct buffer *in)\n+{\n+\tswitch (in->command) {\n+\tdefault:\n+\t\tbreak;\n+\t}\n+}\n+\n+/** Token generator and output processing callback (cmdline API). */\n+static void\n+cmd_flow_cb(void *arg0, struct cmdline *cl, void *arg2)\n+{\n+\tif (cl == NULL)\n+\t\tcmd_flow_tok(arg0, arg2);\n+\telse\n+\t\tcmd_flow_parsed(arg0);\n+}\n+\n+/** Global parser instance (cmdline API). */\n+cmdline_parse_inst_t cmd_flow = {\n+\t.f = cmd_flow_cb,\n+\t.data = NULL, /**< Unused. */\n+\t.help_str = NULL, /**< Updated by cmd_flow_get_help(). */\n+\t.tokens = {\n+\t\tNULL,\n+\t}, /**< Tokens are returned by cmd_flow_tok(). */\n+};\n",
    "prefixes": [
        "dpdk-dev",
        "05/22"
    ]
}