Don't use <envar> in docs
[platform/upstream/glib.git] / glib / glib-init.c
1 /*
2  * Copyright © 2011 Canonical Limited
3  *
4  * This library is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * licence, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
16  *
17  * Author: Ryan Lortie <desrt@desrt.ca>
18  */
19
20 #include "config.h"
21
22 #include "glib-init.h"
23
24 #include "glib-private.h"
25 #include "gtypes.h"
26 #include "gutils.h"     /* for GDebugKey */
27 #include "gconstructor.h"
28 #include "gmem.h"       /* for g_mem_gc_friendly */
29
30 #include <string.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <ctype.h>
34
35 /* This seems as good a place as any to make static assertions about platform
36  * assumptions we make throughout GLib. */
37
38 /* We assume that data pointers are the same size as function pointers... */
39 G_STATIC_ASSERT (sizeof (gpointer) == sizeof (GFunc));
40 G_STATIC_ASSERT (_g_alignof (gpointer) == _g_alignof (GFunc));
41 /* ... and that all function pointers are the same size. */
42 G_STATIC_ASSERT (sizeof (GFunc) == sizeof (GCompareDataFunc));
43 G_STATIC_ASSERT (_g_alignof (GFunc) == _g_alignof (GCompareDataFunc));
44
45 /**
46  * g_mem_gc_friendly:
47  *
48  * This variable is %TRUE if the `G_DEBUG` environment variable
49  * includes the key <literal>gc-friendly</literal>.
50  */
51 #ifdef ENABLE_GC_FRIENDLY_DEFAULT
52 gboolean g_mem_gc_friendly = TRUE;
53 #else
54 gboolean g_mem_gc_friendly = FALSE;
55 #endif
56 GLogLevelFlags g_log_msg_prefix = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_WARNING |
57                                   G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_DEBUG;
58 GLogLevelFlags g_log_always_fatal = G_LOG_FATAL_MASK;
59
60 static gboolean
61 debug_key_matches (const gchar *key,
62                    const gchar *token,
63                    guint        length)
64 {
65   /* may not call GLib functions: see note in g_parse_debug_string() */
66   for (; length; length--, key++, token++)
67     {
68       char k = (*key   == '_') ? '-' : tolower (*key  );
69       char t = (*token == '_') ? '-' : tolower (*token);
70
71       if (k != t)
72         return FALSE;
73     }
74
75   return *key == '\0';
76 }
77
78 /**
79  * g_parse_debug_string:
80  * @string: (allow-none): a list of debug options separated by colons, spaces, or
81  * commas, or %NULL.
82  * @keys: (array length=nkeys): pointer to an array of #GDebugKey which associate
83  *     strings with bit flags.
84  * @nkeys: the number of #GDebugKeys in the array.
85  *
86  * Parses a string containing debugging options
87  * into a %guint containing bit flags. This is used
88  * within GDK and GTK+ to parse the debug options passed on the
89  * command line or through environment variables.
90  *
91  * If @string is equal to "all", all flags are set. Any flags
92  * specified along with "all" in @string are inverted; thus,
93  * "all,foo,bar" or "foo,bar,all" sets all flags except those
94  * corresponding to "foo" and "bar".
95  *
96  * If @string is equal to "help", all the available keys in @keys
97  * are printed out to standard error.
98  *
99  * Returns: the combined set of bit flags.
100  */
101 guint
102 g_parse_debug_string  (const gchar     *string,
103                        const GDebugKey *keys,
104                        guint            nkeys)
105 {
106   guint i;
107   guint result = 0;
108
109   if (string == NULL)
110     return 0;
111
112   /* this function is used during the initialisation of gmessages, gmem
113    * and gslice, so it may not do anything that causes memory to be
114    * allocated or risks messages being emitted.
115    *
116    * this means, more or less, that this code may not call anything
117    * inside GLib.
118    */
119
120   if (!strcasecmp (string, "help"))
121     {
122       /* using stdio directly for the reason stated above */
123       fprintf (stderr, "Supported debug values:");
124       for (i = 0; i < nkeys; i++)
125        fprintf (stderr, " %s", keys[i].key);
126       fprintf (stderr, " all help\n");
127     }
128   else
129     {
130       const gchar *p = string;
131       const gchar *q;
132       gboolean invert = FALSE;
133
134       while (*p)
135        {
136          q = strpbrk (p, ":;, \t");
137          if (!q)
138            q = p + strlen (p);
139
140          if (debug_key_matches ("all", p, q - p))
141            {
142              invert = TRUE;
143            }
144          else
145            {
146              for (i = 0; i < nkeys; i++)
147                if (debug_key_matches (keys[i].key, p, q - p))
148                  result |= keys[i].value;
149            }
150
151          p = q;
152          if (*p)
153            p++;
154        }
155
156       if (invert)
157         {
158           guint all_flags = 0;
159
160           for (i = 0; i < nkeys; i++)
161             all_flags |= keys[i].value;
162
163           result = all_flags & (~result);
164         }
165     }
166
167   return result;
168 }
169
170 static guint
171 g_parse_debug_envvar (const gchar     *envvar,
172                       const GDebugKey *keys,
173                       gint             n_keys,
174                       guint            default_value)
175 {
176   const gchar *value;
177
178 #ifdef OS_WIN32
179   /* "fatal-warnings,fatal-criticals,all,help" is pretty short */
180   gchar buffer[100];
181
182   if (GetEnvironmentVariable (envvar, buffer, 100) < 100)
183     value = buffer;
184   else
185     return 0;
186 #else
187   value = getenv (envvar);
188 #endif
189
190   if (value == NULL)
191     return default_value;
192
193   return g_parse_debug_string (value, keys, n_keys);
194 }
195
196 static void
197 g_messages_prefixed_init (void)
198 {
199   const GDebugKey keys[] = {
200     { "error", G_LOG_LEVEL_ERROR },
201     { "critical", G_LOG_LEVEL_CRITICAL },
202     { "warning", G_LOG_LEVEL_WARNING },
203     { "message", G_LOG_LEVEL_MESSAGE },
204     { "info", G_LOG_LEVEL_INFO },
205     { "debug", G_LOG_LEVEL_DEBUG }
206   };
207
208   g_log_msg_prefix = g_parse_debug_envvar ("G_MESSAGES_PREFIXED", keys, G_N_ELEMENTS (keys), g_log_msg_prefix);
209 }
210
211 static void
212 g_debug_init (void)
213 {
214   const GDebugKey keys[] = {
215     { "gc-friendly", 1 },
216     {"fatal-warnings",  G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL },
217     {"fatal-criticals", G_LOG_LEVEL_CRITICAL }
218   };
219   GLogLevelFlags flags;
220
221   flags = g_parse_debug_envvar ("G_DEBUG", keys, G_N_ELEMENTS (keys), 0);
222
223   g_log_always_fatal |= flags & G_LOG_LEVEL_MASK;
224
225   g_mem_gc_friendly = flags & 1;
226 }
227
228 static void
229 glib_init (void)
230 {
231   g_messages_prefixed_init ();
232   g_debug_init ();
233 }
234
235 #if defined (G_OS_WIN32)
236
237 BOOL WINAPI DllMain (HINSTANCE hinstDLL,
238                      DWORD     fdwReason,
239                      LPVOID    lpvReserved);
240
241 HMODULE glib_dll;
242
243 BOOL WINAPI
244 DllMain (HINSTANCE hinstDLL,
245          DWORD     fdwReason,
246          LPVOID    lpvReserved)
247 {
248   switch (fdwReason)
249     {
250     case DLL_PROCESS_ATTACH:
251       glib_dll = hinstDLL;
252       g_clock_win32_init ();
253 #ifdef THREADS_WIN32
254       g_thread_win32_init ();
255 #endif
256       glib_init ();
257       break;
258
259     case DLL_THREAD_DETACH:
260 #ifdef THREADS_WIN32
261       g_thread_win32_thread_detach ();
262 #endif
263       break;
264
265     default:
266       /* do nothing */
267       ;
268     }
269
270   return TRUE;
271 }
272
273 #elif defined (G_HAS_CONSTRUCTORS)
274
275 #ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA
276 #pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(glib_init_ctor)
277 #endif
278 G_DEFINE_CONSTRUCTOR(glib_init_ctor)
279
280 static void
281 glib_init_ctor (void)
282 {
283   glib_init ();
284 }
285
286 #else
287 # error Your platform/compiler is missing constructor support
288 #endif