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