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 55#if HAVE_W32_SYSTEM 56/* The implementation follows below. */ 57static char *get_locale_dir (void); 58static void drop_locale_dir (char *locale_dir); 59#else 60#define get_locale_dir() LOCALEDIR 61#define drop_locale_dir(dir) 62#endif 63 64static void 65i18n_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 97#ifdef HAVE_W32_SYSTEM 98 99#include <windows.h> 100 101 102static char * 103get_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 158static void 159drop_locale_dir (char *locale_dir) 160{ 161 free (locale_dir); 162} 163 164#endif /* HAVE_W32_SYSTEM */ 165 166 167const char *gpg_strerror_sym (gpg_error_t err); 168const char *gpg_strsource_sym (gpg_error_t err); 169 170 171static int 172get_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 202static int 203get_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 254static int 255get_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 289static int 290get_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 328static int 329get_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 374int 375main (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} 455