diff options
Diffstat (limited to 'Build/source/texk/dvisvgm/dvisvgm-src/src/FileFinder.cpp')
-rw-r--r-- | Build/source/texk/dvisvgm/dvisvgm-src/src/FileFinder.cpp | 278 |
1 files changed, 278 insertions, 0 deletions
diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FileFinder.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FileFinder.cpp new file mode 100644 index 00000000000..2418c8fb786 --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FileFinder.cpp @@ -0,0 +1,278 @@ +/************************************************************************* +** FileFinder.cpp ** +** ** +** This file is part of dvisvgm -- the DVI to SVG converter ** +** Copyright (C) 2005-2015 Martin Gieseking <martin.gieseking@uos.de> ** +** ** +** 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 <http://www.gnu.org/licenses/>. ** +*************************************************************************/ + +#include <config.h> + +#ifdef MIKTEX + #include "MessageException.h" + #include "MiKTeXCom.h" + static MiKTeXCom *miktex=0; +#else + #ifdef KPSE_CXX_UNSAFE + extern "C" { + #endif + #include <kpathsea/kpathsea.h> + #ifdef KPSE_CXX_UNSAFE + } + #endif +#endif + +#include <cstdlib> +#include <fstream> +#include <map> +#include <string> +#include "FileFinder.h" +#include "FileSystem.h" +#include "FontMap.h" +#include "Message.h" +#include "Process.h" + +// --------------------------------------------------- + +static bool _initialized = false; +static bool _mktex_enabled = false; + +// --------------------------------------------------- + +static const char* find_file (const std::string &fname, const char *ftype); +static const char* find_mapped_file (std::string fname); +static const char* mktex (const std::string &fname); + + +/** Initializes the file finder. This function must be called before any other + * FileFinder function. + * @param[in] argv0 argv[0] of main() function + * @param[in] progname name of application using the FileFinder + * @param[in] enable_mktexmf if true, tfm and mf file generation is activated */ +void FileFinder::init (const char *argv0, const char *progname, bool enable_mktexmf) { + if (_initialized) + return; + + _mktex_enabled = enable_mktexmf; +#ifdef MIKTEX + miktex = new MiKTeXCom; +#else + kpse_set_program_name(argv0, progname); + // enable tfm and mf generation (actually invoked by calls of kpse_make_tex) + kpse_set_program_enabled(kpse_tfm_format, 1, kpse_src_env); + kpse_set_program_enabled(kpse_mf_format, 1, kpse_src_env); + kpse_make_tex_discard_errors = true; // suppress messages from mktexFOO tools +#ifdef TEXLIVEWIN32 + texlive_gs_init(); +#endif +#endif + _initialized = true; +} + + +/** Cleans up the FileFinder. This function must be called before leaving the + * application's main() function. */ +void FileFinder::finish () { +#ifdef MIKTEX + if (miktex) { + delete miktex; + miktex = 0; + } +#endif + _initialized = false; +} + + +/** Returns the version string of the underlying file searching library (kpathsea, MiKTeX) */ +std::string FileFinder::version () { +#ifdef MIKTEX + bool autoinit=false; + try { + if (!_initialized) { + init("", "", false); + autoinit = true; + } + std::string ret = miktex->getVersion(); + if (autoinit) + finish(); + return ret; + } + catch (MessageException &e) { + if (autoinit) + finish(); + } +#else + if (const char *v = strrchr(KPSEVERSION, ' ')) + return v+1; +#endif + return "unknown"; +} + + +/** Determines filetype by the filename extension and calls kpse_find_file + * to actually look up the file. + * @param[in] fname name of file to look up + * @param[in] ftype expected file format of file fname; if 0, it's derived from the filename suffix + * @return file path on success, 0 otherwise */ +static const char* find_file (const std::string &fname, const char *ftype) { + if (!_initialized || fname.empty()) + return 0; + + std::string ext; + if (ftype) + ext = ftype; + else { + size_t pos = fname.rfind('.'); + if (pos == std::string::npos) + return 0; // no extension and no file type => no search + ext = fname.substr(pos+1); + } + + static std::string buf; +#ifdef MIKTEX + if (ext == "dll" || ext == "exe") { + // lookup dll and exe files in the MiKTeX bin directory first + buf = miktex->getBinDir() + "/" + fname; + if (FileSystem::exists(buf.c_str())) + return buf.c_str(); + } + else if (ext == "cmap") { + // The MiKTeX SDK doesn't support the lookup of files without suffix (yet), thus + // it's not possible to find cmap files which usually don't have a suffix. In order + // to work around this, we try to lookup the files by calling kpsewhich. + Process process("kpsewhich", std::string("-format=cmap ")+fname); + process.run(&buf); + return buf.empty() ? 0 : buf.c_str(); + } + try { + return miktex->findFile(fname.c_str()); + } + catch (const MessageException &e) { + return 0; + } +#else +#ifdef TEXLIVEWIN32 + if (ext == "exe") { + // lookup exe files in directory where dvisvgm is located + if (const char *path = kpse_var_value("SELFAUTOLOC")) { + buf = std::string(path) + "/" + fname; + return FileSystem::exists(buf.c_str()) ? buf.c_str() : 0; + } + return 0; + } +#endif + static std::map<std::string, kpse_file_format_type> types; + if (types.empty()) { + types["tfm"] = kpse_tfm_format; + types["pfb"] = kpse_type1_format; + types["vf"] = kpse_vf_format; + types["mf"] = kpse_mf_format; + types["ttc"] = kpse_truetype_format; + types["ttf"] = kpse_truetype_format; + types["otf"] = kpse_opentype_format; + types["map"] = kpse_fontmap_format; + types["cmap"] = kpse_cmap_format; + types["sty"] = kpse_tex_format; + types["enc"] = kpse_enc_format; + types["pro"] = kpse_tex_ps_header_format; + types["sfd"] = kpse_sfd_format; + } + std::map<std::string, kpse_file_format_type>::iterator it = types.find(ext.c_str()); + if (it == types.end()) + return 0; + + if (char *path = kpse_find_file(fname.c_str(), it->second, 0)) { + // In the current version of libkpathsea, each call of kpse_find_file produces + // a memory leak since the path buffer is not freed. I don't think we can do + // anything against it here... + buf = path; + std::free(path); + return buf.c_str(); + } + return 0; +#endif +} + + +/** Checks whether the given file is mapped to a different name and if the + * file can be found under this name. + * @param[in] fname name of file to look up + * @return file path on success, 0 otherwise */ +static const char* find_mapped_file (std::string fname) { + size_t pos = fname.rfind('.'); + if (pos == std::string::npos) + return 0; + const std::string ext = fname.substr(pos+1); // file extension + const std::string base = fname.substr(0, pos); + if (const FontMap::Entry *entry = FontMap::instance().lookup(base)) { + const char *path=0; + if (entry->fontname.find('.') != std::string::npos) // does the mapped filename has an extension? + path = find_file(entry->fontname, 0); // look for that file + else { // otherwise, use extension of unmapped file + fname = entry->fontname + "." + ext; + (path = find_file(fname, 0)) || (path = mktex(fname)); + } + return path; + } + return 0; +} + + +/** Runs external mktexFOO tool to create missing tfm or mf file. + * @param[in] fname name of file to build + * @return file path on success, 0 otherwise */ +static const char* mktex (const std::string &fname) { + if (!_initialized) + return 0; + + size_t pos = fname.rfind('.'); + if (!_mktex_enabled || pos == std::string::npos) + return 0; + + std::string ext = fname.substr(pos+1); // file extension + if (ext != "tfm" && ext != "mf") + return 0; + + const char *path = 0; +#ifdef MIKTEX + // maketfm and makemf are located in miktex/bin which is in the search PATH + std::string toolname = (ext == "tfm" ? "miktex-maketfm" : "miktex-makemf"); + system((toolname+".exe "+fname).c_str()); + path = find_file(fname, 0); +#else + kpse_file_format_type type = (ext == "tfm" ? kpse_tfm_format : kpse_mf_format); + path = kpse_make_tex(type, fname.c_str()); +#endif + return path; +} + + +/** Searches a file in the TeX directory tree. + * If the file doesn't exist, maximal two further steps are applied + * (if "extended" is true): + * - checks whether the filename is mapped to a different name and returns + * the path to that name + * - in case of tfm or mf files: invokes the external mktextfm/mktexmf tool + * to create the missing file + * @param[in] fname name of file to look up + * @param[in] ftype type/format of file to look up + * @param[in] extended if true, use fontmap lookup and mktexFOO calls + * @return path to file on success, 0 otherwise */ +const char* FileFinder::lookup (const std::string &fname, const char *ftype, bool extended) { + const char *path; + if ((path = find_file(fname, ftype)) || (extended && ((path = find_mapped_file(fname)) || (path = mktex(fname))))) + return path; + return 0; +} |