1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1995 Matthias Ettrich
7 * Copyright 1995-2000 The LyX Team.
9 * ====================================================== */
14 #pragma implementation
19 #include "converter.h"
21 #include "support/syscall.h"
22 #include "support/path.h"
24 #include "bufferview_funcs.h"
27 #include "minibuffer.h"
28 #include "lyx_gui_misc.h"
29 #include "lyx_cb.h" // ShowMessage()
37 //////////////////////////////////////////////////////////////////////////////
39 map<string, Format> Formats::formats;
40 vector<Command> Converter::commands;
41 string Converter::latex_command;
44 string const add_options(string const & command, string const & options)
47 string tail = split(command, head, ' ');
48 return head + ' ' + options + ' ' + tail;
51 //////////////////////////////////////////////////////////////////////////////
53 Format::Format(string const & n)
58 char const * prettyname;
63 { "ps", "PostScript" },
67 { "nw", "NoWeb/LaTeX"},
72 for (int i = 0; items[i].name != 0; ++i)
73 if (items[i].name == n) {
74 prettyname = items[i].prettyname;
80 void Formats::Add(string const & name)
82 if (formats.find(name) == formats.end())
83 formats[name] = Format(name);
87 void Formats::SetViewer(string const & name, string const & command)
90 string command2 = command;
91 if (!contains(command2,"$$FName"))
92 command2 += " $$FName";
95 GetFormat(name)->viewer = command2;
99 bool Formats::View(Buffer const * buffer, string const & filename)
101 if (filename.empty())
104 string extension = GetExtension(filename);
105 Format * format = GetFormat(extension);
106 if (!format || format->viewer.empty()) {
107 WriteAlert(_("Can not view file"),
108 _("No information for viewing ")
109 + Formats::PrettyName(extension));
113 string command = format->viewer;
115 if (extension == "dvi" &&
116 !lyxrc.view_dvi_paper_option.empty()) {
117 string options = lyxrc.view_dvi_paper_option;
118 options += " " + Converter::dvi_papersize(buffer);
119 if (buffer->params.orientation
120 == BufferParams::ORIENTATION_LANDSCAPE)
122 command = add_options(command, options);
125 string command2 = subst(command, "$$FName", OnlyFilename(filename));
126 lyxerr << "Executing command: " << command2 << endl;
127 ShowMessage(buffer, _("Executing command:"), command2);
129 command = subst(command, "$$FName", QuoteName(filename));
131 int res = one.startscript(Systemcalls::SystemDontWait, command);
134 WriteAlert(_("Can not view file"),
135 _("Error while executing"),
136 command.substr(0, 50));
143 Format * Formats::GetFormat(string const & name)
145 map<string, Format>::iterator it = formats.find(name);
146 if (it != formats.end())
147 return &(*it).second;
153 string const Formats::PrettyName(string const & name)
156 Converter::SplitFormat(name, format);
157 Format * f = GetFormat(format);
159 return f->prettyname;
165 //////////////////////////////////////////////////////////////////////////////
167 void Converter::Add(string const & from, string const & to,
168 string const & command, string const & flags)
170 if (command == "none")
173 Command Com(from, to, command);
177 (to == "pdf" && latex_command.empty())))
178 latex_command = command;
181 string flag_name,flag_value;
182 string flag_list(flags);
183 while (!flag_list.empty()) {
184 flag_list = split(flag_list, flag_value,',');
185 flag_value = split(flag_value, flag_name, '=');
186 if (flag_name == "originaldir")
187 Com.original_dir = true;
188 else if (flag_name == "needaux")
190 else if (flag_name == "resultdir")
191 Com.result_dir = (flag_value.empty())
192 ? "$$BaseName" : flag_value;
193 else if (flag_name == "resultfile")
194 Com.result_file = flag_value;
195 else if (flag_name == "parselog")
196 Com.parselog = flag_value;
198 if (!Com.result_dir.empty() && Com.result_file.empty())
199 Com.result_file = "index." + to;
201 for (vector<Command>::iterator it = commands.begin();
202 it != commands.end(); ++it)
203 if ((*it).from == from && (*it).to == to) {
207 commands.push_back(Com);
213 vector<FormatPair> const
214 Converter::GetReachable(string const & from, bool only_viewable)
216 vector<FormatPair> result;
217 Format * format = Formats::GetFormat(from);
221 if (!only_viewable || !format->viewer.empty())
222 result.push_back(FormatPair(format, 0, ""));
224 queue< vector<Command>::iterator > Q;
225 for (vector<Command>::iterator it = commands.begin();
226 it != commands.end(); ++it)
227 if ((*it).from == from) {
229 (*it).visited = true;
231 (*it).visited = false;
234 vector<Command>::iterator it = Q.front();
236 format = Formats::GetFormat((*it).to);
237 if (!only_viewable || !format->viewer.empty())
238 result.push_back(FormatPair(format,
239 Formats::GetFormat((*it).from),
241 for (vector<Command>::iterator it2 = commands.begin();
242 it2 != commands.end(); ++it2)
243 if (!(*it2).visited && (*it).to == (*it2).from) {
245 (*it2).visited = true;
252 bool Converter::IsReachable(string const & from, string const & target_format)
254 Format * format = Formats::GetFormat(from);
257 else if (format->name == target_format)
260 queue< vector<Command>::iterator > Q;
261 for (vector<Command>::iterator it = commands.begin();
262 it != commands.end(); ++it)
263 if ((*it).from == from) {
265 (*it).visited = true;
267 (*it).visited = false;
270 vector<Command>::iterator it = Q.front();
272 format = Formats::GetFormat((*it).to);
273 if (format->name == target_format)
275 for (vector<Command>::iterator it2 = commands.begin();
276 it2 != commands.end(); ++it2)
277 if (!(*it2).visited && (*it).to == (*it2).from) {
279 (*it2).visited = true;
286 bool Converter::Convert(Buffer const * buffer, string const & from_file,
287 string const & to_file, string const & using_format,
291 *view_file = to_file;
293 string from_format = GetExtension(from_file);
294 string to_format = GetExtension(to_file);
295 if (from_format == to_format)
296 if (from_file != to_file)
297 return lyx::rename(from_file, to_file);
301 queue< vector<Command>::iterator > Q;
302 for (vector<Command>::iterator it = commands.begin();
303 it != commands.end(); ++it)
304 if ((*it).from == from_format) {
306 (*it).visited = true;
307 (*it).previous = commands.end();
309 (*it).visited = false;
312 WriteAlert(_("Can not convert file"),
313 ("Unknown format ") + from_format);
318 vector<Command>::iterator it;
321 if ((*it).to == to_format &&
322 (using_format.empty() || using_format == (*it).from)) {
327 for (vector<Command>::iterator it2 = commands.begin();
328 it2 != commands.end(); ++it2)
329 if (!(*it2).visited && (*it).to == (*it2).from) {
331 (*it2).visited = true;
332 (*it2).previous = it;
337 WriteAlert(_("Can not convert file"),
338 _("No information for converting from ")
339 + Formats::PrettyName(from_format) + _(" to ")
340 + Formats::PrettyName(to_format));
344 vector< vector<Command>::iterator > S;
345 while (it != commands.end()) {
350 string path = OnlyPath(from_file);
353 bool run_latex = false;
354 string from_base = ChangeExtension(from_file, "");
355 string to_base = ChangeExtension(to_file, "");
357 string outfile = from_file;
358 for (vector< vector<Command>::iterator >::reverse_iterator rit =
359 S.rbegin(); rit != S.rend(); ++rit) {
361 lyxerr << "Converting from "
362 << (*it).from << " to " << (*it).to << endl;
364 outfile = (*it).result_dir.empty()
365 ? ChangeExtension(from_file, (*it).to)
366 : AddName(subst((*it).result_dir,
367 "$$BaseName", from_base),
368 subst((*it).result_file,
369 "$$BaseName", OnlyFilename(from_base)));
371 if ((*it).from == "tex" &&
372 ( (*it).to == "dvi" || (*it).to == "pdf") ) {
373 lyxrc.pdf_mode = (*it).to == "pdf";
374 lyxerr << "Running " << (*it).command << endl;
376 if (!runLaTeX(buffer, (*it).command))
379 if ((*it).need_aux && !run_latex
380 && !latex_command.empty()) {
381 lyxerr << "Running " << latex_command
382 << " to update aux file"<< endl;
383 runLaTeX(buffer, latex_command);
386 string infile2 = ((*it).original_dir)
387 ? infile : MakeRelPath(infile, path);
388 string outfile2 = ((*it).original_dir)
389 ? outfile : MakeRelPath(outfile, path);
391 string command = (*it).command;
392 command = subst(command, "$$FName", QuoteName(infile2));
393 command = subst(command, "$$BaseName", QuoteName(from_base));
394 command = subst(command, "$$OutName", QuoteName(outfile2));
396 if (!(*it).parselog.empty())
397 command += " 2> " + QuoteName(infile2 + ".out");
399 if ((*it).from == "dvi" && (*it).to == "ps")
400 command = add_options(command,
401 dvips_options(buffer));
403 lyxerr << "Calling " << command << endl;
404 ShowMessage(buffer, _("Executing command:"), command);
408 if ((*it).original_dir) {
409 Path p(buffer->filepath);
410 res = one.startscript(Systemcalls::System, command);
412 res = one.startscript(Systemcalls::System, command);
414 if (!(*it).parselog.empty()) {
415 string const logfile = infile2 + ".log";
416 string const command2 = (*it).parselog +
417 " < " + QuoteName(infile2 + ".out") +
418 " > " + QuoteName(logfile);
419 one.startscript(Systemcalls::System, command2);
420 if (!scanLog(buffer, command, logfile))
425 if ((*it).to == "Program")
426 WriteAlert(_("There were errors during the Build process."),
427 _("You should try to fix them."));
429 WriteAlert(_("Can not convert file"),
430 "Error while executing",
431 command.substr(0, 50));
437 if (!(*it).result_dir.empty()) {
439 *view_file = AddName(subst((*it).result_dir,
440 "$$BaseName", to_base),
441 subst((*it).result_file,
442 "$$BaseName", OnlyFilename(to_base)));
443 if (from_base != to_base) {
444 string from = subst((*it).result_dir,
445 "$$BaseName", from_base);
446 string to = subst((*it).result_dir,
447 "$$BaseName", to_base);
448 return lyx::rename(from, to);
451 } else if (outfile != to_file)
452 if ((*it).from == "tex" &&
453 ( (*it).to == "dvi" || (*it).to == "pdf") )
454 return lyx::copy(outfile, to_file);
456 return lyx::rename(outfile, to_file);
462 string const Converter::SplitFormat(string const & str, string & format)
464 string using_format = split(str, format, ':');
470 bool Converter::scanLog(Buffer const * buffer, string const & command,
471 string const & filename)
473 BufferView * bv = buffer->getUser();
474 bool need_redraw = false;
477 // Remove all error insets
478 need_redraw = bv->removeAutoInsets();
481 LaTeX latex("", filename, "");
483 int result = latex.scanLogFile(terr);
485 if ((result & LaTeX::ERRORS)) {
486 // Insert all errors as errors boxes
487 bv->insertErrors(terr);
492 bv->fitCursor(bv->text);
494 if (result & LaTeX::NO_OUTPUT) {
495 string const s = _("The operation resulted in");
496 string const t = _("an empty file.");
497 WriteAlert(_("Resulting file is empty"), s, t);
502 if ((result & LaTeX::ERRORS)) {
503 int num_errors = latex.getNumErrors();
506 if (num_errors == 1) {
507 s = _("One error detected");
508 t = _("You should try to fix it.");
510 s = tostr(num_errors);
511 s += _(" errors detected.");
512 t = _("You should try to fix them.");
515 split(command, head, ' ');
516 WriteAlert(_("There were errors during running of ") + head,
523 bool Converter::runLaTeX(Buffer const * buffer, string const & command)
526 BufferView * bv = buffer->getUser();
527 string name = buffer->getLatexName();
528 bool need_redraw = false;
532 bv->owner()->getMiniBuffer()->Set(_("Running LaTeX..."));
533 // Remove all error insets
534 need_redraw = bv->removeAutoInsets();
538 // do the LaTex run(s)
540 LaTeX latex(command, name, buffer->filepath);
541 int result = latex.run(terr,
542 bv ? bv->owner()->getMiniBuffer() : 0);
546 if ((result & LaTeX::ERRORS)) {
547 // Insert all errors as errors boxes
548 bv->insertErrors(terr);
552 // if we removed error insets before we ran LaTeX or if we inserted
553 // error insets after we ran LaTeX this must be run:
556 bv->fitCursor(bv->text);
558 } else if (result & LaTeX::NO_OUTPUT) {
559 string const s = _("The operation resulted in");
560 string const t = _("an empty file.");
561 WriteAlert(_("Resulting file is empty"), s, t);
564 // check return value from latex.run().
565 if ((result & LaTeX::NO_LOGFILE)) {
566 WriteAlert(_("LaTeX did not work!"),
567 _("Missing log file:"), name);
568 } else if ((result & LaTeX::ERRORS)) {
569 int num_errors = latex.getNumErrors();
572 if (num_errors == 1) {
573 s = _("One error detected");
574 t = _("You should try to fix it.");
576 s = tostr(num_errors);
577 s += _(" errors detected.");
578 t = _("You should try to fix them.");
580 WriteAlert(_("There were errors during the LaTeX run."),
587 int const ERROR_MASK =
592 return (result & ERROR_MASK) == 0;
597 string const Converter::dvi_papersize(Buffer const * buffer)
599 char real_papersize = buffer->params.papersize;
600 if (real_papersize == BufferParams::PAPER_DEFAULT)
601 real_papersize = lyxrc.default_papersize;
603 switch (real_papersize) {
604 case BufferParams::PAPER_A3PAPER:
606 case BufferParams::PAPER_A4PAPER:
608 case BufferParams::PAPER_A5PAPER:
610 case BufferParams::PAPER_B5PAPER:
612 case BufferParams::PAPER_EXECUTIVEPAPER:
614 case BufferParams::PAPER_LEGALPAPER:
616 case BufferParams::PAPER_USLETTER:
623 string const Converter::dvips_options(Buffer const * buffer)
626 if (buffer->params.use_geometry
627 && buffer->params.papersize2 == BufferParams::VM_PAPER_CUSTOM
628 && !lyxrc.print_paper_dimension_flag.empty()
629 && !buffer->params.paperwidth.empty()
630 && !buffer->params.paperheight.empty()) {
631 // using a custom papersize
632 result = lyxrc.print_paper_dimension_flag;
633 result += ' ' + buffer->params.paperwidth;
634 result += ',' + buffer->params.paperheight;
636 string paper_option = dvi_papersize(buffer);
637 if (paper_option == "us")
638 paper_option = "letter";
639 if (paper_option != "letter" ||
640 buffer->params.orientation != BufferParams::ORIENTATION_LANDSCAPE) {
641 // dvips won't accept -t letter -t landscape. In all other
642 // cases, include the paper size explicitly.
643 result = lyxrc.print_paper_flag;
644 result += ' ' + paper_option;
647 if (buffer->params.orientation == BufferParams::ORIENTATION_LANDSCAPE)
648 result += ' ' + lyxrc.print_landscape_flag;
652 void Converter::init()