Updating to version 1.13. Libgcrypt depends on libgpg-error
[platform/upstream/libgpg-error.git] / src / init.c
1 /* init.c - Initialize the GnuPG error library.
2    Copyright (C) 2005, 2010 g10 Code GmbH
3
4    This file is part of libgpg-error.
5
6    libgpg-error is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public License
8    as published by the Free Software Foundation; either version 2.1 of
9    the License, or (at your option) any later version.
10  
11    libgpg-error is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15  
16    You should have received a copy of the GNU Lesser General Public
17    License along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #if HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <errno.h>
28
29 #include <gpg-error.h>
30
31 #include "gettext.h"
32 #include "init.h"
33
34 #ifdef HAVE_W32CE_SYSTEM
35 # include "mkw32errmap.map.c"  /* Generated map_w32codes () */
36 # ifndef TLS_OUT_OF_INDEXES
37 #  define TLS_OUT_OF_INDEXES 0xFFFFFFFF
38 # endif
39 # ifndef __MINGW32CE__
40 #  /* Replace the Mingw32CE provided abort function.  */
41 #  define abort() do { TerminateProcess (GetCurrentProcess(), 8); } while (0)
42 # endif
43 #endif
44
45 \f
46 /* Locale directory support.  */
47
48 #if HAVE_W32_SYSTEM
49
50 #include <windows.h>
51
52 static int tls_index = TLS_OUT_OF_INDEXES;  /* Index for the TLS functions.  */ 
53
54 static char *get_locale_dir (void);
55 static void drop_locale_dir (char *locale_dir);
56
57 #else /*!HAVE_W32_SYSTEM*/
58
59 #define get_locale_dir() LOCALEDIR
60 #define drop_locale_dir(dir)
61
62 #endif /*!HAVE_W32_SYSTEM*/
63
64 \f
65 static void
66 real_init (void)
67 {
68 #ifdef ENABLE_NLS
69   char *locale_dir;
70
71   /* We only have to bind our locale directory to our text domain.  */
72   locale_dir = get_locale_dir ();
73   if (locale_dir)
74     {
75       bindtextdomain (PACKAGE, locale_dir);
76       drop_locale_dir (locale_dir);
77     }
78 #endif
79 }
80
81 /* Initialize the library.  This function should be run early.  */
82 gpg_error_t
83 gpg_err_init (void)
84 {
85 #ifdef HAVE_W32_SYSTEM
86 # ifdef DLL_EXPORT
87   /* We always have a constructor and thus this function is called
88      automatically.  Due to the way the C init code of mingw works,
89      the constructors are called before our DllMain function is
90      called.  The problem with that is that the TLS has not been setup
91      and w32-gettext.c requires TLS.  To solve this we do nothing here
92      but call the actual init code from our DllMain.  */
93 # else /*!DLL_EXPORT*/
94   /* Note that if the TLS is actually used, we can't release the TLS
95      as there is no way to know when a thread terminates (i.e. no
96      thread-specific-atexit).  You are really better off to use the
97      DLL! */
98   if (tls_index == TLS_OUT_OF_INDEXES)
99     {
100       tls_index = TlsAlloc ();
101       if (tls_index == TLS_OUT_OF_INDEXES)
102         {
103           /* No way to continue - commit suicide.  */
104           abort ();
105         }
106       _gpg_w32__init_gettext_module ();
107       real_init ();
108     }
109 # endif /*!DLL_EXPORT*/
110 #else
111   real_init ();
112 #endif
113   return 0;
114 }
115
116
117 /* Deinitialize libgpg-error.  This function is only used in special
118    circumstances.  No gpg-error function should be used after this
119    function has been called.  A value of 0 passed for MODE
120    deinitializes the entire libgpg-error, a value of 1 releases
121    resources allocated for the current thread and only that thread may
122    not anymore access libgpg-error after such a call.  Under Windows
123    this function may be called from the DllMain function of a DLL
124    which statically links to libgpg-error.  */
125 void
126 gpg_err_deinit (int mode)
127 {
128 #if defined (HAVE_W32_SYSTEM) && !defined(DLL_EXPORT)
129   struct tls_space_s *tls;
130   
131   tls = TlsGetValue (tls_index);
132   if (tls)
133     {
134       TlsSetValue (tls_index, NULL);
135       LocalFree (tls);
136     }
137
138   if (mode == 0)
139     {
140       TlsFree (tls_index);
141       tls_index = TLS_OUT_OF_INDEXES;
142     }
143 #else
144   (void)mode;
145 #endif
146 }
147
148
149 \f
150 #ifdef HAVE_W32_SYSTEM
151
152 /* Return a malloced string encoded in UTF-8 from the wide char input
153    string STRING.  Caller must free this value.  Returns NULL on
154    failure.  Caller may use GetLastError to get the actual error
155    number.  The result of calling this function with STRING set to
156    NULL is not defined.  */
157 static char *
158 wchar_to_utf8 (const wchar_t *string)
159 {
160   int n;
161   char *result;
162
163   /* Note, that CP_UTF8 is not defined in Windows versions earlier
164      than NT.  */
165   n = WideCharToMultiByte (CP_UTF8, 0, string, -1, NULL, 0, NULL, NULL);
166   if (n < 0)
167     return NULL;
168
169   result = malloc (n+1);
170   if (result)
171     {
172       n = WideCharToMultiByte (CP_UTF8, 0, string, -1, result, n, NULL, NULL);
173       if (n < 0)
174         {
175           free (result);
176           result = NULL;
177         }
178     }
179   return result;
180 }
181
182
183 /* Return a malloced wide char string from an UTF-8 encoded input
184    string STRING.  Caller must free this value.  Returns NULL on
185    failure.  Caller may use GetLastError to get the actual error
186    number.  The result of calling this function with STRING set to
187    NULL is not defined.  */
188 static wchar_t *
189 utf8_to_wchar (const char *string)
190 {
191   int n;
192   wchar_t *result;
193
194   n = MultiByteToWideChar (CP_UTF8, 0, string, -1, NULL, 0);
195   if (n < 0)
196     return NULL;
197
198   result = malloc ((n+1) * sizeof *result);
199   if (result)
200     {
201       n = MultiByteToWideChar (CP_UTF8, 0, string, -1, result, n);
202       if (n < 0)
203         {
204           free (result);
205           result = NULL;
206         }
207       return NULL;
208     }
209   return result;
210 }
211
212
213 static char *
214 get_locale_dir (void)
215 {
216   static wchar_t moddir[MAX_PATH+5];
217   char *result, *p;
218   int nbytes;
219
220   if (!GetModuleFileNameW (NULL, moddir, MAX_PATH))
221     *moddir = 0;
222
223 #define SLDIR "\\share\\locale"
224   if (*moddir)
225     {
226       nbytes = WideCharToMultiByte (CP_UTF8, 0, moddir, -1, NULL, 0, NULL, NULL);
227       if (nbytes < 0)
228         return NULL;
229       
230       result = malloc (nbytes + strlen (SLDIR) + 1);
231       if (result)
232         {
233           nbytes = WideCharToMultiByte (CP_UTF8, 0, moddir, -1,
234                                         result, nbytes, NULL, NULL);
235           if (nbytes < 0)
236             {
237               free (result);
238               result = NULL;
239             }
240           else
241             {
242               p = strrchr (result, '\\');
243               if (p)
244                 *p = 0;
245               /* If we are installed below "bin" strip that part and
246                  use the top directory instead.
247
248                  Background: Under Windows we don't install GnuPG
249                  below bin/ but in the top directory with only share/,
250                  lib/, and etc/ below it.  One of the reasons is to
251                  keep the the length of the filenames at bay so not to
252                  increase the limited length of the PATH envvar.
253                  Another and more important reason, however, is that
254                  the very first GPG versions on W32 were installed
255                  into a flat directory structure and for best
256                  compatibility with these versions we didn't changed
257                  that later.  For WindowsCE we can right away install
258                  it under bin, though.  The hack with detection of the
259                  bin directory part allows us to eventually migrate to
260                  such a directory layout under plain Windows without
261                  the need to change libgpg-error.  */
262               p = strrchr (result, '\\');
263               if (p && !strcmp (p+1, "bin"))
264                 *p = 0;
265               /* Append the static part.  */
266               strcat (result, SLDIR);
267             }
268         }
269     }
270   else /* Use the old default value.  */
271     {
272       result = malloc (10 + strlen (SLDIR) + 1);
273       if (result)
274         {
275           strcpy (result, "c:\\gnupg");
276           strcat (result, SLDIR);
277         }
278     }  
279 #undef SLDIR  
280   return result;
281 }
282
283
284 static void
285 drop_locale_dir (char *locale_dir)
286 {
287   free (locale_dir);
288 }
289
290
291 /* Return the tls object.  This function is guaranteed to return a
292    valid non-NULL object.  */
293 struct tls_space_s *
294 get_tls (void)
295 {
296   struct tls_space_s *tls;
297
298   tls = TlsGetValue (tls_index);
299   if (!tls)
300     {
301       /* Called by a thread which existed before this DLL was loaded.
302          Allocate the space.  */
303       tls = LocalAlloc (LPTR, sizeof *tls);
304       if (!tls)
305         {
306           /* No way to continue - commit suicide.  */
307           abort ();
308         }
309       tls->gt_use_utf8 = 0;
310       TlsSetValue (tls_index, tls);
311     }
312         
313   return tls;
314 }
315
316
317 /* Return the value of the ERRNO variable.  This needs to be a
318    function so that we can have a per-thread ERRNO.  This is used only
319    on WindowsCE because that OS misses an errno.   */
320 #ifdef HAVE_W32CE_SYSTEM
321 int
322 _gpg_w32ce_get_errno (void)
323 {
324   return map_w32codes ( GetLastError () );
325 }
326 #endif /*HAVE_W32CE_SYSTEM*/
327
328
329 /* Replacement strerror function for WindowsCE.  */
330 #ifdef HAVE_W32CE_SYSTEM
331 char *
332 _gpg_w32ce_strerror (int err)
333 {
334   struct tls_space_s *tls = get_tls ();
335   wchar_t tmpbuf[STRBUFFER_SIZE];
336   int n;
337
338   if (err == -1)
339     err = _gpg_w32ce_get_errno ();
340
341   /* Note: On a German HTC Touch Pro2 device I also tried
342      LOCALE_USER_DEFAULT and LOCALE_SYSTEM_DEFAULT - both returned
343      English messages.  */
344   if (FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
345                       MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
346                       tmpbuf, STRBUFFER_SIZE -1,
347                       NULL))
348     {
349       n = WideCharToMultiByte (CP_UTF8, 0, tmpbuf, -1,
350                                tls->strerror_buffer,
351                                sizeof tls->strerror_buffer -1,
352                                NULL, NULL);
353     }
354   else
355     n = -1;
356
357   if (n < 0)
358     snprintf (tls->strerror_buffer, sizeof tls->strerror_buffer -1,
359               "[w32err=%d]", err);
360   return tls->strerror_buffer;    
361 }
362 #endif /*HAVE_W32CE_SYSTEM*/
363
364
365 void
366 gpg_err_set_errno (int err)
367 {
368 #ifdef HAVE_W32CE_SYSTEM
369   SetLastError (err);
370 #else /*!HAVE_W32CE_SYSTEM*/
371   errno = err;
372 #endif /*!HAVE_W32CE_SYSTEM*/
373 }
374
375
376 /* Entry point called by the DLL loader.  */
377 #ifdef DLL_EXPORT
378 int WINAPI
379 DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved)
380 {
381   struct tls_space_s *tls;
382   (void)reserved;
383
384   switch (reason)
385     {
386     case DLL_PROCESS_ATTACH:
387       tls_index = TlsAlloc ();
388       if (tls_index == TLS_OUT_OF_INDEXES)
389         return FALSE; 
390 #ifndef _GPG_ERR_HAVE_CONSTRUCTOR
391       /* If we have not constructors (e.g. MSC) we call it here.  */
392       _gpg_w32__init_gettext_module ();
393 #endif
394       /* falltru.  */
395     case DLL_THREAD_ATTACH:
396       tls = LocalAlloc (LPTR, sizeof *tls);
397       if (!tls)
398         return FALSE;
399       tls->gt_use_utf8 = 0;
400       TlsSetValue (tls_index, tls);
401       if (reason == DLL_PROCESS_ATTACH)
402         {
403           real_init ();
404         }
405       break;
406
407     case DLL_THREAD_DETACH:
408       tls = TlsGetValue (tls_index);
409       if (tls)
410         LocalFree (tls);
411       break;
412
413     case DLL_PROCESS_DETACH:
414       tls = TlsGetValue (tls_index);
415       if (tls)
416         LocalFree (tls);
417       TlsFree (tls_index);
418       break;
419
420     default:
421       break;
422     }
423   
424   return TRUE;
425 }
426 #endif /*DLL_EXPORT*/
427
428 #else /*!HAVE_W32_SYSTEM*/
429
430 void
431 gpg_err_set_errno (int err)
432 {
433   errno = err;
434 }
435
436 #endif /*!HAVE_W32_SYSTEM*/