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