Tizen 2.1 base
[external/libgpg-error.git] / src / gpg-error.c
1 /* gpg-error.c - Determining gpg-error error codes.
2    Copyright (C) 2004 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 libgpg-error; if not, write to the Free
18    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19    02111-1307, USA.  */
20
21 #if HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <stddef.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <limits.h>
30 #include <stdio.h>
31
32 #ifdef HAVE_LOCALE_H
33 # include <locale.h>    
34 #endif
35 #ifdef ENABLE_NLS
36 #ifdef HAVE_W32_SYSTEM
37 # include "gettext.h"
38 #else
39 # include <libintl.h>
40 #endif
41 # define _(a) gettext (a)
42 # ifdef gettext_noop
43 #  define N_(a) gettext_noop (a)
44 # else
45 #  define N_(a) (a)
46 # endif
47 #else
48 # define _(a) (a)
49 # define N_(a) (a)
50 #endif
51
52 #include <gpg-error.h>
53
54 \f
55 #if HAVE_W32_SYSTEM
56 /* The implementation follows below.  */
57 static char *get_locale_dir (void);
58 static void drop_locale_dir (char *locale_dir);
59 #else
60 #define get_locale_dir() LOCALEDIR
61 #define drop_locale_dir(dir)
62 #endif
63
64 static void
65 i18n_init (void)
66 {
67 #ifdef ENABLE_NLS
68   char *locale_dir;
69
70 # ifdef HAVE_LC_MESSAGES
71   setlocale (LC_TIME, "");
72   setlocale (LC_MESSAGES, "");
73 # else
74   setlocale (LC_ALL, "" );
75 # endif
76
77   locale_dir = get_locale_dir ();
78   if (locale_dir)
79     {
80       bindtextdomain (PACKAGE, locale_dir);
81       drop_locale_dir (locale_dir);
82     }
83   textdomain (PACKAGE);
84 #endif
85 }
86
87 \f
88 #ifdef HAVE_W32_SYSTEM
89
90 #include <windows.h>
91
92 static HKEY
93 get_root_key(const char *root)
94 {
95   HKEY root_key;
96
97   if( !root )
98     root_key = HKEY_CURRENT_USER;
99   else if( !strcmp( root, "HKEY_CLASSES_ROOT" ) )
100     root_key = HKEY_CLASSES_ROOT;
101   else if( !strcmp( root, "HKEY_CURRENT_USER" ) )
102     root_key = HKEY_CURRENT_USER;
103   else if( !strcmp( root, "HKEY_LOCAL_MACHINE" ) )
104     root_key = HKEY_LOCAL_MACHINE;
105   else if( !strcmp( root, "HKEY_USERS" ) )
106     root_key = HKEY_USERS;
107   else if( !strcmp( root, "HKEY_PERFORMANCE_DATA" ) )
108     root_key = HKEY_PERFORMANCE_DATA;
109   else if( !strcmp( root, "HKEY_CURRENT_CONFIG" ) )
110     root_key = HKEY_CURRENT_CONFIG;
111   else
112     return NULL;
113   return root_key;
114 }
115
116 /****************
117  * Return a string from the Win32 Registry or NULL in case of
118  * error.  Caller must release the return value.   A NULL for root
119  * is an alias for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn.
120  * NOTE: The value is allocated with a plain malloc() - use free() and not
121  * the usual xfree()!!!
122  */
123 static char *
124 read_w32_registry_string( const char *root, const char *dir, const char *name )
125 {
126   HKEY root_key, key_handle;
127   DWORD n1, nbytes, type;
128   char *result = NULL;
129
130   if ( !(root_key = get_root_key(root) ) )
131     return NULL;
132
133   if( RegOpenKeyEx( root_key, dir, 0, KEY_READ, &key_handle ) )
134     {
135       if (root)
136         return NULL; /* no need for a RegClose, so return direct */
137       /* It seems to be common practise to fall back to HKLM. */
138       if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) )
139         return NULL; /* still no need for a RegClose, so return direct */
140     }
141
142   nbytes = 1;
143   if( RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes ) ) {
144     if (root)
145       goto leave;
146     /* Try to fallback to HKLM also vor a missing value.  */
147     RegCloseKey (key_handle);
148     if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) )
149       return NULL; /* Nope.  */
150     if (RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes))
151       goto leave;
152   }
153   result = malloc( (n1=nbytes+1) );
154   if( !result )
155     goto leave;
156   if( RegQueryValueEx( key_handle, name, 0, &type, result, &n1 ) ) {
157     free(result); result = NULL;
158     goto leave;
159   }
160   result[nbytes] = 0; /* make sure it is really a string  */
161   if (type == REG_EXPAND_SZ && strchr (result, '%')) {
162     char *tmp;
163
164     n1 += 1000;
165     tmp = malloc (n1+1);
166     if (!tmp)
167       goto leave;
168     nbytes = ExpandEnvironmentStrings (result, tmp, n1);
169     if (nbytes && nbytes > n1) {
170       free (tmp);
171       n1 = nbytes;
172       tmp = malloc (n1 + 1);
173       if (!tmp)
174         goto leave;
175       nbytes = ExpandEnvironmentStrings (result, tmp, n1);
176       if (nbytes && nbytes > n1) {
177         free (tmp); /* oops - truncated, better don't expand at all */
178         goto leave;
179       }
180       tmp[nbytes] = 0;
181       free (result);
182       result = tmp;
183     }
184     else if (nbytes) { /* okay, reduce the length */
185       tmp[nbytes] = 0;
186       free (result);
187       result = malloc (strlen (tmp)+1);
188       if (!result)
189         result = tmp;
190       else {
191         strcpy (result, tmp);
192         free (tmp);
193       }
194     }
195     else {  /* error - don't expand */
196       free (tmp);
197     }
198   }
199
200  leave:
201   RegCloseKey( key_handle );
202   return result;
203 }
204
205
206 #define REGKEY "Software\\GNU\\GnuPG"
207
208 static char *
209 get_locale_dir (void)
210 {
211   char *instdir;
212   char *p;
213   char *dname;
214
215   instdir = read_w32_registry_string ("HKEY_LOCAL_MACHINE", REGKEY,
216                                       "Install Directory");
217   if (!instdir)
218     return NULL;
219   
220   /* Build the key: "<instdir>/share/locale".  */
221 #define SLDIR "\\share\\locale"
222   dname = malloc (strlen (instdir) + strlen (SLDIR) + 1);
223   if (!dname)
224     {
225       free (instdir);
226       return NULL;
227     }
228   p = dname;
229   strcpy (p, instdir);
230   p += strlen (instdir);
231   strcpy (p, SLDIR);
232   
233   free (instdir);
234   
235   return dname;
236 }
237
238
239 static void
240 drop_locale_dir (char *locale_dir)
241 {
242   free (locale_dir);
243 }
244
245 #endif  /* HAVE_W32_SYSTEM */
246
247 \f
248 const char *gpg_strerror_sym (gpg_error_t err);
249 const char *gpg_strsource_sym (gpg_error_t err);
250
251 \f
252 static int
253 get_err_from_number (char *str, gpg_error_t *err)
254 {
255   unsigned long nr;
256   char *tail;
257
258   errno = 0;
259   nr = strtoul (str, &tail, 0);
260   if (errno)
261     return 0;
262
263   if (nr > UINT_MAX)
264     return 0;
265
266   if (*tail)
267     {
268       unsigned long cnr = strtoul (tail + 1, &tail, 0);
269       if (errno || *tail)
270         return 0;
271
272       if (nr >= GPG_ERR_SOURCE_DIM || cnr >= GPG_ERR_CODE_DIM)
273         return 0;
274
275       nr = gpg_err_make (nr, cnr);
276     }
277
278   *err = (unsigned int) nr;
279   return 1;
280 }
281
282
283 static int
284 get_err_from_symbol_one (char *str, gpg_error_t *err,
285                          int *have_source, int *have_code)
286 {
287   static const char src_prefix[] = "GPG_ERR_SOURCE_";
288   static const char code_prefix[] = "GPG_ERR_";
289
290   if (!strncasecmp (src_prefix, str, sizeof (src_prefix) - 1))
291     {
292       gpg_err_source_t src;
293
294       if (*have_source)
295         return 0;
296       *have_source = 1;
297       str += sizeof (src_prefix) - 1;
298
299       for (src = 0; src < GPG_ERR_SOURCE_DIM; src++)
300         {
301           const char *src_sym;
302
303           src_sym = gpg_strsource_sym (src << GPG_ERR_SOURCE_SHIFT);
304           if (src_sym && !strcasecmp (str, src_sym + sizeof (src_prefix) - 1))
305             {
306               *err |= src << GPG_ERR_SOURCE_SHIFT;
307               return 1;
308             }
309         }
310     }
311   else if (!strncasecmp (code_prefix, str, sizeof (code_prefix) - 1))
312     {
313       gpg_err_code_t code;
314
315       if (*have_code)
316         return 0;
317       *have_code = 1;
318       str += sizeof (code_prefix) - 1;
319
320       for (code = 0; code < GPG_ERR_CODE_DIM; code++)
321         {
322           const char *code_sym = gpg_strerror_sym (code);
323           if (code_sym
324               && !strcasecmp (str, code_sym + sizeof (code_prefix) - 1))
325             {
326               *err |= code;
327               return 1;
328             }
329         }
330     }
331   return 0;
332 }
333
334
335 static int
336 get_err_from_symbol (char *str, gpg_error_t *err)
337 {
338   char *str2 = str;
339   int have_source = 0;
340   int have_code = 0;
341   int ret;
342   char *saved_pos = NULL;
343   char saved_char;
344
345   *err = 0;
346   while (*str2 && ((*str2 >= 'A' && *str2 <= 'Z')
347                    || (*str2 >= '0' && *str2 <= '9')
348                    || *str2 == '_'))
349     str2++;
350   if (*str2)
351     {
352       saved_pos = str2;
353       saved_char = *str2;
354       *str2 = '\0';
355       str2++;
356     }
357   else
358     str2 = NULL;
359
360   ret = get_err_from_symbol_one (str, err, &have_source, &have_code);
361   if (ret && str2)
362     ret = get_err_from_symbol_one (str2, err, &have_source, &have_code);
363
364   if (saved_pos)
365     *saved_pos = saved_char;
366   return ret;
367 }
368
369
370 static int
371 get_err_from_str_one (char *str, gpg_error_t *err,
372                       int *have_source, int *have_code)
373 {
374   gpg_err_source_t src;
375   gpg_err_code_t code;
376
377   for (src = 0; src < GPG_ERR_SOURCE_DIM; src++)
378     {
379       const char *src_str = gpg_strsource (src << GPG_ERR_SOURCE_SHIFT);
380       if (src_str && !strcasecmp (str, src_str))
381         {
382           if (*have_source)
383             return 0;
384
385           *have_source = 1;
386           *err |= src << GPG_ERR_SOURCE_SHIFT;
387           return 1;
388         }
389     }
390
391   for (code = 0; code < GPG_ERR_CODE_DIM; code++)
392     {
393       const char *code_str = gpg_strerror (code);
394       if (code_str && !strcasecmp (str, code_str))
395         {
396           if (*have_code)
397             return 0;
398           
399           *have_code = 1;
400           *err |= code;
401           return 1;
402         }
403     }
404
405   return 0;
406 }
407
408
409 static int
410 get_err_from_str (char *str, gpg_error_t *err)
411 {
412   char *str2 = str;
413   int have_source = 0;
414   int have_code = 0;
415   int ret;
416   char *saved_pos = NULL;
417   char saved_char;
418
419   *err = 0;
420   ret = get_err_from_str_one (str, err, &have_source, &have_code);
421   if (ret)
422     return ret;
423
424   while (*str2 && ((*str2 >= 'A' && *str2 <= 'Z')
425                    || (*str2 >= 'a' && *str2 <= 'z')
426                    || (*str2 >= '0' && *str2 <= '9')
427                    || *str2 == '_'))
428     str2++;
429   if (*str2)
430     {
431       saved_pos = str2;
432       saved_char = *str2;
433       *((char *) str2) = '\0';
434       str2++;
435       while (*str2 && !((*str2 >= 'A' && *str2 <= 'Z')
436                         || (*str2 >= 'a' && *str2 <= 'z')
437                         || (*str2 >= '0' && *str2 <= '9')
438                         || *str2 == '_'))
439         str2++;
440     }
441   else
442     str2 = NULL;
443
444   ret = get_err_from_str_one (str, err, &have_source, &have_code);
445   if (ret && str2)
446     ret = get_err_from_str_one (str2, err, &have_source, &have_code);
447
448   if (saved_pos)
449     *saved_pos = saved_char;
450   return ret;
451 }
452
453
454 \f
455 int
456 main (int argc, char *argv[])
457 {
458   int i = 1;
459
460 #ifndef GPG_ERR_INITIALIZED
461   gpg_err_init ();
462 #endif
463
464   i18n_init ();
465
466
467   if (argc == 1)
468     {
469       fprintf (stderr, _("Usage: %s GPG-ERROR [...]\n"), 
470                strrchr (argv[0],'/')? (strrchr (argv[0], '/')+1): argv[0]);
471       exit (1);
472     }
473   else if (argc == 2 && !strcmp (argv[1], "--version"))
474     {
475       fputs ("gpg-error (" PACKAGE_NAME ") " PACKAGE_VERSION "\n", stdout);
476       exit (0);
477     }
478
479
480   while (i < argc)
481     {
482       gpg_error_t err;
483
484       if (get_err_from_number (argv[i], &err)
485           || get_err_from_symbol (argv[i], &err)
486           || get_err_from_str (argv[i], &err))
487         {
488           const char *source_sym = gpg_strsource_sym (err);
489           const char *error_sym = gpg_strerror_sym (err);
490           
491           printf ("%u = (%u, %u) = (%s, %s) = (%s, %s)\n",
492                   err, gpg_err_source (err), gpg_err_code (err),
493                   source_sym ? source_sym : "-", error_sym ? error_sym : "-",
494                   gpg_strsource (err), gpg_strerror (err));
495         }
496       else
497         fprintf (stderr, _("%s: warning: could not recognize %s\n"),
498                  argv[0], argv[i]);
499       i++;
500     }
501
502   exit (0);
503 }