LCOV - code coverage report
Current view: top level - src - m_args.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 77 77 100.0 %
Date: 2017-02-27 17:05:36 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /*********************************** LICENSE **********************************\
       2             : *                            Copyright 2017 Morphux                            *
       3             : *                                                                              *
       4             : *        Licensed under the Apache License, Version 2.0 (the "License");       *
       5             : *        you may not use this file except in compliance with the License.      *
       6             : *                  You may obtain a copy of the License at                     *
       7             : *                                                                              *
       8             : *                 http://www.apache.org/licenses/LICENSE-2.0                   *
       9             : *                                                                              *
      10             : *      Unless required by applicable law or agreed to in writing, software     *
      11             : *       distributed under the License is distributed on an "AS IS" BASIS,      *
      12             : *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  *
      13             : *        See the License for the specific language governing permissions and   *
      14             : *                       limitations under the License.                         *
      15             : \******************************************************************************/
      16             : 
      17             : #include <m_args.h>
      18             : #define LIB_OPT_TOKEN_HELP 'h'
      19             : #define LIB_OPT_STRING_HELP "help"
      20             : #define LIB_OPT_TOKEN_VERSION 'V'
      21             : #define LIB_OPT_STRING_VERSION "version"
      22             : 
      23             : /*!
      24             :  * \brief Read the options given by the program
      25             :  * \param ac Number of argument in av
      26             :  * \param av Array of string, containing the arguments
      27             :  * \param args Array of margs_t, containing the preset options. Must end with
      28             :  * an empty structure.
      29             :  * \return Number of options read
      30             :  *
      31             :  * The read_opt function reads a given list of arguments, and parse the options
      32             :  * in it. The options are read from the args array.
      33             :  * If an option is not known, the function calls the help and quit.
      34             :  * If the option -h | --help is passed, the function call the help and quit.
      35             :  * If the option -v | --version is passed, the function call the version and quit.
      36             :  *
      37             :  * \note Only the arguments beginning with - are parsed.
      38             :  */
      39          32 : u32_t           read_opt(const int ac, char **av, const margs_t *args) {
      40          32 :         u32_t           ret = 0, it, k;
      41             :         u8_t            n_dash;
      42             : 
      43          32 :         if (ac == 0 || av == NULL || args == NULL)
      44           6 :                 return ret;
      45             : 
      46          59 :         for (u32_t i = 1, j = 0; i < (u32_t)ac; i++) {
      47             : 
      48          41 :                 if (av[i] == NULL || strlen(av[i]) == 0)
      49           4 :                         continue ;
      50             : 
      51          37 :                 n_dash = 0;
      52          92 :                 for (j = 0; av[i][j] != '\0' && av[i][j] == '-'; j++)
      53          55 :                         n_dash++;
      54             : 
      55             :                 /* Argument have more than two '-' */
      56          37 :                 if (n_dash > 2) {
      57           1 :                         m_error("Malformed option: %s\n", av[i]);
      58           1 :                         continue ;
      59             :                 }
      60             : 
      61             :                 /* Single letter option */
      62          36 :                 if (n_dash == 1) {
      63             : 
      64          14 :                         if (strlen(av[i]) < 2) {
      65           2 :                                 m_error("Dash without option. Ignoring...\n");
      66           2 :                                 continue ;
      67             :                         }
      68             : 
      69             :                         /* Builtins options */
      70          12 :                         if (av[i][1] == LIB_OPT_TOKEN_HELP)
      71           1 :                                 opt_help(args, 0);
      72          11 :                         else if (av[i][1] == LIB_OPT_TOKEN_VERSION)
      73           1 :                                 p_version(0);
      74             : 
      75             :                         /* Search the option in the args array */
      76          22 :                         for (u32_t z = 1; av[i][z] != '\0'; z++) {
      77          16 :                                 for (it = 0; !IS_EOL(args[it]) && args[it].opt != av[i][z]; it++)
      78             :                                         ;
      79             : 
      80             :                                 /* Can't find the option */
      81          16 :                                 if (IS_EOL(args[it])) {
      82           1 :                                         m_error("Unknow option -%s\n", &(av[i][z]));
      83           1 :                                         opt_help(args, 1);
      84             :                                 } else {
      85          15 :                                         if (args[it].take_arg) {
      86           3 :                                                 if (i + 1 < (u32_t)ac) {
      87           2 :                                                         args[it].callback(av[++i]);
      88           2 :                                                         ret++;
      89           2 :                                                         break ;
      90             :                                                 } else {
      91           1 :                                                         m_error("Option -%c must take an argument\n",
      92           1 :                                                                 args[it].opt);
      93           1 :                                                         opt_help(args, 1);
      94             :                                                 }
      95             :                                         } else {
      96          12 :                                                 args[it].callback(NULL);
      97          12 :                                                 ret++;
      98             :                                         }
      99             :                                 }
     100             :                         }
     101             : 
     102             :                 /* Word option */
     103          22 :                 } else if (n_dash == 2) {
     104          19 :                         bool    got_arg = false;
     105             : 
     106          19 :                         if (strlen(av[i]) < 3) {
     107           1 :                                 m_error("Double dash without option. Ignoring...\n");
     108           1 :                                 continue ;
     109             :                         }
     110             : 
     111             :                         /* Builtins options */
     112          18 :                         if (strcmp(&(av[i][2]), LIB_OPT_STRING_HELP) == 0)
     113           1 :                                 opt_help(args, 0);
     114          17 :                         else if (strcmp(&(av[i][2]), LIB_OPT_STRING_VERSION) == 0)
     115           1 :                                 p_version(0);
     116             : 
     117             :                         /* Look for an argument */
     118          16 :                         for (k = 2; av[i][k] != '\0' && av[i][k] != '='; k++)
     119             :                                 ;
     120             : 
     121          16 :                         if (av[i][k] != '\0') {
     122           4 :                                 got_arg = true;
     123           4 :                                 k -= 2;
     124             :                         } else {
     125          12 :                                 k = strlen(av[i]) - 2;
     126             :                         }
     127             : 
     128             :                         /* Search the option in the args array */
     129          83 :                         for (it = 0; !IS_EOL(args[it]) &&
     130          51 :                                                 (strncmp(args[it].s_opt, &(av[i][2]), k) != 0); it++)
     131             :                                 ;
     132             : 
     133             :                         /* Can't find the option */
     134          16 :                         if (IS_EOL(args[it])) {
     135           1 :                                 m_error("Unknown option %s\n", av[i]);
     136           1 :                                 opt_help(args, 1);
     137             :                         } else {
     138          15 :                                 if (args[it].take_arg && !got_arg) {
     139           1 :                                         m_error("Option %s must take an argument", args[it].s_opt);
     140           1 :                                         opt_help(args, 1);
     141             :                                 }
     142          14 :                                 if (got_arg)
     143           4 :                                         args[it].callback(&(av[i][k + 3]));
     144             :                                 else
     145          10 :                                         args[it].callback(NULL);
     146          14 :                                 ret++;
     147             :                         }
     148             :                 }
     149             :         }
     150          18 :         return ret;
     151             : }
     152             : 
     153             : /*!
     154             :  * \brief Print helps with a list of argument, and exit
     155             :  * \param args List of arguments to print
     156             :  * \param ret Return code of the exit
     157             :  */
     158           6 : void            opt_help(const margs_t *args, u8_t ret) {
     159           6 :         m_info("Help:\n");
     160          22 :         for (u32_t i = 0; args[i].opt != 0; i++) {
     161          16 :                 m_info("\t-%c | --%s : %s\n", args[i].opt, args[i].s_opt, args[i].desc);
     162             :         }
     163           6 :         write(1, "\n", 1);
     164           6 :         m_info("If an argument requires a value, you can set it two ways:\n");
     165           6 :         m_info("\t-o value\n");
     166           6 :         m_info("\t--option=value\n");
     167           6 :         exit(ret);
     168             : }
     169             : 
     170             : /*!
     171             :  * \brief Print the program name, the version and the maintainer, then exit
     172             :  * \param ret Return code of the exit
     173             :  */
     174           2 : void            p_version(u8_t ret) {
     175           2 :         m_info("Program: %s\n", get_program_name());
     176           2 :         m_info("Version: %s\n", get_version());
     177           2 :         m_info("%s\n", get_maintainer());
     178           2 :         exit(ret);
     179             : }

Generated by: LCOV version 1.11