]> git.lyx.org Git - lyx.git/blob - src/insets/ExternalSupport.C
0ae746b5745c600ebdeabd7b193b00b6af98987a
[lyx.git] / src / insets / ExternalSupport.C
1 /**
2  * \file ExternalSupport.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Asger Alstrup Nielsen
7  * \author Angus Leeming
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "ExternalSupport.h"
15 #include "insetexternal.h"
16
17 #include "buffer.h"
18 #include "converter.h"
19 #include "debug.h"
20 #include "ExternalTemplate.h"
21
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"
29
30 #include "support/std_ostream.h"
31
32
33 namespace support = lyx::support;
34
35 using std::endl;
36 using std::string;
37 using std::ostream;
38
39
40 namespace lyx {
41 namespace external {
42
43 Template const * getTemplatePtr(InsetExternalParams const & params)
44 {
45         TemplateManager const & etm = TemplateManager::get();
46         return etm.getTemplateByName(params.templatename());
47 }
48
49
50 void editExternal(InsetExternalParams const & params, Buffer const & buffer)
51 {
52         external::Template const * const et_ptr =
53                 external::getTemplatePtr(params);
54         if (!et_ptr)
55                 return;
56         external::Template const & et = *et_ptr;
57
58         if (et.editCommand.empty())
59                 return;
60
61         string const command = doSubstitution(params, buffer, et.editCommand);
62
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;
68         }
69         call.startscript(support::Forkedcall::DontWait, command);
70 }
71
72
73 namespace {
74
75 string const doSubstitution(InsetExternalParams const & params,
76                             Buffer const & buffer, string const & s,
77                             string const & filename)
78 {
79         string result;
80         string const basename = support::ChangeExtension(filename, string());
81         string const filepath = support::OnlyPath(filename);
82
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());
88
89         // Handle the $$Contents(filename) syntax
90         if (support::contains(result, "$$Contents(\"")) {
91
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));
95                 string contents;
96
97                 string const filepath = support::IsFileReadable(file) ?
98                         buffer.filePath() : buffer.temppath();
99                 support::Path p(filepath);
100
101                 if (support::IsFileReadable(file))
102                         contents = support::GetFileContents(file);
103
104                 result = support::subst(result,
105                                         ("$$Contents(\"" + file + "\")").c_str(),
106                                         contents);
107         }
108
109         return result;
110 }
111
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.
115 */
116 void updateExternal(InsetExternalParams const & params,
117                     string const & format,
118                     Buffer const & buffer,
119                     bool external_in_tmpdir)
120 {
121         external::Template const * const et_ptr =
122                 external::getTemplatePtr(params);
123         if (!et_ptr)
124                 return; // FAILURE
125         external::Template const & et = *et_ptr;
126
127         if (!et.automaticProduction)
128                 return; // NOT_NEEDED
129
130         external::Template::Formats::const_iterator cit =
131                 et.formats.find(format);
132         if (cit == et.formats.end())
133                 return; // FAILURE
134
135         external::Template::Format const & outputFormat = cit->second;
136         if (outputFormat.updateResult.empty())
137                 return; // NOT_NEEDED
138
139         string from_format = et.inputFormat;
140         if (from_format.empty())
141                 return; // NOT_NEEDED
142
143         string from_file = params.filename.absFilename();
144
145         if (from_format == "*") {
146                 if (from_file.empty())
147                         return; // NOT_NEEDED
148
149                 // Try and ascertain the file format from its contents.
150                 from_format = support::getExtFromContents(from_file);
151                 if (from_format.empty())
152                         return; // FAILURE
153         }
154
155         string const to_format = outputFormat.updateFormat;
156         if (to_format.empty())
157                 return; // NOT_NEEDED
158
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;
164                 return; // FAILURE
165         }
166
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(),
171                                              buffer.temppath());
172                 unsigned long const from_checksum = support::sum(from_file);
173                 unsigned long const temp_checksum = support::sum(temp_file);
174
175                 if (from_checksum != temp_checksum) {
176                         if (!support::copy(from_file, temp_file))
177                                 return; // FAILURE
178                 }
179
180                 from_file = temp_file;
181         }
182
183         string const to_file = doSubstitution(params, buffer,
184                                               outputFormat.updateResult,
185                                               from_file);
186
187         string const abs_to_file =
188                 support::MakeAbsPath(to_file, buffer.filePath());
189
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)
193                 return; // SUCCESS
194
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);
200         // return success
201 }
202
203 } // namespace anon
204
205
206 int writeExternal(InsetExternalParams const & params,
207                   string const & format,
208                   Buffer const & buffer, ostream & os,
209                   bool external_in_tmpdir)
210 {
211         external::Template const * const et_ptr =
212                 external::getTemplatePtr(params);
213         if (!et_ptr)
214                 return 0;
215         external::Template const & et = *et_ptr;
216
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;
224                 return 0;
225         }
226
227         updateExternal(params, format, buffer, external_in_tmpdir);
228
229         string from_file = params.filename.outputFilename(buffer.filePath());
230         if (external_in_tmpdir && !from_file.empty()) {
231                 // We are running stuff through LaTeX
232                 from_file =
233                         support::MakeAbsPath(params.filename.mangledFilename(),
234                                              buffer.temppath());
235         }
236         
237         string const str = doSubstitution(params, buffer, cit->second.product,
238                                           from_file);
239         os << str;
240         return int(lyx::count(str.begin(), str.end(),'\n') + 1);
241 }
242
243
244 /// Substitute meta-variables in this string
245 string const doSubstitution(InsetExternalParams const & params,
246                             Buffer const & buffer, string const & s)
247 {
248         string const buffer_path = buffer.filePath();
249         string const filename = params.filename.outputFilename(buffer_path);
250         return doSubstitution(params, buffer, s, filename);
251 }
252
253 } // namespace external
254 } // namespace lyx