LCOV - code coverage report
Current view: top level - home/runner/zephyrproject/zephyr/boards/native/native_posix - cmdline_common.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 18 194 9.3 %
Date: 2024-09-16 20:15:30 Functions: 1 9 11.1 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 7 103 6.8 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2018 Oticon A/S
       3                 :            :  *
       4                 :            :  * SPDX-License-Identifier: Apache-2.0
       5                 :            :  */
       6                 :            : 
       7                 :            : #include <string.h>
       8                 :            : #include <strings.h>
       9                 :            : #include <stdbool.h>
      10                 :            : #include <stdlib.h>
      11                 :            : #include <stdio.h>
      12                 :            : #include <math.h>
      13                 :            : #include <zephyr/arch/posix/posix_trace.h>
      14                 :            : #include "posix_board_if.h"
      15                 :            : #include <zephyr/types.h>
      16                 :            : #include "cmdline_common.h"
      17                 :            : 
      18                 :            : /**
      19                 :            :  * Check if <arg> is the option <option>
      20                 :            :  * The accepted syntax is:
      21                 :            :  *   * For options without a value following:
      22                 :            :  *       [-[-]]<option>
      23                 :            :  *   * For options with value:
      24                 :            :  *       [-[-]]<option>{:|=}<value>
      25                 :            :  *
      26                 :            :  * Returns 0 if it is not, or a number > 0 if it is.
      27                 :            :  * The returned number is the number of characters it went through
      28                 :            :  * to find the end of the option including the ':' or '=' character in case of
      29                 :            :  * options with value
      30                 :            :  */
      31                 :          0 : int cmd_is_option(const char *arg, const char *option, int with_value)
      32                 :            : {
      33                 :          0 :         int of = 0;
      34                 :          0 :         size_t to_match_len = strlen(option);
      35                 :            : 
      36         [ #  # ]:          0 :         if (arg[of] == '-') {
      37                 :          0 :                 of++;
      38                 :            :         }
      39         [ #  # ]:          0 :         if (arg[of] == '-') {
      40                 :          0 :                 of++;
      41                 :            :         }
      42                 :            : 
      43         [ #  # ]:          0 :         if (!with_value) {
      44         [ #  # ]:          0 :                 if (strcmp(&arg[of], option) != 0) {
      45                 :            :                         return 0;
      46                 :            :                 } else {
      47                 :          0 :                         return of + to_match_len;
      48                 :            :                 }
      49                 :            :         }
      50                 :            : 
      51   [ #  #  #  # ]:          0 :         while (!(arg[of] == 0 && *option == 0)) {
      52         [ #  # ]:          0 :                 if (*option == 0) {
      53         [ #  # ]:          0 :                         if ((arg[of] == ':') || (arg[of] == '=')) {
      54                 :          0 :                                 of++;
      55                 :          0 :                                 break;
      56                 :            :                         }
      57                 :            :                         return 0;
      58                 :            :                 }
      59         [ #  # ]:          0 :                 if (arg[of] != *option) {
      60                 :            :                         return 0;
      61                 :            :                 }
      62                 :          0 :                 of++;
      63                 :          0 :                 option++;
      64                 :            :         }
      65                 :            : 
      66         [ #  # ]:          0 :         if (arg[of] == 0) { /* we need a value to follow */
      67                 :          0 :                 posix_print_error_and_exit("Incorrect option syntax '%s'. The "
      68                 :            :                                            "value should follow the options. "
      69                 :            :                                            "For example --ratio=3\n",
      70                 :            :                                            arg);
      71                 :            :         }
      72                 :            :         return of;
      73                 :            : }
      74                 :            : 
      75                 :            : /**
      76                 :            :  * Return 1 if <arg> matches an accepted help option.
      77                 :            :  * 0 otherwise
      78                 :            :  *
      79                 :            :  * Valid help options are [-[-]]{?|h|help}
      80                 :            :  * with the h or help in any case combination
      81                 :            :  */
      82                 :          0 : int cmd_is_help_option(const char *arg)
      83                 :            : {
      84         [ #  # ]:          0 :         if (arg[0] == '-') {
      85                 :          0 :                 arg++;
      86                 :            :         }
      87         [ #  # ]:          0 :         if (arg[0] == '-') {
      88                 :          0 :                 arg++;
      89                 :            :         }
      90         [ #  # ]:          0 :         if ((strcasecmp(arg, "?") == 0) ||
      91         [ #  # ]:          0 :             (strcasecmp(arg, "h") == 0) ||
      92         [ #  # ]:          0 :             (strcasecmp(arg, "help") == 0)) {
      93                 :            :                 return 1;
      94                 :            :         } else {
      95                 :          0 :                 return 0;
      96                 :            :         }
      97                 :            : }
      98                 :            : 
      99                 :            : #define CMD_TYPE_ERROR "Coding error: type %c not understood"
     100                 :            : #define CMD_ERR_BOOL_SWI "Programming error: I only know how to "\
     101                 :            :         "automatically read boolean switches\n"
     102                 :            : 
     103                 :            : /**
     104                 :            :  * Read out a the value following an option from str, and store it into
     105                 :            :  * <dest>
     106                 :            :  * <type> indicates the type of parameter (and type of dest pointer)
     107                 :            :  *   'b' : boolean
     108                 :            :  *   's' : string (char *)
     109                 :            :  *   'u' : 32 bit unsigned integer
     110                 :            :  *   'U' : 64 bit unsigned integer
     111                 :            :  *   'i' : 32 bit signed integer
     112                 :            :  *   'I' : 64 bit signed integer
     113                 :            :  *   'd' : *double* float
     114                 :            :  *
     115                 :            :  * Note: list type ('l') cannot be handled by this function and must always be
     116                 :            :  *       manual
     117                 :            :  *
     118                 :            :  *  <long_d> is the long name of the option
     119                 :            :  */
     120                 :          0 : void cmd_read_option_value(const char *str, void *dest, const char type,
     121                 :            :                            const char *option)
     122                 :            : {
     123                 :          0 :         int error = 0;
     124                 :          0 :         char *endptr = NULL;
     125                 :            : 
     126   [ #  #  #  #  :          0 :         switch (type) {
             #  #  #  # ]
     127                 :          0 :         case 'b':
     128         [ #  # ]:          0 :                 if (strcasecmp(str, "false") == 0) {
     129                 :          0 :                         *(bool *)dest = false;
     130                 :          0 :                         endptr = (char *)str + 5;
     131         [ #  # ]:          0 :                 } else if (strcmp(str, "0") == 0) {
     132                 :          0 :                         *(bool *)dest = false;
     133                 :          0 :                         endptr = (char *)str + 1;
     134         [ #  # ]:          0 :                 } else if (strcasecmp(str, "true") == 0) {
     135                 :          0 :                         *(bool *)dest = true;
     136                 :          0 :                         endptr = (char *)str + 4;
     137         [ #  # ]:          0 :                 } else if (strcmp(str, "1") == 0) {
     138                 :          0 :                         *(bool *)dest = true;
     139                 :          0 :                         endptr = (char *)str + 1;
     140                 :            :                 } else {
     141                 :            :                         error = 1;
     142                 :            :                 }
     143                 :            :                 break;
     144                 :          0 :         case 's':
     145                 :          0 :                 *(char **)dest = (char *)str;
     146                 :          0 :                 endptr = (char *)str + strlen(str);
     147                 :          0 :                 break;
     148                 :          0 :         case 'u':
     149                 :          0 :                 *(uint32_t *)dest = strtoul(str, &endptr, 0);
     150                 :          0 :                 break;
     151                 :          0 :         case 'U':
     152                 :          0 :                 *(uint64_t *)dest = strtoull(str, &endptr, 0);
     153                 :          0 :                 break;
     154                 :          0 :         case 'i':
     155                 :          0 :                 *(int32_t *)dest = strtol(str, &endptr, 0);
     156                 :          0 :                 break;
     157                 :          0 :         case 'I':
     158                 :          0 :                 *(int64_t *)dest = strtoll(str, &endptr, 0);
     159                 :          0 :                 break;
     160                 :          0 :         case 'd':
     161                 :          0 :                 *(double *)dest = strtod(str, &endptr);
     162                 :          0 :                 break;
     163                 :          0 :         default:
     164                 :          0 :                 posix_print_error_and_exit(CMD_TYPE_ERROR, type);
     165                 :            :                 /* Unreachable */
     166                 :          0 :                 break;
     167                 :            :         }
     168                 :            : 
     169   [ #  #  #  # ]:          0 :         if (!error && endptr && *endptr != 0) {
     170                 :            :                 error = 1;
     171                 :            :         }
     172                 :            : 
     173         [ #  # ]:          0 :         if (error) {
     174                 :          0 :                 posix_print_error_and_exit("Error reading value of %s '%s'. Use"
     175                 :            :                                            " --help for usage information\n",
     176                 :            :                                            option, str);
     177                 :            :         }
     178                 :          0 : }
     179                 :            : 
     180                 :            : /**
     181                 :            :  * Initialize existing dest* to defaults based on type
     182                 :            :  */
     183                 :          1 : void cmd_args_set_defaults(struct args_struct_t args_struct[])
     184                 :            : {
     185                 :          1 :         int count = 0;
     186                 :            : 
     187         [ +  + ]:         14 :         while (args_struct[count].option != NULL) {
     188                 :            : 
     189         [ +  + ]:         13 :                 if (args_struct[count].dest == NULL) {
     190                 :          7 :                         count++;
     191                 :          7 :                         continue;
     192                 :            :                 }
     193                 :            : 
     194   [ +  +  -  -  :          6 :                 switch (args_struct[count].type) {
             -  -  +  -  
                      - ]
     195                 :            :                 case 0: /* does not have storage */
     196                 :            :                         break;
     197                 :          1 :                 case 'b':
     198                 :          1 :                         *(bool *)args_struct[count].dest = false;
     199                 :          1 :                         break;
     200                 :          1 :                 case 's':
     201                 :          1 :                         *(char **)args_struct[count].dest = NULL;
     202                 :          1 :                         break;
     203                 :          0 :                 case 'u':
     204                 :          0 :                         *(uint32_t *)args_struct[count].dest = UINT32_MAX;
     205                 :          0 :                         break;
     206                 :          0 :                 case 'U':
     207                 :          0 :                         *(uint64_t *)args_struct[count].dest = UINT64_MAX;
     208                 :          0 :                         break;
     209                 :          0 :                 case 'i':
     210                 :          0 :                         *(int32_t *)args_struct[count].dest = INT32_MAX;
     211                 :          0 :                         break;
     212                 :          0 :                 case 'I':
     213                 :          0 :                         *(int64_t *)args_struct[count].dest = INT64_MAX;
     214                 :          0 :                         break;
     215                 :          4 :                 case 'd':
     216                 :          4 :                         *(double *)args_struct[count].dest = (double)NAN;
     217                 :          4 :                         break;
     218                 :          0 :                 default:
     219                 :          0 :                         posix_print_error_and_exit(CMD_TYPE_ERROR,
     220                 :            :                                                    args_struct[count].type);
     221                 :          0 :                         break;
     222                 :            :                 }
     223                 :          6 :                 count++;
     224                 :            :         }
     225                 :          1 : }
     226                 :            : 
     227                 :            : /**
     228                 :            :  * For the help messages:
     229                 :            :  * Generate a string containing how the option described by <args_s_el>
     230                 :            :  * should be used
     231                 :            :  *
     232                 :            :  * The string is saved in <buf> which has been allocated <size> bytes by the
     233                 :            :  * caller
     234                 :            :  */
     235                 :          0 : static void cmd_gen_switch_syntax(char *buf, int size,
     236                 :            :                                   struct args_struct_t *args_s_el)
     237                 :            : {
     238                 :          0 :         int ret = 0;
     239                 :            : 
     240         [ #  # ]:          0 :         if (size <= 0) {
     241                 :            :                 return;
     242                 :            :         }
     243                 :            : 
     244         [ #  # ]:          0 :         if (args_s_el->is_mandatory == false) {
     245                 :          0 :                 *buf++ = '[';
     246                 :          0 :                 size--;
     247                 :            :         }
     248                 :            : 
     249         [ #  # ]:          0 :         if (args_s_el->is_switch == true) {
     250                 :          0 :                 ret = snprintf(buf, size, "-%s", args_s_el->option);
     251                 :            :         } else {
     252         [ #  # ]:          0 :                 if (args_s_el->type != 'l') {
     253                 :          0 :                         ret = snprintf(buf, size, "-%s=<%s>",
     254                 :            :                                         args_s_el->option, args_s_el->name);
     255                 :            :                 } else {
     256                 :          0 :                         ret = snprintf(buf, size, "-%s <%s>...",
     257                 :            :                                         args_s_el->option, args_s_el->name);
     258                 :            :                 }
     259                 :            :         }
     260                 :            : 
     261         [ #  # ]:          0 :         if (ret < 0) {
     262                 :          0 :                 posix_print_error_and_exit("Unexpected error in %s %i\n",
     263                 :            :                                            __FILE__, __LINE__);
     264                 :            :         }
     265         [ #  # ]:          0 :         if (size - ret < 0) {
     266                 :            :                 /*
     267                 :            :                  * If we run out of space we can just stop,
     268                 :            :                  * this is not critical
     269                 :            :                  */
     270                 :            :                 return;
     271                 :            :         }
     272                 :          0 :         buf += ret;
     273                 :          0 :         size -= ret;
     274                 :            : 
     275         [ #  # ]:          0 :         if (args_s_el->is_mandatory == false) {
     276                 :          0 :                 snprintf(buf, size, "] ");
     277                 :            :         } else {
     278                 :          0 :                 snprintf(buf, size, " ");
     279                 :            :         }
     280                 :            : }
     281                 :            : 
     282                 :            : /**
     283                 :            :  * Print short list of available switches
     284                 :            :  */
     285                 :          0 : void cmd_print_switches_help(struct args_struct_t args_struct[])
     286                 :            : {
     287                 :          0 :         int count = 0;
     288                 :          0 :         int printed_in_line = strlen(_HELP_SWITCH) + 1;
     289                 :            : 
     290                 :          0 :         fprintf(stdout, "%s ", _HELP_SWITCH);
     291                 :            : 
     292         [ #  # ]:          0 :         while (args_struct[count].option != NULL) {
     293                 :          0 :                 char stringy[_MAX_STRINGY_LEN];
     294                 :            : 
     295                 :          0 :                 cmd_gen_switch_syntax(stringy, _MAX_STRINGY_LEN,
     296                 :            :                                       &args_struct[count]);
     297                 :            : 
     298         [ #  # ]:          0 :                 if (printed_in_line + strlen(stringy) > _MAX_LINE_WIDTH) {
     299                 :          0 :                         fprintf(stdout, "\n");
     300                 :          0 :                         printed_in_line = 0;
     301                 :            :                 }
     302                 :            : 
     303                 :          0 :                 fprintf(stdout, "%s", stringy);
     304                 :          0 :                 printed_in_line += strlen(stringy);
     305                 :          0 :                 count++;
     306                 :            :         }
     307                 :            : 
     308                 :          0 :         fprintf(stdout, "\n");
     309                 :          0 : }
     310                 :            : 
     311                 :            : /**
     312                 :            :  * Print the long help message of the program
     313                 :            :  */
     314                 :          0 : void cmd_print_long_help(struct args_struct_t args_struct[])
     315                 :            : {
     316                 :          0 :         int ret;
     317                 :          0 :         int count = 0;
     318                 :          0 :         int printed_in_line = 0;
     319                 :          0 :         char stringy[_MAX_STRINGY_LEN];
     320                 :            : 
     321                 :          0 :         cmd_print_switches_help(args_struct);
     322                 :            : 
     323                 :          0 :         fprintf(stdout, "\n %-*s:%s\n", _LONG_HELP_ALIGN-1,
     324                 :            :                 _HELP_SWITCH, _HELP_DESCR);
     325                 :            : 
     326         [ #  # ]:          0 :         while (args_struct[count].option != NULL) {
     327                 :          0 :                 int printed_right;
     328                 :          0 :                 char *toprint;
     329                 :          0 :                 int total_to_print;
     330                 :            : 
     331                 :          0 :                 cmd_gen_switch_syntax(stringy, _MAX_STRINGY_LEN,
     332                 :            :                                       &args_struct[count]);
     333                 :            : 
     334                 :          0 :                 ret = fprintf(stdout, " %-*s:", _LONG_HELP_ALIGN-1, stringy);
     335                 :          0 :                 printed_in_line = ret;
     336                 :          0 :                 printed_right = 0;
     337                 :          0 :                 toprint = args_struct[count].descript;
     338                 :          0 :                 total_to_print = strlen(toprint);
     339                 :          0 :                 ret = fprintf(stdout, "%.*s\n",
     340                 :            :                                 _MAX_LINE_WIDTH - printed_in_line,
     341                 :            :                                 &toprint[printed_right]);
     342                 :          0 :                 printed_right += ret - 1;
     343                 :            : 
     344         [ #  # ]:          0 :                 while (printed_right < total_to_print) {
     345                 :          0 :                         fprintf(stdout, "%*s", _LONG_HELP_ALIGN, "");
     346                 :          0 :                         ret = fprintf(stdout, "%.*s\n",
     347                 :            :                                       _MAX_LINE_WIDTH - _LONG_HELP_ALIGN,
     348                 :            :                                       &toprint[printed_right]);
     349                 :          0 :                         printed_right += ret - 1;
     350                 :            :                 }
     351                 :          0 :                 count++;
     352                 :            :         }
     353                 :          0 :         fprintf(stdout, "\n");
     354                 :          0 :         fprintf(stdout, "Note that which options are available depends on the "
     355                 :            :                 "enabled features/drivers\n\n");
     356                 :          0 : }
     357                 :            : 
     358                 :            : /*
     359                 :            :  * <argv> matched the argument described in <arg_element>
     360                 :            :  *
     361                 :            :  * If arg_element->dest points to a place to store a possible value, read it
     362                 :            :  * If there is a callback registered, call it after
     363                 :            :  */
     364                 :          0 : static void cmd_handle_this_matched_arg(char *argv, int offset,
     365                 :            :                                         struct args_struct_t *arg_element)
     366                 :            : {
     367         [ #  # ]:          0 :         if (arg_element->dest != NULL) {
     368         [ #  # ]:          0 :                 if (arg_element->is_switch) {
     369         [ #  # ]:          0 :                         if (arg_element->type == 'b') {
     370                 :          0 :                                 *(bool *)arg_element->dest = true;
     371                 :            :                         } else {
     372                 :          0 :                                 posix_print_error_and_exit(CMD_ERR_BOOL_SWI);
     373                 :            :                         }
     374                 :            :                 } else { /* if not a switch we need to read its value */
     375                 :          0 :                         cmd_read_option_value(&argv[offset],
     376                 :            :                                               arg_element->dest,
     377                 :          0 :                                               arg_element->type,
     378                 :          0 :                                               arg_element->option);
     379                 :            :                 }
     380                 :            :         }
     381                 :            : 
     382         [ #  # ]:          0 :         if (arg_element->call_when_found) {
     383                 :          0 :                 arg_element->call_when_found(argv, offset);
     384                 :            :         }
     385                 :          0 : }
     386                 :            : 
     387                 :            : /**
     388                 :            :  * Try to find if this argument is in the list (and it is not manual)
     389                 :            :  * if it does, try to parse it, set its dest accordingly, and return true
     390                 :            :  * if it is not found, return false
     391                 :            :  */
     392                 :          0 : bool cmd_parse_one_arg(char *argv, struct args_struct_t args_struct[])
     393                 :            : {
     394                 :          0 :         int count = 0;
     395                 :          0 :         int ret;
     396                 :            : 
     397         [ #  # ]:          0 :         if (cmd_is_help_option(argv)) {
     398                 :          0 :                 cmd_print_long_help(args_struct);
     399                 :          0 :                 posix_exit(0);
     400                 :            :         }
     401                 :            : 
     402         [ #  # ]:          0 :         while (args_struct[count].option != NULL) {
     403         [ #  # ]:          0 :                 if (args_struct[count].manual) {
     404                 :          0 :                         count++;
     405                 :          0 :                         continue;
     406                 :            :                 }
     407                 :          0 :                 ret = cmd_is_option(argv, args_struct[count].option,
     408                 :          0 :                                     !args_struct[count].is_switch);
     409         [ #  # ]:          0 :                 if (ret) {
     410                 :          0 :                         cmd_handle_this_matched_arg(argv,
     411                 :            :                                                     ret,
     412                 :            :                                                     &args_struct[count]);
     413                 :          0 :                         return true;
     414                 :            :                 }
     415                 :          0 :                 count++;
     416                 :            :         }
     417                 :            :         return false;
     418                 :            : }

Generated by: LCOV version 1.14