| /**************************************************************************** |
| * apps/testing/ostest/getopt.c |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. The |
| * ASF licenses this file to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the |
| * License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations |
| * under the License. |
| * |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Included Files |
| ****************************************************************************/ |
| |
| #include <nuttx/config.h> |
| |
| #include <assert.h> |
| #include <getopt.h> |
| #include <stdio.h> |
| #include <string.h> |
| |
| #include "ostest.h" |
| |
| /**************************************************************************** |
| * Pre-processor DEFINITIONS |
| ****************************************************************************/ |
| |
| #define SHORT_RESULT_A(n) \ |
| { \ |
| results[n].ret = 'a'; \ |
| results[n].flag = 0; \ |
| results[n].arg = NULL; \ |
| } |
| |
| #define SHORT_RESULT_B(n) \ |
| { \ |
| results[n].ret = 'b'; \ |
| results[n].flag = 0; \ |
| results[n].arg = NULL; \ |
| } |
| |
| #define SHORT_RESULT_C1(n) \ |
| { \ |
| results[n].ret = 'c'; \ |
| results[n].flag = 0; \ |
| results[n].arg = "Arg1"; \ |
| } |
| |
| #define SHORT_RESULT_C2(n) \ |
| { \ |
| results[n].ret = 'c'; \ |
| results[n].flag = 0; \ |
| results[n].arg = NULL; \ |
| } |
| |
| #define SHORT_RESULT_D(n) \ |
| { \ |
| results[n].ret = 'd'; \ |
| results[n].flag = 0; \ |
| results[n].arg = "Arg2"; \ |
| } |
| |
| #define SHORT_RESULT_X(n) \ |
| { \ |
| results[n].ret = '?'; \ |
| results[n].flag = 0; \ |
| results[n].arg = NULL; \ |
| } |
| |
| #define LONG_OPTION_A(n) \ |
| { \ |
| long_options[n].name = "OptionA"; \ |
| long_options[n].has_arg = no_argument; \ |
| long_options[n].flag = NULL; \ |
| long_options[n].val = 'a'; \ |
| } |
| |
| #define LONG_OPTION_B(n) \ |
| { \ |
| long_options[n].name = "OptionB"; \ |
| long_options[n].has_arg = no_argument; \ |
| long_options[n].flag = &g_flag; \ |
| long_options[n].val = 'b'; \ |
| } |
| |
| #define LONG_OPTION_C(n) \ |
| { \ |
| long_options[n].name = "OptionC"; \ |
| long_options[n].has_arg = required_argument; \ |
| long_options[n].flag = NULL; \ |
| long_options[n].val = 'c'; \ |
| } |
| |
| #define LONG_OPTION_D(n) \ |
| { \ |
| long_options[n].name = "OptionD"; \ |
| long_options[n].has_arg = optional_argument; \ |
| long_options[n].flag = &g_flag; \ |
| long_options[n].val = 'd'; \ |
| } |
| |
| #define LONG_OPTION_END(n) \ |
| { \ |
| long_options[n].name = NULL; \ |
| long_options[n].has_arg = 0; \ |
| long_options[n].flag = NULL; \ |
| long_options[n].val = 0; \ |
| } |
| |
| #define LONG_RESULT_A(n) \ |
| { \ |
| results[n].ret = 'a'; \ |
| results[n].flag = 0; \ |
| results[n].arg = NULL; \ |
| } |
| |
| #define LONG_RESULT_B(n) \ |
| { \ |
| results[n].ret = OK; \ |
| results[n].flag = 'b'; \ |
| results[n].arg = NULL; \ |
| } |
| |
| #define LONG_RESULT_C(n) \ |
| { \ |
| results[n].ret = 'c'; \ |
| results[n].flag = 0; \ |
| results[n].arg = "Arg1"; \ |
| } |
| |
| #define LONG_RESULT_D1(n) \ |
| { \ |
| results[n].ret = OK; \ |
| results[n].flag = 'd'; \ |
| results[n].arg = "Arg2"; \ |
| } |
| |
| #define LONG_RESULT_D2(n) \ |
| { \ |
| results[n].ret = OK; \ |
| results[n].flag = 'd'; \ |
| results[n].arg = NULL; \ |
| } |
| |
| #define LONG_RESULT_X(n) \ |
| { \ |
| results[n].ret = '?'; \ |
| results[n].flag = 0; \ |
| results[n].arg = NULL; \ |
| } |
| |
| /**************************************************************************** |
| * Private Types |
| ****************************************************************************/ |
| |
| struct result_s |
| { |
| int ret; |
| int flag; |
| FAR char *arg; |
| }; |
| |
| /**************************************************************************** |
| * Private Data |
| ****************************************************************************/ |
| |
| static int g_flag; |
| static const char *g_optstring = "abc::d:"; |
| |
| /**************************************************************************** |
| * Private Functions |
| ****************************************************************************/ |
| |
| static int getopt_short_test(int noptions, int argc, FAR char **argv, |
| FAR const char *optstring, |
| FAR const struct result_s *expected) |
| { |
| int ndx; |
| int ret; |
| |
| optarg = NULL; |
| |
| for (ndx = 0; |
| (ret = getopt(argc, argv, optstring)) != ERROR && ndx < noptions; |
| ndx++) |
| { |
| /* optind may index through argc (to the NULL argv entry) since it is |
| * required to always point to the next command line argument. |
| */ |
| |
| if (optind < 1 || optind > argc) |
| { |
| printf("ERROR: optind=%d\n", optind); |
| ASSERT(false); |
| } |
| |
| /* Parse until getopt(), but do not process anything if ndx exceeds |
| * noptions. |
| */ |
| |
| if (ndx < noptions) |
| { |
| if (expected[ndx].ret != ret) |
| { |
| printf("ERROR: arg %d: ret=%d (expected %d)\n", |
| ndx + 1, ret, expected[ndx].ret); |
| ASSERT(false); |
| } |
| |
| if ((expected[ndx].arg == NULL && |
| optarg != NULL) || |
| (expected[ndx].arg != NULL && |
| strcmp(expected[ndx].arg, optarg) != 0)) |
| { |
| printf("ERROR: arg %d: optarg=%s (expected %s)\n", |
| ndx + 1, optarg == NULL ? "null" : optarg, |
| expected[ndx].arg == NULL ? "null" : |
| expected[ndx].arg); |
| ASSERT(false); |
| } |
| } |
| |
| optarg = NULL; |
| } |
| |
| /* Verify the number of options. Some tests have and extra value at the |
| * end of the command line after the options. |
| */ |
| |
| if (ndx != noptions && ndx != noptions + 1) |
| { |
| printf("ERROR: ndx=%d (expected %d)\n", ndx, noptions); |
| ASSERT(false); |
| } |
| |
| return OK; |
| } |
| |
| static int getopt_long_test(int noptions, int argc, FAR char **argv, |
| FAR const char *optstring, |
| FAR const struct option *longopts, |
| FAR int *longindex, |
| FAR const struct result_s *expected) |
| { |
| int ndx; |
| int ret; |
| |
| optarg = NULL; |
| g_flag = 0; |
| |
| for (ndx = 0; |
| (ret = getopt_long(argc, argv, optstring, longopts, |
| longindex)) != ERROR; |
| ndx++) |
| { |
| /* optind may index through argc (to the NULL argv entry) since it is |
| * required to always point to the next command line argument. |
| */ |
| |
| if (optind < 1 || optind > argc) |
| { |
| printf("ERROR: optind=%d\n", optind); |
| ASSERT(false); |
| } |
| |
| /* Parse until getop_long(), but do not process anything if ndx exceeds |
| * noptions. |
| */ |
| |
| if (ndx < noptions) |
| { |
| if (expected[ndx].ret != ret) |
| { |
| printf("ERROR: arg %d: ret=%d (expected %d)\n", |
| ndx + 1, ret, expected[ndx].ret); |
| ASSERT(false); |
| } |
| |
| if (expected[ndx].flag != g_flag) |
| { |
| printf("ERROR: arg %d; flag=%d (expected %d)\n", |
| ndx + 1, expected[ndx].flag, g_flag); |
| ASSERT(false); |
| } |
| |
| if ((expected[ndx].arg == NULL && |
| optarg != NULL) || |
| (expected[ndx].arg != NULL && |
| strcmp(expected[ndx].arg, optarg) != 0)) |
| { |
| printf("ERROR: arg %d: optarg=%s (expected %s)\n", |
| ndx + 1, optarg == NULL ? "null" : optarg, |
| expected[ndx].arg == NULL ? "null" : |
| expected[ndx].arg); |
| ASSERT(false); |
| } |
| } |
| |
| optarg = NULL; |
| g_flag = 0; |
| } |
| |
| /* Verify the number of options. Some tests have and extra value at the |
| * end of the command line after the options. |
| */ |
| |
| if (ndx != noptions && ndx != noptions + 1) |
| { |
| printf("ERROR: ndx=%d (expected %d)\n", ndx, noptions); |
| ASSERT(false); |
| } |
| |
| return OK; |
| } |
| |
| static int getopt_longonly_test(int noptions, int argc, FAR char **argv, |
| FAR const char *optstring, |
| FAR const struct option *longopts, |
| FAR int *longindex, |
| FAR const struct result_s *expected) |
| { |
| int ndx; |
| int ret; |
| |
| optarg = NULL; |
| g_flag = 0; |
| |
| for (ndx = 0; |
| (ret = getopt_long_only(argc, argv, optstring, longopts, |
| longindex)) != ERROR; |
| ndx++) |
| { |
| /* optind may index through argc (to the NULL argv entry) since it is |
| * required to always point to the next command line argument. |
| */ |
| |
| if (optind < 1 || optind > argc) |
| { |
| printf("ERROR: optind=%d\n", optind); |
| ASSERT(false); |
| } |
| |
| /* Parse until getop_long(), but do not process anything if ndx exceeds |
| * noptions. |
| */ |
| |
| if (ndx < noptions) |
| { |
| if (expected[ndx].ret != ret) |
| { |
| printf("ERROR: arg %d: ret=%d (expected %d)\n", |
| ndx + 1, ret, expected[ndx].ret); |
| ASSERT(false); |
| } |
| |
| if (expected[ndx].flag != g_flag) |
| { |
| printf("ERROR: arg %d; flag=%d (expected %d)\n", |
| ndx + 1, expected[ndx].flag, g_flag); |
| ASSERT(false); |
| } |
| |
| if ((expected[ndx].arg == NULL && |
| optarg != NULL) || |
| (expected[ndx].arg != NULL && |
| strcmp(expected[ndx].arg, optarg) != 0)) |
| { |
| printf("ERROR: arg %d: optarg=%s (expected %s)\n", |
| ndx + 1, optarg == NULL ? "null" : optarg, |
| expected[ndx].arg == NULL ? "null" : |
| expected[ndx].arg); |
| ASSERT(false); |
| } |
| } |
| |
| optarg = NULL; |
| g_flag = 0; |
| } |
| |
| /* Verify the number of options. Some tests have and extra value at the |
| * end of the command line after the options. |
| */ |
| |
| if (ndx != noptions && ndx != noptions + 1) |
| { |
| printf("ERROR: ndx=%d (expected %d)\n", ndx, noptions); |
| ASSERT(false); |
| } |
| |
| return OK; |
| } |
| |
| /**************************************************************************** |
| * Public Functions |
| ****************************************************************************/ |
| |
| int getopt_test(void) |
| { |
| struct option long_options[5]; |
| struct result_s results[5]; |
| FAR char *argv[10]; |
| |
| printf("getopt(): Simple test\n"); |
| |
| argv[0] = NULL; |
| argv[1] = "-a"; |
| argv[2] = "-b"; |
| argv[3] = "-c"; |
| argv[4] = "Arg1"; |
| argv[5] = "-d"; |
| argv[6] = "Arg2"; |
| argv[7] = "NoOption"; |
| argv[8] = NULL; |
| |
| SHORT_RESULT_A(0); |
| SHORT_RESULT_B(1); |
| SHORT_RESULT_C1(2); |
| SHORT_RESULT_D(3); |
| |
| getopt_short_test(4, 8, argv, g_optstring, results); |
| |
| printf("getopt(): Invalid argument\n"); |
| |
| argv[0] = NULL; |
| argv[1] = "-a"; |
| argv[2] = "-b"; |
| argv[3] = "-c"; |
| argv[4] = "Arg1"; |
| argv[5] = "-d"; |
| argv[6] = "Arg2"; |
| argv[7] = "-x"; |
| argv[8] = "NoOption"; |
| argv[9] = NULL; |
| |
| SHORT_RESULT_A(0); |
| SHORT_RESULT_B(1); |
| SHORT_RESULT_C1(2); |
| SHORT_RESULT_D(3); |
| SHORT_RESULT_X(4); |
| |
| getopt_short_test(5, 9, argv, g_optstring, results); |
| |
| argv[8] = NULL; |
| getopt_short_test(5, 8, argv, g_optstring, results); |
| |
| printf("getopt(): Missing optional argument\n"); |
| |
| argv[0] = NULL; |
| argv[1] = "-a"; |
| argv[2] = "-b"; |
| argv[3] = "-c"; |
| argv[4] = "-d"; |
| argv[5] = "Arg2"; |
| argv[6] = "NoOption"; |
| argv[7] = NULL; |
| |
| SHORT_RESULT_A(0); |
| SHORT_RESULT_B(1); |
| SHORT_RESULT_C2(2); |
| SHORT_RESULT_D(3); |
| |
| getopt_short_test(4, 7, argv, g_optstring, results); |
| |
| printf("getopt_long(): Simple test\n"); |
| |
| argv[0] = NULL; |
| argv[1] = "--OptionA"; |
| argv[2] = "--OptionB"; |
| argv[3] = "--OptionC"; |
| argv[4] = "Arg1"; |
| argv[5] = "--OptionD"; |
| argv[6] = "Arg2"; |
| argv[7] = "NoOption"; |
| argv[8] = NULL; |
| |
| LONG_OPTION_A(0); |
| LONG_OPTION_B(1); |
| LONG_OPTION_C(2); |
| LONG_OPTION_D(3); |
| LONG_OPTION_END(4) |
| |
| LONG_RESULT_A(0); |
| LONG_RESULT_B(1); |
| LONG_RESULT_C(2); |
| LONG_RESULT_D1(3); |
| |
| getopt_long_test(4, 8, argv, g_optstring, long_options, NULL, |
| results); |
| |
| printf("getopt_long(): No short options\n"); |
| |
| getopt_long_test(4, 8, argv, NULL, long_options, NULL, |
| results); |
| |
| printf("getopt_long(): Argument for --option=argument\n"); |
| |
| argv[0] = NULL; |
| argv[1] = "--OptionA"; |
| argv[2] = "--OptionB"; |
| argv[3] = "--OptionC=Arg1"; |
| argv[4] = "--OptionD=Arg2"; |
| argv[5] = "NoOption"; |
| argv[6] = NULL; |
| |
| LONG_OPTION_A(0); |
| LONG_OPTION_B(1); |
| LONG_OPTION_C(2); |
| LONG_OPTION_D(3); |
| LONG_OPTION_END(4) |
| |
| LONG_RESULT_A(0); |
| LONG_RESULT_B(1); |
| LONG_RESULT_C(2); |
| LONG_RESULT_D1(3); |
| |
| getopt_long_test(4, 6, argv, g_optstring, long_options, NULL, |
| results); |
| |
| printf("getopt_long(): Invalid long option\n"); |
| |
| argv[0] = NULL; |
| argv[1] = "--OptionA"; |
| argv[2] = "--OptionB"; |
| argv[3] = "--OptionC"; |
| argv[4] = "Arg1"; |
| argv[5] = "--OptionD"; |
| argv[6] = "Arg2"; |
| argv[7] = "--OptionX"; |
| argv[8] = "NoOption"; |
| argv[9] = NULL; |
| |
| LONG_OPTION_A(0); |
| LONG_OPTION_B(1); |
| LONG_OPTION_C(2); |
| LONG_OPTION_D(3); |
| LONG_OPTION_END(4) |
| |
| LONG_RESULT_A(0); |
| LONG_RESULT_B(1); |
| LONG_RESULT_C(2); |
| LONG_RESULT_D1(3); |
| LONG_RESULT_X(4); |
| |
| getopt_long_test(5, 9, argv, g_optstring, long_options, NULL, |
| results); |
| |
| argv[8] = NULL; |
| getopt_long_test(5, 8, argv, g_optstring, long_options, NULL, |
| results); |
| |
| printf("getopt_long(): Mixed long and short options\n"); |
| |
| argv[0] = NULL; |
| argv[1] = "--OptionA"; |
| argv[2] = "-b"; |
| argv[3] = "--OptionC"; |
| argv[4] = "Arg1"; |
| argv[5] = "-d"; |
| argv[6] = "Arg2"; |
| argv[7] = "NoOption"; |
| argv[8] = NULL; |
| |
| LONG_OPTION_A(0); |
| LONG_OPTION_C(1); |
| LONG_OPTION_END(2) |
| |
| LONG_RESULT_A(0); |
| SHORT_RESULT_B(1); |
| LONG_RESULT_C(2); |
| SHORT_RESULT_D(3); |
| |
| getopt_long_test(4, 8, argv, g_optstring, long_options, NULL, |
| results); |
| |
| printf("getopt_long(): Invalid short option\n"); |
| |
| argv[0] = NULL; |
| argv[1] = "--OptionA"; |
| argv[2] = "--OptionB"; |
| argv[3] = "--OptionC"; |
| argv[4] = "Arg1"; |
| argv[5] = "--OptionD"; |
| argv[6] = "Arg2"; |
| argv[7] = "-x"; |
| argv[8] = "NoOption"; |
| argv[9] = NULL; |
| |
| LONG_OPTION_A(0); |
| LONG_OPTION_B(1); |
| LONG_OPTION_C(2); |
| LONG_OPTION_D(3); |
| LONG_OPTION_END(4) |
| |
| LONG_RESULT_A(0); |
| LONG_RESULT_B(1); |
| LONG_RESULT_C(2); |
| LONG_RESULT_D1(3); |
| SHORT_RESULT_X(4); |
| |
| getopt_long_test(5, 9, argv, g_optstring, long_options, NULL, |
| results); |
| |
| printf("getopt_long(): Missing optional arguments\n"); |
| |
| argv[0] = NULL; |
| argv[1] = "--OptionA"; |
| argv[2] = "--OptionB"; |
| argv[3] = "-c"; |
| argv[4] = "--OptionD"; |
| argv[5] = NULL; |
| |
| LONG_OPTION_A(0); |
| LONG_OPTION_B(1); |
| LONG_OPTION_D(2); |
| LONG_OPTION_END(3) |
| |
| LONG_RESULT_A(0); |
| LONG_RESULT_B(1); |
| SHORT_RESULT_C2(2); |
| LONG_RESULT_D2(3); |
| |
| getopt_long_test(4, 6, argv, g_optstring, long_options, NULL, |
| results); |
| |
| printf("getopt_long_only(): Mixed long and short options\n"); |
| |
| argv[0] = NULL; |
| argv[1] = "-a"; |
| argv[2] = "--OptionB"; |
| argv[3] = "-c"; |
| argv[4] = "Arg1"; |
| argv[5] = "--OptionD"; |
| argv[6] = "Arg2"; |
| argv[7] = "NoOption"; |
| argv[8] = NULL; |
| |
| LONG_OPTION_B(0); |
| LONG_OPTION_D(1); |
| LONG_OPTION_END(2) |
| |
| SHORT_RESULT_A(0); |
| LONG_RESULT_B(1); |
| SHORT_RESULT_C1(2); |
| LONG_RESULT_D1(3); |
| |
| getopt_longonly_test(4, 8, argv, g_optstring, long_options, NULL, |
| results); |
| |
| printf("getopt_long_only(): Single hyphen long options\n"); |
| |
| argv[0] = NULL; |
| argv[1] = "-OptionA"; |
| argv[2] = "-b"; |
| argv[3] = "--OptionC"; |
| argv[4] = "Arg1"; |
| argv[5] = "-d"; |
| argv[6] = "Arg2"; |
| argv[7] = "NoOption"; |
| argv[8] = NULL; |
| |
| LONG_OPTION_A(0); |
| LONG_OPTION_C(1); |
| LONG_OPTION_END(2) |
| |
| LONG_RESULT_A(0); |
| SHORT_RESULT_B(1); |
| LONG_RESULT_C(2); |
| SHORT_RESULT_D(3); |
| |
| getopt_longonly_test(4, 8, argv, g_optstring, long_options, NULL, |
| results); |
| return OK; |
| } |