diff --git a/include/unistd.h b/include/unistd.h index c719ff9f952ec..e57ab2854f1b1 100644 --- a/include/unistd.h +++ b/include/unistd.h @@ -289,12 +289,19 @@ #define getdtablesize(f) ((int)sysconf(_SC_OPEN_MAX)) #define getpagesize(f) ((int)sysconf(_SC_PAGESIZE)) -/* Accessor functions associated with getopt(). */ +/* Accessor functions associated with getopt(). In the user space of a + * kernel build every process has its own copy of the C library data, so + * optarg, opterr, optind and optopt are the plain variables that POSIX + * specifies (see below). Programs that bring their own getopt() depend + * on that. + */ -#define optarg (*(getoptargp())) -#define opterr (*(getopterrp())) -#define optind (*(getoptindp())) -#define optopt (*(getoptoptp())) +#if !defined(CONFIG_BUILD_KERNEL) || defined(__KERNEL__) +# define optarg (*(getoptargp())) +# define opterr (*(getopterrp())) +# define optind (*(getoptindp())) +# define optopt (*(getoptoptp())) +#endif #if defined(CONFIG_FS_LARGEFILE) # define lseek64 lseek @@ -481,6 +488,13 @@ FAR int *getopterrp(void); /* Print error message */ FAR int *getoptindp(void); /* Index into argv */ FAR int *getoptoptp(void); /* Unrecognized option character */ +#if defined(CONFIG_BUILD_KERNEL) && !defined(__KERNEL__) +EXTERN FAR char *optarg; /* Optional argument following option */ +EXTERN int opterr; /* Print error message */ +EXTERN int optind; /* Index into argv */ +EXTERN int optopt; /* Unrecognized option character */ +#endif + int gethostname(FAR char *name, size_t namelen); int sethostname(FAR const char *name, size_t namelen); diff --git a/libs/libc/unistd/CMakeLists.txt b/libs/libc/unistd/CMakeLists.txt index 7d1b146143987..a6de4511dc8b4 100644 --- a/libs/libc/unistd/CMakeLists.txt +++ b/libs/libc/unistd/CMakeLists.txt @@ -37,6 +37,7 @@ set(SRCS lib_getopterrp.c lib_getoptindp.c lib_getoptoptp.c + lib_getoptpublic.c lib_times.c lib_alarm.c lib_fstatvfs.c diff --git a/libs/libc/unistd/Make.defs b/libs/libc/unistd/Make.defs index c4a582292f404..d1b4c193176af 100644 --- a/libs/libc/unistd/Make.defs +++ b/libs/libc/unistd/Make.defs @@ -25,7 +25,7 @@ CSRCS += lib_access.c lib_daemon.c lib_swab.c lib_pathconf.c lib_sysconf.c CSRCS += lib_getcwd.c lib_getentropy.c lib_getopt_common.c lib_getopt.c CSRCS += lib_getopt_long.c lib_getopt_longonly.c lib_getoptvars.c lib_getoptargp.c -CSRCS += lib_getopterrp.c lib_getoptindp.c lib_getoptoptp.c lib_times.c +CSRCS += lib_getopterrp.c lib_getoptindp.c lib_getoptoptp.c lib_getoptpublic.c lib_times.c CSRCS += lib_alarm.c lib_fstatvfs.c lib_statvfs.c lib_sleep.c lib_nice.c CSRCS += lib_getrusage.c lib_utime.c lib_utimes.c CSRCS += lib_setrlimit.c lib_getrlimit.c lib_setpriority.c lib_getpriority.c diff --git a/libs/libc/unistd/lib_getopt_common.c b/libs/libc/unistd/lib_getopt_common.c index 404c27e577f38..d8a9eca7f8fbc 100644 --- a/libs/libc/unistd/lib_getopt_common.c +++ b/libs/libc/unistd/lib_getopt_common.c @@ -167,20 +167,20 @@ static int getopt_long_option(FAR struct getopt_s *go, { FAR char *next; - case no_argument: - /* No, no arguments. Just return the argument that we - * found. - */ + /* No, no arguments. Just return the argument that we + * found. + */ + case no_argument: go->go_optptr = NULL; go->go_optind++; break; - case optional_argument: - /* Check if there is a following argument and if that - * following argument is another option. - */ + /* Check if there is a following argument and if that + * following argument is another option. + */ + case optional_argument: next = argv[go->go_optind + 1]; if (next == NULL || next[0] == '-') { @@ -334,17 +334,26 @@ static int getopt_long_option(FAR struct getopt_s *go, * ****************************************************************************/ +#ifdef GETOPT_PUBLIC_VARIABLES +static int getopt_internal(int argc, FAR char * const argv[], + FAR const char *optstring, + FAR const struct option *longopts, + FAR int *longindex, + enum getopt_mode_e mode) +#else int getopt_common(int argc, FAR char * const argv[], FAR const char *optstring, FAR const struct option *longopts, FAR int *longindex, enum getopt_mode_e mode) +#endif { int ret; /* Get thread-specific getopt() variables */ FAR struct getopt_s *go = getoptvars(); + if (go == NULL) { return '?'; @@ -640,3 +649,31 @@ int getopt_common(int argc, FAR char * const argv[], go->go_binitialized = false; return ERROR; } + +#ifdef GETOPT_PUBLIC_VARIABLES +int getopt_common(int argc, FAR char * const argv[], + FAR const char *optstring, + FAR const struct option *longopts, + FAR int *longindex, + enum getopt_mode_e mode) +{ + FAR struct getopt_s *go = getoptvars(); + int ret; + + /* The program may have set optind (to restart) or opterr */ + + go->go_optarg = optarg; + go->go_opterr = opterr; + go->go_optind = optind; + go->go_optopt = optopt; + + ret = getopt_internal(argc, argv, optstring, longopts, longindex, mode); + + optarg = go->go_optarg; + opterr = go->go_opterr; + optind = go->go_optind; + optopt = go->go_optopt; + + return ret; +} +#endif diff --git a/libs/libc/unistd/lib_getoptargp.c b/libs/libc/unistd/lib_getoptargp.c index 02ff2a7c3da12..c26beb4396702 100644 --- a/libs/libc/unistd/lib_getoptargp.c +++ b/libs/libc/unistd/lib_getoptargp.c @@ -43,6 +43,11 @@ FAR char **getoptargp(void) { +#ifdef GETOPT_PUBLIC_VARIABLES + return &optarg; +#else FAR struct getopt_s *go = getoptvars(); + return &go->go_optarg; +#endif } diff --git a/libs/libc/unistd/lib_getopterrp.c b/libs/libc/unistd/lib_getopterrp.c index 9d6f5311b75ce..7474bc426d285 100644 --- a/libs/libc/unistd/lib_getopterrp.c +++ b/libs/libc/unistd/lib_getopterrp.c @@ -43,6 +43,11 @@ FAR int *getopterrp(void) { +#ifdef GETOPT_PUBLIC_VARIABLES + return &opterr; +#else FAR struct getopt_s *go = getoptvars(); + return &go->go_opterr; +#endif } diff --git a/libs/libc/unistd/lib_getoptindp.c b/libs/libc/unistd/lib_getoptindp.c index 596208e4b2272..6693b9fc90404 100644 --- a/libs/libc/unistd/lib_getoptindp.c +++ b/libs/libc/unistd/lib_getoptindp.c @@ -43,6 +43,11 @@ int *getoptindp(void) { +#ifdef GETOPT_PUBLIC_VARIABLES + return &optind; +#else FAR struct getopt_s *go = getoptvars(); + return &go->go_optind; +#endif } diff --git a/libs/libc/unistd/lib_getoptoptp.c b/libs/libc/unistd/lib_getoptoptp.c index fb529330d0db2..daa535366dea8 100644 --- a/libs/libc/unistd/lib_getoptoptp.c +++ b/libs/libc/unistd/lib_getoptoptp.c @@ -43,6 +43,11 @@ int *getoptoptp(void) { +#ifdef GETOPT_PUBLIC_VARIABLES + return &optopt; +#else FAR struct getopt_s *go = getoptvars(); + return &go->go_optopt; +#endif } diff --git a/libs/libc/unistd/lib_getoptpublic.c b/libs/libc/unistd/lib_getoptpublic.c new file mode 100644 index 0000000000000..815191536afd9 --- /dev/null +++ b/libs/libc/unistd/lib_getoptpublic.c @@ -0,0 +1,52 @@ +/**************************************************************************** + * libs/libc/unistd/lib_getoptpublic.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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 + +#include "unistd.h" + +#ifdef GETOPT_PUBLIC_VARIABLES + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* The public getopt() variables of a kernel-build process. They are in a + * file of their own, so that a program that defines its own does not get + * a second definition from the C library. + * getopt_common() copies them to and from its internal state. + */ + +FAR char *optarg; +int opterr = 1; +int optind = 1; +int optopt = '?'; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#endif /* GETOPT_PUBLIC_VARIABLES */ diff --git a/libs/libc/unistd/unistd.h b/libs/libc/unistd/unistd.h index ca2a23eb852f6..f25a569c03d1d 100644 --- a/libs/libc/unistd/unistd.h +++ b/libs/libc/unistd/unistd.h @@ -66,6 +66,14 @@ extern "C" * getopt_long_only() that is being emulated by getopt_common(). */ +/* In the user space of a kernel build, the public getopt() variables are + * plain variables (see include/unistd.h). + */ + +#if defined(CONFIG_BUILD_KERNEL) && !defined(__KERNEL__) +# define GETOPT_PUBLIC_VARIABLES 1 +#endif + enum getopt_mode_e { GETOPT_MODE = 0,