PageRenderTime 34ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/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
Possible License(s): LGPL-2.1
  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. #include "llviewerprecompiledheaders.h"
  27. #include "llexternaleditor.h"
  28. #include "lltrans.h"
  29. #include "llui.h"
  30. // static
  31. const std::string LLExternalEditor::sFilenameMarker = "%s";
  32. // static
  33. const std::string LLExternalEditor::sSetting = "ExternalEditor";
  34. LLExternalEditor::EErrorCode LLExternalEditor::setCommand(const std::string& env_var, const std::string& override)
  35. {
  36. std::string cmd = findCommand(env_var, override);
  37. if (cmd.empty())
  38. {
  39. llwarns << "Editor command is empty or not set" << llendl;
  40. return EC_NOT_SPECIFIED;
  41. }
  42. // Add the filename marker if missing.
  43. if (cmd.find(sFilenameMarker) == std::string::npos)
  44. {
  45. cmd += " \"" + sFilenameMarker + "\"";
  46. llinfos << "Adding the filename marker (" << sFilenameMarker << ")" << llendl;
  47. }
  48. string_vec_t tokens;
  49. if (tokenize(tokens, cmd) < 2) // 2 = bin + at least one arg (%s)
  50. {
  51. llwarns << "Error parsing editor command" << llendl;
  52. return EC_PARSE_ERROR;
  53. }
  54. // Check executable for existence.
  55. std::string bin_path = tokens[0];
  56. if (!LLFile::isfile(bin_path))
  57. {
  58. llwarns << "Editor binary [" << bin_path << "] not found" << llendl;
  59. return EC_BINARY_NOT_FOUND;
  60. }
  61. // Save command.
  62. mProcess.setExecutable(bin_path);
  63. mArgs.clear();
  64. for (size_t i = 1; i < tokens.size(); ++i)
  65. {
  66. if (i > 1) mArgs += " ";
  67. mArgs += "\"" + tokens[i] + "\"";
  68. }
  69. llinfos << "Setting command [" << bin_path << " " << mArgs << "]" << llendl;
  70. return EC_SUCCESS;
  71. }
  72. LLExternalEditor::EErrorCode LLExternalEditor::run(const std::string& file_path)
  73. {
  74. std::string args = mArgs;
  75. if (mProcess.getExecutable().empty() || args.empty())
  76. {
  77. llwarns << "Editor command not set" << llendl;
  78. return EC_NOT_SPECIFIED;
  79. }
  80. // Substitute the filename marker in the command with the actual passed file name.
  81. LLStringUtil::replaceString(args, sFilenameMarker, file_path);
  82. // Split command into separate tokens.
  83. string_vec_t tokens;
  84. tokenize(tokens, args);
  85. // Set process arguments taken from the command.
  86. mProcess.clearArguments();
  87. for (string_vec_t::const_iterator arg_it = tokens.begin(); arg_it != tokens.end(); ++arg_it)
  88. {
  89. mProcess.addArgument(*arg_it);
  90. }
  91. // Run the editor.
  92. llinfos << "Running editor command [" << mProcess.getExecutable() + " " + args << "]" << llendl;
  93. int result = mProcess.launch();
  94. if (result == 0)
  95. {
  96. // Prevent killing the process in destructor (will add it to the zombies list).
  97. mProcess.orphan();
  98. }
  99. return result == 0 ? EC_SUCCESS : EC_FAILED_TO_RUN;
  100. }
  101. // static
  102. std::string LLExternalEditor::getErrorMessage(EErrorCode code)
  103. {
  104. switch (code)
  105. {
  106. case EC_SUCCESS: return LLTrans::getString("ok");
  107. case EC_NOT_SPECIFIED: return LLTrans::getString("ExternalEditorNotSet");
  108. case EC_PARSE_ERROR: return LLTrans::getString("ExternalEditorCommandParseError");
  109. case EC_BINARY_NOT_FOUND: return LLTrans::getString("ExternalEditorNotFound");
  110. case EC_FAILED_TO_RUN: return LLTrans::getString("ExternalEditorFailedToRun");
  111. }
  112. return LLTrans::getString("Unknown");
  113. }
  114. // static
  115. size_t LLExternalEditor::tokenize(string_vec_t& tokens, const std::string& str)
  116. {
  117. tokens.clear();
  118. // Split the argument string into separate strings for each argument
  119. typedef boost::tokenizer< boost::char_separator<char> > tokenizer;
  120. boost::char_separator<char> sep("", "\" ", boost::drop_empty_tokens);
  121. tokenizer tokens_list(str, sep);
  122. tokenizer::iterator token_iter;
  123. BOOL inside_quotes = FALSE;
  124. BOOL last_was_space = FALSE;
  125. for (token_iter = tokens_list.begin(); token_iter != tokens_list.end(); ++token_iter)
  126. {
  127. if (!strncmp("\"",(*token_iter).c_str(),2))
  128. {
  129. inside_quotes = !inside_quotes;
  130. }
  131. else if (!strncmp(" ",(*token_iter).c_str(),2))
  132. {
  133. if(inside_quotes)
  134. {
  135. tokens.back().append(std::string(" "));
  136. last_was_space = TRUE;
  137. }
  138. }
  139. else
  140. {
  141. std::string to_push = *token_iter;
  142. if (last_was_space)
  143. {
  144. tokens.back().append(to_push);
  145. last_was_space = FALSE;
  146. }
  147. else
  148. {
  149. tokens.push_back(to_push);
  150. }
  151. }
  152. }
  153. return tokens.size();
  154. }
  155. // static
  156. std::string LLExternalEditor::findCommand(
  157. const std::string& env_var,
  158. const std::string& override)
  159. {
  160. std::string cmd;
  161. // Get executable path.
  162. if (!override.empty()) // try the supplied override first
  163. {
  164. cmd = override;
  165. llinfos << "Using override" << llendl;
  166. }
  167. else if (!LLUI::sSettingGroups["config"]->getString(sSetting).empty())
  168. {
  169. cmd = LLUI::sSettingGroups["config"]->getString(sSetting);
  170. llinfos << "Using setting" << llendl;
  171. }
  172. else // otherwise use the path specified by the environment variable
  173. {
  174. char* env_var_val = getenv(env_var.c_str());
  175. if (env_var_val)
  176. {
  177. cmd = env_var_val;
  178. llinfos << "Using env var " << env_var << llendl;
  179. }
  180. }
  181. llinfos << "Found command [" << cmd << "]" << llendl;
  182. return cmd;
  183. }