From 19fbc5c14400aa2cda95ca396a64ab548da60b5b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 7 Apr 2023 00:19:10 +0200 Subject: [PATCH] Implemented tilde expansion, internal stream path names are now absolute, fixed tests --- src/db/unit_tests/dbNetlistReaderTests.cc | 4 +-- src/tl/tl/tlFileUtils.cc | 40 +++++++++++++++++++++-- src/tl/tl/tlFileUtils.h | 5 +++ src/tl/tl/tlStream.cc | 22 ++++++------- src/tl/unit_tests/tlFileUtilsTests.cc | 17 ++++++++++ testdata/ruby/dbNetlistReaderTests.rb | 1 + 6 files changed, 74 insertions(+), 15 deletions(-) diff --git a/src/db/unit_tests/dbNetlistReaderTests.cc b/src/db/unit_tests/dbNetlistReaderTests.cc index d82d3b02e..5a5a6315b 100644 --- a/src/db/unit_tests/dbNetlistReaderTests.cc +++ b/src/db/unit_tests/dbNetlistReaderTests.cc @@ -500,7 +500,7 @@ TEST(11_ErrorOnCircuitRedefinition) msg = ex.msg (); } - EXPECT_EQ (tl::replaced (msg, path, "?"), "Redefinition of circuit SUBCKT in ?, line 20"); + EXPECT_EQ (tl::replaced (msg, tl::absolute_file_path (path), "?"), "Redefinition of circuit SUBCKT in ?, line 20"); } TEST(12_IgnoreDuplicateGlobals) @@ -580,7 +580,7 @@ TEST(14_IncludeWithError) reader.read (is, nl); EXPECT_EQ (true, false); // must not happen } catch (tl::Exception &ex) { - EXPECT_EQ (ex.msg (), "'M' element must have four nodes in " + std::string (tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "nreader14x.cir")) + ", line 3"); + EXPECT_EQ (ex.msg (), "'M' element must have four nodes in " + std::string (tl::absolute_file_path (tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "nreader14x.cir"))) + ", line 3"); } } diff --git a/src/tl/tl/tlFileUtils.cc b/src/tl/tl/tlFileUtils.cc index 8b002aa78..9707f3c54 100644 --- a/src/tl/tl/tlFileUtils.cc +++ b/src/tl/tl/tlFileUtils.cc @@ -24,6 +24,7 @@ #include "tlStream.h" #include "tlLog.h" #include "tlInternational.h" +#include "tlEnv.h" #include @@ -59,6 +60,7 @@ # include # include # include +# include #endif @@ -629,7 +631,7 @@ bool chdir (const std::string &path) static std::pair absolute_path_of_existing (const std::string &s) { -#if defined (_WIN32) +#if defined(_WIN32) wchar_t *fp = _wfullpath (NULL, tl::to_wstring (s).c_str (), 0); if (fp == NULL) { @@ -657,6 +659,11 @@ static std::pair absolute_path_of_existing (const std::string bool is_absolute (const std::string &s) { + // ~ paths are always absolute, because the home directory is + if (s.size () > 0 && s[0] == '~') { + return true; + } + std::vector parts = split_path (s); if (parts.size () > 1 && is_drive (parts [0])) { return is_part_with_separator (parts [1]); @@ -669,6 +676,11 @@ bool is_absolute (const std::string &s) std::string absolute_file_path (const std::string &s) { + // ~ paths are always absolute, because the home directory is + if (s.size () > 0 && s[0] == '~') { + return get_home_path () + std::string (s, 1); + } + std::vector parts = split_path (s); if (parts.empty ()) { return current_dir (); @@ -854,10 +866,34 @@ bool is_same_file (const std::string &a, const std::string &b) #endif } +std::string +get_home_path () +{ +#if !defined(_WIN32) + if (tl::has_env ("HOME")) { + return tl::get_env ("HOME"); + } else { + struct passwd *pwd = getpwuid (getuid ()); + if (pwd) { + return std::string (pwd->pw_dir); + } + } + tl::warn << tl::to_string (tr ("Unable to get home directory (set HOME environment variable)")); +#else + if (tl::has_env ("HOMEDRIVE") && tl::has_env ("HOMEPATH")) { + return tl::get_env ("HOMEDRIVE") + tl::get_env ("HOMEPATH"); + } else if (tl::has_env ("HOMESHARE") && tl::has_env ("HOMEPATH")) { + return tl::get_env ("HOMESHARE") + tl::get_env ("HOMEPATH"); + } + tl::warn << tl::to_string (tr ("Unable to get home directory (no HOMEDRIVE/HOMEPATH or HOMESHARE/HOMEPATH environment variables)")); +#endif + return std::string ("."); +} + static std::string get_inst_path_internal () { -#ifdef _WIN32 +#if defined(_WIN32) wchar_t buffer[MAX_PATH]; int len; diff --git a/src/tl/tl/tlFileUtils.h b/src/tl/tl/tlFileUtils.h index 354ab786e..f192599ff 100644 --- a/src/tl/tl/tlFileUtils.h +++ b/src/tl/tl/tlFileUtils.h @@ -194,6 +194,11 @@ bool TL_PUBLIC chdir (const std::string &path); */ std::vector TL_PUBLIC split_path (const std::string &p, bool keep_last = false); +/** + * @brief Gets the home directory path + */ +std::string TL_PUBLIC get_home_path (); + /** * @brief Gets the path of the currently running process */ diff --git a/src/tl/tl/tlStream.cc b/src/tl/tl/tlStream.cc index 2fc9e1244..442a78122 100644 --- a/src/tl/tl/tlStream.cc +++ b/src/tl/tl/tlStream.cc @@ -666,15 +666,15 @@ TextInputStream::reset () InputFile::InputFile (const std::string &path) : m_fd (-1) { - m_source = path; + m_source = tl::absolute_file_path (path);; #if defined(_WIN32) - int fd = _wopen (tl::to_wstring (path).c_str (), _O_BINARY | _O_RDONLY | _O_SEQUENTIAL); + int fd = _wopen (tl::to_wstring (m_source).c_str (), _O_BINARY | _O_RDONLY | _O_SEQUENTIAL); if (fd < 0) { throw FileOpenErrorException (m_source, errno); } m_fd = fd; #else - int fd = open (path.c_str (), O_RDONLY); + int fd = open (m_source.c_str (), O_RDONLY); if (fd < 0) { throw FileOpenErrorException (m_source, errno); } @@ -747,15 +747,15 @@ InputFile::filename () const InputZLibFile::InputZLibFile (const std::string &path) : mp_d (new ZLibFilePrivate ()) { - m_source = path; + m_source = tl::absolute_file_path (path); #if defined(_WIN32) - int fd = _wopen (tl::to_wstring (path).c_str (), _O_BINARY | _O_RDONLY | _O_SEQUENTIAL); + int fd = _wopen (tl::to_wstring (m_source).c_str (), _O_BINARY | _O_RDONLY | _O_SEQUENTIAL); if (fd < 0) { throw FileOpenErrorException (m_source, errno); } mp_d->zs = gzdopen (fd, "rb"); #else - mp_d->zs = gzopen (tl::string_to_system (path).c_str (), "rb"); + mp_d->zs = gzopen (tl::string_to_system (m_source).c_str (), "rb"); #endif if (mp_d->zs == NULL) { throw FileOpenErrorException (m_source, errno); @@ -1035,10 +1035,10 @@ OutputStream::seek (size_t pos) // OutputFileBase implementation OutputFileBase::OutputFileBase (const std::string &path, int keep_backups) - : m_keep_backups (keep_backups), m_path (path), m_has_error (false) + : m_keep_backups (keep_backups), m_path (tl::absolute_file_path (path)), m_has_error (false) { - if (tl::file_exists (path)) { - m_backup_path = path + ".~backup"; + if (tl::file_exists (m_path)) { + m_backup_path = m_path + ".~backup"; if (tl::file_exists (m_backup_path)) { if (! tl::rm_file (m_backup_path)) { tl::warn << tl::sprintf (tl::to_string (tr ("Could not create backup file: unable to remove existing file '%s'")), m_backup_path); @@ -1046,8 +1046,8 @@ OutputFileBase::OutputFileBase (const std::string &path, int keep_backups) } } if (! m_backup_path.empty ()) { - if (! tl::rename_file (path, tl::filename (m_backup_path))) { - tl::warn << tl::sprintf (tl::to_string (tr ("Could not create backup file: unable to rename original file '%s' to backup file")), path, m_backup_path); + if (! tl::rename_file (m_path, tl::filename (m_backup_path))) { + tl::warn << tl::sprintf (tl::to_string (tr ("Could not create backup file: unable to rename original file '%s' to backup file")), m_path, m_backup_path); m_backup_path = std::string (); } } diff --git a/src/tl/unit_tests/tlFileUtilsTests.cc b/src/tl/unit_tests/tlFileUtilsTests.cc index 146c91923..78b173502 100644 --- a/src/tl/unit_tests/tlFileUtilsTests.cc +++ b/src/tl/unit_tests/tlFileUtilsTests.cc @@ -401,6 +401,8 @@ TEST (10) EXPECT_EQ (tl::extension_last ("\\hello\\.world.gz"), "gz"); EXPECT_EQ (tl::extension_last ("/hello//world/"), ""); + EXPECT_EQ (tl::is_absolute ("~/world"), true); + EXPECT_EQ (tl::is_absolute ("~"), true); EXPECT_EQ (tl::is_absolute ("world"), false); EXPECT_EQ (tl::is_absolute ("world/"), false); EXPECT_EQ (tl::is_absolute ("hello//world/"), false); @@ -796,3 +798,18 @@ TEST (18) EXPECT_EQ (is.read_all (), "hello, world!\n"); } } + +// get_home_path +TEST (19) +{ + std::string home = tl::get_home_path (); + // no specific value, just something ... + EXPECT_EQ (home.size () > 5, true); +} + +// absolute path with "~" expansion +TEST (20) +{ + EXPECT_EQ (tl::absolute_file_path ("~"), tl::get_home_path ()); + EXPECT_EQ (tl::absolute_file_path (tl::combine_path ("~", "test")), tl::combine_path (tl::get_home_path (), "test")); +} diff --git a/testdata/ruby/dbNetlistReaderTests.rb b/testdata/ruby/dbNetlistReaderTests.rb index 3632c72f7..4ef69884f 100644 --- a/testdata/ruby/dbNetlistReaderTests.rb +++ b/testdata/ruby/dbNetlistReaderTests.rb @@ -167,6 +167,7 @@ END nl = RBA::Netlist::new input = File.join($ut_testsrc, "testdata", "algo", "nreader6.cir") + input = File.absolute_path(input) mydelegate = MyNetlistSpiceReaderDelegate::new