/************************************************************************* ** MetafontWrapper.cpp ** ** ** ** This file is part of dvisvgm -- a fast DVI to SVG converter ** ** Copyright (C) 2005-2019 Martin Gieseking ** ** ** ** This program is free software; you can redistribute it and/or ** ** modify it under the terms of the GNU General Public License as ** ** published by the Free Software Foundation; either version 3 of ** ** the License, or (at your option) any later version. ** ** ** ** This program is distributed in the hope that it will be useful, but ** ** WITHOUT ANY WARRANTY; without even the implied warranty of ** ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** ** GNU General Public License for more details. ** ** ** ** You should have received a copy of the GNU General Public License ** ** along with this program; if not, see . ** *************************************************************************/ #include #include #include #include "FileSystem.hpp" #include "FileFinder.hpp" #include "Message.hpp" #include "MetafontWrapper.hpp" #include "Process.hpp" #include "XMLString.hpp" using namespace std; MetafontWrapper::MetafontWrapper (string fname, string dir) : _fontname(std::move(fname)), _dir(std::move(dir)) { // ensure that folder paths ends with slash if (_dir.empty()) _dir = "./"; else if (_dir != "/" && _dir.back() != '/') _dir += '/'; } /** Calls Metafont and evaluates the logfile. If a gf file was successfully * generated the dpi value is stripped from the filename * (e.g. cmr10.600gf => cmr10.gf). This makes life easier... * @param[in] mode Metafont mode, e.g. "ljfour" * @param[in] mag magnification factor * @return true on success */ bool MetafontWrapper::call (const string &mode, double mag) { if (!FileFinder::instance().lookup(_fontname+".mf")) return false; // mf file not available => no need to call the "slow" Metafont FileSystem::remove(_fontname+".gf"); #ifdef _WIN32 #ifdef TEXLIVEWIN32 const char *mfname = "mf-nowin.exe"; #else const char *mfname = "mf.exe"; #endif const char *cmd = FileFinder::instance().lookup(mfname, false); if (!cmd) { Message::estream(true) << "can't run Metafont (" << mfname << " not found)\n"; return false; } #else const char *cmd = "mf"; #endif ostringstream oss; oss << "\"\\mode=" << mode << ";" // set MF mode, e.g. 'proof', 'ljfour' or 'localfont' "mode_setup;" // initialize MF variables "mag:=" << mag << ";" // set magnification factor "show pixels_per_inch*mag;" // print character resolution to stdout "batchmode;" // don't halt on errors and don't print informational messages "input " << _fontname << "\""; // load font description Message::mstream(false, Message::MC_STATE) << "\nrunning Metafont for " << _fontname << '\n'; Process mf_process(cmd, oss.str()); string mf_messages; mf_process.run(_dir, &mf_messages); // get resolution value from stdout created by above MF command char buf[256]; istringstream iss(mf_messages); int resolution = 0; while (iss) { iss.getline(buf, sizeof(buf)); string line = buf; if (line.substr(0, 3) == ">> ") { resolution = stoi(line.substr(3)); break; } } // compose expected name of GF file (see Metafont Book, p. 324) string gfname = _dir + _fontname + "."; if (resolution > 0) gfname += XMLString(resolution); gfname += "gf"; FileSystem::rename(gfname, _dir+_fontname+".gf"); // remove resolution value from filename return FileSystem::exists(_dir+_fontname+".gf"); } /** Calls Metafont if output files (tfm and gf) don't already exist. * @param[in] mode Metafont mode to be used (e.g. 'ljfour') * @param[in] mag magnification factor * @return true on success */ bool MetafontWrapper::make (const string &mode, double mag) { ifstream tfm(_dir+_fontname+".tfm"); ifstream gf(_dir+_fontname+".gf"); if (gf && tfm) // @@ distinguish between gf and tfm return true; return call(mode, mag); } bool MetafontWrapper::success () const { ifstream tfm(_dir+_fontname+".tfm"); ifstream gf(_dir+_fontname+".gf"); return tfm && gf; }