1/*
2 * Copyright © 2011 Canonical Limited
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, 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#include "gmacros.h"
24#include "gtypes.h"
25#include "gutils.h" /* for GDebugKey */
26#include "gconstructor.h"
27#include "gmem.h" /* for g_mem_gc_friendly */
28
29#include <string.h>
30#include <stdlib.h>
31#include <stdio.h>
32#include <ctype.h>
33
34/* Deliberately not checking HAVE_STDINT_H here: we officially require a
35 * C99 toolchain, which implies <stdint.h>, int8_t and so on. If your
36 * toolchain does not have this, now would be a good time to upgrade. */
37#include <stdint.h>
38
39/* This seems as good a place as any to make static assertions about platform
40 * assumptions we make throughout GLib. */
41
42/* We do not support 36-bit bytes or other historical curiosities. */
43G_STATIC_ASSERT (CHAR_BIT == 8);
44
45/* We assume that data pointers are the same size as function pointers... */
46G_STATIC_ASSERT (sizeof (gpointer) == sizeof (GFunc));
47G_STATIC_ASSERT (G_ALIGNOF (gpointer) == G_ALIGNOF (GFunc));
48/* ... and that all function pointers are the same size. */
49G_STATIC_ASSERT (sizeof (GFunc) == sizeof (GCompareDataFunc));
50G_STATIC_ASSERT (G_ALIGNOF (GFunc) == G_ALIGNOF (GCompareDataFunc));
51
52/* We assume that "small" enums (those where all values fit in INT32_MIN
53 * to INT32_MAX) are exactly int-sized. In particular, we assume that if
54 * an enum has no members that exceed the range of char/short, the
55 * compiler will make it int-sized anyway, so adding a member later that
56 * *does* exceed the range of char/short is not an ABI break. */
57typedef enum {
58 TEST_CHAR_0 = 0
59} TestChar;
60typedef enum {
61 TEST_SHORT_0 = 0,
62 TEST_SHORT_256 = 256
63} TestShort;
64typedef enum {
65 TEST_INT32_MIN = G_MININT32,
66 TEST_INT32_MAX = G_MAXINT32
67} TestInt;
68G_STATIC_ASSERT (sizeof (TestChar) == sizeof (int));
69G_STATIC_ASSERT (sizeof (TestShort) == sizeof (int));
70G_STATIC_ASSERT (sizeof (TestInt) == sizeof (int));
71G_STATIC_ASSERT (G_ALIGNOF (TestChar) == G_ALIGNOF (int));
72G_STATIC_ASSERT (G_ALIGNOF (TestShort) == G_ALIGNOF (int));
73G_STATIC_ASSERT (G_ALIGNOF (TestInt) == G_ALIGNOF (int));
74
75G_STATIC_ASSERT (sizeof (gchar) == 1);
76G_STATIC_ASSERT (sizeof (guchar) == 1);
77G_STATIC_ASSERT (sizeof (gint8) * CHAR_BIT == 8);
78G_STATIC_ASSERT (sizeof (guint8) * CHAR_BIT == 8);
79G_STATIC_ASSERT (sizeof (gint16) * CHAR_BIT == 16);
80G_STATIC_ASSERT (sizeof (guint16) * CHAR_BIT == 16);
81G_STATIC_ASSERT (sizeof (gint32) * CHAR_BIT == 32);
82G_STATIC_ASSERT (sizeof (guint32) * CHAR_BIT == 32);
83G_STATIC_ASSERT (sizeof (gint64) * CHAR_BIT == 64);
84G_STATIC_ASSERT (sizeof (guint64) * CHAR_BIT == 64);
85
86G_STATIC_ASSERT (sizeof (void *) == GLIB_SIZEOF_VOID_P);
87G_STATIC_ASSERT (sizeof (gintptr) == sizeof (void *));
88G_STATIC_ASSERT (sizeof (guintptr) == sizeof (void *));
89
90G_STATIC_ASSERT (sizeof (long) == GLIB_SIZEOF_LONG);
91
92G_STATIC_ASSERT (G_HAVE_GINT64 == 1);
93
94G_STATIC_ASSERT (sizeof (size_t) == GLIB_SIZEOF_SIZE_T);
95/* Not a typo: ssize_t is POSIX, not Standard C, but if it exists then
96 * it's the same size as size_t. */
97G_STATIC_ASSERT (sizeof (size_t) == GLIB_SIZEOF_SSIZE_T);
98G_STATIC_ASSERT (sizeof (gsize) == GLIB_SIZEOF_SSIZE_T);
99G_STATIC_ASSERT (sizeof (gsize) == sizeof (size_t));
100/* Again this is size_t not ssize_t, because ssize_t is POSIX, not C99 */
101G_STATIC_ASSERT (sizeof (gssize) == sizeof (size_t));
102G_STATIC_ASSERT (G_ALIGNOF (gsize) == G_ALIGNOF (size_t));
103G_STATIC_ASSERT (G_ALIGNOF (gssize) == G_ALIGNOF (size_t));
104
105/* goffset is always 64-bit, even if off_t is only 32-bit
106 * (compiling without large-file-support on 32-bit) */
107G_STATIC_ASSERT (sizeof (goffset) == sizeof (gint64));
108G_STATIC_ASSERT (G_ALIGNOF (goffset) == G_ALIGNOF (gint64));
109
110G_STATIC_ASSERT (sizeof (gfloat) == sizeof (float));
111G_STATIC_ASSERT (G_ALIGNOF (gfloat) == G_ALIGNOF (float));
112G_STATIC_ASSERT (sizeof (gdouble) == sizeof (double));
113G_STATIC_ASSERT (G_ALIGNOF (gdouble) == G_ALIGNOF (double));
114
115G_STATIC_ASSERT (sizeof (gintptr) == sizeof (intptr_t));
116G_STATIC_ASSERT (sizeof (guintptr) == sizeof (uintptr_t));
117G_STATIC_ASSERT (G_ALIGNOF (gintptr) == G_ALIGNOF (intptr_t));
118G_STATIC_ASSERT (G_ALIGNOF (guintptr) == G_ALIGNOF (uintptr_t));
119
120G_STATIC_ASSERT (sizeof (gint8) == sizeof (int8_t));
121G_STATIC_ASSERT (sizeof (guint8) == sizeof (uint8_t));
122G_STATIC_ASSERT (G_ALIGNOF (gint8) == G_ALIGNOF (int8_t));
123G_STATIC_ASSERT (G_ALIGNOF (guint8) == G_ALIGNOF (uint8_t));
124
125G_STATIC_ASSERT (sizeof (gint16) == sizeof (int16_t));
126G_STATIC_ASSERT (sizeof (guint16) == sizeof (uint16_t));
127G_STATIC_ASSERT (G_ALIGNOF (gint16) == G_ALIGNOF (int16_t));
128G_STATIC_ASSERT (G_ALIGNOF (guint16) == G_ALIGNOF (uint16_t));
129
130G_STATIC_ASSERT (sizeof (gint32) == sizeof (int32_t));
131G_STATIC_ASSERT (sizeof (guint32) == sizeof (uint32_t));
132G_STATIC_ASSERT (G_ALIGNOF (gint32) == G_ALIGNOF (int32_t));
133G_STATIC_ASSERT (G_ALIGNOF (guint32) == G_ALIGNOF (uint32_t));
134
135G_STATIC_ASSERT (sizeof (gint64) == sizeof (int64_t));
136G_STATIC_ASSERT (sizeof (guint64) == sizeof (uint64_t));
137G_STATIC_ASSERT (G_ALIGNOF (gint64) == G_ALIGNOF (int64_t));
138G_STATIC_ASSERT (G_ALIGNOF (guint64) == G_ALIGNOF (uint64_t));
139
140/**
141 * g_mem_gc_friendly:
142 *
143 * This variable is %TRUE if the `G_DEBUG` environment variable
144 * includes the key `gc-friendly`.
145 */
146gboolean g_mem_gc_friendly = FALSE;
147
148GLogLevelFlags g_log_msg_prefix = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_WARNING |
149 G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_DEBUG;
150GLogLevelFlags g_log_always_fatal = G_LOG_FATAL_MASK;
151
152static gboolean
153debug_key_matches (const gchar *key,
154 const gchar *token,
155 guint length)
156{
157 /* may not call GLib functions: see note in g_parse_debug_string() */
158 for (; length; length--, key++, token++)
159 {
160 char k = (*key == '_') ? '-' : tolower (*key );
161 char t = (*token == '_') ? '-' : tolower (*token);
162
163 if (k != t)
164 return FALSE;
165 }
166
167 return *key == '\0';
168}
169
170/* The GVariant documentation indirectly says that int is at least 32 bits
171 * (by saying that b, y, n, q, i, u, h are promoted to int). On any
172 * reasonable platform, int is in fact *exactly* 32 bits long, because
173 * otherwise, {signed char, short, int} wouldn't be sufficient to provide
174 * {int8_t, int16_t, int32_t}. */
175G_STATIC_ASSERT (sizeof (int) == sizeof (gint32));
176
177/**
178 * g_parse_debug_string:
179 * @string: (nullable): a list of debug options separated by colons, spaces, or
180 * commas, or %NULL.
181 * @keys: (array length=nkeys): pointer to an array of #GDebugKey which associate
182 * strings with bit flags.
183 * @nkeys: the number of #GDebugKeys in the array.
184 *
185 * Parses a string containing debugging options
186 * into a %guint containing bit flags. This is used
187 * within GDK and GTK+ to parse the debug options passed on the
188 * command line or through environment variables.
189 *
190 * If @string is equal to "all", all flags are set. Any flags
191 * specified along with "all" in @string are inverted; thus,
192 * "all,foo,bar" or "foo,bar,all" sets all flags except those
193 * corresponding to "foo" and "bar".
194 *
195 * If @string is equal to "help", all the available keys in @keys
196 * are printed out to standard error.
197 *
198 * Returns: the combined set of bit flags.
199 */
200guint
201g_parse_debug_string (const gchar *string,
202 const GDebugKey *keys,
203 guint nkeys)
204{
205 guint i;
206 guint result = 0;
207
208 if (string == NULL)
209 return 0;
210
211 /* this function is used during the initialisation of gmessages, gmem
212 * and gslice, so it may not do anything that causes memory to be
213 * allocated or risks messages being emitted.
214 *
215 * this means, more or less, that this code may not call anything
216 * inside GLib.
217 */
218
219 if (!strcasecmp (s1: string, s2: "help"))
220 {
221 /* using stdio directly for the reason stated above */
222 fprintf (stderr, format: "Supported debug values:");
223 for (i = 0; i < nkeys; i++)
224 fprintf (stderr, format: " %s", keys[i].key);
225 fprintf (stderr, format: " all help\n");
226 }
227 else
228 {
229 const gchar *p = string;
230 const gchar *q;
231 gboolean invert = FALSE;
232
233 while (*p)
234 {
235 q = strpbrk (s: p, accept: ":;, \t");
236 if (!q)
237 q = p + strlen (s: p);
238
239 if (debug_key_matches (key: "all", token: p, length: q - p))
240 {
241 invert = TRUE;
242 }
243 else
244 {
245 for (i = 0; i < nkeys; i++)
246 if (debug_key_matches (key: keys[i].key, token: p, length: q - p))
247 result |= keys[i].value;
248 }
249
250 p = q;
251 if (*p)
252 p++;
253 }
254
255 if (invert)
256 {
257 guint all_flags = 0;
258
259 for (i = 0; i < nkeys; i++)
260 all_flags |= keys[i].value;
261
262 result = all_flags & (~result);
263 }
264 }
265
266 return result;
267}
268
269static guint
270g_parse_debug_envvar (const gchar *envvar,
271 const GDebugKey *keys,
272 gint n_keys,
273 guint default_value)
274{
275 const gchar *value;
276
277#ifdef OS_WIN32
278 /* "fatal-warnings,fatal-criticals,all,help" is pretty short */
279 gchar buffer[100];
280
281 if (GetEnvironmentVariable (envvar, buffer, 100) < 100)
282 value = buffer;
283 else
284 return 0;
285#else
286 value = getenv (name: envvar);
287#endif
288
289 if (value == NULL)
290 return default_value;
291
292 return g_parse_debug_string (string: value, keys, nkeys: n_keys);
293}
294
295static void
296g_messages_prefixed_init (void)
297{
298 const GDebugKey keys[] = {
299 { "error", G_LOG_LEVEL_ERROR },
300 { "critical", G_LOG_LEVEL_CRITICAL },
301 { "warning", G_LOG_LEVEL_WARNING },
302 { "message", G_LOG_LEVEL_MESSAGE },
303 { "info", G_LOG_LEVEL_INFO },
304 { "debug", G_LOG_LEVEL_DEBUG }
305 };
306
307 g_log_msg_prefix = g_parse_debug_envvar (envvar: "G_MESSAGES_PREFIXED", keys, G_N_ELEMENTS (keys), default_value: g_log_msg_prefix);
308}
309
310static void
311g_debug_init (void)
312{
313 const GDebugKey keys[] = {
314 { "gc-friendly", 1 },
315 {"fatal-warnings", G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL },
316 {"fatal-criticals", G_LOG_LEVEL_CRITICAL }
317 };
318 GLogLevelFlags flags;
319
320 flags = g_parse_debug_envvar (envvar: "G_DEBUG", keys, G_N_ELEMENTS (keys), default_value: 0);
321
322 g_log_always_fatal |= flags & G_LOG_LEVEL_MASK;
323
324 g_mem_gc_friendly = flags & 1;
325}
326
327void
328glib_init (void)
329{
330 static gboolean glib_inited;
331
332 if (glib_inited)
333 return;
334
335 glib_inited = TRUE;
336
337 g_messages_prefixed_init ();
338 g_debug_init ();
339 g_quark_init ();
340 g_error_init ();
341}
342
343#if defined (G_OS_WIN32)
344
345BOOL WINAPI DllMain (HINSTANCE hinstDLL,
346 DWORD fdwReason,
347 LPVOID lpvReserved);
348
349HMODULE glib_dll;
350
351BOOL WINAPI
352DllMain (HINSTANCE hinstDLL,
353 DWORD fdwReason,
354 LPVOID lpvReserved)
355{
356 switch (fdwReason)
357 {
358 case DLL_PROCESS_ATTACH:
359 glib_dll = hinstDLL;
360 g_crash_handler_win32_init ();
361 g_clock_win32_init ();
362#ifdef THREADS_WIN32
363 g_thread_win32_init ();
364#endif
365 glib_init ();
366 /* must go after glib_init */
367 g_console_win32_init ();
368 break;
369
370 case DLL_THREAD_DETACH:
371#ifdef THREADS_WIN32
372 g_thread_win32_thread_detach ();
373#endif
374 break;
375
376 case DLL_PROCESS_DETACH:
377#ifdef THREADS_WIN32
378 if (lpvReserved == NULL)
379 g_thread_win32_process_detach ();
380#endif
381 g_crash_handler_win32_deinit ();
382 break;
383
384 default:
385 /* do nothing */
386 ;
387 }
388
389 return TRUE;
390}
391
392#elif defined (G_HAS_CONSTRUCTORS)
393
394#ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA
395#pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(glib_init_ctor)
396#endif
397G_DEFINE_CONSTRUCTOR(glib_init_ctor)
398
399static void
400glib_init_ctor (void)
401{
402 glib_init ();
403}
404
405#else
406# error Your platform/compiler is missing constructor support
407#endif
408

source code of gtk/subprojects/glib/glib/glib-init.c