home/src/shell_manager.cc
Maxime Coste 7fb49b183e ShellManager environment variable use a regex instead of an exact match
when a kakoune releated env var used in a shell command, the ShellManager
tries to match it with given regex and the first that matches calls its
value retriever.

For this to be useful, EnvVarRetrievers now also take the variable
name in its parameters.
2012-06-25 19:40:18 +02:00

109 lines
2.9 KiB
C++

#include "shell_manager.hh"
#include <cstring>
#include <sys/types.h>
#include <sys/wait.h>
namespace Kakoune
{
String env_var_regex(R"(\$\{kak_([a-z0-9_]+)[^}]*\}|\$kak_([a-z0-9_]+))");
ShellManager::ShellManager()
: m_regex(env_var_regex.begin(), env_var_regex.end())
{
}
String ShellManager::eval(const String& cmdline, const Context& context,
const EnvVarMap& env_vars)
{
return pipe("", cmdline, context, env_vars);
}
String ShellManager::pipe(const String& input,
const String& cmdline, const Context& context,
const EnvVarMap& env_vars)
{
int write_pipe[2];
int read_pipe[2];
::pipe(write_pipe);
::pipe(read_pipe);
String output;
if (pid_t pid = fork())
{
close(write_pipe[0]);
close(read_pipe[1]);
memoryview<char> data = input.data();
write(write_pipe[1], data.pointer(), data.size());
close(write_pipe[1]);
char buffer[1024];
while (size_t size = read(read_pipe[0], buffer, 1024))
{
if (size == -1)
break;
output += String(buffer, buffer+size);
}
close(read_pipe[0]);
waitpid(pid, NULL, 0);
}
else
{
close(write_pipe[1]);
close(read_pipe[0]);
dup2(read_pipe[1], 1);
dup2(write_pipe[0], 0);
boost::regex_iterator<String::iterator> it(cmdline.begin(), cmdline.end(), m_regex);
boost::regex_iterator<String::iterator> end;
while (it != end)
{
auto& match = *it;
String name;
if (match[1].matched)
name = String(match[1].first, match[1].second);
else if (match[2].matched)
name = String(match[2].first, match[2].second);
else
assert(false);
assert(name.length() > 0);
auto local_var = env_vars.find(name);
if (local_var != env_vars.end())
setenv(("kak_" + name).c_str(), local_var->second.c_str(), 1);
else
{
auto env_var = std::find_if(
m_env_vars.begin(), m_env_vars.end(),
[&](const std::pair<Regex, EnvVarRetriever>& pair)
{ return boost::regex_match(name.begin(), name.end(),
pair.first); });
if (env_var != m_env_vars.end())
{
String value = env_var->second(name, context);
setenv(("kak_" + name).c_str(), value.c_str(), 1);
}
}
++it;
}
execlp("sh", "sh", "-c", cmdline.c_str(), NULL);
}
return output;
}
void ShellManager::register_env_var(const String& regex,
EnvVarRetriever retriever)
{
m_env_vars.push_back({ Regex(regex.begin(), regex.end()), std::move(retriever) });
}
}