diff options
Diffstat (limited to 'builtins/bashgetopt.c')
-rw-r--r-- | builtins/bashgetopt.c | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/builtins/bashgetopt.c b/builtins/bashgetopt.c new file mode 100644 index 0000000..4c8d907 --- /dev/null +++ b/builtins/bashgetopt.c @@ -0,0 +1,175 @@ +/* bashgetopt.c -- `getopt' for use by the builtins. */ + +/* Copyright (C) 1992-2002 Free Software Foundation, Inc. + +This file is part of GNU Bash, the Bourne Again SHell. + +Bash is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +Bash is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with Bash; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#include <config.h> + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif + +#include "../bashansi.h" +#include <chartypes.h> +#include <errno.h> + +#include "../shell.h" +#include "common.h" + +#define ISOPT(s) (((*(s) == '-') || (plus && *(s) == '+')) && (s)[1]) +#define NOTOPT(s) (((*(s) != '-') && (!plus || *(s) != '+')) || (s)[1] == '\0') + +static int sp; + +char *list_optarg; +int list_optopt; +int list_opttype; + +static WORD_LIST *lhead = (WORD_LIST *)NULL; +WORD_LIST *lcurrent = (WORD_LIST *)NULL; +WORD_LIST *loptend; /* Points to the first non-option argument in the list */ + +int +internal_getopt(list, opts) +WORD_LIST *list; +char *opts; +{ + register int c; + register char *cp; + int plus; /* nonzero means to handle +option */ + static char errstr[3] = { '-', '\0', '\0' }; + + plus = *opts == '+'; + if (plus) + opts++; + + if (list == 0) { + list_optarg = (char *)NULL; + loptend = (WORD_LIST *)NULL; /* No non-option arguments */ + return -1; + } + + if (list != lhead || lhead == 0) { + /* Hmmm.... called with a different word list. Reset. */ + sp = 1; + lcurrent = lhead = list; + loptend = (WORD_LIST *)NULL; + } + + if (sp == 1) { + if (lcurrent == 0 || NOTOPT(lcurrent->word->word)) { + lhead = (WORD_LIST *)NULL; + loptend = lcurrent; + return(-1); + } else if (lcurrent->word->word[0] == '-' && + lcurrent->word->word[1] == '-' && + lcurrent->word->word[2] == 0) { + lhead = (WORD_LIST *)NULL; + loptend = lcurrent->next; + return(-1); + } + errstr[0] = list_opttype = lcurrent->word->word[0]; + } + + list_optopt = c = lcurrent->word->word[sp]; + + if (c == ':' || (cp = strchr(opts, c)) == NULL) { + errstr[1] = c; + sh_invalidopt (errstr); + if (lcurrent->word->word[++sp] == '\0') { + lcurrent = lcurrent->next; + sp = 1; + } + list_optarg = NULL; + if (lcurrent) + loptend = lcurrent->next; + return('?'); + } + + if (*++cp == ':' || *cp == ';') { + /* `:': Option requires an argument. */ + /* `;': option argument may be missing */ + /* We allow -l2 as equivalent to -l 2 */ + if (lcurrent->word->word[sp+1]) { + list_optarg = lcurrent->word->word + sp + 1; + lcurrent = lcurrent->next; + /* If the specifier is `;', don't set optarg if the next + argument looks like another option. */ +#if 0 + } else if (lcurrent->next && (*cp == ':' || lcurrent->next->word->word[0] != '-')) { +#else + } else if (lcurrent->next && (*cp == ':' || NOTOPT(lcurrent->next->word->word))) { +#endif + lcurrent = lcurrent->next; + list_optarg = lcurrent->word->word; + lcurrent = lcurrent->next; + } else if (*cp == ';') { + list_optarg = (char *)NULL; + lcurrent = lcurrent->next; + } else { /* lcurrent->next == NULL */ + errstr[1] = c; + sh_needarg (errstr); + sp = 1; + list_optarg = (char *)NULL; + return('?'); + } + sp = 1; + } else if (*cp == '#') { + /* option requires a numeric argument */ + if (lcurrent->word->word[sp+1]) { + if (DIGIT(lcurrent->word->word[sp+1])) { + list_optarg = lcurrent->word->word + sp + 1; + lcurrent = lcurrent->next; + } else + list_optarg = (char *)NULL; + } else { + if (lcurrent->next && legal_number(lcurrent->next->word->word, (intmax_t *)0)) { + lcurrent = lcurrent->next; + list_optarg = lcurrent->word->word; + lcurrent = lcurrent->next; + } else { + errstr[1] = c; + sh_neednumarg (errstr); + sp = 1; + list_optarg = (char *)NULL; + return ('?'); + } + } + + } else { + /* No argument, just return the option. */ + if (lcurrent->word->word[++sp] == '\0') { + sp = 1; + lcurrent = lcurrent->next; + } + list_optarg = (char *)NULL; + } + + return(c); +} + +/* + * reset_internal_getopt -- force the in[ft]ernal getopt to reset + */ + +void +reset_internal_getopt () +{ + lhead = lcurrent = loptend = (WORD_LIST *)NULL; + sp = 1; +} |