2003-03-24 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / dbus / dbus-errors.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-errors.c Error reporting
3  *
4  * Copyright (C) 2002  Red Hat Inc.
5  * Copyright (C) 2003  CodeFactory AB
6  *
7  * Licensed under the Academic Free License version 1.2
8  * 
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  * 
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  */
24 #include "dbus-errors.h"
25 #include "dbus-internals.h"
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <string.h>
29
30 /**
31  * @defgroup DBusErrors Error reporting
32  * @ingroup  DBus
33  * @brief Error reporting
34  *
35  * Types and functions related to reporting errors.
36  *
37  *
38  * In essence D-BUS error reporting works as follows:
39  *
40  * @code
41  * DBusResultCode result = DBUS_RESULT_SUCCESS;
42  * dbus_some_function (arg1, arg2, &result);
43  * if (result != DBUS_RESULT_SUCCESS)
44  *   printf ("an error occurred\n");
45  * @endcode
46  *
47  * @todo add docs with DBusError
48  * 
49  * @{
50  */
51
52 typedef struct
53 {
54   const char *name; /**< error name */
55   char *message; /**< error message */
56
57   unsigned int const_message : 1; /** Message is not owned by DBusError */
58
59   unsigned int dummy2 : 1; /**< placeholder */
60   unsigned int dummy3 : 1; /**< placeholder */
61   unsigned int dummy4 : 1; /**< placeholder */
62   unsigned int dummy5 : 1; /**< placeholder */
63
64   void *padding1; /**< placeholder */
65   
66 } DBusRealError;
67
68 /**
69  * Returns a longer message describing an error name.
70  * If the error name is unknown, returns the name
71  * itself.
72  *
73  * @param error the error to describe
74  * @returns a constant string describing the error.
75  */
76 static const char*
77 message_from_error (const char *error)
78 {
79   if (strcmp (error, DBUS_ERROR_FAILED) == 0)
80     return "Unknown error";
81   else if (strcmp (error, DBUS_ERROR_NO_MEMORY) == 0)
82     return "Not enough memory available";
83   else if (strcmp (error, DBUS_ERROR_IO_ERROR) == 0)
84     return "Error reading or writing data";
85   else if (strcmp (error, DBUS_ERROR_BAD_ADDRESS) == 0)
86     return "Could not parse address";
87   else if (strcmp (error, DBUS_ERROR_NOT_SUPPORTED) == 0)
88     return "Feature not supported";
89   else if (strcmp (error, DBUS_ERROR_LIMITS_EXCEEDED) == 0)
90     return "Resource limits exceeded";
91   else if (strcmp (error, DBUS_ERROR_ACCESS_DENIED) == 0)
92     return "Permission denied";
93   else if (strcmp (error, DBUS_ERROR_AUTH_FAILED) == 0)
94     return "Could not authenticate to server";
95   else if (strcmp (error, DBUS_ERROR_NO_SERVER) == 0)
96     return "No server";
97   else if (strcmp (error, DBUS_ERROR_TIMEOUT) == 0)
98     return "Connection timed out";
99   else if (strcmp (error, DBUS_ERROR_NO_NETWORK) == 0)
100     return "Network unavailable";
101   else if (strcmp (error, DBUS_ERROR_ADDRESS_IN_USE) == 0)
102     return "Address already in use";
103   else if (strcmp (error, DBUS_ERROR_DISCONNECTED) == 0)
104     return "Disconnected.";
105   else if (strcmp (error, DBUS_ERROR_INVALID_ARGS) == 0)
106     return "Invalid argumemts.";
107   else if (strcmp (error, DBUS_ERROR_NO_REPLY) == 0)
108     return "Did not get a reply message.";
109   else if (strcmp (error, DBUS_ERROR_FILE_NOT_FOUND) == 0)
110     return "File doesn't exist.";
111   else
112     return error;
113 }
114
115 /**
116  * Initializes a DBusError structure. Does not allocate
117  * any memory; the error only needs to be freed
118  * if it is set at some point. 
119  *
120  * @param error the DBusError.
121  */
122 void
123 dbus_error_init (DBusError *error)
124 {
125   DBusRealError *real;
126
127   _dbus_assert (error != NULL);
128
129   _dbus_assert (sizeof (DBusError) == sizeof (DBusRealError));
130
131   real = (DBusRealError *)error;
132   
133   real->name = NULL;  
134   real->message = NULL;
135
136   real->const_message = TRUE;
137 }
138
139 /**
140  * Frees an error that's been set (or just initialized),
141  * then reinitializes the error as in dbus_error_init().
142  *
143  * @param error memory where the error is stored.
144  */
145 void
146 dbus_error_free (DBusError *error)
147 {
148   DBusRealError *real;
149
150   real = (DBusRealError *)error;
151
152   if (!real->const_message)
153     dbus_free (real->message);
154
155   dbus_error_init (error);
156 }
157
158 /**
159  * Assigns an error name and message to a DBusError.
160  * Does nothing if error is #NULL. The message may
161  * be NULL only if the error is DBUS_ERROR_NO_MEMORY.
162  *
163  * @param error the error.
164  * @param name the error name (not copied!!!)
165  * @param message the error message (not copied!!!)
166  */
167 void
168 dbus_set_error_const (DBusError  *error,
169                       const char *name,
170                       const char *message)
171 {
172   DBusRealError *real;
173
174   if (error == NULL)
175     return;
176
177   /* it's a bug to pile up errors */
178   _dbus_assert (error->name == NULL);
179   _dbus_assert (error->message == NULL);
180   _dbus_assert (name != NULL);
181
182   if (message == NULL)
183     message = message_from_error (name);
184   
185   real = (DBusRealError *)error;
186   
187   real->name = name;
188   real->message = (char *)message;
189   real->const_message = TRUE;
190 }
191
192 /**
193  * Moves an error src into dest, freeing src and
194  * overwriting dest. Both src and dest must be initialized.
195  * src is reinitialized to an empty error. dest may not
196  * contain an existing error. If the destination is
197  * #NULL, just frees and reinits the source error.
198  *
199  * @param src the source error
200  * @param dest the destination error or #NULL
201  */
202 void
203 dbus_move_error (DBusError *src,
204                  DBusError *dest)
205 {
206   _dbus_assert (!dbus_error_is_set (dest));
207
208   if (dest)
209     {
210       dbus_error_free (dest);
211       *dest = *src;
212       dbus_error_init (src);
213     }
214   else
215     dbus_error_free (src);
216 }
217
218 /**
219  * Checks whether the error is set and has the given
220  * name.
221  * @param error the error
222  * @param name the name
223  * @returns #TRUE if the given named error occurred
224  */
225 dbus_bool_t
226 dbus_error_has_name (const DBusError *error,
227                      const char      *name)
228 {
229   _dbus_assert (error != NULL);
230   _dbus_assert (name != NULL);
231   _dbus_assert ((error->name != NULL && error->message != NULL) ||
232                 (error->name == NULL && error->message == NULL));
233   
234   if (error->name != NULL)
235     {
236       DBusString str1, str2;
237       _dbus_string_init_const (&str1, error->name);
238       _dbus_string_init_const (&str2, name);
239       return _dbus_string_equal (&str1, &str2);
240     }
241   else
242     return FALSE;
243 }
244
245 /**
246  * Checks whether an error occurred (the error is set).
247  *
248  * @param error the error object
249  * @returns #TRUE if an error occurred
250  */
251 dbus_bool_t
252 dbus_error_is_set (const DBusError *error)
253 {
254   _dbus_assert (error != NULL);  
255   _dbus_assert ((error->name != NULL && error->message != NULL) ||
256                 (error->name == NULL && error->message == NULL));
257   return error->name != NULL;
258 }
259
260 /**
261  * Assigns an error name and message to a DBusError.
262  * Does nothing if error is #NULL.
263  *
264  * The format may be NULL only if the error is DBUS_ERROR_NO_MEMORY.
265  *
266  * If no memory can be allocated for the error message, 
267  * an out-of-memory error message will be set instead.
268  *
269  * @todo stdio.h shouldn't be included in this file,
270  * should write _dbus_string_append_printf instead
271  * 
272  * @param error the error.
273  * @param name the error name (not copied!!!)
274  * @param format printf-style format string.
275  */
276 void
277 dbus_set_error (DBusError  *error,
278                 const char *name,
279                 const char *format,
280                 ...)
281 {
282   DBusRealError *real;
283   va_list args;
284   int message_length;
285   char *message;
286   char c;
287
288   if (error == NULL)
289     return;
290
291   /* it's a bug to pile up errors */
292   _dbus_assert (error->name == NULL);
293   _dbus_assert (error->message == NULL);
294   _dbus_assert (name != NULL);
295
296   if (format == NULL)
297     format = message_from_error (name);
298   
299   va_start (args, format);
300   /* Measure the message length */
301   message_length = vsnprintf (&c, 1, format, args) + 1;
302   va_end (args);
303   
304   message = dbus_malloc (message_length);
305   
306   if (!message)
307     {
308       dbus_set_error_const (error, DBUS_ERROR_NO_MEMORY, NULL);
309       return;
310     }
311   
312   va_start (args, format);  
313   vsprintf (message, format, args);  
314   va_end (args);
315
316   real = (DBusRealError *)error;
317   
318   real->name = name;
319   real->message = message;
320   real->const_message = FALSE;
321 }
322
323 /** @} */