2 * \file ExternalSupport.C
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Asger Alstrup Nielsen
7 * \author Angus Leeming
9 * Full author contact details are available in file CREDITS.
14 #include "ExternalSupport.h"
15 #include "insetexternal.h"
18 #include "converter.h"
20 #include "ExternalTemplate.h"
22 #include "support/filetools.h"
23 #include "support/forkedcall.h"
24 #include "support/lstrings.h"
25 #include "support/lyxalgo.h"
26 #include "support/lyxlib.h"
27 #include "support/path.h"
28 #include "support/path_defines.h"
30 #include "support/std_ostream.h"
33 namespace support = lyx::support;
43 Template const * getTemplatePtr(InsetExternalParams const & params)
45 TemplateManager const & etm = TemplateManager::get();
46 return etm.getTemplateByName(params.templatename());
50 void editExternal(InsetExternalParams const & params, Buffer const & buffer)
52 external::Template const * const et_ptr =
53 external::getTemplatePtr(params);
56 external::Template const & et = *et_ptr;
58 if (et.editCommand.empty())
61 string const command = doSubstitution(params, buffer, et.editCommand);
63 support::Path p(buffer.filePath());
64 support::Forkedcall call;
65 if (lyxerr.debugging(Debug::EXTERNAL)) {
66 lyxerr << "Executing '" << command << "' in '"
67 << buffer.filePath() << '\'' << endl;
69 call.startscript(support::Forkedcall::DontWait, command);
75 string const doSubstitution(InsetExternalParams const & params,
76 Buffer const & buffer, string const & s,
77 string const & filename)
80 string const basename = support::ChangeExtension(filename, string());
81 string const filepath = support::OnlyPath(filename);
83 result = support::subst(s, "$$FName", filename);
84 result = support::subst(result, "$$Basename", basename);
85 result = support::subst(result, "$$FPath", filepath);
86 result = support::subst(result, "$$Tempname", params.tempname());
87 result = support::subst(result, "$$Sysdir", support::system_lyxdir());
89 // Handle the $$Contents(filename) syntax
90 if (support::contains(result, "$$Contents(\"")) {
92 string::size_type const pos = result.find("$$Contents(\"");
93 string::size_type const end = result.find("\")", pos);
94 string const file = result.substr(pos + 12, end - (pos + 12));
97 string const filepath = support::IsFileReadable(file) ?
98 buffer.filePath() : buffer.temppath();
99 support::Path p(filepath);
101 if (support::IsFileReadable(file))
102 contents = support::GetFileContents(file);
104 result = support::subst(result,
105 ("$$Contents(\"" + file + "\")").c_str(),
112 /** update the file represented by the template.
113 If \param external_in_tmpdir == true, then the generated file is
114 place in the buffer's temporary directory.
116 void updateExternal(InsetExternalParams const & params,
117 string const & format,
118 Buffer const & buffer,
119 bool external_in_tmpdir)
121 external::Template const * const et_ptr =
122 external::getTemplatePtr(params);
125 external::Template const & et = *et_ptr;
127 if (!et.automaticProduction)
128 return; // NOT_NEEDED
130 external::Template::Formats::const_iterator cit =
131 et.formats.find(format);
132 if (cit == et.formats.end())
135 external::Template::Format const & outputFormat = cit->second;
136 if (outputFormat.updateResult.empty())
137 return; // NOT_NEEDED
139 string from_format = et.inputFormat;
140 if (from_format.empty())
141 return; // NOT_NEEDED
143 string from_file = params.filename.absFilename();
145 if (from_format == "*") {
146 if (from_file.empty())
147 return; // NOT_NEEDED
149 // Try and ascertain the file format from its contents.
150 from_format = support::getExtFromContents(from_file);
151 if (from_format.empty())
155 string const to_format = outputFormat.updateFormat;
156 if (to_format.empty())
157 return; // NOT_NEEDED
159 if (!converters.isReachable(from_format, to_format)) {
160 lyxerr[Debug::EXTERNAL]
161 << "InsetExternal::updateExternal. "
162 << "Unable to convert from "
163 << from_format << " to " << to_format << endl;
167 if (external_in_tmpdir && !from_file.empty()) {
168 // We are running stuff through LaTeX
169 string const temp_file =
170 support::MakeAbsPath(params.filename.mangledFilename(),
172 unsigned long const from_checksum = support::sum(from_file);
173 unsigned long const temp_checksum = support::sum(temp_file);
175 if (from_checksum != temp_checksum) {
176 if (!support::copy(from_file, temp_file))
180 from_file = temp_file;
183 string const to_file = doSubstitution(params, buffer,
184 outputFormat.updateResult,
187 string const abs_to_file =
188 support::MakeAbsPath(to_file, buffer.filePath());
190 // Do we need to perform the conversion?
191 // Yes if to_file does not exist or if from_file is newer than to_file
192 if (support::compare_timestamps(from_file, abs_to_file) < 0)
195 string const to_file_base =
196 support::ChangeExtension(to_file, string());
197 /* bool const success = */
198 converters.convert(&buffer, from_file, to_file_base,
199 from_format, to_format);
206 int writeExternal(InsetExternalParams const & params,
207 string const & format,
208 Buffer const & buffer, ostream & os,
209 bool external_in_tmpdir)
211 external::Template const * const et_ptr =
212 external::getTemplatePtr(params);
215 external::Template const & et = *et_ptr;
217 external::Template::Formats::const_iterator cit =
218 et.formats.find(format);
219 if (cit == et.formats.end()) {
220 lyxerr[Debug::EXTERNAL]
221 << "External template format '" << format
222 << "' not specified in template "
223 << params.templatename() << endl;
227 updateExternal(params, format, buffer, external_in_tmpdir);
229 string from_file = params.filename.outputFilename(buffer.filePath());
230 if (external_in_tmpdir && !from_file.empty()) {
231 // We are running stuff through LaTeX
233 support::MakeAbsPath(params.filename.mangledFilename(),
237 string const str = doSubstitution(params, buffer, cit->second.product,
240 return int(lyx::count(str.begin(), str.end(),'\n') + 1);
244 /// Substitute meta-variables in this string
245 string const doSubstitution(InsetExternalParams const & params,
246 Buffer const & buffer, string const & s)
248 string const buffer_path = buffer.filePath();
249 string const filename = params.filename.outputFilename(buffer_path);
250 return doSubstitution(params, buffer, s, filename);
253 } // namespace external