source: trunk/third/glib2/glib/gwin32.c @ 18159

Revision 18159, 20.6 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18158, which included commits to RCS files with non-trunk default branches.
Line 
1/* GLIB - Library of useful routines for C programming
2 * Copyright (C) 1995-1998  Peter Mattis, Spencer Kimball and Josh MacDonald
3 * Copyright (C) 1998-1999  Tor Lillqvist
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
19 */
20
21/*
22 * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
23 * file for a list of people on the GLib Team.  See the ChangeLog
24 * files for a list of changes.  These files are distributed with
25 * GLib at ftp://ftp.gtk.org/pub/gtk/.
26 */
27
28/*
29 * MT safe for the unix part, FIXME: make the win32 part MT safe as well.
30 */
31
32#include "config.h"
33
34#include "glibconfig.h"
35
36#include <stdlib.h>
37#include <stdio.h>
38#include <string.h>
39#include <errno.h>
40
41#define STRICT                  /* Strict typing, please */
42#include <windows.h>
43#undef STRICT
44#ifndef G_WITH_CYGWIN
45#include <direct.h>
46#endif
47#include <errno.h>
48#include <ctype.h>
49#ifdef _MSC_VER
50#  include <io.h>
51#endif /* _MSC_VER */
52
53#include "glib.h"
54
55#ifdef G_WITH_CYGWIN
56#include <sys/cygwin.h>
57#endif
58
59#ifndef G_WITH_CYGWIN
60
61gint
62g_win32_ftruncate (gint  fd,
63                   guint size)
64{
65  HANDLE hfile;
66  guint curpos;
67
68  g_return_val_if_fail (fd >= 0, -1);
69 
70  hfile = (HANDLE) _get_osfhandle (fd);
71  curpos = SetFilePointer (hfile, 0, NULL, FILE_CURRENT);
72  if (curpos == 0xFFFFFFFF
73      || SetFilePointer (hfile, size, NULL, FILE_BEGIN) == 0xFFFFFFFF
74      || !SetEndOfFile (hfile))
75    {
76      gint error = GetLastError ();
77
78      switch (error)
79        {
80        case ERROR_INVALID_HANDLE:
81          errno = EBADF;
82          break;
83        default:
84          errno = EIO;
85          break;
86        }
87
88      return -1;
89    }
90
91  return 0;
92}
93
94#endif
95
96/**
97 * g_win32_getlocale:
98 *
99 * The setlocale in the Microsoft C library uses locale names of the
100 * form "English_United States.1252" etc. We want the UNIXish standard
101 * form "en_US", "zh_TW" etc. This function gets the current thread
102 * locale from Windows - without any encoding info - and returns it as
103 * a string of the above form for use in forming file names etc. The
104 * returned string should be deallocated with g_free().
105 *
106 * Returns: newly-allocated locale name.
107 **/
108
109gchar *
110g_win32_getlocale (void)
111{
112  LCID lcid;
113  LANGID langid;
114  gchar *ev;
115  gint primary, sub;
116  gchar *l = NULL, *sl = NULL;
117  gchar bfr[20];
118
119  /* Let the user override the system settings through environment
120     variables, as on POSIX systems.  */
121  if (((ev = getenv ("LC_ALL")) != NULL && ev[0] != '\0')
122      || ((ev = getenv ("LC_MESSAGES")) != NULL && ev[0] != '\0')
123      || ((ev = getenv ("LANG")) != NULL && ev[0] != '\0'))
124    return g_strdup (ev);
125
126  /* Use native Win32 API locale ID.  */
127  lcid = GetThreadLocale ();
128
129  /* Strip off the sorting rules, keep only the language part.  */
130  langid = LANGIDFROMLCID (lcid);
131
132  /* Split into language and territory part.  */
133  primary = PRIMARYLANGID (langid);
134  sub = SUBLANGID (langid);
135  switch (primary)
136    {
137    case LANG_AFRIKAANS: l = "af"; sl = "ZA"; break;
138    case LANG_ALBANIAN: l = "sq"; sl = "AL"; break;
139    case LANG_ARABIC:
140      l = "ar";
141      switch (sub)
142        {
143        case SUBLANG_ARABIC_SAUDI_ARABIA: sl = "SA"; break;
144        case SUBLANG_ARABIC_IRAQ: sl = "IQ"; break;
145        case SUBLANG_ARABIC_EGYPT: sl = "EG"; break;
146        case SUBLANG_ARABIC_LIBYA: sl = "LY"; break;
147        case SUBLANG_ARABIC_ALGERIA: sl = "DZ"; break;
148        case SUBLANG_ARABIC_MOROCCO: sl = "MA"; break;
149        case SUBLANG_ARABIC_TUNISIA: sl = "TN"; break;
150        case SUBLANG_ARABIC_OMAN: sl = "OM"; break;
151        case SUBLANG_ARABIC_YEMEN: sl = "YE"; break;
152        case SUBLANG_ARABIC_SYRIA: sl = "SY"; break;
153        case SUBLANG_ARABIC_JORDAN: sl = "JO"; break;
154        case SUBLANG_ARABIC_LEBANON: sl = "LB"; break;
155        case SUBLANG_ARABIC_KUWAIT: sl = "KW"; break;
156        case SUBLANG_ARABIC_UAE: sl = "AE"; break;
157        case SUBLANG_ARABIC_BAHRAIN: sl = "BH"; break;
158        case SUBLANG_ARABIC_QATAR: sl = "QA"; break;
159        }
160      break;
161#ifdef LANG_ARMENIAN
162    case LANG_ARMENIAN: l = "hy"; sl = "AM"; break;
163#endif
164#ifdef LANG_ASSAMESE
165    case LANG_ASSAMESE: l = "as"; sl = "IN"; break;
166#endif
167#ifdef LANG_AZERI
168    case LANG_AZERI:
169      l = "az";
170#if defined (SUBLANG_AZERI_LATIN) && defined (SUBLANG_AZERI_CYRILLIC)
171      switch (sub)
172        {
173        /* FIXME: Adjust this when Azerbaijani locales appear on Unix.  */
174        case SUBLANG_AZERI_LATIN: sl = "@latin"; break;
175        case SUBLANG_AZERI_CYRILLIC: sl = "@cyrillic"; break;
176        }
177#endif
178      break;
179#endif
180    case LANG_BASQUE:
181      l = "eu"; /* sl could be "ES" or "FR".  */
182      break;
183    case LANG_BELARUSIAN: l = "be"; sl = "BY"; break;
184#ifdef LANG_BENGALI
185    case LANG_BENGALI: l = "bn"; sl = "IN"; break;
186#endif
187    case LANG_BULGARIAN: l = "bg"; sl = "BG"; break;
188    case LANG_CATALAN: l = "ca"; sl = "ES"; break;
189    case LANG_CHINESE:
190      l = "zh";
191      switch (sub)
192        {
193        case SUBLANG_CHINESE_TRADITIONAL: sl = "TW"; break;
194        case SUBLANG_CHINESE_SIMPLIFIED: sl = "CN"; break;
195        case SUBLANG_CHINESE_HONGKONG: sl = "HK"; break;
196        case SUBLANG_CHINESE_SINGAPORE: sl = "SG"; break;
197#ifdef SUBLANG_CHINESE_MACAU
198        case SUBLANG_CHINESE_MACAU: sl = "MO"; break;
199#endif
200        }
201      break;
202    case LANG_CROATIAN:         /* LANG_CROATIAN == LANG_SERBIAN
203                                 * What used to be called Serbo-Croatian
204                                 * should really now be two separate
205                                 * languages because of political reasons.
206                                 * (Says tml, who knows nothing about Serbian
207                                 * or Croatian.)
208                                 * (I can feel those flames coming already.)
209                                 */
210      switch (sub)
211        {
212        /* FIXME: How to distinguish Croatian and Latin Serbian locales?  */
213        case SUBLANG_SERBIAN_LATIN: l = "sr"; break;
214        case SUBLANG_SERBIAN_CYRILLIC: l = "sr"; sl = "@cyrillic"; break;
215        default: l = "hr"; sl = "HR";
216        }
217      break;
218    case LANG_CZECH: l = "cs"; sl = "CZ"; break;
219    case LANG_DANISH: l = "da"; sl = "DK"; break;
220#ifdef LANG_DIVEHI
221    case LANG_DIVEHI: l = "div"; sl = "MV"; break;
222#endif
223    case LANG_DUTCH:
224      l = "nl";
225      switch (sub)
226        {
227        case SUBLANG_DUTCH: sl = "NL"; break;
228        case SUBLANG_DUTCH_BELGIAN: sl = "BE"; break;
229        }
230      break;
231    case LANG_ENGLISH:
232      l = "en";
233      switch (sub)
234        {
235        case SUBLANG_ENGLISH_US: sl = "US"; break;
236        case SUBLANG_ENGLISH_UK: sl = "GB"; break;
237        case SUBLANG_ENGLISH_AUS: sl = "AU"; break;
238        case SUBLANG_ENGLISH_CAN: sl = "CA"; break;
239        case SUBLANG_ENGLISH_NZ: sl = "NZ"; break;
240        case SUBLANG_ENGLISH_EIRE: sl = "IE"; break;
241        case SUBLANG_ENGLISH_SOUTH_AFRICA: sl = "ZA"; break;
242        case SUBLANG_ENGLISH_JAMAICA: sl = "JM"; break;
243        case SUBLANG_ENGLISH_CARIBBEAN: sl = "GD"; break; /* Grenada? */
244        case SUBLANG_ENGLISH_BELIZE: sl = "BZ"; break;
245        case SUBLANG_ENGLISH_TRINIDAD: sl = "TT"; break;
246#ifdef SUBLANG_ENGLISH_ZIMBABWE
247        case SUBLANG_ENGLISH_ZIMBABWE: sl = "ZW"; break;
248#endif
249#ifdef SUBLANG_ENGLISH_PHILIPPINES
250        case SUBLANG_ENGLISH_PHILIPPINES: sl = "PH"; break;
251#endif
252        }
253      break;
254    case LANG_ESTONIAN: l = "et"; sl = "EE"; break;
255    case LANG_FAEROESE: l = "fo"; sl = "FO"; break;
256    case LANG_FARSI: l = "fa"; sl = "IR"; break;
257    case LANG_FINNISH: l = "fi"; sl = "FI"; break;
258    case LANG_FRENCH:
259      l = "fr";
260      switch (sub)
261        {
262        case SUBLANG_FRENCH: sl = "FR"; break;
263        case SUBLANG_FRENCH_BELGIAN: sl = "BE"; break;
264        case SUBLANG_FRENCH_CANADIAN: sl = "CA"; break;
265        case SUBLANG_FRENCH_SWISS: sl = "CH"; break;
266        case SUBLANG_FRENCH_LUXEMBOURG: sl = "LU"; break;
267#ifdef SUBLANG_FRENCH_MONACO
268        case SUBLANG_FRENCH_MONACO: sl = "MC"; break;
269#endif
270        }
271      break;
272      /* FIXME: LANG_GALICIAN: What's the code for Galician? */
273#ifdef LANG_GEORGIAN
274    case LANG_GEORGIAN: l = "ka"; sl = "GE"; break;
275#endif
276    case LANG_GERMAN:
277      l = "de";
278      switch (sub)
279        {
280        case SUBLANG_GERMAN: sl = "DE"; break;
281        case SUBLANG_GERMAN_SWISS: sl = "CH"; break;
282        case SUBLANG_GERMAN_AUSTRIAN: sl = "AT"; break;
283        case SUBLANG_GERMAN_LUXEMBOURG: sl = "LU"; break;
284        case SUBLANG_GERMAN_LIECHTENSTEIN: sl = "LI"; break;
285        }
286      break;
287    case LANG_GREEK: l = "el"; sl = "GR"; break;
288#ifdef LANG_GUJARATI
289    case LANG_GUJARATI: l = "gu"; sl = "IN"; break;
290#endif
291    case LANG_HEBREW: l = "he"; sl = "IL"; break;
292#ifdef LANG_HINDI
293    case LANG_HINDI: l = "hi"; sl = "IN"; break;
294#endif
295    case LANG_HUNGARIAN: l = "hu"; sl = "HU"; break;
296    case LANG_ICELANDIC: l = "is"; sl = "IS"; break;
297    case LANG_INDONESIAN: l = "id"; sl = "ID"; break;
298    case LANG_ITALIAN:
299      l = "it";
300      switch (sub)
301        {
302        case SUBLANG_ITALIAN: sl = "IT"; break;
303        case SUBLANG_ITALIAN_SWISS: sl = "CH"; break;
304        }
305      break;
306    case LANG_JAPANESE: l = "ja"; sl = "JP"; break;
307#ifdef LANG_KANNADA
308    case LANG_KANNADA: l = "kn"; sl = "IN"; break;
309#endif
310#ifdef LANG_KASHMIRI
311    case LANG_KASHMIRI:
312      l = "ks";
313      switch (sub)
314        {
315        case SUBLANG_DEFAULT: sl = "PK"; break;
316#ifdef SUBLANG_KASHMIRI_INDIA
317        case SUBLANG_KASHMIRI_INDIA: sl = "IN"; break;
318#endif
319        }
320      break;
321#endif
322#ifdef LANG_KAZAK
323    case LANG_KAZAK: l = "kk"; sl = "KZ"; break;
324#endif
325#ifdef LANG_KONKANI
326    case LANG_KONKANI:
327      /* FIXME: Adjust this when such locales appear on Unix.  */
328      l = "kok"; sl = "IN";
329      break;
330#endif
331    case LANG_KOREAN: l = "ko"; sl = "KR"; break;
332#ifdef LANG_KYRGYZ
333    case LANG_KYRGYZ: l = "ky"; sl = "KG"; /* ??? */ break;
334#endif
335    case LANG_LATVIAN: l = "lv"; sl = "LV"; break;
336    case LANG_LITHUANIAN: l = "lt"; sl = "LT"; break;
337#ifdef LANG_MACEDONIAN
338    case LANG_MACEDONIAN: l = "mk"; sl = "MK"; break;
339#endif
340#ifdef LANG_MALAY
341    case LANG_MALAY:
342      l = "ms";
343      switch (sub)
344        {
345#ifdef SUBLANG_MALAY_MALAYSIA
346        case SUBLANG_MALAY_MALAYSIA: sl = "MY"; break;
347#endif
348#ifdef SUBLANG_MALAY_BRUNEI_DARUSSALAM
349        case SUBLANG_MALAY_BRUNEI_DARUSSALAM: sl = "BN"; break;
350#endif
351        }
352      break;
353#endif
354#ifdef LANG_MALAYALAM
355    case LANG_MALAYALAM: l = "ml"; sl = "IN"; break;
356#endif
357#ifdef LANG_MANIPURI
358    case LANG_MANIPURI:
359      /* FIXME: Adjust this when such locales appear on Unix.  */
360      l = "mni"; sl = "IN";
361      break;
362#endif
363#ifdef LANG_MARATHI
364    case LANG_MARATHI: l = "mr"; sl = "IN"; break;
365#endif
366#ifdef LANG_MONGOLIAN
367    case LANG_MONGOLIAN: l = "mn"; sl = "MN"; break;
368#endif
369#ifdef LANG_NEPALI
370    case LANG_NEPALI:
371      l = "ne";
372      switch (sub)
373        {
374        case SUBLANG_DEFAULT: sl = "NP"; break;
375#ifdef SUBLANG_NEPALI_INDIA
376        case SUBLANG_NEPALI_INDIA: sl = "IN"; break;
377#endif
378        }
379      break;
380#endif
381    case LANG_NORWEGIAN:
382      l = "no";
383      switch (sub)
384        {
385        case SUBLANG_NORWEGIAN_BOKMAL: sl = "NO"; break;
386        case SUBLANG_NORWEGIAN_NYNORSK: l = "nn"; sl = "NO"; break;
387        }
388      break;
389#ifdef LANG_ORIYA
390    case LANG_ORIYA: l = "or"; sl = "IN"; break;
391#endif
392    case LANG_POLISH: l = "pl"; sl = "PL"; break;
393    case LANG_PORTUGUESE:
394      l = "pt";
395      switch (sub)
396        {
397        case SUBLANG_PORTUGUESE: sl = "PT"; break;
398        case SUBLANG_PORTUGUESE_BRAZILIAN: sl = "BR"; break;
399        }
400      break;
401#ifdef LANG_PUNJABI
402    case LANG_PUNJABI: l = "pa"; sl = "IN"; break;
403#endif
404    case LANG_ROMANIAN: l = "ro"; sl = "RO"; break;
405    case LANG_RUSSIAN:
406      l = "ru"; /* sl could be "RU" or "UA".  */
407      break;
408#ifdef LANG_SANSKRIT
409    case LANG_SANSKRIT: l = "sa"; sl = "IN"; break;
410#endif
411#ifdef LANG_SINDHI
412    case LANG_SINDHI: l = "sd"; break;
413#endif
414    case LANG_SLOVAK: l = "sk"; sl = "SK"; break;
415    case LANG_SLOVENIAN: l = "sl"; sl = "SI"; break;
416#ifdef LANG_SORBIAN
417    case LANG_SORBIAN:
418      /* FIXME: Adjust this when such locales appear on Unix.  */
419      l = "wen"; sl = "DE";
420      break;
421#endif
422    case LANG_SPANISH:
423      l = "es";
424      switch (sub)
425        {
426        case SUBLANG_SPANISH: sl = "ES"; break;
427        case SUBLANG_SPANISH_MEXICAN: sl = "MX"; break;
428        case SUBLANG_SPANISH_MODERN:
429          sl = "ES@modern"; break;      /* not seen on Unix */
430        case SUBLANG_SPANISH_GUATEMALA: sl = "GT"; break;
431        case SUBLANG_SPANISH_COSTA_RICA: sl = "CR"; break;
432        case SUBLANG_SPANISH_PANAMA: sl = "PA"; break;
433        case SUBLANG_SPANISH_DOMINICAN_REPUBLIC: sl = "DO"; break;
434        case SUBLANG_SPANISH_VENEZUELA: sl = "VE"; break;
435        case SUBLANG_SPANISH_COLOMBIA: sl = "CO"; break;
436        case SUBLANG_SPANISH_PERU: sl = "PE"; break;
437        case SUBLANG_SPANISH_ARGENTINA: sl = "AR"; break;
438        case SUBLANG_SPANISH_ECUADOR: sl = "EC"; break;
439        case SUBLANG_SPANISH_CHILE: sl = "CL"; break;
440        case SUBLANG_SPANISH_URUGUAY: sl = "UY"; break;
441        case SUBLANG_SPANISH_PARAGUAY: sl = "PY"; break;
442        case SUBLANG_SPANISH_BOLIVIA: sl = "BO"; break;
443        case SUBLANG_SPANISH_EL_SALVADOR: sl = "SV"; break;
444        case SUBLANG_SPANISH_HONDURAS: sl = "HN"; break;
445        case SUBLANG_SPANISH_NICARAGUA: sl = "NI"; break;
446        case SUBLANG_SPANISH_PUERTO_RICO: sl = "PR"; break;
447        }
448      break;
449#ifdef LANG_SWAHILI
450    case LANG_SWAHILI: l = "sw"; break;
451#endif
452    case LANG_SWEDISH:
453      l = "sv";
454      switch (sub)
455        {
456        case SUBLANG_DEFAULT: sl = "SE"; break;
457        case SUBLANG_SWEDISH_FINLAND: sl = "FI"; break;
458        }
459      break;
460#ifdef LANG_SYRIAC
461    case LANG_SYRIAC: l = "syr"; break;
462#endif
463#ifdef LANG_TAMIL
464    case LANG_TAMIL:
465      l = "ta"; /* sl could be "IN" or "LK".  */
466      break;
467#endif
468#ifdef LANG_TATAR
469    case LANG_TATAR: l = "tt"; break;
470#endif
471#ifdef LANG_TELUGU
472    case LANG_TELUGU: l = "te"; sl = "IN"; break;
473#endif
474    case LANG_THAI: l = "th"; sl = "TH"; break;
475    case LANG_TURKISH: l = "tr"; sl = "TR"; break;
476    case LANG_UKRAINIAN: l = "uk"; sl = "UA"; break;
477#ifdef LANG_URDU
478    case LANG_URDU:
479      l = "ur";
480      switch (sub)
481        {
482#ifdef SUBLANG_URDU_PAKISTAN
483        case SUBLANG_URDU_PAKISTAN: sl = "PK"; break;
484#endif
485#ifdef SUBLANG_URDU_INDIA
486        case SUBLANG_URDU_INDIA: sl = "IN"; break;
487#endif
488        }
489      break;
490#endif
491#ifdef LANG_UZBEK
492    case LANG_UZBEK:
493      l = "uz";
494      switch (sub)
495        {
496        /* FIXME: Adjust this when Uzbek locales appear on Unix.  */
497#ifdef SUBLANG_UZBEK_LATIN
498        case SUBLANG_UZBEK_LATIN: sl = "UZ@latin"; break;
499#endif
500#ifdef SUBLANG_UZBEK_CYRILLIC
501        case SUBLANG_UZBEK_CYRILLIC: sl = "UZ@cyrillic"; break;
502#endif
503        }
504      break;
505#endif
506    case LANG_VIETNAMESE: l = "vi"; sl = "VN"; break;
507    default: l = "xx"; break;
508    }
509  strcpy (bfr, l);
510  if (sl != NULL)
511    {
512      if (sl[0] != '@')
513        strcat (bfr, "_");
514      strcat (bfr, sl);
515    }
516
517  return g_strdup (bfr);
518}
519
520/**
521 * g_win32_error_message:
522 * @error: error code.
523 *
524 * Translate a Win32 error code (as returned by GetLastError()) into
525 * the corresponding message. The message is either language neutral,
526 * or in the thread's language, or the user's language, the system's
527 * language, or US English (see docs for <function>FormatMessage()</function>). *
528 * The returned string should be deallocated with g_free().
529 *
530 * Returns: newly-allocated error message
531 **/
532gchar *
533g_win32_error_message (gint error)
534{
535  gchar *msg;
536  gchar *retval;
537  int nbytes;
538
539  FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER
540                 |FORMAT_MESSAGE_IGNORE_INSERTS
541                 |FORMAT_MESSAGE_FROM_SYSTEM,
542                 NULL, error, 0,
543                 (LPTSTR) &msg, 0, NULL);
544  nbytes = strlen (msg);
545
546  if (nbytes > 2 && msg[nbytes-1] == '\n' && msg[nbytes-2] == '\r')
547    msg[nbytes-2] = '\0';
548 
549  retval = g_strdup (msg);
550
551  if (msg != NULL)
552    LocalFree (msg);
553
554  return retval;
555}
556
557static gchar *
558get_package_directory_from_module (gchar *module_name)
559{
560  static GHashTable *module_dirs = NULL;
561  G_LOCK_DEFINE_STATIC (module_dirs);
562  HMODULE hmodule = NULL;
563  gchar *fn;
564  gchar *p;
565  gchar *result;
566
567  G_LOCK (module_dirs);
568
569  if (module_dirs == NULL)
570    module_dirs = g_hash_table_new (g_str_hash, g_str_equal);
571 
572  result = g_hash_table_lookup (module_dirs, module_name ? module_name : "");
573     
574  if (result)
575    {
576      G_UNLOCK (module_dirs);
577      return g_strdup (result);
578    }
579
580  if (module_name)
581    {
582      hmodule = GetModuleHandle (module_name);
583      if (!hmodule)
584        return NULL;
585    }
586
587  fn = g_malloc (MAX_PATH);
588  if (!GetModuleFileName (hmodule, fn, MAX_PATH))
589    {
590      G_UNLOCK (module_dirs);
591      g_free (fn);
592      return NULL;
593    }
594
595  if ((p = strrchr (fn, G_DIR_SEPARATOR)) != NULL)
596    *p = '\0';
597
598  p = strrchr (fn, G_DIR_SEPARATOR);
599  if (p && (g_ascii_strcasecmp (p + 1, "bin") == 0 ||
600            g_ascii_strcasecmp (p + 1, "lib") == 0))
601    *p = '\0';
602
603#ifdef G_WITH_CYGWIN
604  /* In Cygwin we need to have POSIX paths */
605  {
606    gchar tmp[MAX_PATH];
607
608    cygwin_conv_to_posix_path(fn, tmp);
609    g_free(fn);
610    fn = g_strdup(tmp);
611  }
612#endif
613
614  g_hash_table_insert (module_dirs, module_name ? module_name : "", fn);
615
616  G_UNLOCK (module_dirs);
617
618  return g_strdup (fn);
619}
620
621/**
622 * g_win32_get_package_installation_directory:
623 * @package: An identifier for a software package, or %NULL
624 * @dll_name: The name of a DLL that a package provides, or %NULL.
625 *
626 * Try to determine the installation directory for a software package.
627 * Typically used by GNU software packages.
628 *
629 * @package should be a short identifier for the package. Typically it
630 * is the same identifier as used for
631 * <literal>GETTEXT_PACKAGE</literal> in software configured according
632 * to GNU standards. The function first looks in the Windows Registry
633 * for the value <literal>&num;InstallationDirectory</literal> in the key
634 * <literal>&num;HKLM\Software\@package</literal>, and if that value
635 * exists and is a string, returns that.
636 *
637 * If @package is %NULL, or the above value isn't found in the
638 * Registry, but @dll_name is non-%NULL, it should name a DLL loaded
639 * into the current process. Typically that would be the name of the
640 * DLL calling this function, looking for its installation
641 * directory. The function then asks Windows what directory that DLL
642 * was loaded from. If that directory's last component is "bin" or
643 * "lib", the parent directory is returned, otherwise the directory
644 * itself. If that DLL isn't loaded, the function proceeds as if
645 * @dll_name was %NULL.
646 *
647 * If both @package and @dll_name are %NULL, the directory from where
648 * the main executable of the process was loaded is uses instead in
649 * the same way as above.
650 *
651 * Returns: a string containing the installation directory for @package.
652 * The return value should be freed with g_free() when not needed any longer.
653 **/
654
655gchar *
656g_win32_get_package_installation_directory (gchar *package,
657                                            gchar *dll_name)
658{
659  static GHashTable *package_dirs = NULL;
660  G_LOCK_DEFINE_STATIC (package_dirs);
661  gchar *result = NULL;
662  gchar *key;
663  HKEY reg_key = NULL;
664  DWORD type;
665  DWORD nbytes;
666
667  if (package != NULL)
668    {
669      G_LOCK (package_dirs);
670     
671      if (package_dirs == NULL)
672        package_dirs = g_hash_table_new (g_str_hash, g_str_equal);
673     
674      result = g_hash_table_lookup (package_dirs, package);
675     
676      if (result && result[0])
677        {
678          G_UNLOCK (package_dirs);
679          return g_strdup (result);
680        }
681     
682      key = g_strconcat ("Software\\", package, NULL);
683     
684      nbytes = 0;
685      if ((RegOpenKeyEx (HKEY_CURRENT_USER, key, 0,
686                         KEY_QUERY_VALUE, &reg_key) == ERROR_SUCCESS
687           && RegQueryValueEx (reg_key, "InstallationDirectory", 0,
688                               &type, NULL, &nbytes) == ERROR_SUCCESS)
689          ||
690          ((RegOpenKeyEx (HKEY_LOCAL_MACHINE, key, 0,
691                         KEY_QUERY_VALUE, &reg_key) == ERROR_SUCCESS
692           && RegQueryValueEx (reg_key, "InstallationDirectory", 0,
693                               &type, NULL, &nbytes) == ERROR_SUCCESS)
694           && type == REG_SZ))
695        {
696          result = g_malloc (nbytes + 1);
697          RegQueryValueEx (reg_key, "InstallationDirectory", 0,
698                           &type, result, &nbytes);
699          result[nbytes] = '\0';
700        }
701
702      if (reg_key != NULL)
703        RegCloseKey (reg_key);
704     
705      g_free (key);
706
707      if (result)
708        {
709          g_hash_table_insert (package_dirs, package, result);
710          G_UNLOCK (package_dirs);
711          return g_strdup (result);
712        }
713      G_UNLOCK (package_dirs);
714    }
715
716  if (dll_name != NULL)
717    result = get_package_directory_from_module (dll_name);
718
719  if (result == NULL)
720    result = get_package_directory_from_module (NULL);
721
722  return result;
723}
724
725/**
726 * g_win32_get_package_installation_subdirectory:
727 * @package: An identifier for a software package, or %NULL.
728 * @dll_name: The name of a DLL that a package provides, or %NULL.
729 * @subdir: A subdirectory of the package installation directory.
730 *
731 * Returns a newly-allocated string containing the path of the
732 * subdirectory @subdir in the return value from calling
733 * g_win32_get_package_installation_directory() with the @package and
734 * @dll_name parameters.
735 *
736 * Returns: a string containing the complete path to @subdir inside the
737 * installation directory of @package. The return value should be freed with
738 * g_free() when no longer needed.
739 **/
740
741gchar *
742g_win32_get_package_installation_subdirectory (gchar *package,
743                                               gchar *dll_name,
744                                               gchar *subdir)
745{
746  gchar *prefix;
747
748  prefix = g_win32_get_package_installation_directory (package, dll_name);
749
750  return g_build_filename (prefix, subdir, NULL);
751}
Note: See TracBrowser for help on using the repository browser.