You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ag...@apache.org on 2021/04/02 20:31:14 UTC

[incubator-nuttx] branch master updated: Correct some getopt() logic

This is an automated email from the ASF dual-hosted git repository.

aguettouche pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new af3c76b  Correct some getopt() logic
af3c76b is described below

commit af3c76bb53f6194b49e2684d3d74d03c16408dfa
Author: Gregory Nutt <gn...@nuttx.org>
AuthorDate: Fri Apr 2 08:34:25 2021 -0600

    Correct some getopt() logic
    
    1. Null pointer dereference:
    
    -  for (ndx = 0; longopts[ndx].name[0] != '\0'; ndx++)
    +  for (ndx = 0; longopts[ndx].name != NULL; ndx++)
    
    2. Handle single character long options.  An option like -x could be either a short option or a long option (under getopt_long_only()).  This case was not being handled correctly.
    
    3. Add missing support for optional arguments to short options (indicated with two "::"
    
    This effects all members of the getopt() family of APIs.
    
    Tested on the simulator using extensions to apps/testing/ostest.
---
 libs/libc/unistd/lib_getopt_common.c | 59 ++++++++++++++++++++++++------------
 1 file changed, 39 insertions(+), 20 deletions(-)

diff --git a/libs/libc/unistd/lib_getopt_common.c b/libs/libc/unistd/lib_getopt_common.c
index 4fa0db9..86d2159 100644
--- a/libs/libc/unistd/lib_getopt_common.c
+++ b/libs/libc/unistd/lib_getopt_common.c
@@ -69,7 +69,7 @@ static int getopt_long_option(FAR struct getopt_s *go,
    * The last element of the option arry must be filled with zeroes.
    */
 
-  for (ndx = 0; longopts[ndx].name[0] != '\0'; ndx++)
+  for (ndx = 0; longopts[ndx].name != NULL; ndx++)
     {
       if (strcmp(go->go_optptr, longopts[ndx].name) == 0)
         {
@@ -99,6 +99,7 @@ static int getopt_long_option(FAR struct getopt_s *go,
                 if (next == NULL || next[0] == '-')
                   {
                     go->go_optptr = NULL;
+                    go->go_optarg = NULL;
                     go->go_optind++;
                     break;
                   }
@@ -168,7 +169,6 @@ static int getopt_long_option(FAR struct getopt_s *go,
   /* This option is not in the list of valid options */
 
   go->go_optopt = *go->go_optptr;
-  go->go_optptr++;
   return '?';
 
 errout:
@@ -251,6 +251,8 @@ int getopt_common(int argc, FAR char * const argv[],
                   FAR int *longindex,
                   enum getopt_mode_e mode)
 {
+  int ret;
+
   /* Get thread-specific getopt() variables */
 
   FAR struct getopt_s *go = getoptvars();
@@ -360,19 +362,22 @@ int getopt_common(int argc, FAR char * const argv[],
       /* go->go_optptr now points at the next option and it is not something
        * crazy.  Possibilities:
        *
-       *  -o
-       *  -o reqarg
-       *  -option
-       *  -option reqarg
-       *  -option optarg
-       *  --option reqarg
-       *  --option optarg
+       *  FORM              APPLICABILITY
+       *  -o                getopt(), getopt_long_only()
+       *  -o reqarg         getopt(), getopt_long_only()
+       *  -o optarg         getopt_long_only()
+       *  -option           getopt_long_only()
+       *  -option reqarg    getopt_long_only()
+       *  -option optarg    getopt_long_only()
+       *  --option          getopt_long(), getopt_long_only()
+       *  --option reqarg   getopt_long(), getopt_long_only()
+       *  --option optarg   getopt_long(), getopt_long_only()
        *
        * Where:
-       *   o      - Some short option
-       *   option - Some long option
-       *   reqarg - A required argument
-       *   optarg - An optional argument
+       *  o      - Some short option
+       *  option - Some long option
+       *  reqarg - A required argument
+       *  optarg - An optional argument
        */
 
       /* Check for --option forms or -option forms */
@@ -396,14 +401,25 @@ int getopt_common(int argc, FAR char * const argv[],
            * must be distinguished from the -o case forms.
            */
 
-          if (GETOPT_HAVE_LONGONLY(mode) && *(go->go_optptr + 1) != '\0')
+          else if (GETOPT_HAVE_LONGONLY(mode))
             {
-              return getopt_long_option(go, argv, longopts, longindex);
+              /* A special case is that the option is of a form like
+               * -o but is represented as a single character long option.
+               * In that case, getopt_long_option() will fail with '?' and,
+               * if it is a single character option, we can just fall
+               * through to the short option logic.
+               */
+
+              ret = getopt_long_option(go, argv, longopts, longindex);
+              if (ret != '?' ||  *(go->go_optptr + 1) != '\0')
+                {
+                  return ret;
+                }
             }
         }
 
       /* Check if the option is in the list of valid short options.
-       * In long option modes, opstring may be NULL. However, but that is
+       * In long option modes, opstring may be NULL. However, that is
        * an error in any case here because we have not found any
        * long options.
        */
@@ -435,8 +451,8 @@ int getopt_common(int argc, FAR char * const argv[],
           return *optchar;
         }
 
-      /* Yes, it has a required argument.  Is the required argument
-       * immediately after the command in this same argument?
+      /* Yes, it may have an argument.  Is the argument immediately after
+       * the command in this same argument?
        */
 
       if (go->go_optptr[1] != '\0')
@@ -449,7 +465,7 @@ int getopt_common(int argc, FAR char * const argv[],
           return *optchar;
         }
 
-      /* No.. is the optional argument the next argument in argv[] ? */
+      /* No.. is there an argument in the next value of argv[] ? */
 
       if (argv[go->go_optind + 1] && *argv[go->go_optind + 1] != '-')
         {
@@ -467,7 +483,10 @@ int getopt_common(int argc, FAR char * const argv[],
       go->go_optarg = NULL;
       go->go_optopt = *optchar;
       go->go_optind++;
-      return noarg_ret;
+
+      /* Two colons means that the argument is optional. */
+
+      return (optchar[2] == ':') ? *optchar : noarg_ret;
     }
 
 errout: