aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO2
-rw-r--r--cutl/fs/path.cxx18
-rw-r--r--cutl/fs/path.hxx97
-rw-r--r--cutl/fs/path.txx96
-rw-r--r--cutl/makefile2
-rw-r--r--doc/components.txt2
-rw-r--r--tests/fs/makefile18
-rw-r--r--tests/fs/path/driver.cxx67
-rw-r--r--tests/fs/path/makefile70
-rw-r--r--tests/makefile2
10 files changed, 373 insertions, 1 deletions
diff --git a/TODO b/TODO
index 25de54b..0c0e18e 100644
--- a/TODO
+++ b/TODO
@@ -1,2 +1,4 @@
@@ Common exception class (print typeid(*this).name () in what()).
@@ Add memprof?
+@@ path::base() and ".." & "." special directories
+
diff --git a/cutl/fs/path.cxx b/cutl/fs/path.cxx
new file mode 100644
index 0000000..6e295c6
--- /dev/null
+++ b/cutl/fs/path.cxx
@@ -0,0 +1,18 @@
+// file : cutl/fs/path.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009 Code Synthesis Tools CC
+// license : MIT; see accompanying LICENSE file
+
+#include <cutl/fs/path.hxx>
+
+namespace cutl
+{
+ namespace fs
+ {
+ char const* invalid_path::
+ what () const throw ()
+ {
+ return "invalid filesystem path";
+ }
+ }
+}
diff --git a/cutl/fs/path.hxx b/cutl/fs/path.hxx
new file mode 100644
index 0000000..a79fc5c
--- /dev/null
+++ b/cutl/fs/path.hxx
@@ -0,0 +1,97 @@
+// file : cutl/fs/path.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009 Code Synthesis Tools CC
+// license : MIT; see accompanying LICENSE file
+
+#ifndef CUTL_FS_PATH_HXX
+#define CUTL_FS_PATH_HXX
+
+#include <string>
+#include <iosfwd>
+
+namespace cutl
+{
+ namespace fs
+ {
+ struct invalid_path: std::exception
+ {
+ virtual char const*
+ what () const throw ();
+ };
+
+ template <typename C>
+ class basic_path;
+
+ typedef basic_path<char> path;
+ typedef basic_path<wchar_t> wpath;
+
+ template <typename C>
+ class basic_path
+ {
+ public:
+ typedef std::basic_string<C> string_type;
+ typedef typename string_type::size_type size_type;
+
+ explicit
+ basic_path (C const* s)
+ : path_ (s)
+ {
+ init (false);
+ }
+
+ explicit
+ basic_path (string_type const& s)
+ : path_ (s)
+ {
+ init (false);
+ }
+
+ public:
+ basic_path
+ leaf () const;
+
+ basic_path
+ directory () const;
+
+ basic_path
+ base () const;
+
+ public:
+ basic_path
+ operator/ (basic_path const&);
+
+ public:
+ string_type
+ string () const
+ {
+ return path_.empty () ? string_type (1, '/') : path_;
+ }
+
+ private:
+ void
+ init (bool internal);
+
+ // Assume internal format.
+ //
+ basic_path (C const* s, size_type n)
+ : path_ (s, n)
+ {
+ init (true);
+ }
+
+ private:
+ string_type path_;
+ };
+
+ template <typename C>
+ inline std::basic_ostream<C>&
+ operator<< (std::basic_ostream<C>& os, basic_path<C> const& p)
+ {
+ return os << p.string ();
+ }
+ }
+}
+
+#include <cutl/fs/path.txx>
+
+#endif // CUTL_FS_PATH_HXX
diff --git a/cutl/fs/path.txx b/cutl/fs/path.txx
new file mode 100644
index 0000000..caff259
--- /dev/null
+++ b/cutl/fs/path.txx
@@ -0,0 +1,96 @@
+// file : cutl/fs/path.txx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009 Code Synthesis Tools CC
+// license : MIT; see accompanying LICENSE file
+
+namespace cutl
+{
+ namespace fs
+ {
+ template <typename C>
+ basic_path<C> basic_path<C>::
+ leaf () const
+ {
+ size_type n (path_.size ()), i (n);
+
+ for (; i > 0; --i)
+ {
+ if (path_[i - 1] == '/' || path_[i - 1] == '\\')
+ break;
+ }
+
+ return i != 0 ? basic_path (path_.c_str () + i, n - i) : *this;
+ }
+
+ template <typename C>
+ basic_path<C> basic_path<C>::
+ directory () const
+ {
+ size_type i (path_.size ());
+
+ for (; i > 0; --i)
+ {
+ if (path_[i - 1] == '/' || path_[i - 1] == '\\')
+ break;
+ }
+
+ return i != 0 ? basic_path (path_.c_str (), i - 1) : *this;
+ }
+
+ template <typename C>
+ basic_path<C> basic_path<C>::
+ base () const
+ {
+ size_type i (path_.size ());
+
+ for (; i > 0; --i)
+ {
+ if (path_[i - 1] == '.')
+ break;
+
+ if (path_[i - 1] == '/' || path_[i - 1] == '\\')
+ {
+ i = 0;
+ break;
+ }
+ }
+
+ // Weed out paths like ".txt" and "/.txt"
+ //
+ if (i > 1 && path_[i - 2] != '/' && path_[i - 2] != '\\')
+ {
+ return basic_path (path_.c_str (), i - 1);
+ }
+ else
+ return *this;
+ }
+
+ template <typename C>
+ basic_path<C> basic_path<C>::
+ operator/ (basic_path<C> const& r)
+ {
+ if (r.path_.empty ())
+ throw invalid_path ();
+
+ basic_path<C> x (*this);
+ x.path_ += '/';
+ x.path_ += r.path_;
+ return x;
+ }
+
+ template <typename C>
+ void basic_path<C>::
+ init (bool internal)
+ {
+ if (!internal && path_.empty ())
+ throw invalid_path ();
+
+ // Strip trailing slashes. This way empty string represents
+ // root directory.
+ //
+ size_type n (path_.size ());
+ for (; n > 0 && (path_[n - 1] == '/' || path_[n - 1] == '\\'); --n) ;
+ path_.resize (n);
+ }
+ }
+}
diff --git a/cutl/makefile b/cutl/makefile
index 635524e..f5adfce 100644
--- a/cutl/makefile
+++ b/cutl/makefile
@@ -7,6 +7,8 @@ include $(dir $(lastword $(MAKEFILE_LIST)))../build/bootstrap.make
cxx_tun := shared-ptr/base.cxx
+cxx_tun += fs/path.cxx
+
cxx_tun += \
compiler/context.cxx \
compiler/type-info.cxx \
diff --git a/doc/components.txt b/doc/components.txt
index cdb1920..72a340f 100644
--- a/doc/components.txt
+++ b/doc/components.txt
@@ -3,4 +3,6 @@ Components
core: meta/ shared-ptr/ shared-ptr.hxx
container: container/
compiler: compiler/
+ fs: fs/
+
diff --git a/tests/fs/makefile b/tests/fs/makefile
new file mode 100644
index 0000000..071c394
--- /dev/null
+++ b/tests/fs/makefile
@@ -0,0 +1,18 @@
+# file : tests/fs/makefile
+# author : Boris Kolpackov <boris@codesynthesis.com>
+# copyright : Copyright (c) 2009 Code Synthesis Tools CC
+# license : MIT; see accompanying LICENSE file
+
+include $(dir $(lastword $(MAKEFILE_LIST)))../../build/bootstrap.make
+
+tests := path
+
+default := $(out_base)/
+test := $(out_base)/.test
+clean := $(out_base)/.clean
+
+$(default): $(addprefix $(out_base)/,$(addsuffix /,$(tests)))
+$(test): $(addprefix $(out_base)/,$(addsuffix /.test,$(tests)))
+$(clean): $(addprefix $(out_base)/,$(addsuffix /.clean,$(tests)))
+
+$(foreach t,$(tests),$(call import,$(src_base)/$t/makefile))
diff --git a/tests/fs/path/driver.cxx b/tests/fs/path/driver.cxx
new file mode 100644
index 0000000..d758bde
--- /dev/null
+++ b/tests/fs/path/driver.cxx
@@ -0,0 +1,67 @@
+// file : tests/fs/path/driver.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009 Code Synthesis Tools CC
+// license : MIT; see accompanying LICENSE file
+
+#include <cassert>
+
+#include <cutl/fs/path.hxx>
+
+using namespace cutl::fs;
+
+int
+main ()
+{
+ // Construction.
+ //
+ try
+ {
+ path ("");
+ assert (false);
+ }
+ catch (invalid_path const&)
+ {
+ }
+
+ assert (path ("/").string () == "/");
+ assert (path ("//").string () == "/");
+ assert (path ("\\\\").string () == "/");
+ assert (path ("/\\").string () == "/");
+ assert (path ("C:").string () == "C:");
+ assert (path ("C:\\").string () == "C:");
+ assert (path ("/tmp/foo/").string () == "/tmp/foo");
+ assert (path ("C:\\tmp\\foo\\").string () == "C:\\tmp\\foo");
+
+ // leaf
+ //
+ assert (path ("/").leaf ().string () == "/");
+ assert (path ("C:").leaf ().string () == "C:");
+ assert (path ("/tmp").leaf ().string () == "tmp");
+ assert (path ("C:\\tmp").leaf ().string () == "tmp");
+ assert (path ("//tmp").leaf ().string () == "tmp");
+ assert (path ("C:\\\\tmp").leaf ().string () == "tmp");
+
+ // directory
+ //
+ assert (path ("/").directory ().string () == "/");
+ assert (path ("C:").directory ().string () == "C:");
+ assert (path ("/tmp").directory ().string () == "/");
+ assert (path ("//tmp").directory ().string () == "/");
+ assert (path ("C:\\tmp").directory ().string () == "C:");
+ assert (path ("C:\\\\tmp").directory ().string () == "C:");
+
+ // base
+ //
+ assert (path ("/").base ().string () == "/");
+ assert (path ("C:").base ().string () == "C:");
+ assert (path ("/foo.txt").base ().string () == "/foo");
+ assert (path ("C:\\foo.txt").base ().string () == "C:\\foo");
+ assert (path (".txt").base ().string () == ".txt");
+ assert (path ("/.txt").base ().string () == "/.txt");
+ assert (path ("foo.txt.orig").base ().string () == "foo.txt");
+
+ // operator/
+ //
+ assert ((path ("/") / path ("tmp")).string () == "/tmp");
+ assert ((path ("foo") / path ("bar")).string () == "foo/bar");
+}
diff --git a/tests/fs/path/makefile b/tests/fs/path/makefile
new file mode 100644
index 0000000..55bf89d
--- /dev/null
+++ b/tests/fs/path/makefile
@@ -0,0 +1,70 @@
+# file : tests/fs/path/makefile
+# author : Boris Kolpackov <boris@codesynthesis.com>
+# copyright : Copyright (c) 2009 Code Synthesis Tools CC
+# license : MIT; see accompanying LICENSE file
+
+include $(dir $(lastword $(MAKEFILE_LIST)))../../../build/bootstrap.make
+
+cxx_tun := driver.cxx
+
+#
+#
+cxx_obj := $(addprefix $(out_base)/,$(cxx_tun:.cxx=.o))
+cxx_od := $(cxx_obj:.o=.o.d)
+
+cutl.l := $(out_root)/cutl/cutl.l
+cutl.l.cpp-options := $(out_root)/cutl/cutl.l.cpp-options
+
+driver := $(out_base)/driver
+test := $(out_base)/.test
+clean := $(out_base)/.clean
+
+# Build.
+#
+$(driver): $(cxx_obj) $(cutl.l)
+$(cxx_obj) $(cxx_od): $(cutl.l.cpp-options)
+
+
+$(call include-dep,$(cxx_od))
+
+
+# Alias for default target.
+#
+$(out_base)/: $(driver)
+
+
+# Test.
+#
+$(test): $(driver)
+ $(call message,test $<,$<)
+
+
+# Clean.
+#
+$(clean): \
+ $(driver).o.clean \
+ $(addsuffix .cxx.clean,$(cxx_obj)) \
+ $(addsuffix .cxx.clean,$(cxx_od))
+
+
+# Generated .gitignore.
+#
+ifeq ($(out_base),$(src_base))
+$(driver): | $(out_base)/.gitignore
+
+$(out_base)/.gitignore: files := driver
+$(clean): $(out_base)/.gitignore.clean
+
+$(call include,$(bld_root)/git/gitignore.make)
+endif
+
+
+# How to.
+#
+$(call include,$(bld_root)/cxx/o-e.make)
+$(call include,$(bld_root)/cxx/cxx-o.make)
+$(call include,$(bld_root)/cxx/cxx-d.make)
+
+# Dependencies.
+#
+$(call import,$(src_root)/cutl/makefile)
diff --git a/tests/makefile b/tests/makefile
index ffbd8bd..e3873cb 100644
--- a/tests/makefile
+++ b/tests/makefile
@@ -5,7 +5,7 @@
include $(dir $(lastword $(MAKEFILE_LIST)))../build/bootstrap.make
-tests := compiler shared-ptr
+tests := compiler fs shared-ptr
default := $(out_base)/
test := $(out_base)/.test