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" },
73 for (int i = 0; items[i].name != 0; ++i)
74 if (items[i].name == n) {
75 prettyname = items[i].prettyname;
81 void Formats::Add(string const & name)
83 if (formats.find(name) == formats.end())
84 formats[name] = Format(name);
88 void Formats::SetViewer(string const & name, string const & command)
91 string command2 = subst(command, "$$FName", "'$$FName'");
92 if (!contains(command,"$$FName"))
93 command2 += " '$$FName'";
96 GetFormat(name)->viewer = command2;
100 bool Formats::View(Buffer * buffer, string const & filename)
102 if (filename.empty())
105 string extension = GetExtension(filename);
106 Format * format = GetFormat(extension);
107 if (!format || format->viewer.empty()) {
108 WriteAlert(_("Can not view file"),
109 _("No information for viewing ")
110 + Formats::PrettyName(extension));
114 string command = format->viewer;
116 if (extension == "dvi" &&
117 !lyxrc.view_dvi_paper_option.empty()) {
118 string options = lyxrc.view_dvi_paper_option;
119 options += " " + Converter::dvi_papersize(buffer);
120 if (buffer->params.orientation
121 == BufferParams::ORIENTATION_LANDSCAPE)
123 command = add_options(command, options);
126 string command2 = subst(command, "$$FName", OnlyFilename(filename));
127 lyxerr << "Executing command: " << command2 << endl;
128 ShowMessage(buffer, _("Executing command:"), command2);
130 command = subst(command, "$$FName", filename);
132 int res = one.startscript(Systemcalls::SystemDontWait, command);
135 WriteAlert(_("Can not view file"),
136 _("Error while executing"),
137 command.substr(0, 50));
144 Format * Formats::GetFormat(string const & name)
146 map<string, Format>::iterator it = formats.find(name);
147 if (it != formats.end())
148 return &(*it).second;
154 string const Formats::PrettyName(string const & name)
157 Converter::SplitFormat(name, format);
158 Format * f = GetFormat(format);
160 return f->prettyname;
166 //////////////////////////////////////////////////////////////////////////////
168 void Converter::Add(string const & from, string const & to,
169 string const & command, string const & flags)
171 if (command == "none")
175 subst(command, "$$FName", "'$$FName'");
176 command2 = subst(command2, "$$BaseName", "'$$BaseName'");
177 command2 = subst(command2, "$$OutName", "'$$OutName'");
178 Command Com(from, to, command2);
182 (to == "pdf" && latex_command.empty())))
183 latex_command = command2;
186 string flag_name,flag_value;
187 string flag_list(flags);
188 while (!flag_list.empty()) {
189 flag_list = split(flag_list, flag_value,',');
190 flag_value = split(flag_value, flag_name, '=');
191 if (flag_name == "originaldir")
192 Com.original_dir = true;
193 else if (flag_name == "needaux")
195 else if (flag_name == "resultdir")
196 Com.result_dir = (flag_value.empty())
197 ? "$$BaseName" : flag_value;
198 else if (flag_name == "resultfile")
199 Com.result_file = flag_value;
201 if (!Com.result_dir.empty() && Com.result_file.empty())
202 Com.result_file = "index." + to;
204 for (vector<Command>::iterator it = commands.begin();
205 it != commands.end(); ++it)
206 if ((*it).from == from && (*it).to == to) {
210 commands.push_back(Com);
213 ++Formats::GetFormat(to)->in_degree;
217 vector< pair<string,string> > const
218 Converter::GetReachable(string const & from, bool only_viewable)
220 vector< pair<string,string> > result;
221 Format * format = Formats::GetFormat(from);
226 if (!only_viewable || !format->viewer.empty()) {
227 result.push_back(pair<string,string>(from, format->prettyname));
231 queue< vector<Command>::iterator > Q;
232 for (vector<Command>::iterator it = commands.begin();
233 it != commands.end(); ++it)
234 if ((*it).from == from) {
236 (*it).visited = true;
238 (*it).visited = false;
241 vector<Command>::iterator it = Q.front();
242 format = Formats::GetFormat((*it).to);
243 string name = format->name;
244 string prettyname = format->prettyname;
245 if (format->in_degree > 1) {
246 name += ":" + (*it).from;
248 split((*it).command, tmp, ' ');
249 prettyname += _(" (using ") + tmp + ")";
251 if (!only_viewable || !format->viewer.empty())
252 result.push_back(pair<string,string>(name, prettyname));
254 for (vector<Command>::iterator it2 = commands.begin();
255 it2 != commands.end(); ++it2)
256 if (!(*it2).visited && (*it).to == (*it2).from) {
258 (*it2).visited = true;
262 sort(result.begin() + sort_start, result.end());
267 bool Converter::Convert(Buffer * buffer, string const & from_file,
268 string const & to_file, string const & using_format,
272 *view_file = to_file;
274 string from_format = GetExtension(from_file);
275 string to_format = GetExtension(to_file);
276 if (from_format == to_format)
277 if (from_file != to_file)
278 return lyx::rename(from_file, to_file);
282 queue< vector<Command>::iterator > Q;
283 for (vector<Command>::iterator it = commands.begin();
284 it != commands.end(); ++it)
285 if ((*it).from == from_format) {
287 (*it).visited = true;
288 (*it).previous = commands.end();
290 (*it).visited = false;
293 WriteAlert(_("Can not convert file"),
294 ("Unknown format ") + from_format);
299 vector<Command>::iterator it;
302 if ((*it).to == to_format &&
303 (using_format.empty() || using_format == (*it).from)) {
308 for (vector<Command>::iterator it2 = commands.begin();
309 it2 != commands.end(); ++it2)
310 if (!(*it2).visited && (*it).to == (*it2).from) {
312 (*it2).visited = true;
313 (*it2).previous = it;
318 WriteAlert(_("Can not convert file"),
319 _("No information for converting from ")
320 + Formats::PrettyName(from_format) + _(" to ")
321 + Formats::PrettyName(to_format));
325 vector< vector<Command>::iterator > S;
326 while (it != commands.end()) {
331 string path = OnlyPath(from_file);
334 bool run_latex = false;
335 string from_base = ChangeExtension(from_file, "");
336 string to_base = ChangeExtension(to_file, "");
338 string outfile = from_file;
339 for (vector< vector<Command>::iterator >::reverse_iterator rit =
340 S.rbegin(); rit != S.rend(); ++rit) {
342 lyxerr << "Converting from "
343 << (*it).from << " to " << (*it).to << endl;
345 outfile = (*it).result_dir.empty()
346 ? ChangeExtension(from_file, (*it).to)
347 : AddName(subst((*it).result_dir,
348 "$$BaseName", from_base),
349 subst((*it).result_file,
350 "$$BaseName", OnlyFilename(from_base)));
352 if ((*it).from == "tex" &&
353 ( (*it).to == "dvi" || (*it).to == "pdf") ) {
354 lyxrc.pdf_mode = (*it).to == "pdf";
355 lyxerr << "Running " << (*it).command << endl;
357 if (!runLaTeX(buffer, (*it).command))
360 if ((*it).need_aux && !run_latex
361 && !latex_command.empty()) {
362 lyxerr << "Running " << latex_command
363 << " to update aux file"<< endl;
364 runLaTeX(buffer, latex_command);
367 string infile2 = ((*it).original_dir)
368 ? infile : MakeRelPath(infile, path);
369 string outfile2 = ((*it).original_dir)
370 ? outfile : MakeRelPath(outfile, path);
372 string command = (*it).command;
373 command = subst(command, "$$FName", infile2);
374 command = subst(command, "$$BaseName", from_base);
375 command = subst(command, "$$OutName", outfile2);
377 if ((*it).from == "dvi" && (*it).to == "ps")
378 command = add_options(command,
379 dvips_options(buffer));
381 lyxerr << "Calling " << command << endl;
382 ShowMessage(buffer, _("Executing command:"), command);
386 if ((*it).original_dir) {
387 Path p(buffer->filepath);
388 res = one.startscript(Systemcalls::System, command);
390 res = one.startscript(Systemcalls::System, command);
392 WriteAlert(_("Can not convert file"),
393 "Error while executing",
394 command.substr(0, 50));
400 if (!(*it).result_dir.empty()) {
402 *view_file = AddName(subst((*it).result_dir,
403 "$$BaseName", to_base),
404 subst((*it).result_file,
405 "$$BaseName", OnlyFilename(to_base)));
406 if (from_base != to_base) {
407 string from = subst((*it).result_dir,
408 "$$BaseName", from_base);
409 string to = subst((*it).result_dir,
410 "$$BaseName", to_base);
411 return lyx::rename(from, to);
414 } else if (outfile != to_file)
415 if ((*it).from == "tex" &&
416 ( (*it).to == "dvi" || (*it).to == "pdf") )
417 return lyx::copy(outfile, to_file);
419 return lyx::rename(outfile, to_file);
425 string const Converter::SplitFormat(string const & str, string & format)
427 string using_format = split(str, format, ':');
434 bool Converter::runLaTeX(Buffer * buffer, string const & command)
437 BufferView * bv = buffer->getUser();
438 string name = buffer->getLatexName();
439 bool need_redraw = false;
443 bv->owner()->getMiniBuffer()->Set(_("Running LaTeX..."));
444 // Remove all error insets
445 need_redraw = bv->removeAutoInsets();
449 // do the LaTex run(s)
451 LaTeX latex(command, name, buffer->filepath);
452 int result = latex.run(terr,
453 bv ? bv->owner()->getMiniBuffer() : 0);
457 if ((result & LaTeX::ERRORS)) {
458 // Insert all errors as errors boxes
459 bv->insertErrors(terr);
463 // if we removed error insets before we ran LaTeX or if we inserted
464 // error insets after we ran LaTeX this must be run:
467 bv->fitCursor(bv->text);
471 // check return value from latex.run().
472 if ((result & LaTeX::NO_LOGFILE)) {
473 WriteAlert(_("LaTeX did not work!"),
474 _("Missing log file:"), name);
475 } else if ((result & LaTeX::ERRORS)) {
476 int num_errors = latex.getNumErrors();
479 if (num_errors == 1) {
480 s = _("One error detected");
481 t = _("You should try to fix it.");
483 s = tostr(num_errors);
484 s += _(" errors detected.");
485 t = _("You should try to fix them.");
487 WriteAlert(_("There were errors during the LaTeX run."),
494 return (result & (LaTeX::NO_LOGFILE | LaTeX::ERRORS)) == 0;
499 string const Converter::dvi_papersize(Buffer const * buffer)
501 char real_papersize = buffer->params.papersize;
502 if (real_papersize == BufferParams::PAPER_DEFAULT)
503 real_papersize = lyxrc.default_papersize;
505 switch (real_papersize) {
506 case BufferParams::PAPER_A3PAPER:
508 case BufferParams::PAPER_A4PAPER:
510 case BufferParams::PAPER_A5PAPER:
512 case BufferParams::PAPER_B5PAPER:
514 case BufferParams::PAPER_EXECUTIVEPAPER:
516 case BufferParams::PAPER_LEGALPAPER:
518 case BufferParams::PAPER_USLETTER:
525 string const Converter::dvips_options(Buffer const * buffer)
528 if (buffer->params.use_geometry
529 && buffer->params.papersize2 == BufferParams::VM_PAPER_CUSTOM
530 && !lyxrc.print_paper_dimension_flag.empty()
531 && !buffer->params.paperwidth.empty()
532 && !buffer->params.paperheight.empty()) {
533 // using a custom papersize
534 result = lyxrc.print_paper_dimension_flag;
535 result += ' ' + buffer->params.paperwidth;
536 result += ',' + buffer->params.paperheight;
538 string paper_option = dvi_papersize(buffer);
539 if (paper_option == "us")
540 paper_option = "letter";
541 if (paper_option != "letter" ||
542 buffer->params.orientation != BufferParams::ORIENTATION_LANDSCAPE) {
543 // dvips won't accept -t letter -t landscape. In all other
544 // cases, include the paper size explicitly.
545 result = lyxrc.print_paper_flag;
546 result += ' ' + paper_option;
549 if (buffer->params.orientation == BufferParams::ORIENTATION_LANDSCAPE)
550 result += ' ' + lyxrc.print_landscape_flag;