LCOV - code coverage report
Current view: top level - src - m_args.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 72 77 93.5 %
Date: 2017-03-13 16:41:56 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             : #include <m_list.h>
      19             : #define LIB_OPT_TOKEN_HELP 'h'
      20             : #define LIB_OPT_STRING_HELP "help"
      21             : #define LIB_OPT_TOKEN_VERSION 'V'
      22             : #define LIB_OPT_STRING_VERSION "version"
      23             : 
      24             : /*!
      25             :  * \brief Read the options given by the program
      26             :  * \param ac Number of argument in av
      27             :  * \param av Array of string, containing the arguments
      28             :  * \param args Array of margs_t, containing the preset options. Must end with
      29             :  * an empty structure.
      30             :  * \param params Adress of linked list, that will be filled with av with
      31             :  * flags removed
      32             :  * \return Number of options read
      33             :  *
      34             :  * The read_opt function reads a given list of arguments, and parse the options
      35             :  * in it. The options are read from the args array.
      36             :  * If an option is not known, the function calls the help and quit.
      37             :  * If the option -h | --help is passed, the function call the help and quit.
      38             :  * If the option -V | --version is passed, the function display the version
      39             :  * and quit.
      40             :  *
      41             :  * \note Only the arguments beginning with - are parsed.
      42             :  */
      43          96 : u32_t           read_opt(const int ac, char **av, const mopts_t *opts, \
      44             :                                                 mlist_t **args) {
      45          96 :         u32_t           ret = 0, i = 1, it, k;
      46             :         u8_t            n_dash;
      47             : 
      48          96 :         if (ac == 0 || av == NULL || opts == NULL || args == NULL)
      49          30 :                 return ret;
      50             : 
      51         158 :         for (/* Using u32_t i */ u32_t j = 0; i < (u32_t)ac; i++) {
      52             : 
      53         112 :                 if (av[i] == NULL || strlen(av[i]) == 0)
      54          16 :                         continue ;
      55             : 
      56          96 :                 n_dash = 0;
      57         228 :                 for (j = 0; av[i][j] != '\0' && av[i][j] == '-'; j++)
      58         132 :                         n_dash++;
      59             : 
      60             :                 /* Single letter option */
      61          96 :                 if (n_dash == 1) {
      62             : 
      63             :                         /* If single dash alone, its a parameter */
      64          34 :                         if (strlen(av[i]) < 2) {
      65             :                                 /* And we stop reading options. */
      66           0 :                                 break ;
      67             :                         }
      68             : 
      69             :                         /* Builtins options */
      70          34 :                         if (av[i][1] == LIB_OPT_TOKEN_HELP)
      71           2 :                                 opt_help(opts, 0);
      72          32 :                         else if (av[i][1] == LIB_OPT_TOKEN_VERSION)
      73           2 :                                 p_version(0);
      74             : 
      75             :                         /* Search the option in the opts array */
      76          64 :                         for (u32_t z = 1; av[i][z] != '\0'; z++) {
      77          42 :                                 for (it = 0; !IS_EOL(opts[it]) && opts[it].opt != av[i][z]; it++)
      78             :                                         ;
      79             : 
      80             :                                 /* Can't find the option */
      81          42 :                                 if (IS_EOL(opts[it])) {
      82           2 :                                         m_error("Unknow option -%s\n", &(av[i][z]));
      83           2 :                                         opt_help(opts, 1);
      84             :                                 } else {
      85          40 :                                         if (opts[it].take_arg) {
      86           6 :                                                 if (i + 1 < (u32_t)ac) {
      87           4 :                                                         opts[it].callback(av[++i]);
      88           4 :                                                         ret++;
      89           4 :                                                         break ;
      90             :                                                 } else {
      91           2 :                                                         m_error("Option -%c must take an argument\n",
      92           2 :                                                                 opts[it].opt);
      93           2 :                                                         opt_help(opts, 1);
      94             :                                                 }
      95             :                                         } else {
      96          34 :                                                 opts[it].callback(NULL);
      97          34 :                                                 ret++;
      98             :                                         }
      99             :                                 }
     100             :                         }
     101             : 
     102             :                 /* Word option */
     103          62 :                 } else if (n_dash == 2) {
     104          46 :                         bool    got_arg = false;
     105             : 
     106             :                         /* If double dash alone, skip it and then stop reading options */
     107          46 :                         if (strlen(av[i]) < 3) {
     108           0 :                                 i++;
     109           0 :                                 break ;
     110             :                         }
     111             : 
     112             :                         /* Builtins options */
     113          46 :                         if (strcmp(&(av[i][2]), LIB_OPT_STRING_HELP) == 0)
     114           4 :                                 opt_help(opts, 0);
     115          42 :                         else if (strcmp(&(av[i][2]), LIB_OPT_STRING_VERSION) == 0)
     116           4 :                                 p_version(0);
     117             : 
     118             :                         /* Look for an argument */
     119          38 :                         for (k = 2; av[i][k] != '\0' && av[i][k] != '='; k++)
     120             :                                 ;
     121             : 
     122          38 :                         if (av[i][k] != '\0') {
     123           8 :                                 got_arg = true;
     124           8 :                                 k -= 2;
     125             :                         } else {
     126          30 :                                 k = strlen(av[i]) - 2;
     127             :                         }
     128             : 
     129             :                         /* Search the option in the opts array */
     130         196 :                         for (it = 0; !IS_EOL(opts[it]) &&
     131         120 :                                                 (strncmp(opts[it].s_opt, &(av[i][2]), k) != 0); it++)
     132             :                                 ;
     133             : 
     134             :                         /* Can't find the option */
     135          38 :                         if (IS_EOL(opts[it])) {
     136           2 :                                 m_error("Unknown option %s\n", av[i]);
     137           2 :                                 opt_help(opts, 1);
     138             :                         } else {
     139          36 :                                 if (opts[it].take_arg && !got_arg) {
     140           2 :                                         m_error("Option %s must take an argument", opts[it].s_opt);
     141           2 :                                         opt_help(opts, 1);
     142             :                                 }
     143          34 :                                 if (got_arg)
     144           8 :                                         opts[it].callback(&(av[i][k + 3]));
     145             :                                 else
     146          26 :                                         opts[it].callback(NULL);
     147          34 :                                 ret++;
     148             :                         }
     149             :                 /* Not beginning with a dash */
     150             :                 } else {
     151             :                         /* Stop reading options */
     152          16 :                         list_add(*args, av[i], strlen(av[i]) + 1);
     153             :                 }
     154             :         }
     155             :         /* If reading of flags is stopped by '-' or '--'
     156             :          * get the rest of the parameters */
     157          46 :         for ( /* Using u32_t i */ ; i < (u32_t)ac; i++) {
     158           0 :                 if (av[i] && strlen(av[i]))
     159           0 :                         list_add(*args, av[i], strlen(av[i]) + 1);
     160             :         }
     161          46 :         return ret;
     162             : }
     163             : 
     164             : /*!
     165             :  * \brief Print helps with a list of argument, and exit
     166             :  * \param opts List of arguments to print
     167             :  * \param ret Return code of the exit
     168             :  */
     169          14 : void            opt_help(const mopts_t *opts, u8_t ret) {
     170          14 :         m_info("Help:\n");
     171          48 :         for (u32_t i = 0; opts[i].opt != 0; i++) {
     172          34 :                 m_info("\t-%c | --%s : %s\n", opts[i].opt, opts[i].s_opt, opts[i].desc);
     173             :         }
     174          14 :         write(1, "\n", 1);
     175          14 :         m_info("If an argument requires a value, you can set it two ways:\n");
     176          14 :         m_info("\t-o value\n");
     177          14 :         m_info("\t--option=value\n");
     178          14 :         exit(ret);
     179             : }
     180             : 
     181             : /*!
     182             :  * \brief Print the program name, the version and the maintainer, then exit
     183             :  * \param ret Return code of the exit
     184             :  */
     185           6 : void            p_version(u8_t ret) {
     186           6 :         m_info("Program: %s\n", get_program_name());
     187           6 :         m_info("Version: %s\n", get_version());
     188           6 :         m_info("%s\n", get_maintainer());
     189           6 :         exit(ret);
     190             : }

Generated by: LCOV version 1.11