added dbus support
[monky] / src / dbus / dbus-errors.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-errors.c Error reporting
3  *
4  * Copyright (C) 2002, 2004  Red Hat Inc.
5  * Copyright (C) 2003  CodeFactory AB
6  *
7  * Licensed under the Academic Free License version 2.1
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 "dbus-protocol.h"
28 #include <stdarg.h>
29 #include <string.h>
30
31 /**
32  * @defgroup DBusErrorInternals Error reporting internals
33  * @ingroup  DBusInternals
34  * @brief Error reporting internals
35  * @{
36  */
37
38 /**
39  * @def DBUS_ERROR_INIT
40  *
41  * Expands to a suitable initializer for a DBusError on the stack.
42  * Declaring a DBusError with:
43  *
44  * @code
45  * DBusError error = DBUS_ERROR_INIT;
46  *
47  * do_things_with (&error);
48  * @endcode
49  *
50  * is a more concise form of:
51  *
52  * @code
53  * DBusError error;
54  *
55  * dbus_error_init (&error);
56  * do_things_with (&error);
57  * @endcode
58  */
59
60 /**
61  * Internals of DBusError
62  */
63 typedef struct
64 {
65   char *name; /**< error name */
66   char *message; /**< error message */
67
68   unsigned int const_message : 1; /**< Message is not owned by DBusError */
69
70   unsigned int dummy2 : 1; /**< placeholder */
71   unsigned int dummy3 : 1; /**< placeholder */
72   unsigned int dummy4 : 1; /**< placeholder */
73   unsigned int dummy5 : 1; /**< placeholder */
74
75   void *padding1; /**< placeholder */
76   
77 } DBusRealError;
78
79 /**
80  * Returns a longer message describing an error name.
81  * If the error name is unknown, returns the name
82  * itself.
83  *
84  * @param error the error to describe
85  * @returns a constant string describing the error.
86  */
87 static const char*
88 message_from_error (const char *error)
89 {
90   if (strcmp (error, DBUS_ERROR_FAILED) == 0)
91     return "Unknown error";
92   else if (strcmp (error, DBUS_ERROR_NO_MEMORY) == 0)
93     return "Not enough memory available";
94   else if (strcmp (error, DBUS_ERROR_IO_ERROR) == 0)
95     return "Error reading or writing data";
96   else if (strcmp (error, DBUS_ERROR_BAD_ADDRESS) == 0)
97     return "Could not parse address";
98   else if (strcmp (error, DBUS_ERROR_NOT_SUPPORTED) == 0)
99     return "Feature not supported";
100   else if (strcmp (error, DBUS_ERROR_LIMITS_EXCEEDED) == 0)
101     return "Resource limits exceeded";
102   else if (strcmp (error, DBUS_ERROR_ACCESS_DENIED) == 0)
103     return "Permission denied";
104   else if (strcmp (error, DBUS_ERROR_AUTH_FAILED) == 0)
105     return "Could not authenticate to server";
106   else if (strcmp (error, DBUS_ERROR_NO_SERVER) == 0)
107     return "No server available at address";
108   else if (strcmp (error, DBUS_ERROR_TIMEOUT) == 0)
109     return "Connection timed out";
110   else if (strcmp (error, DBUS_ERROR_NO_NETWORK) == 0)
111     return "Network unavailable";
112   else if (strcmp (error, DBUS_ERROR_ADDRESS_IN_USE) == 0)
113     return "Address already in use";
114   else if (strcmp (error, DBUS_ERROR_DISCONNECTED) == 0)
115     return "Disconnected.";
116   else if (strcmp (error, DBUS_ERROR_INVALID_ARGS) == 0)
117     return "Invalid arguments.";
118   else if (strcmp (error, DBUS_ERROR_NO_REPLY) == 0)
119     return "Did not get a reply message.";
120   else if (strcmp (error, DBUS_ERROR_FILE_NOT_FOUND) == 0)
121     return "File doesn't exist.";
122   else if (strcmp (error, DBUS_ERROR_OBJECT_PATH_IN_USE) == 0)
123     return "Object path already in use";
124   else
125     return error;
126 }
127
128 /** @} */ /* End of internals */
129
130 /**
131  * @defgroup DBusErrors Error reporting
132  * @ingroup  DBus
133  * @brief Error reporting
134  *
135  * Types and functions related to reporting errors.
136  *
137  *
138  * In essence D-Bus error reporting works as follows:
139  *
140  * @code
141  * DBusError error;
142  * dbus_error_init (&error);
143  * dbus_some_function (arg1, arg2, &error);
144  * if (dbus_error_is_set (&error))
145  *   {
146  *     fprintf (stderr, "an error occurred: %s\n", error.message);
147  *     dbus_error_free (&error);
148  *   }
149  * @endcode
150  *
151  * By convention, all functions allow #NULL instead of a DBusError*,
152  * so callers who don't care about the error can ignore it.
153  * 
154  * There are some rules. An error passed to a D-Bus function must
155  * always be unset; you can't pass in an error that's already set.  If
156  * a function has a return code indicating whether an error occurred,
157  * and also a #DBusError parameter, then the error will always be set
158  * if and only if the return code indicates an error occurred. i.e.
159  * the return code and the error are never going to disagree.
160  *
161  * An error only needs to be freed if it's been set, not if
162  * it's merely been initialized.
163  *
164  * You can check the specific error that occurred using
165  * dbus_error_has_name().
166  * 
167  * Errors will not be set for programming errors, such as passing
168  * invalid arguments to the libdbus API. Instead, libdbus will print
169  * warnings, exit on a failed assertion, or even crash in those cases
170  * (in other words, incorrect use of the API results in undefined
171  * behavior, possibly accompanied by helpful debugging output if
172  * you're lucky).
173  * 
174  * @{
175  */
176
177 /**
178  * Initializes a DBusError structure. Does not allocate any memory;
179  * the error only needs to be freed if it is set at some point.
180  *
181  * @param error the DBusError.
182  */
183 void
184 dbus_error_init (DBusError *error)
185 {
186   DBusRealError *real;
187
188   _dbus_return_if_fail (error != NULL);
189
190   _dbus_assert (sizeof (DBusError) == sizeof (DBusRealError));
191
192   real = (DBusRealError *)error;
193   
194   real->name = NULL;  
195   real->message = NULL;
196
197   real->const_message = TRUE;
198 }
199
200 /**
201  * Frees an error that's been set (or just initialized),
202  * then reinitializes the error as in dbus_error_init().
203  *
204  * @param error memory where the error is stored.
205  */
206 void
207 dbus_error_free (DBusError *error)
208 {
209   DBusRealError *real;
210
211   _dbus_return_if_fail (error != NULL);
212   
213   real = (DBusRealError *)error;
214
215   if (!real->const_message)
216     {
217       dbus_free (real->name);
218       dbus_free (real->message);
219     }
220
221   dbus_error_init (error);
222 }
223
224 /**
225  * Assigns an error name and message to a DBusError.  Does nothing if
226  * error is #NULL. The message may be #NULL, which means a default
227  * message will be deduced from the name. The default message will be
228  * totally useless, though, so using a #NULL message is not recommended.
229  *
230  * Because this function does not copy the error name or message, you
231  * must ensure the name and message are global data that won't be
232  * freed. You probably want dbus_set_error() instead, in most cases.
233  * 
234  * @param error the error.or #NULL
235  * @param name the error name (not copied!!!)
236  * @param message the error message (not copied!!!)
237  */
238 void
239 dbus_set_error_const (DBusError  *error,
240                       const char *name,
241                       const char *message)
242 {
243   DBusRealError *real;
244
245   _dbus_return_if_error_is_set (error);
246   _dbus_return_if_fail (name != NULL);
247   
248   if (error == NULL)
249     return;
250
251   _dbus_assert (error->name == NULL);
252   _dbus_assert (error->message == NULL);
253
254   if (message == NULL)
255     message = message_from_error (name);
256   
257   real = (DBusRealError *)error;
258   
259   real->name = (char*) name;
260   real->message = (char *)message;
261   real->const_message = TRUE;
262 }
263
264 /**
265  * Moves an error src into dest, freeing src and
266  * overwriting dest. Both src and dest must be initialized.
267  * src is reinitialized to an empty error. dest may not
268  * contain an existing error. If the destination is
269  * #NULL, just frees and reinits the source error.
270  * 
271  * @param src the source error
272  * @param dest the destination error or #NULL
273  */
274 void
275 dbus_move_error (DBusError *src,
276                  DBusError *dest)
277 {
278   _dbus_return_if_error_is_set (dest);
279
280   if (dest)
281     {
282       dbus_error_free (dest);
283       *dest = *src;
284       dbus_error_init (src);
285     }
286   else
287     dbus_error_free (src);
288 }
289
290 /**
291  * Checks whether the error is set and has the given
292  * name.
293  * @param error the error
294  * @param name the name
295  * @returns #TRUE if the given named error occurred
296  */
297 dbus_bool_t
298 dbus_error_has_name (const DBusError *error,
299                      const char      *name)
300 {
301   _dbus_return_val_if_fail (error != NULL, FALSE);
302   _dbus_return_val_if_fail (name != NULL, FALSE);
303
304   _dbus_assert ((error->name != NULL && error->message != NULL) ||
305                 (error->name == NULL && error->message == NULL));
306   
307   if (error->name != NULL)
308     {
309       DBusString str1, str2;
310       _dbus_string_init_const (&str1, error->name);
311       _dbus_string_init_const (&str2, name);
312       return _dbus_string_equal (&str1, &str2);
313     }
314   else
315     return FALSE;
316 }
317
318 /**
319  * Checks whether an error occurred (the error is set).
320  *
321  * @param error the error object
322  * @returns #TRUE if an error occurred
323  */
324 dbus_bool_t
325 dbus_error_is_set (const DBusError *error)
326 {
327   _dbus_return_val_if_fail (error != NULL, FALSE);  
328   _dbus_assert ((error->name != NULL && error->message != NULL) ||
329                 (error->name == NULL && error->message == NULL));
330   return error->name != NULL;
331 }
332
333 /**
334  * Assigns an error name and message to a DBusError.
335  * Does nothing if error is #NULL.
336  *
337  * The format may be #NULL, which means a (pretty much useless)
338  * default message will be deduced from the name. This is not a good
339  * idea, just go ahead and provide a useful error message. It won't
340  * hurt you.
341  *
342  * If no memory can be allocated for the error message, 
343  * an out-of-memory error message will be set instead.
344  *
345  * @param error the error.or #NULL
346  * @param name the error name
347  * @param format printf-style format string.
348  */
349 void
350 dbus_set_error (DBusError  *error,
351                 const char *name,
352                 const char *format,
353                 ...)
354 {
355   DBusRealError *real;
356   DBusString str;
357   va_list args;
358   
359   if (error == NULL)
360     return;
361
362   /* it's a bug to pile up errors */
363   _dbus_return_if_error_is_set (error);
364   _dbus_return_if_fail (name != NULL);
365   
366   _dbus_assert (error->name == NULL);
367   _dbus_assert (error->message == NULL);
368
369   if (!_dbus_string_init (&str))
370     goto nomem;
371   
372   if (format == NULL)
373     {
374       if (!_dbus_string_append (&str,
375                                 message_from_error (name)))
376         {
377           _dbus_string_free (&str);
378           goto nomem;
379         }
380     }
381   else
382     {
383       va_start (args, format);
384       if (!_dbus_string_append_printf_valist (&str, format, args))
385         {
386           _dbus_string_free (&str);
387           va_end (args);
388           goto nomem;
389         }
390       va_end (args);
391     }
392
393   real = (DBusRealError *)error;
394
395   if (!_dbus_string_steal_data (&str, &real->message))
396     {
397       _dbus_string_free (&str);
398       goto nomem;
399     }
400   _dbus_string_free (&str);
401   
402   real->name = _dbus_strdup (name);
403   if (real->name == NULL)
404     {
405       dbus_free (real->message);
406       real->message = NULL;
407       goto nomem;
408     }
409   real->const_message = FALSE;
410
411   return;
412   
413  nomem:
414   _DBUS_SET_OOM (error);
415 }
416
417 /** @} */ /* End public API */