]> git.lyx.org Git - lyx.git/blob - src/converter.C
c1af3b58726f27f3fa18a7ebbffbf4c7e7c31eb8
[lyx.git] / src / converter.C
1 /* This file is part of
2  * ====================================================== 
3  * 
4  *           LyX, The Document Processor
5  *        
6  *           Copyright 1995 Matthias Ettrich
7  *           Copyright 1995-2000 The LyX Team.
8  *
9  * ====================================================== */
10
11 #include <config.h>
12
13 #ifdef __GNUG__
14 #pragma implementation
15 #endif
16
17 #include <queue>
18 #include <stack>
19 #include <algorithm>
20 #include <stdio.h>
21
22 #include "converter.h"
23 #include "lyxrc.h"
24 #include "support/syscall.h"
25 #include "support/path.h"
26 #include "debug.h"
27 #include "buffer.h"
28
29 #include "bufferview_funcs.h"
30 #include "LaTeX.h"
31 #include "LyXView.h"
32 #include "minibuffer.h"
33 #include "lyx_gui_misc.h"
34 #include "lyx_cb.h"
35
36 using std::map;
37 using std::vector;
38 using std::queue;
39 using std::stack;
40
41 //////////////////////////////////////////////////////////////////////////////
42
43 map<string, Format> Formats::formats;
44 vector<Command> Converter::commands;
45
46 //////////////////////////////////////////////////////////////////////////////
47
48 Format::Format(string const & n)
49         : name(n), in_degree(0)
50 {
51         struct Item {
52                 char const * name;
53                 char const * prettyname;
54         };
55         Item items[] = {
56                 { "tex", "LaTeX" },
57                 { "dvi", "DVI" },
58                 { "ps", "PostScript" },
59                 { "txt", "Ascii" },
60                 { "html", "HTML" },
61                 { "pdf", "PDF" },
62                 { 0, 0}
63         };
64
65         prettyname = n;
66         for (int i = 0; items[i].name != 0; ++i)
67                 if (items[i].name == n) {
68                         prettyname = items[i].prettyname;
69                         break;
70                 }
71 }
72
73
74 void Formats::Add(string const & name)
75 {
76         if (formats.find(name) == formats.end())
77                 formats[name] = Format(name);
78 }
79
80
81 void Formats::SetViewer(string const & name, string const & command)
82 {
83         Add(name);
84         Format * f = GetFormat(name);
85         if (!f->viewer.empty())
86                 lyxerr << "Error: a viewer for " << name
87                        << " is already defined!" << endl;
88         else
89                 f->viewer = command;
90 }
91
92
93 bool Formats::View(string const & filename)
94 {
95         string extension = GetExtension(filename);
96         Format * format = GetFormat(extension);
97         if (!format || format->viewer.empty()) {
98                 WriteAlert(_("Can not view file"),
99                            _("No information for viewing ")
100                            + Formats::PrettyName(extension));
101                            return false;
102         }
103
104         string command = format->viewer;
105         command = subst(command, "$$FName", filename);
106 #ifndef __EMX__
107         command += " &";
108 #else
109         // OS/2 cmd.exe has another use for '&'
110         // This is not NLS safe, but it's OK, I think.
111         string sh = OnlyFilename(GetEnvPath("EMXSHELL"));
112         if (sh.empty()) {
113                 // COMSPEC is set, unless user unsets 
114                 sh = OnlyFilename(GetEnvPath("COMSPEC"));
115                 if (sh.empty())
116                         sh = "cmd.exe";
117         }
118         sh = lowercase(sh);
119         if (contains(sh, "cmd.exe")
120             || contains(sh, "4os2.exe"))
121                 command = "start /min/n " + command;
122         else
123                 command += " &";
124 #endif
125         lyxerr << "Executing command: " << command << endl;
126         //ShowMessage(buffer, _("Executing command:"), command);
127         Systemcalls one;
128         int res = one.startscript(Systemcalls::System, command);
129
130         if (res) {
131                 WriteAlert(_("Can not view file"),
132                            _("Error while executing"),
133                            command.substr(0, 50));
134                 return false;
135         }
136         return true;
137 }
138
139
140 Format * Formats::GetFormat(string const & name)
141 {
142         map<string, Format>::iterator it = formats.find(name);
143         if (it != formats.end())
144                 return &(*it).second;
145         else
146                 return 0;
147 }
148
149 string const Formats::PrettyName(string const & name)
150 {
151         string format;
152         Converter::SplitFormat(name, format);
153         Format * f = GetFormat(format);
154         if (f)
155                 return f->prettyname;
156         else
157                 return format;
158 }
159
160
161 //////////////////////////////////////////////////////////////////////////////
162 void Converter::Add(string const & from, string const & to,
163                     string const & command, string const & flags)
164 {
165         for (vector<Command>::const_iterator cit = commands.begin();
166              cit != commands.end(); ++cit)
167                 if ((*cit).from == from && (*cit).to == to) {
168                         lyxerr << "Error: Convertor from " << from
169                                << " to " << to
170                                << " already exists!" << endl;
171                         return;
172                 }
173         bool original_dir = flags == "origdir";
174         commands.push_back(Command(from, to, command, original_dir));
175
176         Formats::Add(from);
177         Formats::Add(to);
178         ++Formats::GetFormat(to)->in_degree;
179 }
180
181
182 vector< pair<string,string> > const
183 Converter::GetReachable(string const & from, bool only_viewable)
184 {
185         vector< pair<string,string> > result;
186         Format * format = Formats::GetFormat(from);
187         if (!format)
188                 return result;
189
190         int sort_start = 0;
191         if (!only_viewable || !format->viewer.empty()) {
192                 result.push_back(pair<string,string>(from, format->prettyname));
193                 sort_start = 1;
194         }
195
196         queue< vector<Command>::iterator > Q;
197         for (vector<Command>::iterator it = commands.begin();
198              it != commands.end(); ++it)
199                 if ((*it).from == from) {
200                         Q.push(it);
201                         (*it).visited = true;
202                 } else
203                         (*it).visited = false;
204
205         while (!Q.empty()) {
206                 vector<Command>::iterator it = Q.front();
207                 format = Formats::GetFormat((*it).to);
208                 string name = format->name;
209                 string prettyname = format->prettyname;
210                 if (format->in_degree > 1) {
211                         name += ":" + (*it).from;
212                         string tmp;
213                         split((*it).command, tmp, ' ');
214                         prettyname  += _("(using ") + tmp + ")";        
215                 }
216                 if (!only_viewable || !format->viewer.empty())
217                         result.push_back(pair<string,string>(name, prettyname));
218                 Q.pop();
219                 for (vector<Command>::iterator it2 = commands.begin();
220                      it2 != commands.end(); ++it2)
221                         if (!(*it2).visited && (*it).to == (*it2).from) {
222                                 Q.push(it2);
223                                 (*it2).visited = true;
224                         }
225         }
226
227         sort(result.begin() + sort_start, result.end());
228         return result;
229 }
230
231
232 bool Converter::convert(Buffer * buffer, string const & from_file,
233                         string const & to_format)
234
235 {
236         string format;
237         string using_format = SplitFormat(to_format, format);
238         string from_format = GetExtension(from_file);
239         if (from_format == format)
240                 return true;
241
242         queue< vector<Command>::iterator > Q;
243         for (vector<Command>::iterator it = commands.begin();
244              it != commands.end(); ++it)
245                 if ((*it).from == from_format) {
246                         Q.push(it);
247                         (*it).visited = true;
248                         (*it).previous = commands.end();
249                 } else
250                         (*it).visited = false;
251
252         if (Q.empty()) {
253                 WriteAlert(_("Can not convert file"),
254                            ("Unknown format ") + from_format);
255                 return false;
256         }
257
258         bool found = false;
259         vector<Command>::iterator it;
260         while (!Q.empty()) {
261                 it = Q.front();
262                 if ((*it).to == format &&
263                     (using_format.empty() || using_format == (*it).from)) {
264                         found = true;
265                         break;
266                 }
267                 Q.pop();
268                 for (vector<Command>::iterator it2 = commands.begin();
269                      it2 != commands.end(); ++it2)
270                         if (!(*it2).visited && (*it).to == (*it2).from) {
271                                 Q.push(it2);
272                                 (*it2).visited = true;
273                                 (*it2).previous = it;
274                         }
275         }
276
277         if (!found) {
278                 WriteAlert(_("Can not convert file"),
279                            _("No information for converting from ")
280                            + Formats::PrettyName(from_format) + _(" to ")
281                            + Formats::PrettyName(to_format));
282                 return false;
283         }
284
285         stack< vector<Command>::iterator > S;
286         while (it != commands.end()) {
287                 S.push(it);
288                 it = (*it).previous;
289         }
290
291         //Path p(OnlyPath(buffer->fileName()));
292         Path p(OnlyPath(from_file));
293
294         string basename = ChangeExtension(from_file, "");
295         while (!S.empty()) {
296                 it = S.top();
297                 S.pop();
298                 lyxerr << "Converting from  "
299                        << (*it).from << " to " << (*it).to << endl;
300
301                 if ((*it).from == "tex" &&
302                     ( (*it).to == "dvi" || (*it).to == "pdf") ) {
303                         lyxrc.pdf_mode = (*it).to == "pdf";
304                         if (!runLaTeX(buffer, (*it).command))
305                                 return false;
306                 } else {
307                         string infile = ChangeExtension(from_file, (*it).from);
308                         if (!(*it).original_dir)
309                                 infile = OnlyFilename(infile);
310                         string outfile = ChangeExtension(infile, (*it).to);
311
312                         string command = (*it).command;
313                         command = subst(command, "$$FName", infile);
314                         command = subst(command, "$$BaseName", basename);
315                         command = subst(command, "$$OutName", outfile);
316                         lyxerr << "Calling " << command << endl;
317                         ShowMessage(buffer, _("Executing command:"), command);
318                         
319                         Systemcalls one;
320                         int res;
321                         if ((*it).original_dir) {
322                                 Path p(buffer->filepath);
323                                 res = one.startscript(Systemcalls::System, command);
324                         } else
325                                 res = one.startscript(Systemcalls::System, command);
326                         if (res) {
327                                 WriteAlert(_("Can not convert file"),
328                                            "Error while executing",
329                                            command.substr(0, 50));
330                                 return false;
331                         }
332                 }
333         }
334
335         return true;
336 }
337
338
339 string const Converter::SplitFormat(string const & str, string & format)
340 {
341         string using_format = split(str, format, ':');
342         if (format.empty())
343                 format = "dvi";
344         return using_format;
345 }
346
347
348 bool Converter::runLaTeX(Buffer * buffer, string const & command)
349 {
350         
351         BufferView * bv = buffer->getUser();
352
353         if (!bv->text) return 0;
354
355         ProhibitInput(bv);
356
357         string name = buffer->getLatexName();
358
359         bv->owner()->getMiniBuffer()->Set(_("Running LaTeX..."));   
360
361         // Remove all error insets
362         bool a = bv->removeAutoInsets();
363
364         // do the LaTex run(s)
365         TeXErrors terr;
366         LaTeX latex(command, name, buffer->filepath);
367         int result = latex.run(terr,
368                             bv->owner()->getMiniBuffer()); // running latex
369
370         if ((result & LaTeX::ERRORS)) {
371                 // Insert all errors as errors boxes
372                 bv->insertErrors(terr);
373         }
374
375         // if we removed error insets before we ran LaTeX or if we inserted
376         // error insets after we ran LaTeX this must be run:
377         if (a || (result & LaTeX::ERRORS)){
378                 bv->redraw();
379                 bv->fitCursor();
380                 //bv->updateScrollbar();
381         }
382
383         // check return value from latex.run().
384         if ((result & LaTeX::NO_LOGFILE)) {
385                 WriteAlert(_("LaTeX did not work!"),
386                            _("Missing log file:"), name);
387         } else if ((result & LaTeX::ERRORS)) {
388                 int num_errors = latex.getNumErrors();
389                 string s;
390                 string t;
391                 if (num_errors == 1) {
392                         s = _("One error detected");
393                         t = _("You should try to fix it.");
394                 } else {
395                         s = tostr(num_errors);
396                         s += _(" errors detected.");
397                         t = _("You should try to fix them.");
398                 }
399                 WriteAlert(_("There were errors during the LaTeX run."),
400                            s, t);
401         }
402         AllowInput(bv);
403  
404         return (result & (LaTeX::NO_LOGFILE | LaTeX::ERRORS)) == 0;
405
406 }
407