public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Philipp Rudo <prudo@linux.vnet.ibm.com>
To: Pedro Alves <palves@redhat.com>
Cc: Yao Qi <qiyaoltc@gmail.com>, gdb-patches@sourceware.org
Subject: Re: [RFC 2/7] Add unit test to builtin tdesc generated by xml
Date: Thu, 01 Jun 2017 17:53:00 -0000	[thread overview]
Message-ID: <20170601195305.707dba3e@ThinkPad> (raw)
In-Reply-To: <20170530100007.309c5669@ThinkPad>

[-- Attachment #1: Type: text/plain, Size: 11936 bytes --]

Hi Pedro,

On Tue, 30 May 2017 10:00:07 +0200
Philipp Rudo <prudo@linux.vnet.ibm.com> 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 <http://www.gnu.org/licenses/>.  */

#ifndef __COMMON_GDB_PATH__
#define __COMMON_GDB_PATH__

#include <iomanip>
#include <iostream>
#include <list>
#include <string>

namespace gdb {
namespace filesystem {

/* Stub implementation of C++17 std::filesystem::path.  */

class path
{
public:
  path () noexcept {}

  template<class T>
  path (const T &s);

  /* Replace this path by OTHER.  */
  template<class T>
  path &operator= (const T &other);

  /* Append OTHER to this path.  */
  template<class T>
  path &operator/= (const T &other);

  /* Same as operator/=.  */
  template<class T>
  path &append (const T &other)
    {
      return *this /= other;
    }

  /* Append RHS to LHS and return the resulting path.  */
  template<class T>
  friend path operator/ (path lhs, const T &rhs);

  /* Add OTHER to this path without adding a dir seperator.  */
  template<class T>
  path &operator+= (const T &other);

  /* Same as operator+=.  */
  template<class T>
  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 <std::string> 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<class T>
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<class T>
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<class T>
path &
path::operator/= (const T &other)
{
  return *this /= path (other);
}

/* See declaration.  */

template<class T>
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<class T>
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<class T>
  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__ */

[-- Attachment #2: gdb_path.h --]
[-- Type: text/x-chdr, Size: 10141 bytes --]

/* 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 <http://www.gnu.org/licenses/>.  */

#ifndef __COMMON_GDB_PATH__
#define __COMMON_GDB_PATH__

#include <iomanip>
#include <iostream>
#include <list>
#include <string>

namespace gdb {
namespace filesystem {

/* Stub implementation of C++17 std::filesystem::path.  */

class path
{
public:
  path () noexcept {}

  template<class T>
  path (const T &s);

  /* Replace this path by OTHER.  */
  template<class T>
  path &operator= (const T &other);

  /* Append OTHER to this path.  */
  template<class T>
  path &operator/= (const T &other);

  /* Same as operator/=.  */
  template<class T>
  path &append (const T &other)
    {
      return *this /= other;
    }

  /* Append RHS to LHS and return the resulting path.  */
  template<class T>
  friend path operator/ (path lhs, const T &rhs);

  /* Add OTHER to this path without adding a dir seperator.  */
  template<class T>
  path &operator+= (const T &other);

  /* Same as operator+=.  */
  template<class T>
  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 <std::string> 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<class T>
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<class T>
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<class T>
path &
path::operator/= (const T &other)
{
  return *this /= path (other);
}

/* See declaration.  */

template<class T>
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<class T>
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<class T>
  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__ */

[-- Attachment #3: gdb_path-selftest.c --]
[-- Type: text/x-c++src, Size: 2388 bytes --]

/* 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 <http://www.gnu.org/licenses/>.  */

#include <iostream>

#include "gdb_path.h"

//namespace selftest {

namespace fs = gdb::filesystem;
static int i = 0;

template<class T>
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 */

  reply	other threads:[~2017-06-01 17:53 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-05-11 15:55 [RFC 0/7] Make GDB builtin target descriptions more flexible Yao Qi
2017-05-11 15:55 ` [RFC 7/7] Remove builtin tdesc_i386_*_linux Yao Qi
2017-05-16 12:02   ` Philipp Rudo
2017-05-17 15:46   ` Pedro Alves
2017-05-11 15:55 ` [RFC 1/7] Move initialize_tdesc_mips* calls from mips-linux-nat.c to mips-linux-tdep.c Yao Qi
2017-05-11 15:55 ` [RFC 2/7] Add unit test to builtin tdesc generated by xml Yao Qi
2017-05-16 12:00   ` Philipp Rudo
2017-05-16 15:46     ` Yao Qi
2017-05-17  9:09       ` Philipp Rudo
2017-05-17 16:06     ` Pedro Alves
2017-05-30  8:00       ` Philipp Rudo
2017-06-01 17:53         ` Philipp Rudo [this message]
2017-05-17 15:41   ` Pedro Alves
2017-05-18  9:54     ` Yao Qi
2017-05-18 11:34       ` Pedro Alves
2017-05-19 15:47         ` Yao Qi
2017-05-22  8:51           ` Yao Qi
2017-05-11 15:55 ` [RFC 3/7] Adjust the order of 32bit-linux.xml and 32bit-sse.xml in i386/i386-linux.xml Yao Qi
2017-05-11 15:55 ` [RFC 6/7] Lazily and dynamically create i386-linux target descriptions Yao Qi
2017-05-11 18:14   ` John Baldwin
2017-05-11 21:03     ` Yao Qi
2017-05-17 15:43   ` Pedro Alves
2017-05-18 15:12     ` Yao Qi
2017-05-19 10:15       ` Pedro Alves
2017-05-19 14:27         ` Yao Qi
2017-05-11 15:55 ` [RFC 5/7] Centralize i386 linux " Yao Qi
2017-05-11 16:06 ` [RFC 0/7] Make GDB builtin target descriptions more flexible Eli Zaretskii
2017-05-11 20:56   ` Yao Qi
2017-05-11 20:55 ` [RFC 4/7] Share code in initialize_tdesc_ functions Yao Qi
2017-05-16 12:02   ` Philipp Rudo
2017-05-17 15:43     ` Pedro Alves
2017-05-18 11:21       ` Yao Qi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170601195305.707dba3e@ThinkPad \
    --to=prudo@linux.vnet.ibm.com \
    --cc=gdb-patches@sourceware.org \
    --cc=palves@redhat.com \
    --cc=qiyaoltc@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).