Updating to version 1.13. Libgcrypt depends on libgpg-error
[platform/upstream/libgpg-error.git] / src / strerror.c
1 /* strerror.c - Describing an error code.
2    Copyright (C) 2003 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 <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <errno.h>
29
30 #include <gpg-error.h>
31
32 #include "gettext.h"
33 #include "err-codes.h"
34
35 /* Return a pointer to a string containing a description of the error
36    code in the error value ERR.  This function is not thread-safe.  */
37 const char *
38 gpg_strerror (gpg_error_t err)
39 {
40   gpg_err_code_t code = gpg_err_code (err);
41
42   if (code & GPG_ERR_SYSTEM_ERROR)
43     {
44       int no = gpg_err_code_to_errno (code);
45       if (no)
46         return strerror (no);
47       else
48         code = GPG_ERR_UNKNOWN_ERRNO;
49     }
50   return dgettext (PACKAGE, msgstr + msgidx[msgidxof (code)]);
51 }
52
53
54 #ifdef HAVE_STRERROR_R
55 #ifdef STRERROR_R_CHAR_P
56 /* The GNU C library and probably some other systems have this weird
57    variant of strerror_r.  */
58
59 /* Return a dynamically allocated string in *STR describing the system
60    error NO.  If this call succeeds, return 1.  If this call fails due
61    to a resource shortage, set *STR to NULL and return 1.  If this
62    call fails because the error number is not valid, don't set *STR
63    and return 0.  */
64 static int
65 system_strerror_r (int no, char *buf, size_t buflen)
66 {
67   char *errstr;
68
69   errstr = strerror_r (no, buf, buflen);
70   if (errstr != buf)
71     {
72       size_t errstr_len = strlen (errstr) + 1;
73       size_t cpy_len = errstr_len < buflen ? errstr_len : buflen;
74       memcpy (buf, errstr, cpy_len);
75
76       return cpy_len == errstr_len ? 0 : ERANGE;
77     }
78   else
79     {
80       /* We can not tell if the buffer was large enough, but we can
81          try to make a guess.  */
82       if (strlen (buf) + 1 >= buflen)
83         return ERANGE;
84
85       return 0;
86     }
87 }
88
89 #else   /* STRERROR_R_CHAR_P */
90 /* Now the POSIX version.  */
91
92 static int
93 system_strerror_r (int no, char *buf, size_t buflen)
94 {
95   return strerror_r (no, buf, buflen);
96 }
97
98 #endif  /* STRERROR_R_CHAR_P */
99
100 #else   /* HAVE_STRERROR_H */
101 /* Without strerror_r(), we can still provide a non-thread-safe
102    version.  Maybe we are even lucky and the system's strerror() is
103    already thread-safe.  */
104
105 static int
106 system_strerror_r (int no, char *buf, size_t buflen)
107 {
108   char *errstr = strerror (no);
109
110   if (!errstr)
111     {
112       int saved_errno = errno;
113
114       if (saved_errno != EINVAL)
115         snprintf (buf, buflen, "strerror failed: %i\n", errno);
116       return saved_errno;
117     }
118   else
119     {
120       size_t errstr_len = strlen (errstr) + 1;
121       size_t cpy_len = errstr_len < buflen ? errstr_len : buflen;
122       memcpy (buf, errstr, cpy_len);
123       return cpy_len == errstr_len ? 0 : ERANGE;
124     }
125 }
126 #endif
127
128
129 /* Return the error string for ERR in the user-supplied buffer BUF of
130    size BUFLEN.  This function is, in contrast to gpg_strerror,
131    thread-safe if a thread-safe strerror_r() function is provided by
132    the system.  If the function succeeds, 0 is returned and BUF
133    contains the string describing the error.  If the buffer was not
134    large enough, ERANGE is returned and BUF contains as much of the
135    beginning of the error string as fits into the buffer.  */
136 int
137 gpg_strerror_r (gpg_error_t err, char *buf, size_t buflen)
138 {
139   gpg_err_code_t code = gpg_err_code (err);
140   const char *errstr;
141   size_t errstr_len;
142   size_t cpy_len;
143
144   if (code & GPG_ERR_SYSTEM_ERROR)
145     {
146       int no = gpg_err_code_to_errno (code);
147       if (no)
148         {
149           int system_err = system_strerror_r (no, buf, buflen);
150
151           if (system_err != EINVAL)
152             {
153               if (buflen)
154                 buf[buflen - 1] = '\0';
155               return system_err;
156             }
157         }
158       code = GPG_ERR_UNKNOWN_ERRNO;
159     }
160
161   errstr = dgettext (PACKAGE, msgstr + msgidx[msgidxof (code)]);
162   errstr_len = strlen (errstr) + 1;
163   cpy_len = errstr_len < buflen ? errstr_len : buflen;
164   memcpy (buf, errstr, cpy_len);
165   if (buflen)
166     buf[buflen - 1] = '\0';
167
168   return cpy_len == errstr_len ? 0 : ERANGE;
169 }