PageRenderTime 52ms CodeModel.GetById 13ms app.highlight 34ms RepoModel.GetById 1ms app.codeStats 1ms

/indra/newview/llexternaleditor.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 208 lines | 143 code | 25 blank | 40 comment | 26 complexity | 22940f8439e4edb03f29af5d70e9d7da MD5 | raw file
  1/** 
  2 * @file llexternaleditor.cpp
  3 * @brief A convenient class to run external editor.
  4 *
  5 * $LicenseInfo:firstyear=2010&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27#include "llviewerprecompiledheaders.h"
 28#include "llexternaleditor.h"
 29
 30#include "lltrans.h"
 31#include "llui.h"
 32
 33// static
 34const std::string LLExternalEditor::sFilenameMarker = "%s";
 35
 36// static
 37const std::string LLExternalEditor::sSetting = "ExternalEditor";
 38
 39LLExternalEditor::EErrorCode LLExternalEditor::setCommand(const std::string& env_var, const std::string& override)
 40{
 41	std::string cmd = findCommand(env_var, override);
 42	if (cmd.empty())
 43	{
 44		llwarns << "Editor command is empty or not set" << llendl;
 45		return EC_NOT_SPECIFIED;
 46	}
 47
 48	// Add the filename marker if missing.
 49	if (cmd.find(sFilenameMarker) == std::string::npos)
 50	{
 51		cmd += " \"" + sFilenameMarker + "\"";
 52		llinfos << "Adding the filename marker (" << sFilenameMarker << ")" << llendl;
 53	}
 54
 55	string_vec_t tokens;
 56	if (tokenize(tokens, cmd) < 2) // 2 = bin + at least one arg (%s)
 57	{
 58		llwarns << "Error parsing editor command" << llendl;
 59		return EC_PARSE_ERROR;
 60	}
 61
 62	// Check executable for existence.
 63	std::string bin_path = tokens[0];
 64	if (!LLFile::isfile(bin_path))
 65	{
 66		llwarns << "Editor binary [" << bin_path << "] not found" << llendl;
 67		return EC_BINARY_NOT_FOUND;
 68	}
 69
 70	// Save command.
 71	mProcess.setExecutable(bin_path);
 72	mArgs.clear();
 73	for (size_t i = 1; i < tokens.size(); ++i)
 74	{
 75		if (i > 1) mArgs += " ";
 76		mArgs += "\"" + tokens[i] + "\"";
 77	}
 78	llinfos << "Setting command [" << bin_path << " " << mArgs << "]" << llendl;
 79
 80	return EC_SUCCESS;
 81}
 82
 83LLExternalEditor::EErrorCode LLExternalEditor::run(const std::string& file_path)
 84{
 85	std::string args = mArgs;
 86	if (mProcess.getExecutable().empty() || args.empty())
 87	{
 88		llwarns << "Editor command not set" << llendl;
 89		return EC_NOT_SPECIFIED;
 90	}
 91
 92	// Substitute the filename marker in the command with the actual passed file name.
 93	LLStringUtil::replaceString(args, sFilenameMarker, file_path);
 94
 95	// Split command into separate tokens.
 96	string_vec_t tokens;
 97	tokenize(tokens, args);
 98
 99	// Set process arguments taken from the command.
100	mProcess.clearArguments();
101	for (string_vec_t::const_iterator arg_it = tokens.begin(); arg_it != tokens.end(); ++arg_it)
102	{
103		mProcess.addArgument(*arg_it);
104	}
105
106	// Run the editor.
107	llinfos << "Running editor command [" << mProcess.getExecutable() + " " + args << "]" << llendl;
108	int result = mProcess.launch();
109	if (result == 0)
110	{
111		// Prevent killing the process in destructor (will add it to the zombies list).
112		mProcess.orphan();
113	}
114
115	return result == 0 ? EC_SUCCESS : EC_FAILED_TO_RUN;
116}
117
118// static
119std::string LLExternalEditor::getErrorMessage(EErrorCode code)
120{
121	switch (code)
122	{
123	case EC_SUCCESS: 			return LLTrans::getString("ok");
124	case EC_NOT_SPECIFIED: 		return LLTrans::getString("ExternalEditorNotSet");
125	case EC_PARSE_ERROR:		return LLTrans::getString("ExternalEditorCommandParseError");
126	case EC_BINARY_NOT_FOUND:	return LLTrans::getString("ExternalEditorNotFound");
127	case EC_FAILED_TO_RUN:		return LLTrans::getString("ExternalEditorFailedToRun");
128	}
129
130	return LLTrans::getString("Unknown");
131}
132
133// static
134size_t LLExternalEditor::tokenize(string_vec_t& tokens, const std::string& str)
135{
136	tokens.clear();
137
138	// Split the argument string into separate strings for each argument
139	typedef boost::tokenizer< boost::char_separator<char> > tokenizer;
140	boost::char_separator<char> sep("", "\" ", boost::drop_empty_tokens);
141
142	tokenizer tokens_list(str, sep);
143	tokenizer::iterator token_iter;
144	BOOL inside_quotes = FALSE;
145	BOOL last_was_space = FALSE;
146	for (token_iter = tokens_list.begin(); token_iter != tokens_list.end(); ++token_iter)
147	{
148		if (!strncmp("\"",(*token_iter).c_str(),2))
149		{
150			inside_quotes = !inside_quotes;
151		}
152		else if (!strncmp(" ",(*token_iter).c_str(),2))
153		{
154			if(inside_quotes)
155			{
156				tokens.back().append(std::string(" "));
157				last_was_space = TRUE;
158			}
159		}
160		else
161		{
162			std::string to_push = *token_iter;
163			if (last_was_space)
164			{
165				tokens.back().append(to_push);
166				last_was_space = FALSE;
167			}
168			else
169			{
170				tokens.push_back(to_push);
171			}
172		}
173	}
174
175	return tokens.size();
176}
177
178// static
179std::string LLExternalEditor::findCommand(
180	const std::string& env_var,
181	const std::string& override)
182{
183	std::string cmd;
184
185	// Get executable path.
186	if (!override.empty())	// try the supplied override first
187	{
188		cmd = override;
189		llinfos << "Using override" << llendl;
190	}
191	else if (!LLUI::sSettingGroups["config"]->getString(sSetting).empty())
192	{
193		cmd = LLUI::sSettingGroups["config"]->getString(sSetting);
194		llinfos << "Using setting" << llendl;
195	}
196	else					// otherwise use the path specified by the environment variable
197	{
198		char* env_var_val = getenv(env_var.c_str());
199		if (env_var_val)
200		{
201			cmd = env_var_val;
202			llinfos << "Using env var " << env_var << llendl;
203		}
204	}
205
206	llinfos << "Found command [" << cmd << "]" << llendl;
207	return cmd;
208}