From patchwork Tue May 17 13:04:08 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christophe Milard X-Patchwork-Id: 67948 Delivered-To: patch@linaro.org Received: by 10.140.92.199 with SMTP id b65csp2068169qge; Tue, 17 May 2016 06:15:13 -0700 (PDT) X-Received: by 10.140.223.10 with SMTP id t10mr1348000qhb.96.1463490913756; Tue, 17 May 2016 06:15:13 -0700 (PDT) Return-Path: Received: from lists.linaro.org (lists.linaro.org. [54.225.227.206]) by mx.google.com with ESMTP id a202si2168623qkc.132.2016.05.17.06.15.13; Tue, 17 May 2016 06:15:13 -0700 (PDT) Received-SPF: pass (google.com: domain of lng-odp-bounces@lists.linaro.org designates 54.225.227.206 as permitted sender) client-ip=54.225.227.206; Authentication-Results: mx.google.com; spf=pass (google.com: domain of lng-odp-bounces@lists.linaro.org designates 54.225.227.206 as permitted sender) smtp.mailfrom=lng-odp-bounces@lists.linaro.org; dmarc=pass (p=NONE dis=NONE) header.from=linaro.org Received: by lists.linaro.org (Postfix, from userid 109) id 6C85A61806; Tue, 17 May 2016 13:15:13 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on ip-10-142-244-252 X-Spam-Level: X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, URIBL_BLOCKED autolearn=disabled version=3.4.0 Received: from [127.0.0.1] (localhost [127.0.0.1]) by lists.linaro.org (Postfix) with ESMTP id 6D2F26177E; Tue, 17 May 2016 13:13:50 +0000 (UTC) X-Original-To: lng-odp@lists.linaro.org Delivered-To: lng-odp@lists.linaro.org Received: by lists.linaro.org (Postfix, from userid 109) id 6E697617E0; Tue, 17 May 2016 13:13:44 +0000 (UTC) Received: from mail-lf0-f54.google.com (mail-lf0-f54.google.com [209.85.215.54]) by lists.linaro.org (Postfix) with ESMTPS id 7FDAA6177C for ; Tue, 17 May 2016 13:05:11 +0000 (UTC) Received: by mail-lf0-f54.google.com with SMTP id m64so6521211lfd.1 for ; Tue, 17 May 2016 06:05:11 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=1g+8k9s8SVS9YiFchcFPMBDLGXhAfHCtfNON3H7b25w=; b=ggp8LfmRtO6uGkIbHBERtz+7L6Q7HhXo2/O1JA+s4Tyq9BDTl1xvcqiSXTFqfPIGMg 1gxvrTjQqxVIuqc9QID7VsioUKC87RCwuiTXvghEEJg/swIjPQP22m/dQAXum3zCcjQ8 o1HNzIwMe2YViaXiu6/XZAvUnEubWQMvMRIx6UFThpRRELWy1qIxPlU3uzoFuDcG3/Zv dQTvktE3pF0etOIVc7NdbIOdd5WFu6Cq2GaxggyDp/mZ4CRReyCCCjhRK4wo8nlvSTgX HhSLM2VahKsGURhQHO/kk3wuX7nGWOama+eB2ZXxAGLkJ2YXz1HIuPDA8YJJE05U4Wk8 +0DA== X-Gm-Message-State: AOPr4FW3eJbid6oe72qkIDYZ+fZFqKGC1q7+RnEfyeALZZaEU71cnIvsOqBTB+rE1LA7YWGyyJM= X-Received: by 10.25.147.82 with SMTP id v79mr443714lfd.43.1463490310388; Tue, 17 May 2016 06:05:10 -0700 (PDT) Received: from localhost.localdomain (c-83-233-90-46.cust.bredband2.com. [83.233.90.46]) by smtp.gmail.com with ESMTPSA id q1sm506536lbo.4.2016.05.17.06.05.09 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 17 May 2016 06:05:09 -0700 (PDT) From: Christophe Milard To: lng-odp@lists.linaro.org, brian.brooks@linaro.org, mike.holmes@linaro.org Date: Tue, 17 May 2016 15:04:08 +0200 Message-Id: <1463490282-23277-2-git-send-email-christophe.milard@linaro.org> X-Mailer: git-send-email 2.5.0 In-Reply-To: <1463490282-23277-1-git-send-email-christophe.milard@linaro.org> References: <1463490282-23277-1-git-send-email-christophe.milard@linaro.org> X-Topics: patch Subject: [lng-odp] [PATCHv7 01/35] helpers: adding command line argument parsing X-BeenThere: lng-odp@lists.linaro.org X-Mailman-Version: 2.1.16 Precedence: list List-Id: "The OpenDataPlane \(ODP\) List" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: lng-odp-bounces@lists.linaro.org Sender: "lng-odp" A function (odph_merge_getopt_options()) to merge command line arguments is added. This function can be called by intermediate clients (e.g c_unit_common) before calling odph_parse_options(). The new function, odph_parse_options() is also added to parse options meant for the helpers out of a the command line. This parse function picks up options altering the behaviour of the helpers out of the command line, and also checks for unknown options (i.e. options not belonging to the caller set of options or to the helpers.) No helper options are definied (yet). Signed-off-by: Christophe Milard --- helper/include/odp/helper/linux.h | 71 ++++++++++++++++++++++ helper/linux.c | 123 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 194 insertions(+) diff --git a/helper/include/odp/helper/linux.h b/helper/include/odp/helper/linux.h index e2dca35..d47abef 100644 --- a/helper/include/odp/helper/linux.h +++ b/helper/include/odp/helper/linux.h @@ -25,6 +25,7 @@ extern "C" { #include #include +#include #include /** @addtogroup odph_linux ODPH LINUX @@ -134,6 +135,76 @@ int odph_linux_process_fork_n(odph_linux_process_t *proc_tbl, int odph_linux_process_wait_n(odph_linux_process_t *proc_tbl, int num); /** + * Merge getopt options + * + * Given two sets of getopt options (each containing possibly both short + * options -a string- and long options -a option array-) this function + * return a single set (i.e. a string for short and an array for long) + * being the concatenation of the two given sets. + * Due to the fact that the size of these arrays is unknown at compilation + * time, this function actually mallocs the the resulting arrays. + * The fourth and fith parameters are actually pointers where these malloc'ed + * areas are returned. + * This means that the caller of this function has to free the two returned + * areas! + * + * @param shortopts1 first set of short options (a string) + * @param shortopts2 second set of short options (a string) + * @param longopts1 first set of long options (a getopt option array) + * @param longopts2 second set of long options (a getopt option array) + * @param shortopts a pointer where the address of the short options list + * (a string) is returned. It contains the concatenation of + * the two given short option strings. + * @param longopts a pointer where the address of the long options list + * (a getopt option array) is returned. + * It contains the concatenation of the two given long + * option arrays. + * if any of shortopts1, shortopts2, longopts1, longopts2 is NULL, the + * corresponding list as assumed to be empty. + * if any of shortopts, longopts is NULL, the corresponding malloc is not + * performed. + * + * @return On success: 0 : both shortopts and longopts are returned (assuming + * the given pointer where not null), possibly + * pointing to an empty string or an empty option array. + * On success, the caller is due to free these areas. + * On failure: -1: Nothing is malloc'ed. + */ +int odph_merge_getopt_options(const char *shortopts1, + const char *shortopts2, + const struct option *longopts1, + const struct option *longopts2, + char **shortopts, + struct option **longopts); + +/** + * Parse linux helper options + * + * Parse the command line options. Pick up options meant for the helper itself. + * If the caller is also having a set of option to parse, it should include + * their description here (shortopts desribes the short options and longopts + * describes the long options, as for getopt_long()). + * This function will issue errors on unknown arguments, so callers failing + * to pass their own command line options description here will see their + * options rejected. + * (the caller wants to set opterr to zero when parsing its own stuff + * with getopts to avoid reacting on helper's options). + * + * @param argc argument count + * @param argv argument values + * @param caller_shortopts caller's set of short options (string). or NULL. + * @param caller_longopts caller's set of long options (getopt option array). + * or NULL. + * + * @return On success: 0 + * On failure: -1 failure occurs if a value passed for a helper + * option is invalid, or on meeting unknown options. + */ +int odph_parse_options(int argc, char *argv[], + const char *caller_shortopts, + const struct option *caller_longopts); + +/** * @} */ diff --git a/helper/linux.c b/helper/linux.c index 24e243b..ef435bd 100644 --- a/helper/linux.c +++ b/helper/linux.c @@ -236,3 +236,126 @@ int odph_linux_process_wait_n(odph_linux_process_t *proc_tbl, int num) return 0; } + +/* + * return the number of elements in an array of getopt options, excluding the + * terminating {0,0,0,0} + */ +static int get_getopt_options_length(const struct option *longopts) +{ + int l = 0; + + if (!longopts) + return 0; + + while (longopts[l].name) + l++; + + return l; +} + +/* Merge getopt options */ +int odph_merge_getopt_options(const char *shortopts1, + const char *shortopts2, + const struct option *longopts1, + const struct option *longopts2, + char **shortopts, + struct option **longopts) +{ + int shortopts1_len; + int shortopts2_len; + int longopts1_len; + int longopts2_len; + int index; + int res_index = 0; + struct option termination = {0, 0, 0, 0}; + + /* merge short options: */ + if (shortopts) { + shortopts1_len = (shortopts1) ? strlen(shortopts1) : 0; + shortopts2_len = (shortopts2) ? strlen(shortopts2) : 0; + *shortopts = malloc(shortopts1_len + shortopts2_len + 1); + if (!*shortopts) + return -1; + + (*shortopts)[0] = 0; + + if (shortopts1) + strcpy((*shortopts), shortopts1); + if (shortopts2) + strcat((*shortopts), shortopts2); + } + + /* merge long options */ + if (!longopts) + return 0; + + longopts1_len = get_getopt_options_length(longopts1); + longopts2_len = get_getopt_options_length(longopts2); + *longopts = malloc(sizeof(struct option) * + (longopts1_len + longopts2_len + 1)); + if (!*longopts) { + if (shortopts) + free(*shortopts); + return -1; + } + + for (index = 0; (longopts1) && (longopts1[index].name); index++) + (*longopts)[res_index++] = longopts1[index]; + + for (index = 0; (longopts2) && (longopts2[index].name); index++) + (*longopts)[res_index++] = longopts2[index]; + + (*longopts)[res_index] = termination; + + return 0; +} + +/* + * Parse command line options to extract options affecting helpers. + */ +int odph_parse_options(int argc, char *argv[], + const char *caller_shortopts, + const struct option *caller_longopts) +{ + int c; + char *shortopts; + struct option *longopts; + int res = 0; + + static struct option helper_long_options[] = { + /* These options set a flag. */ + {0, 0, 0, 0} + }; + + static char *helper_short_options = ""; + + /* merge caller's command line options descriptions with helper's: */ + if (odph_merge_getopt_options(caller_shortopts, helper_short_options, + caller_longopts, helper_long_options, + &shortopts, &longopts) < 0) + return -1; + + while (1) { + /* getopt_long stores the option index here. */ + int option_index = 0; + + c = getopt_long (argc, argv, + shortopts, longopts, &option_index); + + /* Detect the end of the options. */ + if (c == -1) + break; + + /* check for unknown options or missing arguments */ + if (c == '?' || c == ':') + res = -1; + } + + optind = 0; /* caller expects this to be zero if it parses too*/ + + free(shortopts); + free(longopts); + + return res; +}