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
18 #include <algorithm> // sort()
20 #include "converter.h"
22 #include "support/syscall.h"
23 #include "support/path.h"
25 #include "bufferview_funcs.h"
28 #include "minibuffer.h"
29 #include "lyx_gui_misc.h"
30 #include "lyx_cb.h" // ShowMessage()
39 //////////////////////////////////////////////////////////////////////////////
41 map<string, Format> Formats::formats;
42 vector<Command> Converter::commands;
43 string Converter::latex_command;
46 string const add_options(string const & command, string const & options)
49 string tail = split(command, head, ' ');
50 return head + ' ' + options + ' ' + tail;
53 //////////////////////////////////////////////////////////////////////////////
55 Format::Format(string const & n)
56 : name(n), in_degree(0)
60 char const * prettyname;
65 { "ps", "PostScript" },
69 { "nw", "NoWeb/LaTeX"},
74 for (int i = 0; items[i].name != 0; ++i)
75 if (items[i].name == n) {
76 prettyname = items[i].prettyname;
82 void Formats::Add(string const & name)
84 if (formats.find(name) == formats.end())
85 formats[name] = Format(name);
89 void Formats::SetViewer(string const & name, string const & command)
92 string command2 = command;
93 if (!contains(command2,"$$FName"))
94 command2 += " $$FName";
97 GetFormat(name)->viewer = command2;
101 bool Formats::View(Buffer const * buffer, string const & filename)
103 if (filename.empty())
106 string extension = GetExtension(filename);
107 Format * format = GetFormat(extension);
108 if (!format || format->viewer.empty()) {
109 WriteAlert(_("Can not view file"),
110 _("No information for viewing ")
111 + Formats::PrettyName(extension));
115 string command = format->viewer;
117 if (extension == "dvi" &&
118 !lyxrc.view_dvi_paper_option.empty()) {
119 string options = lyxrc.view_dvi_paper_option;
120 options += " " + Converter::dvi_papersize(buffer);
121 if (buffer->params.orientation
122 == BufferParams::ORIENTATION_LANDSCAPE)
124 command = add_options(command, options);
127 string command2 = subst(command, "$$FName", OnlyFilename(filename));
128 lyxerr << "Executing command: " << command2 << endl;
129 ShowMessage(buffer, _("Executing command:"), command2);
131 command = subst(command, "$$FName", QuoteName(filename));
133 int res = one.startscript(Systemcalls::SystemDontWait, command);
136 WriteAlert(_("Can not view file"),
137 _("Error while executing"),
138 command.substr(0, 50));
145 Format * Formats::GetFormat(string const & name)
147 map<string, Format>::iterator it = formats.find(name);
148 if (it != formats.end())
149 return &(*it).second;
155 string const Formats::PrettyName(string const & name)
158 Converter::SplitFormat(name, format);
159 Format * f = GetFormat(format);
161 return f->prettyname;
167 //////////////////////////////////////////////////////////////////////////////
169 void Converter::Add(string const & from, string const & to,
170 string const & command, string const & flags)
172 if (command == "none")
175 Command Com(from, to, command);
179 (to == "pdf" && latex_command.empty())))
180 latex_command = command;
183 string flag_name,flag_value;
184 string flag_list(flags);
185 while (!flag_list.empty()) {
186 flag_list = split(flag_list, flag_value,',');
187 flag_value = split(flag_value, flag_name, '=');
188 if (flag_name == "originaldir")
189 Com.original_dir = true;
190 else if (flag_name == "needaux")
192 else if (flag_name == "resultdir")
193 Com.result_dir = (flag_value.empty())
194 ? "$$BaseName" : flag_value;
195 else if (flag_name == "resultfile")
196 Com.result_file = flag_value;
197 else if (flag_name == "parselog")
198 Com.parselog = flag_value;
200 if (!Com.result_dir.empty() && Com.result_file.empty())
201 Com.result_file = "index." + to;
203 for (vector<Command>::iterator it = commands.begin();
204 it != commands.end(); ++it)
205 if ((*it).from == from && (*it).to == to) {
209 commands.push_back(Com);
212 ++Formats::GetFormat(to)->in_degree;
216 vector< pair<string,string> > const
217 Converter::GetReachable(string const & from, bool only_viewable)
219 vector< pair<string,string> > result;
220 Format * format = Formats::GetFormat(from);
225 if (!only_viewable || !format->viewer.empty()) {
226 result.push_back(pair<string,string>(from, format->prettyname));
230 queue< vector<Command>::iterator > Q;
231 for (vector<Command>::iterator it = commands.begin();
232 it != commands.end(); ++it)
233 if ((*it).from == from) {
235 (*it).visited = true;
237 (*it).visited = false;
240 vector<Command>::iterator it = Q.front();
241 format = Formats::GetFormat((*it).to);
242 string name = format->name;
243 string prettyname = format->prettyname;
244 if (format->in_degree > 1) {
245 name += ":" + (*it).from;
247 split((*it).command, tmp, ' ');
248 prettyname += _(" (using ") + tmp + ")";
250 if (!only_viewable || !format->viewer.empty())
251 result.push_back(pair<string,string>(name, prettyname));
253 for (vector<Command>::iterator it2 = commands.begin();
254 it2 != commands.end(); ++it2)
255 if (!(*it2).visited && (*it).to == (*it2).from) {
257 (*it2).visited = true;
261 sort(result.begin() + sort_start, result.end());
266 bool Converter::Convert(Buffer const * buffer, string const & from_file,
267 string const & to_file, string const & using_format,
271 *view_file = to_file;
273 string from_format = GetExtension(from_file);
274 string to_format = GetExtension(to_file);
275 if (from_format == to_format)
276 if (from_file != to_file)
277 return lyx::rename(from_file, to_file);
281 queue< vector<Command>::iterator > Q;
282 for (vector<Command>::iterator it = commands.begin();
283 it != commands.end(); ++it)
284 if ((*it).from == from_format) {
286 (*it).visited = true;
287 (*it).previous = commands.end();
289 (*it).visited = false;
292 WriteAlert(_("Can not convert file"),
293 ("Unknown format ") + from_format);
298 vector<Command>::iterator it;
301 if ((*it).to == to_format &&
302 (using_format.empty() || using_format == (*it).from)) {
307 for (vector<Command>::iterator it2 = commands.begin();
308 it2 != commands.end(); ++it2)
309 if (!(*it2).visited && (*it).to == (*it2).from) {
311 (*it2).visited = true;
312 (*it2).previous = it;
317 WriteAlert(_("Can not convert file"),
318 _("No information for converting from ")
319 + Formats::PrettyName(from_format) + _(" to ")
320 + Formats::PrettyName(to_format));
324 vector< vector<Command>::iterator > S;
325 while (it != commands.end()) {
330 string path = OnlyPath(from_file);
333 bool run_latex = false;
334 string from_base = ChangeExtension(from_file, "");
335 string to_base = ChangeExtension(to_file, "");
337 string outfile = from_file;
338 for (vector< vector<Command>::iterator >::reverse_iterator rit =
339 S.rbegin(); rit != S.rend(); ++rit) {
341 lyxerr << "Converting from "
342 << (*it).from << " to " << (*it).to << endl;
344 outfile = (*it).result_dir.empty()
345 ? ChangeExtension(from_file, (*it).to)
346 : AddName(subst((*it).result_dir,
347 "$$BaseName", from_base),
348 subst((*it).result_file,
349 "$$BaseName", OnlyFilename(from_base)));
351 if ((*it).from == "tex" &&
352 ( (*it).to == "dvi" || (*it).to == "pdf") ) {
353 lyxrc.pdf_mode = (*it).to == "pdf";
354 lyxerr << "Running " << (*it).command << endl;
356 if (!runLaTeX(buffer, (*it).command))
359 if ((*it).need_aux && !run_latex
360 && !latex_command.empty()) {
361 lyxerr << "Running " << latex_command
362 << " to update aux file"<< endl;
363 runLaTeX(buffer, latex_command);
366 string infile2 = ((*it).original_dir)
367 ? infile : MakeRelPath(infile, path);
368 string outfile2 = ((*it).original_dir)
369 ? outfile : MakeRelPath(outfile, path);
371 string command = (*it).command;
372 command = subst(command, "$$FName", QuoteName(infile2));
373 command = subst(command, "$$BaseName", QuoteName(from_base));
374 command = subst(command, "$$OutName", QuoteName(outfile2));
376 if (!(*it).parselog.empty())
377 command += " 2> " + QuoteName(infile2 + ".out");
379 if ((*it).from == "dvi" && (*it).to == "ps")
380 command = add_options(command,
381 dvips_options(buffer));
383 lyxerr << "Calling " << command << endl;
384 ShowMessage(buffer, _("Executing command:"), command);
388 if ((*it).original_dir) {
389 Path p(buffer->filepath);
390 res = one.startscript(Systemcalls::System, command);
392 res = one.startscript(Systemcalls::System, command);
394 if (!(*it).parselog.empty()) {
395 string const logfile = infile2 + ".log";
396 string const command2 = (*it).parselog +
397 " < " + QuoteName(infile2 + ".out") +
398 " > " + QuoteName(logfile);
399 one.startscript(Systemcalls::System, command2);
400 if (!scanLog(buffer, command, logfile))
405 if ((*it).to == "Program")
406 WriteAlert(_("There were errors during the Build process."),
407 _("You should try to fix them."));
409 WriteAlert(_("Can not convert file"),
410 "Error while executing",
411 command.substr(0, 50));
417 if (!(*it).result_dir.empty()) {
419 *view_file = AddName(subst((*it).result_dir,
420 "$$BaseName", to_base),
421 subst((*it).result_file,
422 "$$BaseName", OnlyFilename(to_base)));
423 if (from_base != to_base) {
424 string from = subst((*it).result_dir,
425 "$$BaseName", from_base);
426 string to = subst((*it).result_dir,
427 "$$BaseName", to_base);
428 return lyx::rename(from, to);
431 } else if (outfile != to_file)
432 if ((*it).from == "tex" &&
433 ( (*it).to == "dvi" || (*it).to == "pdf") )
434 return lyx::copy(outfile, to_file);
436 return lyx::rename(outfile, to_file);
442 string const Converter::SplitFormat(string const & str, string & format)
444 string using_format = split(str, format, ':');
450 bool Converter::scanLog(Buffer const * buffer, string const & command,
451 string const & filename)
453 BufferView * bv = buffer->getUser();
454 bool need_redraw = false;
457 // Remove all error insets
458 need_redraw = bv->removeAutoInsets();
461 LaTeX latex("", filename, "");
463 int result = latex.scanLogFile(terr);
465 if ((result & LaTeX::ERRORS)) {
466 // Insert all errors as errors boxes
467 bv->insertErrors(terr);
472 bv->fitCursor(bv->text);
476 if ((result & LaTeX::ERRORS)) {
477 int num_errors = latex.getNumErrors();
480 if (num_errors == 1) {
481 s = _("One error detected");
482 t = _("You should try to fix it.");
484 s = tostr(num_errors);
485 s += _(" errors detected.");
486 t = _("You should try to fix them.");
489 split(command, head, ' ');
490 WriteAlert(_("There were errors during running of ") + head,
497 bool Converter::runLaTeX(Buffer const * buffer, string const & command)
500 BufferView * bv = buffer->getUser();
501 string name = buffer->getLatexName();
502 bool need_redraw = false;
506 bv->owner()->getMiniBuffer()->Set(_("Running LaTeX..."));
507 // Remove all error insets
508 need_redraw = bv->removeAutoInsets();
512 // do the LaTex run(s)
514 LaTeX latex(command, name, buffer->filepath);
515 int result = latex.run(terr,
516 bv ? bv->owner()->getMiniBuffer() : 0);
520 if ((result & LaTeX::ERRORS)) {
521 // Insert all errors as errors boxes
522 bv->insertErrors(terr);
526 // if we removed error insets before we ran LaTeX or if we inserted
527 // error insets after we ran LaTeX this must be run:
530 bv->fitCursor(bv->text);
534 // check return value from latex.run().
535 if ((result & LaTeX::NO_LOGFILE)) {
536 WriteAlert(_("LaTeX did not work!"),
537 _("Missing log file:"), name);
538 } else if ((result & LaTeX::ERRORS)) {
539 int num_errors = latex.getNumErrors();
542 if (num_errors == 1) {
543 s = _("One error detected");
544 t = _("You should try to fix it.");
546 s = tostr(num_errors);
547 s += _(" errors detected.");
548 t = _("You should try to fix them.");
550 WriteAlert(_("There were errors during the LaTeX run."),
557 return (result & (LaTeX::NO_LOGFILE | LaTeX::ERRORS)) == 0;
562 string const Converter::dvi_papersize(Buffer const * buffer)
564 char real_papersize = buffer->params.papersize;
565 if (real_papersize == BufferParams::PAPER_DEFAULT)
566 real_papersize = lyxrc.default_papersize;
568 switch (real_papersize) {
569 case BufferParams::PAPER_A3PAPER:
571 case BufferParams::PAPER_A4PAPER:
573 case BufferParams::PAPER_A5PAPER:
575 case BufferParams::PAPER_B5PAPER:
577 case BufferParams::PAPER_EXECUTIVEPAPER:
579 case BufferParams::PAPER_LEGALPAPER:
581 case BufferParams::PAPER_USLETTER:
588 string const Converter::dvips_options(Buffer const * buffer)
591 if (buffer->params.use_geometry
592 && buffer->params.papersize2 == BufferParams::VM_PAPER_CUSTOM
593 && !lyxrc.print_paper_dimension_flag.empty()
594 && !buffer->params.paperwidth.empty()
595 && !buffer->params.paperheight.empty()) {
596 // using a custom papersize
597 result = lyxrc.print_paper_dimension_flag;
598 result += ' ' + buffer->params.paperwidth;
599 result += ',' + buffer->params.paperheight;
601 string paper_option = dvi_papersize(buffer);
602 if (paper_option == "us")
603 paper_option = "letter";
604 if (paper_option != "letter" ||
605 buffer->params.orientation != BufferParams::ORIENTATION_LANDSCAPE) {
606 // dvips won't accept -t letter -t landscape. In all other
607 // cases, include the paper size explicitly.
608 result = lyxrc.print_paper_flag;
609 result += ' ' + paper_option;
612 if (buffer->params.orientation == BufferParams::ORIENTATION_LANDSCAPE)
613 result += ' ' + lyxrc.print_landscape_flag;