LGPL
[vlc.git] / lib / error.c
1 /*****************************************************************************
2  * error.c: Error handling for libvlc
3  *****************************************************************************
4  * Copyright (C) 2009 RĂ©mi Denis-Courmont
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 2.1 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19  *****************************************************************************/
20
21 #include "libvlc_internal.h"
22
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <assert.h>
26 #include <vlc/libvlc.h>
27
28
29 static const char oom[] = "Out of memory";
30 /* TODO: use only one thread-specific key for whole libvlc */
31 static vlc_threadvar_t context;
32
33 static void libvlc_setup_threads (bool init)
34 {
35     static vlc_mutex_t lock = VLC_STATIC_MUTEX;
36     static uintptr_t refs = 0;
37
38     vlc_mutex_lock (&lock);
39     if (init)
40     {
41         if (refs++ == 0)
42             vlc_threadvar_create (&context, free);
43     }
44     else
45     {
46         assert (refs > 0);
47         if (--refs == 0)
48             vlc_threadvar_delete (&context);
49     }
50     vlc_mutex_unlock (&lock);
51 }
52
53 void libvlc_init_threads (void)
54 {
55     libvlc_setup_threads (true);
56 }
57
58 void libvlc_deinit_threads (void)
59 {
60     libvlc_setup_threads (false);
61 }
62
63 static char *get_error (void)
64 {
65     return vlc_threadvar_get (context);
66 }
67
68 static void free_error (void)
69 {
70     char *msg = get_error ();
71     if (msg != oom)
72         free (msg);
73 }
74
75 /**
76  * Gets a human-readable error message for the last LibVLC error in the calling
77  * thread. The resulting string is valid until another error occurs (at least
78  * until the next LibVLC call).
79  *
80  * @return NULL if there was no error, a nul-terminated string otherwise.
81  */
82 const char *libvlc_errmsg (void)
83 {
84     return get_error ();
85 }
86
87 /**
88  * Clears the LibVLC error status for the current thread. This is optional.
89  * By default, the error status is automatically overridden when a new error
90  * occurs, and destroyed when the thread exits.
91  */
92 void libvlc_clearerr (void)
93 {
94     free_error ();
95     vlc_threadvar_set (context, NULL);
96 }
97
98 /**
99  * Sets the LibVLC error status and message for the current thread.
100  * Any previous error is overridden.
101  * @return a nul terminated string (always)
102  */
103 const char *libvlc_vprinterr (const char *fmt, va_list ap)
104 {
105     char *msg;
106
107     assert (fmt != NULL);
108     if (vasprintf (&msg, fmt, ap) == -1)
109         msg = (char *)oom;
110
111     free_error ();
112     vlc_threadvar_set (context, msg);
113     return msg;
114 }
115
116 /**
117  * Sets the LibVLC error status and message for the current thread.
118  * Any previous error is overridden.
119  * @return a nul terminated string (always)
120  */
121 const char *libvlc_printerr (const char *fmt, ...)
122 {
123     va_list ap;
124     const char *msg;
125
126     va_start (ap, fmt);
127     msg = libvlc_vprinterr (fmt, ap);
128     va_end (ap);
129     return msg;
130 }
131