QProcess * Engine::run(QFileInfo input, QObject * parent /* = nullptr */) { QString exeFilePath = programPath(program()); if (exeFilePath.isEmpty()) return nullptr; QStringList env = QProcess::systemEnvironment(); QProcess * process = new QProcess(parent); QString workingDir = input.canonicalPath(); #if defined(Q_OS_WIN) // files in the root directory of the current drive have to be handled specially // because QFileInfo::canonicalPath() returns a path without trailing slash // (i.e., a bare drive letter) if (workingDir.length() == 2 && workingDir.endsWith(QChar::fromLatin1(':'))) workingDir.append(QChar::fromLatin1('/')); #endif process->setWorkingDirectory(workingDir); #if !defined(Q_OS_DARWIN) // not supported on OS X yet :( // Add a (customized) TEXEDIT environment variable env << QString::fromLatin1("TEXEDIT=%1 --position=%d %s").arg(QCoreApplication::applicationFilePath()); #if defined(Q_OS_WIN) // MiKTeX apparently uses it's own variable env << QString::fromLatin1("MIKTEX_EDITOR=%1 --position=%l \"%f\"").arg(QCoreApplication::applicationFilePath()); #endif #endif QStringList args = arguments(); #if !defined(MIKTEX) // for old MikTeX versions: delete $synctexoption if it causes an error static bool checkedForSynctex = false; static bool synctexSupported = true; if (!checkedForSynctex) { QString pdftex = programPath(QString::fromLatin1("pdftex")); if (!pdftex.isEmpty()) { int result = QProcess::execute(pdftex, QStringList() << QString::fromLatin1("-synctex=1") << QString::fromLatin1("-version")); synctexSupported = (result == 0); } checkedForSynctex = true; } if (!synctexSupported) args.removeAll(QString::fromLatin1("$synctexoption")); #endif args.replaceInStrings(QString::fromLatin1("$synctexoption"), QString::fromLatin1("-synctex=1")); args.replaceInStrings(QString::fromLatin1("$fullname"), input.fileName()); args.replaceInStrings(QString::fromLatin1("$basename"), input.completeBaseName()); args.replaceInStrings(QString::fromLatin1("$suffix"), input.suffix()); args.replaceInStrings(QString::fromLatin1("$directory"), input.absoluteDir().absolutePath()); process->setEnvironment(env); process->setProcessChannelMode(QProcess::MergedChannels); process->start(exeFilePath, args); return process; }
/* http://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe Some OS-specific interfaces: Mac OS X: _NSGetExecutablePath() (man 3 dyld) Linux : readlink /proc/self/exe Solaris : getexecname() FreeBSD : sysctl CTL_KERN KERN_PROC KERN_PROC_PATHNAME -1 BSD with procfs: readlink /proc/curproc/file Windows : GetModuleFileName() with hModule = NULL The portable (but less reliable) method is to use argv[0]. Although it could be set to anything by the calling program, by convention it is set to either a path name of the executable or a name that was found using $PATH. Some shells, including bash and ksh, set the environment variable "_" to the full path of the executable before it is executed. In that case you can use getenv("_") to get it. However this is unreliable because not all shells do this, and it could be set to anything or be left over from a parent process which did not change it before executing your program. */ const char *Application::realProgram() { try { if (!globalRealProgram.empty()) return globalRealProgram.c_str(); #ifdef __APPLE__ { char *fname = (char *)malloc(PATH_MAX); uint32_t sz = PATH_MAX; fname[0] = 0; int ret; ret = _NSGetExecutablePath(fname, &sz); if (ret == 0) { globalRealProgram = fname; globalRealProgram = detail::normalizePath(globalRealProgram); } else { globalRealProgram = guess_app_from_path(::qi::Application::argv()[0]); } free(fname); } #elif __linux__ boost::filesystem::path p("/proc/self/exe"); boost::filesystem::path fname = boost::filesystem::read_symlink(p); if (!boost::filesystem::is_empty(fname)) globalRealProgram = fname.string().c_str(); else globalRealProgram = guess_app_from_path(::qi::Application::argv()[0]); #elif _WIN32 WCHAR fname[MAX_PATH]; int ret = GetModuleFileNameW(NULL, fname, MAX_PATH); if (ret > 0) { fname[ret] = '\0'; boost::filesystem::path programPath(fname, qi::unicodeFacet()); globalRealProgram = programPath.string(qi::unicodeFacet()); } else { // GetModuleFileName failed, trying to guess from argc, argv... globalRealProgram = guess_app_from_path(::qi::Application::argv()[0]); } #else globalRealProgram = guess_app_from_path(::qi::Application::argv()[0]); #endif return globalRealProgram.c_str(); } catch (...) { return NULL; } }
bool Engine::isAvailable() const { return !(programPath(program()).isEmpty()); }