From patchwork Thu May 19 16:26:40 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christophe Milard X-Patchwork-Id: 68132 Delivered-To: patch@linaro.org Received: by 10.140.92.199 with SMTP id b65csp3268861qge; Thu, 19 May 2016 08:30:31 -0700 (PDT) X-Received: by 10.55.168.3 with SMTP id r3mr15284698qke.24.1463671831704; Thu, 19 May 2016 08:30:31 -0700 (PDT) Return-Path: Received: from lists.linaro.org (lists.linaro.org. [54.225.227.206]) by mx.google.com with ESMTP id 67si4828007qgf.12.2016.05.19.08.30.31; Thu, 19 May 2016 08:30:31 -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 563B46184C; Thu, 19 May 2016 15:30:31 +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 D423C617F8; Thu, 19 May 2016 15:28:38 +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 08D63617F3; Thu, 19 May 2016 15:28:36 +0000 (UTC) Received: from mail-lb0-f180.google.com (mail-lb0-f180.google.com [209.85.217.180]) by lists.linaro.org (Postfix) with ESMTPS id EC37B6158E for ; Thu, 19 May 2016 15:28:29 +0000 (UTC) Received: by mail-lb0-f180.google.com with SMTP id k7so5150852lbm.0 for ; Thu, 19 May 2016 08:28:29 -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=OWUspD2e/GwoqcYXU3Ay1D64dwhEUOD30HE4T1poT4UIfz6uI4V4L/arshWH1pHDd8 b0upxdQfZd5I3DQwHC1lLFe0dAdLCZPjteQM3qp9d79BAgOthWrS+kjnxfs+g7fW94Hm KU0cx7IT2o8cEZOBzWrgVoR9n2ih8ccZeNtMb9qaeG4glOtIlmZJMXk9SEWCpZRnp12K Llxf6vlMaTh2i1I5cPZfay5gyIAhvQ9e+YjBHV1D/J7yJb3q71g33rvzQxxXnH5RPD+w VLmSdnRytgWHVB+AQi2hmrBYq7T+K9ZRFp9vvUm+ekMCXlJAdog8d3nlZEpqG+DK5D0x m+Kw== X-Gm-Message-State: AOPr4FWQdNTK5axbEUv2b61syrLDYiFWzleudOrGaIH60/RF18zF3oW0LKt4WIKYCXuyD+0Bs1E= X-Received: by 10.112.172.105 with SMTP id bb9mr4286601lbc.129.1463671708639; Thu, 19 May 2016 08:28:28 -0700 (PDT) Received: from erachmi-ericsson.ki.sw.ericsson.se (c-83-233-90-46.cust.bredband2.com. [83.233.90.46]) by smtp.gmail.com with ESMTPSA id cv11sm2366290lbb.49.2016.05.19.08.28.26 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 19 May 2016 08:28:27 -0700 (PDT) From: Christophe Milard To: brian.brooks@linaro.org, maxim.uvarov@linaro.com, lng-odp@lists.linaro.org Date: Thu, 19 May 2016 18:26:40 +0200 Message-Id: <1463675234-6739-2-git-send-email-christophe.milard@linaro.org> X-Mailer: git-send-email 2.5.0 In-Reply-To: <1463675234-6739-1-git-send-email-christophe.milard@linaro.org> References: <1463675234-6739-1-git-send-email-christophe.milard@linaro.org> X-Topics: patch Subject: [lng-odp] [PATCHv8 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; +}