]> git.lyx.org Git - lyx.git/blob - src/converter.C
cf38de44bf59bc747fd43a06f58ed5ff717e8d7d
[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
35 using std::map;
36 using std::vector;
37 using std::queue;
38 using std::stack;
39
40 extern void ShowMessage(Buffer * buf,
41                  string const & msg1,
42                  string const & msg2 = string(),
43                  string const & msg3 = string(), int delay = 6);
44
45 //////////////////////////////////////////////////////////////////////////////
46
47 map<string, Format> Formats::formats;
48 vector<Command> Converter::commands;
49
50 //////////////////////////////////////////////////////////////////////////////
51
52 Format::Format(string const & n) : name(n), in_degree(0)
53 {
54         struct Item {
55                 char const * name;
56                 char const * prettyname;
57         };
58         Item items[] = {
59                 { "tex", "LaTeX" },
60                 { "dvi", "DVI" },
61                 { "ps", "PostScript" },
62                 { "txt", "Ascii" },
63                 { "html", "HTML" },
64                 { "pdf", "PDF" },
65                 { 0, 0}
66         };
67
68         prettyname = n;
69         for (int i = 0; items[i].name != 0; ++i)
70                 if (items[i].name == n) {
71                         prettyname = items[i].prettyname;
72                         break;
73                 }
74 }
75
76 void Formats::Add(string const & name)
77 {
78         if (formats.find(name) == formats.end())
79                 formats[name] = Format(name);
80 }
81
82 void Formats::SetViewer(string const & name, string const & command)
83 {
84         Add(name);
85         Format * f = GetFormat(name);
86         if (!f->viewer.empty())
87                 lyxerr << "Error: a viewer for " << name
88                        << " is already defined!" << endl;
89         else
90                 f->viewer = command;
91 }
92
93
94 bool Formats::View(string const & filename)
95 {
96         string extension = GetExtension(filename);
97         Format * format = GetFormat(extension);
98         if (!format || format->viewer.empty()) {
99                 WriteAlert(_("Can not view file"),
100                            _("No information for viewing ")
101                            + Formats::PrettyName(extension));
102                            return false;
103         }
104
105         string command = format->viewer;
106         command = subst(command, "$$FName", filename);
107 #ifndef __EMX__
108         command += " &";
109 #else
110         // OS/2 cmd.exe has another use for '&'
111         // This is not NLS safe, but it's OK, I think.
112         string sh = OnlyFilename(GetEnvPath("EMXSHELL"));
113         if (sh.empty()) {
114                 // COMSPEC is set, unless user unsets 
115                 sh = OnlyFilename(GetEnvPath("COMSPEC"));
116                 if (sh.empty())
117                         sh = "cmd.exe";
118         }
119         sh = lowercase(sh);
120         if (contains(sh, "cmd.exe")
121             || contains(sh, "4os2.exe"))
122                 command = "start /min/n " + command;
123         else
124                 command += " &";
125 #endif
126         lyxerr << "Executing command: " << command << endl;
127         //ShowMessage(buffer, _("Executing command:"), command);
128         Systemcalls one;
129         int res = one.startscript(Systemcalls::System, command);
130
131         if (res) {
132                 WriteAlert(_("Can not view file"),
133                            _("Error while executing"),
134                            command.substr(0, 50));
135                 return false;
136         }
137         return true;
138 }
139
140
141 Format * Formats::GetFormat(string const & name)
142 {
143         map<string, Format>::iterator it = formats.find(name);
144         if (it != formats.end())
145                 return &(*it).second;
146         else
147                 return 0;
148 }
149
150 string Formats::PrettyName(string const & name)
151 {
152
153         string format;
154         Converter::SplitFormat(name, format);
155         Format * f = GetFormat(format);
156         if (f)
157                 return f->prettyname;
158         else
159                 return format;
160 }
161
162 //////////////////////////////////////////////////////////////////////////////
163 void Converter::Add(string const & from, string const & to,
164                     string const & command, string const & flags)
165 {
166         for (vector<Command>::const_iterator cit = commands.begin();
167              cit != commands.end(); ++cit)
168                 if ((*cit).from == from && (*cit).to == to) {
169                         lyxerr << "Error: Convertor from " << from
170                                << " to " << to
171                                << " already exists!" << endl;
172                         return;
173                 }
174         bool original_dir = flags == "origdir";
175         commands.push_back(Command(from, to, command, original_dir));
176
177         Formats::Add(from);
178         Formats::Add(to);
179         ++Formats::GetFormat(to)->in_degree;
180 }
181
182 vector< pair<string,string> > 
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 using_format, format;
237         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 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 bool Converter::runLaTeX(Buffer * buffer, string const & command)
348 {
349         
350         BufferView * bv = buffer->getUser();
351
352         if (!bv->text) return 0;
353
354         ProhibitInput(bv);
355
356         string name = buffer->getLatexName();
357
358         bv->owner()->getMiniBuffer()->Set(_("Running LaTeX..."));   
359
360         // Remove all error insets
361         bool a = bv->removeAutoInsets();
362
363         // do the LaTex run(s)
364         TeXErrors terr;
365         LaTeX latex(command, name, buffer->filepath);
366         int result = latex.run(terr,
367                             bv->owner()->getMiniBuffer()); // running latex
368
369         if ((result & LaTeX::ERRORS)) {
370                 // Insert all errors as errors boxes
371                 bv->insertErrors(terr);
372         }
373
374         // if we removed error insets before we ran LaTeX or if we inserted
375         // error insets after we ran LaTeX this must be run:
376         if (a || (result & LaTeX::ERRORS)){
377                 bv->redraw();
378                 bv->fitCursor();
379                 //bv->updateScrollbar();
380         }
381
382         // check return value from latex.run().
383         if ((result & LaTeX::NO_LOGFILE)) {
384                 WriteAlert(_("LaTeX did not work!"),
385                            _("Missing log file:"), name);
386         } else if ((result & LaTeX::ERRORS)) {
387                 int num_errors = latex.getNumErrors();
388                 string s;
389                 string t;
390                 if (num_errors == 1) {
391                         s = _("One error detected");
392                         t = _("You should try to fix it.");
393                 } else {
394                         s = tostr(num_errors);
395                         s += _(" errors detected.");
396                         t = _("You should try to fix them.");
397                 }
398                 WriteAlert(_("There were errors during the LaTeX run."),
399                            s, t);
400         }
401         AllowInput(bv);
402  
403         return (result & (LaTeX::NO_LOGFILE | LaTeX::ERRORS)) == 0;
404
405 }
406