Wed Mar 26 15:20:18 2008  Google Inc. <opensource@google.com>

	* google-gflags: version 0.8
	* Export DescribeOneFlag() in the API
	* Add support for automatic line wrapping at 80 cols for gflags.py
	* Bugfix: do not treat an isolated "-" the same as an isolated "--"
	* Update rpm spec to point to Google Code rather than sourceforge (!)
	* Improve documentation (including documenting thread-safety)
	* Improve #include hygiene
	* Improve testing


git-svn-id: https://gflags.googlecode.com/svn/trunk@21 6586e3c6-dcc4-952a-343f-ff74eb82781d
diff --git a/ChangeLog b/ChangeLog
index 9a46b21..af505ab 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+Wed Mar 26 15:20:18 2008  Google Inc. <opensource@google.com>
+
+	* google-gflags: version 0.8
+	* Export DescribeOneFlag() in the API
+	* Add support for automatic line wrapping at 80 cols for gflags.py
+	* Bugfix: do not treat an isolated "-" the same as an isolated "--"
+	* Update rpm spec to point to Google Code rather than sourceforge (!)
+	* Improve documentation (including documenting thread-safety)
+	* Improve #include hygiene
+	* Improve testing
+	
 Thu Oct 18 11:33:20 2007  Google Inc. <opensource@google.com>
 
 	* google-gflags: version 0.7
diff --git a/configure b/configure
index 7dfdd13..fd5a2d9 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.59 for gflags 0.7.
+# Generated by GNU Autoconf 2.59 for gflags 0.8.
 #
 # Report bugs to <opensource@google.com>.
 #
@@ -423,8 +423,8 @@
 # Identity of this package.
 PACKAGE_NAME='gflags'
 PACKAGE_TARNAME='gflags'
-PACKAGE_VERSION='0.7'
-PACKAGE_STRING='gflags 0.7'
+PACKAGE_VERSION='0.8'
+PACKAGE_STRING='gflags 0.8'
 PACKAGE_BUGREPORT='opensource@google.com'
 
 ac_unique_file="README"
@@ -954,7 +954,7 @@
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures gflags 0.7 to adapt to many kinds of systems.
+\`configure' configures gflags 0.8 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1020,7 +1020,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of gflags 0.7:";;
+     short | recursive ) echo "Configuration of gflags 0.8:";;
    esac
   cat <<\_ACEOF
 
@@ -1163,7 +1163,7 @@
 test -n "$ac_init_help" && exit 0
 if $ac_init_version; then
   cat <<\_ACEOF
-gflags configure 0.7
+gflags configure 0.8
 generated by GNU Autoconf 2.59
 
 Copyright (C) 2003 Free Software Foundation, Inc.
@@ -1177,7 +1177,7 @@
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by gflags $as_me 0.7, which was
+It was created by gflags $as_me 0.8, which was
 generated by GNU Autoconf 2.59.  Invocation command line was
 
   $ $0 $@
@@ -1823,7 +1823,7 @@
 
 # Define the identity of the package.
  PACKAGE='gflags'
- VERSION='0.7'
+ VERSION='0.8'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -20943,7 +20943,7 @@
 } >&5
 cat >&5 <<_CSEOF
 
-This file was extended by gflags $as_me 0.7, which was
+This file was extended by gflags $as_me 0.8, which was
 generated by GNU Autoconf 2.59.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -21006,7 +21006,7 @@
 
 cat >>$CONFIG_STATUS <<_ACEOF
 ac_cs_version="\\
-gflags config.status 0.7
+gflags config.status 0.8
 configured by $0, generated by GNU Autoconf 2.59,
   with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
 
diff --git a/configure.ac b/configure.ac
index 304c313..e0e5511 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4,7 +4,7 @@
 # make sure we're interpreted by some minimal autoconf
 AC_PREREQ(2.57)
 
-AC_INIT(gflags, 0.7, opensource@google.com)
+AC_INIT(gflags, 0.8, opensource@google.com)
 # The argument here is just something that should be in the current directory
 # (for sanity checking)
 AC_CONFIG_SRCDIR(README)
diff --git a/doc/gflags.html b/doc/gflags.html
index edb5b48..e059a7b 100644
--- a/doc/gflags.html
+++ b/doc/gflags.html
@@ -81,11 +81,11 @@
 
 <p> Defining a flag is easy: just use the appropriate macro for the
 type you want the flag to be, as defined at the bottom of
-<code>base/commandlineflags.h</code>.  Here's an example file,
+<code>google/gflags.h</code>.  Here's an example file,
 <code>foo.cc</code>:</p>
 
 <pre>
-   #include "base/commandlineflags.h"
+   #include &lt;google/gflags.h&gt;
 
    DEFINE_bool(big_menu, true, "Include 'advanced' options in the menu listing");
    DEFINE_string(languages, "english,french,german",
@@ -131,7 +131,7 @@
 <h2> <A name=using>Accessing the Flag</A> </h2>
 
 <p>All defined flags are available to the program as just a normal
-variable, with the prefix <code>FLAGS_</code> appended.  In the above
+variable, with the prefix <code>FLAGS_</code> prepended.  In the above
 example, the macros define two variables, <code>FLAGS_big_menu</code>
 (a bool), and <code>FLAGS_languages</code> (a C++ string).</p>
 
@@ -145,7 +145,7 @@
 </pre>
 
 <p>You can also get and set flag values via special functions in
-<code>commandlineflags.h</code>.  That's a rarer use case, though.</p>
+<code>gflags.h</code>.  That's a rarer use case, though.</p>
 
 
 <h2> <A name=declare>DECLARE: Using the Flag in a Different File</A> </h2>
@@ -173,16 +173,21 @@
 
 <blockquote>
 If you DEFINE a flag in <code>foo.cc</code>, either don't DECLARE it
-at all, or only DECLARE it in <code>foo.h</code>.
+at all, only DECLARE it in tightly related tests, or only DECLARE
+it in <code>foo.h</code>.
 </blockquote>
 
 <p>You should go the do-not-DECLARE route when the flag is only needed
-by <code>foo.cc</code>, and not in any other file.  If the flag does
-span multiple files, DECLARE it in the associated <code>.h</code>
-file, and make others <code>#include</code> that <code>.h</code> file
-if they want to access the flag.  The <code>#include</code> will make
-explicit the dependency between the two files.</p>
+by <code>foo.cc</code>, and not in any other file. If you want to
+modify the value of the flag in the related test file to see if it is
+functioning as expected, DECLARE it in the <code>foo_test.cc</code>
+file.
 
+<p>If the flag does span multiple files, DECLARE it in the associated
+<code>.h</code> file, and make others <code>#include</code> that
+<code>.h</code> file if they want to access the flag.  The
+<code>#include</code> will make explicit the dependency between the
+two files. This causes the flag to be a global variable.</p>
 
 <h2> <A name=together>Putting It Together: How to Set Up Flags</A> </h2>
 
diff --git a/packages/deb/changelog b/packages/deb/changelog
index 3025c8c..fcdbd3c 100644
--- a/packages/deb/changelog
+++ b/packages/deb/changelog
@@ -1,3 +1,9 @@
+google-gflags (0.8-1) unstable; urgency=low
+
+  * New upstream release.
+
+ -- Google Inc. <opensource@google.com>  Wed, 26 Mar 2008 15:20:18 -0700
+
 google-gflags (0.7-1) unstable; urgency=low
 
   * New upstream release.
diff --git a/packages/rpm/rpm.spec b/packages/rpm/rpm.spec
index 1f599fc..fa68885 100644
--- a/packages/rpm/rpm.spec
+++ b/packages/rpm/rpm.spec
@@ -1,18 +1,17 @@
-%define	ver	%VERSION
 %define	RELEASE	1
 %define rel     %{?CUSTOM_RELEASE} %{!?CUSTOM_RELEASE:%RELEASE}
 %define	prefix	/usr
 
 Name: %NAME
 Summary: A commandline flags library that allows for distributed flags
-Version: %ver
+Version: %VERSION
 Release: %rel
 Group: Development/Libraries
-URL: http://code.google.com/p/google-gflags
+URL: http://code.google.com/p/gflags
 License: BSD
 Vendor: Google
 Packager: Google Inc. <opensource@google.com>
-Source: http://google-gflags.googlecode.com/files/%{NAME}-%{PACKAGE_VERSION}.tar.gz
+Source: http://%{NAME}.googlecode.com/files/%{NAME}-%{VERSION}.tar.gz
 Distribution: Redhat 7 and above.
 Buildroot: %{_tmppath}/%{name}-root
 Prefix: %prefix
@@ -26,6 +25,7 @@
 %package devel
 Summary: A commandline flags library that allows for distributed flags
 Group: Development/Libraries
+Requires: %{NAME} = %{VERSION}
 
 %description devel
 The %name-devel package contains static and debug libraries and header
diff --git a/python/gflags.py b/python/gflags.py
index 2a37afb..bd35d81 100755
--- a/python/gflags.py
+++ b/python/gflags.py
@@ -116,6 +116,7 @@
    --help (or -?)  prints a list of all the flags in a human-readable fashion
    --helpshort     prints a list of all the flags in the 'main' .py file only
    --flagfile=foo  read flags from foo.
+   --undefok=f1,f2 ignore unrecognized option errors for f1,f2
    --              as in getopt(), terminates flag-processing
 
 Note on --flagfile:
@@ -157,11 +158,10 @@
   # Flag names are globally defined!  So in general, we need to be
   # careful to pick names that are unlikely to be used by other libraries.
   # If there is a conflict, we'll get an error at import time.
-  gflags.DEFINE_string("name", "Mr. President" "NAME: your name")
-  gflags.DEFINE_integer("age", None, "AGE: your age in years", lower_bound=0)
-  gflags.DEFINE_boolean("debug", 0, "produces debugging output")
-  gflags.DEFINE_enum("gender", "male", ["male", "female"],
-                     "GENDER: your gender")
+  gflags.DEFINE_string('name', 'Mr. President', 'your name')
+  gflags.DEFINE_integer('age', None, 'your age in years', lower_bound=0)
+  gflags.DEFINE_boolean('debug', 0, 'produces debugging output')
+  gflags.DEFINE_enum('gender', 'male', ['male', 'female'], 'your gender')
 
   def main(argv):
     try:
@@ -172,13 +172,15 @@
     if FLAGS.debug: print 'non-flag arguments:', argv
     print 'Happy Birthday', FLAGS.name
     if FLAGS.age is not None:
-      print "You are a %s, who is %d years old" % (FLAGS.gender, FLAGS.age)
+      print 'You are a %s, who is %d years old' % (FLAGS.gender, FLAGS.age)
 
-  if __name__ == '__main__': main(sys.argv)
+  if __name__ == '__main__':
+    main(sys.argv)
 """
 
 import getopt
 import os
+import re
 import sys
 
 # Are we running at least python 2.2?
@@ -188,16 +190,256 @@
 except AttributeError:   # a very old python, that lacks sys.version_info
   raise NotImplementedError("requires python 2.2.0 or later")
 
+# If we're not running at least python 2.3, define True and False
+# Thanks, Guido, for the code.
+try:
+  True, False
+except NameError:
+  False = 0
+  True = 1
+
 # Are we running under pychecker?
 _RUNNING_PYCHECKER = 'pychecker.python' in sys.modules
 
+
+def _GetCallingModule():
+  """
+  Get the name of the module that's calling into this module; e.g.,
+  the module calling a DEFINE_foo... function.
+  """
+  # Walk down the stack to find the first globals dict that's not ours.
+  for depth in range(1, sys.getrecursionlimit()):
+    if not sys._getframe(depth).f_globals is globals():
+      return __GetModuleName(sys._getframe(depth).f_globals)
+  raise AssertionError, "No module was found"
+
+
 # module exceptions:
-class FlagsError(Exception): "The base class for all flags errors"
-class DuplicateFlag(FlagsError): "Thrown if there is a flag naming conflict"
+class FlagsError(Exception):
+  """The base class for all flags errors"""
+
+class DuplicateFlag(FlagsError):
+  """"Raised if there is a flag naming conflict"""
+
+# A DuplicateFlagError conveys more information than
+# a DuplicateFlag. Since there are external modules
+# that create DuplicateFlags, the interface to
+# DuplicateFlag shouldn't change.
+class DuplicateFlagError(DuplicateFlag):
+  def __init__(self, flagname, flag_values):
+    self.flagname = flagname
+    message = "The flag '%s' is defined twice." % self.flagname
+    flags_by_module = flag_values.__dict__['__flags_by_module']
+    for module in flags_by_module:
+      for flag in flags_by_module[module]:
+        if flag.name == flagname:
+          message = message + " First from " + module + ","
+          break
+    message = message + " Second from " + _GetCallingModule()
+    Exception.__init__(self, message)
+
 class IllegalFlagValue(FlagsError): "The flag command line argument is illegal"
 
+class UnrecognizedFlag(FlagsError):
+  """Raised if a flag is unrecognized"""
+
+# An UnrecognizedFlagError conveys more information than
+# an UnrecognizedFlag. Since there are external modules
+# that create DuplicateFlags, the interface to
+# DuplicateFlag shouldn't change.
+class UnrecognizedFlagError(UnrecognizedFlag):
+  def __init__(self, flagname):
+    self.flagname = flagname
+    Exception.__init__(self, "Unknown command line flag '%s'" % flagname)
+
 # Global variable used by expvar
 _exported_flags = {}
+_help_width = 80  # width of help output
+
+
+def GetHelpWidth():
+  """
+  Length of help to be used in TextWrap
+  """
+  global _help_width
+  return _help_width
+
+
+def CutCommonSpacePrefix(text):
+  """
+  Cut out a common space prefix. If the first line does not start with a space
+  it is left as is and only in the remaining lines a common space prefix is
+  being searched for. That means the first line will stay untouched. This is
+  especially useful to turn doc strings into help texts. This is because some
+  people prefer to have the doc comment start already after the apostrophy and
+  then align the following lines while others have the apostrophies on a
+  seperately line. The function also drops trailing empty lines and ignores
+  empty lines following the initial content line while calculating the initial
+  common whitespace.
+
+  Args:
+    text:  text to work on
+
+  Returns:
+    the resulting text
+  """
+  text_lines = text.splitlines()
+  # Drop trailing empty lines
+  while text_lines and not text_lines[-1]:
+    text_lines = text_lines[:-1]
+  if text_lines:
+    # We got some content, is the first line starting with a space?
+    if text_lines[0] and text_lines[0][0].isspace():
+      text_first_line = []
+    else:
+      text_first_line = [text_lines.pop(0)]
+    # Calculate length of common leading whitesppace (only over content lines)
+    common_prefix = os.path.commonprefix([line for line in text_lines if line])
+    space_prefix_len = len(common_prefix) - len(common_prefix.lstrip())
+    # If we have a common space prefix, drop it from all lines
+    if space_prefix_len:
+      for index in xrange(len(text_lines)):
+        if text_lines[index]:
+          text_lines[index] = text_lines[index][space_prefix_len:]
+    return '\n'.join(text_first_line + text_lines)
+  return ''
+
+
+def TextWrap(text, length=None, indent='', firstline_indent=None, tabs='    '):
+  """
+  Wrap a given text to a maximum line length and return it.
+  We turn lines that only contain whitespace into empty lines.
+  We keep new lines.
+  We also keep tabs (e.g. we do not treat tabs as spaces).
+
+  Args:
+    text:             text to wrap
+    length:           maximum length of a line, includes indentation
+                      if this is None then use GetHelpWidth()
+    indent:           indent for all but first line
+    firstline_indent: indent for first line, if None then fall back to indent
+    tabs:             replacement for tabs
+
+  Returns:
+    wrapped text
+
+  Raises:
+    CommandsError: if indent not shorter than length
+    CommandsError: if firstline_indent not shorter than length
+  """
+  # Get defaults where callee used None
+  if length is None:
+    length = GetHelpWidth()
+  if indent is None:
+    indent = ''
+  if len(indent) >= length:
+    raise CommandsError('Indent must be shorter than length')
+  # In line we will be holding the current line which is to be started with
+  # indent (or firstline_indent if available) and then appended with words.
+  if firstline_indent is None:
+    firstline_indent = ''
+    line = indent
+  else:
+    line = firstline_indent
+    if len(firstline_indent) >= length:
+      raise CommandsError('First iline indent must be shorter than length')
+
+  # If the callee does not care about tabs we simply convert them to spaces
+  # If callee wanted tabs to be single space then we do that already here.
+  if not tabs or tabs == ' ':
+    text = text.replace('\t', ' ')
+  else:
+    tabs_are_whitespace = not tabs.strip()
+
+  line_regex = re.compile('([ ]*)(\t*)([^ \t]+)', re.MULTILINE)
+
+  # Split the text into lines and the lines with the regex above. The resulting
+  # lines are collected in result[]. For each split we get the spaces, the tabs
+  # and the next non white space (e.g. next word).
+  result = []
+  for text_line in text.splitlines():
+    # Store result length so we can find out whether processing the next line
+    # gave any new content
+    old_result_len = len(result)
+    # Process next line with line_regex. For optimization we do an rstrip().
+    # - process tabs (changes either line or word, see below)
+    # - process word (first try to squeeze on line, then wrap or force wrap)
+    # Spaces found on the line are ignored, they get added while wrapping as
+    # needed.
+    for spaces, current_tabs, word in line_regex.findall(text_line.rstrip()):
+      # If tabs weren't converted to spaces, handle them now
+      if current_tabs:
+        # If the last thing we added was a space anyway then drop it. But
+        # let's not get rid of the indentation.
+        if (((result and line != indent) or
+            (not result and line != firstline_indent)) and line[-1] == ' '):
+          line = line[:-1]
+        # Add the tabs, if that means adding whitespace, just add it at the
+        # line, the rstrip() code while shorten the line down if necessary
+        if tabs_are_whitespace:
+          line += tabs * len(current_tabs)
+        else:
+          # if not all tab replacement is whitespace we prepend it to the word
+          word = tabs * len(current_tabs) + word
+      # Handle the case where word cannot be squeezed onto current last line
+      if len(line) + len(word) > length and len(indent) + len(word) <= length:
+        result.append(line.rstrip())
+        line = indent + word
+        word = ''
+        # No space left on line or can we append a space?
+        if len(line) + 1 >= length:
+          result.append(line.rstrip())
+          line = indent
+        else:
+          line += ' '
+      # Add word and shorten it up to allowed line length. Restart next line
+      # with indent and repeat, or add a space if we're done (word finished)
+      # This deals with words that caanot fit on one line (e.g. indent + word
+      # longer than allowed line length).
+      while len(line) + len(word) >= length:
+        line += word
+        result.append(line[:length])
+        word = line[length:]
+        line = indent
+      # Default case, simply append the word and a space
+      if word:
+        line += word + ' '
+    # End of input line. If we have content we finish the line. If the
+    # current line is just the indent but we had content in during this
+    # original line then we need to add an emoty line.
+    if (result and line != indent) or (not result and line != firstline_indent):
+      result.append(line.rstrip())
+    elif len(result) == old_result_len:
+      result.append('')
+    line = indent
+
+  return '\n'.join(result)
+
+
+def DocToHelp(doc):
+  """
+  Takes a __doc__ string and reformats it as help.
+  """
+  # Get rid of starting and ending white space. Using lstrip() or even strip()
+  # could drop more than maximum of first line and right space of last line.
+  doc = doc.strip()
+
+  # Get rid of all empty lines
+  whitespace_only_line = re.compile('^[ \t]+$', re.M)
+  doc = whitespace_only_line.sub('', doc)
+
+  # Cut out common space at line beginnings
+  doc = CutCommonSpacePrefix(doc)
+
+  # Just like this module's comment, comments tend to be aligned somehow.
+  # In other words they all start with the same amount of white space
+  # 1) keep double new lines
+  # 2) keep ws after new lines if not empty line
+  # 3) all other new lines shall be changed to a space
+  # Solution: Match new lines between non white space and replace with space.
+  doc = re.sub('(?<=\S)\n(?=\S)', ' ', doc, re.M)
+
+  return doc
 
 
 def __GetModuleName(globals_dict):
@@ -209,16 +451,6 @@
       return name
   raise AssertionError, "No module was found"
 
-def __GetCallingModule():
-  """Get the name of the module that's calling into this module; e.g.,
-     the module calling a DEFINE_foo... function.
-  """
-  # Walk down the stack to find the first globals dict that's not ours.
-  for depth in range(1, sys.getrecursionlimit()):
-    if not sys._getframe(depth).f_globals is globals():
-      return __GetModuleName(sys._getframe(depth).f_globals)
-  raise AssertionError, "No module was found"
-
 def _GetMainModule():
   """Get the module name from which execution started."""
   for depth in range(1, sys.getrecursionlimit()):
@@ -262,6 +494,7 @@
   The str() operator of a 'FlagValues' object provides help for all of
   the registered 'Flag' objects.
   """
+
   def __init__(self):
     # Since everything in this class is so heavily overloaded,
     # the only way of defining and using fields is to access __dict__
@@ -279,6 +512,15 @@
     flags_by_module = self.__dict__['__flags_by_module']
     flags_by_module.setdefault(module_name, []).append(flag)
 
+  def AppendFlagValues(self, flag_values):
+    """Append flags registered in another FlagValues instance.
+
+    Args:
+      flag_values: registry to copy from
+    """
+    for flag_name, flag in flag_values.FlagDict().iteritems():
+      self[flag_name] = flag
+
   def __setitem__(self, name, flag):
     """
     Register a new flag variable.
@@ -294,12 +536,12 @@
     # Disable check for duplicate keys when pycheck'ing.
     if (fl.has_key(name) and not flag.allow_override and
         not fl[name].allow_override and not _RUNNING_PYCHECKER):
-      raise DuplicateFlag, name
+      raise DuplicateFlagError(name, self)
     short_name = flag.short_name
     if short_name is not None:
       if (fl.has_key(short_name) and not flag.allow_override and
           not fl[short_name].allow_override and not _RUNNING_PYCHECKER):
-        raise DuplicateFlag, short_name
+        raise DuplicateFlagError(short_name, self)
       fl[short_name] = flag
     fl[name] = flag
     global _exported_flags
@@ -365,8 +607,16 @@
     Argument Syntax Conventions, using getopt:
 
     http://www.gnu.org/software/libc/manual/html_mono/libc.html#Getopt
-    """
 
+    Args:
+       argv: argument list. Can be of any type that may be converted to a list.
+
+    Returns:
+       The list of arguments not parsed as options, including argv[0]
+
+    Raises:
+       FlagsError: on any parsing error
+    """
     # Support any sequence type that can be converted to a list
     argv = list(argv)
 
@@ -384,7 +634,7 @@
     # having options that may or may not have a parameter.  We replace
     # instances of the short form --mybool and --nomybool with their
     # full forms: --mybool=(true|false).
-    original_argv = list(argv)
+    original_argv = list(argv)  # list() makes a copy
     shortest_matches = None
     for name, flag in fl.items():
       if not flag.boolean:
@@ -412,16 +662,45 @@
     # Each string ends with an '=' if it takes an argument.
     for name, flag in fl.items():
       longopts.append(name + "=")
-      if len(name) == 1: # one-letter option: allow short flag type also
+      if len(name) == 1:  # one-letter option: allow short flag type also
         shortopts += name
         if not flag.boolean:
           shortopts += ":"
 
-    try:
-      optlist, unparsed_args = getopt.getopt(argv[1:], shortopts, longopts)
-    except getopt.GetoptError, e:
-      raise FlagsError, e
+    longopts.append('undefok=')
+    undefok_flags = []
+
+    # In case --undefok is specified, loop to pick up unrecognized
+    # options one by one.
+    unrecognized_opts = []
+    args = argv[1:]
+    while True:
+      try:
+        optlist, unparsed_args = getopt.getopt(args, shortopts, longopts)
+        break
+      except getopt.GetoptError, e:
+        if not e.opt or e.opt in fl:
+          # Not an unrecognized option, reraise the exception as a FlagsError
+          raise FlagsError(e)
+        # Handle an unrecognized option.
+        unrecognized_opts.append(e.opt)
+        # Remove offender from args and try again
+        for arg_index in range(len(args)):
+          if ((args[arg_index] == '--' + e.opt) or
+              (args[arg_index] == '-' + e.opt) or
+              args[arg_index].startswith('--' + e.opt + '=')):
+            args = args[0:arg_index] + args[arg_index+1:]
+            break
+        else:
+          # We should have found the option, so we don't expect to get
+          # here.  We could assert, but raising the original exception
+          # might work better.
+          raise FlagsError(e)
+
     for name, arg in optlist:
+      if name == '--undefok':
+        undefok_flags.extend(arg.split(','))
+        continue
       if name.startswith('--'):
         # long option
         name = name[2:]
@@ -435,6 +714,12 @@
         if flag.boolean and short_option: arg = 1
         flag.Parse(arg)
 
+    # If there were unrecognized options, raise an exception unless
+    # the options were named via --undefok.
+    for opt in unrecognized_opts:
+      if opt not in undefok_flags:
+        raise UnrecognizedFlagError(opt)
+
     if unparsed_args:
       # unparsed_args becomes the first non-flag detected by getopt to
       # the end of argv.  Because argv may have been modified above,
@@ -472,6 +757,12 @@
     """
     Generate a help string for all known flags.
     """
+    return self.GetHelp()
+
+  def GetHelp(self, prefix=""):
+    """
+    Generate a help string for all known flags.
+    """
     helplist = []
 
     flags_by_module = self.__dict__['__flags_by_module']
@@ -487,33 +778,47 @@
         modules = [ main_module ] + modules
 
       for module in modules:
-        self.__RenderModuleFlags(module, helplist)
+        self.__RenderOurModuleFlags(module, helplist)
+
+      self.__RenderModuleFlags('google3.pyglib.flags',
+                               _SPECIAL_FLAGS.FlagDict().values(),
+                               helplist)
 
     else:
       # Just print one long list of flags.
-      self.__RenderFlagList(self.FlagDict().values(), helplist)
+      self.__RenderFlagList(
+          self.FlagDict().values() + _SPECIAL_FLAGS.FlagDict().values(),
+          helplist, prefix)
 
     return '\n'.join(helplist)
 
-  def __RenderModuleFlags(self, module, output_lines):
+  def __RenderModuleFlags(self, module, flags, output_lines, prefix=""):
+    """
+    Generate a help string for a given module.
+    """
+    output_lines.append('\n%s%s:' % (prefix, module))
+    self.__RenderFlagList(flags, output_lines, prefix + "  ")
+
+  def __RenderOurModuleFlags(self, module, output_lines, prefix=""):
     """
     Generate a help string for a given module.
     """
     flags_by_module = self.__dict__['__flags_by_module']
     if module in flags_by_module:
-      output_lines.append('\n%s:' % module)
-      self.__RenderFlagList(flags_by_module[module], output_lines)
+      self.__RenderModuleFlags(module, flags_by_module[module],
+                               output_lines, prefix)
 
   def MainModuleHelp(self):
     """
     Generate a help string for all known flags of the main module.
     """
     helplist = []
-    self.__RenderModuleFlags(_GetMainModule(), helplist)
+    self.__RenderOurModuleFlags(_GetMainModule(), helplist)
     return '\n'.join(helplist)
 
-  def __RenderFlagList(self, flaglist, output_lines):
+  def __RenderFlagList(self, flaglist, output_lines, prefix="  "):
     fl = self.FlagDict()
+    special_fl = _SPECIAL_FLAGS.FlagDict()
     flaglist = [(flag.name, flag) for flag in flaglist]
     flaglist.sort()
     flagset = {}
@@ -521,12 +826,13 @@
       # It's possible this flag got deleted or overridden since being
       # registered in the per-module flaglist.  Check now against the
       # canonical source of current flag information, the FlagDict.
-      if fl.get(name, None) != flag:   # a different flag is using this name now
+      if fl.get(name, None) != flag and special_fl.get(name, None) != flag:
+        # a different flag is using this name now
         continue
       # only print help once
       if flagset.has_key(flag): continue
       flagset[flag] = 1
-      flaghelp = "  "
+      flaghelp = ""
       if flag.short_name: flaghelp += "-%s," % flag.short_name
       if flag.boolean:
         flaghelp += "--[no]%s" % flag.name + ":"
@@ -535,10 +841,16 @@
       flaghelp += "  "
       if flag.help:
         flaghelp += flag.help
+      flaghelp = TextWrap(flaghelp, indent=prefix+"  ",
+                          firstline_indent=prefix)
       if flag.default_as_str:
-        flaghelp += "\n    (default: %s)" % flag.default_as_str
+        flaghelp += "\n"
+        flaghelp += TextWrap("(default: %s)" % flag.default_as_str,
+                             indent=prefix+"  ")
       if flag.parser.syntactic_help:
-        flaghelp += "\n    (%s)" % flag.parser.syntactic_help
+        flaghelp += "\n"
+        flaghelp += TextWrap("(%s)" % flag.parser.syntactic_help,
+                             indent=prefix+"  ")
       output_lines.append(flaghelp)
 
   def get(self, name, default):
@@ -730,7 +1042,7 @@
 
   def FlagsIntoString(self):
     """
-    Retreive a string version of all the flags with assignments stored
+    Retrieve a string version of all the flags with assignments stored
     in this FlagValues object.  Should mirror the behavior of the c++
     version of FlagsIntoString.  Each flag assignment is seperated by
     a newline.
@@ -751,9 +1063,7 @@
     out_file = open(filename, 'a')
     out_file.write(self.FlagsIntoString())
     out_file.close()
-
-#end of the FLAGS registry class
-
+# end of FlagValues definition
 
 # The global FlagValues instance
 FLAGS = FlagValues()
@@ -869,6 +1179,7 @@
       self.value = None
     self.default = value
     self.default_as_str = self.__GetParsedValueAsString(value)
+# End of Flag definition
 
 class ArgumentParser:
   """
@@ -929,7 +1240,7 @@
   default, the global FLAGS 'FlagValue' object is used.
 
   Typical users will use one of the more specialized DEFINE_xxx
-  functions, such as DEFINE_string or DEFINEE_integer.  But developers
+  functions, such as DEFINE_string or DEFINE_integer.  But developers
   who need to create Flag objects themselves should use this function to
   register their flags.
   """
@@ -944,7 +1255,7 @@
     # of which module is creating the flags.
 
     # Tell FLAGS who's defining flag.
-    FLAGS._RegisterFlagByModule(__GetCallingModule(), flag)
+    FLAGS._RegisterFlagByModule(_GetCallingModule(), flag)
 
 
 ###############################
@@ -1369,3 +1680,18 @@
 # these flagnames for their own purposes, if they want.
 DEFINE_flag(HelpFlag())
 DEFINE_flag(HelpshortFlag())
+
+# Define special flags here so that help may be generated for them.
+_SPECIAL_FLAGS = FlagValues()
+
+DEFINE_string(
+    'flagfile', "",
+    "Insert flag definitions from the given file into the command line.",
+    _SPECIAL_FLAGS)
+
+DEFINE_string(
+    'undefok', "",
+    "comma-separated list of flag names that it is okay to specify "
+    "on the command line even if the program does not define a flag "
+    "with that name.  IMPORTANT: flags in this list that have "
+    "arguments MUST use the --flag=value format.", _SPECIAL_FLAGS)
diff --git a/python/gflags_unittest.py b/python/gflags_unittest.py
index 342a557..c574070 100755
--- a/python/gflags_unittest.py
+++ b/python/gflags_unittest.py
@@ -44,6 +44,15 @@
 import gflags as flags
 FLAGS=flags.FLAGS
 
+# If we're not running at least python 2.3, as is the case when
+# invoked from flags_unittest_2_2, define True and False.
+# Thanks, Guido, for the code.
+try:
+  True, False
+except NameError:
+  False = 0
+  True = 1
+
 class FlagsUnitTest(unittest.TestCase):
   "Flags Unit Test"
 
@@ -179,10 +188,10 @@
     assert len(argv) == 1, "wrong number of arguments pulled"
     assert argv[0] == './program', "program name not preserved"
     assert FLAGS['debug'].present == 1
-    assert FLAGS['debug'].value == True
+    assert FLAGS['debug'].value
     FLAGS.Reset()
     assert FLAGS['debug'].present == 0
-    assert FLAGS['debug'].value == False
+    assert not FLAGS['debug'].value
 
     # Test that reset restores default value when default value is None.
     argv = ('./program', '--kwery=who')
@@ -531,11 +540,32 @@
     self.assert_(str(FLAGS).find('runhelp d31') == -1)
     self.assert_(str(FLAGS).find('runhelp d32') != -1)
 
+    # Make sure AppendFlagValues works
+    new_flags = flags.FlagValues()
+    flags.DEFINE_boolean("new1", 0, "runhelp n1", flag_values=new_flags)
+    flags.DEFINE_boolean("new2", 0, "runhelp n2", flag_values=new_flags)
+    self.assertEqual(len(new_flags.FlagDict()), 2)
+    old_len = len(FLAGS.FlagDict())
+    FLAGS.AppendFlagValues(new_flags)
+    self.assertEqual(len(FLAGS.FlagDict())-old_len, 2)
+    self.assertEqual("new1" in FLAGS.FlagDict(), True)
+    self.assertEqual("new2" in FLAGS.FlagDict(), True)
+
+    # Make sure AppendFlagValues fails on duplicates
+    flags.DEFINE_boolean("dup4", 0, "runhelp d41")
+    new_flags = flags.FlagValues()
+    flags.DEFINE_boolean("dup4", 0, "runhelp d42", flag_values=new_flags)
+    try:
+      FLAGS.AppendFlagValues(new_flags)
+      raise AssertionError("ignore_copy was not set but caused no exception")
+    except flags.DuplicateFlag, e:
+      pass
+
     # Integer out of bounds
     try:
       argv = ('./program', '--repeat=-4')
       FLAGS(argv)
-      raise AssertionError('integer bounds exception not thrown:'
+      raise AssertionError('integer bounds exception not raised:'
                            + str(FLAGS.repeat))
     except flags.IllegalFlagValue:
       pass
@@ -544,7 +574,7 @@
     try:
       argv = ('./program', '--repeat=2.5')
       FLAGS(argv)
-      raise AssertionError("malformed integer value exception not thrown")
+      raise AssertionError("malformed integer value exception not raised")
     except flags.IllegalFlagValue:
       pass
 
@@ -552,7 +582,7 @@
     try:
       argv = ('./program', '--name')
       FLAGS(argv)
-      raise AssertionError("Flag argument required exception not thrown")
+      raise AssertionError("Flag argument required exception not raised")
     except flags.FlagsError:
       pass
 
@@ -560,23 +590,16 @@
     try:
       argv = ('./program', '--debug=goofup')
       FLAGS(argv)
-      raise AssertionError("No argument allowed exception not thrown")
+      raise AssertionError("No argument allowed exception not raised")
     except flags.FlagsError:
       pass
 
-    # Unknown argument --nosuchflag
-    try:
-      argv = ('./program', '--nosuchflag', '--name=Bob', 'extra')
-      FLAGS(argv)
-      raise AssertionError("Unknown argument exception not thrown")
-    except flags.FlagsError:
-      pass
 
     # Non-numeric argument for integer flag --repeat
     try:
       argv = ('./program', '--repeat', 'Bob', 'extra')
       FLAGS(argv)
-      raise AssertionError("Illegal flag value exception not thrown")
+      raise AssertionError("Illegal flag value exception not raised")
     except flags.IllegalFlagValue:
       pass
 
@@ -708,7 +731,7 @@
   # end testThree def
 
   def testMethod_flagfiles_4(self):
-    """Tests parsing self referetial files + arguments of simulated argv.
+    """Tests parsing self-referential files + arguments of simulated argv.
       This test should print a warning to stderr of some sort.
     """
     self.__DeclareSomeFlags()
@@ -854,6 +877,303 @@
     FLAGS.__delattr__('zz')
     FLAGS.__delattr__('nozz')
 
+  def test_twodasharg_first(self):
+    flags.DEFINE_string("twodash_name", "Bob", "namehelp")
+    flags.DEFINE_string("twodash_blame", "Rob", "blamehelp")
+    argv = ('./program',
+            '--',
+            '--twodash_name=Harry')
+    argv = FLAGS(argv)
+    self.assertEqual('Bob', FLAGS.twodash_name)
+    self.assertEqual(argv[1], '--twodash_name=Harry')
+
+  def test_twodasharg_middle(self):
+    flags.DEFINE_string("twodash2_name", "Bob", "namehelp")
+    flags.DEFINE_string("twodash2_blame", "Rob", "blamehelp")
+    argv = ('./program',
+            '--twodash2_blame=Larry',
+            '--',
+            '--twodash2_name=Harry')
+    argv = FLAGS(argv)
+    self.assertEqual('Bob', FLAGS.twodash2_name)
+    self.assertEqual('Larry', FLAGS.twodash2_blame)
+    self.assertEqual(argv[1], '--twodash2_name=Harry')
+
+  def test_onedasharg_first(self):
+    flags.DEFINE_string("onedash_name", "Bob", "namehelp")
+    flags.DEFINE_string("onedash_blame", "Rob", "blamehelp")
+    argv = ('./program',
+            '-',
+            '--onedash_name=Harry')
+    argv = FLAGS(argv)
+    self.assertEqual(argv[1], '-')
+    # TODO(csilvers): we should still parse --onedash_name=Harry as a
+    # flag, but currently we don't (we stop flag processing as soon as
+    # we see the first non-flag).
+
+  def test_unrecognized_flags(self):
+    # Unknown flag --nosuchflag
+    try:
+      argv = ('./program', '--nosuchflag', '--name=Bob', 'extra')
+      FLAGS(argv)
+      raise AssertionError("Unknown flag exception not raised")
+    except flags.UnrecognizedFlag, e:
+      assert e.flagname == 'nosuchflag'
+
+    # Unknown flag -w (short option)
+    try:
+      argv = ('./program', '-w', '--name=Bob', 'extra')
+      FLAGS(argv)
+      raise AssertionError("Unknown flag exception not raised")
+    except flags.UnrecognizedFlag, e:
+      assert e.flagname == 'w'
+
+    # Unknown flag --nosuchflagwithparam=foo
+    try:
+      argv = ('./program', '--nosuchflagwithparam=foo', '--name=Bob', 'extra')
+      FLAGS(argv)
+      raise AssertionError("Unknown flag exception not raised")
+    except flags.UnrecognizedFlag, e:
+      assert e.flagname == 'nosuchflagwithparam'
+
+    # Allow unknown flag --nosuchflag if specified with undefok
+    argv = ('./program', '--nosuchflag', '--name=Bob',
+            '--undefok=nosuchflag', 'extra')
+    argv = FLAGS(argv)
+    assert len(argv) == 2, "wrong number of arguments pulled"
+    assert argv[0]=='./program', "program name not preserved"
+    assert argv[1]=='extra', "extra argument not preserved"
+
+    # But not if the flagname is misspelled:
+    try:
+      argv = ('./program', '--nosuchflag', '--name=Bob',
+              '--undefok=nosuchfla', 'extra')
+      FLAGS(argv)
+      raise AssertionError("Unknown flag exception not raised")
+    except flags.UnrecognizedFlag, e:
+      assert e.flagname == 'nosuchflag'
+
+    try:
+      argv = ('./program', '--nosuchflag', '--name=Bob',
+              '--undefok=nosuchflagg', 'extra')
+      FLAGS(argv)
+      raise AssertionError("Unknown flag exception not raised")
+    except flags.UnrecognizedFlag:
+      assert e.flagname == 'nosuchflag'
+
+    # Allow unknown short flag -w if specified with undefok
+    argv = ('./program', '-w', '--name=Bob', '--undefok=w', 'extra')
+    argv = FLAGS(argv)
+    assert len(argv) == 2, "wrong number of arguments pulled"
+    assert argv[0]=='./program', "program name not preserved"
+    assert argv[1]=='extra', "extra argument not preserved"
+
+    # Allow unknown flag --nosuchflagwithparam=foo if specified
+    # with undefok
+    argv = ('./program', '--nosuchflagwithparam=foo', '--name=Bob',
+            '--undefok=nosuchflagwithparam', 'extra')
+    argv = FLAGS(argv)
+    assert len(argv) == 2, "wrong number of arguments pulled"
+    assert argv[0]=='./program', "program name not preserved"
+    assert argv[1]=='extra', "extra argument not preserved"
+
+    # Even if undefok specifies multiple flags
+    argv = ('./program', '--nosuchflag', '-w', '--nosuchflagwithparam=foo',
+            '--name=Bob',
+            '--undefok=nosuchflag,w,nosuchflagwithparam',
+            'extra')
+    argv = FLAGS(argv)
+    assert len(argv) == 2, "wrong number of arguments pulled"
+    assert argv[0]=='./program', "program name not preserved"
+    assert argv[1]=='extra', "extra argument not preserved"
+
+    # However, not if undefok doesn't specify the flag
+    try:
+      argv = ('./program', '--nosuchflag', '--name=Bob',
+              '--undefok=another_such', 'extra')
+      FLAGS(argv)
+      raise AssertionError("Unknown flag exception not raised")
+    except flags.UnrecognizedFlag, e:
+      assert e.flagname == 'nosuchflag'
+
+    # Make sure --undefok doesn't mask other option errors.
+    try:
+      # Provide an option requiring a parameter but not giving it one.
+      argv = ('./program', '--undefok=name', '--name')
+      FLAGS(argv)
+      raise AssertionError("Missing option parameter exception not raised")
+    except flags.UnrecognizedFlag:
+      raise AssertionError("Wrong kind of error exception raised")
+    except flags.FlagsError:
+      pass
+
+    # Test --undefok <list>
+    argv = ('./program', '--nosuchflag', '-w', '--nosuchflagwithparam=foo',
+            '--name=Bob',
+            '--undefok',
+            'nosuchflag,w,nosuchflagwithparam',
+            'extra')
+    argv = FLAGS(argv)
+    assert len(argv) == 2, "wrong number of arguments pulled"
+    assert argv[0]=='./program', "program name not preserved"
+    assert argv[1]=='extra', "extra argument not preserved"
+
+  def test_nonglobal_flags(self):
+    """Test use of non-global FlagValues"""
+    nonglobal_flags = flags.FlagValues()
+    flags.DEFINE_string("nonglobal_flag", "Bob", "flaghelp", nonglobal_flags)
+    argv = ('./program',
+            '--nonglobal_flag=Mary',
+            'extra')
+    argv = nonglobal_flags(argv)
+    assert len(argv) == 2, "wrong number of arguments pulled"
+    assert argv[0]=='./program', "program name not preserved"
+    assert argv[1]=='extra', "extra argument not preserved"
+    assert nonglobal_flags['nonglobal_flag'].value == 'Mary'
+
+  def test_unrecognized_nonglobal_flags(self):
+    """Test unrecognized non-global flags"""
+    nonglobal_flags = flags.FlagValues()
+    argv = ('./program',
+            '--nosuchflag')
+    try:
+      argv = nonglobal_flags(argv)
+      raise AssertionError("Unknown flag exception not raised")
+    except flags.UnrecognizedFlag, e:
+      assert e.flagname == 'nosuchflag'
+      pass
+
+    argv = ('./program',
+            '--nosuchflag',
+            '--undefok=nosuchflag')
+
+    argv = nonglobal_flags(argv)
+    assert len(argv) == 1, "wrong number of arguments pulled"
+    assert argv[0]=='./program', "program name not preserved"
+
+  def test_main_module_help(self):
+    """Test MainModuleHelp()"""
+    help = FLAGS.MainModuleHelp()
+
+    # When this test is invoked on behalf of flags_unittest_2_2,
+    # the main module has not defined any flags. Since there's
+    # no easy way to run this script in our test environment
+    # directly from python2.2, don't bother to test the output
+    # of MainModuleHelp() in that scenario.
+    if sys.version.startswith('2.2.'):
+      return
+
+    expected_help = "\n" + sys.argv[0] + ':' + """
+  --[no]debug: debughelp
+    (default: 'false')
+  -u,--[no]dup1: runhelp d12
+    (default: 'true')
+  -u,--[no]dup2: runhelp d22
+    (default: 'true')
+  -u,--[no]dup3: runhelp d32
+    (default: 'true')
+  --[no]dup4: runhelp d41
+    (default: 'false')
+  -?,--[no]help: show this help
+  --[no]helpshort: show usage only for this module
+  --kwery: <who|what|why|where|when>: ?
+  --l: how long to be
+    (default: '9223372032559808512')
+    (an integer)
+  --letters: a list of letters
+    (default: 'a,b,c')
+    (a comma separated list)
+  -m,--m_str: string option that can occur multiple times;
+    repeat this option to specify a list of values
+    (default: "['def1', 'def2']")
+  --name: namehelp
+    (default: 'Bob')
+  --[no]noexec: boolean flag with no as prefix
+    (default: 'true')
+  --[no]q: quiet mode
+    (default: 'true')
+  --[no]quack: superstring of 'q'
+    (default: 'false')
+  -r,--repeat: how many times to repeat (0-5)
+    (default: '4')
+    (a non-negative integer)
+  -s,--s_str: string option that can occur multiple times;
+    repeat this option to specify a list of values
+    (default: "['sing1']")
+  --[no]test0: test boolean parsing
+  --[no]test1: test boolean parsing
+  --[no]testget1: test parsing with defaults
+  --[no]testget2: test parsing with defaults
+  --[no]testget3: test parsing with defaults
+  --testget4: test parsing with defaults
+    (an integer)
+  --testlist: test lists parsing
+    (default: '')
+    (a comma separated list)
+  --[no]testnone: test boolean parsing
+  --testspacelist: tests space lists parsing
+    (default: '')
+    (a whitespace separated list)
+  --x: how eXtreme to be
+    (default: '3')
+    (an integer)
+  -z,--[no]zoom1: runhelp z1
+    (default: 'false')"""
+
+    if help != expected_help:
+      print "Error: FLAGS.MainModuleHelp() didn't return the expected result."
+      print "Got:"
+      print help
+      print "[End of got]"
+
+      help_lines = help.split('\n')
+      expected_help_lines = expected_help.split('\n')
+
+      num_help_lines = len(help_lines)
+      num_expected_help_lines = len(expected_help_lines)
+
+      if num_help_lines != num_expected_help_lines:
+        print "Number of help lines = %d, expected %d" % (
+            num_help_lines, num_expected_help_lines)
+
+      num_to_match = min(num_help_lines, num_expected_help_lines)
+
+      for i in range(num_to_match):
+        if help_lines[i] != expected_help_lines[i]:
+          print "One discrepancy: Got:"
+          print help_lines[i]
+          print "Expected:"
+          print expected_help_lines[i]
+          break
+      else:
+        # If we got here, found no discrepancy, print first new line.
+        if num_help_lines > num_expected_help_lines:
+          print "New help line:"
+          print help_lines[num_expected_help_lines]
+        elif num_expected_help_lines > num_help_lines:
+          print "Missing expected help line:"
+          print expected_help_lines[num_help_lines]
+        else:
+          print "Bug in this test -- discrepancy detected but not found."
+
+      self.fail()
+
+  def test_create_flag_errors(self):
+    # Since the exception classes are exposed, nothing stops users
+    # from creating their own instances. This test makes sure that
+    # people modifying the flags module understand that the external
+    # mechanisms for creating the exceptions should continue to work.
+    e = flags.FlagsError()
+    e = flags.FlagsError("message")
+    e = flags.DuplicateFlag()
+    e = flags.DuplicateFlag("message")
+    e = flags.IllegalFlagValue()
+    e = flags.IllegalFlagValue("message")
+    e = flags.UnrecognizedFlag()
+    e = flags.UnrecognizedFlag("message")
+
+def main():
+  unittest.main()
 
 if __name__ == '__main__':
-  unittest.main()
+  main()
diff --git a/python/setup.py b/python/setup.py
index 79f7554..f82c4fb 100755
--- a/python/setup.py
+++ b/python/setup.py
@@ -32,7 +32,7 @@
 from distutils.core import setup
 
 setup(name='gflags',
-      version='0.6',
+      version='0.8',
       description='Google Commandline Flags Module',
       license='BSD',
       author='Google Inc.',
diff --git a/src/gflags.cc b/src/gflags.cc
index c14e120..78aad91 100644
--- a/src/gflags.cc
+++ b/src/gflags.cc
@@ -40,7 +40,6 @@
 #include <errno.h>
 #include <string.h>
 #include <assert.h>
-#include <pthread.h>
 #include <fnmatch.h>
 #include <pthread.h>
 #include <string>
@@ -96,8 +95,7 @@
 // The help message indicating that the commandline flag has been
 // 'stripped'. It will not show up when doing "-help" and its
 // variants. The flag is stripped if STRIP_FLAG_HELP is set to 1
-// before including base/commandlineflags.h (or in
-// base/global_strip_options.h).
+// before including google/gflags.h.
 
 const char kStrippedFlagHelp[] = "\001\002\003\004 (unknown) \004\003\002\001";
 
@@ -105,7 +103,7 @@
 // Enables deferred processing of flags in dynamically loaded libraries.
 static bool allow_command_line_reparsing = false;
 
-static bool logging_is_probably_set_up = false;   // google3-specific
+static bool logging_is_probably_set_up = false;
 
 // This is used by the unittest to test error-exit code
 void (*commandlineflags_exitfunc)(int) = &exit;   // from stdlib.h
@@ -114,7 +112,7 @@
 // FlagValue
 //    This represent the value a single flag might have.  The major
 //    functionality is to convert from a string to an object of a
-//    given type, and back.
+//    given type, and back.  Thread-compatible.
 // --------------------------------------------------------------------
 
 class FlagValue {
@@ -375,21 +373,19 @@
 const char* CommandLineFlag::CleanFileName() const {
   // Compute top-level directory & file that this appears in
   // search full path backwards.
-  // Stop going backwards at kGoogle; and skip by the first slash.
-  // E.g.
-  //   filename_where_defined = "froogle/wrapping/autowrap/clustering/**.cc"
-  //   filename_where_defined = "file/util/fileutil.cc"
-  static const char kGoogle[] = "";    // can set this to whatever
+  // Stop going backwards at kRootDir; and skip by the first slash.
+  static const char kRootDir[] = "";    // can set this to root directory,
+                                        // e.g. "myproject"
 
-  if (sizeof(kGoogle)-1 == 0)          // no prefix to strip
+  if (sizeof(kRootDir)-1 == 0)          // no prefix to strip
     return filename();
 
   const char* clean_name = filename() + strlen(filename()) - 1;
   while ( clean_name > filename() ) {
     if (*clean_name == PATH_SEPARATOR) {
-      if (strncmp(clean_name, kGoogle, sizeof(kGoogle)-1) == 0) {
-        // ".../google/base/logging.cc" ==> "base/logging.cc"
-        clean_name += sizeof(kGoogle)-1;    // past "/google/"
+      if (strncmp(clean_name, kRootDir, sizeof(kRootDir)-1) == 0) {
+        // ".../myproject/base/logging.cc" ==> "base/logging.cc"
+        clean_name += sizeof(kRootDir)-1;    // past "/myproject/"
         break;
       }
     }
@@ -790,7 +786,7 @@
 }
 const char* ProgramInvocationShortName() {        // like the GNU libc fn
   const char* slash = strrchr(argv0, '/');
-#ifdef OS_WINDOWS
+#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
   if (!slash)  slash = strrchr(argv0, '\\');
 #endif
   return slash ? slash + 1 : argv0;
@@ -939,7 +935,8 @@
     char* arg = (*argv)[i];
 
     // Like getopt(), we permute non-option flags to be at the end.
-    if (arg[0] != '-') {           // must be a program argument
+    if (arg[0] != '-' ||           // must be a program argument
+        (arg[0] == '-' && arg[1] == '\0')) {  // "-" is an argument, not a flag
       memmove((*argv) + i, (*argv) + i+1, (*argc - (i+1)) * sizeof((*argv)[i]));
       (*argv)[*argc-1] = arg;      // we go last
       first_nonopt--;              // we've been pushed onto the stack
@@ -950,7 +947,7 @@
     if (arg[0] == '-') arg++;      // allow leading '-'
     if (arg[0] == '-') arg++;      // or leading '--'
 
-    // - and -- alone mean what they do for GNU: stop options parsing
+    // -- alone means what it does for GNU: stop options parsing
     if (*arg == '\0') {
       first_nonopt = i+1;
       break;
diff --git a/src/gflags_reporting.cc b/src/gflags_reporting.cc
index 981dccd..e8099fb 100644
--- a/src/gflags_reporting.cc
+++ b/src/gflags_reporting.cc
@@ -37,8 +37,8 @@
 // reporting flags, but we also have flags like --helpxml, etc.
 //
 // There's only one function that's meant to be called externally:
-// HandleCommandLineHelpFlags().  (Well, actually,
-// ShowUsageWithFlags() and ShowUsageWithFlagsRestrict() can be called
+// HandleCommandLineHelpFlags().  (Well, actually, ShowUsageWithFlags(),
+// ShowUsageWithFlagsRestrict(), and DescribeOneFlag() can be called
 // externally too, but there's little need for it.)  These are all
 // declared in the main commandlineflags.h header file.
 //
@@ -110,7 +110,7 @@
 
 // Create a descriptive string for a flag.
 // Goes to some trouble to make pretty line breaks.
-static string DescribeOneFlag(const CommandLineFlagInfo& flag) {
+string DescribeOneFlag(const CommandLineFlagInfo& flag) {
   string main_part = (string("    -") + flag.name +
                       " (" + flag.description + ')');
   const char* c_string = main_part.c_str();
@@ -242,8 +242,8 @@
 
 // Show help for every filename which matches any of the target substrings.
 // If substrings is empty, shows help for every file. If a flag's help message
-// has been stripped (e.g. by adding '#define STRIP_FLAG_HELP 1' to
-// base/global_strip_options.h), then this flag will not be displayed by
+// has been stripped (e.g. by adding '#define STRIP_FLAG_HELP 1' before
+// including google/gflags.h), then this flag will not be displayed by
 // '--help' and its variants.
 static void ShowUsageWithFlagsMatching(const char *argv0,
                                        const vector<string> &substrings) {
diff --git a/src/gflags_unittest.cc b/src/gflags_unittest.cc
index 8a8db97..03219c6 100644
--- a/src/gflags_unittest.cc
+++ b/src/gflags_unittest.cc
@@ -35,6 +35,7 @@
 
 #include "config.h"
 #include <stdio.h>
+#include <stdlib.h>     // for &exit
 #include <string.h>
 #include <unistd.h>     // for unlink()
 #include <sys/stat.h>   // for mkdir()
@@ -46,8 +47,7 @@
 using std::vector;
 using std::string;
 
-// Returns the number of elements in an array.  We don't use the safer
-// version in base/basictypes.h as commandlineflags is open-sourced.
+// Returns the number of elements in an array.
 #define GET_ARRAY_SIZE(arr) (sizeof(arr)/sizeof(*(arr)))
 
 DECLARE_string(tryfromenv);   // in commandlineflags.cc
@@ -1109,6 +1109,43 @@
   EXPECT_EQ(3, ParseTestFlag(false, GET_ARRAY_SIZE(argv) - 1, argv));
 }
 
+TEST(ParseCommandLineFlagsAndDashArgs, TwoDashArgFirst) {
+  const char* argv[] = {
+    "my_test",
+    "--",
+    "--test_flag=0",
+    NULL,
+  };
+
+  EXPECT_EQ(-1, ParseTestFlag(true, GET_ARRAY_SIZE(argv) - 1, argv));
+  EXPECT_EQ(-1, ParseTestFlag(false, GET_ARRAY_SIZE(argv) - 1, argv));
+}
+
+TEST(ParseCommandLineFlagsAndDashArgs, TwoDashArgMiddle) {
+  const char* argv[] = {
+    "my_test",
+    "--test_flag=7",
+    "--",
+    "--test_flag=0",
+    NULL,
+  };
+
+  EXPECT_EQ(7, ParseTestFlag(true, GET_ARRAY_SIZE(argv) - 1, argv));
+  EXPECT_EQ(7, ParseTestFlag(false, GET_ARRAY_SIZE(argv) - 1, argv));
+}
+
+TEST(ParseCommandLineFlagsAndDashArgs, OneDashArg) {
+  const char* argv[] = {
+    "my_test",
+    "-",
+    "--test_flag=0",
+    NULL,
+  };
+
+  EXPECT_EQ(0, ParseTestFlag(true, GET_ARRAY_SIZE(argv) - 1, argv));
+  EXPECT_EQ(0, ParseTestFlag(false, GET_ARRAY_SIZE(argv) - 1, argv));
+}
+
 static int Main(int argc, char **argv) {
   // We need to call SetArgv before InitGoogle, so our "test" argv will
   // win out over this executable's real argv.  That makes running this
diff --git a/src/google/gflags.h.in b/src/google/gflags.h.in
index 285a53f..8d3921d 100644
--- a/src/google/gflags.h.in
+++ b/src/google/gflags.h.in
@@ -50,6 +50,24 @@
 //
 // For more details, see
 //    doc/gflags.html
+//
+// --- A note about thread-safety:
+//
+// We describe many functions in this routine as being thread-hostile,
+// thread-compatible, or thread-safe.  Here are the meanings we use:
+//
+// thread-safe: it is safe for multiple threads to call this routine
+//   (or, when referring to a class, methods of this class)
+//   concurrently.
+// thread-hostile: it is not safe for multiple threads to call this
+//   routine (or methods of this class) concurrently.  In gflags,
+//   most thread-hostile routines are intended to be called early in,
+//   or even before, main() -- that is, before threads are spawned.
+// thread-compatible: it is safe for multiple threads to read from
+//   this variable (when applied to variables), or to call const
+//   methods of this class (when applied to classes), as long as no
+//   other thread is writing to the variable or calling non-const
+//   methods of this class.
 
 #ifndef BASE_COMMANDLINEFLAGS_H__
 #define BASE_COMMANDLINEFLAGS_H__
@@ -120,13 +138,22 @@
 extern void ShowUsageWithFlags(const char *argv0);  // what --help does
 extern void ShowUsageWithFlagsRestrict(const char *argv0, const char *restrict);
 
+// Create a descriptive string for a flag.
+// Goes to some trouble to make pretty line breaks.
+extern std::string DescribeOneFlag(const CommandLineFlagInfo& flag);
+
+// Thread-hostile; meant to be called before any threads are spawned.
 extern void SetArgv(int argc, const char** argv);
+// The following functions are thread-safe as long as SetArgv() is
+// only called before any threads start.
 extern const std::vector<std::string>& GetArgvs();  // all of argv as a vector
 extern const char* GetArgv();               // all of argv as a string
 extern const char* GetArgv0();              // only argv0
 extern uint32 GetArgvSum();                 // simple checksum of argv
 extern const char* ProgramInvocationName(); // argv0, or "UNKNOWN" if not set
 extern const char* ProgramInvocationShortName();   // basename(argv0)
+// ProgramUsage() is thread-safe as long as SetUsageMessage() is only
+// called before any threads start.
 extern const char* ProgramUsage();          // string set by SetUsageMessage()
 
 
@@ -135,6 +162,8 @@
 // or whatever, and set them by calling "FLAGS_foo = bar" (or, more
 // commonly, via the DEFINE_foo macro).  But if you need a bit more
 // control, we have programmatic ways to get/set the flags as well.
+// These programmatic ways to access flags are thread-safe, but direct
+// access is only thread-compatible.
 
 // Return true iff the flagname was found.
 // OUTPUT is set to the flag's value, or unchanged if we return false.
@@ -196,6 +225,8 @@
 // work is done in the constructor and destructor, so in the standard
 // usage example above, the compiler would complain that it's an
 // unused variable.
+//
+// This class is thread-safe.
 
 class FlagSaver {
  public:
@@ -251,6 +282,7 @@
 //   usage += argv[0] + " <uselessarg1> <uselessarg2>";
 //   SetUsageMessage(usage);
 // Do not include commandline flags in the usage: we do that for you!
+// Thread-hostile; meant to be called before any threads are spawned.
 extern void SetUsageMessage(const std::string& usage);
 
 // Looks for flags in argv and parses them.  Rearranges argv to put
@@ -280,8 +312,10 @@
 // it's too late to change that now. :-(
 extern void HandleCommandLineHelpFlags();   // in commandlineflags_reporting.cc
 
-// Allow command line reparsing.  Disables the error normaly generated
-// when an unknown flag is found, since it may be found in a later parse.
+// Allow command line reparsing.  Disables the error normally
+// generated when an unknown flag is found, since it may be found in a
+// later parse.  Thread-hostile; meant to be called before any threads
+// are spawned.
 extern void AllowCommandLineReparsing();
 
 // Reparse the flags that have not yet been recognized.