/* * mooutils-win32.c * * Copyright (C) 2004-2007 by Yevgen Muntyan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation. * * See COPYING file that comes with this distribution. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "mooutils/mooutils-misc.h" #include "mooutils/mooutils-fs.h" #include "mooutils/moowin32/mingw/fnmatch.h" #include "mooutils/moowin32/mingw/sys/mman.h" #include #include #include #include #include #include #include static char *libmoo_dll_name; BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved); BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, G_GNUC_UNUSED LPVOID lpvReserved) { char *name = NULL; wchar_t buf[MAX_PATH+1]; switch (fdwReason) { case DLL_PROCESS_ATTACH: if (GetModuleFileNameW ((HMODULE) hinstDLL, buf, G_N_ELEMENTS (buf))) name = g_utf16_to_utf8 (buf, -1, NULL, NULL, NULL); if (name) libmoo_dll_name = g_path_get_basename (name); if (!libmoo_dll_name) libmoo_dll_name = g_strdup ("libmoo.dll"); g_free (name); break; } return TRUE; } #ifdef _MSC_VER /* This is stuff from newer Microsoft C runtime, but we want msvcrt.dll * which doesn't have these functions */ long _ftol( double ); long _ftol2( double dblSource ) { return _ftol( dblSource ); } long _ftol2_sse( double dblSource ) { return _ftol( dblSource ); } #endif const char * _moo_win32_get_locale_dir (void) { G_LOCK_DEFINE_STATIC (moo_locale_dir); static char *moo_locale_dir = NULL; G_LOCK (moo_locale_dir); if (!moo_locale_dir) { char *tmp; tmp = g_win32_get_package_installation_subdirectory (NULL, libmoo_dll_name, "lib\\locale"); moo_locale_dir = g_win32_locale_filename_from_utf8 (tmp); g_free (tmp); } G_UNLOCK (moo_locale_dir); return moo_locale_dir; } static void add_win32_data_dirs_for_dll (GPtrArray *list, const char *subdir_name, const char *dllname) { char *dlldir, *datadir; dlldir = moo_win32_get_dll_dir (dllname); if (g_str_has_suffix (dlldir, "\\")) { char *tmp = g_strndup (dlldir, strlen(dlldir) - 1); g_free (dlldir); dlldir = tmp; } if (g_str_has_suffix (dlldir, "bin") || g_str_has_suffix (dlldir, "lib")) { char *tmp = g_path_get_dirname (dlldir); datadir = g_build_filename (tmp, subdir_name, NULL); g_free (tmp); } else { datadir = g_strdup (dlldir); } g_free (dlldir); g_ptr_array_add (list, datadir); } void _moo_win32_add_data_dirs (GPtrArray *list, const char *prefix) { char *subdir; subdir = g_strdup_printf ("%s\\" MOO_PACKAGE_NAME, prefix); add_win32_data_dirs_for_dll (list, subdir, NULL); add_win32_data_dirs_for_dll (list, subdir, libmoo_dll_name); g_free (subdir); } char * moo_win32_get_app_dir (void) { static char *moo_app_dir; G_LOCK_DEFINE_STATIC(moo_app_dir); G_LOCK (moo_app_dir); if (!moo_app_dir) moo_app_dir = moo_win32_get_dll_dir (NULL); G_UNLOCK (moo_app_dir); return g_strdup (moo_app_dir); } char * moo_win32_get_dll_dir (const char *dll) { wchar_t *dll_utf16 = NULL; char *dir; char *dllname = NULL; HMODULE handle; wchar_t buf[MAX_PATH+1]; if (dll) { GError *error = NULL; dll_utf16 = g_utf8_to_utf16 (dll, -1, NULL, NULL, &error); if (!dll_utf16) { g_critical ("could not convert name '%s' to UTF16: %s", dll, error ? error->message : ""); g_error_free (error); return g_strdup ("."); } } handle = GetModuleHandleW (dll_utf16); g_return_val_if_fail (handle != NULL, g_strdup (".")); if (GetModuleFileNameW (handle, buf, G_N_ELEMENTS (buf)) > 0) dllname = g_utf16_to_utf8 (buf, -1, NULL, NULL, NULL); if (dllname) dir = g_path_get_dirname (dllname); else dir = g_strdup ("."); g_free (dllname); g_free (dll_utf16); return dir; } gboolean _moo_win32_open_uri (const char *uri) { HINSTANCE h; g_return_val_if_fail (uri != NULL, FALSE); h = ShellExecuteA (NULL, "open", uri, NULL, NULL, SW_SHOWNORMAL); if ((int)h <= 32) { char *msg = g_win32_error_message (GetLastError()); g_warning ("%s: %s", G_STRLOC, msg); g_free (msg); return FALSE; } return TRUE; } void _moo_win32_show_fatal_error (const char *domain, const char *logmsg) { char *msg = NULL; #define PLEASE_REPORT \ "Please report it to " PACKAGE_BUGREPORT " and provide "\ "steps needed to reproduce this error." if (domain) msg = g_strdup_printf ("Fatal " PACKAGE " error:\n---\n%s: %s\n---\n" PLEASE_REPORT, domain, logmsg); else msg = g_strdup_printf ("Fatal " PACKAGE " error:\n---\n%s\n---\n" PLEASE_REPORT, logmsg); #undef PLEASE_REPORT MessageBoxA (NULL, msg, "Error", MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND); g_free (msg); } char ** _moo_win32_lame_parse_cmd_line (const char *cmd_line, GError **error) { char **argv; char *filename; if (!g_shell_parse_argv (cmd_line, NULL, &argv, error)) return NULL; if (!(filename = g_find_program_in_path (argv[0]))) { guint len = g_strv_length (argv); argv = g_renew (char*, argv, len + 3); memmove (argv + 2, argv, (len + 1) * sizeof (*argv)); argv[0] = g_strdup ("cmd.exe"); argv[1] = g_strdup ("/c"); } g_free (filename); return argv; } #ifndef HAVE_GETTIMEOFDAY #include int _moo_win32_gettimeofday (struct timeval *tp, G_GNUC_UNUSED gpointer tzp) { time_t sec; if (tp == NULL || tzp != NULL) { errno = EINVAL; return -1; } sec = time (NULL); if (sec == (time_t) -1) return -1; tp->tv_sec = sec; tp->tv_usec = 0; return 0; } #endif /* !HAVE_GETTIMEOFDAY */ int _moo_win32_fnmatch (const char *pattern, const char *string, int flags) { if (flags != 0) { errno = EINVAL; return -1; } return _moo_glob_match_simple (pattern, string) ? 0 : 1; } #ifdef MOO_ENABLE_UNIT_TESTS #include static void test_parse_cmd_line_one (const char *cmd_line, const char **expected) { char **argv; GError *error = NULL; /* Anything but NULL must be treated properly, without warnings */ TEST_EXPECT_WARNING (!cmd_line, "_moo_win32_lame_parse_cmd_line(%s)", TEST_FMT_STR (cmd_line)); argv = _moo_win32_lame_parse_cmd_line (cmd_line, &error); TEST_CHECK_WARNING (); TEST_ASSERT_STRV_EQ_MSG (argv, (char**) expected, "_moo_win32_lame_parse_cmd_line(%s)", TEST_FMT_STR (cmd_line)); if (cmd_line && !expected && !argv) TEST_ASSERT_MSG (error != NULL, "_moo_win32_lame_parse_cmd_line(%s): error not set", TEST_FMT_STR (cmd_line)); if (error) g_error_free (error); g_strfreev (argv); } static void test_moo_win32_lame_parse_cmd_line (void) { guint i; struct { const char *cmd_line; const char *argv[20]; } cases[] = { { "dir foobar", { "cmd.exe", "/c", "dir", "foobar" } }, { "dir \"c:\\program files\"", { "cmd.exe", "/c", "dir", "c:\\program files" } }, /* wine doesn't have cmd.exe even though it has msiexec.exe! */ { "msiexec", { "msiexec" } }, { "msiexec.exe", { "msiexec.exe" } }, }; const char *fail_cases[] = { "quote '", "quote \"", NULL, "", " " }; for (i = 0; i < G_N_ELEMENTS (cases); ++i) test_parse_cmd_line_one (cases[i].cmd_line, cases[i].argv); for (i = 0; i < G_N_ELEMENTS (fail_cases); ++i) test_parse_cmd_line_one (fail_cases[i], NULL); } void moo_test_mooutils_win32 (void) { MooTestSuite *suite; suite = moo_test_suite_new ("mooutils/mooutils-win32.c", NULL, NULL, NULL); moo_test_suite_add_test (suite, "test of _moo_win32_lame_parse_cmd_line()", (MooTestFunc) test_moo_win32_lame_parse_cmd_line, NULL); } #endif /*************************************************************************** * mmap for poor */ static GHashTable *mapped_files; #define MAPPING_ALLOCATED ((HANDLE) -2) static void add_mapped_file (gpointer buffer, HANDLE mapping) { if (!mapped_files) mapped_files = g_hash_table_new (g_direct_hash, g_direct_equal); g_hash_table_insert (mapped_files, buffer, mapping); } static gboolean remove_mapped_file (gpointer buffer) { HANDLE mapping; if (!mapped_files) return FALSE; mapping = g_hash_table_lookup (mapped_files, buffer); g_return_val_if_fail (mapping != NULL, FALSE); g_hash_table_remove (mapped_files, buffer); if (mapping == MAPPING_ALLOCATED) { g_free (buffer); } else { UnmapViewOfFile (buffer); CloseHandle (mapping); } if (g_hash_table_size (mapped_files) == 0) { g_hash_table_destroy (mapped_files); mapped_files = NULL; } return TRUE; } void * _moo_win32_mmap (gpointer start, guint64 length, int prot, int flags, int fd, guint64 offset) { struct stat st; HANDLE mapping; char *buffer; g_return_val_if_fail (start == NULL, NULL); g_return_val_if_fail (prot == PROT_READ, NULL); g_return_val_if_fail (flags == MAP_SHARED, NULL); g_return_val_if_fail (offset == 0, NULL); errno = 0; if (fstat (fd, &st) != 0) return MAP_FAILED; if ((guint64) st.st_size != length) { errno = EINVAL; return MAP_FAILED; } if (length == 0) { buffer = g_new (char, 1); buffer[0] = 0; add_mapped_file (buffer, MAPPING_ALLOCATED); return buffer; } mapping = CreateFileMapping ((HANDLE) _get_osfhandle (fd), NULL, PAGE_READONLY, 0, 0, NULL); if (!mapping) { errno = EINVAL; return MAP_FAILED; } buffer = MapViewOfFile (mapping, FILE_MAP_READ, 0, 0, 0); if (!buffer) { CloseHandle (mapping); errno = EINVAL; return MAP_FAILED; } add_mapped_file (buffer, mapping); return buffer; } int _moo_win32_munmap (gpointer start, G_GNUC_UNUSED gsize length) { if (!remove_mapped_file (start)) { errno = EINVAL; return -1; } else { return 0; } }