]> git.lyx.org Git - lyx.git/blob - src/converter.C
Reduced header file includes somewhat
[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-2001 The LyX Team.
8  *
9  * ====================================================== */
10
11 #include <config.h>
12
13 #ifdef __GNUG__
14 #pragma implementation
15 #endif
16
17 #include <cctype>
18
19 #include "converter.h"
20 #include "lyxrc.h"
21 #include "support/syscall.h"
22 #include "support/path.h"
23 #include "support/filetools.h"
24 #include "buffer.h"
25 #include "bufferview_funcs.h"
26 #include "LaTeX.h"
27 #include "LyXView.h"
28 #include "lyx_gui_misc.h"
29 #include "lyx_cb.h" // ShowMessage()
30 #include "support/lyxfunctional.h"
31 #include "gettext.h"
32 #include "BufferView.h"
33 #include "debug.h"
34
35 using std::vector;
36 using std::queue;
37 using std::endl;
38 using std::fill;
39 using std::find_if;
40 using std::reverse;
41 using std::sort;
42
43 namespace {
44
45 string const token_from("$$i");
46 string const token_base("$$b");
47 string const token_to("$$o");
48
49 //////////////////////////////////////////////////////////////////////////////
50
51 inline
52 string const add_options(string const & command, string const & options)
53 {
54         string head;
55         string const tail = split(command, head, ' ');
56         return head + ' ' + options + ' ' + tail;
57 }
58
59 } // namespace anon
60
61 //////////////////////////////////////////////////////////////////////////////
62
63 bool Format::dummy() const
64 {
65         return extension().empty();
66 }
67
68
69 bool Format::IsChildFormat() const
70 {
71         if (name_.empty())
72                 return false;
73         return isdigit(name_[name_.length() - 1]);
74 }
75
76
77 string const Format::ParentFormat() const
78 {
79         return name_.substr(0, name_.length() - 1);
80 }
81
82 //////////////////////////////////////////////////////////////////////////////
83
84 // This method should return a reference, and throw an exception
85 // if the format named name cannot be found (Lgb)
86 Format const * Formats::GetFormat(string const & name) const
87 {
88         FormatList::const_iterator cit =
89                 find_if(formatlist.begin(), formatlist.end(),
90                         lyx::compare_memfun(&Format::name, name));
91         if (cit != formatlist.end())
92                 return &(*cit);
93         else
94                 return 0;
95 }
96
97
98 int Formats::GetNumber(string const & name) const
99 {
100         FormatList::const_iterator cit =
101                 find_if(formatlist.begin(), formatlist.end(),
102                         lyx::compare_memfun(&Format::name, name));
103         if (cit != formatlist.end())
104                 return cit - formatlist.begin();
105         else
106                 return -1;
107 }
108
109
110 void Formats::Add(string const & name)
111 {
112         if (!GetFormat(name))
113                 Add(name, name, name, string());
114 }
115
116
117 void Formats::Add(string const & name, string const & extension, 
118                   string const & prettyname, string const & shortcut)
119 {
120         FormatList::iterator it = 
121                 find_if(formatlist.begin(), formatlist.end(),
122                         lyx::compare_memfun(&Format::name, name));
123         if (it == formatlist.end())
124                 formatlist.push_back(Format(name, extension, prettyname,
125                                             shortcut, ""));
126         else {
127                 string viewer = it->viewer();
128                 *it = Format(name, extension, prettyname, shortcut, viewer);
129         }
130 }
131
132
133 void Formats::Delete(string const & name)
134 {
135         FormatList::iterator it = 
136                 find_if(formatlist.begin(), formatlist.end(),
137                         lyx::compare_memfun(&Format::name, name));
138         if (it != formatlist.end())
139                 formatlist.erase(it);
140 }
141
142
143 void Formats::Sort()
144 {
145         sort(formatlist.begin(), formatlist.end());
146 }
147
148
149 void Formats::SetViewer(string const & name, string const & command)
150 {
151         Add(name);
152         FormatList::iterator it =
153                 find_if(formatlist.begin(), formatlist.end(),
154                         lyx::compare_memfun(&Format::name, name));
155         if (it != formatlist.end())
156                 it->setViewer(command);
157 }
158
159
160 bool Formats::View(Buffer const * buffer, string const & filename,
161                    string const & format_name) const
162 {
163         if (filename.empty())
164                 return false;
165
166         Format const * format = GetFormat(format_name);
167         if (format && format->viewer().empty() &&
168             format->IsChildFormat())
169                 format = GetFormat(format->ParentFormat());
170         if (!format || format->viewer().empty()) {
171                 WriteAlert(_("Can not view file"),
172                            _("No information for viewing ")
173                            + PrettyName(format_name));
174                            return false;
175         }
176
177         string command = format->viewer();
178
179         if (format_name == "dvi" &&
180             !lyxrc.view_dvi_paper_option.empty()) {
181                 command += " " + lyxrc.view_dvi_paper_option;
182                 string paper_size = converters.papersize(buffer);
183                 if (paper_size == "letter")
184                         paper_size = "us";
185                 command += " " + paper_size;
186                 if (buffer->params.orientation 
187                     == BufferParams::ORIENTATION_LANDSCAPE)
188                         command += 'r';
189         }
190
191         command += " " + QuoteName(OnlyFilename((filename)));
192
193         lyxerr[Debug::FILES] << "Executing command: " << command << endl;
194         ShowMessage(buffer, _("Executing command:"), command);
195
196         Path p(OnlyPath(filename));
197         Systemcalls one;
198         int const res = one.startscript(Systemcalls::SystemDontWait, command);
199
200         if (res) {
201                 WriteAlert(_("Can not view file"),
202                            _("Error while executing"),
203                            command.substr(0, 50));
204                 return false;
205         }
206         return true;
207 }
208
209
210 string const Formats::PrettyName(string const & name) const
211 {
212         Format const * format = GetFormat(name);
213         if (format)
214                 return format->prettyname();
215         else
216                 return name;
217 }
218
219
220 string const Formats::Extension(string const & name) const
221 {
222         Format const * format = GetFormat(name);
223         if (format)
224                 return format->extension();
225         else
226                 return name;
227 }
228
229 //////////////////////////////////////////////////////////////////////////////
230
231 void Converter::ReadFlags()
232 {
233         string flag_list(flags);
234         while (!flag_list.empty()) {
235                 string flag_name, flag_value;
236                 flag_list = split(flag_list, flag_value, ',');
237                 flag_value = split(flag_value, flag_name, '=');
238                 if (flag_name == "latex")
239                         latex = true;
240                 else if (flag_name == "originaldir")
241                         original_dir = true;
242                 else if (flag_name == "needaux")
243                         need_aux = true;
244                 else if (flag_name == "resultdir")
245                         result_dir = (flag_value.empty())
246                                 ? token_base : flag_value;
247                 else if (flag_name == "resultfile")
248                         result_file = flag_value;
249                 else if (flag_name == "parselog")
250                         parselog = flag_value;
251         }
252         if (!result_dir.empty() && result_file.empty())
253                 result_file = "index." + formats.Extension(to);
254         //if (!contains(command, token_from))
255         //      latex = true;
256 }
257
258
259 bool operator<(Converter const & a, Converter const & b)
260 {
261         int const i = compare_no_case(a.From->prettyname(),
262                                       b.From->prettyname());
263         if (i == 0)
264                 return compare_no_case(a.To->prettyname(), b.To->prettyname())
265                         < 0;
266         else
267                 return i < 0;
268 }
269
270 //////////////////////////////////////////////////////////////////////////////
271
272 class compare_Converter {
273 public:
274         compare_Converter(string const & f, string const & t)
275                 : from(f), to(t) {}
276         bool operator()(Converter const & c) {
277                 return c.from == from && c.to == to;
278         }
279 private:
280         string const & from;
281         string const & to;
282 };
283
284
285 Converter const * Converters::GetConverter(string const & from,
286                                             string const & to)
287 {
288         ConverterList::const_iterator cit =
289                 find_if(converterlist.begin(), converterlist.end(),
290                         compare_Converter(from, to));
291         if (cit != converterlist.end())
292                 return &(*cit);
293         else
294                 return 0;
295 }
296
297
298 int Converters::GetNumber(string const & from, string const & to)
299 {
300         ConverterList::const_iterator cit =
301                 find_if(converterlist.begin(), converterlist.end(),
302                         compare_Converter(from, to));
303         if (cit != converterlist.end())
304                 return cit - converterlist.begin();
305         else
306                 return -1;
307 }
308
309
310 void Converters::Add(string const & from, string const & to,
311                      string const & command, string const & flags)
312 {
313         formats.Add(from);
314         formats.Add(to);
315         ConverterList::iterator it = find_if(converterlist.begin(),
316                                              converterlist.end(),
317                                              compare_Converter(from, to));
318
319         Converter converter(from, to, command, flags);
320         if (it != converterlist.end() && !flags.empty() && flags[0] == '*') {
321                 converter = *it;
322                 converter.command = command;
323                 converter.flags = flags;
324         }
325         converter.ReadFlags();
326         
327         if (converter.latex && (latex_command.empty() || to == "dvi"))
328                 latex_command = subst(command, token_from, "");
329         // If we have both latex & pdflatex, we set latex_command to latex.
330         // The latex_command is used to update the .aux file when running
331         // a converter that uses it.
332
333         if (it == converterlist.end())
334                 converterlist.push_back(converter);
335         else {
336                 converter.From = it->From;
337                 converter.To = it->To;
338                 *it = converter;
339         }
340 }
341
342
343 void Converters::Delete(string const & from, string const & to)
344 {
345         ConverterList::iterator it = find_if(converterlist.begin(),
346                                              converterlist.end(),
347                                              compare_Converter(from, to));
348         if (it != converterlist.end())
349                 converterlist.erase(it);
350 }
351
352
353 // This method updates the pointers From and To in all the converters.
354 // The code is not very efficient, but it doesn't matter as the number
355 // of formats and converters is small.
356 // Furthermore, this method is called only on startup, or after 
357 // adding/deleting a format in FormPreferences (the latter calls can be
358 // eliminated if the formats in the Formats class are stored using a map or
359 // a list (instead of a vector), but this will cause other problems). 
360 void Converters::Update(Formats const & formats)
361 {
362         for (ConverterList::iterator it = converterlist.begin();
363              it != converterlist.end(); ++it) {
364                 it->From = formats.GetFormat(it->from);
365                 it->To = formats.GetFormat(it->to);
366         }
367 }
368
369
370 // This method updates the pointers From and To in the last converter.
371 // It is called when adding a new converter in FormPreferences
372 void Converters::UpdateLast(Formats const & formats)
373 {
374         if (converterlist.begin() != converterlist.end()) {
375                 ConverterList::iterator it = converterlist.end()-1;
376                 it->From = formats.GetFormat(it->from);
377                 it->To = formats.GetFormat(it->to);
378         }
379 }
380
381
382 void Converters::Sort()
383 {
384         sort(converterlist.begin(), converterlist.end());
385 }
386
387
388 int Converters::BFS_init(string const & start, bool clear_visited)
389 {
390         int const s = formats.GetNumber(start);
391         if (s < 0)
392                 return s;
393
394         Q = queue<int>();
395         if (clear_visited)
396                 fill(visited.begin(), visited.end(), false);
397         if (visited[s] == false) {
398                 Q.push(s);
399                 visited[s] = true;
400         }
401         return s;
402 }
403
404
405 vector<Format const *> const
406 Converters::GetReachableTo(string const & target, bool clear_visited)
407 {
408         vector<Format const *> result;
409         int const s = BFS_init(target, clear_visited);
410         if (s < 0)
411                 return result;
412
413         while (!Q.empty()) {
414                 int const i = Q.front();
415                 Q.pop();
416                 if (i != s || target != "lyx")
417                         result.push_back(&formats.Get(i));
418                 for (vector<int>::iterator it = vertices[i].in_vertices.begin();
419                      it != vertices[i].in_vertices.end(); ++it)
420                         if (!visited[*it]) {
421                                 visited[*it] = true;
422                                 Q.push(*it);
423                         }
424         }
425
426         return result;
427 }
428
429
430 vector<Format const *> const
431 Converters::GetReachable(string const & from, bool only_viewable,
432                          bool clear_visited)
433 {
434         vector<Format const *> result;
435
436         if (BFS_init(from, clear_visited) < 0)
437                 return result;
438
439         while (!Q.empty()) {
440                 int const i = Q.front();
441                 Q.pop();
442                 Format const & format = formats.Get(i);
443                 if (format.name() == "lyx")
444                         continue;
445                 if (!only_viewable || !format.viewer().empty() ||
446                     format.IsChildFormat())
447                         result.push_back(&format);
448                 for (vector<int>::iterator it = vertices[i].out_vertices.begin();
449                      it != vertices[i].out_vertices.end(); ++it)
450                         if (!visited[*it]) {
451                                 visited[*it] = true;
452                                 Q.push(*it);
453                         }
454         }
455
456         return result;
457 }
458
459
460 bool Converters::IsReachable(string const & from, string const & to)
461 {
462         if (from == to)
463                 return true;
464
465         int const s = BFS_init(from);
466         int const t = formats.GetNumber(to);
467         if (s < 0 || t < 0)
468                 return false;
469
470         while (!Q.empty()) {
471                 int const i = Q.front();
472                 Q.pop();
473                 if (i == t)
474                         return true;
475                 for (vector<int>::iterator it = vertices[i].out_vertices.begin();
476                      it != vertices[i].out_vertices.end(); ++it)
477                         if (!visited[*it]) {
478                                 visited[*it] = true;
479                                 Q.push(*it);
480                         }
481         }
482
483         return false;
484 }
485
486
487 Converters::EdgePath const
488 Converters::GetPath(string const & from, string const & to)
489 {
490         EdgePath path;
491         if (from == to)
492                 return path;
493
494         int const s = BFS_init(from);
495         int t = formats.GetNumber(to);
496         if (s < 0 || t < 0)
497                 return path;
498
499         vector<int> prev_edge(formats.size());
500         vector<int> prev_vertex(formats.size());
501
502         bool found = false;
503         while (!Q.empty()) {
504                 int const i = Q.front();
505                 Q.pop();
506                 if (i == t) {
507                         found = true;
508                         break;
509                 }
510                 for (vector<int>::iterator it = vertices[i].out_vertices.begin();
511                      it != vertices[i].out_vertices.end(); ++it)
512                         if (!visited[*it]) {
513                                 int const j = *it;
514                                 visited[j] = true;
515                                 Q.push(j);
516                                 int const k = it - vertices[i].out_vertices.begin();
517                                 prev_edge[j] = vertices[i].out_edges[k];
518                                 prev_vertex[j] = i;
519                         }
520         }
521         if (!found)
522                 return path;
523
524         while (t != s) {
525                 path.push_back(prev_edge[t]);
526                 t = prev_vertex[t];
527         }
528         reverse(path.begin(), path.end());
529         return path;
530 }
531
532
533 bool Converters::UsePdflatex(EdgePath const & path)
534 {
535         for (EdgePath::const_iterator cit = path.begin();
536              cit != path.end(); ++cit) {
537                 Converter const & conv = converterlist[*cit];
538                 if (conv.latex)
539                         return contains(conv.to, "pdf");
540         }
541         return false;
542 }
543
544
545 bool Converters::Convert(Buffer const * buffer,
546                          string const & from_file, string const & to_file_base,
547                          string const & from_format, string const & to_format,
548                          string & to_file)
549 {
550         to_file = ChangeExtension(to_file_base,
551                                   formats.Extension(to_format));
552
553         if (from_format == to_format)
554                 return Move(from_file, to_file, false);
555
556         EdgePath edgepath = GetPath(from_format, to_format);
557         if (edgepath.empty()) {
558                 WriteAlert(_("Can not convert file"),
559                            _("No information for converting from ")
560                            + formats.PrettyName(from_format) + _(" to ")
561                            + formats.PrettyName(to_format));
562                 return false;
563         }
564
565         string path = OnlyPath(from_file);
566         Path p(path);
567
568         bool run_latex = false;
569         string from_base = ChangeExtension(from_file, "");
570         string to_base = ChangeExtension(to_file, "");
571         string infile;
572         string outfile = from_file;
573         for (EdgePath::const_iterator cit = edgepath.begin();
574              cit != edgepath.end(); ++cit) {
575                 Converter const & conv = converterlist[*cit];
576                 bool dummy = conv.To->dummy() && conv.to != "program";
577                 if (!dummy)
578                         lyxerr[Debug::FILES] << "Converting from  "
579                                << conv.from << " to " << conv.to << endl;
580                 infile = outfile;
581                 outfile = conv.result_dir.empty()
582                         ? ChangeExtension(from_file, conv.To->extension())
583                         : AddName(subst(conv.result_dir,
584                                         token_base, from_base),
585                                   subst(conv.result_file,
586                                         token_base, OnlyFilename(from_base)));
587
588                 if (conv.latex) {
589                         run_latex = true;
590                         string command = subst(conv.command, token_from, "");
591                         lyxerr[Debug::FILES] << "Running " << command << endl;
592                         if (!runLaTeX(buffer, command))
593                                 return false;
594                 } else {
595                         if (conv.need_aux && !run_latex
596                             && !latex_command.empty()) {
597                                 lyxerr[Debug::FILES] 
598                                         << "Running " << latex_command 
599                                         << " to update aux file"<<  endl;
600                                 runLaTeX(buffer, latex_command);
601                         }
602
603                         string infile2 = (conv.original_dir)
604                                 ? infile : MakeRelPath(infile, path);
605                         string outfile2 = (conv.original_dir)
606                                 ? outfile : MakeRelPath(outfile, path);
607
608                         string command = conv.command;
609                         command = subst(command, token_from, QuoteName(infile2));
610                         command = subst(command, token_base, QuoteName(from_base));
611                         command = subst(command, token_to, QuoteName(outfile2));
612
613                         if (!conv.parselog.empty())
614                                 command += " 2> " + QuoteName(infile2 + ".out");
615
616                         if (conv.from == "dvi" && conv.to == "ps")
617                                 command = add_options(command,
618                                                       dvips_options(buffer));
619                         else if (conv.from == "dvi" && prefixIs(conv.to, "pdf"))
620                                 command = add_options(command,
621                                                       dvipdfm_options(buffer));
622
623                         lyxerr[Debug::FILES] << "Calling " << command << endl;
624                         if (buffer)
625                                 ShowMessage(buffer, _("Executing command:"), command);
626
627                         Systemcalls::Starttype type = (dummy)
628                                 ? Systemcalls::SystemDontWait : Systemcalls::System;
629                         Systemcalls one;
630                         int res;
631                         if (conv.original_dir && buffer) {
632                                 Path p(buffer->filepath);
633                                 res = one.startscript(type, command);
634                         } else
635                                 res = one.startscript(type, command);
636
637                         if (!conv.parselog.empty()) {
638                                 string const logfile =  infile2 + ".log";
639                                 string const command2 = conv.parselog +
640                                         " < " + QuoteName(infile2 + ".out") +
641                                         " > " + QuoteName(logfile);
642                                 one.startscript(Systemcalls::System, command2);
643                                 if (!scanLog(buffer, command, logfile))
644                                         return false;
645                         }
646
647                         if (res) {
648                                 if (conv.to == "program")
649                                         WriteAlert(_("There were errors during the Build process."),
650                                                    _("You should try to fix them."));
651                                 else
652                                         WriteAlert(_("Can not convert file"),
653                                                    "Error while executing",
654                                                    command.substr(0, 50));
655                                 return false;
656                         }
657                 }
658         }
659
660         Converter const & conv = converterlist[edgepath.back()];
661         if (conv.To->dummy())
662                 return true;
663
664
665         if (!conv.result_dir.empty()) {
666                 to_file = AddName(subst(conv.result_dir, token_base, to_base),
667                                   subst(conv.result_file,
668                                         token_base, OnlyFilename(to_base)));
669                 if (from_base != to_base) {
670                         string from = subst(conv.result_dir,
671                                             token_base, from_base);
672                         string to = subst(conv.result_dir,
673                                           token_base, to_base);
674                         if (!lyx::rename(from, to)) {
675                                 WriteAlert(_("Error while trying to move directory:"),
676                                            from, ("to ") + to);
677                                 return false;
678                         }
679                 }
680                 return true;
681         } else 
682                 return Move(outfile, to_file, conv.latex);
683 }
684
685 // If from = /path/file.ext and to = /path2/file2.ext2 then this method 
686 // moves each /path/file*.ext file to /path2/file2*.ext2'
687 bool Converters::Move(string const & from, string const & to, bool copy)
688 {
689         if (from == to)
690                 return true;
691
692         bool no_errors = true;
693         string const path = OnlyPath(from);
694         string const base = OnlyFilename(ChangeExtension(from, ""));
695         string const to_base = ChangeExtension(to, "");
696         string const to_extension = GetExtension(to);
697
698         vector<string> files = DirList(OnlyPath(from), GetExtension(from));
699         for (vector<string>::const_iterator it = files.begin();
700              it != files.end(); ++it)
701                 if (prefixIs(*it, base)) {
702                         string from2 = path + *it;
703                         string to2 = to_base + it->substr(base.length());
704                         to2 = ChangeExtension(to2, to_extension);
705                         lyxerr[Debug::FILES] << "moving " << from2 
706                                              << " to " << to2 << endl;
707                         bool moved = (copy)
708                                 ? lyx::copy(from2, to2)
709                                 : lyx::rename(from2, to2);
710                         if (!moved && no_errors) {
711                                 WriteAlert(_("Error while trying to move file:"),
712                                            from2, _("to ") + to2);
713                                 no_errors = false;
714                         }
715                 }
716         return no_errors;
717 }
718
719 bool Converters::Convert(Buffer const * buffer,
720                         string const & from_file, string const & to_file_base,
721                         string const & from_format, string const & to_format)
722 {
723         string to_file;
724         return Convert(buffer, from_file, to_file_base, from_format, to_format,
725                        to_file);
726 }
727
728
729
730 void Converters::BuildGraph()
731 {
732         vertices = vector<Vertex>(formats.size());
733         visited.resize(formats.size());
734
735         for (ConverterList::iterator it = converterlist.begin();
736              it != converterlist.end(); ++it) {
737                 int const s = formats.GetNumber(it->from);
738                 int const t = formats.GetNumber(it->to);
739                 vertices[t].in_vertices.push_back(s);
740                 vertices[s].out_vertices.push_back(t);
741                 vertices[s].out_edges.push_back(it - converterlist.begin());
742         }
743 }
744
745
746 bool Converters::FormatIsUsed(string const & format)
747 {
748         for (ConverterList::const_iterator cit = converterlist.begin();
749             cit != converterlist.end(); ++cit)
750                 if (cit->from == format || cit->to == format)
751                         return true;
752         return false;
753 }
754
755
756 bool Converters::scanLog(Buffer const * buffer, string const & command,
757                         string const & filename)
758 {
759         if (!buffer)
760                 return false;
761
762         BufferView * bv = buffer->getUser();
763         bool need_redraw = false;
764         if (bv) {
765                 bv->owner()->prohibitInput();
766                 // Remove all error insets
767                 need_redraw = bv->removeAutoInsets();
768         }
769
770         LaTeX latex("", filename, "");
771         TeXErrors terr;
772         int result = latex.scanLogFile(terr);
773         if (bv) {
774                 if ((result & LaTeX::ERRORS)) {
775                         // Insert all errors as errors boxes
776                         bv->insertErrors(terr);
777                         need_redraw = true;
778                 }
779                 if (need_redraw) {
780                         bv->redraw();
781                         bv->fitCursor(bv->text);
782                 }
783                 bv->owner()->allowInput();
784         }
785
786         if ((result & LaTeX::ERRORS)) {
787                 int num_errors = latex.getNumErrors();
788                 string s;
789                 string t;
790                 if (num_errors == 1) {
791                         s = _("One error detected");
792                         t = _("You should try to fix it.");
793                 } else {
794                         s = tostr(num_errors);
795                         s += _(" errors detected.");
796                         t = _("You should try to fix them.");
797                 }
798                 string head;
799                 split(command, head, ' ');
800                 WriteAlert(_("There were errors during running of ") + head,
801                            s, t);
802                 return false;
803         } else if (result & LaTeX::NO_OUTPUT) {
804                 string const s = _("The operation resulted in");
805                 string const t = _("an empty file.");
806                 WriteAlert(_("Resulting file is empty"), s, t);
807                 return false;
808         }
809         return true;
810 }
811
812
813 bool Converters::runLaTeX(Buffer const * buffer, string const & command)
814 {
815         if (!buffer)
816                 return false;
817
818         BufferView * bv = buffer->getUser();
819         string name = buffer->getLatexName();
820         bool need_redraw = false;
821
822         if (bv) {
823                 bv->owner()->prohibitInput();
824                 bv->owner()->message(_("Running LaTeX..."));
825                 // Remove all error insets
826                 need_redraw = bv->removeAutoInsets();
827         }
828
829
830         // do the LaTex run(s)
831         TeXErrors terr;
832         LaTeX latex(command, name, buffer->filepath);
833         int result = latex.run(terr,
834                                bv ? bv->owner()->getLyXFunc() : 0);
835         
836
837         if (bv) {
838                 if ((result & LaTeX::ERRORS)) {
839                         // Insert all errors as errors boxes
840                         bv->insertErrors(terr);
841                         need_redraw = true;
842                 }
843
844                 // if we removed error insets before we ran LaTeX or if we inserted
845                 // error insets after we ran LaTeX this must be run:
846                 if (need_redraw) {
847                         bv->redraw();
848                         bv->fitCursor(bv->text);
849                 }
850         }
851
852         // check return value from latex.run().
853         if ((result & LaTeX::NO_LOGFILE)) {
854                 WriteAlert(_("LaTeX did not work!"),
855                            _("Missing log file:"), name);
856         } else if ((result & LaTeX::ERRORS)) {
857                 int num_errors = latex.getNumErrors();
858                 string s;
859                 string t;
860                 if (num_errors == 1) {
861                         s = _("One error detected");
862                         t = _("You should try to fix it.");
863                 } else {
864                         s = tostr(num_errors);
865                         s += _(" errors detected.");
866                         t = _("You should try to fix them.");
867                 }
868                 WriteAlert(_("There were errors during the LaTeX run."),
869                            s, t);
870         }  else if (result & LaTeX::NO_OUTPUT) {
871                 string const s = _("The operation resulted in");
872                 string const t = _("an empty file.");
873                 WriteAlert(_("Resulting file is empty"), s, t);
874         }
875
876         if (bv)
877                 bv->owner()->allowInput();
878  
879         int const ERROR_MASK = 
880                         LaTeX::NO_LOGFILE |
881                         LaTeX::ERRORS |
882                         LaTeX::NO_OUTPUT;
883         
884         return (result & ERROR_MASK) == 0;
885
886 }
887
888
889 string const Converters::papersize(Buffer const * buffer)
890 {
891         char real_papersize = buffer->params.papersize;
892         if (real_papersize == BufferParams::PAPER_DEFAULT)
893                 real_papersize = lyxrc.default_papersize;
894
895         switch (real_papersize) {
896         case BufferParams::PAPER_A3PAPER:
897                 return "a3";
898         case BufferParams::PAPER_A4PAPER:
899                 return "a4";
900         case BufferParams::PAPER_A5PAPER:
901                 return "a5";
902         case BufferParams::PAPER_B5PAPER:
903                 return "b5";
904         case BufferParams::PAPER_EXECUTIVEPAPER:
905                 return "foolscap";
906         case BufferParams::PAPER_LEGALPAPER:
907                 return "legal";
908         case BufferParams::PAPER_USLETTER:
909         default:
910                 return "letter";
911         }
912 }
913
914
915 string const Converters::dvips_options(Buffer const * buffer)
916 {
917         string result;
918         if (!buffer)
919                 return result;
920
921         if (buffer->params.use_geometry
922             && buffer->params.papersize2 == BufferParams::VM_PAPER_CUSTOM
923             && !lyxrc.print_paper_dimension_flag.empty()
924             && !buffer->params.paperwidth.empty()
925             && !buffer->params.paperheight.empty()) {
926                 // using a custom papersize
927                 result = lyxrc.print_paper_dimension_flag;
928                 result += ' ' + buffer->params.paperwidth;
929                 result += ',' + buffer->params.paperheight;
930         } else {
931                 string paper_option = papersize(buffer);
932                 if (paper_option != "letter" ||
933                     buffer->params.orientation != BufferParams::ORIENTATION_LANDSCAPE) {
934                         // dvips won't accept -t letter -t landscape.  In all other
935                         // cases, include the paper size explicitly.
936                         result = lyxrc.print_paper_flag;
937                         result += ' ' + paper_option;
938                 }
939         }
940         if (buffer->params.orientation == BufferParams::ORIENTATION_LANDSCAPE &&
941             buffer->params.papersize2 != BufferParams::VM_PAPER_CUSTOM)
942                 result += ' ' + lyxrc.print_landscape_flag;
943         return result;
944 }
945
946
947 string const Converters::dvipdfm_options(Buffer const * buffer)
948 {
949         string result;
950         if (!buffer)
951                 return result;
952
953         if (buffer->params.papersize2 != BufferParams::VM_PAPER_CUSTOM) {
954                 string paper_size = papersize(buffer);
955                 if (paper_size != "b5" && paper_size != "foolscap")
956                         result = "-p "+ paper_size;
957
958                 if (buffer->params.orientation == BufferParams::ORIENTATION_LANDSCAPE)
959                         result += " -l";
960         }
961
962         return result;
963 }
964
965
966 vector<Converters::Vertex> Converters::vertices;
967
968
969 /// The global instance
970 Formats formats;
971 Converters converters;
972
973 // The global copy after reading lyxrc.defaults
974 Formats system_formats;
975 Converters system_converters;