]> git.lyx.org Git - lyx.git/blob - src/insets/ExternalSupport.C
a2c9340f13ce787a6a6cbf6f9813bf121647efbc
[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 namespace support = lyx::support;
33
34 using std::endl;
35
36 using std::ostream;
37 using std::string;
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         Template const * const et_ptr = getTemplatePtr(params);
53         if (!et_ptr)
54                 return;
55         Template const & et = *et_ptr;
56
57         if (et.editCommand.empty())
58                 return;
59
60         string const command = doSubstitution(params, buffer, et.editCommand);
61
62         support::Path p(buffer.filePath());
63         support::Forkedcall call;
64         if (lyxerr.debugging(Debug::EXTERNAL)) {
65                 lyxerr << "Executing '" << command << "' in '"
66                        << buffer.filePath() << '\'' << endl;
67         }
68         call.startscript(support::Forkedcall::DontWait, command);
69 }
70
71
72 namespace {
73
74 string const doSubstitution(InsetExternalParams const & params,
75                             Buffer const & buffer, string const & s,
76                             string const & filename)
77 {
78         string result;
79         string const basename = support::ChangeExtension(filename, string());
80         string const filepath = support::OnlyPath(filename);
81
82         result = support::subst(s, "$$FName", filename);
83         result = support::subst(result, "$$Basename", basename);
84         result = support::subst(result, "$$FPath", filepath);
85         result = support::subst(result, "$$Tempname", params.tempname());
86         result = support::subst(result, "$$Sysdir", support::system_lyxdir());
87
88         // Handle the $$Contents(filename) syntax
89         if (support::contains(result, "$$Contents(\"")) {
90
91                 string::size_type const pos = result.find("$$Contents(\"");
92                 string::size_type const end = result.find("\")", pos);
93                 string const file = result.substr(pos + 12, end - (pos + 12));
94                 string contents;
95
96                 string const filepath = support::IsFileReadable(file) ?
97                         buffer.filePath() : buffer.temppath();
98                 support::Path p(filepath);
99
100                 if (support::IsFileReadable(file))
101                         contents = support::GetFileContents(file);
102
103                 result = support::subst(result,
104                                         ("$$Contents(\"" + file + "\")").c_str(),
105                                         contents);
106         }
107
108         return result;
109 }
110
111 /** update the file represented by the template.
112     If \param external_in_tmpdir == true, then the generated file is
113     place in the buffer's temporary directory.
114 */
115 void updateExternal(InsetExternalParams const & params,
116                     string const & format,
117                     Buffer const & buffer,
118                     bool external_in_tmpdir)
119 {
120         Template const * const et_ptr = getTemplatePtr(params);
121         if (!et_ptr)
122                 return; // FAILURE
123         Template const & et = *et_ptr;
124
125         if (!et.automaticProduction)
126                 return; // NOT_NEEDED
127
128         Template::Formats::const_iterator cit = et.formats.find(format);
129         if (cit == et.formats.end())
130                 return; // FAILURE
131
132         Template::Format const & outputFormat = cit->second;
133         if (outputFormat.updateResult.empty())
134                 return; // NOT_NEEDED
135
136         string from_format = et.inputFormat;
137         if (from_format.empty())
138                 return; // NOT_NEEDED
139
140         string from_file = params.filename.absFilename();
141
142         if (from_format == "*") {
143                 if (from_file.empty())
144                         return; // NOT_NEEDED
145
146                 // Try and ascertain the file format from its contents.
147                 from_format = support::getExtFromContents(from_file);
148                 if (from_format.empty())
149                         return; // FAILURE
150         }
151
152         string const to_format = outputFormat.updateFormat;
153         if (to_format.empty())
154                 return; // NOT_NEEDED
155
156         if (!converters.isReachable(from_format, to_format)) {
157                 lyxerr[Debug::EXTERNAL]
158                         << "external::updateExternal. "
159                         << "Unable to convert from "
160                         << from_format << " to " << to_format << endl;
161                 return; // FAILURE
162         }
163
164         if (external_in_tmpdir && !from_file.empty()) {
165                 // We are running stuff through LaTeX
166                 string const temp_file =
167                         support::MakeAbsPath(params.filename.mangledFilename(),
168                                              buffer.temppath());
169                 unsigned long const from_checksum = support::sum(from_file);
170                 unsigned long const temp_checksum = support::sum(temp_file);
171
172                 if (from_checksum != temp_checksum) {
173                         if (!support::copy(from_file, temp_file))
174                                 return; // FAILURE
175                 }
176
177                 from_file = temp_file;
178         }
179
180         string const to_file = doSubstitution(params, buffer,
181                                               outputFormat.updateResult,
182                                               from_file);
183
184         string const abs_to_file =
185                 support::MakeAbsPath(to_file, buffer.filePath());
186
187         // Do we need to perform the conversion?
188         // Yes if to_file does not exist or if from_file is newer than to_file
189         if (support::compare_timestamps(from_file, abs_to_file) < 0)
190                 return; // SUCCESS
191
192         string const to_file_base =
193                 support::ChangeExtension(to_file, string());
194         /* bool const success = */
195                 converters.convert(&buffer, from_file, to_file_base,
196                                    from_format, to_format);
197         // return success
198 }
199
200 } // namespace anon
201
202
203 int writeExternal(InsetExternalParams const & params,
204                   string const & format,
205                   Buffer const & buffer, ostream & os,
206                   bool external_in_tmpdir)
207 {
208         Template const * const et_ptr = getTemplatePtr(params);
209         if (!et_ptr)
210                 return 0;
211         Template const & et = *et_ptr;
212
213         Template::Formats::const_iterator cit = et.formats.find(format);
214         if (cit == et.formats.end()) {
215                 lyxerr[Debug::EXTERNAL]
216                         << "External template format '" << format
217                         << "' not specified in template "
218                         << params.templatename() << endl;
219                 return 0;
220         }
221
222         updateExternal(params, format, buffer, external_in_tmpdir);
223
224         string from_file = params.filename.outputFilename(buffer.filePath());
225         if (external_in_tmpdir && !from_file.empty()) {
226                 // We are running stuff through LaTeX
227                 from_file =
228                         support::MakeAbsPath(params.filename.mangledFilename(),
229                                              buffer.temppath());
230         }
231         
232         string const str = doSubstitution(params, buffer, cit->second.product,
233                                           from_file);
234         os << str;
235         return int(lyx::count(str.begin(), str.end(),'\n') + 1);
236 }
237
238
239 /// Substitute meta-variables in this string
240 string const doSubstitution(InsetExternalParams const & params,
241                             Buffer const & buffer, string const & s)
242 {
243         string const buffer_path = buffer.filePath();
244         string const filename = params.filename.outputFilename(buffer_path);
245         return doSubstitution(params, buffer, s, filename);
246 }
247
248 } // namespace external
249 } // namespace lyx