From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 104343 invoked by alias); 1 Jun 2017 17:53:14 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 103139 invoked by uid 89); 1 Jun 2017 17:53:13 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-12.4 required=5.0 tests=AWL,BAYES_00,GIT_PATCH_2,GIT_PATCH_3,KAM_LAZY_DOMAIN_SECURITY,RCVD_IN_DNSWL_LOW autolearn=ham version=3.3.2 spammy=Components, Ie X-HELO: mx0a-001b2d01.pphosted.com Received: from mx0a-001b2d01.pphosted.com (HELO mx0a-001b2d01.pphosted.com) (148.163.156.1) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 01 Jun 2017 17:53:09 +0000 Received: from pps.filterd (m0098399.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.20/8.16.0.20) with SMTP id v51Hmk1U070677 for ; Thu, 1 Jun 2017 13:53:12 -0400 Received: from e06smtp15.uk.ibm.com (e06smtp15.uk.ibm.com [195.75.94.111]) by mx0a-001b2d01.pphosted.com with ESMTP id 2atpa6bske-1 (version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT) for ; Thu, 01 Jun 2017 13:53:11 -0400 Received: from localhost by e06smtp15.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Thu, 1 Jun 2017 18:53:09 +0100 Received: from b06cxnps4075.portsmouth.uk.ibm.com (9.149.109.197) by e06smtp15.uk.ibm.com (192.168.101.145) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Thu, 1 Jun 2017 18:53:07 +0100 Received: from d06av21.portsmouth.uk.ibm.com (d06av21.portsmouth.uk.ibm.com [9.149.105.232]) by b06cxnps4075.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id v51Hr7Bf35127424; Thu, 1 Jun 2017 17:53:07 GMT Received: from d06av21.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 4CF3752045; Thu, 1 Jun 2017 17:50:03 +0100 (BST) Received: from ThinkPad (unknown [9.152.212.148]) by d06av21.portsmouth.uk.ibm.com (Postfix) with ESMTP id 2864F5203F; Thu, 1 Jun 2017 17:50:03 +0100 (BST) Date: Thu, 01 Jun 2017 17:53:00 -0000 From: Philipp Rudo To: Pedro Alves Cc: Yao Qi , gdb-patches@sourceware.org Subject: Re: [RFC 2/7] Add unit test to builtin tdesc generated by xml In-Reply-To: <20170530100007.309c5669@ThinkPad> References: <1494518105-15412-1-git-send-email-yao.qi@linaro.org> <1494518105-15412-3-git-send-email-yao.qi@linaro.org> <20170516140027.29636db3@ThinkPad> <4c6f2f5a-e2c2-df09-0440-0f9431e7594a@redhat.com> <20170530100007.309c5669@ThinkPad> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="MP_/VCbOjyE_mwEoqivHMFs_5DG" X-TM-AS-GCONF: 00 x-cbid: 17060117-0020-0000-0000-0000037D9DDF X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 17060117-0021-0000-0000-000041F4C8CA Message-Id: <20170601195305.707dba3e@ThinkPad> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:,, definitions=2017-06-01_04:,, signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 suspectscore=2 malwarescore=0 phishscore=0 adultscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1703280000 definitions=main-1706010332 X-IsSubscribed: yes X-SW-Source: 2017-06/txt/msg00001.txt.bz2 --MP_/VCbOjyE_mwEoqivHMFs_5DG Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Content-Disposition: inline Content-length: 11936 Hi Pedro, On Tue, 30 May 2017 10:00:07 +0200 Philipp Rudo wrote: [...] > > I still think that if we're adding some utility for building > > paths from dir components, that it'd be preferred to model > > the API on (a small subset of) std::experimental::filesystem::path, > > since in a few years that's the API that everyone learning C++ will > > be learning. > > Also true, let me see if I can hack something today. Currently I don't like > to do what I should do and there are many meeting today anyway. So this > looks like a perfect task for today ;) I looked into it a "little" and it got a "little" out of hand... I'm going on vacation, starting tomorrow until next Wednesday, and didn't have the time to include it in GDB yet. So you find the code attached in two files as separate "programm". My plan is once I'm back (and finished the work I should have done this week (sorry Yao and Omair)) to move gdb_path.h to common/gdb_path.h and expand gdb_path-selftest.c with some static_asserts. While working on it I noticed one detail in std::filesystem::path which could be problematic for GDB. The dir separator it uses (preferred_separator) is 'static constexpr char'. So for cross debugging, with different dir separators, it doesn't allow us to distinguish between host and target paths. That's why my implementation uses a simple "char" such that the dir separator can be changed anytime. Otherwise the implementation should be compatible with std::filesystem::path http://en.cppreference.com/w/cpp/filesystem/path Any comment is welcome. Philipp ---------- To be added as binutils-gdb/gdb/common/gdb_path.h gdb_path.h | 542 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 542 insertions(+) ---------- /* Filesystem path handling for GDB. Copyright (C) 2017 Free Software Foundation, Inc. This file is part of GDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef __COMMON_GDB_PATH__ #define __COMMON_GDB_PATH__ #include #include #include #include namespace gdb { namespace filesystem { /* Stub implementation of C++17 std::filesystem::path. */ class path { public: path () noexcept {} template path (const T &s); /* Replace this path by OTHER. */ template path &operator= (const T &other); /* Append OTHER to this path. */ template path &operator/= (const T &other); /* Same as operator/=. */ template path &append (const T &other) { return *this /= other; } /* Append RHS to LHS and return the resulting path. */ template friend path operator/ (path lhs, const T &rhs); /* Add OTHER to this path without adding a dir seperator. */ template path &operator+= (const T &other); /* Same as operator+=. */ template path &concat (const T &other) { return *this += other; } /* Send this path to an ostream. */ friend std::ostream &operator<< (std::ostream &os, const path &p); /* Directory seperator. */ char preferred_seperator = '/'; /* Erase the content of this path. */ void clear (); /* Concatenate the path and return it as a std::string. */ std::string string () const; /* Same as .string but returns const char *. */ const char * c_str () { return string ().c_str (); } /* Return the root_name of path, e.g. on DOS-like systems the drive name. */ path root_name () const; /* Return the root directory if it exists. */ path root_directory () const; /* Return the root path, i.e. root_name + root_directory. */ path root_path () const; /* Return the relative path from root_path. */ path relative_path () const; /* Return the parent path of this path. */ path parent_path () const; /* Return the filename component of this path. */ path filename () const; /* Return the stem of filename component of this path, i.e. the filename without extension. */ path stem () const; /* Return the extension of filename component of this path. */ path extension () const; /* Check if this path is empty. */ bool empty () const noexcept; protected: /* Root of the filesystem, e.g. "C:" on dos-like filesystems. */ std::string m_root_name = ""; /* Is this path absolute? I.e. do we need to add a dir_sep at the beginning? */ bool m_absolute = false; /* Components of the path relative to root_path. */ std::list m_path = {}; /* Helper function. */ /* Does the given string sart with a root_name? Needed for constructor. */ bool has_root_name (const std::string &s) const; /* Is the substring of S starting at position POS a dir_seperator? */ bool is_dirsep (const std::string &s, const size_t pos) const; /* Calculate the size (i.e. number of characters) of the total path including dir_sep's. */ size_t path_size () const; /* Append path component COMP to m_path. */ void append_component (std::string &comp); }; /* See declaration. */ inline bool path::has_root_name (const std::string &s) const { //#if defined (HAVE_DOS_BASED_FILESYSTEM) /* Assume 'C:'-like root_names. */ return s.size () >= 2 && (std::isalpha (s[0]) && s[1] == ':'); //#else return false; //#endif /* HAVE_DOS_BASED_FILESYSTEM */ } /* See declaration. */ inline bool path::is_dirsep (const std::string &s, const size_t pos) const { return s[pos] == preferred_seperator; } /* See declaration. */ size_t path::path_size () const { size_t size = 0; for (auto &p : m_path) size += p.size () + 1; return size; } /* See declaration. */ void path::append_component (std::string &comp) { if (comp == ".") return; if (comp == ".." && !m_path.empty ()) { m_path.pop_back (); return; } m_path.push_back (comp); } /* Constructors. */ template path::path (const T &s) : path (std::string (s)) {} template<> path::path (const std::string &s) { size_t pos = 0; if (has_root_name (s)) { /* Assume 'C:'-like root_names. */ m_root_name = s.substr (pos, 2); pos += 2; } if (is_dirsep (s, pos)) { m_absolute = true; pos++; } do { /* Remove duplicate dir_seps. */ while (s[pos] == preferred_seperator) pos++; size_t last_pos = pos; pos = s.find (preferred_seperator, pos); std::string comp (s.substr (last_pos, pos - last_pos)); append_component (comp); } while (pos != std::string::npos); } template<> path::path (const path &other) { *this = other; } /* See declaration. */ std::ostream & operator<< (std::ostream &os, const path &p) { os << std::quoted (p.string ()); return os; } /* See declaration. */ template path & path::operator= (const T &other) { return *this = path (other); } /* See declaration. */ template<> path & path::operator= (const path &other) { preferred_seperator = other.preferred_seperator; m_root_name = other.m_root_name; m_absolute = other.m_absolute; m_path = other.m_path; return *this; } /* See declaration. */ template<> path & path::operator/= (const path &other) { for (auto comp : other.m_path) append_component (comp); return *this; } /* See declaration. */ template path & path::operator/= (const T &other) { return *this /= path (other); } /* See declaration. */ template path operator/ (path lhs, const T &rhs) { return lhs /= rhs; } /* See declaration. */ template<> path & path::operator+= (const path &other) { /* Ignore a possible root_name in other. */ m_path.back () += other.m_path.front (); m_path.insert (m_path.end (), ++other.m_path.begin (), other.m_path.end ()); return *this; } /* See declaration. */ template path & path::operator+= (const T &other) { return *this += path (other); } /* See declaration. */ void path::clear () { m_root_name.clear (); m_path.clear (); m_absolute = false; } /* See declaration. */ std::string path::string () const { std::string ret; if (empty ()) return ""; ret.reserve (path_size ()); ret += m_root_name; if (m_absolute) ret += preferred_seperator; for (auto p = m_path.begin (); p != m_path.end (); p++) ret += *p + preferred_seperator; /* Remove trailing dir_sep. */ ret.pop_back (); return ret; } /* See declaration. */ path path::root_name () const { return empty () ? path () : path (m_root_name); } /* See declaration. */ path path::root_directory () const { return m_absolute ? path (&preferred_seperator) : path (); } /* See declaration. */ path path::root_path () const { return root_name () / root_directory (); } /* See declaration. */ path path::relative_path () const { if (empty ()) return path (); path ret (*this); ret.m_root_name = ""; ret.m_absolute = false; return ret; } /* See declaration. */ path path::parent_path () const { if (empty ()) return path (); path ret (*this); ret.m_path.pop_back (); return ret; } /* See declaration. */ path path::filename () const { if (empty ()) return path (); return path (m_path.back ()); } /* See declaration. */ path path::stem () const { if (empty ()) return path (); auto pos = m_path.back ().rfind ('.'); if (pos == 0) return path (m_path.back ()); return path (m_path.back ().substr (0, pos)); } /* See declaration. */ path path::extension () const { if (empty ()) return path (); auto pos = m_path.back ().rfind ('.'); if (pos == 0 || pos == std::string::npos) return path (); return path (m_path.back ().substr (pos)); } /* See declaration. */ bool path::empty () const noexcept { return m_path.empty () && m_root_name.empty () && !m_absolute; } } /* namespace filesystem */ enum path_type { HOST_PATH, TARGET_PATH, }; class path : public gdb::filesystem::path { public: path () noexcept {}; template path (const T& s, enum path_type _type = HOST_PATH) : gdb::filesystem::path (s), type (_type) {} /* Overload .string method to prepend target_prefix. */ std::string string () const; /* Substitute all occurrences of FROM to TO in this path. */ path &substitute (const std::string &from, const std::string &to); /* Type of this path (host or target). */ enum path_type type; private: /* Prefix to be prepended to target paths. */ const std::string m_target_prefix = "target:"; }; /* See declaration. */ std::string path::string () const { std::string ret; if (type == TARGET_PATH) { ret.reserve (path_size () + m_target_prefix.size ()); ret = m_target_prefix + gdb::filesystem::path::string (); } else { ret = gdb::filesystem::path::string (); } return ret; } /* See declaration. */ path & path::substitute (const std::string &from, const std::string &to) { if (from.empty ()) return *this; /* Use TO == "" to remove the component completely. */ if (to.empty ()) { m_path.remove (from); return *this; } for (auto it = m_path.begin (); it != m_path.end (); ++it) { if (*it != from) continue; *it = to; } return *this; } } /* namespace gdb */ #endif /*__COMMON_GDB_PATH__ */ --MP_/VCbOjyE_mwEoqivHMFs_5DG Content-Type: text/x-chdr Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=gdb_path.h Content-length: 10141 /* Filesystem path handling for GDB. Copyright (C) 2017 Free Software Foundation, Inc. This file is part of GDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef __COMMON_GDB_PATH__ #define __COMMON_GDB_PATH__ #include #include #include #include namespace gdb { namespace filesystem { /* Stub implementation of C++17 std::filesystem::path. */ class path { public: path () noexcept {} template path (const T &s); /* Replace this path by OTHER. */ template path &operator= (const T &other); /* Append OTHER to this path. */ template path &operator/= (const T &other); /* Same as operator/=. */ template path &append (const T &other) { return *this /= other; } /* Append RHS to LHS and return the resulting path. */ template friend path operator/ (path lhs, const T &rhs); /* Add OTHER to this path without adding a dir seperator. */ template path &operator+= (const T &other); /* Same as operator+=. */ template path &concat (const T &other) { return *this += other; } /* Send this path to an ostream. */ friend std::ostream &operator<< (std::ostream &os, const path &p); /* Directory seperator. */ char preferred_seperator = '/'; /* Erase the content of this path. */ void clear (); /* Concatenate the path and return it as a std::string. */ std::string string () const; /* Same as .string but returns const char *. */ const char * c_str () { return string ().c_str (); } /* Return the root_name of path, e.g. on DOS-like systems the drive name. */ path root_name () const; /* Return the root directory if it exists. */ path root_directory () const; /* Return the root path, i.e. root_name + root_directory. */ path root_path () const; /* Return the relative path from root_path. */ path relative_path () const; /* Return the parent path of this path. */ path parent_path () const; /* Return the filename component of this path. */ path filename () const; /* Return the stem of filename component of this path, i.e. the filename without extension. */ path stem () const; /* Return the extension of filename component of this path. */ path extension () const; /* Check if this path is empty. */ bool empty () const noexcept; protected: /* Root of the filesystem, e.g. "C:" on dos-like filesystems. */ std::string m_root_name = ""; /* Is this path absolute? I.e. do we need to add a dir_sep at the beginning? */ bool m_absolute = false; /* Components of the path relative to root_path. */ std::list m_path = {}; /* Helper function. */ /* Does the given string sart with a root_name? Needed for constructor. */ bool has_root_name (const std::string &s) const; /* Is the substring of S starting at position POS a dir_seperator? */ bool is_dirsep (const std::string &s, const size_t pos) const; /* Calculate the size (i.e. number of characters) of the total path including dir_sep's. */ size_t path_size () const; /* Append path component COMP to m_path. */ void append_component (std::string &comp); }; /* See declaration. */ inline bool path::has_root_name (const std::string &s) const { //#if defined (HAVE_DOS_BASED_FILESYSTEM) /* Assume 'C:'-like root_names. */ return s.size () >= 2 && (std::isalpha (s[0]) && s[1] == ':'); //#else return false; //#endif /* HAVE_DOS_BASED_FILESYSTEM */ } /* See declaration. */ inline bool path::is_dirsep (const std::string &s, const size_t pos) const { return s[pos] == preferred_seperator; } /* See declaration. */ size_t path::path_size () const { size_t size = 0; for (auto &p : m_path) size += p.size () + 1; return size; } /* See declaration. */ void path::append_component (std::string &comp) { if (comp == ".") return; if (comp == ".." && !m_path.empty ()) { m_path.pop_back (); return; } m_path.push_back (comp); } /* Constructors. */ template path::path (const T &s) : path (std::string (s)) {} template<> path::path (const std::string &s) { size_t pos = 0; if (has_root_name (s)) { /* Assume 'C:'-like root_names. */ m_root_name = s.substr (pos, 2); pos += 2; } if (is_dirsep (s, pos)) { m_absolute = true; pos++; } do { /* Remove duplicate dir_seps. */ while (s[pos] == preferred_seperator) pos++; size_t last_pos = pos; pos = s.find (preferred_seperator, pos); std::string comp (s.substr (last_pos, pos - last_pos)); append_component (comp); } while (pos != std::string::npos); } template<> path::path (const path &other) { *this = other; } /* See declaration. */ std::ostream & operator<< (std::ostream &os, const path &p) { os << std::quoted (p.string ()); return os; } /* See declaration. */ template path & path::operator= (const T &other) { return *this = path (other); } /* See declaration. */ template<> path & path::operator= (const path &other) { preferred_seperator = other.preferred_seperator; m_root_name = other.m_root_name; m_absolute = other.m_absolute; m_path = other.m_path; return *this; } /* See declaration. */ template<> path & path::operator/= (const path &other) { for (auto comp : other.m_path) append_component (comp); return *this; } /* See declaration. */ template path & path::operator/= (const T &other) { return *this /= path (other); } /* See declaration. */ template path operator/ (path lhs, const T &rhs) { return lhs /= rhs; } /* See declaration. */ template<> path & path::operator+= (const path &other) { /* Ignore a possible root_name in other. */ m_path.back () += other.m_path.front (); m_path.insert (m_path.end (), ++other.m_path.begin (), other.m_path.end ()); return *this; } /* See declaration. */ template path & path::operator+= (const T &other) { return *this += path (other); } /* See declaration. */ void path::clear () { m_root_name.clear (); m_path.clear (); m_absolute = false; } /* See declaration. */ std::string path::string () const { std::string ret; if (empty ()) return ""; ret.reserve (path_size ()); ret += m_root_name; if (m_absolute) ret += preferred_seperator; for (auto p = m_path.begin (); p != m_path.end (); p++) ret += *p + preferred_seperator; /* Remove trailing dir_sep. */ ret.pop_back (); return ret; } /* See declaration. */ path path::root_name () const { return empty () ? path () : path (m_root_name); } /* See declaration. */ path path::root_directory () const { return m_absolute ? path (&preferred_seperator) : path (); } /* See declaration. */ path path::root_path () const { return root_name () / root_directory (); } /* See declaration. */ path path::relative_path () const { if (empty ()) return path (); path ret (*this); ret.m_root_name = ""; ret.m_absolute = false; return ret; } /* See declaration. */ path path::parent_path () const { if (empty ()) return path (); path ret (*this); ret.m_path.pop_back (); return ret; } /* See declaration. */ path path::filename () const { if (empty ()) return path (); return path (m_path.back ()); } /* See declaration. */ path path::stem () const { if (empty ()) return path (); auto pos = m_path.back ().rfind ('.'); if (pos == 0) return path (m_path.back ()); return path (m_path.back ().substr (0, pos)); } /* See declaration. */ path path::extension () const { if (empty ()) return path (); auto pos = m_path.back ().rfind ('.'); if (pos == 0 || pos == std::string::npos) return path (); return path (m_path.back ().substr (pos)); } /* See declaration. */ bool path::empty () const noexcept { return m_path.empty () && m_root_name.empty () && !m_absolute; } } /* namespace filesystem */ enum path_type { HOST_PATH, TARGET_PATH, }; class path : public gdb::filesystem::path { public: path () noexcept {}; template path (const T& s, enum path_type _type = HOST_PATH) : gdb::filesystem::path (s), type (_type) {} /* Overload .string method to prepend target_prefix. */ std::string string () const; /* Substitute all occurrences of FROM to TO in this path. */ path &substitute (const std::string &from, const std::string &to); /* Type of this path (host or target). */ enum path_type type; private: /* Prefix to be prepended to target paths. */ const std::string m_target_prefix = "target:"; }; /* See declaration. */ std::string path::string () const { std::string ret; if (type == TARGET_PATH) { ret.reserve (path_size () + m_target_prefix.size ()); ret = m_target_prefix + gdb::filesystem::path::string (); } else { ret = gdb::filesystem::path::string (); } return ret; } /* See declaration. */ path & path::substitute (const std::string &from, const std::string &to) { if (from.empty ()) return *this; /* Use TO == "" to remove the component completely. */ if (to.empty ()) { m_path.remove (from); return *this; } for (auto it = m_path.begin (); it != m_path.end (); ++it) { if (*it != from) continue; *it = to; } return *this; } } /* namespace gdb */ #endif /*__COMMON_GDB_PATH__ */ --MP_/VCbOjyE_mwEoqivHMFs_5DG Content-Type: text/x-c++src Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=gdb_path-selftest.c Content-length: 2388 /* Self tests for filesystem path handling for GDB. Copyright (C) 2017 Free Software Foundation, Inc. This file is part of GDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "gdb_path.h" //namespace selftest { namespace fs = gdb::filesystem; static int i = 0; template void print_path (T &p) { std::cout << i++ << ":\n"; std::cout << "string = " << p.string () << "\n"; std::cout << "c_str = " << p.c_str () << "\n"; std::cout << "root_name = " << p.root_name () << "\n"; std::cout << "root_dir = " << p.root_directory () << "\n"; std::cout << "root_path = " << p.root_path () << "\n"; std::cout << "relative_path = " << p.relative_path () << "\n"; std::cout << "parent_path = " << p.parent_path () << "\n"; std::cout << "filename = " << p.filename () << "\n"; std::cout << "stem = " << p.stem () << "\n"; std::cout << "extension = " << p.extension () << "\n"; std::cout << "\n"; } int main () { fs::path p ("/"); print_path (p); p.clear (); p = "C:1/2///"; print_path (p); p.clear (); p = "C:/1/2///"; print_path (p); p.clear (); p = fs::path ("/1/x/y/z/../../..///2/."); fs::path q = "3"; fs::path r = "4"; fs::path s; s = q / r; p /= s; p /= std::string ("5"); p /= "6"; p.append (".7"); p /= "."; p /= "x"; p /= ".."; print_path (p); p += fs::path (".foo"); print_path (p); p += ".bar"; print_path (p); fs::path t; print_path (t); gdb::path gp ("/a/b/c/$x/$y/e/f"); print_path (gp); gp.type = gdb::TARGET_PATH; gp.substitute ("$x", "d"); gp.substitute ("$y", ""); print_path (gp); gp.clear (); gp /= "../foo"; print_path (gp); } //} /* namespace selftest */ --MP_/VCbOjyE_mwEoqivHMFs_5DG--