/* This file is part of dvi2bitmap; see README for copyrights and licence */ #include // Put the entire module inside #if ENABLE_KPATHSEA. // We _shouldn't_ be compiling this is that's false, but we obviously are, // if we get here, so make it a no-op. #ifdef ENABLE_KPATHSEA #define NULL 0 #include // for cerr #ifdef HAVE_CSTD_INCLUDE #include #else #include #endif using STD::cerr; #include #include // for PkFont::dpiBase // The Kpathsea library interface has to be isolated in this class because the // kpathsea headers typedef a `string' type, which conflicts with C++ string. // // This WAS: ''It would be more appropriate to put this into a namespace, but egcs // doesn't support that, so fake it by putting them in a class with only // static methods.'' Well, we do have namespaces now (or rather, I // don't want to support C++ compilers which don't have them), so the // kpse stuff is now in a kpse namespace. It might be that this // should prompt a redesign of this class, into something more // object-oriented. We need to use namespacing, now, since we need to // include PkFont.h, and that in turn includes , which // messes things up royally unless we finally use namespaces. // // The headers here use HAVE_ASSERT_H, so that might need to be configured. // They also test HAVE_PROTOTYPES and STDC_HEADERS, both of which should be // defined here, since the facilities they represent should be // available in C++ (that's `should' as in `ought' rather than as in // `probably are'...). // // We must _avoid_ including c-std.h, since that file carefully // declares popen and pclose, but does so K&R-style, with no // arguments. This seems to have got past most compilers, but gcc, // apparently in a recent burst of standards enthusiasm, seems to have // decided to object to this. KPATHSEA_C_STD_H is the guard // definition which c-std.h uses to avoid rereading itself; the one // thing we do need from that file is stdio.h, so we read that // explicitly. #define HAVE_PROTOTYPES #ifndef STDC_HEADERS #define STDC_HEADERS #endif #define KPATHSEA_C_STD_H 1 #include namespace kpse { extern "C" { #include #include #include #include // We should, or we shouldn't, initialise kpse_format_info // here. This array is elaborately initialised at run-time in // kpse_init_format (tex-file.c in web2c sources). If, // however, it isn't initialised at compile time, then it can // cause linking errors on OSX. See thread // , // where I reported what I thought was a non-initialisation // bug, for more details. // // That said, it appears that in later versions of GCC (eg // 4.2) this duplicated initialisation causes compilation // problems (opaque ones, to do with "expected initializer // before '.' token" on this line...!), so it seems best to // remove this fix. I have a horrible feeling this might be // compiler dependent. //kpse_format_info_type kpse_format_info[kpse_last_format] = { 0 }; } } #undef HAVE_PROTOTYPES // Declare static variables KarlPathSearcher *KarlPathSearcher::instance_ = 0; verbosities KarlPathSearcher::verbosity_ = normal; const char* KarlPathSearcher::default_program_name_ = 0; /** * Private constructor, does the initialisation work. * *

Unfortunately, this naive implementation of a Singleton pattern * has the problem that gcc (for example) reasonably enough warns * that ``class KarlPathSearcher' only defines a private destructor * and has no friends'. I think we can address this, somehow, * using code:auto_ptr. However, that doesn't work naively either. * In any case, this is documented to be a singleton object, so * nothing should attempt to delete it. It would be nice, therefore, * to make the destructor private, and damn the warning. Perhaps the * analogues of g++'s -Wctor-dtor-privacy might be useful. * * @param program_name the name to be used in kpathsea feedback * @param basedpi the base resolution of the PK fonts; should * generally be {@link PkFont#dpiBase} */ KarlPathSearcher::KarlPathSearcher(const char* program_name, const int basedpi) { #ifdef DEFAULT_TEXMFCNF // if the TEXMFCNF variable isn't set in the environment, set it to this char *texmfcnf = getenv ("TEXMFCNF"); if (texmfcnf == NULL) { if (setenv ("TEXMFCNF", DEFAULT_TEXMFCNF, 1) && verbosity_ > quiet) cerr << "KarlPathSearcher: Warning: couldn't set TEXMFCNF\n"; } else cerr << "KarlPathSearcher: TEXMFCNF=" << texmfcnf << '\n'; #endif #ifdef FAKE_PROGNAME // Lie about the program name, so we can influence the definitions of // the SELFAUTO{LOC,DIR,PARENT} variables. // // kpse_set_program_name uses the value of program_invocation_name if // that's defined, and defines it, and initialises it to program_name, // if it's not. The only way we can reliably intervene here is by // setting that variable ourselves. Unfortunately, this means that we're // lying about this for the remainder of this program, but we can't do // better than this without independently discovering for ourselves if // program_invocation_name is set in the libc library. We can't get // round this by defining the variables by hand ourselves, since // kpse_set_program_name does elaborate following of links and other // consistency checks, which we do not want to duplicate here. // // In any case, this is supposed to be not much more than a hack to avoid // being bitten by arguably misconfigured texmf.cnf files, so don't lose // sleep over it. program_name = FAKE_PROGNAME; //program_name = kpse::program_invocation_name = FAKE_PROGNAME; if (verbosity_ > normal) { cerr << "KarlPathSearcher: fake-progname=" << program_name << '\n'; } #endif kpse::kpse_set_program_name (program_name, // current program name "dvi2bitmap"); // used in searching texmf.cnf kpse::kpse_init_prog ("TEX", // prefix to make TEXFONTS, TEXHEADERS, etc basedpi, NULL, NULL); } KarlPathSearcher::~KarlPathSearcher() { // nothing } /** * Returns an instance of the object which searches the TeX tree, * using Karl's path-searching algorithm (KPSE). * *

Note that, although it looks as if you should be able to call * this more than once with different parameters, you can't in fact, * and if you call it more than once (that's fine and sensible) you * get the same instance back each time. In fact, there's no good * reason I can think of why you'd want to initialise this in * different ways, so this isn't a problem in fact. The door remains * open to this changing in future, though. About the only reason for * giving non-default parameters here is to register a different * program_name for the kpathsea library to use when * reporting errors or warnings. * * @param program_name the name to be used in kpathsea feedback; if * zero, this default to the value set by {@link #setProgramName}, and * if that has not been set, to "tex" * @param basedpi the base resolution of the PK fonts; if zero, it is * taken to be {@link PkFont.dpiBase} (a sensible default) */ KarlPathSearcher* KarlPathSearcher::getInstance(const char *program_name, const int basedpi) { if (instance_ == 0) { instance_ = new KarlPathSearcher(program_name != 0 ? program_name : (default_program_name_ != 0 ? default_program_name_ : "tex"), basedpi != 0 ? basedpi : PkFont::dpiBase()); } return instance_; } /** * Obtains the Kpathsea version * @return the kpathsea version string */ const char *KarlPathSearcher::version_string (void) { extern char *kpathsea_version_string; return kpathsea_version_string; } /** * Finds a font at a given resolution. * @param fontname the name of the font to search for * @param resolution the desired font resolution * @return the full path to the PK file which defines the font, or * zero if the font cannot be found */ const char *KarlPathSearcher::find (const char *fontname, int resolution) { kpse::kpse_glyph_file_type glyph_info; char *fname; // This next line is really // fname = kpse::kpse_find_pk (fontname, resolution, &glyph_info); // but kpse_find_pk is really a macro (grrr), so we have to unpack it // if the namespacing is to work. fname = kpse::kpse_find_glyph(fontname, resolution, kpse::kpse_pk_format, &glyph_info); if (verbosity_ > normal) { if (fname) { cerr << "KarlPathSearcher: KPSE found file " << fname << '\n'; } else { cerr << "KarlPathSearcher: KPSE can't find file " << fontname << " res=" << resolution << '\n'; } } return fname; } /** * Sets the verbosity level. As well as setting the intrinsic level * of chatter for this class, it controls the amount of chatter from * the libkpathsea library itself: if the * level is above debug, then all * kpathsea debugging information is switched on. * @param level the desired verbosity level * @return the previous verbosity level */ verbosities KarlPathSearcher::verbosity (const verbosities level) { verbosities oldv = verbosity_; verbosity_ = level; if (level > debug) kpse::kpathsea_debug = ~0; // all debugging else kpse::kpathsea_debug = 0; // none return oldv; } #endif // if ENABLE_KPATHSEA