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