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