aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--butl/path10
-rw-r--r--butl/process16
-rw-r--r--butl/process.cxx75
3 files changed, 72 insertions, 29 deletions
diff --git a/butl/path b/butl/path
index e6c9166..d60938f 100644
--- a/butl/path
+++ b/butl/path
@@ -108,10 +108,16 @@ namespace butl
static bool
absolute (const string_type& s)
{
+ return absolute (s.c_str (), s.size ());
+ }
+
+ static bool
+ absolute (const C* s, size_type n)
+ {
#ifdef _WIN32
- return s.size () > 1 && s[1] == ':';
+ return n > 1 && s[1] == ':';
#else
- return s.size () != 0 && is_separator (s[0]);
+ return n != 0 && is_separator (s[0]);
#endif
}
diff --git a/butl/process b/butl/process
index e98e367..ff22577 100644
--- a/butl/process
+++ b/butl/process
@@ -50,21 +50,21 @@ namespace butl
// directory and if found then that's what should end up in child's argv[0].
// So this is the recall path. It is called recall because this is what the
// caller of the parent process will be able to execute if you printed the
- // command line. Finally, effective is the actual path to the executable
- // that will include the directory part if found in PATH, the .exe extension
- // if one is missing, etc.
+ // command line (provided you haven't changed the CWD). Finally, effective
+ // is the absolute path to the executable that will include the directory
+ // part if found in PATH, the .exe extension if one is missing, etc.
//
// As an example, let's say we run foo\foo.exe that itself spawns bar which
// is found as foo\bar.exe. The paths will then be:
//
// initial: bar
// recall: foo\bar
- // effective: foo\bar.exe
+ // effective: c:\...\foo\bar.exe
//
- // In most cases, at least on POSIX, all three paths will be the same. As an
- // optimization, if the recall path is empty, then it means it is the same
- // as initial. Similarly, if the effective path is empty then, it is the
- // same as recall (and if that is empty, as initial).
+ // In most cases, at least on POSIX, the first two paths will be the same.
+ // As an optimization, if the recall path is empty, then it means it is the
+ // same as initial. Similarly, if the effective path is empty then, it is
+ // the same as recall (and if that is empty, as initial).
//
// Note that the call to path_search() below adjust args[0] to point to the
// recall path which brings up lifetime issues. To address this this class
diff --git a/butl/process.cxx b/butl/process.cxx
index 41645e4..1a83481 100644
--- a/butl/process.cxx
+++ b/butl/process.cxx
@@ -153,7 +153,9 @@ namespace butl
(si.st_mode & (S_IEXEC | S_IXGRP | S_IXOTH)) != 0);
};
- auto search = [&ep, f, fn, &exists] (const char* d, size_t dn) -> bool
+ auto search = [&ep, f, fn, &exists] (const char* d,
+ size_t dn,
+ bool norm = false) -> bool
{
string s (move (ep).string ()); // Reuse buffer.
@@ -167,18 +169,33 @@ namespace butl
s.append (f, fn);
ep = path (move (s)); // Move back into result.
+
+ if (norm)
+ ep.normalize ();
+
return exists (ep.string ().c_str ());
};
- // If there is a directory component in the file, then search does not
- // apply. But make sure the file actually exists.
+ // If there is a directory component in the file, then the PATH search
+ // does not apply. If the path is relative, then prepend CWD. In both
+ // cases make sure the file actually exists.
//
if (traits::find_separator (f, fn) != nullptr)
{
- if (exists (f)) // ?: calls deleted copy ctor.
- return r;
+ if (traits::absolute (f, fn))
+ {
+ if (exists (f))
+ return r;
+ }
else
- return process_path ();
+ {
+ const string& d (traits::current ());
+
+ if (search (d.c_str (), d.size (), true))
+ return r;
+ }
+
+ return process_path ();
}
// The search order is documented in exec(3). Some of the differences
@@ -435,7 +452,9 @@ namespace butl
return _stat (f, &si) == 0 && S_ISREG (si.st_mode);
};
- auto search = [&ep, f, fn, ext, &exists] (const char* d, size_t dn) -> bool
+ auto search = [&ep, f, fn, ext, &exists] (const char* d,
+ size_t dn,
+ bool norm = false) -> bool
{
string s (move (ep).string ()); // Reuse buffer.
@@ -450,6 +469,9 @@ namespace butl
s.append (f, fn);
ep = path (move (s)); // Move back into result.
+ if (norm)
+ ep.normalize ();
+
// Add the .exe extension if necessary.
//
if (ext)
@@ -458,22 +480,33 @@ namespace butl
return exists (ep.string ().c_str ());
};
- // If there is a directory component in the file, then search does not
- // apply. But we may still need to append the extension and make sure the
- // file actually exists.
+ // If there is a directory component in the file, then the PATH search
+ // does not apply. If the path is relative, then prepend CWD. In both
+ // cases we may still need to append the extension and make sure the file
+ // actually exists.
//
if (traits::find_separator (f, fn) != nullptr)
{
- if (ext)
+ if (traits::absolute (f, fn))
{
- ep = path (f, fn);
- ep += ".exe";
- }
+ if (ext)
+ {
+ ep = path (f, fn);
+ ep += ".exe";
+ }
- if (exists (r.effect_string ())) // ?: calls deleted copy ctor.
- return r;
+ if (exists (r.effect_string ()))
+ return r;
+ }
else
- return process_path ();
+ {
+ const string& d (traits::current ());
+
+ if (search (d.c_str (), d.size (), true)) // Appends extension.
+ return r;
+ }
+
+ return process_path ();
}
// The search order is documented in CreateProcess(). First we look in the
@@ -526,8 +559,12 @@ namespace butl
// The recall path is the same as initial, though it might not be a bad
// idea to prepend .\ for clarity.
//
- if (search ("", 0))
- return r;
+ {
+ const string& d (traits::current ());
+
+ if (search (d.c_str (), d.size ()))
+ return r;
+ }
// Now search in PATH. Recall is unchanged.
//