Updating to version 1.13. Libgcrypt depends on libgpg-error
[platform/upstream/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 # ifndef HAVE_W32_SYSTEM
75   setlocale (LC_ALL, "" );
76 # endif
77 #endif
78   
79   /* Note that for this program we would only need the textdomain call
80      because libgpg-error already initializes itself to its locale dir
81      (via gpg_err_init or a constructor).  However this is only done
82      for the static standard locale and thus if the above setlocale
83      calls select a different locale the bindtext below will do
84      something else.  */
85
86   locale_dir = get_locale_dir ();
87   if (locale_dir)
88     {
89       bindtextdomain (PACKAGE, locale_dir);
90       drop_locale_dir (locale_dir);
91     }
92   textdomain (PACKAGE);
93 #endif
94 }
95
96 \f
97 #ifdef HAVE_W32_SYSTEM
98
99 #include <windows.h>
100
101
102 static char *
103 get_locale_dir (void)
104 {
105   static wchar_t moddir[MAX_PATH+5];
106   char *result, *p;
107   int nbytes;
108
109   if (!GetModuleFileNameW (NULL, moddir, MAX_PATH))
110     *moddir = 0;
111
112 #define SLDIR "\\share\\locale"
113   if (*moddir)
114     {
115       nbytes = WideCharToMultiByte (CP_UTF8, 0, moddir, -1, NULL, 0, NULL, NULL);
116       if (nbytes < 0)
117         return NULL;
118       
119       result = malloc (nbytes + strlen (SLDIR) + 1);
120       if (result)
121         {
122           nbytes = WideCharToMultiByte (CP_UTF8, 0, moddir, -1,
123                                         result, nbytes, NULL, NULL);
124           if (nbytes < 0)
125             {
126               free (result);
127               result = NULL;
128             }
129           else
130             {
131               p = strrchr (result, '\\');
132               if (p)
133                 *p = 0;
134               /* If we are installed below "bin" strip that part and
135                  use the top directory instead.  */
136               p = strrchr (result, '\\');
137               if (p && !strcmp (p+1, "bin"))
138                 *p = 0;
139               /* Append the static part.  */
140               strcat (result, SLDIR);
141             }
142         }
143     }
144   else /* Use the old default value.  */
145     {
146       result = malloc (10 + strlen (SLDIR) + 1);
147       if (result)
148         {
149           strcpy (result, "c:\\gnupg");
150           strcat (result, SLDIR);
151         }
152     }  
153 #undef SLDIR  
154   return result;
155 }
156
157
158 static void
159 drop_locale_dir (char *locale_dir)
160 {
161   free (locale_dir);
162 }
163
164 #endif  /* HAVE_W32_SYSTEM */
165
166 \f
167 const char *gpg_strerror_sym (gpg_error_t err);
168 const char *gpg_strsource_sym (gpg_error_t err);
169
170 \f
171 static int
172 get_err_from_number (char *str, gpg_error_t *err)
173 {
174   unsigned long nr;
175   char *tail;
176
177   gpg_err_set_errno (0);
178   nr = strtoul (str, &tail, 0);
179   if (errno)
180     return 0;
181
182   if (nr > UINT_MAX)
183     return 0;
184
185   if (*tail)
186     {
187       unsigned long cnr = strtoul (tail + 1, &tail, 0);
188       if (errno || *tail)
189         return 0;
190
191       if (nr >= GPG_ERR_SOURCE_DIM || cnr >= GPG_ERR_CODE_DIM)
192         return 0;
193
194       nr = gpg_err_make (nr, cnr);
195     }
196
197   *err = (unsigned int) nr;
198   return 1;
199 }
200
201
202 static int
203 get_err_from_symbol_one (char *str, gpg_error_t *err,
204                          int *have_source, int *have_code)
205 {
206   static const char src_prefix[] = "GPG_ERR_SOURCE_";
207   static const char code_prefix[] = "GPG_ERR_";
208
209   if (!strncasecmp (src_prefix, str, sizeof (src_prefix) - 1))
210     {
211       gpg_err_source_t src;
212
213       if (*have_source)
214         return 0;
215       *have_source = 1;
216       str += sizeof (src_prefix) - 1;
217
218       for (src = 0; src < GPG_ERR_SOURCE_DIM; src++)
219         {
220           const char *src_sym;
221
222           src_sym = gpg_strsource_sym (src << GPG_ERR_SOURCE_SHIFT);
223           if (src_sym && !strcasecmp (str, src_sym + sizeof (src_prefix) - 1))
224             {
225               *err |= src << GPG_ERR_SOURCE_SHIFT;
226               return 1;
227             }
228         }
229     }
230   else if (!strncasecmp (code_prefix, str, sizeof (code_prefix) - 1))
231     {
232       gpg_err_code_t code;
233
234       if (*have_code)
235         return 0;
236       *have_code = 1;
237       str += sizeof (code_prefix) - 1;
238
239       for (code = 0; code < GPG_ERR_CODE_DIM; code++)
240         {
241           const char *code_sym = gpg_strerror_sym (code);
242           if (code_sym
243               && !strcasecmp (str, code_sym + sizeof (code_prefix) - 1))
244             {
245               *err |= code;
246               return 1;
247             }
248         }
249     }
250   return 0;
251 }
252
253
254 static int
255 get_err_from_symbol (char *str, gpg_error_t *err)
256 {
257   char *str2 = str;
258   int have_source = 0;
259   int have_code = 0;
260   int ret;
261   char *saved_pos = NULL;
262   char saved_char;
263
264   *err = 0;
265   while (*str2 && ((*str2 >= 'A' && *str2 <= 'Z')
266                    || (*str2 >= '0' && *str2 <= '9')
267                    || *str2 == '_'))
268     str2++;
269   if (*str2)
270     {
271       saved_pos = str2;
272       saved_char = *str2;
273       *str2 = '\0';
274       str2++;
275     }
276   else
277     str2 = NULL;
278
279   ret = get_err_from_symbol_one (str, err, &have_source, &have_code);
280   if (ret && str2)
281     ret = get_err_from_symbol_one (str2, err, &have_source, &have_code);
282
283   if (saved_pos)
284     *saved_pos = saved_char;
285   return ret;
286 }
287
288
289 static int
290 get_err_from_str_one (char *str, gpg_error_t *err,
291                       int *have_source, int *have_code)
292 {
293   gpg_err_source_t src;
294   gpg_err_code_t code;
295
296   for (src = 0; src < GPG_ERR_SOURCE_DIM; src++)
297     {
298       const char *src_str = gpg_strsource (src << GPG_ERR_SOURCE_SHIFT);
299       if (src_str && !strcasecmp (str, src_str))
300         {
301           if (*have_source)
302             return 0;
303
304           *have_source = 1;
305           *err |= src << GPG_ERR_SOURCE_SHIFT;
306           return 1;
307         }
308     }
309
310   for (code = 0; code < GPG_ERR_CODE_DIM; code++)
311     {
312       const char *code_str = gpg_strerror (code);
313       if (code_str && !strcasecmp (str, code_str))
314         {
315           if (*have_code)
316             return 0;
317           
318           *have_code = 1;
319           *err |= code;
320           return 1;
321         }
322     }
323
324   return 0;
325 }
326
327
328 static int
329 get_err_from_str (char *str, gpg_error_t *err)
330 {
331   char *str2 = str;
332   int have_source = 0;
333   int have_code = 0;
334   int ret;
335   char *saved_pos = NULL;
336   char saved_char;
337
338   *err = 0;
339   ret = get_err_from_str_one (str, err, &have_source, &have_code);
340   if (ret)
341     return ret;
342
343   while (*str2 && ((*str2 >= 'A' && *str2 <= 'Z')
344                    || (*str2 >= 'a' && *str2 <= 'z')
345                    || (*str2 >= '0' && *str2 <= '9')
346                    || *str2 == '_'))
347     str2++;
348   if (*str2)
349     {
350       saved_pos = str2;
351       saved_char = *str2;
352       *((char *) str2) = '\0';
353       str2++;
354       while (*str2 && !((*str2 >= 'A' && *str2 <= 'Z')
355                         || (*str2 >= 'a' && *str2 <= 'z')
356                         || (*str2 >= '0' && *str2 <= '9')
357                         || *str2 == '_'))
358         str2++;
359     }
360   else
361     str2 = NULL;
362
363   ret = get_err_from_str_one (str, err, &have_source, &have_code);
364   if (ret && str2)
365     ret = get_err_from_str_one (str2, err, &have_source, &have_code);
366
367   if (saved_pos)
368     *saved_pos = saved_char;
369   return ret;
370 }
371
372
373 \f
374 int
375 main (int argc, char *argv[])
376 {
377   int i = 1;
378   int listmode = 0;
379   const char *source_sym;
380   const char *error_sym;
381   gpg_error_t err;
382
383 #ifndef GPG_ERR_INITIALIZED
384   gpg_err_init ();
385 #endif
386
387   i18n_init ();
388
389
390   if (argc == 1)
391     {
392       fprintf (stderr, _("Usage: %s GPG-ERROR [...]\n"), 
393                strrchr (argv[0],'/')? (strrchr (argv[0], '/')+1): argv[0]);
394       exit (1);
395     }
396   else if (argc == 2 && !strcmp (argv[1], "--version"))
397     {
398       fputs ("gpg-error (" PACKAGE_NAME ") " PACKAGE_VERSION "\n", stdout);
399       exit (0);
400     }
401   else if (argc == 2 && !strcmp (argv[1], "--list"))
402     {
403       listmode = 1;
404     }
405
406
407   if (listmode)
408     {
409       for (i=0; i <  GPG_ERR_SOURCE_DIM; i++)
410         {
411           /* We use error code 1 because gpg_err_make requires a
412              non-zero error code. */
413           err = gpg_err_make (i, 1);
414           err -= 1;
415           source_sym = gpg_strsource_sym (err);
416           if (source_sym)
417             printf ("%u = (%u, -) = (%s, -) = (%s, -)\n",
418                     err, gpg_err_source (err),
419                     source_sym, gpg_strsource (err));
420         }
421       for (i=0; i <  GPG_ERR_CODE_DIM; i++)
422         {
423           err = gpg_err_make (GPG_ERR_SOURCE_UNKNOWN, i);
424           error_sym = gpg_strerror_sym (err);
425           if (error_sym)
426             printf ("%u = (-, %u) = (-, %s) = (-, %s)\n",
427                     err, gpg_err_code (err),
428                     error_sym, gpg_strerror (err));
429         }
430
431       i = argc;  /* Don't run the usual stuff.  */
432     }
433   while (i < argc)
434     {
435       if (get_err_from_number (argv[i], &err)
436           || get_err_from_symbol (argv[i], &err)
437           || get_err_from_str (argv[i], &err))
438         {
439           source_sym = gpg_strsource_sym (err);
440           error_sym = gpg_strerror_sym (err);
441           
442           printf ("%u = (%u, %u) = (%s, %s) = (%s, %s)\n",
443                   err, gpg_err_source (err), gpg_err_code (err),
444                   source_sym ? source_sym : "-", error_sym ? error_sym : "-",
445                   gpg_strsource (err), gpg_strerror (err));
446         }
447       else
448         fprintf (stderr, _("%s: warning: could not recognize %s\n"),
449                  argv[0], argv[i]);
450       i++;
451     }
452
453   exit (0);
454 }