X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=glib%2Fgwin32.c;h=3c60df4c9d92412c24475b2ca9a07c1eaf3abca5;hb=7e3d32b7053b47ca7feecf185abac96b619770c2;hp=90cddc415e7a6eca29557106d2fc416f0efc1db5;hpb=8e847255e8c396a5bacbbf2897ad78e36ee47900;p=platform%2Fupstream%2Fglib.git diff --git a/glib/gwin32.c b/glib/gwin32.c index 90cddc4..3c60df4 100644 --- a/glib/gwin32.c +++ b/glib/gwin32.c @@ -13,9 +13,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library; if not, see . */ /* @@ -29,796 +27,608 @@ * MT safe for the unix part, FIXME: make the win32 part MT safe as well. */ -#ifdef HAVE_CONFIG_H -#include -#endif +#include "config.h" #include "glibconfig.h" #include #include #include +#include #include #define STRICT /* Strict typing, please */ #include +#undef STRICT +#ifndef G_WITH_CYGWIN #include +#endif #include #include -#ifdef _MSC_VER +#if defined(_MSC_VER) || defined(__DMC__) # include -#endif /* _MSC_VER */ +#endif /* _MSC_VER || __DMC__ */ #include "glib.h" +#include "gthreadprivate.h" + +#ifdef G_WITH_CYGWIN +#include +#endif + +#ifndef G_WITH_CYGWIN -int +gint g_win32_ftruncate (gint fd, guint size) { - HANDLE hfile; - guint curpos; + return _chsize (fd, size); +} + +#endif + +/** + * g_win32_getlocale: + * + * The setlocale() function in the Microsoft C library uses locale + * names of the form "English_United States.1252" etc. We want the + * UNIXish standard form "en_US", "zh_TW" etc. This function gets the + * current thread locale from Windows - without any encoding info - + * and returns it as a string of the above form for use in forming + * file names etc. The returned string should be deallocated with + * g_free(). + * + * Returns: newly-allocated locale name. + **/ + +#ifndef SUBLANG_SERBIAN_LATIN_BA +#define SUBLANG_SERBIAN_LATIN_BA 0x06 +#endif + +gchar * +g_win32_getlocale (void) +{ + LCID lcid; + LANGID langid; + gchar *ev; + gint primary, sub; + char iso639[10]; + char iso3166[10]; + const gchar *script = NULL; + + /* Let the user override the system settings through environment + * variables, as on POSIX systems. Note that in GTK+ applications + * since GTK+ 2.10.7 setting either LC_ALL or LANG also sets the + * Win32 locale and C library locale through code in gtkmain.c. + */ + if (((ev = getenv ("LC_ALL")) != NULL && ev[0] != '\0') + || ((ev = getenv ("LC_MESSAGES")) != NULL && ev[0] != '\0') + || ((ev = getenv ("LANG")) != NULL && ev[0] != '\0')) + return g_strdup (ev); - g_return_val_if_fail (fd >= 0, -1); + lcid = GetThreadLocale (); + + if (!GetLocaleInfo (lcid, LOCALE_SISO639LANGNAME, iso639, sizeof (iso639)) || + !GetLocaleInfo (lcid, LOCALE_SISO3166CTRYNAME, iso3166, sizeof (iso3166))) + return g_strdup ("C"); - hfile = (HANDLE) _get_osfhandle (fd); - curpos = SetFilePointer (hfile, 0, NULL, FILE_CURRENT); - if (curpos == 0xFFFFFFFF - || SetFilePointer (hfile, size, NULL, FILE_BEGIN) == 0xFFFFFFFF - || !SetEndOfFile (hfile)) - { - gint error = GetLastError (); + /* Strip off the sorting rules, keep only the language part. */ + langid = LANGIDFROMLCID (lcid); - switch (error) + /* Split into language and territory part. */ + primary = PRIMARYLANGID (langid); + sub = SUBLANGID (langid); + + /* Handle special cases */ + switch (primary) + { + case LANG_AZERI: + switch (sub) + { + case SUBLANG_AZERI_LATIN: + script = "@Latn"; + break; + case SUBLANG_AZERI_CYRILLIC: + script = "@Cyrl"; + break; + } + break; + case LANG_SERBIAN: /* LANG_CROATIAN == LANG_SERBIAN */ + switch (sub) { - case ERROR_INVALID_HANDLE: - errno = EBADF; + case SUBLANG_SERBIAN_LATIN: + case 0x06: /* Serbian (Latin) - Bosnia and Herzegovina */ + script = "@Latn"; break; - default: - errno = EIO; + } + break; + case LANG_UZBEK: + switch (sub) + { + case SUBLANG_UZBEK_LATIN: + script = "@Latn"; + break; + case SUBLANG_UZBEK_CYRILLIC: + script = "@Cyrl"; break; } + break; + } + return g_strconcat (iso639, "_", iso3166, script, NULL); +} - return -1; +/** + * g_win32_error_message: + * @error: error code. + * + * Translate a Win32 error code (as returned by GetLastError() or + * WSAGetLastError()) into the corresponding message. The message is + * either language neutral, or in the thread's language, or the user's + * language, the system's language, or US English (see docs for + * FormatMessage()). The returned string is in UTF-8. It should be + * deallocated with g_free(). + * + * Returns: newly-allocated error message + **/ +gchar * +g_win32_error_message (gint error) +{ + gchar *retval; + wchar_t *msg = NULL; + int nchars; + + FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER + |FORMAT_MESSAGE_IGNORE_INSERTS + |FORMAT_MESSAGE_FROM_SYSTEM, + NULL, error, 0, + (LPWSTR) &msg, 0, NULL); + if (msg != NULL) + { + nchars = wcslen (msg); + + if (nchars > 2 && msg[nchars-1] == '\n' && msg[nchars-2] == '\r') + msg[nchars-2] = '\0'; + + retval = g_utf16_to_utf8 (msg, -1, NULL, NULL, NULL); + + LocalFree (msg); } + else + retval = g_strdup (""); + + return retval; +} + +/** + * g_win32_get_package_installation_directory_of_module: + * @hmodule: (allow-none): The Win32 handle for a DLL loaded into the current process, or %NULL + * + * This function tries to determine the installation directory of a + * software package based on the location of a DLL of the software + * package. + * + * @hmodule should be the handle of a loaded DLL or %NULL. The + * function looks up the directory that DLL was loaded from. If + * @hmodule is NULL, the directory the main executable of the current + * process is looked up. If that directory's last component is "bin" + * or "lib", its parent directory is returned, otherwise the directory + * itself. + * + * It thus makes sense to pass only the handle to a "public" DLL of a + * software package to this function, as such DLLs typically are known + * to be installed in a "bin" or occasionally "lib" subfolder of the + * installation folder. DLLs that are of the dynamically loaded module + * or plugin variety are often located in more private locations + * deeper down in the tree, from which it is impossible for GLib to + * deduce the root of the package installation. + * + * The typical use case for this function is to have a DllMain() that + * saves the handle for the DLL. Then when code in the DLL needs to + * construct names of files in the installation tree it calls this + * function passing the DLL handle. + * + * Returns: a string containing the guessed installation directory for + * the software package @hmodule is from. The string is in the GLib + * file name encoding, i.e. UTF-8. The return value should be freed + * with g_free() when not needed any longer. If the function fails + * %NULL is returned. + * + * Since: 2.16 + */ +gchar * +g_win32_get_package_installation_directory_of_module (gpointer hmodule) +{ + gchar *retval; + gchar *p; + wchar_t wc_fn[MAX_PATH]; + + if (!GetModuleFileNameW (hmodule, wc_fn, MAX_PATH)) + return NULL; + + retval = g_utf16_to_utf8 (wc_fn, -1, NULL, NULL, NULL); + + if ((p = strrchr (retval, G_DIR_SEPARATOR)) != NULL) + *p = '\0'; + + p = strrchr (retval, G_DIR_SEPARATOR); + if (p && (g_ascii_strcasecmp (p + 1, "bin") == 0 || + g_ascii_strcasecmp (p + 1, "lib") == 0)) + *p = '\0'; + +#ifdef G_WITH_CYGWIN + /* In Cygwin we need to have POSIX paths */ + { + gchar tmp[MAX_PATH]; + + cygwin_conv_to_posix_path (retval, tmp); + g_free (retval); + retval = g_strdup (tmp); + } +#endif - return 0; + return retval; } -DIR* -g_win32_opendir (const char *dirname) +static gchar * +get_package_directory_from_module (const gchar *module_name) { - DIR *result; - gchar *mask; - guint k; + static GHashTable *module_dirs = NULL; + G_LOCK_DEFINE_STATIC (module_dirs); + HMODULE hmodule = NULL; + gchar *fn; - g_return_val_if_fail (dirname != NULL, NULL); + G_LOCK (module_dirs); - result = g_new0 (DIR, 1); - result->find_file_data = g_new0 (WIN32_FIND_DATA, 1); - result->dir_name = g_strdup (dirname); + if (module_dirs == NULL) + module_dirs = g_hash_table_new (g_str_hash, g_str_equal); - k = strlen (result->dir_name); - if (k && result->dir_name[k - 1] == '\\') + fn = g_hash_table_lookup (module_dirs, module_name ? module_name : ""); + + if (fn) { - result->dir_name[k - 1] = '\0'; + G_UNLOCK (module_dirs); + return g_strdup (fn); } - mask = g_strdup_printf ("%s\\*", result->dir_name); - - result->find_file_handle = (guint) FindFirstFile (mask, - (LPWIN32_FIND_DATA) result->find_file_data); - g_free (mask); - if (result->find_file_handle == (guint) INVALID_HANDLE_VALUE) + if (module_name) { - int error = GetLastError (); + wchar_t *wc_module_name = g_utf8_to_utf16 (module_name, -1, NULL, NULL, NULL); + hmodule = GetModuleHandleW (wc_module_name); + g_free (wc_module_name); - g_free (result->dir_name); - g_free (result->find_file_data); - g_free (result); - switch (error) + if (!hmodule) { - default: - errno = EIO; + G_UNLOCK (module_dirs); return NULL; } } - result->just_opened = TRUE; + + fn = g_win32_get_package_installation_directory_of_module (hmodule); + + if (fn == NULL) + { + G_UNLOCK (module_dirs); + return NULL; + } + + g_hash_table_insert (module_dirs, module_name ? g_strdup (module_name) : "", fn); + + G_UNLOCK (module_dirs); + + return g_strdup (fn); +} + +/** + * g_win32_get_package_installation_directory: + * @package: (allow-none): You should pass %NULL for this. + * @dll_name: (allow-none): The name of a DLL that a package provides in UTF-8, or %NULL. + * + * Try to determine the installation directory for a software package. + * + * This function is deprecated. Use + * g_win32_get_package_installation_directory_of_module() instead. + * + * The use of @package is deprecated. You should always pass %NULL. A + * warning is printed if non-NULL is passed as @package. + * + * The original intended use of @package was for a short identifier of + * the package, typically the same identifier as used for + * `GETTEXT_PACKAGE` in software configured using GNU + * autotools. The function first looks in the Windows Registry for the + * value `#InstallationDirectory` in the key + * `#HKLM\Software\@package`, and if that value + * exists and is a string, returns that. + * + * It is strongly recommended that packagers of GLib-using libraries + * for Windows do not store installation paths in the Registry to be + * used by this function as that interfers with having several + * parallel installations of the library. Enabling multiple + * installations of different versions of some GLib-using library, or + * GLib itself, is desirable for various reasons. + * + * For this reason it is recommeded to always pass %NULL as + * @package to this function, to avoid the temptation to use the + * Registry. In version 2.20 of GLib the @package parameter + * will be ignored and this function won't look in the Registry at all. + * + * If @package is %NULL, or the above value isn't found in the + * Registry, but @dll_name is non-%NULL, it should name a DLL loaded + * into the current process. Typically that would be the name of the + * DLL calling this function, looking for its installation + * directory. The function then asks Windows what directory that DLL + * was loaded from. If that directory's last component is "bin" or + * "lib", the parent directory is returned, otherwise the directory + * itself. If that DLL isn't loaded, the function proceeds as if + * @dll_name was %NULL. + * + * If both @package and @dll_name are %NULL, the directory from where + * the main executable of the process was loaded is used instead in + * the same way as above. + * + * Returns: a string containing the installation directory for + * @package. The string is in the GLib file name encoding, + * i.e. UTF-8. The return value should be freed with g_free() when not + * needed any longer. If the function fails %NULL is returned. + * + * Deprecated: 2.18: Pass the HMODULE of a DLL or EXE to + * g_win32_get_package_installation_directory_of_module() instead. + **/ + + gchar * +g_win32_get_package_installation_directory_utf8 (const gchar *package, + const gchar *dll_name) +{ + gchar *result = NULL; + + if (package != NULL) + g_warning ("Passing a non-NULL package to g_win32_get_package_installation_directory() is deprecated and it is ignored."); + + if (dll_name != NULL) + result = get_package_directory_from_module (dll_name); + + if (result == NULL) + result = get_package_directory_from_module (NULL); return result; } -struct dirent* -g_win32_readdir (DIR *dir) +#if !defined (_WIN64) + +/* DLL ABI binary compatibility version that uses system codepage file names */ + +gchar * +g_win32_get_package_installation_directory (const gchar *package, + const gchar *dll_name) { - gchar *basename; + gchar *utf8_package = NULL, *utf8_dll_name = NULL; + gchar *utf8_retval, *retval; - g_return_val_if_fail (dir != NULL, NULL); + if (package != NULL) + utf8_package = g_locale_to_utf8 (package, -1, NULL, NULL, NULL); - if (dir->just_opened) - dir->just_opened = FALSE; - else - { - if (!FindNextFile ((HANDLE) dir->find_file_handle, - (LPWIN32_FIND_DATA) dir->find_file_data)) - { - int error = GetLastError (); + if (dll_name != NULL) + utf8_dll_name = g_locale_to_utf8 (dll_name, -1, NULL, NULL, NULL); - switch (error) - { - case ERROR_NO_MORE_FILES: - return NULL; - default: - errno = EIO; - return NULL; - } - } - } - - basename = g_path_get_basename (((LPWIN32_FIND_DATA) dir->find_file_data)->cFileName); + utf8_retval = + g_win32_get_package_installation_directory_utf8 (utf8_package, + utf8_dll_name); - strcpy (dir->readdir_result.d_name, basename); + retval = g_locale_from_utf8 (utf8_retval, -1, NULL, NULL, NULL); - g_free (basename); - - return &dir->readdir_result; + g_free (utf8_package); + g_free (utf8_dll_name); + g_free (utf8_retval); + + return retval; } -void -g_win32_rewinddir (DIR *dir) +#endif + +/** + * g_win32_get_package_installation_subdirectory: + * @package: (allow-none): You should pass %NULL for this. + * @dll_name: (allow-none): The name of a DLL that a package provides, in UTF-8, or %NULL. + * @subdir: A subdirectory of the package installation directory, also in UTF-8 + * + * This function is deprecated. Use + * g_win32_get_package_installation_directory_of_module() and + * g_build_filename() instead. + * + * Returns a newly-allocated string containing the path of the + * subdirectory @subdir in the return value from calling + * g_win32_get_package_installation_directory() with the @package and + * @dll_name parameters. See the documentation for + * g_win32_get_package_installation_directory() for more details. In + * particular, note that it is deprecated to pass anything except NULL + * as @package. + * + * Returns: a string containing the complete path to @subdir inside + * the installation directory of @package. The returned string is in + * the GLib file name encoding, i.e. UTF-8. The return value should be + * freed with g_free() when no longer needed. If something goes wrong, + * %NULL is returned. + * + * Deprecated: 2.18: Pass the HMODULE of a DLL or EXE to + * g_win32_get_package_installation_directory_of_module() instead, and + * then construct a subdirectory pathname with g_build_filename(). + **/ + +gchar * +g_win32_get_package_installation_subdirectory_utf8 (const gchar *package, + const gchar *dll_name, + const gchar *subdir) { - gchar *mask; + gchar *prefix; + gchar *dirname; - g_return_if_fail (dir != NULL); +G_GNUC_BEGIN_IGNORE_DEPRECATIONS + prefix = g_win32_get_package_installation_directory_utf8 (package, dll_name); +G_GNUC_END_IGNORE_DEPRECATIONS - if (!FindClose ((HANDLE) dir->find_file_handle)) - g_warning ("gwin_rewinddir(): FindClose() failed\n"); + dirname = g_build_filename (prefix, subdir, NULL); + g_free (prefix); - mask = g_strdup_printf ("%s\\*", dir->dir_name); - dir->find_file_handle = (guint) FindFirstFile (mask, - (LPWIN32_FIND_DATA) dir->find_file_data); - g_free (mask); + return dirname; +} - if (dir->find_file_handle == (guint) INVALID_HANDLE_VALUE) - { - int error = GetLastError (); +#if !defined (_WIN64) - switch (error) - { - default: - errno = EIO; - return; - } - } - dir->just_opened = TRUE; -} +/* DLL ABI binary compatibility version that uses system codepage file names */ -gint -g_win32_closedir (DIR *dir) +gchar * +g_win32_get_package_installation_subdirectory (const gchar *package, + const gchar *dll_name, + const gchar *subdir) { - g_return_val_if_fail (dir != NULL, -1); - - if (!FindClose ((HANDLE) dir->find_file_handle)) - { - int error = GetLastError (); + gchar *prefix; + gchar *dirname; - switch (error) - { - default: - errno = EIO; return -1; - } - } + G_GNUC_BEGIN_IGNORE_DEPRECATIONS + prefix = g_win32_get_package_installation_directory (package, dll_name); + G_GNUC_END_IGNORE_DEPRECATIONS - g_free (dir->dir_name); - g_free (dir->find_file_data); - g_free (dir); + dirname = g_build_filename (prefix, subdir, NULL); + g_free (prefix); - return 0; + return dirname; } -/* Mingw32 headers don't have latest language and sublanguage codes */ -#ifndef LANG_AFRIKAANS -#define LANG_AFRIKAANS 0x36 -#endif -#ifndef LANG_ALBANIAN -#define LANG_ALBANIAN 0x1c -#endif -#ifndef LANG_ARABIC -#define LANG_ARABIC 0x01 -#endif -#ifndef LANG_ARMENIAN -#define LANG_ARMENIAN 0x2b -#endif -#ifndef LANG_ASSAMESE -#define LANG_ASSAMESE 0x4d -#endif -#ifndef LANG_AZERI -#define LANG_AZERI 0x2c -#endif -#ifndef LANG_BASQUE -#define LANG_BASQUE 0x2d -#endif -#ifndef LANG_BELARUSIAN -#define LANG_BELARUSIAN 0x23 -#endif -#ifndef LANG_BENGALI -#define LANG_BENGALI 0x45 -#endif -#ifndef LANG_CATALAN -#define LANG_CATALAN 0x03 -#endif -#ifndef LANG_ESTONIAN -#define LANG_ESTONIAN 0x25 -#endif -#ifndef LANG_FAEROESE -#define LANG_FAEROESE 0x38 -#endif -#ifndef LANG_FARSI -#define LANG_FARSI 0x29 -#endif -#ifndef LANG_GEORGIAN -#define LANG_GEORGIAN 0x37 -#endif -#ifndef LANG_GUJARATI -#define LANG_GUJARATI 0x47 -#endif -#ifndef LANG_HEBREW -#define LANG_HEBREW 0x0d -#endif -#ifndef LANG_HINDI -#define LANG_HINDI 0x39 -#endif -#ifndef LANG_INDONESIAN -#define LANG_INDONESIAN 0x21 -#endif -#ifndef LANG_KANNADA -#define LANG_KANNADA 0x4b -#endif -#ifndef LANG_KASHMIRI -#define LANG_KASHMIRI 0x60 -#endif -#ifndef LANG_KAZAK -#define LANG_KAZAK 0x3f -#endif -#ifndef LANG_KONKANI -#define LANG_KONKANI 0x57 -#endif -#ifndef LANG_LATVIAN -#define LANG_LATVIAN 0x26 -#endif -#ifndef LANG_LITHUANIAN -#define LANG_LITHUANIAN 0x27 -#endif -#ifndef LANG_MACEDONIAN -#define LANG_MACEDONIAN 0x2f -#endif -#ifndef LANG_MALAY -#define LANG_MALAY 0x3e -#endif -#ifndef LANG_MALAYALAM -#define LANG_MALAYALAM 0x4c -#endif -#ifndef LANG_MANIPURI -#define LANG_MANIPURI 0x58 -#endif -#ifndef LANG_MARATHI -#define LANG_MARATHI 0x4e -#endif -#ifndef LANG_NEPALI -#define LANG_NEPALI 0x61 -#endif -#ifndef LANG_ORIYA -#define LANG_ORIYA 0x48 -#endif -#ifndef LANG_PUNJABI -#define LANG_PUNJABI 0x46 -#endif -#ifndef LANG_SANSKRIT -#define LANG_SANSKRIT 0x4f -#endif -#ifndef LANG_SERBIAN -#define LANG_SERBIAN 0x1a -#endif -#ifndef LANG_SINDHI -#define LANG_SINDHI 0x59 -#endif -#ifndef LANG_SLOVAK -#define LANG_SLOVAK 0x1b -#endif -#ifndef LANG_SWAHILI -#define LANG_SWAHILI 0x41 -#endif -#ifndef LANG_TAMIL -#define LANG_TAMIL 0x49 -#endif -#ifndef LANG_TATAR -#define LANG_TATAR 0x44 -#endif -#ifndef LANG_TELUGU -#define LANG_TELUGU 0x4a -#endif -#ifndef LANG_THAI -#define LANG_THAI 0x1e -#endif -#ifndef LANG_UKRAINIAN -#define LANG_UKRAINIAN 0x22 -#endif -#ifndef LANG_URDU -#define LANG_URDU 0x20 -#endif -#ifndef LANG_UZBEK -#define LANG_UZBEK 0x43 -#endif -#ifndef LANG_VIETNAMESE -#define LANG_VIETNAMESE 0x2a -#endif -#ifndef SUBLANG_ARABIC_SAUDI_ARABIA -#define SUBLANG_ARABIC_SAUDI_ARABIA 0x01 -#endif -#ifndef SUBLANG_ARABIC_IRAQ -#define SUBLANG_ARABIC_IRAQ 0x02 -#endif -#ifndef SUBLANG_ARABIC_EGYPT -#define SUBLANG_ARABIC_EGYPT 0x03 -#endif -#ifndef SUBLANG_ARABIC_LIBYA -#define SUBLANG_ARABIC_LIBYA 0x04 -#endif -#ifndef SUBLANG_ARABIC_ALGERIA -#define SUBLANG_ARABIC_ALGERIA 0x05 -#endif -#ifndef SUBLANG_ARABIC_MOROCCO -#define SUBLANG_ARABIC_MOROCCO 0x06 -#endif -#ifndef SUBLANG_ARABIC_TUNISIA -#define SUBLANG_ARABIC_TUNISIA 0x07 -#endif -#ifndef SUBLANG_ARABIC_OMAN -#define SUBLANG_ARABIC_OMAN 0x08 -#endif -#ifndef SUBLANG_ARABIC_YEMEN -#define SUBLANG_ARABIC_YEMEN 0x09 -#endif -#ifndef SUBLANG_ARABIC_SYRIA -#define SUBLANG_ARABIC_SYRIA 0x0a -#endif -#ifndef SUBLANG_ARABIC_JORDAN -#define SUBLANG_ARABIC_JORDAN 0x0b -#endif -#ifndef SUBLANG_ARABIC_LEBANON -#define SUBLANG_ARABIC_LEBANON 0x0c -#endif -#ifndef SUBLANG_ARABIC_KUWAIT -#define SUBLANG_ARABIC_KUWAIT 0x0d -#endif -#ifndef SUBLANG_ARABIC_UAE -#define SUBLANG_ARABIC_UAE 0x0e -#endif -#ifndef SUBLANG_ARABIC_BAHRAIN -#define SUBLANG_ARABIC_BAHRAIN 0x0f -#endif -#ifndef SUBLANG_ARABIC_QATAR -#define SUBLANG_ARABIC_QATAR 0x10 -#endif -#ifndef SUBLANG_AZERI_LATIN -#define SUBLANG_AZERI_LATIN 0x01 -#endif -#ifndef SUBLANG_AZERI_CYRILLIC -#define SUBLANG_AZERI_CYRILLIC 0x02 -#endif -#ifndef SUBLANG_CHINESE_MACAU -#define SUBLANG_CHINESE_MACAU 0x05 -#endif -#ifndef SUBLANG_ENGLISH_SOUTH_AFRICA -#define SUBLANG_ENGLISH_SOUTH_AFRICA 0x07 -#endif -#ifndef SUBLANG_ENGLISH_JAMAICA -#define SUBLANG_ENGLISH_JAMAICA 0x08 -#endif -#ifndef SUBLANG_ENGLISH_CARIBBEAN -#define SUBLANG_ENGLISH_CARIBBEAN 0x09 -#endif -#ifndef SUBLANG_ENGLISH_BELIZE -#define SUBLANG_ENGLISH_BELIZE 0x0a -#endif -#ifndef SUBLANG_ENGLISH_TRINIDAD -#define SUBLANG_ENGLISH_TRINIDAD 0x0b -#endif -#ifndef SUBLANG_ENGLISH_ZIMBABWE -#define SUBLANG_ENGLISH_ZIMBABWE 0x0c -#endif -#ifndef SUBLANG_ENGLISH_PHILIPPINES -#define SUBLANG_ENGLISH_PHILIPPINES 0x0d -#endif -#ifndef SUBLANG_FRENCH_LUXEMBOURG -#define SUBLANG_FRENCH_LUXEMBOURG 0x05 -#endif -#ifndef SUBLANG_FRENCH_MONACO -#define SUBLANG_FRENCH_MONACO 0x06 -#endif -#ifndef SUBLANG_GERMAN_LUXEMBOURG -#define SUBLANG_GERMAN_LUXEMBOURG 0x04 -#endif -#ifndef SUBLANG_GERMAN_LIECHTENSTEIN -#define SUBLANG_GERMAN_LIECHTENSTEIN 0x05 -#endif -#ifndef SUBLANG_KASHMIRI_INDIA -#define SUBLANG_KASHMIRI_INDIA 0x02 -#endif -#ifndef SUBLANG_MALAY_MALAYSIA -#define SUBLANG_MALAY_MALAYSIA 0x01 -#endif -#ifndef SUBLANG_MALAY_BRUNEI_DARUSSALAM -#define SUBLANG_MALAY_BRUNEI_DARUSSALAM 0x02 -#endif -#ifndef SUBLANG_NEPALI_INDIA -#define SUBLANG_NEPALI_INDIA 0x02 -#endif -#ifndef SUBLANG_SERBIAN_LATIN -#define SUBLANG_SERBIAN_LATIN 0x02 -#endif -#ifndef SUBLANG_SERBIAN_CYRILLIC -#define SUBLANG_SERBIAN_CYRILLIC 0x03 -#endif -#ifndef SUBLANG_SPANISH_GUATEMALA -#define SUBLANG_SPANISH_GUATEMALA 0x04 -#endif -#ifndef SUBLANG_SPANISH_COSTA_RICA -#define SUBLANG_SPANISH_COSTA_RICA 0x05 -#endif -#ifndef SUBLANG_SPANISH_PANAMA -#define SUBLANG_SPANISH_PANAMA 0x06 -#endif -#ifndef SUBLANG_SPANISH_DOMINICAN_REPUBLIC -#define SUBLANG_SPANISH_DOMINICAN_REPUBLIC 0x07 -#endif -#ifndef SUBLANG_SPANISH_VENEZUELA -#define SUBLANG_SPANISH_VENEZUELA 0x08 -#endif -#ifndef SUBLANG_SPANISH_COLOMBIA -#define SUBLANG_SPANISH_COLOMBIA 0x09 -#endif -#ifndef SUBLANG_SPANISH_PERU -#define SUBLANG_SPANISH_PERU 0x0a -#endif -#ifndef SUBLANG_SPANISH_ARGENTINA -#define SUBLANG_SPANISH_ARGENTINA 0x0b -#endif -#ifndef SUBLANG_SPANISH_ECUADOR -#define SUBLANG_SPANISH_ECUADOR 0x0c -#endif -#ifndef SUBLANG_SPANISH_CHILE -#define SUBLANG_SPANISH_CHILE 0x0d -#endif -#ifndef SUBLANG_SPANISH_URUGUAY -#define SUBLANG_SPANISH_URUGUAY 0x0e -#endif -#ifndef SUBLANG_SPANISH_PARAGUAY -#define SUBLANG_SPANISH_PARAGUAY 0x0f -#endif -#ifndef SUBLANG_SPANISH_BOLIVIA -#define SUBLANG_SPANISH_BOLIVIA 0x10 -#endif -#ifndef SUBLANG_SPANISH_EL_SALVADOR -#define SUBLANG_SPANISH_EL_SALVADOR 0x11 -#endif -#ifndef SUBLANG_SPANISH_HONDURAS -#define SUBLANG_SPANISH_HONDURAS 0x12 -#endif -#ifndef SUBLANG_SPANISH_NICARAGUA -#define SUBLANG_SPANISH_NICARAGUA 0x13 -#endif -#ifndef SUBLANG_SPANISH_PUERTO_RICO -#define SUBLANG_SPANISH_PUERTO_RICO 0x14 -#endif -#ifndef SUBLANG_SWEDISH_FINLAND -#define SUBLANG_SWEDISH_FINLAND 0x02 -#endif -#ifndef SUBLANG_URDU_PAKISTAN -#define SUBLANG_URDU_PAKISTAN 0x01 -#endif -#ifndef SUBLANG_URDU_INDIA -#define SUBLANG_URDU_INDIA 0x02 -#endif -#ifndef SUBLANG_UZBEK_LATIN -#define SUBLANG_UZBEK_LATIN 0x01 -#endif -#ifndef SUBLANG_UZBEK_CYRILLIC -#define SUBLANG_UZBEK_CYRILLIC 0x02 #endif -gchar * -g_win32_getlocale (void) +/** + * g_win32_get_windows_version: + * + * Returns version information for the Windows operating system the + * code is running on. See MSDN documentation for the GetVersion() + * function. To summarize, the most significant bit is one on Win9x, + * and zero on NT-based systems. Since version 2.14, GLib works only + * on NT-based systems, so checking whether your are running on Win9x + * in your own software is moot. The least significant byte is 4 on + * Windows NT 4, and 5 on Windows XP. Software that needs really + * detailed version and feature information should use Win32 API like + * GetVersionEx() and VerifyVersionInfo(). + * + * Returns: The version information. + * + * Since: 2.6 + **/ +guint +g_win32_get_windows_version (void) { - LCID lcid; - gchar *ev; - gint primary, sub; - gchar *l = NULL, *sl = NULL; - gchar bfr[20]; + static gsize windows_version; - if ((ev = getenv ("LC_ALL")) != NULL - || (ev = getenv ("LC_CTYPE")) != NULL - || (ev = getenv ("LANG")) != NULL) - return g_strdup (ev); + if (g_once_init_enter (&windows_version)) + g_once_init_leave (&windows_version, GetVersion ()); - lcid = GetThreadLocale (); - primary = PRIMARYLANGID (LANGIDFROMLCID (lcid)); - sub = SUBLANGID (LANGIDFROMLCID (lcid)); - switch (primary) + return windows_version; +} + +/** + * g_win32_locale_filename_from_utf8: + * @utf8filename: a UTF-8 encoded filename. + * + * Converts a filename from UTF-8 to the system codepage. + * + * On NT-based Windows, on NTFS file systems, file names are in + * Unicode. It is quite possible that Unicode file names contain + * characters not representable in the system codepage. (For instance, + * Greek or Cyrillic characters on Western European or US Windows + * installations, or various less common CJK characters on CJK Windows + * installations.) + * + * In such a case, and if the filename refers to an existing file, and + * the file system stores alternate short (8.3) names for directory + * entries, the short form of the filename is returned. Note that the + * "short" name might in fact be longer than the Unicode name if the + * Unicode name has very short pathname components containing + * non-ASCII characters. If no system codepage name for the file is + * possible, %NULL is returned. + * + * The return value is dynamically allocated and should be freed with + * g_free() when no longer needed. + * + * Returns: The converted filename, or %NULL on conversion + * failure and lack of short names. + * + * Since: 2.8 + */ +gchar * +g_win32_locale_filename_from_utf8 (const gchar *utf8filename) +{ + gchar *retval = g_locale_from_utf8 (utf8filename, -1, NULL, NULL, NULL); + + if (retval == NULL) { - case LANG_AFRIKAANS: l = "af"; break; - case LANG_ALBANIAN: l = "sq"; break; - case LANG_ARABIC: - l = "ar"; - switch (sub) + /* Conversion failed, so convert to wide chars, check if there + * is a 8.3 version, and use that. + */ + wchar_t *wname = g_utf8_to_utf16 (utf8filename, -1, NULL, NULL, NULL); + if (wname != NULL) { - case SUBLANG_ARABIC_SAUDI_ARABIA: sl = "SA"; break; - case SUBLANG_ARABIC_IRAQ: sl = "IQ"; break; - case SUBLANG_ARABIC_EGYPT: sl = "EG"; break; - case SUBLANG_ARABIC_LIBYA: sl = "LY"; break; - case SUBLANG_ARABIC_ALGERIA: sl = "DZ"; break; - case SUBLANG_ARABIC_MOROCCO: sl = "MA"; break; - case SUBLANG_ARABIC_TUNISIA: sl = "TN"; break; - case SUBLANG_ARABIC_OMAN: sl = "OM"; break; - case SUBLANG_ARABIC_YEMEN: sl = "YE"; break; - case SUBLANG_ARABIC_SYRIA: sl = "SY"; break; - case SUBLANG_ARABIC_JORDAN: sl = "JO"; break; - case SUBLANG_ARABIC_LEBANON: sl = "LB"; break; - case SUBLANG_ARABIC_KUWAIT: sl = "KW"; break; - case SUBLANG_ARABIC_UAE: sl = "AE"; break; - case SUBLANG_ARABIC_BAHRAIN: sl = "BH"; break; - case SUBLANG_ARABIC_QATAR: sl = "QA"; break; - } - break; - case LANG_ARMENIAN: l = "hy"; break; - case LANG_ASSAMESE: l = "as"; break; - case LANG_AZERI: l = "az"; break; - case LANG_BASQUE: l = "eu"; break; - case LANG_BELARUSIAN: l = "be"; break; - case LANG_BENGALI: l = "bn"; break; - case LANG_BULGARIAN: l = "bg"; break; - case LANG_CATALAN: l = "ca"; break; - case LANG_CHINESE: - l = "zh"; - switch (sub) - { - case SUBLANG_CHINESE_TRADITIONAL: sl = "TW"; break; - case SUBLANG_CHINESE_SIMPLIFIED: sl = "CH"; break; - case SUBLANG_CHINESE_HONGKONG: sl = "HK"; break; - case SUBLANG_CHINESE_SINGAPORE: sl = "SG"; break; - case SUBLANG_CHINESE_MACAU: sl = "MO"; break; - } - break; - case LANG_CROATIAN: /* LANG_CROATIAN == LANG_SERBIAN - * What used to be called Serbo-Croatian - * should really now be two separate - * languages because of political reasons. - * (Says tml, who knows nothing about Serbian - * or Croatian.) - * (I can feel those flames coming already.) - */ - switch (sub) - { - case SUBLANG_SERBIAN_LATIN: l = "hr"; break; - case SUBLANG_SERBIAN_CYRILLIC: l = "sr"; break; - default: l = "hr"; /* ??? */ - } - break; - case LANG_CZECH: l = "cs"; break; - case LANG_DANISH: l = "da"; break; - case LANG_DUTCH: - l = "nl"; - switch (sub) - { - case SUBLANG_DUTCH_BELGIAN: sl = "BE"; break; - } - break; - case LANG_ENGLISH: - l = "en"; - switch (sub) - { - /* SUBLANG_ENGLISH_US == SUBLANG_DEFAULT. Heh. I thought - * English was the language spoken in England. - * Oh well. - */ - case SUBLANG_ENGLISH_UK: sl = "GB"; break; - case SUBLANG_ENGLISH_AUS: sl = "AU"; break; - case SUBLANG_ENGLISH_CAN: sl = "CA"; break; - case SUBLANG_ENGLISH_NZ: sl = "NZ"; break; - case SUBLANG_ENGLISH_EIRE: sl = "IE"; break; - case SUBLANG_ENGLISH_SOUTH_AFRICA: sl = "SA"; break; - case SUBLANG_ENGLISH_JAMAICA: sl = "JM"; break; - case SUBLANG_ENGLISH_CARIBBEAN: sl = "@caribbean"; break; /* ??? */ - case SUBLANG_ENGLISH_BELIZE: sl = "BZ"; break; - case SUBLANG_ENGLISH_TRINIDAD: sl = "TT"; break; - case SUBLANG_ENGLISH_ZIMBABWE: sl = "ZW"; break; - case SUBLANG_ENGLISH_PHILIPPINES: sl = "PH"; break; - } - break; - case LANG_ESTONIAN: l = "et"; break; - case LANG_FAEROESE: l = "fo"; break; - case LANG_FARSI: l = "fa"; break; - case LANG_FINNISH: l = "fi"; break; - case LANG_FRENCH: - l = "fr"; - switch (sub) - { - case SUBLANG_FRENCH_BELGIAN: sl = "BE"; break; - case SUBLANG_FRENCH_CANADIAN: sl = "CA"; break; - case SUBLANG_FRENCH_SWISS: sl = "CH"; break; - case SUBLANG_FRENCH_LUXEMBOURG: sl = "LU"; break; - case SUBLANG_FRENCH_MONACO: sl = "MC"; break; - } - break; - case LANG_GEORGIAN: l = "ka"; break; - case LANG_GERMAN: - l = "de"; - switch (sub) - { - case SUBLANG_GERMAN_SWISS: sl = "CH"; break; - case SUBLANG_GERMAN_AUSTRIAN: sl = "AT"; break; - case SUBLANG_GERMAN_LUXEMBOURG: sl = "LU"; break; - case SUBLANG_GERMAN_LIECHTENSTEIN: sl = "LI"; break; - } - break; - case LANG_GREEK: l = "el"; break; - case LANG_GUJARATI: l = "gu"; break; - case LANG_HEBREW: l = "he"; break; - case LANG_HINDI: l = "hi"; break; - case LANG_HUNGARIAN: l = "hu"; break; - case LANG_ICELANDIC: l = "is"; break; - case LANG_INDONESIAN: l = "id"; break; - case LANG_ITALIAN: - l = "it"; - switch (sub) - { - case SUBLANG_ITALIAN_SWISS: sl = "CH"; break; - } - break; - case LANG_JAPANESE: l = "ja"; break; - case LANG_KANNADA: l = "kn"; break; - case LANG_KASHMIRI: - l = "ks"; - switch (sub) - { - case SUBLANG_KASHMIRI_INDIA: sl = "IN"; break; - } - break; - case LANG_KAZAK: l = "kk"; break; - case LANG_KONKANI: l = "kok"; break; /* ??? */ - case LANG_KOREAN: l = "ko"; break; - case LANG_LATVIAN: l = "lv"; break; - case LANG_LITHUANIAN: l = "lt"; break; - case LANG_MACEDONIAN: l = "mk"; break; - case LANG_MALAY: - l = "ms"; - switch (sub) - { - case SUBLANG_MALAY_BRUNEI_DARUSSALAM: sl = "BN"; break; - } - break; - case LANG_MALAYALAM: l = "ml"; break; - case LANG_MANIPURI: l = "mni"; break; - case LANG_MARATHI: l = "mr"; break; - case LANG_NEPALI: - l = "ne"; - switch (sub) - { - case SUBLANG_NEPALI_INDIA: sl = "IN"; break; - } - break; - case LANG_NORWEGIAN: - l = "no"; - switch (sub) - { - /* SUBLANG_NORWEGIAN_BOKMAL == SUBLANG_DEFAULT */ - case SUBLANG_NORWEGIAN_NYNORSK: sl = "@nynorsk"; break; - } - break; - case LANG_ORIYA: l = "or"; break; - case LANG_POLISH: l = "pl"; break; - case LANG_PORTUGUESE: - l = "pt"; - switch (sub) - { - /* Hmm. SUBLANG_PORTUGUESE_BRAZILIAN == SUBLANG_DEFAULT */ - case SUBLANG_PORTUGUESE_BRAZILIAN: sl = "BR"; break; - } - break; - case LANG_PUNJABI: l = "pa"; break; - case LANG_ROMANIAN: l = "ro"; break; - case LANG_RUSSIAN: l = "ru"; break; - case LANG_SANSKRIT: l = "sa"; break; - case LANG_SINDHI: l = "sd"; break; - case LANG_SLOVAK: l = "sk"; break; - case LANG_SLOVENIAN: l = "sl"; break; - case LANG_SPANISH: - l = "es"; - switch (sub) - { - case SUBLANG_SPANISH_MEXICAN: sl = "MX"; break; - case SUBLANG_SPANISH_MODERN: sl = "@modern"; break; /* ??? */ - case SUBLANG_SPANISH_GUATEMALA: sl = "GT"; break; - case SUBLANG_SPANISH_COSTA_RICA: sl = "CR"; break; - case SUBLANG_SPANISH_PANAMA: sl = "PA"; break; - case SUBLANG_SPANISH_DOMINICAN_REPUBLIC: sl = "DO"; break; - case SUBLANG_SPANISH_VENEZUELA: sl = "VE"; break; - case SUBLANG_SPANISH_COLOMBIA: sl = "CO"; break; - case SUBLANG_SPANISH_PERU: sl = "PE"; break; - case SUBLANG_SPANISH_ARGENTINA: sl = "AR"; break; - case SUBLANG_SPANISH_ECUADOR: sl = "EC"; break; - case SUBLANG_SPANISH_CHILE: sl = "CL"; break; - case SUBLANG_SPANISH_URUGUAY: sl = "UY"; break; - case SUBLANG_SPANISH_PARAGUAY: sl = "PY"; break; - case SUBLANG_SPANISH_BOLIVIA: sl = "BO"; break; - case SUBLANG_SPANISH_EL_SALVADOR: sl = "SV"; break; - case SUBLANG_SPANISH_HONDURAS: sl = "HN"; break; - case SUBLANG_SPANISH_NICARAGUA: sl = "NI"; break; - case SUBLANG_SPANISH_PUERTO_RICO: sl = "PR"; break; - } - break; - case LANG_SWAHILI: l = "sw"; break; - case LANG_SWEDISH: - l = "sv"; - switch (sub) - { - case SUBLANG_SWEDISH_FINLAND: sl = "FI"; break; - } - break; - case LANG_TAMIL: l = "ta"; break; - case LANG_TATAR: l = "tt"; break; - case LANG_TELUGU: l = "te"; break; - case LANG_THAI: l = "th"; break; - case LANG_TURKISH: l = "tr"; break; - case LANG_UKRAINIAN: l = "uk"; break; - case LANG_URDU: - l = "ur"; - switch (sub) - { - case SUBLANG_URDU_PAKISTAN: sl = "PK"; break; - case SUBLANG_URDU_INDIA: sl = "IN"; break; - } - break; - case LANG_UZBEK: - l = "uz"; - switch (sub) - { - case SUBLANG_UZBEK_CYRILLIC: sl = "@cyrillic"; break; + wchar_t wshortname[MAX_PATH + 1]; + if (GetShortPathNameW (wname, wshortname, G_N_ELEMENTS (wshortname))) + { + gchar *tem = g_utf16_to_utf8 (wshortname, -1, NULL, NULL, NULL); + retval = g_locale_from_utf8 (tem, -1, NULL, NULL, NULL); + g_free (tem); + } + g_free (wname); } - break; - case LANG_VIETNAMESE: l = "vi"; break; - default: l = "xx"; break; - } - strcpy (bfr, l); - if (sl != NULL) - { - strcat (bfr, "_"); - strcat (bfr, sl); } - - return g_strdup (bfr); + return retval; } -gchar * -g_win32_error_message (gint error) +/** + * g_win32_get_command_line: + * + * Gets the command line arguments, on Windows, in the GLib filename + * encoding (ie: UTF-8). + * + * Normally, on Windows, the command line arguments are passed to main() + * in the system codepage encoding. This prevents passing filenames as + * arguments if the filenames contain characters that fall outside of + * this codepage. If such filenames are passed, then substitutions + * will occur (such as replacing some characters with '?'). + * + * GLib's policy of using UTF-8 as a filename encoding on Windows was + * designed to localise the pain of dealing with filenames outside of + * the system codepage to one area: dealing with commandline arguments + * in main(). + * + * As such, most GLib programs should ignore the value of argv passed to + * their main() function and call g_win32_get_command_line() instead. + * This will get the "full Unicode" commandline arguments using + * GetCommandLineW() and convert it to the GLib filename encoding (which + * is UTF-8 on Windows). + * + * The strings returned by this function are suitable for use with + * functions such as g_open() and g_file_new_for_commandline_arg() but + * are not suitable for use with g_option_context_parse(), which assumes + * that its input will be in the system codepage. The return value is + * suitable for use with g_option_context_parse_strv(), however, which + * is a better match anyway because it won't leak memory. + * + * Unlike argv, the returned value is a normal strv and can (and should) + * be freed with g_strfreev() when no longer needed. + * + * Returns: (transfer full): the commandline arguments in the GLib + * filename encoding (ie: UTF-8) + * + * Since: 2.40 + **/ +gchar ** +g_win32_get_command_line (void) { - gchar *msg; - gchar *retval; - int nbytes; + gchar **result; + LPWSTR *args; + gint i, n; - FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER - |FORMAT_MESSAGE_IGNORE_INSERTS - |FORMAT_MESSAGE_FROM_SYSTEM, - NULL, error, 0, - (LPTSTR) &msg, 0, NULL); - nbytes = strlen (msg); + args = CommandLineToArgvW (GetCommandLineW(), &n); - if (nbytes > 2 && msg[nbytes-1] == '\n' && msg[nbytes-2] == '\r') - msg[nbytes-2] = '\0'; - - retval = g_strdup (msg); - - if (msg != NULL) - LocalFree (msg); + result = g_new (gchar *, n + 1); + for (i = 0; i < n; i++) + result[i] = g_utf16_to_utf8 (args[i], -1, NULL, NULL, NULL); + result[i] = NULL; - return retval; + return result; }