Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / src / core / getopt.c
diff --git a/qemu/roms/ipxe/src/core/getopt.c b/qemu/roms/ipxe/src/core/getopt.c
new file mode 100644 (file)
index 0000000..abc1edd
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program 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 of the
+ * License, or any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <getopt.h>
+
+/** @file
+ *
+ * Parse command-line options
+ *
+ */
+
+/**
+ * Option argument
+ *
+ * This will point to the argument for the most recently returned
+ * option, if applicable.
+ */
+char *optarg;
+
+/**
+ * Current option index
+ *
+ * This is an index into the argv[] array.  When getopt() returns -1,
+ * @c optind is the index to the first element that is not an option.
+ */
+int optind;
+
+/**
+ * Current option character index
+ *
+ * This is an index into the current element of argv[].
+ */
+int nextchar;
+
+/**
+ * Unrecognised option
+ *
+ * When an unrecognised option is encountered, the actual option
+ * character is stored in @c optopt.
+ */
+int optopt;
+
+/**
+ * Get option argument from argv[] array
+ *
+ * @v argc             Argument count
+ * @v argv             Argument list
+ * @ret argument       Option argument, or NULL
+ *
+ * Grab the next element of argv[], if it exists and is not an option.
+ */
+static const char * get_argv_argument ( int argc, char * const argv[] ) {
+       char *arg;
+
+       /* Don't overrun argv[] */
+       if ( optind >= argc )
+               return NULL;
+       arg = argv[optind];
+
+       /* If next argv element is an option, then it's not usable as
+        * an argument.
+        */
+       if ( *arg == '-' )
+               return NULL;
+
+       /** Consume this argv element, and return it */
+       optind++;
+       return arg;
+}
+
+/**
+ * Match long option
+ *
+ * @v argc             Argument count
+ * @v argv             Argument list
+ * @v opttext          Option text within current argv[] element
+ * @v longopt          Long option specification
+ * @ret option         Option to return from getopt()
+ * @ret matched                Found a match for this long option
+ */
+static int match_long_option ( int argc, char * const argv[],
+                              const char *opttext,
+                              const struct option *longopt, int *option ) {
+       size_t optlen;
+       const char *argument = NULL;
+
+       /* Compare option name */
+       optlen = strlen ( longopt->name );
+       if ( strncmp ( opttext, longopt->name, optlen ) != 0 )
+               return 0;
+
+       /* Check for inline argument */
+       if ( opttext[optlen] == '=' ) {
+               argument = &opttext[ optlen + 1 ];
+       } else if ( opttext[optlen] ) {
+               /* Long option with trailing garbage - no match */
+               return 0;
+       }
+
+       /* Consume this argv element */
+       optind++;
+
+       /* If we want an argument but don't have one yet, try to grab
+        * the next argv element
+        */
+       if ( ( longopt->has_arg != no_argument ) && ( ! argument ) )
+               argument = get_argv_argument ( argc, argv );
+
+       /* If we need an argument but don't have one, sulk */
+       if ( ( longopt->has_arg == required_argument ) && ( ! argument ) ) {
+               printf ( "Option \"%s\" requires an argument\n",
+                        longopt->name );
+               *option = ':';
+               return 1;
+       }
+
+       /* If we have an argument where we shouldn't have one, sulk */
+       if ( ( longopt->has_arg == no_argument ) && argument ) {
+               printf ( "Option \"%s\" takes no argument\n", longopt->name );
+               *option = ':';
+               return 1;
+       }
+
+       /* Store values and return success */
+       optarg = ( char * ) argument;
+       if ( longopt->flag ) {
+               *(longopt->flag) = longopt->val;
+               *option = 0;
+       } else {
+               *option = longopt->val;
+       }
+       return 1;
+}
+
+/**
+ * Match short option
+ *
+ * @v argc             Argument count
+ * @v argv             Argument list
+ * @v opttext          Option text within current argv[] element
+ * @v shortopt         Option character from option specification
+ * @ret option         Option to return from getopt()
+ * @ret matched                Found a match for this short option
+ */
+static int match_short_option ( int argc, char * const argv[],
+                               const char *opttext, int shortopt,
+                               enum getopt_argument_requirement has_arg,
+                               int *option ) {
+       const char *argument = NULL;
+
+       /* Compare option character */
+       if ( *opttext != shortopt )
+               return 0;
+
+       /* Consume option character */
+       opttext++;
+       nextchar++;
+       if ( *opttext ) {
+               if ( has_arg != no_argument ) {
+                       /* Consume remainder of element as inline argument */
+                       argument = opttext;
+                       optind++;
+                       nextchar = 0;
+               }
+       } else {
+               /* Reached end of argv element */
+               optind++;
+               nextchar = 0;
+       }
+
+       /* If we want an argument but don't have one yet, try to grab
+        * the next argv element
+        */
+       if ( ( has_arg != no_argument ) && ( ! argument ) )
+               argument = get_argv_argument ( argc, argv );
+
+       /* If we need an argument but don't have one, sulk */
+       if ( ( has_arg == required_argument ) && ( ! argument ) ) {
+               printf ( "Option \"%c\" requires an argument\n", shortopt );
+               *option = ':';
+               return 1;
+       }
+
+       /* Store values and return success */
+       optarg = ( char * ) argument;
+       *option = shortopt;
+       return 1;
+}
+
+/**
+ * Parse command-line options
+ *
+ * @v argc             Argument count
+ * @v argv             Argument list
+ * @v optstring                Option specification string
+ * @v longopts         Long option specification table
+ * @ret longindex      Index of long option (or NULL)
+ * @ret option         Option found, or -1 for no more options
+ *
+ * Note that the caller must arrange for reset_getopt() to be called
+ * before each set of calls to getopt_long().  In Etherboot, this is
+ * done automatically by execv().
+ */
+int getopt_long ( int argc, char * const argv[], const char *optstring,
+                 const struct option *longopts, int *longindex ) {
+       const char *opttext = argv[optind];
+       const struct option *longopt;
+       int shortopt;
+       enum getopt_argument_requirement has_arg;
+       int option;
+
+       /* Check for end of argv array */
+       if ( optind >= argc )
+               return -1;
+
+       /* Check for end of options */
+       if ( *(opttext++) != '-' )
+               return -1;
+
+       /* Check for long options */
+       if ( *(opttext++) == '-' ) {
+               /* "--" indicates end of options */
+               if ( *opttext == '\0' ) {
+                       optind++;
+                       return -1;
+               }
+               for ( longopt = longopts ; longopt->name ; longopt++ ) {
+                       if ( ! match_long_option ( argc, argv, opttext,
+                                                  longopt, &option ) )
+                               continue;
+                       if ( longindex )
+                               *longindex = ( longopt - longopts );
+                       return option;
+               }
+               optopt = '?';
+               printf ( "Unrecognised option \"--%s\"\n", opttext );
+               return '?';
+       }
+
+       /* Check for short options */
+       if ( nextchar < 1 )
+               nextchar = 1;
+       opttext = ( argv[optind] + nextchar );
+       while ( ( shortopt = *(optstring++) ) ) {
+               has_arg = no_argument;
+               while ( *optstring == ':' ) {
+                       has_arg++;
+                       optstring++;
+               }
+               if ( match_short_option ( argc, argv, opttext, shortopt,
+                                         has_arg, &option ) ) {
+                       return option;
+               }
+       }
+       optopt = *opttext;
+       printf ( "Unrecognised option \"-%c\"\n", optopt );
+       return '?';
+}