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