2003-04-27 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 <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  * 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  * @param error the error.
182  * @param name the error name (not copied!!!)
183  * @param message the error message (not copied!!!)
184  */
185 void
186 dbus_set_error_const (DBusError  *error,
187                       const char *name,
188                       const char *message)
189 {
190   DBusRealError *real;
191
192   _dbus_return_if_error_is_set (error);
193   _dbus_return_if_fail (name != NULL);
194   
195   if (error == NULL)
196     return;
197
198   _dbus_assert (error->name == NULL);
199   _dbus_assert (error->message == NULL);
200
201   if (message == NULL)
202     message = message_from_error (name);
203   
204   real = (DBusRealError *)error;
205   
206   real->name = name;
207   real->message = (char *)message;
208   real->const_message = TRUE;
209 }
210
211 /**
212  * Moves an error src into dest, freeing src and
213  * overwriting dest. Both src and dest must be initialized.
214  * src is reinitialized to an empty error. dest may not
215  * contain an existing error. If the destination is
216  * #NULL, just frees and reinits the source error.
217  *
218  * @param src the source error
219  * @param dest the destination error or #NULL
220  */
221 void
222 dbus_move_error (DBusError *src,
223                  DBusError *dest)
224 {
225   _dbus_return_if_error_is_set (dest);
226
227   if (dest)
228     {
229       dbus_error_free (dest);
230       *dest = *src;
231       dbus_error_init (src);
232     }
233   else
234     dbus_error_free (src);
235 }
236
237 /**
238  * Checks whether the error is set and has the given
239  * name.
240  * @param error the error
241  * @param name the name
242  * @returns #TRUE if the given named error occurred
243  */
244 dbus_bool_t
245 dbus_error_has_name (const DBusError *error,
246                      const char      *name)
247 {
248   _dbus_return_val_if_fail (error != NULL, FALSE);
249   _dbus_return_val_if_fail (name != NULL, FALSE);
250
251   _dbus_assert ((error->name != NULL && error->message != NULL) ||
252                 (error->name == NULL && error->message == NULL));
253   
254   if (error->name != NULL)
255     {
256       DBusString str1, str2;
257       _dbus_string_init_const (&str1, error->name);
258       _dbus_string_init_const (&str2, name);
259       return _dbus_string_equal (&str1, &str2);
260     }
261   else
262     return FALSE;
263 }
264
265 /**
266  * Checks whether an error occurred (the error is set).
267  *
268  * @param error the error object
269  * @returns #TRUE if an error occurred
270  */
271 dbus_bool_t
272 dbus_error_is_set (const DBusError *error)
273 {
274   _dbus_return_val_if_fail (error != NULL, FALSE);  
275   _dbus_assert ((error->name != NULL && error->message != NULL) ||
276                 (error->name == NULL && error->message == NULL));
277   return error->name != NULL;
278 }
279
280 /**
281  * Assigns an error name and message to a DBusError.
282  * Does nothing if error is #NULL.
283  *
284  * The format may be NULL, which means a default message will be
285  * deduced from the name. If the error name is unknown to D-BUS the
286  * default message will be totally useless, though.
287  *
288  * If no memory can be allocated for the error message, 
289  * an out-of-memory error message will be set instead.
290  *
291  * @todo stdio.h shouldn't be included in this file,
292  * should write _dbus_string_append_printf instead
293  * 
294  * @param error the error.
295  * @param name the error name (not copied!!!)
296  * @param format printf-style format string.
297  */
298 void
299 dbus_set_error (DBusError  *error,
300                 const char *name,
301                 const char *format,
302                 ...)
303 {
304   DBusRealError *real;
305   va_list args;
306   int message_length;
307   char *message;
308   char c;
309
310   if (error == NULL)
311     return;
312
313   /* it's a bug to pile up errors */
314   _dbus_return_if_error_is_set (error);
315   _dbus_return_if_fail (name != NULL);
316   
317   _dbus_assert (error->name == NULL);
318   _dbus_assert (error->message == NULL);
319
320   if (format == NULL)
321     format = message_from_error (name);
322   
323   va_start (args, format);
324   /* Measure the message length */
325   message_length = vsnprintf (&c, 1, format, args) + 1;
326   va_end (args);
327   
328   message = dbus_malloc (message_length);
329   
330   if (!message)
331     {
332       dbus_set_error_const (error, DBUS_ERROR_NO_MEMORY, NULL);
333       return;
334     }
335   
336   va_start (args, format);  
337   vsprintf (message, format, args);  
338   va_end (args);
339
340   real = (DBusRealError *)error;
341   
342   real->name = name;
343   real->message = message;
344   real->const_message = FALSE;
345 }
346
347 /** @} */