Enabled relative includes in glslc.

glslc will now by default try and resolve #included files relative to
the current file first, only after that fails will it try to include
files based on the -I parameters.
diff --git a/glslc/README.asciidoc b/glslc/README.asciidoc
index 5ed1f91..1e47d7b 100644
--- a/glslc/README.asciidoc
+++ b/glslc/README.asciidoc
@@ -210,7 +210,10 @@
 
 `-I` adds the specified directory to the search path for include files.
 
-WARNING: Implementation is not complete yet.
+Only `""` style includes are permitted. When searching for included files, first
+the directory of the current file is attempted. If this fails each directory
+supplied via `-I` on the command line is searched in the given order for the
+file.
 
 === Code Generation Options
 
@@ -386,3 +389,11 @@
 
 The `GL_GOOGLE_cpp_style_line_directive` extension is implicitly turned on by
 the `GL_GOOGLE_include_directive` extension.
+
+It is invalid to have any '\' or '/' characters in any filename provided to
+an `#include` directive. The presence of any such characters may lead to
+unexpected behavior on different systems.
+
+Furthermore it is not possible to escape any characters in an `#include`
+directive and as such, any special characters that would have to be escaped in
+C may not show up in file names either.
diff --git a/glslc/src/file_includer.cc b/glslc/src/file_includer.cc
index 8af500f..ea42e81 100644
--- a/glslc/src/file_includer.cc
+++ b/glslc/src/file_includer.cc
@@ -25,13 +25,16 @@
   return new shaderc_include_result{"", 0, message, strlen(message)};
 }
 
-shaderc_include_result* FileIncluder::GetInclude(const char* requested_source,
-                                                 shaderc_include_type,
-                                                 const char*, size_t) {
-  // TODO(dneto): Be sensitive to requesting_source
-  // We don't actually care about the include type.
+shaderc_include_result* FileIncluder::GetInclude(
+    const char* requested_source, shaderc_include_type include_type,
+    const char* requesting_source, size_t) {
+
   const std::string full_path =
-      file_finder_.FindReadableFilepath(requested_source);
+      (include_type == shaderc_include_type_relative)
+          ? file_finder_.FindRelativeReadableFilepath(requesting_source,
+                                                      requested_source)
+          : file_finder_.FindReadableFilepath(requested_source);
+
   if (full_path.empty())
     return MakeErrorIncludeResult("Cannot find or open include file.");
 
diff --git a/glslc/src/main.cc b/glslc/src/main.cc
index 5f84c87..9482949 100644
--- a/glslc/src/main.cc
+++ b/glslc/src/main.cc
@@ -112,8 +112,6 @@
   bool success = true;
   bool has_stdin_input = false;
 
-  compiler.AddIncludeDirectory("");
-
   for (int i = 1; i < argc; ++i) {
     const string_piece arg = argv[i];
     if (arg == "--help") {
diff --git a/glslc/test/glslc_test_framework.py b/glslc/test/glslc_test_framework.py
index e6f2f52..6a2a3b9 100755
--- a/glslc/test/glslc_test_framework.py
+++ b/glslc/test/glslc_test_framework.py
@@ -269,6 +269,10 @@
                 setattr(
                     self.test, expectation_name,
                     ''.join(expanded_expections))
+            elif isinstance(expectation, PlaceHolder):
+                setattr(self.test, expectation_name,
+                        expectation.instantiate_for_expectation(self))
+
 
     def tearDown(self):
         """Removes the directory if we were not instructed to do otherwise."""
diff --git a/glslc/test/include.py b/glslc/test/include.py
index dfb1aa0..a965032 100644
--- a/glslc/test/include.py
+++ b/glslc/test/include.py
@@ -14,6 +14,7 @@
 
 import expect
 from glslc_test_framework import inside_glslc_testsuite
+from placeholder import SpecializedString
 from environment import File, Directory
 
 
@@ -306,3 +307,255 @@
         "b.glsl:1: error: '#version' : must occur first in shader\n",
         '1 error generated.\n'
     ]
+
+
+@inside_glslc_testsuite('Include')
+class VerifyRelativeInclude(expect.StdoutMatch):
+    """Tests #including a relative sibling."""
+
+    environment = Directory('.', [
+        File('a.vert', '#version 140\ncontent a\n#include "foo/b.glsl"\n'),
+        Directory('foo', [
+            File('b.glsl', '#include "c.glsl"\ncontent b\n'),
+            File('c.glsl', 'content c\n')
+        ])])
+
+    glslc_args = ['-E', 'a.vert']
+
+    expected_stdout = \
+"""#version 140
+#extension GL_GOOGLE_include_directive : enable
+#line 0 "a.vert"
+
+content a
+#line 0 "foo/b.glsl"
+#line 0 "foo/c.glsl"
+ content c
+#line 1 "foo/b.glsl"
+ content b
+#line 3 "a.vert"
+
+"""
+
+@inside_glslc_testsuite('Include')
+class VerifyNestedRelativeInclude(expect.StdoutMatch):
+    """Tests #including a relative child file."""
+
+    environment = Directory('.', [
+        File('a.vert', '#version 140\ncontent a\n#include "foo/b.glsl"\n'),
+        Directory('foo', [
+            File('b.glsl', '#include "bar/c.glsl"\ncontent b\n'),
+            Directory('bar', [
+                File('c.glsl', 'content c\n')
+            ])
+        ])
+    ])
+
+    glslc_args = ['-E', 'a.vert']
+
+    expected_stdout = \
+"""#version 140
+#extension GL_GOOGLE_include_directive : enable
+#line 0 "a.vert"
+
+content a
+#line 0 "foo/b.glsl"
+#line 0 "foo/bar/c.glsl"
+ content c
+#line 1 "foo/b.glsl"
+ content b
+#line 3 "a.vert"
+
+"""
+
+
+@inside_glslc_testsuite('Include')
+class VerifyRelativeIncludeWithDashI(expect.StdoutMatch):
+    """Tests #including a relative file from a -I directory."""
+
+    environment = Directory('.', [
+        File('a.vert', '#version 140\ncontent a\n#include "bar/b.glsl"\n'),
+        Directory('foo', [
+            Directory('bar', [
+                File('b.glsl', '#include "c.glsl"\ncontent b\n'),
+            ]),
+            File('c.glsl', 'content c\n')
+        ])
+    ])
+
+    glslc_args = ['-E', 'a.vert', '-Ifoo']
+
+    expected_stdout = \
+"""#version 140
+#extension GL_GOOGLE_include_directive : enable
+#line 0 "a.vert"
+
+content a
+#line 0 "foo/bar/b.glsl"
+#line 0 "foo/c.glsl"
+ content c
+#line 1 "foo/bar/b.glsl"
+ content b
+#line 3 "a.vert"
+
+"""
+
+
+@inside_glslc_testsuite('Include')
+class VerifyRelativeOverridesDashI(expect.StdoutMatch):
+    """Tests that relative includes override -I parameters."""
+
+    environment = Directory('.', [
+        File('a.vert', '#version 140\ncontent a\n#include "b.glsl"\n'),
+        File('b.glsl', 'content base_b\n'),
+        Directory('foo', [
+            File('b.glsl', '#include "c.glsl"\ncontent b\n'),
+            File('c.glsl', 'content c\n')
+        ])
+    ])
+
+    glslc_args = ['-E', 'a.vert', '-Ifoo']
+
+    expected_stdout = \
+"""#version 140
+#extension GL_GOOGLE_include_directive : enable
+#line 0 "a.vert"
+
+content a
+#line 0 "b.glsl"
+ content base_b
+#line 3 "a.vert"
+
+"""
+
+
+@inside_glslc_testsuite('Include')
+class VerifyRelativeParent(expect.StdoutMatch):
+    """Tests #including a parent file."""
+
+    environment = Directory('.', [
+        File('a.vert', '#version 140\ncontent a\n#include "b.glsl"\n'),
+        File('c.glsl', 'content c\n'),
+        Directory('foo', [
+            File('b.glsl', '#include "../c.glsl"\ncontent b\n')
+        ])
+    ])
+
+    glslc_args = ['-E', 'a.vert', '-Ifoo']
+
+    expected_stdout = \
+"""#version 140
+#extension GL_GOOGLE_include_directive : enable
+#line 0 "a.vert"
+
+content a
+#line 0 "foo/b.glsl"
+#line 0 "foo/../c.glsl"
+ content c
+#line 1 "foo/b.glsl"
+ content b
+#line 3 "a.vert"
+
+"""
+
+
+@inside_glslc_testsuite('Include')
+class VerifyRelativeNeighbourDirectory(expect.StdoutMatch):
+    """Tests #including a relative file in a neighbour directory."""
+
+    environment = Directory('.', [
+        File('a.vert', '#version 140\ncontent a\n#include "foo/b.glsl"\n'),
+        Directory('foo', [
+            File('b.glsl', '#include "../bar/c.glsl"\ncontent b\n')
+        ]),
+        Directory('bar', [
+            File('c.glsl', 'content c\n')
+        ])
+    ])
+
+    glslc_args = ['-E', 'a.vert']
+
+    expected_stdout = \
+"""#version 140
+#extension GL_GOOGLE_include_directive : enable
+#line 0 "a.vert"
+
+content a
+#line 0 "foo/b.glsl"
+#line 0 "foo/../bar/c.glsl"
+ content c
+#line 1 "foo/b.glsl"
+ content b
+#line 3 "a.vert"
+
+"""
+
+
+@inside_glslc_testsuite('Include')
+class VerifyRelativeOnlyToSelf(expect.ErrorMessage):
+    """Tests that a relative includes are only relative to yourself."""
+
+    environment = Directory('.', [
+        File('a.vert', '#version 140\ncontent a\n#include "foo/b.glsl"\n'),
+        File('c.glsl', 'content c\n'),
+        Directory('foo', [
+            File('b.glsl', '#include "c.glsl"\ncontent b\n')
+        ]),
+    ])
+
+    glslc_args = ['-E', 'a.vert']
+
+    expected_error = [
+        "foo/b.glsl:1: error: '#include' : Cannot find or open include file.\n",
+        '1 error generated.\n'
+    ]
+
+
+@inside_glslc_testsuite('Include')
+class VerifyRelativeFromAbsolutePath(expect.StdoutMatch):
+    """Tests that absolute files can relatively include."""
+
+    environment = Directory('.', [
+        File('a.vert', '#version 140\ncontent a\n#include "b.glsl"\n'),
+        File('b.glsl', 'content b\n')
+    ])
+
+    glslc_args = ['-E', SpecializedString('$directory/a.vert')]
+
+    expected_stdout = SpecializedString(
+"""#version 140
+#extension GL_GOOGLE_include_directive : enable
+#line 0 "$directory/a.vert"
+
+content a
+#line 0 "$directory/b.glsl"
+ content b
+#line 3 "$directory/a.vert"
+
+""")
+
+
+@inside_glslc_testsuite('Include')
+class VerifyDashIAbsolutePath(expect.StdoutMatch):
+    """Tests that -I parameters can be absolute paths."""
+
+    environment = Directory('.', [
+        File('a.vert', '#version 140\ncontent a\n#include "b.glsl"\n'),
+        Directory('foo', {
+            File('b.glsl', 'content b\n')
+        })
+    ])
+
+    glslc_args = ['-E', 'a.vert', '-I', SpecializedString('$directory/foo')]
+
+    expected_stdout = SpecializedString(
+"""#version 140
+#extension GL_GOOGLE_include_directive : enable
+#line 0 "a.vert"
+
+content a
+#line 0 "$directory/foo/b.glsl"
+ content b
+#line 3 "a.vert"
+
+""")
diff --git a/glslc/test/placeholder.py b/glslc/test/placeholder.py
index 2cb8e50..9c5bcfc 100644
--- a/glslc/test/placeholder.py
+++ b/glslc/test/placeholder.py
@@ -22,6 +22,7 @@
 """
 import os
 import tempfile
+from string import Template
 
 
 class PlaceHolderException(Exception):
@@ -115,3 +116,24 @@
 
     def instantiate_for_expectation(self, testcase):
         return os.path.join(testcase.directory, self.filename)
+
+
+class SpecializedString(PlaceHolder):
+    """Returns a string that has been specialized based on TestCase.
+
+    The string is specialized by expanding it as a string.Template
+    with all of the specialization being done with each $param replaced
+    by the associated member on TestCase.
+    """
+
+    def __init__(self, filename):
+        assert isinstance(filename, str)
+        assert filename != ''
+        self.filename = filename
+
+    def instantiate_for_glslc_args(self, testcase):
+        return Template(self.filename).substitute(vars(testcase))
+
+    def instantiate_for_expectation(self, testcase):
+        return Template(self.filename).substitute(vars(testcase))
+
diff --git a/libshaderc_util/include/libshaderc_util/counting_includer.h b/libshaderc_util/include/libshaderc_util/counting_includer.h
index c583e20..d341ad1 100644
--- a/libshaderc_util/include/libshaderc_util/counting_includer.h
+++ b/libshaderc_util/include/libshaderc_util/counting_includer.h
@@ -43,7 +43,8 @@
       const char* requesting_source,
       size_t include_depth) final {
     ++num_include_directives_;
-    return include_delegate(requested_source, type, requesting_source, include_depth);
+    return include_delegate(requested_source, type, requesting_source,
+                            include_depth);
   }
 
   // Releases the given IncludeResult.
diff --git a/libshaderc_util/include/libshaderc_util/file_finder.h b/libshaderc_util/include/libshaderc_util/file_finder.h
index 8aec788..2c1c9d1 100644
--- a/libshaderc_util/include/libshaderc_util/file_finder.h
+++ b/libshaderc_util/include/libshaderc_util/file_finder.h
@@ -33,14 +33,18 @@
   // If a search_path() element is non-empty and not ending in a slash, then a
   // slash is inserted between it and filename before its search attempt. An
   // empty string in search_path() means that the filename is tried as-is.
-  //
-  // Usage advice: when searching #include files, you almost certainly want ""
-  // to be the first element in search_path().  That way both relative and
-  // absolute filenames will work as expected.  Note that a "." entry on the
-  // search path may be prepended to an absolute filename (eg, "/a/b/c") to
-  // create a relative result (eg, ".//a/b/c").
   std::string FindReadableFilepath(const std::string& filename) const;
 
+  // Searches for a read-openable file based on filename, which must be
+  // non-empty. The search is first attempted as a path relative to
+  // the requesting_file parameter. If no file is found relative to the
+  // requesting_file then this acts as FindReadableFilepath does. If
+  // requesting_file does not contain a '/' or a '\' character then it is
+  // assumed to be a filename and the request will be relative to the
+  // current directory.
+  std::string FindRelativeReadableFilepath(const std::string& requesting_file,
+                                           const std::string& filename) const;
+
   // Search path for Find().  Users may add/remove elements as desired.
   std::vector<std::string>& search_path() { return search_path_; }
 
diff --git a/libshaderc_util/src/file_finder.cc b/libshaderc_util/src/file_finder.cc
index df926b6..d25c611 100644
--- a/libshaderc_util/src/file_finder.cc
+++ b/libshaderc_util/src/file_finder.cc
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 #include "libshaderc_util/file_finder.h"
+#include "libshaderc_util/string_piece.h"
 
 #include <cassert>
 #include <fstream>
@@ -21,7 +22,7 @@
 namespace {
 
 // Returns "" if path is empty or ends in '/'.  Otherwise, returns "/".
-std::string MaybeSlash(const std::string& path) {
+std::string MaybeSlash(const shaderc_util::string_piece& path) {
   return (path.empty() || path.back() == '/') ? "" : "/";
 }
 
@@ -42,4 +43,29 @@
   return "";
 }
 
+std::string FileFinder::FindRelativeReadableFilepath(
+    const std::string& requesting_file, const std::string& filename) const {
+  assert(!filename.empty());
+
+  string_piece dir_name(requesting_file);
+
+  size_t last_slash = requesting_file.find_last_of("/\\");
+  if (last_slash != std::string::npos) {
+    dir_name = string_piece(requesting_file.c_str(),
+                            requesting_file.c_str() + last_slash);
+  }
+
+  if (dir_name.size() == requesting_file.size()) {
+    dir_name.clear();
+  }
+
+  static const auto for_reading = std::ios_base::in;
+  std::filebuf opener;
+  const std::string relative_filename =
+      dir_name.str() + MaybeSlash(dir_name) + filename;
+  if (opener.open(relative_filename, for_reading)) return relative_filename;
+
+  return FindReadableFilepath(filename);
+}
+
 }  // namespace shaderc_util