X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fsupport%2Ffiletools.cpp;h=a72c93ed610ce7c711df4eab94f2d8d0f7ae7446;hb=8d640dc77608bedddb5b00982c23665584f52d21;hp=810694ec785c74ea8ce2fb7bcfea02bfc63790ba;hpb=8f3acbb4842ff31d1229eec8fba4890be743f2d9;p=lyx.git diff --git a/src/support/filetools.cpp b/src/support/filetools.cpp index 810694ec78..a72c93ed61 100644 --- a/src/support/filetools.cpp +++ b/src/support/filetools.cpp @@ -21,6 +21,8 @@ #include +#include "LyXRC.h" + #include "support/filetools.h" #include "support/debug.h" @@ -28,17 +30,25 @@ #include "support/gettext.h" #include "support/lstrings.h" #include "support/os.h" +#include "support/Messages.h" #include "support/Package.h" -#include "support/Path.h" +#include "support/PathChanger.h" #include "support/Systemcall.h" #include "support/qstring_helpers.h" #include +#include #include "support/lassert.h" -#include +#include "support/regex.h" #include +#ifdef HAVE_MAGIC_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif #include #include @@ -47,6 +57,12 @@ #include #include #include +#include + +#if defined (_WIN32) +#include +#include +#endif using namespace std; @@ -55,25 +71,86 @@ using namespace std; namespace lyx { namespace support { -bool isLyXFilename(string const & filename) +bool isLyXFileName(string const & filename) { return suffixIs(ascii_lowercase(filename), ".lyx"); } -bool isSGMLFilename(string const & filename) +bool isSGMLFileName(string const & filename) { return suffixIs(ascii_lowercase(filename), ".sgml"); } -bool isValidLaTeXFilename(string const & filename) +bool isValidLaTeXFileName(string const & filename) +{ + string const invalid_chars("#%\""); + return filename.find_first_of(invalid_chars) == string::npos; +} + + +bool isValidDVIFileName(string const & filename) { - string const invalid_chars("#$%{}()[]\"^"); + string const invalid_chars("${}()[]^"); return filename.find_first_of(invalid_chars) == string::npos; } +bool isBinaryFile(FileName const & filename) +{ + bool isbinary = false; + if (filename.empty() || !filename.exists()) + return isbinary; + +#ifdef HAVE_MAGIC_H + magic_t magic_cookie = magic_open(MAGIC_MIME_ENCODING); + if (magic_cookie) { + bool detected = true; + if (magic_load(magic_cookie, NULL) != 0) { + LYXERR(Debug::FILES, "isBinaryFile: " + "Could not load magic database - " + << magic_error(magic_cookie)); + detected = false; + } else { + char const *charset = magic_file(magic_cookie, + filename.toFilesystemEncoding().c_str()); + isbinary = contains(charset, "binary"); + } + magic_close(magic_cookie); + if (detected) + return isbinary; + } +#endif + // Try by looking for binary chars at the beginning of the file. + // Note that this is formally not correct, since count_bin_chars + // expects utf8, and the passed string can be anything: plain text + // in any encoding, or really binary data. In practice it works, + // since QString::fromUtf8() drops invalid utf8 sequences, and + // while the exact number may not be correct, we still get a high + // number for truly binary files. + + ifstream ifs(filename.toFilesystemEncoding().c_str()); + if (!ifs) + return isbinary; + + // Maximum strings to read + int const max_count = 50; + + // Maximum number of binary chars allowed + int const max_bin = 5; + + int count = 0; + int binchars = 0; + string str; + while (count++ < max_count && !ifs.eof()) { + getline(ifs, str); + binchars += count_bin_chars(str); + } + return binchars > max_bin; +} + + string const latex_path(string const & original_path, latex_path_extension extension, latex_path_dots dots) @@ -85,13 +162,13 @@ string const latex_path(string const & original_path, // We can't use '"' because " is sometimes active (e.g. if // babel is loaded with the "german" option) if (extension == EXCLUDE_EXTENSION) { - // ChangeExtension calls os::internal_path internally + // changeExtension calls os::internal_path internally // so don't use it to remove the extension. string const ext = getExtension(path); string const base = ext.empty() ? path : path.substr(0, path.length() - ext.length() - 1); - // ChangeExtension calls os::internal_path internally + // changeExtension calls os::internal_path internally // so don't use it to re-add the extension. path = "\\string\"" + base + "\\string\"." + ext; } else { @@ -99,7 +176,18 @@ string const latex_path(string const & original_path, } } - return dots == ESCAPE_DOTS ? subst(path, ".", "\\lyxdot ") : path; + if (dots != ESCAPE_DOTS) + return path; + + // Replace dots with the lyxdot macro, but only in the file name, + // not the directory part. + // addName etc call os::internal_path internally + // so don't use them for path manipulation + // The directory separator is always '/' for LaTeX. + string::size_type pos = path.rfind('/'); + if (pos == string::npos) + return subst(path, ".", "\\lyxdot "); + return path.substr(0, pos) + subst(path.substr(pos), ".", "\\lyxdot "); } @@ -107,7 +195,7 @@ string const latex_path(string const & original_path, FileName const makeLatexName(FileName const & file) { string name = file.onlyFileName(); - string const path = file.onlyPath().absFilename() + "/"; + string const path = file.onlyPath().absFileName() + "/"; // ok so we scan through the string twice, but who cares. // FIXME: in Unicode time this will break for sure! There is @@ -130,20 +218,29 @@ string const quoteName(string const & name, quote_style style) { switch(style) { case quote_shell: - // This does not work for filenames containing " (windows) - // or ' (all other OSes). This can't be changed easily, since - // we would need to adapt the command line parser in - // Forkedcall::generateChild. Therefore we don't pass user - // filenames to child processes if possible. We store them in - // a python script instead, where we don't have these - // limitations. + // This does not work on native Windows for filenames + // containing the following characters < > : " / \ | ? * + // Moreover, it can't be made to work, as, according to + // http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx + // those are reserved characters, and thus are forbidden. + // Please, also note that the command-line parser in + // ForkedCall::generateChild cannot deal with filenames + // containing " or ', therefore we don't pass user filenames + // to child processes if possible. We store them in a python + // script instead, where we don't have these limitations. #ifndef USE_QPROCESS return (os::shell() == os::UNIX) ? - '\'' + name + '\'': + '\'' + subst(name, "'", "\'\\\'\'") + '\'' : '"' + name + '"'; #else - return '"' + name + '"'; + // According to the QProcess parser, a single double + // quote is represented by three consecutive ones. + // Here we simply escape the double quote and let our + // simple parser in Systemcall.cpp do the substitution. + return '"' + subst(name, "\"", "\\\"") + '"'; #endif + case quote_shell_filename: + return quoteName(os::external_path(name), quote_shell); case quote_python: return "\"" + subst(subst(name, "\\", "\\\\"), "\"", "\\\"") + "\""; @@ -172,9 +269,9 @@ FileName const fileOpenSearch(string const & path, string const & name, if (!suffixIs(path_element, '/')) path_element += '/'; path_element = subst(path_element, "$$LyX", - package().system_support().absFilename()); + package().system_support().absFileName()); path_element = subst(path_element, "$$User", - package().user_support().absFilename()); + package().user_support().absFileName()); real_file = fileSearch(path_element, name, ext); @@ -194,7 +291,7 @@ FileName const fileOpenSearch(string const & path, string const & name, // Returns the real name of file name in directory path, with optional // extension ext. FileName const fileSearch(string const & path, string const & name, - string const & ext, search_mode mode) + string const & exts, search_mode mode) { // if `name' is an absolute path, we ignore the setting of `path' // Expand Environmentvariables in 'name' @@ -203,15 +300,29 @@ FileName const fileSearch(string const & path, string const & name, // search first without extension, then with it. if (fullname.isReadableFile()) return fullname; - if (ext.empty()) + if (exts.empty()) // We are done. return mode == may_not_exist ? fullname : FileName(); - // Only add the extension if it is not already the extension of - // fullname. - if (getExtension(fullname.absFilename()) != ext) - fullname = FileName(addExtension(fullname.absFilename(), ext)); - if (fullname.isReadableFile() || mode == may_not_exist) - return fullname; + int n = 0; + string ext = token(exts, ',', n); + while (!ext.empty()) { + // Only add the extension if it is not already the extension of + // fullname. + bool addext = getExtension(fullname.absFileName()) != ext; + if (addext) { + if (mode == check_hidpi) { + FileName fullname2x = FileName(addExtension(fullname.absFileName() + "@2x", ext)); + if (fullname2x.isReadableFile()) + return fullname2x; + } + fullname = FileName(addExtension(fullname.absFileName(), ext)); + } + if (fullname.isReadableFile() || mode == may_not_exist) + return fullname; + if (addext) + fullname.changeExtension(""); + ext = token(exts, ',', ++n); + } return FileName(); } @@ -221,20 +332,21 @@ FileName const fileSearch(string const & path, string const & name, // 2) build_lyxdir (if not empty) // 3) system_lyxdir FileName const libFileSearch(string const & dir, string const & name, - string const & ext) + string const & ext, search_mode mode) { - FileName fullname = fileSearch(addPath(package().user_support().absFilename(), dir), - name, ext); + FileName fullname = fileSearch(addPath(package().user_support().absFileName(), dir), + name, ext, mode); if (!fullname.empty()) return fullname; if (!package().build_support().empty()) - fullname = fileSearch(addPath(package().build_support().absFilename(), dir), - name, ext); + fullname = fileSearch(addPath(package().build_support().absFileName(), dir), + name, ext, mode); if (!fullname.empty()) return fullname; - return fileSearch(addPath(package().system_support().absFilename(), dir), name, ext); + return fileSearch(addPath(package().system_support().absFileName(), dir), + name, ext, mode); } @@ -249,7 +361,7 @@ FileName const i18nLibFileSearch(string const & dir, string const & name, each po file is able to tell us its name. (JMarc) */ - string lang = to_ascii(_("[[Replace with the code of your language]]")); + string lang = getGuiMessages().language(); string const language = getEnv("LANGUAGE"); if (!lang.empty() && !language.empty()) lang = language; @@ -288,11 +400,30 @@ FileName const i18nLibFileSearch(string const & dir, string const & name, } -string const libScriptSearch(string const & command_in, quote_style style) +FileName const imageLibFileSearch(string & dir, string const & name, + string const & ext, search_mode mode) +{ + if (!lyx::lyxrc.icon_set.empty()) { + string const imagedir = addPath(dir, lyx::lyxrc.icon_set); + FileName const fn = libFileSearch(imagedir, name, ext, mode); + if (fn.exists()) { + dir = imagedir; + return fn; + } + } + return libFileSearch(dir, name, ext, mode); +} + + +string const commandPrep(string const & command_in) { static string const token_scriptpath = "$$s/"; + string const python_call = "python -tt"; string command = command_in; + if (prefixIs(command_in, python_call)) + command = os::python() + command_in.substr(python_call.length()); + // Find the starting position of "$$s/" string::size_type const pos1 = command.find(token_scriptpath); if (pos1 == string::npos) @@ -306,12 +437,16 @@ string const libScriptSearch(string const & command_in, quote_style style) // Does this script file exist? string const script = - libFileSearch(".", command.substr(start_script, size_script)).absFilename(); + libFileSearch(".", command.substr(start_script, size_script)).absFileName(); if (script.empty()) { // Replace "$$s/" with "" command.erase(pos1, 4); } else { + quote_style style = quote_shell; + if (prefixIs(command, os::python())) + style = quote_python; + // Replace "$$s/foo/some_script" with "/some_script". string::size_type const size_replace = size_script + 4; command.replace(pos1, size_replace, quoteName(script, style)); @@ -321,12 +456,35 @@ string const libScriptSearch(string const & command_in, quote_style style) } +static string createTempFile(QString const & mask) +{ + // FIXME: This is not safe. QTemporaryFile creates a file in open(), + // but the file is deleted when qt_tmp goes out of scope. + // Therefore the next call to createTempFile() may create the + // same file again. To make this safe the QTemporaryFile object + // needs to be kept for the whole life time of the temp file name. + // This could be achieved by creating a class TempDir (like + // TempFile, but using a currentlky non-existing + // QTemporaryDirectory object). + QTemporaryFile qt_tmp(mask + ".XXXXXXXXXXXX"); + if (qt_tmp.open()) { + string const temp_file = fromqstr(qt_tmp.fileName()); + LYXERR(Debug::FILES, "Temporary file `" << temp_file << "' created."); + return temp_file; + } + LYXERR(Debug::FILES, "Unable to create temporary file with following template: " + << qt_tmp.fileTemplate()); + return string(); +} + + static FileName createTmpDir(FileName const & tempdir, string const & mask) { LYXERR(Debug::FILES, "createTmpDir: tempdir=`" << tempdir << "'\n" << "createTmpDir: mask=`" << mask << '\''); - FileName const tmpfl = FileName::tempName(tempdir, mask); + QFileInfo tmp_fi(QDir(toqstr(tempdir.absFileName())), toqstr(mask)); + FileName const tmpfl(createTempFile(tmp_fi.absoluteFilePath())); if (tmpfl.empty() || !tmpfl.createDirectory(0700)) { LYXERR0("LyX could not create temporary directory in " << tempdir @@ -343,7 +501,7 @@ FileName const createLyXTmpDir(FileName const & deflt) if (deflt.empty() || deflt == package().system_temp_dir()) return createTmpDir(package().system_temp_dir(), "lyx_tmpdir"); - if (deflt.createDirectory(0777)) + if (deflt.createDirectory(0777)) return deflt; if (deflt.isDirWritable()) { @@ -352,7 +510,7 @@ FileName const createLyXTmpDir(FileName const & deflt) // dir inside deflt. return createTmpDir(deflt, "lyx_tmpdir"); } else { - // some other error occured. + // some other error occurred. return createTmpDir(package().system_temp_dir(), "lyx_tmpdir"); } } @@ -394,7 +552,7 @@ FileName const makeAbsPath(string const & relPath, string const & basePath) if (FileName::isAbsolute(basePath)) tempBase = basePath; else - tempBase = addPath(FileName::getcwd().absFilename(), basePath); + tempBase = addPath(FileName::getcwd().absFileName(), basePath); // Handle /./ at the end of the path while (suffixIs(tempBase, "/./")) @@ -408,7 +566,7 @@ FileName const makeAbsPath(string const & relPath, string const & basePath) // Split by first / rTemp = split(rTemp, temp, '/'); if (temp == "~") { - tempBase = package().home_dir().absFilename(); + tempBase = Package::get_home_dir().absFileName(); tempRel = rTemp; } @@ -457,7 +615,7 @@ FileName const makeAbsPath(string const & relPath, string const & basePath) // Chops any path of filename. string const addName(string const & path, string const & fname) { - string const basename = onlyFilename(fname); + string const basename = onlyFileName(fname); string buf; if (path != "." && path != "./" && !path.empty()) { @@ -471,7 +629,7 @@ string const addName(string const & path, string const & fname) // Strips path from filename -string const onlyFilename(string const & fname) +string const onlyFileName(string const & fname) { if (fname.empty()) return fname; @@ -501,13 +659,13 @@ string const expandPath(string const & path) rTemp = split(rTemp, temp, '/'); if (temp == ".") - return FileName::getcwd().absFilename() + '/' + rTemp; + return FileName::getcwd().absFileName() + '/' + rTemp; if (temp == "~") - return package().home_dir().absFilename() + '/' + rTemp; + return Package::get_home_dir().absFileName() + '/' + rTemp; if (temp == "..") - return makeAbsPath(copy).absFilename(); + return makeAbsPath(copy).absFileName(); // Don't know how to handle this return copy; @@ -522,34 +680,118 @@ string const replaceEnvironmentPath(string const & path) static string const envvar_br = "[$]\\{([A-Za-z_][A-Za-z_0-9]*)\\}"; // $VAR is defined as: - // $\{[A-Za-z_][A-Za-z_0-9]*\} + // $[A-Za-z_][A-Za-z_0-9]* static string const envvar = "[$]([A-Za-z_][A-Za-z_0-9]*)"; - static boost::regex envvar_br_re("(.*)" + envvar_br + "(.*)"); - static boost::regex envvar_re("(.*)" + envvar + "(.*)"); - boost::smatch what; - string result; - string remaining = path; + static regex const envvar_br_re("(.*)" + envvar_br + "(.*)"); + static regex const envvar_re("(.*)" + envvar + "(.*)"); + string result = path; while (1) { - regex_match(remaining, what, envvar_br_re); - if (!what[0].matched) { - regex_match(remaining, what, envvar_re); - if (!what[0].matched) { - result += remaining; + smatch what; + if (!regex_match(result, what, envvar_br_re)) { + if (!regex_match(result, what, envvar_re)) break; - } } string env_var = getEnv(what.str(2)); - if (!env_var.empty()) - result += what.str(1) + env_var; - else - result += what.str(1) + "$" + what.str(2); - remaining = what.str(3); + result = what.str(1) + env_var + what.str(3); } return result; } +// Return a command prefix for setting the environment of the TeX engine. +string latexEnvCmdPrefix(string const & path, string const & lpath) +{ + bool use_lpath = !(lpath.empty() || lpath == "." || lpath == "./"); + + if (path.empty() || (lyxrc.texinputs_prefix.empty() && !use_lpath)) + return string(); + + string texinputs_prefix = lyxrc.texinputs_prefix.empty() ? string() + : os::latex_path_list( + replaceCurdirPath(path, lyxrc.texinputs_prefix)); + string const allother_prefix = os::latex_path_list(path); + string const sep = string(1, os::path_separator(os::TEXENGINE)); + string const texinputs = getEnv("TEXINPUTS"); + string const bibinputs = getEnv("BIBINPUTS"); + string const bstinputs = getEnv("BSTINPUTS"); + string const texfonts = getEnv("TEXFONTS"); + + if (use_lpath) { + string const abslpath = FileName::isAbsolute(lpath) + ? os::latex_path(lpath) + : os::latex_path(FileName(path + "/" + lpath).realPath()); + if (texinputs_prefix.empty()) + texinputs_prefix = abslpath; + else if (suffixIs(texinputs_prefix, sep)) + texinputs_prefix.append(abslpath + sep); + else + texinputs_prefix.append(sep + abslpath); + } + + if (os::shell() == os::UNIX) + return "env TEXINPUTS=\"." + sep + texinputs_prefix + + sep + texinputs + "\" " + + "BIBINPUTS=\"." + sep + allother_prefix + + sep + bibinputs + "\" " + + "BSTINPUTS=\"." + sep + allother_prefix + + sep + bstinputs + "\" " + + "TEXFONTS=\"." + sep + allother_prefix + + sep + texfonts + "\" "; + else + // NOTE: the dummy blank dirs are necessary to force the + // QProcess parser to quote the argument (see bug 9453) + return "cmd /d /c set \"TEXINPUTS=." + sep + " " + + sep + texinputs_prefix + + sep + texinputs + "\" & " + + "set \"BIBINPUTS=." + sep + " " + + sep + allother_prefix + + sep + bibinputs + "\" & " + + "set \"BSTINPUTS=." + sep + " " + + sep + allother_prefix + + sep + bstinputs + "\" & " + + "set \"TEXFONTS=." + sep + " " + + sep + allother_prefix + + sep + texfonts + "\" & "; +} + + +// Replace current directory in all elements of a path list with a given path. +string const replaceCurdirPath(string const & path, string const & pathlist) +{ + string const oldpathlist = replaceEnvironmentPath(pathlist); + char const sep = os::path_separator(); + string newpathlist; + + for (size_t i = 0, k = 0; i != string::npos; k = i) { + i = oldpathlist.find(sep, i); + string p = oldpathlist.substr(k, i - k); + if (FileName::isAbsolute(p)) { + newpathlist += p; + } else if (i > k) { + size_t offset = 0; + if (p == ".") { + offset = 1; + } else if (prefixIs(p, "./")) { + offset = 2; + while (p[offset] == '/') + ++offset; + } + newpathlist += addPath(path, p.substr(offset)); + if (suffixIs(p, "//")) + newpathlist += '/'; + } + if (i != string::npos) { + newpathlist += sep; + // Stop here if the last element is empty + if (++i == oldpathlist.length()) + break; + } + } + return newpathlist; +} + + // Make relative path out of two absolute paths docstring const makeRelPath(docstring const & abspath, docstring const & basepath) // Makes relative path out of absolute path. If it is deeper than basepath, @@ -668,7 +910,9 @@ string const unzippedFileName(string const & zipped_file) string const ext = getExtension(zipped_file); if (ext == "gz" || ext == "z" || ext == "Z") return changeExtension(zipped_file, string()); - return onlyPath(zipped_file) + "unzipped_" + onlyFilename(zipped_file); + else if (ext == "svgz") + return changeExtension(zipped_file, "svg"); + return onlyPath(zipped_file) + "unzipped_" + onlyFileName(zipped_file); } @@ -694,12 +938,12 @@ docstring const makeDisplayPath(string const & path, unsigned int threshold) string str = path; // If file is from LyXDir, display it as if it were relative. - string const system = package().system_support().absFilename(); + string const system = package().system_support().absFileName(); if (prefixIs(str, system) && str != system) return from_utf8("[" + str.erase(0, system.length()) + "]"); // replace /home/blah with ~/ - string const home = package().home_dir().absFilename(); + string const home = Package::get_home_dir().absFileName(); if (!home.empty() && prefixIs(str, home)) str = subst(str, home, "~"); @@ -707,45 +951,64 @@ docstring const makeDisplayPath(string const & path, unsigned int threshold) return from_utf8(os::external_path(str)); string const prefix = ".../"; - string temp; + docstring dstr = from_utf8(str); + docstring temp; - while (str.length() > threshold) - str = split(str, temp, '/'); + while (dstr.length() > threshold) + dstr = split(dstr, temp, '/'); // Did we shorten everything away? - if (str.empty()) { + if (dstr.empty()) { // Yes, filename itself is too long. // Pick the start and the end of the filename. - str = onlyFilename(path); - string const head = str.substr(0, threshold / 2 - 3); - - string::size_type len = str.length(); - string const tail = - str.substr(len - threshold / 2 - 2, len - 1); - str = head + "..." + tail; + docstring fstr = from_utf8(onlyFileName(path)); + dstr = fstr; + if (support::truncateWithEllipsis(dstr, threshold / 2)) + dstr += fstr.substr(fstr.length() - threshold / 2 - 2, + docstring::npos); } - return from_utf8(os::external_path(prefix + str)); + return from_utf8(os::external_path(prefix + to_utf8(dstr))); } +#ifdef HAVE_READLINK bool readLink(FileName const & file, FileName & link) { -#ifdef HAVE_READLINK - char linkbuffer[512]; - // Should be PATH_MAX but that needs autconf support string const encoded = file.toFilesystemEncoding(); - int const nRead = ::readlink(encoded.c_str(), +#ifdef HAVE_DEF_PATH_MAX + char linkbuffer[PATH_MAX + 1]; + ssize_t const nRead = ::readlink(encoded.c_str(), linkbuffer, sizeof(linkbuffer) - 1); if (nRead <= 0) return false; linkbuffer[nRead] = '\0'; // terminator - link = makeAbsPath(linkbuffer, onlyPath(file.absFilename())); +#else + vector buf(1024); + int nRead = -1; + + while (true) { + nRead = ::readlink(encoded.c_str(), &buf[0], buf.size() - 1); + if (nRead < 0) { + return false; + } + if (static_cast(nRead) < buf.size() - 1) { + break; + } + buf.resize(buf.size() * 2); + } + buf[nRead] = '\0'; // terminator + const char * linkbuffer = &buf[0]; +#endif + link = makeAbsPath(linkbuffer, onlyPath(file.absFileName())); return true; +} #else +bool readLink(FileName const &, FileName &) +{ return false; -#endif } +#endif cmd_ret const runCommand(string const & cmd) @@ -760,7 +1023,54 @@ cmd_ret const runCommand(string const & cmd) // pstream (process stream), with the // variants ipstream, opstream -#if defined (HAVE_POPEN) +#if defined (_WIN32) + STARTUPINFO startup; + PROCESS_INFORMATION process; + SECURITY_ATTRIBUTES security; + HANDLE in, out; + FILE * inf = 0; + bool err2out = false; + string command; + string const infile = trim(split(cmd, command, '<'), " \""); + command = rtrim(command); + if (suffixIs(command, "2>&1")) { + command = rtrim(command, "2>&1"); + err2out = true; + } + string const cmdarg = "/d /c " + command; + string const comspec = getEnv("COMSPEC"); + + security.nLength = sizeof(SECURITY_ATTRIBUTES); + security.bInheritHandle = TRUE; + security.lpSecurityDescriptor = NULL; + + if (CreatePipe(&in, &out, &security, 0)) { + memset(&startup, 0, sizeof(STARTUPINFO)); + memset(&process, 0, sizeof(PROCESS_INFORMATION)); + + startup.cb = sizeof(STARTUPINFO); + startup.dwFlags = STARTF_USESTDHANDLES; + + startup.hStdError = err2out ? out : GetStdHandle(STD_ERROR_HANDLE); + startup.hStdInput = infile.empty() + ? GetStdHandle(STD_INPUT_HANDLE) + : CreateFile(infile.c_str(), GENERIC_READ, + FILE_SHARE_READ, &security, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + startup.hStdOutput = out; + + if (startup.hStdInput != INVALID_HANDLE_VALUE && + CreateProcess(comspec.c_str(), (LPTSTR)cmdarg.c_str(), + &security, &security, TRUE, CREATE_NO_WINDOW, + 0, 0, &startup, &process)) { + + CloseHandle(process.hThread); + int fno = _open_osfhandle((intptr_t)in, _O_RDONLY); + CloseHandle(out); + inf = _fdopen(fno, "r"); + } + } +#elif defined (HAVE_POPEN) FILE * inf = ::popen(cmd.c_str(), os::popen_read_mode()); #elif defined (HAVE__POPEN) FILE * inf = ::_popen(cmd.c_str(), os::popen_read_mode()); @@ -768,7 +1078,7 @@ cmd_ret const runCommand(string const & cmd) #error No popen() function. #endif - // (Claus Hentschel) Check if popen was succesful ;-) + // (Claus Hentschel) Check if popen was successful ;-) if (!inf) { lyxerr << "RunCommand:: could not start child process" << endl; return make_pair(-1, string()); @@ -781,7 +1091,13 @@ cmd_ret const runCommand(string const & cmd) c = fgetc(inf); } -#if defined (HAVE_PCLOSE) +#if defined (_WIN32) + WaitForSingleObject(process.hProcess, INFINITE); + if (!infile.empty()) + CloseHandle(startup.hStdInput); + CloseHandle(process.hProcess); + int const pret = fclose(inf); +#elif defined (HAVE_PCLOSE) int const pret = pclose(inf); #elif defined (HAVE__PCLOSE) int const pret = _pclose(inf); @@ -846,59 +1162,6 @@ FileName const findtexfile(string const & fil, string const & /*format*/) } -void readBB_lyxerrMessage(FileName const & file, bool & zipped, - string const & message) -{ - LYXERR(Debug::GRAPHICS, "[readBB_from_PSFile] " << message); - // FIXME: Why is this func deleting a file? (Lgb) - if (zipped) - file.removeFile(); -} - - -string const readBB_from_PSFile(FileName const & file) -{ - // in a (e)ps-file it's an entry like %%BoundingBox:23 45 321 345 - // It seems that every command in the header has an own line, - // getline() should work for all files. - // On the other hand some plot programs write the bb at the - // end of the file. Than we have in the header: - // %%BoundingBox: (atend) - // In this case we must check the end. - bool zipped = file.isZippedFile(); - FileName const file_ = zipped ? unzipFile(file) : file; - string const format = file_.guessFormatFromContents(); - - if (format != "eps" && format != "ps") { - readBB_lyxerrMessage(file_, zipped,"no(e)ps-format"); - return string(); - } - - static boost::regex bbox_re( - "^%%BoundingBox:\\s*([[:digit:]]+)\\s+([[:digit:]]+)\\s+([[:digit:]]+)\\s+([[:digit:]]+)"); - ifstream is(file_.toFilesystemEncoding().c_str()); - while (is) { - string s; - getline(is,s); - boost::smatch what; - if (regex_match(s, what, bbox_re)) { - // Our callers expect the tokens in the string - // separated by single spaces. - // FIXME: change return type from string to something - // sensible - ostringstream os; - os << what.str(1) << ' ' << what.str(2) << ' ' - << what.str(3) << ' ' << what.str(4); - string const bb = os.str(); - readBB_lyxerrMessage(file_, zipped, bb); - return bb; - } - } - readBB_lyxerrMessage(file_, zipped, "no bb found"); - return string(); -} - - int compare_timestamps(FileName const & file1, FileName const & file2) { // If the original is newer than the copy, then copy the original @@ -920,5 +1183,79 @@ int compare_timestamps(FileName const & file1, FileName const & file2) } +bool prefs2prefs(FileName const & filename, FileName const & tempfile, bool lfuns) +{ + FileName const script = libFileSearch("scripts", "prefs2prefs.py"); + if (script.empty()) { + LYXERR0("Could not find bind file conversion " + "script prefs2prefs.py."); + return false; + } + + ostringstream command; + command << os::python() << ' ' << quoteName(script.toFilesystemEncoding()) + << ' ' << (lfuns ? "-l" : "-p") << ' ' + << quoteName(filename.toFilesystemEncoding()) + << ' ' << quoteName(tempfile.toFilesystemEncoding()); + string const command_str = command.str(); + + LYXERR(Debug::FILES, "Running `" << command_str << '\''); + + cmd_ret const ret = runCommand(command_str); + if (ret.first != 0) { + LYXERR0("Could not run file conversion script prefs2prefs.py."); + return false; + } + return true; +} + + +bool configFileNeedsUpdate(string const & file) +{ + // We cannot initialize configure_script directly because the package + // is not initialized yet when static objects are constructed. + static FileName configure_script; + static bool firstrun = true; + if (firstrun) { + configure_script = + FileName(addName(package().system_support().absFileName(), + "configure.py")); + firstrun = false; + } + + FileName absfile = + FileName(addName(package().user_support().absFileName(), file)); + return !absfile.exists() + || configure_script.lastModified() > absfile.lastModified(); +} + + +int fileLock(const char * lock_file) +{ + int fd = -1; +#if defined(HAVE_LOCKF) + fd = open(lock_file, O_CREAT|O_APPEND|O_SYNC|O_RDWR, 0666); + if (fd == -1) + return -1; + if (lockf(fd, F_LOCK, 0) != 0) { + close(fd); + return -1; + } +#endif + return fd; +} + + +void fileUnlock(int fd, const char * /* lock_file*/) +{ +#if defined(HAVE_LOCKF) + if (fd >= 0) { + if (lockf(fd, F_ULOCK, 0)) + LYXERR0("Can't unlock the file."); + close(fd); + } +#endif +} + } //namespace support } // namespace lyx