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