diff --git a/development/Win32/packaging/installer/lyx_configure.C b/development/Win32/packaging/installer/lyx_configure.C index 7057bf4dc7..b98ac6e864 100644 --- a/development/Win32/packaging/installer/lyx_configure.C +++ b/development/Win32/packaging/installer/lyx_configure.C @@ -9,11 +9,16 @@ * Full author contact details are available in file CREDITS or copy at * http://www.lyx.org/about/credits.php * - * This little piece of code is used to insert some code into LyX's - * Resources/lyx/configure script so that it will cause lyxrc.defaults to - * contain + * Define four functions that can be called from the NSIS installer: * - * \path_prefix ";;..." + * set_path_prefix [ configure_file, path_prefix ] + * create_bat_files [ bin_dir, lang ] + * run_configure [ configure_file, path_prefix ] + * set_env [ var_name, var_value ] + * + * The quantities in [ ... ] are the variables that the functions exxpect + * to find on the stack. They push "-1" onto the stack on failure and "0" + * onto the stack on success. * * Compile the code with * @@ -23,16 +28,18 @@ * Move resulting .dll to /c/Program\ Files/NSIS/Plugins */ -#include -#include "ExDLL/exdll.h" -#include -#include +#include +#include #include #include #include #include #include +#include +#include "ExDLL/exdll.h" + + namespace { std::string const subst(std::string const & a, @@ -53,18 +60,18 @@ std::string const subst(std::string const & a, std::string const basename(std::string const & path) { std::string::size_type const final_slash = path.find_last_of('\\'); - if (final_slash == std::string::npos) - return path; - return path.substr(final_slash+1); + return (final_slash == std::string::npos) ? + path : + path.substr(final_slash+1); } std::string const dirname(std::string const & path) { std::string::size_type const final_slash = path.find_last_of('\\'); - if (final_slash == std::string::npos) - return std::string(); - return path.substr(0, final_slash); + return (final_slash == std::string::npos) ? + std::string() : + path.substr(0, final_slash); } @@ -76,6 +83,14 @@ std::string const pop_from_stack() } +void push_to_stack(int data) +{ + std::ostringstream os; + os << data; + pushstring(os.str().c_str()); +} + + std::list const tokenize(std::string data, char const separator) { @@ -192,29 +207,15 @@ bool insert_path_prefix(std::string & data, return true; } -} // namespace anon - - -BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved) -{ - return TRUE; -} - // Inserts code into "configure" to output "path_prefix" to lyxrc.defaults. -extern "C" -void __declspec(dllexport) set_path_prefix(HWND hwndParent, int string_size, char *variables, stack_t **stacktop) +// \returns 0 on success, -1 on failure +int set_path_prefix(std::string const & configure_file, + std::string const & path_prefix) { - EXDLL_INIT(); - - std::string const configure_file = pop_from_stack(); - std::string const path_prefix = pop_from_stack(); - std::ifstream ifs(configure_file.c_str()); - if (!ifs) { - pushstring("-1"); - return; - } + if (!ifs) + return -1; std::istreambuf_iterator const begin_ifs(ifs); std::istreambuf_iterator const end_ifs; @@ -226,137 +227,184 @@ void __declspec(dllexport) set_path_prefix(HWND hwndParent, int string_size, cha std::string::size_type const prefix_pos = configure_data.find("path_prefix"); if (prefix_pos != std::string::npos) { - if (!replace_path_prefix(configure_data, prefix_pos, path_prefix)) { - pushstring("-1"); - return; - } + if (!replace_path_prefix(configure_data, prefix_pos, path_prefix)) + return -1; } else { std::string::size_type const xfonts_pos = configure_data.find("X FONTS"); - if (xfonts_pos == std::string::npos) { - pushstring("-1"); - return; - } + if (xfonts_pos == std::string::npos) + return -1; - if (!insert_path_prefix(configure_data, xfonts_pos, path_prefix)) { - pushstring("-1"); - return; - } + if (!insert_path_prefix(configure_data, xfonts_pos, path_prefix)) + return -1; } std::ofstream ofs(configure_file.c_str()); - if (!ofs) { - pushstring("-1"); - return; - } + if (!ofs) + return -1; ofs << configure_data; - pushstring("0"); + return 0; +} + + +bool write_bat(std::ostream & os, std::string const & quoted_exe) +{ + os << "if \"%~1\" == \"~1\" got win95\n" + << quoted_exe << " %~*\n" + << "goto end\n" + << ":win95\n" + << quoted_exe << " %1 %2 %3 %4 %5 %6 %7 %8 %9\n" + << ":end\n"; + + return os; +} + + +// Creates the files lyx.bat and reLyX.bat in the LyX\bin folder. +// \returns 0 on success, -1 on failure +int create_bat_files(std::string const & bin_dir, std::string const & lang) +{ + std::string const lyx_bat_file = bin_dir + "\\lyx.bat"; + std::ofstream lyx_bat(lyx_bat_file.c_str()); + if (!lyx_bat) + return -1; + + lyx_bat << "@echo off\n" + << "if \"%LANG%\"==\"\" SET LANG=" << lang << "\n"; + + std::string const lyx_exe_file = bin_dir + "\\lyx.exe"; + if (!write_bat(lyx_bat, "\"" + lyx_exe_file + "\"")) + return -1; + + std::string const relyx_bat_file = bin_dir + "\\reLyX.bat"; + std::ofstream relyx_bat(relyx_bat_file.c_str()); + if (!relyx_bat) + return -1; + + std::string relyx_file = bin_dir + "\\reLyX"; + std::string relyx = "perl.exe \"" + relyx_file + "\""; + if (!write_bat(relyx_bat, "perl.exe \"" + relyx_file + "\"")) + return -1; + return 0; +} + + +// Runs "sh configure" to generate things like lyxrc.defaults. +// \returns 0 on success, -1 on failure +int run_configure(std::string const & abs_configure_file, + std::string const & path_prefix) +{ + std::string const configure_dir = dirname(abs_configure_file); + std::string const configure_file = basename(abs_configure_file); + + if (configure_dir.empty()) + return -1; + + if (SetCurrentDirectory(configure_dir.c_str()) == 0) + return -1; + + char path_orig[10*MAX_PATH]; + if (GetEnvironmentVariable("PATH", path_orig, 10*MAX_PATH) == 0) + return -1; + + std::string const path = path_prefix + ';' + path_orig; + if (SetEnvironmentVariable("PATH", path.c_str()) == 0) + return -1; + + // Even "start /WAIT /B sh.exe configure" returns + // before the script is done, so just invoke "sh" directly. + std::string const command = std::string("sh.exe ") + configure_file; + if (system(command.c_str()) != 0) + return -1; + return 0; +} + +} // namespace anon + + +//===========================================// +// // +// Below is the public interface to the .dll // +// // +//===========================================// + +BOOL WINAPI DllMain(HANDLE hInst, + ULONG ul_reason_for_call, + LPVOID lpReserved) +{ + return TRUE; +} + + +// Inserts code into "configure" to output "path_prefix" to lyxrc.defaults. +extern "C" +void __declspec(dllexport) set_path_prefix(HWND hwndParent, + int string_size, + char * variables, + stack_t ** stacktop) +{ + EXDLL_INIT(); + + std::string const configure_file = pop_from_stack(); + std::string const path_prefix = pop_from_stack(); + + int const result = set_path_prefix(configure_file, path_prefix); + push_to_stack(result); } // Creates the files lyx.bat and reLyX.bat in the LyX\bin folder. extern "C" -void __declspec(dllexport) create_bat_files(HWND hwndParent, int string_size, char *variables, stack_t **stacktop) +void __declspec(dllexport) create_bat_files(HWND hwndParent, + int string_size, + char * variables, + stack_t ** stacktop) { EXDLL_INIT(); std::string const bin_dir = pop_from_stack(); std::string const lang = pop_from_stack(); - std::string const lyx_bat_file = bin_dir + "\\lyx.bat"; - std::ofstream lyx_bat(lyx_bat_file.c_str()); - if (!lyx_bat) { - pushstring("-1"); - return; - } - std::string const lyx_exe_file = bin_dir + "\\lyx.exe"; - lyx_bat << "@echo off\n" - << "if \"%LANG%\"==\"\" SET LANG=" << lang << "\n" - << "\"" << lyx_exe_file << "\" %~1 %~2 %~3 %~4 %~5 %~6 %~7 %~8 %~9\n"; - if (!lyx_bat) { - pushstring("-1"); - return; - } - - std::string const relyx_bat_file = bin_dir + "\\reLyX.bat"; - std::ofstream relyx_bat(relyx_bat_file.c_str()); - if (!relyx_bat) { - pushstring("-1"); - return; - } - - std::string const relyx_file = bin_dir + "\\reLyX"; - relyx_bat << "@echo off\r\n" - << "perl.exe \"" << relyx_file << "\" %~1 %~2 %~3 %~4 %~5 %~6 %~7 %~8 %~9\r\n"; - - if (!relyx_bat) { - pushstring("-1"); - return; - } - - pushstring("0"); + int const result = create_bat_files(bin_dir, lang); + push_to_stack(result); } // Runs "sh configure" to generate things like lyxrc.defaults. extern "C" -void __declspec(dllexport) run_configure(HWND hwndParent, int string_size, char *variables, stack_t **stacktop) +void __declspec(dllexport) run_configure(HWND hwndParent, + int string_size, + char * variables, + stack_t ** stacktop) { EXDLL_INIT(); - std::string configure_file = pop_from_stack(); + std::string const configure_file = pop_from_stack(); std::string const path_prefix = pop_from_stack(); - std::string const configure_dir = dirname(configure_file); - configure_file = basename(configure_file); - - if (configure_dir.empty()) { - pushstring("-1"); - return; - } - - if (SetCurrentDirectory(configure_dir.c_str()) == 0) { - pushstring("-1"); - return; - } - - char path_orig[10*MAX_PATH]; - if (GetEnvironmentVariable("PATH", path_orig, 10*MAX_PATH) == 0) { - pushstring("-1"); - return; - } - - std::string const path = path_prefix + ';' + path_orig; - if (SetEnvironmentVariable("PATH", path.c_str()) == 0) { - pushstring("-1"); - return; - } - - // Even "start /WAIT /B sh.exe configure" returns - // before the script is done, so just invoke "sh" directly. - std::string const command = std::string("sh.exe ") + configure_file; - if (system(command.c_str()) != 0) { - pushstring("-1"); - return; - } - - pushstring("0"); + int const result = run_configure(configure_file, path_prefix); + push_to_stack(result); } // Set an environment variable extern "C" -void __declspec(dllexport) set_env(HWND hwndParent, int string_size, - char *variables, stack_t **stacktop) +void __declspec(dllexport) set_env(HWND hwndParent, + int string_size, + char * variables, + stack_t ** stacktop) { EXDLL_INIT(); std::string const var_name = pop_from_stack(); std::string const var_value = pop_from_stack(); - SetEnvironmentVariableA(var_name.c_str(), var_value.c_str()); + // Function returns a nonzero value on success. + int const result = + SetEnvironmentVariableA(var_name.c_str(), var_value.c_str()) ? + 0 : -1; - pushstring("0"); + push_to_stack(result); }