diff --git a/libc/build.mak b/libc/build.mak
index faaf8d38ed80a86add70cdd7f6b676b879c5df07..bbc918196bdcc294112e4291930ba8a829250028 100644
--- a/libc/build.mak
+++ b/libc/build.mak
@@ -1,4 +1,7 @@
-libc = string/strcmp.o
+libc :=
+
+libc += getopt.o
+libc += string/strcmp.o
 libc += string/strcpy.o
 libc += string/strlcpy.o
 libc += string/strlcat.o
diff --git a/libc/getopt.c b/libc/getopt.c
new file mode 100644
index 0000000000000000000000000000000000000000..b2f5778cbfc2a8a97afcad03bc422daed437505b
--- /dev/null
+++ b/libc/getopt.c
@@ -0,0 +1,516 @@
+/****************************************************************************
+
+getopt.c - Read command line options
+
+AUTHOR: Gregory Pietsch
+CREATED Fri Jan 10 21:13:05 1997
+
+DESCRIPTION:
+
+The getopt() function parses the command line arguments.  Its arguments argc
+and argv are the argument count and array as passed to the main() function
+on program invocation.  The argument optstring is a list of available option
+characters.  If such a character is followed by a colon (`:'), the option
+takes an argument, which is placed in optarg.  If such a character is
+followed by two colons, the option takes an optional argument, which is
+placed in optarg.  If the option does not take an argument, optarg is NULL.
+
+The external variable optind is the index of the next array element of argv
+to be processed; it communicates from one call to the next which element to
+process.
+
+The getopt_long() function works like getopt() except that it also accepts
+long options started by two dashes `--'.  If these take values, it is either
+in the form
+
+--arg=value
+
+ or
+
+--arg value
+
+It takes the additional arguments longopts which is a pointer to the first
+element of an array of type struct option.  The last element of the array
+has to be filled with NULL for the name field.
+
+The longind pointer points to the index of the current long option relative
+to longopts if it is non-NULL.
+
+The getopt() function returns the option character if the option was found
+successfully, `:' if there was a missing parameter for one of the options,
+`?' for an unknown option character, and EOF for the end of the option list.
+
+The getopt_long() function's return value is described in the header file.
+
+The function getopt_long_only() is identical to getopt_long(), except that a
+plus sign `+' can introduce long options as well as `--'.
+
+The following describes how to deal with options that follow non-option
+argv-elements.
+
+If the caller did not specify anything, the default is REQUIRE_ORDER if the
+environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+REQUIRE_ORDER means don't recognize them as options; stop option processing
+when the first non-option is seen.  This is what Unix does.  This mode of
+operation is selected by either setting the environment variable
+POSIXLY_CORRECT, or using `+' as the first character of the optstring
+parameter.
+
+PERMUTE is the default.  We permute the contents of ARGV as we scan, so that
+eventually all the non-options are at the end.  This allows options to be
+given in any order, even with programs that were not written to expect this.
+
+RETURN_IN_ORDER is an option available to programs that were written to
+expect options and other argv-elements in any order and that care about the
+ordering of the two.  We describe each non-option argv-element as if it were
+the argument of an option with character code 1.  Using `-' as the first
+character of the optstring parameter selects this mode of operation.
+
+The special argument `--' forces an end of option-scanning regardless of the
+value of ordering.  In the case of RETURN_IN_ORDER, only `--' can cause
+getopt() and friends to return EOF with optind != argc.
+
+2012-08-26: Tried to make the error handling more sus4-like. The functions
+return a colon if getopt() and friends detect a missing argument and the
+first character of shortopts/optstring starts with a colon (`:'). If getopt()
+and friends detect a missing argument and shortopts/optstring does not start
+with a colon, the function returns a question mark (`?'). If it was a missing
+argument to a short option, optopt is set to the character in question. The
+colon goes after the ordering character (`+' or `-').
+
+COPYRIGHT NOTICE AND DISCLAIMER:
+
+Copyright (C) 1997 Gregory Pietsch
+
+This file and the accompanying getopt.h header file are hereby placed in the 
+public domain without restrictions.  Just give the author credit, don't
+claim you wrote it or prevent anyone else from using it.
+
+Gregory Pietsch's current e-mail address:
+gpietsch@comcast.net
+****************************************************************************/
+
+#ifndef HAVE_GETOPT
+
+/* include files */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define __need_getopt_newlib
+#include <getopt.h>
+  
+typedef struct getopt_data
+{
+  char *optarg;
+  int optind, opterr, optopt, optwhere;
+} getopt_data;
+
+/* macros */
+  
+/* macros defined by this include file */
+#define NO_ARG          	no_argument
+#define REQUIRED_ARG    	required_argument
+#define OPTIONAL_ARG    	optional_argument
+
+/* The GETOPT_DATA_INITIALIZER macro is used to initialize a statically-
+   allocated variable of type struct getopt_data.  */
+#define GETOPT_DATA_INITIALIZER	{0,0,0,0,0}
+
+/* types */
+typedef enum GETOPT_ORDERING_T
+{
+  PERMUTE,
+  RETURN_IN_ORDER,
+  REQUIRE_ORDER
+} GETOPT_ORDERING_T;
+
+/* globally-defined variables */
+char *optarg = 0;
+int optind = 0;
+int opterr = 1;
+int optopt = '?';
+
+/* static variables */
+static int optwhere = 0;
+
+/* functions */
+
+/* reverse_argv_elements:  reverses num elements starting at argv */
+static void
+reverse_argv_elements (char **argv, int num)
+{
+  int i;
+  char *tmp;
+
+  for (i = 0; i < (num >> 1); i++)
+    {
+      tmp = argv[i];
+      argv[i] = argv[num - i - 1];
+      argv[num - i - 1] = tmp;
+    }
+}
+
+/* permute: swap two blocks of argv-elements given their lengths */
+static void
+permute (char *const argv[], int len1, int len2)
+{
+  reverse_argv_elements ((char **) argv, len1);
+  reverse_argv_elements ((char **) argv, len1 + len2);
+  reverse_argv_elements ((char **) argv, len2);
+}
+
+/* is_option: is this argv-element an option or the end of the option list? */
+static int
+is_option (char *argv_element, int only)
+{
+  return ((argv_element == 0)
+	  || (argv_element[0] == '-') || (only && argv_element[0] == '+'));
+}
+
+/* read_globals: read the values from the globals into a getopt_data 
+   structure */
+static void
+read_globals (struct getopt_data *data)
+{
+  data->optarg = optarg;
+  data->optind = optind;
+  data->opterr = opterr;
+  data->optopt = optopt;
+  data->optwhere = optwhere;
+}
+
+/* write_globals: write the values into the globals from a getopt_data
+   structure */
+static void
+write_globals (struct getopt_data *data)
+{
+  optarg = data->optarg;
+  optind = data->optind;
+  opterr = data->opterr;
+  optopt = data->optopt;
+  optwhere = data->optwhere;
+}
+
+/* getopt_internal:  the function that does all the dirty work */
+static int
+getopt_internal (int argc, char *const argv[], const char *shortopts,
+		 const struct option *longopts, int *longind, int only,
+		 struct getopt_data *data)
+{
+  GETOPT_ORDERING_T ordering = PERMUTE;
+  size_t permute_from = 0;
+  int num_nonopts = 0;
+  int optindex = 0;
+  size_t match_chars = 0;
+  char *possible_arg = 0;
+  int longopt_match = -1;
+  int has_arg = -1;
+  char *cp = 0;
+  int arg_next = 0;
+  int initial_colon = 0;
+
+  /* first, deal with silly parameters and easy stuff */
+  if (argc == 0 || argv == 0 || (shortopts == 0 && longopts == 0)
+      || data->optind >= argc || argv[data->optind] == 0)
+    return EOF;
+  if (strcmp (argv[data->optind], "--") == 0)
+    {
+      data->optind++;
+      return EOF;
+    }
+
+  /* if this is our first time through */
+  if (data->optind == 0)
+    data->optind = data->optwhere = 1;
+
+  /* define ordering */
+  if (shortopts != 0 && (*shortopts == '-' || *shortopts == '+'))
+    {
+      ordering = (*shortopts == '-') ? RETURN_IN_ORDER : REQUIRE_ORDER;
+      shortopts++;
+    }
+  else
+    ordering = (getenv ("POSIXLY_CORRECT") != 0) ? REQUIRE_ORDER : PERMUTE;
+
+  /* check for initial colon in shortopts */
+  if (shortopts != 0 && *shortopts == ':')
+    {
+      ++shortopts;
+      initial_colon = 1;
+    }
+
+  /*
+   * based on ordering, find our next option, if we're at the beginning of
+   * one
+   */
+  if (data->optwhere == 1)
+    {
+      switch (ordering)
+	{
+	default:		/* shouldn't happen */
+	case PERMUTE:
+	  permute_from = data->optind;
+	  num_nonopts = 0;
+	  while (!is_option (argv[data->optind], only))
+	    {
+	      data->optind++;
+	      num_nonopts++;
+	    }
+	  if (argv[data->optind] == 0)
+	    {
+	      /* no more options */
+	      data->optind = permute_from;
+	      return EOF;
+	    }
+	  else if (strcmp (argv[data->optind], "--") == 0)
+	    {
+	      /* no more options, but have to get `--' out of the way */
+	      permute (argv + permute_from, num_nonopts, 1);
+	      data->optind = permute_from + 1;
+	      return EOF;
+	    }
+	  break;
+	case RETURN_IN_ORDER:
+	  if (!is_option (argv[data->optind], only))
+	    {
+	      data->optarg = argv[data->optind++];
+	      return (data->optopt = 1);
+	    }
+	  break;
+	case REQUIRE_ORDER:
+	  if (!is_option (argv[data->optind], only))
+	    return EOF;
+	  break;
+	}
+    }
+  /* we've got an option, so parse it */
+
+  /* first, is it a long option? */
+  if (longopts != 0
+      && (memcmp (argv[data->optind], "--", 2) == 0
+	  || (only && argv[data->optind][0] == '+')) && data->optwhere == 1)
+    {
+      /* handle long options */
+      if (memcmp (argv[data->optind], "--", 2) == 0)
+	data->optwhere = 2;
+      longopt_match = -1;
+      possible_arg = strchr (argv[data->optind] + data->optwhere, '=');
+      if (possible_arg == 0)
+	{
+	  /* no =, so next argv might be arg */
+	  match_chars = strlen (argv[data->optind]);
+	  possible_arg = argv[data->optind] + match_chars;
+	  match_chars = match_chars - data->optwhere;
+	}
+      else
+	match_chars = (possible_arg - argv[data->optind]) - data->optwhere;
+      for (optindex = 0; longopts[optindex].name != 0; ++optindex)
+	{
+	  if (memcmp
+	      (argv[data->optind] + data->optwhere, longopts[optindex].name,
+	       match_chars) == 0)
+	    {
+	      /* do we have an exact match? */
+	      if (match_chars == (int) (strlen (longopts[optindex].name)))
+		{
+		  longopt_match = optindex;
+		  break;
+		}
+	      /* do any characters match? */
+	      else
+		{
+		  if (longopt_match < 0)
+		    longopt_match = optindex;
+		  else
+		    {
+		      /* we have ambiguous options */
+		      if (data->opterr)
+			printf ("%s: option `%s' is ambiguous "
+				 "(could be `--%s' or `--%s')\n",
+				 argv[0],
+				 argv[data->optind],
+				 longopts[longopt_match].name,
+				 longopts[optindex].name);
+		      return (data->optopt = '?');
+		    }
+		}
+	    }
+	}
+      if (longopt_match >= 0)
+	has_arg = longopts[longopt_match].has_arg;
+    }
+
+  /* if we didn't find a long option, is it a short option? */
+  if (longopt_match < 0 && shortopts != 0)
+    {
+      cp = strchr (shortopts, argv[data->optind][data->optwhere]);
+      if (cp == 0)
+	{
+	  /* couldn't find option in shortopts */
+	  if (data->opterr)
+	    printf (
+		     "%s: invalid option -- `-%c'\n",
+		     argv[0], argv[data->optind][data->optwhere]);
+	  data->optwhere++;
+	  if (argv[data->optind][data->optwhere] == '\0')
+	    {
+	      data->optind++;
+	      data->optwhere = 1;
+	    }
+	  return (data->optopt = '?');
+	}
+      has_arg = ((cp[1] == ':')
+		 ? ((cp[2] == ':') ? OPTIONAL_ARG : REQUIRED_ARG) : NO_ARG);
+      possible_arg = argv[data->optind] + data->optwhere + 1;
+      data->optopt = *cp;
+    }
+
+  /* get argument and reset data->optwhere */
+  arg_next = 0;
+  switch (has_arg)
+    {
+    case OPTIONAL_ARG:
+      if (*possible_arg == '=')
+	possible_arg++;
+      data->optarg = (*possible_arg != '\0') ? possible_arg : 0;
+      data->optwhere = 1;
+      break;
+    case REQUIRED_ARG:
+      if (*possible_arg == '=')
+	possible_arg++;
+      if (*possible_arg != '\0')
+	{
+	  data->optarg = possible_arg;
+	  data->optwhere = 1;
+	}
+      else if (data->optind + 1 >= argc)
+	{
+	  if (data->opterr)
+	    {
+	      printf ("%s: argument required for option `", argv[0]);
+	      if (longopt_match >= 0)
+		{
+		  printf ("--%s'\n", longopts[longopt_match].name);
+		  data->optopt = initial_colon ? ':' : '\?';
+		}
+	      else
+		{
+		  printf ("-%c'\n", *cp);
+		  data->optopt = *cp;
+		}
+	    }
+	  data->optind++;
+	  return initial_colon ? ':' : '\?';
+	}
+      else
+	{
+	  data->optarg = argv[data->optind + 1];
+	  arg_next = 1;
+	  data->optwhere = 1;
+	}
+      break;
+    default:			/* shouldn't happen */
+    case NO_ARG:
+      if (longopt_match < 0)
+	{
+	  data->optwhere++;
+	  if (argv[data->optind][data->optwhere] == '\0')
+	    data->optwhere = 1;
+	}
+      else
+	data->optwhere = 1;
+      data->optarg = 0;
+      break;
+    }
+
+  /* do we have to permute or otherwise modify data->optind? */
+  if (ordering == PERMUTE && data->optwhere == 1 && num_nonopts != 0)
+    {
+      permute (argv + permute_from, num_nonopts, 1 + arg_next);
+      data->optind = permute_from + 1 + arg_next;
+    }
+  else if (data->optwhere == 1)
+    data->optind = data->optind + 1 + arg_next;
+
+  /* finally return */
+  if (longopt_match >= 0)
+    {
+      if (longind != 0)
+	*longind = longopt_match;
+      if (longopts[longopt_match].flag != 0)
+	{
+	  *(longopts[longopt_match].flag) = longopts[longopt_match].val;
+	  return 0;
+	}
+      else
+	return longopts[longopt_match].val;
+    }
+  else
+    return data->optopt;
+}
+
+int
+getopt (int argc, char *const argv[], const char *optstring)
+{
+  struct getopt_data data;
+  int r;
+
+  read_globals (&data);
+  r = getopt_internal (argc, argv, optstring, 0, 0, 0, &data);
+  write_globals (&data);
+  return r;
+}
+
+int
+getopt_long (int argc, char *const argv[], const char *shortopts,
+	     const struct option *longopts, int *longind)
+{
+  struct getopt_data data;
+  int r;
+
+  read_globals (&data);
+  r = getopt_internal (argc, argv, shortopts, longopts, longind, 0, &data);
+  write_globals (&data);
+  return r;
+}
+
+int
+getopt_long_only (int argc, char *const argv[], const char *shortopts,
+		  const struct option *longopts, int *longind)
+{
+  struct getopt_data data;
+  int r;
+
+  read_globals (&data);
+  r = getopt_internal (argc, argv, shortopts, longopts, longind, 1, &data);
+  write_globals (&data);
+  return r;
+}
+
+int
+__getopt_r (int argc, char *const argv[], const char *optstring,
+	    struct getopt_data *data)
+{
+  return getopt_internal (argc, argv, optstring, 0, 0, 0, data);
+}
+
+int
+__getopt_long_r (int argc, char *const argv[], const char *shortopts,
+		 const struct option *longopts, int *longind,
+		 struct getopt_data *data)
+{
+  return getopt_internal (argc, argv, shortopts, longopts, longind, 0, data);
+}
+
+int
+__getopt_long_only_r (int argc, char *const argv[], const char *shortopts,
+		      const struct option *longopts, int *longind,
+		      struct getopt_data *data)
+{
+  return getopt_internal (argc, argv, shortopts, longopts, longind, 1, data);
+}
+
+#endif /* !HAVE_GETOPT */
+
+/* end of file GETOPT.C */