diff --git a/ChangeLog b/ChangeLog index e40f8dc3d3..d529be2e1d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -182,5 +182,7 @@ * tools/mkdeps.sh & arch/arm/src/Makefile: Corrected a problem makeing dependencies * tools/zipme.sh: Force directory name to be nuttx-xx.yy.zz * fs/fs_opendir.c: Correct errors in semaphore usage that can cause deadlock. + * lib/lib_getopt.c: Added getopt() support + * examples/nsh: NSH now supports mount, umount, and mkdir. * Started m68322 diff --git a/Documentation/NuttX.html b/Documentation/NuttX.html index 9e4ca3b7d6..13d8507367 100644 --- a/Documentation/NuttX.html +++ b/Documentation/NuttX.html @@ -617,6 +617,8 @@ Other memory: * tools/mkdeps.sh & arch/arm/src/Makefile: Corrected a problem makeing dependencies * tools/zipme.sh: Force directory name to be nuttx-xx.yy.zz * fs/fs_opendir.c: Correct errors in semaphore usage that can cause deadlock. + * lib/lib_getopt.c: Added getopt() support + * examples/nsh: NSH now supports mount, umount, and mkdir. * Started m68322 diff --git a/include/unistd.h b/include/unistd.h index 4e843c5ebb..03f617b6c1 100644 --- a/include/unistd.h +++ b/include/unistd.h @@ -97,7 +97,7 @@ #define fdatasync(f) fsync(f) /************************************************************ - * Global Function Prototypes + * Global Variables ************************************************************/ #undef EXTERN @@ -108,6 +108,16 @@ extern "C" { #define EXTERN extern #endif +/* Used by getopt (obviously NOT thread safe!) */ + +EXTERN char *optarg; /* Optional argument following option */ +EXTERN int optind; /* Index into argv */ +EXTERN int optopt; /* unrecognized option character */ + +/************************************************************ + * Global Function Prototypes + ************************************************************/ + /* Task Control Interfaces */ EXTERN pid_t getpid(void); @@ -131,6 +141,10 @@ EXTERN int write(int fd, const void *buf, unsigned int nbytes); EXTERN int unlink(const char *pathname); EXTERN int rmdir(const char *pathname); +/* Other */ + +EXTERN int getopt(int argc, char *const argv[], const char *optstring); + #undef EXTERN #if defined(__cplusplus) } diff --git a/lib/Makefile b/lib/Makefile index d13cc7b1e3..107ab055ca 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -74,6 +74,8 @@ STDLIB_SRCS = lib_getenv.c lib_rand.c MATH_SRCS = lib_rint.c +UNISTD_SRCS = lib_getopt.c + SQ_SRCS = sq_addlast.c sq_addfirst.c sq_addafter.c \ sq_rem.c sq_remlast.c sq_remfirst.c sq_remafter.c @@ -81,7 +83,7 @@ DQ_SRCS = dq_addlast.c dq_addfirst.c dq_addafter.c dq_addbefore.c \ dq_rem.c dq_remlast.c dq_remfirst.c CSRCS = $(MISC_SRCS) $(STRING_SRCS) $(CTYPE_SRCS) $(STDIO_SRCS) \ - $(STDLIB_SRCS) $(MATH_SRCS) $(SQ_SRCS) $(DQ_SRCS) + $(STDLIB_SRCS) $(MATH_SRCS) $(UNISTD_SRCS) $(SQ_SRCS) $(DQ_SRCS) COBJS = $(CSRCS:.c=$(OBJEXT)) SRCS = $(ASRCS) $(CSRCS) diff --git a/lib/lib_getopt.c b/lib/lib_getopt.c new file mode 100644 index 0000000000..21b7b1acaf --- /dev/null +++ b/lib/lib_getopt.c @@ -0,0 +1,259 @@ +/**************************************************************************** + * lib_getopt.c + * + * Copyright (C) 2007 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name Gregory Nutt nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include + +/**************************************************************************** + * Global Variables + ****************************************************************************/ + +char *optarg; /* Optional argument following option */ +int optind = 1; /* Index into argv */ +int optopt = '?'; /* unrecognized option character */ + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +static char *g_optptr = NULL; +static boolean g_binitialized = FALSE; + +/**************************************************************************** + * Global Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: Name + * + * Description: getopt() parses command-line arguments. Its arguments argc + * and argv are the argument count and array as passed to the main() + * function on program invocation. An element of argv that starts with + * '-' is an option element. The characters of this element (aside from + * the initial '-') are option characters. If getopt() is called repeatedly, + * it returns successively each of the option characters from each of the + * option elements. + * + * If getopt() finds another option character, it returns that character, + * updating the external variable optind and a static variable nextchar so + * that the next call to getopt() can resume the scan with the following + * option character or argv-element. + * + * If there are no more option characters, getopt() returns -1. Then optind + * is the index in argv of the first argv-element that is not an option. + * + * The 'optstring argument is a string containing the legitimate option + * characters. If such a character is followed by a colon, this indicates + * that the option requires an argument. If an argument is required for an + * option so getopt() places a pointer to the following text in the same + * argv-element, or the text of the following argv-element, in optarg. + * + * NOTES: + * 1. opterr is not supported and this implementation of getopt() never + * printfs error messages. + * 2. getopt is NOT threadsafe! + * + * Return: If an option was successfully found, then getopt() returns the + * option character. If all command-line options have been parsed, then + * getopt() returns -1. If getopt() encounters an option character that + * was not in optstring, then '?' is returned. If getopt() encounters an + * option with a missing argument, then the return value depends on the + * first character in optstring: if it is ':', then ':' is returned; + * otherwise '?' is returned. + * + ****************************************************************************/ + +int getopt(int argc, char *const argv[], const char *optstring) +{ + if (argv && optstring) + { + int noarg_ret = '?'; + char *optchar; + + /* The inital value of optind is 1. If getopt() is called again in the + * program, optind must be reset to some value <= 1. + */ + + if (optind < 1 || !g_binitialized) + { + optind = 1; /* Skip over the program name */ + g_optptr = NULL; /* Start at the beginning of the first argument */ + g_binitialized = TRUE; /* Now we are initialized */ + } + + /* If the first character of opstring s ':', then ':' is in the event of + * a missing argument. Otherwise '?' is returned. + */ + + if (*optstring == ':') + { + noarg_ret = ':'; + optstring++; + } + + /* Are we resuming in the middle, or at the end of a string of arguments? + * g_optptr == NULL means that we are started at the beginning of argv[optind]; + * *g_optptr == means that we are starting at the beginning of optind+1 + */ + + while (!g_optptr || !*g_optptr) + { + /* We need to start at the beginning of the next argv. Check if we need + * to increment optind + */ + + if (g_optptr) + { + /* Yes.. Increment it and check for the case where where we have + * processed everything in the argv[] array. + */ + + optind++; + if (!argv[optind]) + { + /* There are no more arguments, we are finished */ + + g_optptr = NULL; + g_binitialized = FALSE; + + /* Return -1 with optind == all of the arguments */ + + return ERROR; + } + } + + /* We are starting at the beginning of argv[optind]. In this case, the + * first character must be '-' + */ + + g_optptr = argv[optind]; + if (*g_optptr != '-') + { + /* The argument does not start with '-', we are finished */ + + g_optptr = NULL; + g_binitialized = FALSE; + + /* Return the -1 with optind set to the non-option argument */ + + return ERROR; + } + + /* Skip over the '-' */ + + g_optptr++; + } + + /* Special case handling of "-" and "-:" */ + + if (!*g_optptr) + { + optopt = '\0'; /* We'll fix up g_optptr the next time we are called */ + return '?'; + } + + /* Handle the case of "-:" */ + + if (*g_optptr == ':') + { + optopt = ':'; + g_optptr++; + return '?'; + } + + /* g_optptr now points at the next option and it is not something crazy. + * check if the option is in the list of valid options. + */ + + optchar = strchr(optstring, *g_optptr); + if (!optchar) + { + /* No this character is not in the list of valid options */ + + optopt = *g_optptr; + g_optptr++; + return '?'; + } + + /* Yes, the character is in the list of valid options. Does it have an + * required argument? + */ + + if (optchar[1] != ':') + { + /* No, just return the character that we found */ + + g_optptr++; + return *optchar; + } + + /* Yes. Is the required argument after the command in this same argument? */ + + if (g_optptr[1] != '\0') + { + /* Yes, return a pointer into the current argument */ + + optarg = &g_optptr[1]; + optind++; + g_optptr = NULL; + return *optchar; + } + + /* No.. is the optional argument the next argument in argv[] ? */ + if (argv[optind+1] && *argv[optind+1] != '-') + { + /* Yes.. retun that */ + optarg = argv[optind+1]; + optind += 2; + g_optptr = NULL; + return *optchar; + } + + /* No argument was supplied */ + optarg = NULL; + optopt = *optchar; + optind++; + return noarg_ret; + } + + optind = 1; + return ERROR; +}