nuttx-apps/testing/ostest/getopt.c

684 lines
16 KiB
C
Raw Normal View History

/****************************************************************************
* 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"
/****************************************************************************
2022-01-05 16:34:05 +01:00
* 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;
}