2003-08-12 Havoc Pennington <hp@pobox.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 "dbus-string.h"
27 #include <stdarg.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  * DBusError error;
42  * dbus_error_init (&error);
43  * dbus_some_function (arg1, arg2, &error);
44  * if (dbus_error_is_set (&error))
45  *   {
46  *     fprintf (stderr, "an error occurred: %s\n", error.message);
47  *     dbus_error_free (&error);
48  *   }
49  * @endcode
50  *
51  * There are some rules. An error passed to a D-BUS function must
52  * always be unset; you can't pass in an error that's already set.  If
53  * a function has a return code indicating whether an error occurred,
54  * and also a #DBusError parameter, then the error will always be set
55  * if and only if the return code indicates an error occurred. i.e.
56  * the return code and the error are never going to disagree.
57  *
58  * An error only needs to be freed if it's been set, not if
59  * it's merely been initialized.
60  *
61  * You can check the specific error that occurred using
62  * dbus_error_has_name().
63  * 
64  * @{
65  */
66
67 typedef struct
68 {
69   const char *name; /**< error name */
70   char *message; /**< error message */
71
72   unsigned int const_message : 1; /** Message is not owned by DBusError */
73
74   unsigned int dummy2 : 1; /**< placeholder */
75   unsigned int dummy3 : 1; /**< placeholder */
76   unsigned int dummy4 : 1; /**< placeholder */
77   unsigned int dummy5 : 1; /**< placeholder */
78
79   void *padding1; /**< placeholder */
80   
81 } DBusRealError;
82
83 /**
84  * Returns a longer message describing an error name.
85  * If the error name is unknown, returns the name
86  * itself.
87  *
88  * @param error the error to describe
89  * @returns a constant string describing the error.
90  */
91 static const char*
92 message_from_error (const char *error)
93 {
94   if (strcmp (error, DBUS_ERROR_FAILED) == 0)
95     return "Unknown error";
96   else if (strcmp (error, DBUS_ERROR_NO_MEMORY) == 0)
97     return "Not enough memory available";
98   else if (strcmp (error, DBUS_ERROR_IO_ERROR) == 0)
99     return "Error reading or writing data";
100   else if (strcmp (error, DBUS_ERROR_BAD_ADDRESS) == 0)
101     return "Could not parse address";
102   else if (strcmp (error, DBUS_ERROR_NOT_SUPPORTED) == 0)
103     return "Feature not supported";
104   else if (strcmp (error, DBUS_ERROR_LIMITS_EXCEEDED) == 0)
105     return "Resource limits exceeded";
106   else if (strcmp (error, DBUS_ERROR_ACCESS_DENIED) == 0)
107     return "Permission denied";
108   else if (strcmp (error, DBUS_ERROR_AUTH_FAILED) == 0)
109     return "Could not authenticate to server";
110   else if (strcmp (error, DBUS_ERROR_NO_SERVER) == 0)
111     return "No server available at address";
112   else if (strcmp (error, DBUS_ERROR_TIMEOUT) == 0)
113     return "Connection timed out";
114   else if (strcmp (error, DBUS_ERROR_NO_NETWORK) == 0)
115     return "Network unavailable";
116   else if (strcmp (error, DBUS_ERROR_ADDRESS_IN_USE) == 0)
117     return "Address already in use";
118   else if (strcmp (error, DBUS_ERROR_DISCONNECTED) == 0)
119     return "Disconnected.";
120   else if (strcmp (error, DBUS_ERROR_INVALID_ARGS) == 0)
121     return "Invalid argumemts.";
122   else if (strcmp (error, DBUS_ERROR_NO_REPLY) == 0)
123     return "Did not get a reply message.";
124   else if (strcmp (error, DBUS_ERROR_FILE_NOT_FOUND) == 0)
125     return "File doesn't exist.";
126   else
127     return error;
128 }
129
130 /**
131  * Initializes a DBusError structure. Does not allocate
132  * any memory; the error only needs to be freed
133  * if it is set at some point. 
134  *
135  * @param error the DBusError.
136  */
137 void
138 dbus_error_init (DBusError *error)
139 {
140   DBusRealError *real;
141
142   _dbus_return_if_fail (error != NULL);
143
144   _dbus_assert (sizeof (DBusError) == sizeof (DBusRealError));
145
146   real = (DBusRealError *)error;
147   
148   real->name = NULL;  
149   real->message = NULL;
150
151   real->const_message = TRUE;
152 }
153
154 /**
155  * Frees an error that's been set (or just initialized),
156  * then reinitializes the error as in dbus_error_init().
157  *
158  * @param error memory where the error is stored.
159  */
160 void
161 dbus_error_free (DBusError *error)
162 {
163   DBusRealError *real;
164
165   _dbus_return_if_fail (error != NULL);
166   
167   real = (DBusRealError *)error;
168
169   if (!real->const_message)
170     dbus_free (real->message);
171
172   dbus_error_init (error);
173 }
174
175 /**
176  * Assigns an error name and message to a DBusError.  Does nothing if
177  * error is #NULL. The message may be NULL, which means a default
178  * message will be deduced from the name. If the error name is unknown
179  * to D-BUS the default message will be totally useless, though.
180  *
181  * @todo should be called dbus_error_set_const() 
182  * 
183  * @param error the error.
184  * @param name the error name (not copied!!!)
185  * @param message the error message (not copied!!!)
186  */
187 void
188 dbus_set_error_const (DBusError  *error,
189                       const char *name,
190                       const char *message)
191 {
192   DBusRealError *real;
193
194   _dbus_return_if_error_is_set (error);
195   _dbus_return_if_fail (name != NULL);
196   
197   if (error == NULL)
198     return;
199
200   _dbus_assert (error->name == NULL);
201   _dbus_assert (error->message == NULL);
202
203   if (message == NULL)
204     message = message_from_error (name);
205   
206   real = (DBusRealError *)error;
207   
208   real->name = name;
209   real->message = (char *)message;
210   real->const_message = TRUE;
211 }
212
213 /**
214  * Moves an error src into dest, freeing src and
215  * overwriting dest. Both src and dest must be initialized.
216  * src is reinitialized to an empty error. dest may not
217  * contain an existing error. If the destination is
218  * #NULL, just frees and reinits the source error.
219  * 
220  * @param src the source error
221  * @param dest the destination error or #NULL
222  */
223 void
224 dbus_move_error (DBusError *src,
225                  DBusError *dest)
226 {
227   _dbus_return_if_error_is_set (dest);
228
229   if (dest)
230     {
231       dbus_error_free (dest);
232       *dest = *src;
233       dbus_error_init (src);
234     }
235   else
236     dbus_error_free (src);
237 }
238
239 /**
240  * Checks whether the error is set and has the given
241  * name.
242  * @param error the error
243  * @param name the name
244  * @returns #TRUE if the given named error occurred
245  */
246 dbus_bool_t
247 dbus_error_has_name (const DBusError *error,
248                      const char      *name)
249 {
250   _dbus_return_val_if_fail (error != NULL, FALSE);
251   _dbus_return_val_if_fail (name != NULL, FALSE);
252
253   _dbus_assert ((error->name != NULL && error->message != NULL) ||
254                 (error->name == NULL && error->message == NULL));
255   
256   if (error->name != NULL)
257     {
258       DBusString str1, str2;
259       _dbus_string_init_const (&str1, error->name);
260       _dbus_string_init_const (&str2, name);
261       return _dbus_string_equal (&str1, &str2);
262     }
263   else
264     return FALSE;
265 }
266
267 /**
268  * Checks whether an error occurred (the error is set).
269  *
270  * @param error the error object
271  * @returns #TRUE if an error occurred
272  */
273 dbus_bool_t
274 dbus_error_is_set (const DBusError *error)
275 {
276   _dbus_return_val_if_fail (error != NULL, FALSE);  
277   _dbus_assert ((error->name != NULL && error->message != NULL) ||
278                 (error->name == NULL && error->message == NULL));
279   return error->name != NULL;
280 }
281
282 /**
283  * Assigns an error name and message to a DBusError.
284  * Does nothing if error is #NULL.
285  *
286  * The format may be NULL, which means a default message will be
287  * deduced from the name. If the error name is unknown to D-BUS the
288  * default message will be totally useless, though.
289  *
290  * If no memory can be allocated for the error message, 
291  * an out-of-memory error message will be set instead.
292  *
293  * @todo should be called dbus_error_set()
294  *
295  * @param error the error.
296  * @param name the error name (not copied!!!)
297  * @param format printf-style format string.
298  */
299 void
300 dbus_set_error (DBusError  *error,
301                 const char *name,
302                 const char *format,
303                 ...)
304 {
305   DBusRealError *real;
306   DBusString str;
307   va_list args;
308   
309   if (error == NULL)
310     return;
311
312   /* it's a bug to pile up errors */
313   _dbus_return_if_error_is_set (error);
314   _dbus_return_if_fail (name != NULL);
315   
316   _dbus_assert (error->name == NULL);
317   _dbus_assert (error->message == NULL);
318
319   if (!_dbus_string_init (&str))
320     goto nomem;
321   
322   if (format == NULL)
323     {
324       if (!_dbus_string_append (&str,
325                                 message_from_error (name)))
326         {
327           _dbus_string_free (&str);
328           goto nomem;
329         }
330     }
331   else
332     {
333       va_start (args, format);
334       if (!_dbus_string_append_printf_valist (&str, format, args))
335         {
336           _dbus_string_free (&str);
337           goto nomem;
338         }
339       va_end (args);
340     }
341
342   real = (DBusRealError *)error;
343
344   if (!_dbus_string_steal_data (&str, &real->message))
345     {
346       _dbus_string_free (&str);
347       goto nomem;
348     }
349   
350   real->name = name;
351   real->const_message = FALSE;
352
353   _dbus_string_free (&str);
354
355   return;
356   
357  nomem:
358   dbus_set_error_const (error, DBUS_ERROR_NO_MEMORY, NULL);      
359 }
360
361 /** @} */