LCOV - code coverage report
Current view: top level - glib - gutils.c (source / functions) Coverage Total Hit
Test: unnamed Lines: 83.5 % 582 486
Test Date: 2026-01-06 05:14:48 Functions: 98.0 % 50 49
Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* GLIB - Library of useful routines for C programming
       2                 :             :  * Copyright (C) 1995-1998  Peter Mattis, Spencer Kimball and Josh MacDonald
       3                 :             :  *
       4                 :             :  * SPDX-License-Identifier: LGPL-2.1-or-later
       5                 :             :  *
       6                 :             :  * This library is free software; you can redistribute it and/or
       7                 :             :  * modify it under the terms of the GNU Lesser General Public
       8                 :             :  * License as published by the Free Software Foundation; either
       9                 :             :  * version 2.1 of the License, or (at your option) any later version.
      10                 :             :  *
      11                 :             :  * This library 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 GNU
      14                 :             :  * Lesser General Public License for more details.
      15                 :             :  *
      16                 :             :  * You should have received a copy of the GNU Lesser General Public
      17                 :             :  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
      18                 :             :  */
      19                 :             : 
      20                 :             : /*
      21                 :             :  * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
      22                 :             :  * file for a list of people on the GLib Team.  See the ChangeLog
      23                 :             :  * files for a list of changes.  These files are distributed with
      24                 :             :  * GLib at ftp://ftp.gtk.org/pub/gtk/. 
      25                 :             :  */
      26                 :             : 
      27                 :             : /* 
      28                 :             :  * MT safe for the unix part, FIXME: make the win32 part MT safe as well.
      29                 :             :  */
      30                 :             : 
      31                 :             : #include "config.h"
      32                 :             : 
      33                 :             : #include "gutils.h"
      34                 :             : #include "gutilsprivate.h"
      35                 :             : 
      36                 :             : #include <stdarg.h>
      37                 :             : #include <stdlib.h>
      38                 :             : #include <stdio.h>
      39                 :             : #include <locale.h>
      40                 :             : #include <string.h>
      41                 :             : #include <ctype.h>                /* For tolower() */
      42                 :             : #include <errno.h>
      43                 :             : #include <sys/types.h>
      44                 :             : #include <sys/stat.h>
      45                 :             : #ifdef G_OS_UNIX
      46                 :             : #include <pwd.h>
      47                 :             : #include <sys/utsname.h>
      48                 :             : #include <unistd.h>
      49                 :             : #endif
      50                 :             : #include <sys/types.h>
      51                 :             : #ifdef HAVE_SYS_PARAM_H
      52                 :             : #include <sys/param.h>
      53                 :             : #endif
      54                 :             : #ifdef HAVE_CRT_EXTERNS_H 
      55                 :             : #include <crt_externs.h> /* for _NSGetEnviron */
      56                 :             : #endif
      57                 :             : #ifdef HAVE_SYS_AUXV_H
      58                 :             : #include <sys/auxv.h>
      59                 :             : #endif
      60                 :             : 
      61                 :             : #include "glib-init.h"
      62                 :             : #include "glib-private.h"
      63                 :             : #include "genviron.h"
      64                 :             : #include "gfileutils.h"
      65                 :             : #include "ggettext.h"
      66                 :             : #include "ghash.h"
      67                 :             : #include "gthread.h"
      68                 :             : #include "gtestutils.h"
      69                 :             : #include "gunicode.h"
      70                 :             : #include "gstrfuncs.h"
      71                 :             : #include "garray.h"
      72                 :             : #include "glibintl.h"
      73                 :             : #include "gstdio.h"
      74                 :             : #include "gquark.h"
      75                 :             : 
      76                 :             : #ifdef G_PLATFORM_WIN32
      77                 :             : #include "gconvert.h"
      78                 :             : #include "gwin32.h"
      79                 :             : #endif
      80                 :             : 
      81                 :             : 
      82                 :             : #ifdef G_PLATFORM_WIN32
      83                 :             : #  include <windows.h>
      84                 :             : #  ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
      85                 :             : #    define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 2
      86                 :             : #    define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 4
      87                 :             : #  endif
      88                 :             : #  include <lmcons.h>             /* For UNLEN */
      89                 :             : #endif /* G_PLATFORM_WIN32 */
      90                 :             : 
      91                 :             : #ifdef G_OS_WIN32
      92                 :             : #  include <direct.h>
      93                 :             : #  include <shlobj.h>
      94                 :             : #  include <process.h>
      95                 :             : #endif
      96                 :             : 
      97                 :             : #ifdef HAVE_CODESET
      98                 :             : #include <langinfo.h>
      99                 :             : #endif
     100                 :             : 
     101                 :             : /**
     102                 :             :  * g_memmove: 
     103                 :             :  * @dest: the destination address to copy the bytes to.
     104                 :             :  * @src: the source address to copy the bytes from.
     105                 :             :  * @len: the number of bytes to copy.
     106                 :             :  *
     107                 :             :  * Copies a block of memory @len bytes long, from @src to @dest.
     108                 :             :  * The source and destination areas may overlap.
     109                 :             :  *
     110                 :             :  * Deprecated:2.40: Just use memmove().
     111                 :             :  */
     112                 :             : 
     113                 :             : #ifdef G_OS_WIN32
     114                 :             : #undef g_atexit
     115                 :             : #endif
     116                 :             : 
     117                 :             : /**
     118                 :             :  * g_atexit:
     119                 :             :  * @func: (scope async): the function to call on normal program termination.
     120                 :             :  * 
     121                 :             :  * Specifies a function to be called at normal program termination.
     122                 :             :  *
     123                 :             :  * Since GLib 2.8.2, on Windows g_atexit() actually is a preprocessor
     124                 :             :  * macro that maps to a call to the atexit() function in the C
     125                 :             :  * library. This means that in case the code that calls g_atexit(),
     126                 :             :  * i.e. atexit(), is in a DLL, the function will be called when the
     127                 :             :  * DLL is detached from the program. This typically makes more sense
     128                 :             :  * than that the function is called when the GLib DLL is detached,
     129                 :             :  * which happened earlier when g_atexit() was a function in the GLib
     130                 :             :  * DLL.
     131                 :             :  *
     132                 :             :  * The behaviour of atexit() in the context of dynamically loaded
     133                 :             :  * modules is not formally specified and varies wildly.
     134                 :             :  *
     135                 :             :  * On POSIX systems, calling g_atexit() (or atexit()) in a dynamically
     136                 :             :  * loaded module which is unloaded before the program terminates might
     137                 :             :  * well cause a crash at program exit.
     138                 :             :  *
     139                 :             :  * Some POSIX systems implement atexit() like Windows, and have each
     140                 :             :  * dynamically loaded module maintain an own atexit chain that is
     141                 :             :  * called when the module is unloaded.
     142                 :             :  *
     143                 :             :  * On other POSIX systems, before a dynamically loaded module is
     144                 :             :  * unloaded, the registered atexit functions (if any) residing in that
     145                 :             :  * module are called, regardless where the code that registered them
     146                 :             :  * resided. This is presumably the most robust approach.
     147                 :             :  *
     148                 :             :  * As can be seen from the above, for portability it's best to avoid
     149                 :             :  * calling g_atexit() (or atexit()) except in the main executable of a
     150                 :             :  * program.
     151                 :             :  *
     152                 :             :  * Deprecated:2.32: It is best to avoid g_atexit().
     153                 :             :  */
     154                 :             : G_GNUC_BEGIN_IGNORE_DEPRECATIONS
     155                 :             : void
     156                 :           6 : g_atexit (GVoidFunc func)
     157                 :             : {
     158                 :             :   gint result;
     159                 :             :   int errsv;
     160                 :             : 
     161                 :           6 :   result = atexit ((void (*)(void)) func);
     162                 :           6 :   errsv = errno;
     163                 :           6 :   if (result)
     164                 :             :     {
     165                 :           0 :       g_error ("Could not register atexit() function: %s",
     166                 :             :                g_strerror (errsv));
     167                 :             :     }
     168                 :           6 : }
     169                 :             : G_GNUC_END_IGNORE_DEPRECATIONS
     170                 :             : 
     171                 :             : /* Based on execvp() from GNU Libc.
     172                 :             :  * Some of this code is cut-and-pasted into gspawn.c
     173                 :             :  */
     174                 :             : 
     175                 :             : static gchar*
     176                 :        2150 : my_strchrnul (const gchar *str, 
     177                 :             :               gchar        c)
     178                 :             : {
     179                 :        2150 :   gchar *p = (gchar*)str;
     180                 :       37895 :   while (*p && (*p != c))
     181                 :       35745 :     ++p;
     182                 :             : 
     183                 :        2150 :   return p;
     184                 :             : }
     185                 :             : 
     186                 :             : #ifdef G_OS_WIN32
     187                 :             : 
     188                 :             : static gchar *inner_find_program_in_path (const gchar *program);
     189                 :             : 
     190                 :             : gchar*
     191                 :             : g_find_program_in_path (const gchar *program)
     192                 :             : {
     193                 :             :   const gchar *last_dot = strrchr (program, '.');
     194                 :             : 
     195                 :             :   if (last_dot == NULL ||
     196                 :             :       strchr (last_dot, '\\') != NULL ||
     197                 :             :       strchr (last_dot, '/') != NULL)
     198                 :             :     {
     199                 :             :       const size_t program_length = strlen (program);
     200                 :             :       gchar *pathext = g_build_path (";",
     201                 :             :                                      ".exe;.cmd;.bat;.com",
     202                 :             :                                      g_getenv ("PATHEXT"),
     203                 :             :                                      NULL);
     204                 :             :       gchar *p;
     205                 :             :       gchar *decorated_program;
     206                 :             :       gchar *retval;
     207                 :             : 
     208                 :             :       p = pathext;
     209                 :             :       do
     210                 :             :         {
     211                 :             :           gchar *q = my_strchrnul (p, ';');
     212                 :             : 
     213                 :             :           decorated_program = g_malloc (program_length + (q-p) + 1);
     214                 :             :           memcpy (decorated_program, program, program_length);
     215                 :             :           memcpy (decorated_program+program_length, p, q-p);
     216                 :             :           decorated_program [program_length + (q-p)] = '\0';
     217                 :             :           
     218                 :             :           retval = inner_find_program_in_path (decorated_program);
     219                 :             :           g_free (decorated_program);
     220                 :             : 
     221                 :             :           if (retval != NULL)
     222                 :             :             {
     223                 :             :               g_free (pathext);
     224                 :             :               return retval;
     225                 :             :             }
     226                 :             :           p = q;
     227                 :             :         } while (*p++ != '\0');
     228                 :             :       g_free (pathext);
     229                 :             :       return NULL;
     230                 :             :     }
     231                 :             :   else
     232                 :             :     return inner_find_program_in_path (program);
     233                 :             : }
     234                 :             : 
     235                 :             : #endif
     236                 :             : 
     237                 :             : /**
     238                 :             :  * g_find_program_in_path:
     239                 :             :  * @program: (type filename): a program name in the GLib file name encoding
     240                 :             :  * 
     241                 :             :  * Locates the first executable named @program in the user's path, in the
     242                 :             :  * same way that execvp() would locate it. Returns an allocated string
     243                 :             :  * with the absolute path name, or %NULL if the program is not found in
     244                 :             :  * the path. If @program is already an absolute path, returns a copy of
     245                 :             :  * @program if @program exists and is executable, and %NULL otherwise.
     246                 :             :  *  
     247                 :             :  * On Windows, if @program does not have a file type suffix, tries
     248                 :             :  * with the suffixes .exe, .cmd, .bat and .com, and the suffixes in
     249                 :             :  * the `PATHEXT` environment variable. 
     250                 :             :  * 
     251                 :             :  * On Windows, it looks for the file in the same way as CreateProcess() 
     252                 :             :  * would. This means first in the directory where the executing
     253                 :             :  * program was loaded from, then in the current directory, then in the
     254                 :             :  * Windows 32-bit system directory, then in the Windows directory, and
     255                 :             :  * finally in the directories in the `PATH` environment variable. If
     256                 :             :  * the program is found, the return value contains the full name
     257                 :             :  * including the type suffix.
     258                 :             :  *
     259                 :             :  * Returns: (type filename) (transfer full) (nullable): a newly-allocated
     260                 :             :  *   string with the absolute path, or %NULL
     261                 :             :  **/
     262                 :             : #ifdef G_OS_WIN32
     263                 :             : static gchar *
     264                 :             : inner_find_program_in_path (const gchar *program)
     265                 :             : #else
     266                 :             : gchar*
     267                 :         145 : g_find_program_in_path (const gchar *program)
     268                 :             : #endif
     269                 :             : {
     270                 :         145 :   return g_find_program_for_path (program, NULL, NULL);
     271                 :             : }
     272                 :             : 
     273                 :             : /**
     274                 :             :  * g_find_program_for_path:
     275                 :             :  * @program: (type filename): a program name in the GLib file name encoding
     276                 :             :  * @path: (type filename) (nullable): the current dir where to search program
     277                 :             :  * @working_dir: (type filename) (nullable): the working dir where to search
     278                 :             :  *   program
     279                 :             :  *
     280                 :             :  * Locates the first executable named @program in @path, in the
     281                 :             :  * same way that execvp() would locate it. Returns an allocated string
     282                 :             :  * with the absolute path name (taking in account the @working_dir), or
     283                 :             :  * %NULL if the program is not found in @path. If @program is already an
     284                 :             :  * absolute path, returns a copy of @program if @program exists and is
     285                 :             :  * executable, and %NULL otherwise.
     286                 :             :  *
     287                 :             :  * On Windows, if @path is %NULL, it looks for the file in the same way as
     288                 :             :  * CreateProcess()  would. This means first in the directory where the
     289                 :             :  * executing program was loaded from, then in the current directory, then in
     290                 :             :  * the Windows 32-bit system directory, then in the Windows directory, and
     291                 :             :  * finally in the directories in the `PATH` environment variable. If
     292                 :             :  * the program is found, the return value contains the full name
     293                 :             :  * including the type suffix.
     294                 :             :  *
     295                 :             :  * Returns: (type filename) (transfer full) (nullable): a newly-allocated
     296                 :             :  *   string with the absolute path, or %NULL
     297                 :             :  * Since: 2.76
     298                 :             :  **/
     299                 :             : char *
     300                 :         977 : g_find_program_for_path (const char *program,
     301                 :             :                          const char *path,
     302                 :             :                          const char *working_dir)
     303                 :             : {
     304                 :         977 :   const char *original_path = path;
     305                 :         977 :   const char *original_program = program;
     306                 :         977 :   char *program_path = NULL;
     307                 :             :   const gchar *p;
     308                 :             :   gchar *name, *freeme;
     309                 :             : #ifdef G_OS_WIN32
     310                 :             :   const gchar *path_copy;
     311                 :             :   gchar *filename = NULL, *appdir = NULL;
     312                 :             :   gchar *sysdir = NULL, *windir = NULL;
     313                 :             :   int n;
     314                 :             :   wchar_t wfilename[MAXPATHLEN], wsysdir[MAXPATHLEN],
     315                 :             :     wwindir[MAXPATHLEN];
     316                 :             : #endif
     317                 :             :   gsize len;
     318                 :             :   gsize pathlen;
     319                 :             : 
     320                 :         977 :   g_return_val_if_fail (program != NULL, NULL);
     321                 :             : 
     322                 :             :   /* Use the working dir as program path if provided */
     323                 :         977 :   if (working_dir && !g_path_is_absolute (program))
     324                 :             :     {
     325                 :         227 :       program_path = g_build_filename (working_dir, program, NULL);
     326                 :         227 :       program = program_path;
     327                 :             :     }
     328                 :             : 
     329                 :             :   /* If it is an absolute path, or a relative path including subdirectories,
     330                 :             :    * don't look in PATH.
     331                 :             :    */
     332                 :         977 :   if (g_path_is_absolute (program)
     333                 :         725 :       || strchr (original_program, G_DIR_SEPARATOR) != NULL
     334                 :             : #ifdef G_OS_WIN32
     335                 :             :       || strchr (original_program, '/') != NULL
     336                 :             : #endif
     337                 :             :       )
     338                 :             :     {
     339                 :         340 :       if (g_file_test (program, G_FILE_TEST_IS_EXECUTABLE) &&
     340                 :          82 :           !g_file_test (program, G_FILE_TEST_IS_DIR))
     341                 :             :         {
     342                 :          76 :           gchar *out = NULL;
     343                 :             : 
     344                 :          76 :           if (g_path_is_absolute (program))
     345                 :             :             {
     346                 :          70 :               out = g_strdup (program);
     347                 :             :             }
     348                 :             :           else
     349                 :             :             {
     350                 :           6 :               char *cwd = g_get_current_dir ();
     351                 :           6 :               out = g_build_filename (cwd, program, NULL);
     352                 :           6 :               g_free (cwd);
     353                 :             :             }
     354                 :             : 
     355                 :          76 :           g_free (program_path);
     356                 :             : 
     357                 :          76 :           return g_steal_pointer (&out);
     358                 :             :         }
     359                 :             :       else
     360                 :             :         {
     361                 :         182 :           g_clear_pointer (&program_path, g_free);
     362                 :             : 
     363                 :         182 :           if (g_path_is_absolute (original_program))
     364                 :          14 :             return NULL;
     365                 :             :         }
     366                 :             :     }
     367                 :             : 
     368                 :         887 :   program = original_program;
     369                 :             : 
     370                 :         887 :   if G_LIKELY (original_path == NULL)
     371                 :         376 :     path = g_getenv ("PATH");
     372                 :             :   else
     373                 :         511 :     path = original_path;
     374                 :             : 
     375                 :             : #if defined(G_OS_UNIX)
     376                 :         887 :   if (path == NULL)
     377                 :             :     {
     378                 :             :       /* There is no 'PATH' in the environment.  The default
     379                 :             :        * search path in GNU libc is the current directory followed by
     380                 :             :        * the path 'confstr' returns for '_CS_PATH'.
     381                 :             :        */
     382                 :             :       
     383                 :             :       /* In GLib we put . last, for security, and don't use the
     384                 :             :        * unportable confstr(); UNIX98 does not actually specify
     385                 :             :        * what to search if PATH is unset. POSIX may, dunno.
     386                 :             :        */
     387                 :             :       
     388                 :           0 :       path = "/bin:/usr/bin:.";
     389                 :             :     }
     390                 :             : #else
     391                 :             :   if G_LIKELY (original_path == NULL)
     392                 :             :     {
     393                 :             :       n = GetModuleFileNameW (NULL, wfilename, MAXPATHLEN);
     394                 :             :       if (n > 0 && n < MAXPATHLEN)
     395                 :             :         filename = g_utf16_to_utf8 (wfilename, -1, NULL, NULL, NULL);
     396                 :             : 
     397                 :             :       n = GetSystemDirectoryW (wsysdir, MAXPATHLEN);
     398                 :             :       if (n > 0 && n < MAXPATHLEN)
     399                 :             :         sysdir = g_utf16_to_utf8 (wsysdir, -1, NULL, NULL, NULL);
     400                 :             : 
     401                 :             :       n = GetWindowsDirectoryW (wwindir, MAXPATHLEN);
     402                 :             :       if (n > 0 && n < MAXPATHLEN)
     403                 :             :         windir = g_utf16_to_utf8 (wwindir, -1, NULL, NULL, NULL);
     404                 :             : 
     405                 :             :       if (filename)
     406                 :             :         {
     407                 :             :           appdir = g_path_get_dirname (filename);
     408                 :             :           g_free (filename);
     409                 :             :         }
     410                 :             : 
     411                 :             :       path = g_strdup (path);
     412                 :             : 
     413                 :             :       if (windir)
     414                 :             :         {
     415                 :             :           const gchar *tem = path;
     416                 :             :           path = g_strconcat (windir, ";", path, NULL);
     417                 :             :           g_free ((gchar *) tem);
     418                 :             :           g_free (windir);
     419                 :             :         }
     420                 :             : 
     421                 :             :       if (sysdir)
     422                 :             :         {
     423                 :             :           const gchar *tem = path;
     424                 :             :           path = g_strconcat (sysdir, ";", path, NULL);
     425                 :             :           g_free ((gchar *) tem);
     426                 :             :           g_free (sysdir);
     427                 :             :         }
     428                 :             : 
     429                 :             :       {
     430                 :             :         const gchar *tem = path;
     431                 :             :         path = g_strconcat (".;", path, NULL);
     432                 :             :         g_free ((gchar *) tem);
     433                 :             :       }
     434                 :             : 
     435                 :             :       if (appdir)
     436                 :             :         {
     437                 :             :           const gchar *tem = path;
     438                 :             :           path = g_strconcat (appdir, ";", path, NULL);
     439                 :             :           g_free ((gchar *) tem);
     440                 :             :           g_free (appdir);
     441                 :             :         }
     442                 :             : 
     443                 :             :       path_copy = path;
     444                 :             :     }
     445                 :             :   else
     446                 :             :     {
     447                 :             :       path_copy = g_strdup (path);
     448                 :             :     }
     449                 :             : 
     450                 :             : #endif
     451                 :             :   
     452                 :         887 :   len = strlen (program) + 1;
     453                 :         887 :   pathlen = strlen (path);
     454                 :         887 :   freeme = name = g_malloc (pathlen + len + 1);
     455                 :             :   
     456                 :             :   /* Copy the file name at the top, including '\0'  */
     457                 :         887 :   memcpy (name + pathlen + 1, program, len);
     458                 :         887 :   name = name + pathlen;
     459                 :             :   /* And add the slash before the filename  */
     460                 :         887 :   *name = G_DIR_SEPARATOR;
     461                 :             :   
     462                 :         887 :   p = path;
     463                 :             :   do
     464                 :             :     {
     465                 :             :       char *startp;
     466                 :        2150 :       char *startp_path = NULL;
     467                 :             : 
     468                 :        2150 :       path = p;
     469                 :        2150 :       p = my_strchrnul (path, G_SEARCHPATH_SEPARATOR);
     470                 :             : 
     471                 :        2150 :       if (p == path)
     472                 :             :         /* Two adjacent colons, or a colon at the beginning or the end
     473                 :             :          * of 'PATH' means to search the current directory.
     474                 :             :          */
     475                 :          48 :         startp = name + 1;
     476                 :             :       else
     477                 :        2102 :         startp = memcpy (name - (p - path), path, p - path);
     478                 :             : 
     479                 :             :       /* Use the working dir as program path if provided */
     480                 :        2150 :       if (working_dir && !g_path_is_absolute (startp))
     481                 :             :         {
     482                 :          66 :           startp_path = g_build_filename (working_dir, startp, NULL);
     483                 :          66 :           startp = startp_path;
     484                 :             :         }
     485                 :             : 
     486                 :        2581 :       if (g_file_test (startp, G_FILE_TEST_IS_EXECUTABLE) &&
     487                 :         431 :           !g_file_test (startp, G_FILE_TEST_IS_DIR))
     488                 :             :         {
     489                 :             :           gchar *ret;
     490                 :         431 :           if (g_path_is_absolute (startp)) {
     491                 :         413 :             ret = g_strdup (startp);
     492                 :             :           } else {
     493                 :          18 :             gchar *cwd = NULL;
     494                 :          18 :             cwd = g_get_current_dir ();
     495                 :          18 :             ret = g_build_filename (cwd, startp, NULL);
     496                 :          18 :             g_free (cwd);
     497                 :             :           }
     498                 :             : 
     499                 :         431 :           g_free (program_path);
     500                 :         431 :           g_free (startp_path);
     501                 :         431 :           g_free (freeme);
     502                 :             : #ifdef G_OS_WIN32
     503                 :             :           g_free ((gchar *) path_copy);
     504                 :             : #endif
     505                 :         431 :           return ret;
     506                 :             :         }
     507                 :             : 
     508                 :        1719 :       g_free (startp_path);
     509                 :             :     }
     510                 :        1719 :   while (*p++ != '\0');
     511                 :             : 
     512                 :         456 :   g_free (program_path);
     513                 :         456 :   g_free (freeme);
     514                 :             : #ifdef G_OS_WIN32
     515                 :             :   g_free ((gchar *) path_copy);
     516                 :             : #endif
     517                 :             : 
     518                 :         456 :   return NULL;
     519                 :             : }
     520                 :             : 
     521                 :             : /* The functions below are defined this way for compatibility reasons.
     522                 :             :  * See the note in gutils.h.
     523                 :             :  */
     524                 :             : 
     525                 :             : /**
     526                 :             :  * g_bit_nth_lsf:
     527                 :             :  * @mask: a #gulong containing flags
     528                 :             :  * @nth_bit: the index of the bit to start the search from
     529                 :             :  *
     530                 :             :  * Find the position of the first bit set in @mask, searching
     531                 :             :  * from (but not including) @nth_bit upwards. Bits are numbered
     532                 :             :  * from 0 (least significant) to sizeof(#gulong) * 8 - 1 (31 or 63,
     533                 :             :  * usually). To start searching from the 0th bit, set @nth_bit to -1.
     534                 :             :  *
     535                 :             :  * Returns: the index of the first bit set which is higher than @nth_bit, or -1
     536                 :             :  *    if no higher bits are set
     537                 :             :  */
     538                 :             : gint
     539                 :     1260000 : (g_bit_nth_lsf) (gulong mask,
     540                 :             :                  gint   nth_bit)
     541                 :             : {
     542                 :     1260000 :   return g_bit_nth_lsf_impl (mask, nth_bit);
     543                 :             : }
     544                 :             : 
     545                 :             : /**
     546                 :             :  * g_bit_nth_msf:
     547                 :             :  * @mask: a #gulong containing flags
     548                 :             :  * @nth_bit: the index of the bit to start the search from
     549                 :             :  *
     550                 :             :  * Find the position of the first bit set in @mask, searching
     551                 :             :  * from (but not including) @nth_bit downwards. Bits are numbered
     552                 :             :  * from 0 (least significant) to sizeof(#gulong) * 8 - 1 (31 or 63,
     553                 :             :  * usually). To start searching from the last bit, set @nth_bit to
     554                 :             :  * -1 or GLIB_SIZEOF_LONG * 8.
     555                 :             :  *
     556                 :             :  * Returns: the index of the first bit set which is lower than @nth_bit, or -1
     557                 :             :  *    if no lower bits are set
     558                 :             :  */
     559                 :             : gint
     560                 :     1260000 : (g_bit_nth_msf) (gulong mask,
     561                 :             :                  gint   nth_bit)
     562                 :             : {
     563                 :     1260000 :   return g_bit_nth_msf_impl (mask, nth_bit);
     564                 :             : }
     565                 :             : 
     566                 :             : 
     567                 :             : /**
     568                 :             :  * g_bit_storage:
     569                 :             :  * @number: a #guint
     570                 :             :  *
     571                 :             :  * Gets the number of bits used to hold @number,
     572                 :             :  * e.g. if @number is 4, 3 bits are needed.
     573                 :             :  *
     574                 :             :  * Returns: the number of bits used to hold @number
     575                 :             :  */
     576                 :             : guint
     577                 :       18000 : (g_bit_storage) (gulong number)
     578                 :             : {
     579                 :       18000 :   return g_bit_storage_impl (number);
     580                 :             : }
     581                 :             : 
     582                 :             : G_LOCK_DEFINE_STATIC (g_utils_global);
     583                 :             : 
     584                 :             : typedef struct
     585                 :             : {
     586                 :             :   gchar *user_name;
     587                 :             :   gchar *real_name;
     588                 :             :   gchar *home_dir;
     589                 :             : } UserDatabaseEntry;
     590                 :             : 
     591                 :             : /* These must all be read/written with @g_utils_global held. */
     592                 :             : static  gchar   *g_user_data_dir = NULL;
     593                 :             : static  gchar  **g_system_data_dirs = NULL;
     594                 :             : static  gchar   *g_user_cache_dir = NULL;
     595                 :             : static  gchar   *g_user_config_dir = NULL;
     596                 :             : static  gchar   *g_user_state_dir = NULL;
     597                 :             : static  gchar   *g_user_runtime_dir = NULL;
     598                 :             : static  gchar  **g_system_config_dirs = NULL;
     599                 :             : static  gchar  **g_user_special_dirs = NULL;
     600                 :             : static  gchar   *g_tmp_dir = NULL;
     601                 :             : 
     602                 :             : /* fifteen minutes of fame for everybody */
     603                 :             : #define G_USER_DIRS_EXPIRE      15 * 60
     604                 :             : 
     605                 :             : #ifdef G_OS_WIN32
     606                 :             : 
     607                 :             : static gchar *
     608                 :             : get_special_folder (REFKNOWNFOLDERID known_folder_guid_ptr)
     609                 :             : {
     610                 :             :   wchar_t *wcp = NULL;
     611                 :             :   gchar *result = NULL;
     612                 :             :   HRESULT hr;
     613                 :             : 
     614                 :             :   hr = SHGetKnownFolderPath (known_folder_guid_ptr, 0, NULL, &wcp);
     615                 :             : 
     616                 :             :   if (SUCCEEDED (hr))
     617                 :             :     result = g_utf16_to_utf8 (wcp, -1, NULL, NULL, NULL);
     618                 :             : 
     619                 :             :   CoTaskMemFree (wcp);
     620                 :             : 
     621                 :             :   return result;
     622                 :             : }
     623                 :             : 
     624                 :             : static char *
     625                 :             : get_windows_directory_root (void)
     626                 :             : {
     627                 :             :   wchar_t wwindowsdir[MAX_PATH];
     628                 :             : 
     629                 :             :   if (GetWindowsDirectoryW (wwindowsdir, G_N_ELEMENTS (wwindowsdir)))
     630                 :             :     {
     631                 :             :       /* Usually X:\Windows, but in terminal server environments
     632                 :             :        * might be an UNC path, AFAIK.
     633                 :             :        */
     634                 :             :       char *windowsdir = g_utf16_to_utf8 (wwindowsdir, -1, NULL, NULL, NULL);
     635                 :             :       char *p;
     636                 :             : 
     637                 :             :       if (windowsdir == NULL)
     638                 :             :         return g_strdup ("C:\\");
     639                 :             : 
     640                 :             :       p = (char *) g_path_skip_root (windowsdir);
     641                 :             :       if (G_IS_DIR_SEPARATOR (p[-1]) && p[-2] != ':')
     642                 :             :         p--;
     643                 :             :       *p = '\0';
     644                 :             :       return windowsdir;
     645                 :             :     }
     646                 :             :   else
     647                 :             :     return g_strdup ("C:\\");
     648                 :             : }
     649                 :             : 
     650                 :             : #endif
     651                 :             : 
     652                 :             : /* HOLDS: g_utils_global_lock */
     653                 :             : static UserDatabaseEntry *
     654                 :          14 : g_get_user_database_entry (void)
     655                 :             : {
     656                 :             :   static UserDatabaseEntry *entry;
     657                 :             : 
     658                 :          14 :   if (g_once_init_enter_pointer (&entry))
     659                 :             :     {
     660                 :             :       static UserDatabaseEntry e;
     661                 :             : 
     662                 :             : #ifdef G_OS_UNIX
     663                 :             :       {
     664                 :           7 :         struct passwd *pw = NULL;
     665                 :           7 :         gpointer buffer = NULL;
     666                 :             :         gint error;
     667                 :             :         const char *logname;
     668                 :             : 
     669                 :             : #  if defined (HAVE_GETPWUID_R)
     670                 :             :         struct passwd pwd;
     671                 :             : #    ifdef _SC_GETPW_R_SIZE_MAX
     672                 :             :         /* This returns the maximum length */
     673                 :           7 :         glong bufsize = sysconf (_SC_GETPW_R_SIZE_MAX);
     674                 :             : 
     675                 :           7 :         if (bufsize < 0)
     676                 :           0 :           bufsize = 64;
     677                 :             : #    else /* _SC_GETPW_R_SIZE_MAX */
     678                 :             :         glong bufsize = 64;
     679                 :             : #    endif /* _SC_GETPW_R_SIZE_MAX */
     680                 :             : 
     681                 :           7 :         logname = g_getenv ("LOGNAME");
     682                 :             : 
     683                 :             :         do
     684                 :             :           {
     685                 :           7 :             g_free (buffer);
     686                 :             :             /* we allocate 6 extra bytes to work around a bug in
     687                 :             :              * Mac OS < 10.3. See #156446
     688                 :             :              */
     689                 :           7 :             buffer = g_malloc (bufsize + 6);
     690                 :           7 :             errno = 0;
     691                 :             : 
     692                 :           7 :             if (logname) {
     693                 :           0 :               error = getpwnam_r (logname, &pwd, buffer, bufsize, &pw);
     694                 :           0 :               if (!pw || (pw->pw_uid != getuid ())) {
     695                 :             :                 /* LOGNAME is lying, fall back to looking up the uid */
     696                 :           0 :                 error = getpwuid_r (getuid (), &pwd, buffer, bufsize, &pw);
     697                 :             :               }
     698                 :             :             } else {
     699                 :           7 :               error = getpwuid_r (getuid (), &pwd, buffer, bufsize, &pw);
     700                 :             :             }
     701                 :           7 :             error = error < 0 ? errno : error;
     702                 :             : 
     703                 :           7 :             if (!pw)
     704                 :             :               {
     705                 :             :                 /* we bail out prematurely if the user id can't be found
     706                 :             :                  * (should be pretty rare case actually), or if the buffer
     707                 :             :                  * should be sufficiently big and lookups are still not
     708                 :             :                  * successful.
     709                 :             :                  */
     710                 :           0 :                 if (error == 0 || error == ENOENT)
     711                 :             :                   {
     712                 :           0 :                     g_warning ("getpwuid_r(): failed due to unknown user id (%lu)",
     713                 :             :                                (gulong) getuid ());
     714                 :           0 :                     break;
     715                 :             :                   }
     716                 :           0 :                 if (bufsize > 32 * 1024)
     717                 :             :                   {
     718                 :           0 :                     g_warning ("getpwuid_r(): failed due to: %s.",
     719                 :             :                                g_strerror (error));
     720                 :           0 :                     break;
     721                 :             :                   }
     722                 :             : 
     723                 :           0 :                 bufsize *= 2;
     724                 :             :               }
     725                 :             :           }
     726                 :           7 :         while (!pw);
     727                 :             : #  endif /* HAVE_GETPWUID_R */
     728                 :             : 
     729                 :           7 :         if (!pw)
     730                 :             :           {
     731                 :           0 :             pw = getpwuid (getuid ());
     732                 :             :           }
     733                 :           7 :         if (pw)
     734                 :             :           {
     735                 :           7 :             e.user_name = g_strdup (pw->pw_name);
     736                 :             : 
     737                 :             : #ifndef __BIONIC__
     738                 :           7 :             if (pw->pw_gecos && *pw->pw_gecos != '\0' && pw->pw_name)
     739                 :             :               {
     740                 :             :                 gchar **gecos_fields;
     741                 :             :                 gchar **name_parts;
     742                 :             :                 gchar *uppercase_pw_name;
     743                 :             : 
     744                 :             :                 /* split the gecos field and substitute '&' */
     745                 :           0 :                 gecos_fields = g_strsplit (pw->pw_gecos, ",", 0);
     746                 :           0 :                 name_parts = g_strsplit (gecos_fields[0], "&", 0);
     747                 :           0 :                 uppercase_pw_name = g_strdup (pw->pw_name);
     748                 :           0 :                 uppercase_pw_name[0] = g_ascii_toupper (uppercase_pw_name[0]);
     749                 :           0 :                 e.real_name = g_strjoinv (uppercase_pw_name, name_parts);
     750                 :           0 :                 g_strfreev (gecos_fields);
     751                 :           0 :                 g_strfreev (name_parts);
     752                 :           0 :                 g_free (uppercase_pw_name);
     753                 :             :               }
     754                 :             : #endif
     755                 :             : 
     756                 :           7 :             if (!e.home_dir)
     757                 :          14 :               e.home_dir = g_strdup (pw->pw_dir);
     758                 :             :           }
     759                 :           7 :         g_free (buffer);
     760                 :             :       }
     761                 :             : 
     762                 :             : #endif /* G_OS_UNIX */
     763                 :             : 
     764                 :             : #ifdef G_OS_WIN32
     765                 :             :       {
     766                 :             :         guint len = UNLEN+1;
     767                 :             :         wchar_t buffer[UNLEN+1];
     768                 :             : 
     769                 :             :         if (GetUserNameW (buffer, (LPDWORD) &len))
     770                 :             :           {
     771                 :             :             e.user_name = g_utf16_to_utf8 (buffer, -1, NULL, NULL, NULL);
     772                 :             :             e.real_name = g_strdup (e.user_name);
     773                 :             :           }
     774                 :             :       }
     775                 :             : #endif /* G_OS_WIN32 */
     776                 :             : 
     777                 :           7 :       if (!e.user_name)
     778                 :           1 :         e.user_name = g_strdup ("somebody");
     779                 :           7 :       if (!e.real_name)
     780                 :           7 :         e.real_name = g_strdup ("Unknown");
     781                 :             : 
     782                 :           7 :       g_once_init_leave_pointer (&entry, &e);
     783                 :             :     }
     784                 :             : 
     785                 :          14 :   return entry;
     786                 :             : }
     787                 :             : 
     788                 :             : /**
     789                 :             :  * g_get_user_name:
     790                 :             :  *
     791                 :             :  * Gets the user name of the current user. The encoding of the returned
     792                 :             :  * string is system-defined. On UNIX, it might be the preferred file name
     793                 :             :  * encoding, or something else, and there is no guarantee that it is even
     794                 :             :  * consistent on a machine. On Windows, it is always UTF-8.
     795                 :             :  *
     796                 :             :  * Returns: (type filename) (transfer none): the user name of the current user.
     797                 :             :  */
     798                 :             : const gchar *
     799                 :           7 : g_get_user_name (void)
     800                 :             : {
     801                 :             :   UserDatabaseEntry *entry;
     802                 :             : 
     803                 :           7 :   entry = g_get_user_database_entry ();
     804                 :             : 
     805                 :           7 :   return entry->user_name;
     806                 :             : }
     807                 :             : 
     808                 :             : /**
     809                 :             :  * g_get_real_name:
     810                 :             :  *
     811                 :             :  * Gets the real name of the user. This usually comes from the user's
     812                 :             :  * entry in the `passwd` file. The encoding of the returned string is
     813                 :             :  * system-defined. (On Windows, it is, however, always UTF-8.) If the
     814                 :             :  * real user name cannot be determined, the string "Unknown" is 
     815                 :             :  * returned.
     816                 :             :  *
     817                 :             :  * Returns: (type filename) (transfer none): the user's real name.
     818                 :             :  */
     819                 :             : const gchar *
     820                 :           7 : g_get_real_name (void)
     821                 :             : {
     822                 :             :   UserDatabaseEntry *entry;
     823                 :             : 
     824                 :           7 :   entry = g_get_user_database_entry ();
     825                 :             : 
     826                 :           7 :   return entry->real_name;
     827                 :             : }
     828                 :             : 
     829                 :             : /* Protected by @g_utils_global_lock. */
     830                 :             : static gchar *g_home_dir = NULL;  /* (owned) (nullable before initialised) */
     831                 :             : 
     832                 :             : static gchar *
     833                 :          89 : g_build_home_dir (void)
     834                 :             : {
     835                 :             :   gchar *home_dir;
     836                 :             : 
     837                 :             :   /* We first check HOME and use it if it is set */
     838                 :          89 :   home_dir = g_strdup (g_getenv ("HOME"));
     839                 :             : 
     840                 :             : #ifdef G_OS_WIN32
     841                 :             :   /* Only believe HOME if it is an absolute path and exists.
     842                 :             :    *
     843                 :             :    * We only do this check on Windows for a couple of reasons.
     844                 :             :    * Historically, we only did it there because we used to ignore $HOME
     845                 :             :    * on UNIX.  There are concerns about enabling it now on UNIX because
     846                 :             :    * of things like autofs.  In short, if the user has a bogus value in
     847                 :             :    * $HOME then they get what they pay for...
     848                 :             :    */
     849                 :             :   if (home_dir != NULL)
     850                 :             :     {
     851                 :             :       if (!(g_path_is_absolute (home_dir) &&
     852                 :             :             g_file_test (home_dir, G_FILE_TEST_IS_DIR)))
     853                 :             :         g_clear_pointer (&home_dir, g_free);
     854                 :             :     }
     855                 :             : 
     856                 :             :   /* In case HOME is Unix-style (it happens), convert it to
     857                 :             :    * Windows style.
     858                 :             :    */
     859                 :             :   if (home_dir != NULL)
     860                 :             :     {
     861                 :             :       gchar *p;
     862                 :             :       while ((p = strchr (home_dir, '/')) != NULL)
     863                 :             :         *p = '\\';
     864                 :             :     }
     865                 :             : 
     866                 :             :   if (home_dir == NULL)
     867                 :             :     {
     868                 :             :       /* USERPROFILE is probably the closest equivalent to $HOME? */
     869                 :             :       if (g_getenv ("USERPROFILE") != NULL)
     870                 :             :         home_dir = g_strdup (g_getenv ("USERPROFILE"));
     871                 :             :     }
     872                 :             : 
     873                 :             :   if (home_dir == NULL)
     874                 :             :     home_dir = get_special_folder (&FOLDERID_Profile);
     875                 :             : 
     876                 :             :   if (home_dir == NULL)
     877                 :             :     home_dir = get_windows_directory_root ();
     878                 :             : #endif /* G_OS_WIN32 */
     879                 :             : 
     880                 :          89 :   if (home_dir == NULL)
     881                 :             :     {
     882                 :             :       /* If we didn't get it from any of those methods, we will have
     883                 :             :        * to read the user database entry.
     884                 :             :        */
     885                 :           0 :       UserDatabaseEntry *entry = g_get_user_database_entry ();
     886                 :           0 :       home_dir = g_strdup (entry->home_dir);
     887                 :             :     }
     888                 :             : 
     889                 :             :   /* If we have been denied access to /etc/passwd (for example, by an
     890                 :             :    * overly-zealous LSM), make up a junk value. The return value at this
     891                 :             :    * point is explicitly documented as ‘undefined’. */
     892                 :          89 :   if (home_dir == NULL)
     893                 :             :     {
     894                 :           0 :       g_warning ("Could not find home directory: $HOME is not set, and "
     895                 :             :                  "user database could not be read.");
     896                 :           0 :       home_dir = g_strdup ("/");
     897                 :             :     }
     898                 :             : 
     899                 :          89 :   return g_steal_pointer (&home_dir);
     900                 :             : }
     901                 :             : 
     902                 :             : static const gchar *
     903                 :        1262 : g_get_home_dir_unlocked (void)
     904                 :             : {
     905                 :        1262 :   if (g_home_dir == NULL)
     906                 :          60 :     g_home_dir = g_build_home_dir ();
     907                 :             : 
     908                 :        1262 :   return g_home_dir;
     909                 :             : }
     910                 :             : 
     911                 :             : /**
     912                 :             :  * g_get_home_dir:
     913                 :             :  *
     914                 :             :  * Gets the current user's home directory.
     915                 :             :  *
     916                 :             :  * As with most UNIX tools, this function will return the value of the
     917                 :             :  * `HOME` environment variable if it is set to an existing absolute path
     918                 :             :  * name, falling back to the `passwd` file in the case that it is unset.
     919                 :             :  *
     920                 :             :  * If the path given in `HOME` is non-absolute, does not exist, or is
     921                 :             :  * not a directory, the result is undefined.
     922                 :             :  *
     923                 :             :  * Before version 2.36 this function would ignore the `HOME` environment
     924                 :             :  * variable, taking the value from the `passwd` database instead. This was
     925                 :             :  * changed to increase the compatibility of GLib with other programs (and
     926                 :             :  * the XDG basedir specification) and to increase testability of programs
     927                 :             :  * based on GLib (by making it easier to run them from test frameworks).
     928                 :             :  *
     929                 :             :  * If your program has a strong requirement for either the new or the
     930                 :             :  * old behaviour (and if you don't wish to increase your GLib
     931                 :             :  * dependency to ensure that the new behaviour is in effect) then you
     932                 :             :  * should either directly check the `HOME` environment variable yourself
     933                 :             :  * or unset it before calling any functions in GLib.
     934                 :             :  *
     935                 :             :  * Returns: (type filename) (transfer none): the current user's home directory
     936                 :             :  */
     937                 :             : const gchar *
     938                 :        1231 : g_get_home_dir (void)
     939                 :             : {
     940                 :             :   const gchar *home_dir;
     941                 :             : 
     942                 :        1231 :   G_LOCK (g_utils_global);
     943                 :             : 
     944                 :        1231 :   home_dir = g_get_home_dir_unlocked ();
     945                 :             : 
     946                 :        1231 :   G_UNLOCK (g_utils_global);
     947                 :             : 
     948                 :        1231 :   return home_dir;
     949                 :             : }
     950                 :             : 
     951                 :             : void
     952                 :          79 : _g_unset_cached_tmp_dir (void)
     953                 :             : {
     954                 :          79 :   G_LOCK (g_utils_global);
     955                 :             :   /* We have to leak the old value, as user code could be retaining pointers
     956                 :             :    * to it. */
     957                 :          79 :   g_ignore_leak (g_tmp_dir);
     958                 :          79 :   g_tmp_dir = NULL;
     959                 :          79 :   G_UNLOCK (g_utils_global);
     960                 :          79 : }
     961                 :             : 
     962                 :             : /**
     963                 :             :  * g_get_tmp_dir:
     964                 :             :  *
     965                 :             :  * Gets the directory to use for temporary files.
     966                 :             :  *
     967                 :             :  * On UNIX, this is taken from the `TMPDIR` environment variable.
     968                 :             :  * If the variable is not set, `P_tmpdir` is
     969                 :             :  * used, as defined by the system C library. Failing that, a
     970                 :             :  * hard-coded default of "/tmp" is returned.
     971                 :             :  *
     972                 :             :  * On Windows, the `TEMP` environment variable is used, with the
     973                 :             :  * root directory of the Windows installation (eg: "C:\") used
     974                 :             :  * as a default.
     975                 :             :  *
     976                 :             :  * The encoding of the returned string is system-defined. On Windows,
     977                 :             :  * it is always UTF-8. The return value is never %NULL or the empty
     978                 :             :  * string.
     979                 :             :  *
     980                 :             :  * Returns: (type filename) (transfer none): the directory to use for temporary files.
     981                 :             :  */
     982                 :             : const gchar *
     983                 :         607 : g_get_tmp_dir (void)
     984                 :             : {
     985                 :         607 :   G_LOCK (g_utils_global);
     986                 :             : 
     987                 :         607 :   if (g_tmp_dir == NULL)
     988                 :             :     {
     989                 :             :       gchar *tmp;
     990                 :             : 
     991                 :         173 :       tmp = g_strdup (g_getenv ("G_TEST_TMPDIR"));
     992                 :             : 
     993                 :         173 :       if (tmp == NULL || *tmp == '\0')
     994                 :             :         {
     995                 :         107 :           g_free (tmp);
     996                 :         214 :           tmp = g_strdup (g_getenv (
     997                 :             : #ifdef G_OS_WIN32
     998                 :             :             "TEMP"
     999                 :             : #else /* G_OS_WIN32 */
    1000                 :             :             "TMPDIR"
    1001                 :             : #endif /* G_OS_WIN32 */
    1002                 :             :           ));
    1003                 :             :         }
    1004                 :             : 
    1005                 :             : #ifdef G_OS_WIN32
    1006                 :             :       if (tmp == NULL || *tmp == '\0')
    1007                 :             :         {
    1008                 :             :           g_free (tmp);
    1009                 :             :           tmp = get_windows_directory_root ();
    1010                 :             :         }
    1011                 :             : #else /* G_OS_WIN32 */
    1012                 :             : 
    1013                 :             : #ifdef P_tmpdir
    1014                 :         173 :       if (tmp == NULL || *tmp == '\0')
    1015                 :             :         {
    1016                 :             :           gsize k;
    1017                 :         107 :           g_free (tmp);
    1018                 :         107 :           tmp = g_strdup (P_tmpdir);
    1019                 :         107 :           k = strlen (tmp);
    1020                 :         107 :           if (k > 1 && G_IS_DIR_SEPARATOR (tmp[k - 1]))
    1021                 :           0 :             tmp[k - 1] = '\0';
    1022                 :             :         }
    1023                 :             : #endif /* P_tmpdir */
    1024                 :             : 
    1025                 :         173 :       if (tmp == NULL || *tmp == '\0')
    1026                 :             :         {
    1027                 :           0 :           g_free (tmp);
    1028                 :           0 :           tmp = g_strdup ("/tmp");
    1029                 :             :         }
    1030                 :             : #endif /* !G_OS_WIN32 */
    1031                 :             : 
    1032                 :         173 :       g_tmp_dir = g_steal_pointer (&tmp);
    1033                 :             :     }
    1034                 :             : 
    1035                 :         607 :   G_UNLOCK (g_utils_global);
    1036                 :             : 
    1037                 :         607 :   return g_tmp_dir;
    1038                 :             : }
    1039                 :             : 
    1040                 :             : /**
    1041                 :             :  * g_get_host_name:
    1042                 :             :  *
    1043                 :             :  * Return a name for the machine. 
    1044                 :             :  *
    1045                 :             :  * The returned name is not necessarily a fully-qualified domain name,
    1046                 :             :  * or even present in DNS or some other name service at all. It need
    1047                 :             :  * not even be unique on your local network or site, but usually it
    1048                 :             :  * is. Callers should not rely on the return value having any specific
    1049                 :             :  * properties like uniqueness for security purposes. Even if the name
    1050                 :             :  * of the machine is changed while an application is running, the
    1051                 :             :  * return value from this function does not change. The returned
    1052                 :             :  * string is owned by GLib and should not be modified or freed. If no
    1053                 :             :  * name can be determined, a default fixed string "localhost" is
    1054                 :             :  * returned.
    1055                 :             :  *
    1056                 :             :  * The encoding of the returned string is UTF-8.
    1057                 :             :  *
    1058                 :             :  * Returns: (transfer none): the host name of the machine.
    1059                 :             :  *
    1060                 :             :  * Since: 2.8
    1061                 :             :  */
    1062                 :             : const gchar *
    1063                 :           6 : g_get_host_name (void)
    1064                 :             : {
    1065                 :             :   static gchar *hostname;
    1066                 :             : 
    1067                 :           6 :   if (g_once_init_enter_pointer (&hostname))
    1068                 :             :     {
    1069                 :             :       gboolean failed;
    1070                 :           6 :       gchar *utmp = NULL;
    1071                 :             : 
    1072                 :             : #ifndef G_OS_WIN32
    1073                 :             :       gsize size;
    1074                 :             :       /* The number 256 * 256 is taken from the value of _POSIX_HOST_NAME_MAX,
    1075                 :             :        * which is 255. Since we use _POSIX_HOST_NAME_MAX + 1 (= 256) in the
    1076                 :             :        * fallback case, we pick 256 * 256 as the size of the larger buffer here.
    1077                 :             :        * It should be large enough. It doesn't looks reasonable to name a host
    1078                 :             :        * with a string that is longer than 64 KiB.
    1079                 :             :        */
    1080                 :           6 :       const gsize size_large = (gsize) 256 * 256;
    1081                 :             :       gchar *tmp;
    1082                 :             : 
    1083                 :             : #ifdef _SC_HOST_NAME_MAX
    1084                 :             :       {
    1085                 :             :         glong max;
    1086                 :             : 
    1087                 :           6 :         max = sysconf (_SC_HOST_NAME_MAX);
    1088                 :           6 :         if (max > 0 && (gsize) max <= G_MAXSIZE - 1)
    1089                 :           6 :           size = (gsize) max + 1;
    1090                 :             :         else
    1091                 :             : #ifdef HOST_NAME_MAX
    1092                 :           0 :           size = HOST_NAME_MAX + 1;
    1093                 :             : #else
    1094                 :             :           size = _POSIX_HOST_NAME_MAX + 1;
    1095                 :             : #endif /* HOST_NAME_MAX */
    1096                 :             :       }
    1097                 :             : #else
    1098                 :             :       /* Fallback to some reasonable value */
    1099                 :             :       size = 256;
    1100                 :             : #endif /* _SC_HOST_NAME_MAX */
    1101                 :           6 :       tmp = g_malloc (size);
    1102                 :           6 :       failed = (gethostname (tmp, size) == -1);
    1103                 :           6 :       if (failed && size < size_large)
    1104                 :             :         {
    1105                 :             :           /* Try again with a larger buffer if 'size' may be too small. */
    1106                 :           0 :           g_free (tmp);
    1107                 :           0 :           tmp = g_malloc (size_large);
    1108                 :           0 :           failed = (gethostname (tmp, size_large) == -1);
    1109                 :             :         }
    1110                 :             : 
    1111                 :           6 :       if (failed)
    1112                 :           0 :         g_clear_pointer (&tmp, g_free);
    1113                 :           6 :       utmp = tmp;
    1114                 :             : #else
    1115                 :             :       wchar_t tmp[MAX_COMPUTERNAME_LENGTH + 1];
    1116                 :             :       DWORD size = sizeof (tmp) / sizeof (tmp[0]);
    1117                 :             :       failed = (!GetComputerNameW (tmp, &size));
    1118                 :             :       if (!failed)
    1119                 :             :         utmp = g_utf16_to_utf8 (tmp, size, NULL, NULL, NULL);
    1120                 :             :       if (utmp == NULL)
    1121                 :             :         failed = TRUE;
    1122                 :             : #endif
    1123                 :             : 
    1124                 :           6 :       g_once_init_leave_pointer (&hostname, failed ? g_strdup ("localhost") : utmp);
    1125                 :             :     }
    1126                 :             : 
    1127                 :           6 :   return hostname;
    1128                 :             : }
    1129                 :             : 
    1130                 :             : static const gchar *g_prgname = NULL; /* always a quark */
    1131                 :             : 
    1132                 :             : /**
    1133                 :             :  * g_get_prgname:
    1134                 :             :  *
    1135                 :             :  * Gets the name of the program. This name should not be localized,
    1136                 :             :  * in contrast to g_get_application_name().
    1137                 :             :  *
    1138                 :             :  * If you are using #GApplication the program name is set in
    1139                 :             :  * g_application_run(). In case of GDK or GTK it is set in
    1140                 :             :  * gdk_init(), which is called by gtk_init() and the
    1141                 :             :  * #GtkApplication::startup handler. The program name is found by
    1142                 :             :  * taking the last component of @argv[0].
    1143                 :             :  *
    1144                 :             :  * Returns: (nullable) (transfer none): the name of the program,
    1145                 :             :  *   or %NULL if it has not been set yet. The returned string belongs
    1146                 :             :  *   to GLib and must not be modified or freed.
    1147                 :             :  */
    1148                 :             : const gchar*
    1149                 :       16312 : g_get_prgname (void)
    1150                 :             : {
    1151                 :       16312 :   return g_atomic_pointer_get (&g_prgname);
    1152                 :             : }
    1153                 :             : 
    1154                 :             : /**
    1155                 :             :  * g_set_prgname:
    1156                 :             :  * @prgname: the name of the program.
    1157                 :             :  *
    1158                 :             :  * Sets the name of the program. This name should not be localized,
    1159                 :             :  * in contrast to g_set_application_name().
    1160                 :             :  *
    1161                 :             :  * If you are using #GApplication the program name is set in
    1162                 :             :  * g_application_run(). In case of GDK or GTK it is set in
    1163                 :             :  * gdk_init(), which is called by gtk_init() and the
    1164                 :             :  * #GtkApplication::startup handler. By default, the program name is
    1165                 :             :  * found by taking the last component of @argv[0].
    1166                 :             :  *
    1167                 :             :  * Since GLib 2.72, this function can be called multiple times
    1168                 :             :  * and is fully thread safe. Prior to GLib 2.72, this function
    1169                 :             :  * could only be called once per process.
    1170                 :             :  *
    1171                 :             :  * See the [GTK documentation](https://docs.gtk.org/gtk4/migrating-3to4.html#set-a-proper-application-id)
    1172                 :             :  * for requirements on integrating g_set_prgname() with GTK applications.
    1173                 :             :  */
    1174                 :             : void
    1175                 :          75 : g_set_prgname (const gchar *prgname)
    1176                 :             : {
    1177                 :          75 :   prgname = g_intern_string (prgname);
    1178                 :          75 :   g_atomic_pointer_set (&g_prgname, prgname);
    1179                 :          75 : }
    1180                 :             : 
    1181                 :             : /**
    1182                 :             :  * g_set_prgname_once:
    1183                 :             :  * @prgname: the name of the program.
    1184                 :             :  *
    1185                 :             :  * If g_get_prgname() is not set, this is the same as setting
    1186                 :             :  * the name via g_set_prgname() and %TRUE is returned. Otherwise,
    1187                 :             :  * does nothing and returns %FALSE. This is thread-safe.
    1188                 :             :  *
    1189                 :             :  * Returns: whether g_prgname was initialized by the call.
    1190                 :             :  */
    1191                 :             : gboolean
    1192                 :         865 : g_set_prgname_once (const gchar *prgname)
    1193                 :             : {
    1194                 :             :   /* if @prgname is NULL, then this has the same effect as calling
    1195                 :             :    * (g_get_prgname()==NULL). */
    1196                 :         865 :   prgname = g_intern_string (prgname);
    1197                 :         865 :   return g_atomic_pointer_compare_and_exchange (&g_prgname, NULL, prgname);
    1198                 :             : }
    1199                 :             : 
    1200                 :             : static gchar *g_application_name = NULL;
    1201                 :             : 
    1202                 :             : /**
    1203                 :             :  * g_get_application_name:
    1204                 :             :  * 
    1205                 :             :  * Gets a human-readable name for the application, as set by
    1206                 :             :  * g_set_application_name(). This name should be localized if
    1207                 :             :  * possible, and is intended for display to the user.  Contrast with
    1208                 :             :  * g_get_prgname(), which gets a non-localized name. If
    1209                 :             :  * g_set_application_name() has not been called, returns the result of
    1210                 :             :  * g_get_prgname() (which may be %NULL if g_set_prgname() has also not
    1211                 :             :  * been called).
    1212                 :             :  * 
    1213                 :             :  * Returns: (transfer none) (nullable): human-readable application
    1214                 :             :  *   name. May return %NULL
    1215                 :             :  *
    1216                 :             :  * Since: 2.2
    1217                 :             :  **/
    1218                 :             : const gchar *
    1219                 :          24 : g_get_application_name (void)
    1220                 :             : {
    1221                 :             :   const char *retval;
    1222                 :             : 
    1223                 :          24 :   retval = g_atomic_pointer_get (&g_application_name);
    1224                 :             : 
    1225                 :          24 :   if (retval)
    1226                 :           6 :     return retval;
    1227                 :             : 
    1228                 :          18 :   return g_get_prgname ();
    1229                 :             : }
    1230                 :             : 
    1231                 :             : /**
    1232                 :             :  * g_set_application_name:
    1233                 :             :  * @application_name: localized name of the application
    1234                 :             :  *
    1235                 :             :  * Sets a human-readable name for the application. This name should be
    1236                 :             :  * localized if possible, and is intended for display to the user.
    1237                 :             :  * Contrast with g_set_prgname(), which sets a non-localized name.
    1238                 :             :  * g_set_prgname() will be called automatically by gtk_init(),
    1239                 :             :  * but g_set_application_name() will not.
    1240                 :             :  *
    1241                 :             :  * Note that for thread safety reasons, this function can only
    1242                 :             :  * be called once.
    1243                 :             :  *
    1244                 :             :  * The application name will be used in contexts such as error messages,
    1245                 :             :  * or when displaying an application's name in the task list.
    1246                 :             :  * 
    1247                 :             :  * Since: 2.2
    1248                 :             :  **/
    1249                 :             : void
    1250                 :           6 : g_set_application_name (const gchar *application_name)
    1251                 :             : {
    1252                 :             :   char *name;
    1253                 :             : 
    1254                 :           6 :   g_return_if_fail (application_name);
    1255                 :             : 
    1256                 :           6 :   name = g_strdup (application_name);
    1257                 :             : 
    1258                 :           6 :   if (!g_atomic_pointer_compare_and_exchange (&g_application_name, NULL, name))
    1259                 :             :     {
    1260                 :           0 :       g_warning ("g_set_application_name() called multiple times");
    1261                 :           0 :       g_free (name);
    1262                 :             :     }
    1263                 :             : }
    1264                 :             : 
    1265                 :             : #ifdef G_OS_WIN32
    1266                 :             : /* For the past versions we can just
    1267                 :             :  * hardcode all the names.
    1268                 :             :  */
    1269                 :             : static const struct winver
    1270                 :             : {
    1271                 :             :   gint major;
    1272                 :             :   gint minor;
    1273                 :             :   gint sp;
    1274                 :             :   const char *version;
    1275                 :             :   const char *spversion;
    1276                 :             : } versions[] =
    1277                 :             : {
    1278                 :             :   {6, 2, 0, "8", ""},
    1279                 :             :   {6, 1, 1, "7", " SP1"},
    1280                 :             :   {6, 1, 0, "7", ""},
    1281                 :             :   {6, 0, 2, "Vista", " SP2"},
    1282                 :             :   {6, 0, 1, "Vista", " SP1"},
    1283                 :             :   {6, 0, 0, "Vista", ""},
    1284                 :             :   {5, 1, 3, "XP", " SP3"},
    1285                 :             :   {5, 1, 2, "XP", " SP2"},
    1286                 :             :   {5, 1, 1, "XP", " SP1"},
    1287                 :             :   {5, 1, 0, "XP", ""},
    1288                 :             :   {0, 0, 0, NULL, NULL},
    1289                 :             : };
    1290                 :             : 
    1291                 :             : static gchar *
    1292                 :             : get_registry_str (HKEY root_key, const wchar_t *path, const wchar_t *value_name)
    1293                 :             : {
    1294                 :             :   HKEY key_handle;
    1295                 :             :   DWORD req_value_data_size;
    1296                 :             :   DWORD req_value_data_size2;
    1297                 :             :   LONG status;
    1298                 :             :   DWORD value_type_w;
    1299                 :             :   DWORD value_type_w2;
    1300                 :             :   char *req_value_data;
    1301                 :             :   gchar *result;
    1302                 :             : 
    1303                 :             :   status = RegOpenKeyExW (root_key, path, 0, KEY_READ, &key_handle);
    1304                 :             :   if (status != ERROR_SUCCESS)
    1305                 :             :     return NULL;
    1306                 :             : 
    1307                 :             :   req_value_data_size = 0;
    1308                 :             :   status = RegQueryValueExW (key_handle,
    1309                 :             :                              value_name,
    1310                 :             :                              NULL,
    1311                 :             :                              &value_type_w,
    1312                 :             :                              NULL,
    1313                 :             :                              &req_value_data_size);
    1314                 :             : 
    1315                 :             :   if (status != ERROR_MORE_DATA && status != ERROR_SUCCESS)
    1316                 :             :     {
    1317                 :             :       RegCloseKey (key_handle);
    1318                 :             : 
    1319                 :             :       return NULL;
    1320                 :             :     }
    1321                 :             : 
    1322                 :             :   req_value_data = g_malloc (req_value_data_size);
    1323                 :             :   req_value_data_size2 = req_value_data_size;
    1324                 :             : 
    1325                 :             :   status = RegQueryValueExW (key_handle,
    1326                 :             :                              value_name,
    1327                 :             :                              NULL,
    1328                 :             :                              &value_type_w2,
    1329                 :             :                              (gpointer) req_value_data,
    1330                 :             :                              &req_value_data_size2);
    1331                 :             : 
    1332                 :             :   result = NULL;
    1333                 :             : 
    1334                 :             :   if (status == ERROR_SUCCESS && value_type_w2 == REG_SZ)
    1335                 :             :     result = g_utf16_to_utf8 ((gunichar2 *) req_value_data,
    1336                 :             :                               req_value_data_size / sizeof (gunichar2),
    1337                 :             :                               NULL,
    1338                 :             :                               NULL,
    1339                 :             :                               NULL);
    1340                 :             : 
    1341                 :             :   g_free (req_value_data);
    1342                 :             :   RegCloseKey (key_handle);
    1343                 :             : 
    1344                 :             :   return result;
    1345                 :             : }
    1346                 :             : 
    1347                 :             : /* Windows 8.1 can be either plain or with Update 1,
    1348                 :             :  * depending on its build number (9200 or 9600).
    1349                 :             :  */
    1350                 :             : static gchar *
    1351                 :             : get_windows_8_1_update (void)
    1352                 :             : {
    1353                 :             :   gchar *current_build;
    1354                 :             :   gchar *result = NULL;
    1355                 :             : 
    1356                 :             :   current_build = get_registry_str (HKEY_LOCAL_MACHINE,
    1357                 :             :                                     L"SOFTWARE"
    1358                 :             :                                     L"\\Microsoft"
    1359                 :             :                                     L"\\Windows NT"
    1360                 :             :                                     L"\\CurrentVersion",
    1361                 :             :                                     L"CurrentBuild");
    1362                 :             : 
    1363                 :             :   if (current_build != NULL)
    1364                 :             :     {
    1365                 :             :       wchar_t *end;
    1366                 :             :       long build = wcstol ((const wchar_t *) current_build, &end, 10);
    1367                 :             : 
    1368                 :             :       if (build <= INT_MAX &&
    1369                 :             :           build >= INT_MIN &&
    1370                 :             :           errno == 0 &&
    1371                 :             :           *end == L'\0')
    1372                 :             :         {
    1373                 :             :           if (build >= 9600)
    1374                 :             :             result = g_strdup ("Update 1");
    1375                 :             :         }
    1376                 :             :     }
    1377                 :             : 
    1378                 :             :   g_clear_pointer (&current_build, g_free);
    1379                 :             : 
    1380                 :             :   return result;
    1381                 :             : }
    1382                 :             : 
    1383                 :             : static gchar *
    1384                 :             : get_windows_version (gboolean with_windows)
    1385                 :             : {
    1386                 :             :   GString *version = g_string_new (NULL);
    1387                 :             :   gboolean is_win_server = FALSE;
    1388                 :             : 
    1389                 :             :   if (g_win32_check_windows_version (10, 0, 0, G_WIN32_OS_ANY))
    1390                 :             :     {
    1391                 :             :       gchar *win10_release;
    1392                 :             :       gboolean is_win11 = FALSE;
    1393                 :             :       OSVERSIONINFOEXW osinfo;
    1394                 :             : 
    1395                 :             :       /* Are we on Windows 2016/2019/2022 Server? */
    1396                 :             :       is_win_server = g_win32_check_windows_version (10, 0, 0, G_WIN32_OS_SERVER);
    1397                 :             : 
    1398                 :             :       /*
    1399                 :             :        * This always succeeds if we get here, since the
    1400                 :             :        * g_win32_check_windows_version() already did this!
    1401                 :             :        * We want the OSVERSIONINFOEXW here for more even
    1402                 :             :        * fine-grained versioning items
    1403                 :             :        */
    1404                 :             :       _g_win32_call_rtl_version (&osinfo);
    1405                 :             : 
    1406                 :             :       if (!is_win_server)
    1407                 :             :         {
    1408                 :             :           /*
    1409                 :             :            * Windows 11 is actually Windows 10.0.22000+,
    1410                 :             :            * so look at the build number
    1411                 :             :            */
    1412                 :             :           is_win11 = (osinfo.dwBuildNumber >= 22000);
    1413                 :             :         }
    1414                 :             :       else
    1415                 :             :         {
    1416                 :             :           /*
    1417                 :             :            * Windows 2022 Server is actually Windows 10.0.20348+,
    1418                 :             :            * Windows 2019 Server is actually Windows 10.0.17763+,
    1419                 :             :            * Windows 2016 Server is actually Windows 10.0.14393+,
    1420                 :             :            * so look at the build number
    1421                 :             :            */
    1422                 :             :           g_string_append (version, "Server");
    1423                 :             :           if (osinfo.dwBuildNumber >= 20348)
    1424                 :             :             g_string_append (version, " 2022");
    1425                 :             :           else if (osinfo.dwBuildNumber >= 17763)
    1426                 :             :             g_string_append (version, " 2019");
    1427                 :             :           else
    1428                 :             :             g_string_append (version, " 2016");
    1429                 :             :         }
    1430                 :             : 
    1431                 :             :       if (is_win11)
    1432                 :             :         g_string_append (version, "11");
    1433                 :             :       else if (!is_win_server)
    1434                 :             :         g_string_append (version, "10");
    1435                 :             : 
    1436                 :             :       /* Windows 10/Server 2016+ is identified by its ReleaseId or
    1437                 :             :        * DisplayVersion (since 20H2), such as
    1438                 :             :        * 1511, 1607, 1703, 1709, 1803, 1809 or 1903 etc.
    1439                 :             :        * The first version of Windows 10 has no release number.
    1440                 :             :        */
    1441                 :             :       win10_release = get_registry_str (HKEY_LOCAL_MACHINE,
    1442                 :             :                                         L"SOFTWARE"
    1443                 :             :                                         L"\\Microsoft"
    1444                 :             :                                         L"\\Windows NT"
    1445                 :             :                                         L"\\CurrentVersion",
    1446                 :             :                                         L"ReleaseId");
    1447                 :             : 
    1448                 :             :       if (win10_release != NULL)
    1449                 :             :         {
    1450                 :             :           if (g_strcmp0 (win10_release, "2009") != 0)
    1451                 :             :             g_string_append_printf (version, " %s", win10_release);
    1452                 :             :           else
    1453                 :             :             {
    1454                 :             :               g_free (win10_release);
    1455                 :             : 
    1456                 :             :               win10_release = get_registry_str (HKEY_LOCAL_MACHINE,
    1457                 :             :                                                 L"SOFTWARE"
    1458                 :             :                                                 L"\\Microsoft"
    1459                 :             :                                                 L"\\Windows NT"
    1460                 :             :                                                 L"\\CurrentVersion",
    1461                 :             :                                                 L"DisplayVersion");
    1462                 :             : 
    1463                 :             :               if (win10_release != NULL)
    1464                 :             :                 g_string_append_printf (version, " %s", win10_release);
    1465                 :             :               else
    1466                 :             :                 g_string_append_printf (version, " 2009");
    1467                 :             :             }
    1468                 :             :         }
    1469                 :             : 
    1470                 :             :       g_free (win10_release);
    1471                 :             :     }
    1472                 :             :   else if (g_win32_check_windows_version (6, 3, 0, G_WIN32_OS_ANY))
    1473                 :             :     {
    1474                 :             :       gchar *win81_update;
    1475                 :             : 
    1476                 :             :       if (g_win32_check_windows_version (6, 3, 0, G_WIN32_OS_WORKSTATION))
    1477                 :             :         g_string_append (version, "8.1");
    1478                 :             :       else
    1479                 :             :         g_string_append (version, "Server 2012 R2");
    1480                 :             : 
    1481                 :             :       win81_update = get_windows_8_1_update ();
    1482                 :             : 
    1483                 :             :       if (win81_update != NULL)
    1484                 :             :         g_string_append_printf (version, " %s", win81_update);
    1485                 :             : 
    1486                 :             :       g_free (win81_update);
    1487                 :             :     }
    1488                 :             :   else
    1489                 :             :     {
    1490                 :             :       gint i;
    1491                 :             : 
    1492                 :             :       for (i = 0; versions[i].major > 0; i++)
    1493                 :             :         {
    1494                 :             :           if (!g_win32_check_windows_version (versions[i].major, versions[i].minor, versions[i].sp, G_WIN32_OS_ANY))
    1495                 :             :             continue;
    1496                 :             : 
    1497                 :             :           g_string_append (version, versions[i].version);
    1498                 :             : 
    1499                 :             :           if (g_win32_check_windows_version (versions[i].major, versions[i].minor, versions[i].sp, G_WIN32_OS_SERVER))
    1500                 :             :             {
    1501                 :             :               /*
    1502                 :             :                * This condition should now always hold, since Windows
    1503                 :             :                * 7+/Server 2008 R2+ is now required
    1504                 :             :                */
    1505                 :             :               if (versions[i].major == 6)
    1506                 :             :                 {
    1507                 :             :                   g_string_append (version, "Server");
    1508                 :             :                   if (versions[i].minor == 2)
    1509                 :             :                     g_string_append (version, " 2012");
    1510                 :             :                   else if (versions[i].minor == 1)
    1511                 :             :                     g_string_append (version, " 2008 R2");
    1512                 :             :                   else
    1513                 :             :                     g_string_append (version, " 2008");
    1514                 :             :                 }
    1515                 :             :             }
    1516                 :             : 
    1517                 :             :           g_string_append (version, versions[i].spversion);
    1518                 :             : 
    1519                 :             :           break;
    1520                 :             :         }
    1521                 :             :     }
    1522                 :             : 
    1523                 :             :   if (version->len == 0)
    1524                 :             :     {
    1525                 :             :       g_string_free (version, TRUE);
    1526                 :             : 
    1527                 :             :       return NULL;
    1528                 :             :     }
    1529                 :             : 
    1530                 :             :   if (with_windows)
    1531                 :             :     g_string_prepend (version, "Windows ");
    1532                 :             : 
    1533                 :             :   return g_string_free (version, FALSE);
    1534                 :             : }
    1535                 :             : #endif
    1536                 :             : 
    1537                 :             : #if defined (G_OS_UNIX) && !defined (__APPLE__)
    1538                 :             : static gchar *
    1539                 :           6 : get_os_info_from_os_release (const gchar *key_name,
    1540                 :             :                              const gchar *buffer)
    1541                 :             : {
    1542                 :             :   GStrv lines;
    1543                 :             :   gchar *prefix;
    1544                 :             :   size_t i;
    1545                 :           6 :   gchar *result = NULL;
    1546                 :             : 
    1547                 :           6 :   lines = g_strsplit (buffer, "\n", -1);
    1548                 :           6 :   prefix = g_strdup_printf ("%s=", key_name);
    1549                 :           6 :   for (i = 0; lines[i] != NULL; i++)
    1550                 :             :     {
    1551                 :           6 :       const gchar *line = lines[i];
    1552                 :             :       const gchar *value;
    1553                 :             : 
    1554                 :           6 :       if (g_str_has_prefix (line, prefix))
    1555                 :             :         {
    1556                 :           6 :           value = line + strlen (prefix);
    1557                 :           6 :           result = g_shell_unquote (value, NULL);
    1558                 :           6 :           if (result == NULL)
    1559                 :           0 :             result = g_strdup (value);
    1560                 :           6 :           break;
    1561                 :             :         }
    1562                 :             :     }
    1563                 :           6 :   g_strfreev (lines);
    1564                 :           6 :   g_free (prefix);
    1565                 :             : 
    1566                 :             : #ifdef __linux__
    1567                 :             :   /* Default values in spec */
    1568                 :           6 :   if (result == NULL)
    1569                 :             :     {
    1570                 :           0 :       if (g_str_equal (key_name, G_OS_INFO_KEY_NAME))
    1571                 :           0 :         return g_strdup ("Linux");
    1572                 :           0 :       if (g_str_equal (key_name, G_OS_INFO_KEY_ID))
    1573                 :           0 :         return g_strdup ("linux");
    1574                 :           0 :       if (g_str_equal (key_name, G_OS_INFO_KEY_PRETTY_NAME))
    1575                 :           0 :         return g_strdup ("Linux");
    1576                 :             :     }
    1577                 :             : #endif
    1578                 :             : 
    1579                 :           6 :   return g_steal_pointer (&result);
    1580                 :             : }
    1581                 :             : 
    1582                 :             : static gchar *
    1583                 :           0 : get_os_info_from_uname (const gchar *key_name)
    1584                 :             : {
    1585                 :             :   struct utsname info;
    1586                 :             : 
    1587                 :           0 :   if (uname (&info) == -1)
    1588                 :           0 :     return NULL;
    1589                 :             : 
    1590                 :           0 :   if (strcmp (key_name, G_OS_INFO_KEY_NAME) == 0)
    1591                 :           0 :     return g_strdup (info.sysname);
    1592                 :           0 :   else if (strcmp (key_name, G_OS_INFO_KEY_VERSION) == 0)
    1593                 :           0 :     return g_strdup (info.release);
    1594                 :           0 :   else if (strcmp (key_name, G_OS_INFO_KEY_PRETTY_NAME) == 0)
    1595                 :           0 :     return g_strdup_printf ("%s %s", info.sysname, info.release);
    1596                 :           0 :   else if (strcmp (key_name, G_OS_INFO_KEY_ID) == 0)
    1597                 :             :     {
    1598                 :           0 :       gchar *result = g_ascii_strdown (info.sysname, -1);
    1599                 :             : 
    1600                 :           0 :       g_strcanon (result, "abcdefghijklmnopqrstuvwxyz0123456789_-.", '_');
    1601                 :           0 :       return g_steal_pointer (&result);
    1602                 :             :     }
    1603                 :           0 :   else if (strcmp (key_name, G_OS_INFO_KEY_VERSION_ID) == 0)
    1604                 :             :     {
    1605                 :             :       /* We attempt to convert the version string to the format returned by
    1606                 :             :        * config.guess, which is the script used to generate target triplets
    1607                 :             :        * in GNU autotools. There are a lot of rules in the script. We only
    1608                 :             :        * implement a few rules which are easy to understand here.
    1609                 :             :        *
    1610                 :             :        * config.guess can be found at https://savannah.gnu.org/projects/config.
    1611                 :             :        */
    1612                 :             :       gchar *result;
    1613                 :             : 
    1614                 :           0 :       if (strcmp (info.sysname, "NetBSD") == 0)
    1615                 :             :         {
    1616                 :             :           /* sed -e 's,[-_].*,,' */
    1617                 :           0 :           gssize len = G_MAXSSIZE;
    1618                 :             :           const gchar *c;
    1619                 :             : 
    1620                 :           0 :           if ((c = strchr (info.release, '-')) != NULL)
    1621                 :           0 :             len = MIN (len, c - info.release);
    1622                 :           0 :           if ((c = strchr (info.release, '_')) != NULL)
    1623                 :           0 :             len = MIN (len, c - info.release);
    1624                 :           0 :           if (len == G_MAXSSIZE)
    1625                 :           0 :             len = -1;
    1626                 :             : 
    1627                 :           0 :           result = g_ascii_strdown (info.release, len);
    1628                 :             :         }
    1629                 :           0 :       else if (strcmp (info.sysname, "GNU") == 0)
    1630                 :             :         {
    1631                 :             :           /* sed -e 's,/.*$,,' */
    1632                 :           0 :           gssize len = -1;
    1633                 :           0 :           const gchar *c = strchr (info.release, '/');
    1634                 :             : 
    1635                 :           0 :           if (c != NULL)
    1636                 :           0 :             len = c - info.release;
    1637                 :             : 
    1638                 :           0 :           result = g_ascii_strdown (info.release, len);
    1639                 :             :         }
    1640                 :           0 :       else if (g_str_has_prefix (info.sysname, "GNU/") ||
    1641                 :           0 :                strcmp (info.sysname, "FreeBSD") == 0 ||
    1642                 :           0 :                strcmp (info.sysname, "DragonFly") == 0)
    1643                 :           0 :         {
    1644                 :             :           /* sed -e 's,[-(].*,,' */
    1645                 :           0 :           gssize len = G_MAXSSIZE;
    1646                 :             :           const gchar *c;
    1647                 :             : 
    1648                 :           0 :           if ((c = strchr (info.release, '-')) != NULL)
    1649                 :           0 :             len = MIN (len, c - info.release);
    1650                 :           0 :           if ((c = strchr (info.release, '(')) != NULL)
    1651                 :           0 :             len = MIN (len, c - info.release);
    1652                 :           0 :           if (len == G_MAXSSIZE)
    1653                 :           0 :             len = -1;
    1654                 :             : 
    1655                 :           0 :           result = g_ascii_strdown (info.release, len);
    1656                 :             :         }
    1657                 :             :       else
    1658                 :           0 :         result = g_ascii_strdown (info.release, -1);
    1659                 :             : 
    1660                 :           0 :       g_strcanon (result, "abcdefghijklmnopqrstuvwxyz0123456789_-.", '_');
    1661                 :           0 :       return g_steal_pointer (&result);
    1662                 :             :     }
    1663                 :             :   else
    1664                 :           0 :     return NULL;
    1665                 :             : }
    1666                 :             : #endif  /* defined (G_OS_UNIX) && !defined (__APPLE__) */
    1667                 :             : 
    1668                 :             : /**
    1669                 :             :  * g_get_os_info:
    1670                 :             :  * @key_name: a key for the OS info being requested, for example %G_OS_INFO_KEY_NAME.
    1671                 :             :  *
    1672                 :             :  * Get information about the operating system.
    1673                 :             :  *
    1674                 :             :  * On Linux this comes from the `/etc/os-release` file. On other systems, it may
    1675                 :             :  * come from a variety of sources. You can either use the standard key names
    1676                 :             :  * like %G_OS_INFO_KEY_NAME or pass any UTF-8 string key name. For example,
    1677                 :             :  * `/etc/os-release` provides a number of other less commonly used values that may
    1678                 :             :  * be useful. No key is guaranteed to be provided, so the caller should always
    1679                 :             :  * check if the result is %NULL.
    1680                 :             :  *
    1681                 :             :  * Returns: (nullable): The associated value for the requested key or %NULL if
    1682                 :             :  *   this information is not provided.
    1683                 :             :  *
    1684                 :             :  * Since: 2.64
    1685                 :             :  **/
    1686                 :             : gchar *
    1687                 :           6 : g_get_os_info (const gchar *key_name)
    1688                 :             : {
    1689                 :             : #if defined (__APPLE__)
    1690                 :             :   if (g_strcmp0 (key_name, G_OS_INFO_KEY_NAME) == 0)
    1691                 :             :     return g_strdup ("macOS");
    1692                 :             :   else
    1693                 :             :     return NULL;
    1694                 :             : #elif defined (G_OS_UNIX)
    1695                 :           6 :   const gchar * const os_release_files[] = { "/etc/os-release", "/usr/lib/os-release" };
    1696                 :             :   gsize i;
    1697                 :           6 :   gchar *buffer = NULL;
    1698                 :           6 :   gchar *result = NULL;
    1699                 :             : 
    1700                 :           6 :   g_return_val_if_fail (key_name != NULL, NULL);
    1701                 :             : 
    1702                 :           6 :   for (i = 0; i < G_N_ELEMENTS (os_release_files); i++)
    1703                 :             :     {
    1704                 :           6 :       GError *error = NULL;
    1705                 :             :       gboolean file_missing;
    1706                 :             : 
    1707                 :           6 :       if (g_file_get_contents (os_release_files[i], &buffer, NULL, &error))
    1708                 :           6 :         break;
    1709                 :             : 
    1710                 :           0 :       file_missing = g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT);
    1711                 :           0 :       g_clear_error (&error);
    1712                 :             : 
    1713                 :           0 :       if (!file_missing)
    1714                 :           0 :         return NULL;
    1715                 :             :     }
    1716                 :             : 
    1717                 :           6 :   if (buffer != NULL)
    1718                 :           6 :     result = get_os_info_from_os_release (key_name, buffer);
    1719                 :             :   else
    1720                 :           0 :     result = get_os_info_from_uname (key_name);
    1721                 :             : 
    1722                 :           6 :   g_free (buffer);
    1723                 :           6 :   return g_steal_pointer (&result);
    1724                 :             : #elif defined (G_OS_WIN32)
    1725                 :             :   if (g_strcmp0 (key_name, G_OS_INFO_KEY_NAME) == 0)
    1726                 :             :     return g_strdup ("Windows");
    1727                 :             :   else if (g_strcmp0 (key_name, G_OS_INFO_KEY_ID) == 0)
    1728                 :             :     return g_strdup ("windows");
    1729                 :             :   else if (g_strcmp0 (key_name, G_OS_INFO_KEY_PRETTY_NAME) == 0)
    1730                 :             :     /* Windows XP SP2 or Windows 10 1903 or Windows 7 Server SP1 */
    1731                 :             :     return get_windows_version (TRUE);
    1732                 :             :   else if (g_strcmp0 (key_name, G_OS_INFO_KEY_VERSION) == 0)
    1733                 :             :     /* XP SP2 or 10 1903 or 7 Server SP1 */
    1734                 :             :     return get_windows_version (FALSE);
    1735                 :             :   else if (g_strcmp0 (key_name, G_OS_INFO_KEY_VERSION_ID) == 0)
    1736                 :             :     {
    1737                 :             :       /* xp_sp2 or 10_1903 or 7_server_sp1 */
    1738                 :             :       gchar *result;
    1739                 :             :       gchar *version = get_windows_version (FALSE);
    1740                 :             : 
    1741                 :             :       if (version == NULL)
    1742                 :             :         return NULL;
    1743                 :             : 
    1744                 :             :       result = g_ascii_strdown (version, -1);
    1745                 :             :       g_free (version);
    1746                 :             : 
    1747                 :             :       return g_strcanon (result, "abcdefghijklmnopqrstuvwxyz0123456789_-.", '_');
    1748                 :             :     }
    1749                 :             :   else if (g_strcmp0 (key_name, G_OS_INFO_KEY_HOME_URL) == 0)
    1750                 :             :     return g_strdup ("https://microsoft.com/windows/");
    1751                 :             :   else if (g_strcmp0 (key_name, G_OS_INFO_KEY_DOCUMENTATION_URL) == 0)
    1752                 :             :     return g_strdup ("https://docs.microsoft.com/");
    1753                 :             :   else if (g_strcmp0 (key_name, G_OS_INFO_KEY_SUPPORT_URL) == 0)
    1754                 :             :     return g_strdup ("https://support.microsoft.com/");
    1755                 :             :   else if (g_strcmp0 (key_name, G_OS_INFO_KEY_BUG_REPORT_URL) == 0)
    1756                 :             :     return g_strdup ("https://support.microsoft.com/contactus/");
    1757                 :             :   else if (g_strcmp0 (key_name, G_OS_INFO_KEY_PRIVACY_POLICY_URL) == 0)
    1758                 :             :     return g_strdup ("https://privacy.microsoft.com/");
    1759                 :             :   else
    1760                 :             :     return NULL;
    1761                 :             : #endif
    1762                 :             : }
    1763                 :             : 
    1764                 :             : /* Set @global_str to a copy of @new_value if it’s currently unset or has a
    1765                 :             :  * different value. If its current value matches @new_value, do nothing. If
    1766                 :             :  * replaced, we have to leak the old value as client code could still have
    1767                 :             :  * pointers to it. */
    1768                 :             : static void
    1769                 :        5982 : set_str_if_different (gchar       **global_str,
    1770                 :             :                       const gchar  *type,
    1771                 :             :                       const gchar  *new_value)
    1772                 :             : {
    1773                 :        5982 :   if (*global_str == NULL ||
    1774                 :        5246 :       !g_str_equal (new_value, *global_str))
    1775                 :             :     {
    1776                 :        5982 :       g_debug ("g_set_user_dirs: Setting %s to %s", type, new_value);
    1777                 :             : 
    1778                 :             :       /* We have to leak the old value, as user code could be retaining pointers
    1779                 :             :        * to it. */
    1780                 :        5982 :       g_ignore_leak (*global_str);
    1781                 :        5982 :       *global_str = g_strdup (new_value);
    1782                 :             :     }
    1783                 :        5982 : }
    1784                 :             : 
    1785                 :             : static void
    1786                 :        1994 : set_strv_if_different (gchar                ***global_strv,
    1787                 :             :                        const gchar            *type,
    1788                 :             :                        const gchar  * const   *new_value)
    1789                 :             : {
    1790                 :        3743 :   if (*global_strv == NULL ||
    1791                 :        1749 :       !g_strv_equal (new_value, (const gchar * const *) *global_strv))
    1792                 :             :     {
    1793                 :        1994 :       gchar *new_value_str = g_strjoinv (":", (gchar **) new_value);
    1794                 :        1994 :       g_debug ("g_set_user_dirs: Setting %s to %s", type, new_value_str);
    1795                 :        1994 :       g_free (new_value_str);
    1796                 :             : 
    1797                 :             :       /* We have to leak the old value, as user code could be retaining pointers
    1798                 :             :        * to it. */
    1799                 :        1994 :       g_ignore_strv_leak (*global_strv);
    1800                 :        1994 :       *global_strv = g_strdupv ((gchar **) new_value);
    1801                 :             :     }
    1802                 :        1994 : }
    1803                 :             : 
    1804                 :             : /*
    1805                 :             :  * g_set_user_dirs:
    1806                 :             :  * @first_dir_type: Type of the first directory to set
    1807                 :             :  * @...: Value to set the first directory to, followed by additional type/value
    1808                 :             :  *    pairs, followed by %NULL
    1809                 :             :  *
    1810                 :             :  * Set one or more ‘user’ directories to custom values. This is intended to be
    1811                 :             :  * used by test code (particularly with the %G_TEST_OPTION_ISOLATE_DIRS option)
    1812                 :             :  * to override the values returned by the following functions, so that test
    1813                 :             :  * code can be run without touching an installed system and user data:
    1814                 :             :  *
    1815                 :             :  *  - g_get_home_dir() — use type `HOME`, pass a string
    1816                 :             :  *  - g_get_user_cache_dir() — use type `XDG_CACHE_HOME`, pass a string
    1817                 :             :  *  - g_get_system_config_dirs() — use type `XDG_CONFIG_DIRS`, pass a
    1818                 :             :  *    %NULL-terminated string array
    1819                 :             :  *  - g_get_user_config_dir() — use type `XDG_CONFIG_HOME`, pass a string
    1820                 :             :  *  - g_get_system_data_dirs() — use type `XDG_DATA_DIRS`, pass a
    1821                 :             :  *    %NULL-terminated string array
    1822                 :             :  *  - g_get_user_data_dir() — use type `XDG_DATA_HOME`, pass a string
    1823                 :             :  *  - g_get_user_runtime_dir() — use type `XDG_RUNTIME_DIR`, pass a string
    1824                 :             :  *
    1825                 :             :  * The list must be terminated with a %NULL type. All of the values must be
    1826                 :             :  * non-%NULL — passing %NULL as a value won’t reset a directory. If a reference
    1827                 :             :  * to a directory from the calling environment needs to be kept, copy it before
    1828                 :             :  * the first call to g_set_user_dirs(). g_set_user_dirs() can be called multiple
    1829                 :             :  * times.
    1830                 :             :  *
    1831                 :             :  * Since: 2.60
    1832                 :             :  */
    1833                 :             : /*< private > */
    1834                 :             : void
    1835                 :         997 : g_set_user_dirs (const gchar *first_dir_type,
    1836                 :             :                  ...)
    1837                 :             : {
    1838                 :             :   va_list args;
    1839                 :             :   const gchar *dir_type;
    1840                 :             : 
    1841                 :         997 :   G_LOCK (g_utils_global);
    1842                 :             : 
    1843                 :         997 :   va_start (args, first_dir_type);
    1844                 :             : 
    1845                 :        8973 :   for (dir_type = first_dir_type; dir_type != NULL; dir_type = va_arg (args, const gchar *))
    1846                 :             :     {
    1847                 :        7976 :       gconstpointer dir_value = va_arg (args, gconstpointer);
    1848                 :        7976 :       g_assert (dir_value != NULL);
    1849                 :             : 
    1850                 :        7976 :       if (g_str_equal (dir_type, "HOME"))
    1851                 :         997 :         set_str_if_different (&g_home_dir, dir_type, dir_value);
    1852                 :        6979 :       else if (g_str_equal (dir_type, "XDG_CACHE_HOME"))
    1853                 :         997 :         set_str_if_different (&g_user_cache_dir, dir_type, dir_value);
    1854                 :        5982 :       else if (g_str_equal (dir_type, "XDG_CONFIG_DIRS"))
    1855                 :         997 :         set_strv_if_different (&g_system_config_dirs, dir_type, dir_value);
    1856                 :        4985 :       else if (g_str_equal (dir_type, "XDG_CONFIG_HOME"))
    1857                 :         997 :         set_str_if_different (&g_user_config_dir, dir_type, dir_value);
    1858                 :        3988 :       else if (g_str_equal (dir_type, "XDG_DATA_DIRS"))
    1859                 :         997 :         set_strv_if_different (&g_system_data_dirs, dir_type, dir_value);
    1860                 :        2991 :       else if (g_str_equal (dir_type, "XDG_DATA_HOME"))
    1861                 :         997 :         set_str_if_different (&g_user_data_dir, dir_type, dir_value);
    1862                 :        1994 :       else if (g_str_equal (dir_type, "XDG_STATE_HOME"))
    1863                 :         997 :         set_str_if_different (&g_user_state_dir, dir_type, dir_value);
    1864                 :         997 :       else if (g_str_equal (dir_type, "XDG_RUNTIME_DIR"))
    1865                 :         997 :         set_str_if_different (&g_user_runtime_dir, dir_type, dir_value);
    1866                 :             :       else
    1867                 :             :         g_assert_not_reached ();
    1868                 :             :     }
    1869                 :             : 
    1870                 :         997 :   va_end (args);
    1871                 :             : 
    1872                 :         997 :   G_UNLOCK (g_utils_global);
    1873                 :         997 : }
    1874                 :             : 
    1875                 :             : static gchar *
    1876                 :          60 : g_build_user_data_dir (void)
    1877                 :             : {
    1878                 :          60 :   gchar *data_dir = NULL;
    1879                 :          60 :   const gchar *data_dir_env = g_getenv ("XDG_DATA_HOME");
    1880                 :             : 
    1881                 :          60 :   if (data_dir_env && data_dir_env[0])
    1882                 :          50 :     data_dir = g_strdup (data_dir_env);
    1883                 :             : #ifdef G_OS_WIN32
    1884                 :             :   else
    1885                 :             :     data_dir = get_special_folder (&FOLDERID_LocalAppData);
    1886                 :             : #endif
    1887                 :          60 :   if (!data_dir || !data_dir[0])
    1888                 :             :     {
    1889                 :          10 :       gchar *home_dir = g_build_home_dir ();
    1890                 :          10 :       g_free (data_dir);
    1891                 :          10 :       data_dir = g_build_filename (home_dir, ".local", "share", NULL);
    1892                 :          10 :       g_free (home_dir);
    1893                 :             :     }
    1894                 :             : 
    1895                 :          60 :   return g_steal_pointer (&data_dir);
    1896                 :             : }
    1897                 :             : 
    1898                 :             : /**
    1899                 :             :  * g_get_user_data_dir:
    1900                 :             :  * 
    1901                 :             :  * Returns a base directory in which to access application data such
    1902                 :             :  * as icons that is customized for a particular user.  
    1903                 :             :  *
    1904                 :             :  * On UNIX platforms this is determined using the mechanisms described
    1905                 :             :  * in the
    1906                 :             :  * [XDG Base Directory Specification](http://www.freedesktop.org/Standards/basedir-spec).
    1907                 :             :  * In this case the directory retrieved will be `XDG_DATA_HOME`.
    1908                 :             :  *
    1909                 :             :  * On Windows it follows XDG Base Directory Specification if `XDG_DATA_HOME`
    1910                 :             :  * is defined. If `XDG_DATA_HOME` is undefined, the folder to use for local (as
    1911                 :             :  * opposed to roaming) application data is used instead. See the
    1912                 :             :  * [documentation for `FOLDERID_LocalAppData`](https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid).
    1913                 :             :  * Note that in this case on Windows it will be the same
    1914                 :             :  * as what g_get_user_config_dir() returns.
    1915                 :             :  *
    1916                 :             :  * The return value is cached and modifying it at runtime is not supported, as
    1917                 :             :  * it’s not thread-safe to modify environment variables at runtime.
    1918                 :             :  *
    1919                 :             :  * Returns: (type filename) (transfer none): a string owned by GLib that must
    1920                 :             :  *   not be modified or freed.
    1921                 :             :  *
    1922                 :             :  * Since: 2.6
    1923                 :             :  **/
    1924                 :             : const gchar *
    1925                 :         264 : g_get_user_data_dir (void)
    1926                 :             : {
    1927                 :             :   const gchar *user_data_dir;
    1928                 :             : 
    1929                 :         264 :   G_LOCK (g_utils_global);
    1930                 :             : 
    1931                 :         264 :   if (g_user_data_dir == NULL)
    1932                 :          60 :     g_user_data_dir = g_build_user_data_dir ();
    1933                 :         264 :   user_data_dir = g_user_data_dir;
    1934                 :             : 
    1935                 :         264 :   G_UNLOCK (g_utils_global);
    1936                 :             : 
    1937                 :         264 :   return user_data_dir;
    1938                 :             : }
    1939                 :             : 
    1940                 :             : static gchar *
    1941                 :          57 : g_build_user_config_dir (void)
    1942                 :             : {
    1943                 :          57 :   gchar *config_dir = NULL;
    1944                 :          57 :   const gchar *config_dir_env = g_getenv ("XDG_CONFIG_HOME");
    1945                 :             : 
    1946                 :          57 :   if (config_dir_env && config_dir_env[0])
    1947                 :          50 :     config_dir = g_strdup (config_dir_env);
    1948                 :             : #ifdef G_OS_WIN32
    1949                 :             :   else
    1950                 :             :     config_dir = get_special_folder (&FOLDERID_LocalAppData);
    1951                 :             : #endif
    1952                 :          57 :   if (!config_dir || !config_dir[0])
    1953                 :             :     {
    1954                 :           7 :       gchar *home_dir = g_build_home_dir ();
    1955                 :           7 :       g_free (config_dir);
    1956                 :           7 :       config_dir = g_build_filename (home_dir, ".config", NULL);
    1957                 :           7 :       g_free (home_dir);
    1958                 :             :     }
    1959                 :             : 
    1960                 :          57 :   return g_steal_pointer (&config_dir);
    1961                 :             : }
    1962                 :             : 
    1963                 :             : static const char *
    1964                 :         517 : g_get_user_config_dir_unlocked (void)
    1965                 :             : {
    1966                 :         517 :   if (g_user_config_dir == NULL)
    1967                 :          57 :     g_user_config_dir = g_build_user_config_dir ();
    1968                 :             : 
    1969                 :         517 :   return g_user_config_dir;
    1970                 :             : }
    1971                 :             : 
    1972                 :             : /**
    1973                 :             :  * g_get_user_config_dir:
    1974                 :             :  * 
    1975                 :             :  * Returns a base directory in which to store user-specific application 
    1976                 :             :  * configuration information such as user preferences and settings. 
    1977                 :             :  *
    1978                 :             :  * On UNIX platforms this is determined using the mechanisms described
    1979                 :             :  * in the
    1980                 :             :  * [XDG Base Directory Specification](http://www.freedesktop.org/Standards/basedir-spec).
    1981                 :             :  * In this case the directory retrieved will be `XDG_CONFIG_HOME`.
    1982                 :             :  *
    1983                 :             :  * On Windows it follows XDG Base Directory Specification if `XDG_CONFIG_HOME` is defined.
    1984                 :             :  * If `XDG_CONFIG_HOME` is undefined, the folder to use for local (as opposed
    1985                 :             :  * to roaming) application data is used instead. See the
    1986                 :             :  * [documentation for `FOLDERID_LocalAppData`](https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid).
    1987                 :             :  * Note that in this case on Windows it will be  the same
    1988                 :             :  * as what g_get_user_data_dir() returns.
    1989                 :             :  *
    1990                 :             :  * The return value is cached and modifying it at runtime is not supported, as
    1991                 :             :  * it’s not thread-safe to modify environment variables at runtime.
    1992                 :             :  *
    1993                 :             :  * Returns: (type filename) (transfer none): a string owned by GLib that
    1994                 :             :  *   must not be modified or freed.
    1995                 :             :  * Since: 2.6
    1996                 :             :  **/
    1997                 :             : const gchar *
    1998                 :         486 : g_get_user_config_dir (void)
    1999                 :             : {
    2000                 :             :   const gchar *user_config_dir;
    2001                 :             : 
    2002                 :         486 :   G_LOCK (g_utils_global);
    2003                 :             : 
    2004                 :         486 :   user_config_dir = g_get_user_config_dir_unlocked ();
    2005                 :             : 
    2006                 :         486 :   G_UNLOCK (g_utils_global);
    2007                 :             : 
    2008                 :         486 :   return user_config_dir;
    2009                 :             : }
    2010                 :             : 
    2011                 :             : static gchar *
    2012                 :          12 : g_build_user_cache_dir (void)
    2013                 :             : {
    2014                 :          12 :   gchar *cache_dir = NULL;
    2015                 :          12 :   const gchar *cache_dir_env = g_getenv ("XDG_CACHE_HOME");
    2016                 :             : 
    2017                 :          12 :   if (cache_dir_env && cache_dir_env[0])
    2018                 :           1 :     cache_dir = g_strdup (cache_dir_env);
    2019                 :             : #ifdef G_OS_WIN32
    2020                 :             :   else
    2021                 :             :     cache_dir = get_special_folder (&FOLDERID_InternetCache);
    2022                 :             : #endif
    2023                 :          12 :   if (!cache_dir || !cache_dir[0])
    2024                 :             :     {
    2025                 :          11 :       gchar *home_dir = g_build_home_dir ();
    2026                 :          11 :       g_free (cache_dir);
    2027                 :          11 :       cache_dir = g_build_filename (home_dir, ".cache", NULL);
    2028                 :          11 :       g_free (home_dir);
    2029                 :             :     }
    2030                 :             : 
    2031                 :          12 :   return g_steal_pointer (&cache_dir);
    2032                 :             : }
    2033                 :             : 
    2034                 :             : /**
    2035                 :             :  * g_get_user_cache_dir:
    2036                 :             :  * 
    2037                 :             :  * Returns a base directory in which to store non-essential, cached
    2038                 :             :  * data specific to particular user.
    2039                 :             :  *
    2040                 :             :  * On UNIX platforms this is determined using the mechanisms described
    2041                 :             :  * in the
    2042                 :             :  * [XDG Base Directory Specification](http://www.freedesktop.org/Standards/basedir-spec).
    2043                 :             :  * In this case the directory retrieved will be `XDG_CACHE_HOME`.
    2044                 :             :  *
    2045                 :             :  * On Windows it follows XDG Base Directory Specification if `XDG_CACHE_HOME` is defined.
    2046                 :             :  * If `XDG_CACHE_HOME` is undefined, the directory that serves as a common
    2047                 :             :  * repository for temporary Internet files is used instead. A typical path is
    2048                 :             :  * `C:\Documents and Settings\username\Local Settings\Temporary Internet Files`.
    2049                 :             :  * See the [documentation for `FOLDERID_InternetCache`](https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid).
    2050                 :             :  *
    2051                 :             :  * The return value is cached and modifying it at runtime is not supported, as
    2052                 :             :  * it’s not thread-safe to modify environment variables at runtime.
    2053                 :             :  *
    2054                 :             :  * Returns: (type filename) (transfer none): a string owned by GLib that
    2055                 :             :  *   must not be modified or freed.
    2056                 :             :  * Since: 2.6
    2057                 :             :  **/
    2058                 :             : const gchar *
    2059                 :        1376 : g_get_user_cache_dir (void)
    2060                 :             : {
    2061                 :             :   const gchar *user_cache_dir;
    2062                 :             : 
    2063                 :        1376 :   G_LOCK (g_utils_global);
    2064                 :             : 
    2065                 :        1376 :   if (g_user_cache_dir == NULL)
    2066                 :           2 :     g_user_cache_dir = g_build_user_cache_dir ();
    2067                 :        1376 :   user_cache_dir = g_user_cache_dir;
    2068                 :             : 
    2069                 :        1376 :   G_UNLOCK (g_utils_global);
    2070                 :             : 
    2071                 :        1376 :   return user_cache_dir;
    2072                 :             : }
    2073                 :             : 
    2074                 :             : static gchar *
    2075                 :           1 : g_build_user_state_dir (void)
    2076                 :             : {
    2077                 :           1 :   gchar *state_dir = NULL;
    2078                 :           1 :   const gchar *state_dir_env = g_getenv ("XDG_STATE_HOME");
    2079                 :             : 
    2080                 :           1 :   if (state_dir_env && state_dir_env[0])
    2081                 :           0 :     state_dir = g_strdup (state_dir_env);
    2082                 :             : #ifdef G_OS_WIN32
    2083                 :             :   else
    2084                 :             :     state_dir = get_special_folder (&FOLDERID_LocalAppData);
    2085                 :             : #endif
    2086                 :           1 :   if (!state_dir || !state_dir[0])
    2087                 :             :     {
    2088                 :           1 :       gchar *home_dir = g_build_home_dir ();
    2089                 :           1 :       g_free (state_dir);
    2090                 :           1 :       state_dir = g_build_filename (home_dir, ".local/state", NULL);
    2091                 :           1 :       g_free (home_dir);
    2092                 :             :     }
    2093                 :             : 
    2094                 :           1 :   return g_steal_pointer (&state_dir);
    2095                 :             : }
    2096                 :             : 
    2097                 :             : /**
    2098                 :             :  * g_get_user_state_dir:
    2099                 :             :  *
    2100                 :             :  * Returns a base directory in which to store state files specific to
    2101                 :             :  * particular user.
    2102                 :             :  *
    2103                 :             :  * On UNIX platforms this is determined using the mechanisms described
    2104                 :             :  * in the
    2105                 :             :  * [XDG Base Directory Specification](http://www.freedesktop.org/Standards/basedir-spec).
    2106                 :             :  * In this case the directory retrieved will be `XDG_STATE_HOME`.
    2107                 :             :  *
    2108                 :             :  * On Windows it follows XDG Base Directory Specification if `XDG_STATE_HOME` is defined.
    2109                 :             :  * If `XDG_STATE_HOME` is undefined, the folder to use for local (as opposed
    2110                 :             :  * to roaming) application data is used instead. See the
    2111                 :             :  * [documentation for `FOLDERID_LocalAppData`](https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid).
    2112                 :             :  * Note that in this case on Windows it will be the same
    2113                 :             :  * as what g_get_user_data_dir() returns.
    2114                 :             :  *
    2115                 :             :  * The return value is cached and modifying it at runtime is not supported, as
    2116                 :             :  * it’s not thread-safe to modify environment variables at runtime.
    2117                 :             :  *
    2118                 :             :  * Returns: (type filename) (transfer none): a string owned by GLib that
    2119                 :             :  *   must not be modified or freed.
    2120                 :             :  *
    2121                 :             :  * Since: 2.72
    2122                 :             :  **/
    2123                 :             : const gchar *
    2124                 :           2 : g_get_user_state_dir (void)
    2125                 :             : {
    2126                 :             :   const gchar *user_state_dir;
    2127                 :             : 
    2128                 :           2 :   G_LOCK (g_utils_global);
    2129                 :             : 
    2130                 :           2 :   if (g_user_state_dir == NULL)
    2131                 :           1 :     g_user_state_dir = g_build_user_state_dir ();
    2132                 :           2 :   user_state_dir = g_user_state_dir;
    2133                 :             : 
    2134                 :           2 :   G_UNLOCK (g_utils_global);
    2135                 :             : 
    2136                 :           2 :   return user_state_dir;
    2137                 :             : }
    2138                 :             : 
    2139                 :             : static gchar *
    2140                 :          11 : g_build_user_runtime_dir (void)
    2141                 :             : {
    2142                 :          11 :   gchar *runtime_dir = NULL;
    2143                 :          11 :   const gchar *runtime_dir_env = g_getenv ("XDG_RUNTIME_DIR");
    2144                 :             : 
    2145                 :          11 :   if (runtime_dir_env && runtime_dir_env[0])
    2146                 :             :     {
    2147                 :           1 :       runtime_dir = g_strdup (runtime_dir_env);
    2148                 :             : 
    2149                 :             :       /* If the XDG_RUNTIME_DIR environment variable is set, we are being told by
    2150                 :             :        * the OS that this directory exists and is appropriately configured
    2151                 :             :        * already.
    2152                 :             :        */
    2153                 :             :     }
    2154                 :             :   else
    2155                 :             :     {
    2156                 :          10 :       runtime_dir = g_build_user_cache_dir ();
    2157                 :             : 
    2158                 :             :       /* Fallback case: the directory may not yet exist.
    2159                 :             :        *
    2160                 :             :        * The user should be able to rely on the directory existing
    2161                 :             :        * when the function returns.  Probably it already does, but
    2162                 :             :        * let's make sure.  Just do mkdir() directly since it will be
    2163                 :             :        * no more expensive than a stat() in the case that the
    2164                 :             :        * directory already exists and is a lot easier.
    2165                 :             :        *
    2166                 :             :        * $XDG_CACHE_HOME is probably ~/.cache/ so as long as $HOME
    2167                 :             :        * exists this will work.  If the user changed $XDG_CACHE_HOME
    2168                 :             :        * then they can make sure that it exists...
    2169                 :             :        */
    2170                 :          10 :       (void) g_mkdir (runtime_dir, 0700);
    2171                 :             :     }
    2172                 :             : 
    2173                 :          11 :   return g_steal_pointer (&runtime_dir);
    2174                 :             : }
    2175                 :             : 
    2176                 :             : /**
    2177                 :             :  * g_get_user_runtime_dir:
    2178                 :             :  *
    2179                 :             :  * Returns a directory that is unique to the current user on the local
    2180                 :             :  * system.
    2181                 :             :  *
    2182                 :             :  * This is determined using the mechanisms described
    2183                 :             :  * in the 
    2184                 :             :  * [XDG Base Directory Specification](http://www.freedesktop.org/Standards/basedir-spec).
    2185                 :             :  * This is the directory
    2186                 :             :  * specified in the `XDG_RUNTIME_DIR` environment variable.
    2187                 :             :  * In the case that this variable is not set, we return the value of
    2188                 :             :  * g_get_user_cache_dir(), after verifying that it exists.
    2189                 :             :  *
    2190                 :             :  * The return value is cached and modifying it at runtime is not supported, as
    2191                 :             :  * it’s not thread-safe to modify environment variables at runtime.
    2192                 :             :  *
    2193                 :             :  * Returns: (type filename): a string owned by GLib that must not be
    2194                 :             :  *     modified or freed.
    2195                 :             :  *
    2196                 :             :  * Since: 2.28
    2197                 :             :  **/
    2198                 :             : const gchar *
    2199                 :         104 : g_get_user_runtime_dir (void)
    2200                 :             : {
    2201                 :             :   const gchar *user_runtime_dir;
    2202                 :             : 
    2203                 :         104 :   G_LOCK (g_utils_global);
    2204                 :             : 
    2205                 :         104 :   if (g_user_runtime_dir == NULL)
    2206                 :          11 :     g_user_runtime_dir = g_build_user_runtime_dir ();
    2207                 :         104 :   user_runtime_dir = g_user_runtime_dir;
    2208                 :             : 
    2209                 :         104 :   G_UNLOCK (g_utils_global);
    2210                 :             : 
    2211                 :         104 :   return user_runtime_dir;
    2212                 :             : }
    2213                 :             : 
    2214                 :             : #ifdef HAVE_COCOA
    2215                 :             : 
    2216                 :             : /* Implemented in gosxutils.m */
    2217                 :             : void load_user_special_dirs_macos (gchar **table);
    2218                 :             : 
    2219                 :             : static void
    2220                 :             : load_user_special_dirs_unlocked (void)
    2221                 :             : {
    2222                 :             :   load_user_special_dirs_macos (g_user_special_dirs);
    2223                 :             : }
    2224                 :             : 
    2225                 :             : #elif defined(G_OS_WIN32)
    2226                 :             : 
    2227                 :             : static void
    2228                 :             : load_user_special_dirs_unlocked (void)
    2229                 :             : {
    2230                 :             :   g_user_special_dirs[G_USER_DIRECTORY_DESKTOP] = get_special_folder (&FOLDERID_Desktop);
    2231                 :             :   g_user_special_dirs[G_USER_DIRECTORY_DOCUMENTS] = get_special_folder (&FOLDERID_Documents);
    2232                 :             : 
    2233                 :             :   g_user_special_dirs[G_USER_DIRECTORY_DOWNLOAD] = get_special_folder (&FOLDERID_Downloads);
    2234                 :             :   if (g_user_special_dirs[G_USER_DIRECTORY_DOWNLOAD] == NULL)
    2235                 :             :     g_user_special_dirs[G_USER_DIRECTORY_DOWNLOAD] = get_special_folder (&FOLDERID_Desktop);
    2236                 :             : 
    2237                 :             :   g_user_special_dirs[G_USER_DIRECTORY_MUSIC] = get_special_folder (&FOLDERID_Music);
    2238                 :             :   g_user_special_dirs[G_USER_DIRECTORY_PICTURES] = get_special_folder (&FOLDERID_Pictures);
    2239                 :             : 
    2240                 :             :   g_user_special_dirs[G_USER_DIRECTORY_PUBLIC_SHARE] = get_special_folder (&FOLDERID_Public);
    2241                 :             :   if (g_user_special_dirs[G_USER_DIRECTORY_PUBLIC_SHARE] == NULL)
    2242                 :             :     g_user_special_dirs[G_USER_DIRECTORY_PUBLIC_SHARE] = get_special_folder (&FOLDERID_PublicDocuments);
    2243                 :             : 
    2244                 :             :   g_user_special_dirs[G_USER_DIRECTORY_TEMPLATES] = get_special_folder (&FOLDERID_Templates);
    2245                 :             :   g_user_special_dirs[G_USER_DIRECTORY_VIDEOS] = get_special_folder (&FOLDERID_Videos);
    2246                 :             : }
    2247                 :             : 
    2248                 :             : #else /* default is unix */
    2249                 :             : 
    2250                 :             : #include "gutilsprivate.c"
    2251                 :             : 
    2252                 :             : /* adapted from xdg-user-dir-lookup.c
    2253                 :             :  *
    2254                 :             :  * Copyright (C) 2007 Red Hat Inc.
    2255                 :             :  *
    2256                 :             :  * Permission is hereby granted, free of charge, to any person
    2257                 :             :  * obtaining a copy of this software and associated documentation files
    2258                 :             :  * (the "Software"), to deal in the Software without restriction,
    2259                 :             :  * including without limitation the rights to use, copy, modify, merge,
    2260                 :             :  * publish, distribute, sublicense, and/or sell copies of the Software,
    2261                 :             :  * and to permit persons to whom the Software is furnished to do so,
    2262                 :             :  * subject to the following conditions: 
    2263                 :             :  *
    2264                 :             :  * The above copyright notice and this permission notice shall be
    2265                 :             :  * included in all copies or substantial portions of the Software. 
    2266                 :             :  *
    2267                 :             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    2268                 :             :  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    2269                 :             :  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    2270                 :             :  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
    2271                 :             :  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
    2272                 :             :  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
    2273                 :             :  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    2274                 :             :  * SOFTWARE.
    2275                 :             :  */
    2276                 :             : static void
    2277                 :          31 : load_user_special_dirs_unlocked (void)
    2278                 :             : {
    2279                 :          31 :   const gchar *config_dir = NULL;
    2280                 :             :   const gchar *home_dir;
    2281                 :             :   gchar *config_file;
    2282                 :          31 :   char *data = NULL;
    2283                 :             : 
    2284                 :          31 :   config_dir = g_get_user_config_dir_unlocked ();
    2285                 :          31 :   config_file = g_build_filename (config_dir,
    2286                 :             :                                   "user-dirs.dirs",
    2287                 :             :                                   NULL);
    2288                 :          31 :   home_dir = g_get_home_dir_unlocked ();
    2289                 :             : 
    2290                 :          31 :   if (g_file_get_contents (config_file, &data, NULL, NULL))
    2291                 :          18 :     load_user_special_dirs_from_string (data, home_dir, g_user_special_dirs);
    2292                 :             : 
    2293                 :             :   /* Special-case desktop for historical compatibility */
    2294                 :          31 :   if (g_user_special_dirs[G_USER_DIRECTORY_DESKTOP] == NULL)
    2295                 :          13 :     g_user_special_dirs[G_USER_DIRECTORY_DESKTOP] = g_build_filename (home_dir, "Desktop", NULL);
    2296                 :             : 
    2297                 :          31 :   g_free (data);
    2298                 :          31 :   g_free (config_file);
    2299                 :          31 : }
    2300                 :             : 
    2301                 :             : #endif /* platform-specific load_user_special_dirs implementations */
    2302                 :             : 
    2303                 :             : 
    2304                 :             : /**
    2305                 :             :  * g_reload_user_special_dirs_cache:
    2306                 :             :  *
    2307                 :             :  * Resets the cache used for g_get_user_special_dir(), so
    2308                 :             :  * that the latest on-disk version is used. Call this only
    2309                 :             :  * if you just changed the data on disk yourself.
    2310                 :             :  *
    2311                 :             :  * Due to thread safety issues this may cause leaking of strings
    2312                 :             :  * that were previously returned from g_get_user_special_dir()
    2313                 :             :  * that can't be freed. We ensure to only leak the data for
    2314                 :             :  * the directories that actually changed value though.
    2315                 :             :  *
    2316                 :             :  * Since: 2.22
    2317                 :             :  */
    2318                 :             : void
    2319                 :          24 : g_reload_user_special_dirs_cache (void)
    2320                 :             : {
    2321                 :             :   int i;
    2322                 :             : 
    2323                 :          24 :   G_LOCK (g_utils_global);
    2324                 :             : 
    2325                 :          24 :   if (g_user_special_dirs != NULL)
    2326                 :             :     {
    2327                 :             :       /* save a copy of the pointer, to check if some memory can be preserved */
    2328                 :          12 :       char **old_g_user_special_dirs = g_user_special_dirs;
    2329                 :             :       char *old_val;
    2330                 :             : 
    2331                 :             :       /* recreate and reload our cache */
    2332                 :          12 :       g_user_special_dirs = g_new0 (gchar *, G_USER_N_DIRECTORIES);
    2333                 :          12 :       load_user_special_dirs_unlocked ();
    2334                 :             : 
    2335                 :             :       /* only leak changed directories */
    2336                 :         108 :       for (i = 0; i < G_USER_N_DIRECTORIES; i++)
    2337                 :             :         {
    2338                 :          96 :           old_val = old_g_user_special_dirs[i];
    2339                 :             : 
    2340                 :         120 :           if (g_user_special_dirs[i] == NULL ||
    2341                 :          24 :               g_strcmp0 (old_val, g_user_special_dirs[i]) != 0)
    2342                 :             :             {
    2343                 :          84 :               g_ignore_leak (old_val);
    2344                 :             :             }
    2345                 :             :           else
    2346                 :             :             {
    2347                 :             :               /* don't leak */
    2348                 :          12 :               g_free (g_user_special_dirs[i]);
    2349                 :          12 :               g_user_special_dirs[i] = old_val;
    2350                 :             :             }
    2351                 :             :         }
    2352                 :             : 
    2353                 :             :       /* free the old array */
    2354                 :          12 :       g_free (old_g_user_special_dirs);
    2355                 :             :     }
    2356                 :             : 
    2357                 :          24 :   G_UNLOCK (g_utils_global);
    2358                 :          24 : }
    2359                 :             : 
    2360                 :             : /**
    2361                 :             :  * g_get_user_special_dir:
    2362                 :             :  * @directory: the logical id of special directory
    2363                 :             :  *
    2364                 :             :  * Returns the full path of a special directory using its logical id.
    2365                 :             :  *
    2366                 :             :  * On UNIX this is done using the XDG special user directories.
    2367                 :             :  * For compatibility with existing practise, %G_USER_DIRECTORY_DESKTOP
    2368                 :             :  * falls back to `$HOME/Desktop` when XDG special user directories have
    2369                 :             :  * not been set up. 
    2370                 :             :  *
    2371                 :             :  * Depending on the platform, the user might be able to change the path
    2372                 :             :  * of the special directory without requiring the session to restart; GLib
    2373                 :             :  * will not reflect any change once the special directories are loaded.
    2374                 :             :  *
    2375                 :             :  * Returns: (type filename) (nullable): the path to the specified special
    2376                 :             :  *   directory, or %NULL if the logical id was not found. The returned string is
    2377                 :             :  *   owned by GLib and should not be modified or freed.
    2378                 :             :  *
    2379                 :             :  * Since: 2.14
    2380                 :             :  */
    2381                 :             : const gchar *
    2382                 :        1360 : g_get_user_special_dir (GUserDirectory directory)
    2383                 :             : {
    2384                 :             :   const gchar *user_special_dir;
    2385                 :             : 
    2386                 :        1360 :   g_return_val_if_fail (directory >= G_USER_DIRECTORY_DESKTOP &&
    2387                 :             :                         directory < G_USER_N_DIRECTORIES, NULL);
    2388                 :             : 
    2389                 :        1360 :   G_LOCK (g_utils_global);
    2390                 :             : 
    2391                 :        1360 :   if (G_UNLIKELY (g_user_special_dirs == NULL))
    2392                 :             :     {
    2393                 :          19 :       g_user_special_dirs = g_new0 (gchar *, G_USER_N_DIRECTORIES);
    2394                 :          19 :       load_user_special_dirs_unlocked ();
    2395                 :             :     }
    2396                 :        1360 :   user_special_dir = g_user_special_dirs[directory];
    2397                 :             : 
    2398                 :        1360 :   G_UNLOCK (g_utils_global);
    2399                 :             : 
    2400                 :        1360 :   return user_special_dir;
    2401                 :             : }
    2402                 :             : 
    2403                 :             : #ifdef G_OS_WIN32
    2404                 :             : 
    2405                 :             : #undef g_get_system_data_dirs
    2406                 :             : 
    2407                 :             : static HMODULE
    2408                 :             : get_module_for_address (gconstpointer address)
    2409                 :             : {
    2410                 :             :   /* Holds the g_utils_global lock */
    2411                 :             : 
    2412                 :             :   HMODULE hmodule = NULL;
    2413                 :             : 
    2414                 :             :   if (!address)
    2415                 :             :     return NULL;
    2416                 :             : 
    2417                 :             :   if (!GetModuleHandleExW (GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT |
    2418                 :             :                            GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
    2419                 :             :                            address, &hmodule))
    2420                 :             :     {
    2421                 :             :       MEMORY_BASIC_INFORMATION mbi;
    2422                 :             :       VirtualQuery (address, &mbi, sizeof (mbi));
    2423                 :             :       hmodule = (HMODULE) mbi.AllocationBase;
    2424                 :             :     }
    2425                 :             : 
    2426                 :             :   return hmodule;
    2427                 :             : }
    2428                 :             : 
    2429                 :             : static gchar *
    2430                 :             : get_module_share_dir (gconstpointer address)
    2431                 :             : {
    2432                 :             :   HMODULE hmodule;
    2433                 :             :   gchar *filename;
    2434                 :             :   gchar *retval;
    2435                 :             : 
    2436                 :             :   hmodule = get_module_for_address (address);
    2437                 :             :   if (hmodule == NULL)
    2438                 :             :     return NULL;
    2439                 :             : 
    2440                 :             :   filename = g_win32_get_package_installation_directory_of_module (hmodule);
    2441                 :             :   retval = g_build_filename (filename, "share", NULL);
    2442                 :             :   g_free (filename);
    2443                 :             : 
    2444                 :             :   return retval;
    2445                 :             : }
    2446                 :             : 
    2447                 :             : static const gchar * const *
    2448                 :             : g_win32_get_system_data_dirs_for_module_real (void (*address_of_function)(void))
    2449                 :             : {
    2450                 :             :   GArray *data_dirs;
    2451                 :             :   HMODULE hmodule;
    2452                 :             :   static GHashTable *per_module_data_dirs = NULL;
    2453                 :             :   gchar **retval;
    2454                 :             :   gchar *p;
    2455                 :             :   gchar *exe_root;
    2456                 :             : 
    2457                 :             :   hmodule = NULL;
    2458                 :             :   if (address_of_function)
    2459                 :             :     {
    2460                 :             :       G_LOCK (g_utils_global);
    2461                 :             :       hmodule = get_module_for_address (address_of_function);
    2462                 :             :       if (hmodule != NULL)
    2463                 :             :         {
    2464                 :             :           if (per_module_data_dirs == NULL)
    2465                 :             :             per_module_data_dirs = g_hash_table_new (NULL, NULL);
    2466                 :             :           else
    2467                 :             :             {
    2468                 :             :               retval = g_hash_table_lookup (per_module_data_dirs, hmodule);
    2469                 :             :               
    2470                 :             :               if (retval != NULL)
    2471                 :             :                 {
    2472                 :             :                   G_UNLOCK (g_utils_global);
    2473                 :             :                   return (const gchar * const *) retval;
    2474                 :             :                 }
    2475                 :             :             }
    2476                 :             :         }
    2477                 :             :     }
    2478                 :             : 
    2479                 :             :   data_dirs = g_array_new (TRUE, TRUE, sizeof (char *));
    2480                 :             : 
    2481                 :             :   /* Documents and Settings\All Users\Application Data */
    2482                 :             :   p = get_special_folder (&FOLDERID_ProgramData);
    2483                 :             :   if (p)
    2484                 :             :     g_array_append_val (data_dirs, p);
    2485                 :             : 
    2486                 :             :   /* Documents and Settings\All Users\Documents */
    2487                 :             :   p = get_special_folder (&FOLDERID_PublicDocuments);
    2488                 :             :   if (p)
    2489                 :             :     g_array_append_val (data_dirs, p);
    2490                 :             : 
    2491                 :             :   /* Using the above subfolders of Documents and Settings perhaps
    2492                 :             :    * makes sense from a Windows perspective.
    2493                 :             :    *
    2494                 :             :    * But looking at the actual use cases of this function in GTK
    2495                 :             :    * and GNOME software, what we really want is the "share"
    2496                 :             :    * subdirectory of the installation directory for the package
    2497                 :             :    * our caller is a part of.
    2498                 :             :    *
    2499                 :             :    * The address_of_function parameter, if non-NULL, points to a
    2500                 :             :    * function in the calling module. Use that to determine that
    2501                 :             :    * module's installation folder, and use its "share" subfolder.
    2502                 :             :    *
    2503                 :             :    * Additionally, also use the "share" subfolder of the installation
    2504                 :             :    * locations of GLib and the .exe file being run.
    2505                 :             :    *
    2506                 :             :    * To guard against none of the above being what is really wanted,
    2507                 :             :    * callers of this function should have Win32-specific code to look
    2508                 :             :    * up their installation folder themselves, and handle a subfolder
    2509                 :             :    * "share" of it in the same way as the folders returned from this
    2510                 :             :    * function.
    2511                 :             :    */
    2512                 :             : 
    2513                 :             :   p = get_module_share_dir (address_of_function);
    2514                 :             :   if (p)
    2515                 :             :     g_array_append_val (data_dirs, p);
    2516                 :             :     
    2517                 :             :   if (glib_dll != NULL)
    2518                 :             :     {
    2519                 :             :       gchar *glib_root = g_win32_get_package_installation_directory_of_module (glib_dll);
    2520                 :             :       p = g_build_filename (glib_root, "share", NULL);
    2521                 :             :       if (p)
    2522                 :             :         g_array_append_val (data_dirs, p);
    2523                 :             :       g_free (glib_root);
    2524                 :             :     }
    2525                 :             :   
    2526                 :             :   exe_root = g_win32_get_package_installation_directory_of_module (NULL);
    2527                 :             :   p = g_build_filename (exe_root, "share", NULL);
    2528                 :             :   if (p)
    2529                 :             :     g_array_append_val (data_dirs, p);
    2530                 :             :   g_free (exe_root);
    2531                 :             : 
    2532                 :             :   retval = (gchar **) g_array_free (data_dirs, FALSE);
    2533                 :             : 
    2534                 :             :   if (address_of_function)
    2535                 :             :     {
    2536                 :             :       if (hmodule != NULL)
    2537                 :             :         g_hash_table_insert (per_module_data_dirs, hmodule, retval);
    2538                 :             :       G_UNLOCK (g_utils_global);
    2539                 :             :     }
    2540                 :             : 
    2541                 :             :   return (const gchar * const *) retval;
    2542                 :             : }
    2543                 :             : 
    2544                 :             : const gchar * const *
    2545                 :             : g_win32_get_system_data_dirs_for_module (void (*address_of_function)(void))
    2546                 :             : {
    2547                 :             :   gboolean should_call_g_get_system_data_dirs;
    2548                 :             : 
    2549                 :             :   should_call_g_get_system_data_dirs = TRUE;
    2550                 :             :   /* These checks are the same as the ones that g_build_system_data_dirs() does.
    2551                 :             :    * Please keep them in sync.
    2552                 :             :    */
    2553                 :             :   G_LOCK (g_utils_global);
    2554                 :             : 
    2555                 :             :   if (!g_system_data_dirs)
    2556                 :             :     {
    2557                 :             :       const gchar *data_dirs = g_getenv ("XDG_DATA_DIRS");
    2558                 :             : 
    2559                 :             :       if (!data_dirs || !data_dirs[0])
    2560                 :             :         should_call_g_get_system_data_dirs = FALSE;
    2561                 :             :     }
    2562                 :             : 
    2563                 :             :   G_UNLOCK (g_utils_global);
    2564                 :             : 
    2565                 :             :   /* There is a subtle difference between g_win32_get_system_data_dirs_for_module (NULL),
    2566                 :             :    * which is what GLib code can normally call,
    2567                 :             :    * and g_win32_get_system_data_dirs_for_module (&_g_win32_get_system_data_dirs),
    2568                 :             :    * which is what the inline function used by non-GLib code calls.
    2569                 :             :    * The former gets prefix relative to currently-running executable,
    2570                 :             :    * the latter - relative to the module that calls _g_win32_get_system_data_dirs()
    2571                 :             :    * (disguised as g_get_system_data_dirs()), which could be an executable or
    2572                 :             :    * a DLL that is located somewhere else.
    2573                 :             :    * This is why that inline function in gutils.h exists, and why we can't just
    2574                 :             :    * call g_get_system_data_dirs() from there - because we need to get the address
    2575                 :             :    * local to the non-GLib caller-module.
    2576                 :             :    */
    2577                 :             : 
    2578                 :             :   /*
    2579                 :             :    * g_get_system_data_dirs() will fall back to calling
    2580                 :             :    * g_win32_get_system_data_dirs_for_module_real(NULL) if XDG_DATA_DIRS is NULL
    2581                 :             :    * or an empty string. The checks above ensure that we do not call it in such
    2582                 :             :    * cases and use the address_of_function that we've been given by the inline function.
    2583                 :             :    * The reason we're calling g_get_system_data_dirs /at all/ is to give
    2584                 :             :    * XDG_DATA_DIRS precedence (if it is set).
    2585                 :             :    */
    2586                 :             :   if (should_call_g_get_system_data_dirs)
    2587                 :             :     return g_get_system_data_dirs ();
    2588                 :             : 
    2589                 :             :   return g_win32_get_system_data_dirs_for_module_real (address_of_function);
    2590                 :             : }
    2591                 :             : 
    2592                 :             : #endif
    2593                 :             : 
    2594                 :             : static gchar **
    2595                 :          68 : g_build_system_data_dirs (void)
    2596                 :             : {
    2597                 :          68 :   gchar **data_dir_vector = NULL;
    2598                 :          68 :   gchar *data_dirs = (gchar *) g_getenv ("XDG_DATA_DIRS");
    2599                 :             : 
    2600                 :             :   /* These checks are the same as the ones that g_win32_get_system_data_dirs_for_module()
    2601                 :             :    * does. Please keep them in sync.
    2602                 :             :    */
    2603                 :             : #ifndef G_OS_WIN32
    2604                 :          68 :   if (!data_dirs || !data_dirs[0])
    2605                 :          18 :     data_dirs = "/usr/local/share/:/usr/share/";
    2606                 :             : 
    2607                 :          68 :   data_dir_vector = g_strsplit (data_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
    2608                 :             : #else
    2609                 :             :   if (!data_dirs || !data_dirs[0])
    2610                 :             :     data_dir_vector = g_strdupv ((gchar **) g_win32_get_system_data_dirs_for_module_real (NULL));
    2611                 :             :   else
    2612                 :             :     data_dir_vector = g_strsplit (data_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
    2613                 :             : #endif
    2614                 :             : 
    2615                 :          68 :   return g_steal_pointer (&data_dir_vector);
    2616                 :             : }
    2617                 :             : 
    2618                 :             : /**
    2619                 :             :  * g_get_system_data_dirs:
    2620                 :             :  * 
    2621                 :             :  * Returns an ordered list of base directories in which to access 
    2622                 :             :  * system-wide application data.
    2623                 :             :  *
    2624                 :             :  * On UNIX platforms this is determined using the mechanisms described
    2625                 :             :  * in the
    2626                 :             :  * [XDG Base Directory Specification](http://www.freedesktop.org/Standards/basedir-spec)
    2627                 :             :  * In this case the list of directories retrieved will be `XDG_DATA_DIRS`.
    2628                 :             :  *
    2629                 :             :  * On Windows it follows XDG Base Directory Specification if `XDG_DATA_DIRS` is defined.
    2630                 :             :  * If `XDG_DATA_DIRS` is undefined,
    2631                 :             :  * the first elements in the list are the Application Data
    2632                 :             :  * and Documents folders for All Users. (These can be determined only
    2633                 :             :  * on Windows 2000 or later and are not present in the list on other
    2634                 :             :  * Windows versions.) See documentation for FOLDERID_ProgramData and
    2635                 :             :  * FOLDERID_PublicDocuments.
    2636                 :             :  *
    2637                 :             :  * Then follows the "share" subfolder in the installation folder for
    2638                 :             :  * the package containing the DLL that calls this function, if it can
    2639                 :             :  * be determined.
    2640                 :             :  * 
    2641                 :             :  * Finally the list contains the "share" subfolder in the installation
    2642                 :             :  * folder for GLib, and in the installation folder for the package the
    2643                 :             :  * application's .exe file belongs to.
    2644                 :             :  *
    2645                 :             :  * The installation folders above are determined by looking up the
    2646                 :             :  * folder where the module (DLL or EXE) in question is located. If the
    2647                 :             :  * folder's name is "bin", its parent is used, otherwise the folder
    2648                 :             :  * itself.
    2649                 :             :  *
    2650                 :             :  * Note that on Windows the returned list can vary depending on where
    2651                 :             :  * this function is called.
    2652                 :             :  *
    2653                 :             :  * The return value is cached and modifying it at runtime is not supported, as
    2654                 :             :  * it’s not thread-safe to modify environment variables at runtime.
    2655                 :             :  *
    2656                 :             :  * Returns: (array zero-terminated=1) (element-type filename) (transfer none):
    2657                 :             :  *     a %NULL-terminated array of strings owned by GLib that must not be
    2658                 :             :  *     modified or freed.
    2659                 :             :  * 
    2660                 :             :  * Since: 2.6
    2661                 :             :  **/
    2662                 :             : const gchar * const * 
    2663                 :         169 : g_get_system_data_dirs (void)
    2664                 :             : {
    2665                 :             :   const gchar * const *system_data_dirs;
    2666                 :             : 
    2667                 :         169 :   G_LOCK (g_utils_global);
    2668                 :             : 
    2669                 :         169 :   if (g_system_data_dirs == NULL)
    2670                 :          68 :     g_system_data_dirs = g_build_system_data_dirs ();
    2671                 :         169 :   system_data_dirs = (const gchar * const *) g_system_data_dirs;
    2672                 :             : 
    2673                 :         169 :   G_UNLOCK (g_utils_global);
    2674                 :             : 
    2675                 :         169 :   return system_data_dirs;
    2676                 :             : }
    2677                 :             : 
    2678                 :             : static gchar **
    2679                 :          57 : g_build_system_config_dirs (void)
    2680                 :             : {
    2681                 :          57 :   gchar **conf_dir_vector = NULL;
    2682                 :          57 :   const gchar *conf_dirs = g_getenv ("XDG_CONFIG_DIRS");
    2683                 :             : #ifdef G_OS_WIN32
    2684                 :             :   if (conf_dirs)
    2685                 :             :     {
    2686                 :             :       conf_dir_vector = g_strsplit (conf_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
    2687                 :             :     }
    2688                 :             :   else
    2689                 :             :     {
    2690                 :             :       gchar *special_conf_dirs = get_special_folder (&FOLDERID_ProgramData);
    2691                 :             : 
    2692                 :             :       if (special_conf_dirs)
    2693                 :             :         conf_dir_vector = g_strsplit (special_conf_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
    2694                 :             :       else
    2695                 :             :         /* Return empty list */
    2696                 :             :         conf_dir_vector = g_strsplit ("", G_SEARCHPATH_SEPARATOR_S, 0);
    2697                 :             : 
    2698                 :             :       g_free (special_conf_dirs);
    2699                 :             :     }
    2700                 :             : #else
    2701                 :          57 :   if (!conf_dirs || !conf_dirs[0])
    2702                 :           7 :     conf_dirs = "/etc/xdg";
    2703                 :             : 
    2704                 :          57 :   conf_dir_vector = g_strsplit (conf_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
    2705                 :             : #endif
    2706                 :             : 
    2707                 :          57 :   return g_steal_pointer (&conf_dir_vector);
    2708                 :             : }
    2709                 :             : 
    2710                 :             : /**
    2711                 :             :  * g_get_system_config_dirs:
    2712                 :             :  * 
    2713                 :             :  * Returns an ordered list of base directories in which to access 
    2714                 :             :  * system-wide configuration information.
    2715                 :             :  *
    2716                 :             :  * On UNIX platforms this is determined using the mechanisms described
    2717                 :             :  * in the
    2718                 :             :  * [XDG Base Directory Specification](http://www.freedesktop.org/Standards/basedir-spec).
    2719                 :             :  * In this case the list of directories retrieved will be `XDG_CONFIG_DIRS`.
    2720                 :             :  *
    2721                 :             :  * On Windows it follows XDG Base Directory Specification if `XDG_CONFIG_DIRS` is defined.
    2722                 :             :  * If `XDG_CONFIG_DIRS` is undefined, the directory that contains application
    2723                 :             :  * data for all users is used instead. A typical path is
    2724                 :             :  * `C:\Documents and Settings\All Users\Application Data`.
    2725                 :             :  * This folder is used for application data
    2726                 :             :  * that is not user specific. For example, an application can store
    2727                 :             :  * a spell-check dictionary, a database of clip art, or a log file in the
    2728                 :             :  * FOLDERID_ProgramData folder. This information will not roam and is available
    2729                 :             :  * to anyone using the computer.
    2730                 :             :  *
    2731                 :             :  * The return value is cached and modifying it at runtime is not supported, as
    2732                 :             :  * it’s not thread-safe to modify environment variables at runtime.
    2733                 :             :  *
    2734                 :             :  * Returns: (array zero-terminated=1) (element-type filename) (transfer none):
    2735                 :             :  *     a %NULL-terminated array of strings owned by GLib that must not be
    2736                 :             :  *     modified or freed.
    2737                 :             :  * 
    2738                 :             :  * Since: 2.6
    2739                 :             :  **/
    2740                 :             : const gchar * const *
    2741                 :         122 : g_get_system_config_dirs (void)
    2742                 :             : {
    2743                 :             :   const gchar * const *system_config_dirs;
    2744                 :             : 
    2745                 :         122 :   G_LOCK (g_utils_global);
    2746                 :             : 
    2747                 :         122 :   if (g_system_config_dirs == NULL)
    2748                 :          57 :     g_system_config_dirs = g_build_system_config_dirs ();
    2749                 :         122 :   system_config_dirs = (const gchar * const *) g_system_config_dirs;
    2750                 :             : 
    2751                 :         122 :   G_UNLOCK (g_utils_global);
    2752                 :             : 
    2753                 :         122 :   return system_config_dirs;
    2754                 :             : }
    2755                 :             : 
    2756                 :             : /**
    2757                 :             :  * g_nullify_pointer:
    2758                 :             :  * @nullify_location: (not nullable): the memory address of the pointer.
    2759                 :             :  *
    2760                 :             :  * Set the pointer at the specified location to %NULL.
    2761                 :             :  **/
    2762                 :             : void
    2763                 :         225 : g_nullify_pointer (gpointer *nullify_location)
    2764                 :             : {
    2765                 :         225 :   g_return_if_fail (nullify_location != NULL);
    2766                 :             : 
    2767                 :         225 :   *nullify_location = NULL;
    2768                 :             : }
    2769                 :             : 
    2770                 :             : #define KILOBYTE_FACTOR (G_GOFFSET_CONSTANT (1000))
    2771                 :             : #define MEGABYTE_FACTOR (KILOBYTE_FACTOR * KILOBYTE_FACTOR)
    2772                 :             : #define GIGABYTE_FACTOR (MEGABYTE_FACTOR * KILOBYTE_FACTOR)
    2773                 :             : #define TERABYTE_FACTOR (GIGABYTE_FACTOR * KILOBYTE_FACTOR)
    2774                 :             : #define PETABYTE_FACTOR (TERABYTE_FACTOR * KILOBYTE_FACTOR)
    2775                 :             : #define EXABYTE_FACTOR  (PETABYTE_FACTOR * KILOBYTE_FACTOR)
    2776                 :             : 
    2777                 :             : #define KIBIBYTE_FACTOR (G_GOFFSET_CONSTANT (1024))
    2778                 :             : #define MEBIBYTE_FACTOR (KIBIBYTE_FACTOR * KIBIBYTE_FACTOR)
    2779                 :             : #define GIBIBYTE_FACTOR (MEBIBYTE_FACTOR * KIBIBYTE_FACTOR)
    2780                 :             : #define TEBIBYTE_FACTOR (GIBIBYTE_FACTOR * KIBIBYTE_FACTOR)
    2781                 :             : #define PEBIBYTE_FACTOR (TEBIBYTE_FACTOR * KIBIBYTE_FACTOR)
    2782                 :             : #define EXBIBYTE_FACTOR (PEBIBYTE_FACTOR * KIBIBYTE_FACTOR)
    2783                 :             : 
    2784                 :             : /**
    2785                 :             :  * g_format_size:
    2786                 :             :  * @size: a size in bytes
    2787                 :             :  *
    2788                 :             :  * Formats a size (for example the size of a file) into a human readable
    2789                 :             :  * string.  Sizes are rounded to the nearest size prefix (kB, MB, GB)
    2790                 :             :  * and are displayed rounded to the nearest tenth. E.g. the file size
    2791                 :             :  * 3292528 bytes will be converted into the string "3.2 MB". The returned string
    2792                 :             :  * is UTF-8, and may use a non-breaking space to separate the number and units,
    2793                 :             :  * to ensure they aren’t separated when line wrapped.
    2794                 :             :  *
    2795                 :             :  * The prefix units base is 1000 (i.e. 1 kB is 1000 bytes).
    2796                 :             :  *
    2797                 :             :  * This string should be freed with g_free() when not needed any longer.
    2798                 :             :  *
    2799                 :             :  * See g_format_size_full() for more options about how the size might be
    2800                 :             :  * formatted.
    2801                 :             :  *
    2802                 :             :  * Returns: (transfer full): a newly-allocated formatted string containing
    2803                 :             :  *   a human readable file size
    2804                 :             :  *
    2805                 :             :  * Since: 2.30
    2806                 :             :  */
    2807                 :             : gchar *
    2808                 :           9 : g_format_size (guint64 size)
    2809                 :             : {
    2810                 :           9 :   return g_format_size_full (size, G_FORMAT_SIZE_DEFAULT);
    2811                 :             : }
    2812                 :             : 
    2813                 :             : /**
    2814                 :             :  * GFormatSizeFlags:
    2815                 :             :  * @G_FORMAT_SIZE_DEFAULT: behave the same as g_format_size()
    2816                 :             :  * @G_FORMAT_SIZE_LONG_FORMAT: include the exact number of bytes as part
    2817                 :             :  *     of the returned string.  For example, "45.6 kB (45,612 bytes)".
    2818                 :             :  * @G_FORMAT_SIZE_IEC_UNITS: use IEC (base 1024) units with "KiB"-style
    2819                 :             :  *     suffixes. IEC units should only be used for reporting things with
    2820                 :             :  *     a strong "power of 2" basis, like RAM sizes or RAID stripe sizes.
    2821                 :             :  *     Network and storage sizes should be reported in the normal SI units.
    2822                 :             :  * @G_FORMAT_SIZE_BITS: set the size as a quantity in bits, rather than
    2823                 :             :  *     bytes, and return units in bits. For example, ‘Mbit’ rather than ‘MB’.
    2824                 :             :  * @G_FORMAT_SIZE_ONLY_VALUE: return only value, without unit; this should
    2825                 :             :  *     not be used together with @G_FORMAT_SIZE_LONG_FORMAT
    2826                 :             :  *     nor @G_FORMAT_SIZE_ONLY_UNIT. Since: 2.74
    2827                 :             :  * @G_FORMAT_SIZE_ONLY_UNIT: return only unit, without value; this should
    2828                 :             :  *     not be used together with @G_FORMAT_SIZE_LONG_FORMAT
    2829                 :             :  *     nor @G_FORMAT_SIZE_ONLY_VALUE. Since: 2.74
    2830                 :             :  *
    2831                 :             :  * Flags to modify the format of the string returned by g_format_size_full().
    2832                 :             :  */
    2833                 :             : 
    2834                 :             : #pragma GCC diagnostic push
    2835                 :             : #pragma GCC diagnostic ignored "-Wformat-nonliteral"
    2836                 :             : 
    2837                 :             : /**
    2838                 :             :  * g_format_size_full:
    2839                 :             :  * @size: a size in bytes
    2840                 :             :  * @flags: #GFormatSizeFlags to modify the output
    2841                 :             :  *
    2842                 :             :  * Formats a size.
    2843                 :             :  *
    2844                 :             :  * This function is similar to g_format_size() but allows for flags
    2845                 :             :  * that modify the output. See #GFormatSizeFlags.
    2846                 :             :  *
    2847                 :             :  * Returns: (transfer full): a newly-allocated formatted string
    2848                 :             :  *   containing a human readable file size
    2849                 :             :  *
    2850                 :             :  * Since: 2.30
    2851                 :             :  */
    2852                 :             : gchar *
    2853                 :          67 : g_format_size_full (guint64          size,
    2854                 :             :                     GFormatSizeFlags flags)
    2855                 :             : {
    2856                 :             :   struct Format
    2857                 :             :   {
    2858                 :             :     guint64 factor;
    2859                 :             :     char string[10];
    2860                 :             :   };
    2861                 :             : 
    2862                 :             :   typedef enum
    2863                 :             :   {
    2864                 :             :     FORMAT_BYTES,
    2865                 :             :     FORMAT_BYTES_IEC,
    2866                 :             :     FORMAT_BITS,
    2867                 :             :     FORMAT_BITS_IEC
    2868                 :             :   } FormatIndex;
    2869                 :             : 
    2870                 :          67 :   const struct Format formats[4][6] = {
    2871                 :             :     {
    2872                 :             :       /* Translators: A unit symbol for size formatting, showing for example: "13.0 kB" */
    2873                 :             :       { KILOBYTE_FACTOR, N_("kB") },
    2874                 :             :       /* Translators: A unit symbol for size formatting, showing for example: "13.0 MB" */
    2875                 :             :       { MEGABYTE_FACTOR, N_("MB") },
    2876                 :             :       /* Translators: A unit symbol for size formatting, showing for example: "13.0 GB" */
    2877                 :             :       { GIGABYTE_FACTOR, N_("GB") },
    2878                 :             :       /* Translators: A unit symbol for size formatting, showing for example: "13.0 TB" */
    2879                 :             :       { TERABYTE_FACTOR, N_("TB") },
    2880                 :             :       /* Translators: A unit symbol for size formatting, showing for example: "13.0 PB" */
    2881                 :             :       { PETABYTE_FACTOR, N_("PB") },
    2882                 :             :       /* Translators: A unit symbol for size formatting, showing for example: "13.0 EB" */
    2883                 :             :       { EXABYTE_FACTOR,  N_("EB") }
    2884                 :             :     },
    2885                 :             :     {
    2886                 :             :       /* Translators: A unit symbol for size formatting, showing for example: "13.0 KiB" */
    2887                 :             :       { KIBIBYTE_FACTOR, N_("KiB") },
    2888                 :             :       /* Translators: A unit symbol for size formatting, showing for example: "13.0 MiB" */
    2889                 :             :       { MEBIBYTE_FACTOR, N_("MiB") },
    2890                 :             :       /* Translators: A unit symbol for size formatting, showing for example: "13.0 GiB" */
    2891                 :             :       { GIBIBYTE_FACTOR, N_("GiB") },
    2892                 :             :       /* Translators: A unit symbol for size formatting, showing for example: "13.0 TiB" */
    2893                 :             :       { TEBIBYTE_FACTOR, N_("TiB") },
    2894                 :             :       /* Translators: A unit symbol for size formatting, showing for example: "13.0 PiB" */
    2895                 :             :       { PEBIBYTE_FACTOR, N_("PiB") },
    2896                 :             :       /* Translators: A unit symbol for size formatting, showing for example: "13.0 EiB" */
    2897                 :             :       { EXBIBYTE_FACTOR, N_("EiB") }
    2898                 :             :     },
    2899                 :             :     {
    2900                 :             :       /* Translators: A unit symbol for size formatting, showing for example: "13.0 kbit" */
    2901                 :             :       { KILOBYTE_FACTOR, N_("kbit") },
    2902                 :             :       /* Translators: A unit symbol for size formatting, showing for example: "13.0 Mbit" */
    2903                 :             :       { MEGABYTE_FACTOR, N_("Mbit") },
    2904                 :             :       /* Translators: A unit symbol for size formatting, showing for example: "13.0 Gbit" */
    2905                 :             :       { GIGABYTE_FACTOR, N_("Gbit") },
    2906                 :             :       /* Translators: A unit symbol for size formatting, showing for example: "13.0 Tbit" */
    2907                 :             :       { TERABYTE_FACTOR, N_("Tbit") },
    2908                 :             :       /* Translators: A unit symbol for size formatting, showing for example: "13.0 Pbit" */
    2909                 :             :       { PETABYTE_FACTOR, N_("Pbit") },
    2910                 :             :       /* Translators: A unit symbol for size formatting, showing for example: "13.0 Ebit" */
    2911                 :             :       { EXABYTE_FACTOR,  N_("Ebit") }
    2912                 :             :     },
    2913                 :             :     {
    2914                 :             :       /* Translators: A unit symbol for size formatting, showing for example: "13.0 Kibit" */
    2915                 :             :       { KIBIBYTE_FACTOR, N_("Kibit") },
    2916                 :             :       /* Translators: A unit symbol for size formatting, showing for example: "13.0 Mibit" */
    2917                 :             :       { MEBIBYTE_FACTOR, N_("Mibit") },
    2918                 :             :       /* Translators: A unit symbol for size formatting, showing for example: "13.0 Gibit" */
    2919                 :             :       { GIBIBYTE_FACTOR, N_("Gibit") },
    2920                 :             :       /* Translators: A unit symbol for size formatting, showing for example: "13.0 Tibit" */
    2921                 :             :       { TEBIBYTE_FACTOR, N_("Tibit") },
    2922                 :             :       /* Translators: A unit symbol for size formatting, showing for example: "13.0 Pibit" */
    2923                 :             :       { PEBIBYTE_FACTOR, N_("Pibit") },
    2924                 :             :       /* Translators: A unit symbol for size formatting, showing for example: "13.0 Eibit" */
    2925                 :             :       { EXBIBYTE_FACTOR, N_("Eibit") }
    2926                 :             :     }
    2927                 :             :   };
    2928                 :             : 
    2929                 :             :   GString *string;
    2930                 :             :   FormatIndex index;
    2931                 :             : 
    2932                 :          67 :   g_return_val_if_fail ((flags & (G_FORMAT_SIZE_LONG_FORMAT | G_FORMAT_SIZE_ONLY_VALUE)) != (G_FORMAT_SIZE_LONG_FORMAT | G_FORMAT_SIZE_ONLY_VALUE), NULL);
    2933                 :          67 :   g_return_val_if_fail ((flags & (G_FORMAT_SIZE_LONG_FORMAT | G_FORMAT_SIZE_ONLY_UNIT)) != (G_FORMAT_SIZE_LONG_FORMAT | G_FORMAT_SIZE_ONLY_UNIT), NULL);
    2934                 :          67 :   g_return_val_if_fail ((flags & (G_FORMAT_SIZE_ONLY_VALUE | G_FORMAT_SIZE_ONLY_UNIT)) != (G_FORMAT_SIZE_ONLY_VALUE | G_FORMAT_SIZE_ONLY_UNIT), NULL);
    2935                 :             : 
    2936                 :          67 :   string = g_string_new (NULL);
    2937                 :             : 
    2938                 :          67 :   switch (flags & ~(G_FORMAT_SIZE_LONG_FORMAT | G_FORMAT_SIZE_ONLY_VALUE | G_FORMAT_SIZE_ONLY_UNIT))
    2939                 :             :     {
    2940                 :          11 :     case G_FORMAT_SIZE_DEFAULT:
    2941                 :          11 :       index = FORMAT_BYTES;
    2942                 :          11 :       break;
    2943                 :          18 :     case (G_FORMAT_SIZE_DEFAULT | G_FORMAT_SIZE_IEC_UNITS):
    2944                 :          18 :       index = FORMAT_BYTES_IEC;
    2945                 :          18 :       break;
    2946                 :          19 :     case G_FORMAT_SIZE_BITS:
    2947                 :          19 :       index = FORMAT_BITS;
    2948                 :          19 :       break;
    2949                 :          19 :     case (G_FORMAT_SIZE_BITS | G_FORMAT_SIZE_IEC_UNITS):
    2950                 :          19 :       index = FORMAT_BITS_IEC;
    2951                 :          19 :       break;
    2952                 :           0 :     default:
    2953                 :             :       g_assert_not_reached ();
    2954                 :             :     }
    2955                 :             : 
    2956                 :             : 
    2957                 :          67 :   if (size < formats[index][0].factor)
    2958                 :             :     {
    2959                 :             :       const char * units;
    2960                 :             : 
    2961                 :          30 :       if (index == FORMAT_BYTES || index == FORMAT_BYTES_IEC)
    2962                 :             :         {
    2963                 :          12 :           units = g_dngettext (GETTEXT_PACKAGE, "byte", "bytes", (guint) size);
    2964                 :             :         }
    2965                 :             :       else
    2966                 :             :         {
    2967                 :          18 :           units = g_dngettext (GETTEXT_PACKAGE, "bit", "bits", (guint) size);
    2968                 :             :         }
    2969                 :             : 
    2970                 :          30 :       if ((flags & G_FORMAT_SIZE_ONLY_UNIT) != 0)
    2971                 :             :         g_string_append (string, units);
    2972                 :          21 :       else if ((flags & G_FORMAT_SIZE_ONLY_VALUE) != 0)
    2973                 :             :         /* Translators: The "%u" is replaced with the size value, like "13"; it could
    2974                 :             :          * be part of "13 bytes", but only the number is requested this time. */
    2975                 :           9 :         g_string_printf (string, C_("format-size", "%u"), (guint) size);
    2976                 :             :       else
    2977                 :             :         {
    2978                 :             :           /* Translators: The first "%u" is replaced with the value, the "%s" with a unit of the value.
    2979                 :             :            * The order can be changed with "%$2s %$1u". An example: "13 bytes" */
    2980                 :          12 :           g_string_printf (string, C_("format-size", "%u %s"), (guint) size, units);
    2981                 :             :         }
    2982                 :             : 
    2983                 :          30 :       flags &= ~G_FORMAT_SIZE_LONG_FORMAT;
    2984                 :             :     }
    2985                 :             :   else
    2986                 :             :     {
    2987                 :          37 :       const gsize n = G_N_ELEMENTS (formats[index]);
    2988                 :             :       const gchar * units;
    2989                 :             :       gdouble value;
    2990                 :             :       gsize i;
    2991                 :             : 
    2992                 :             :       /*
    2993                 :             :        * Point the last format (the highest unit) by default
    2994                 :             :        * and then then scan all formats, starting with the 2nd one
    2995                 :             :        * because the 1st is already managed by with the plural form
    2996                 :             :        */
    2997                 :          37 :       const struct Format * f = &formats[index][n - 1];
    2998                 :             : 
    2999                 :         110 :       for (i = 1; i < n; i++)
    3000                 :             :         {
    3001                 :         106 :           if (size < formats[index][i].factor)
    3002                 :             :             {
    3003                 :          33 :               f = &formats[index][i - 1];
    3004                 :          33 :               break;
    3005                 :             :             }
    3006                 :             :         }
    3007                 :             : 
    3008                 :          37 :       units = _(f->string);
    3009                 :          37 :       value = (gdouble) size / (gdouble) f->factor;
    3010                 :             : 
    3011                 :          37 :       if ((flags & G_FORMAT_SIZE_ONLY_UNIT) != 0)
    3012                 :             :         g_string_append (string, units);
    3013                 :          34 :       else if ((flags & G_FORMAT_SIZE_ONLY_VALUE) != 0)
    3014                 :             :         /* Translators: The "%.1f" is replaced with the size value, like "13.0"; it could
    3015                 :             :          * be part of "13.0 MB", but only the number is requested this time. */
    3016                 :           3 :         g_string_printf (string, C_("format-size", "%.1f"), value);
    3017                 :             :       else
    3018                 :             :         {
    3019                 :             :           /* Translators: The first "%.1f" is replaced with the value, the "%s" with a unit of the value.
    3020                 :             :            * The order can be changed with "%$2s %$1.1f". Keep the no-break space between the value and
    3021                 :             :            * the unit symbol. An example: "13.0 MB" */
    3022                 :          31 :           g_string_printf (string, C_("format-size", "%.1f %s"), value, units);
    3023                 :             :         }
    3024                 :             :     }
    3025                 :             : 
    3026                 :          67 :   if (flags & G_FORMAT_SIZE_LONG_FORMAT)
    3027                 :             :     {
    3028                 :             :       /* First problem: we need to use the number of bytes to decide on
    3029                 :             :        * the plural form that is used for display, but the number of
    3030                 :             :        * bytes potentially exceeds the size of a guint (which is what
    3031                 :             :        * ngettext() takes).
    3032                 :             :        *
    3033                 :             :        * From a pragmatic standpoint, it seems that all known languages
    3034                 :             :        * base plural forms on one or both of the following:
    3035                 :             :        *
    3036                 :             :        *   - the lowest digits of the number
    3037                 :             :        *
    3038                 :             :        *   - if the number if greater than some small value
    3039                 :             :        *
    3040                 :             :        * Here's how we fake it:  Draw an arbitrary line at one thousand.
    3041                 :             :        * If the number is below that, then fine.  If it is above it,
    3042                 :             :        * then we take the modulus of the number by one thousand (in
    3043                 :             :        * order to keep the lowest digits) and add one thousand to that
    3044                 :             :        * (in order to ensure that 1001 is not treated the same as 1).
    3045                 :             :        */
    3046                 :           3 :       guint plural_form = size < 1000 ? size : size % 1000 + 1000;
    3047                 :             : 
    3048                 :             :       /* Second problem: we need to translate the string "%u byte/bit" and
    3049                 :             :        * "%u bytes/bits" for pluralisation, but the correct number format to
    3050                 :             :        * use for a gsize is different depending on which architecture
    3051                 :             :        * we're on.
    3052                 :             :        *
    3053                 :             :        * Solution: format the number separately and use "%s bytes/bits" on
    3054                 :             :        * all platforms.
    3055                 :             :        */
    3056                 :             :       const gchar *translated_format;
    3057                 :             :       gchar *formatted_number;
    3058                 :             : 
    3059                 :           3 :       if (index == FORMAT_BYTES || index == FORMAT_BYTES_IEC)
    3060                 :             :         {
    3061                 :             :           /* Translators: the %s in "%s bytes" will always be replaced by a number. */
    3062                 :           1 :           translated_format = g_dngettext (GETTEXT_PACKAGE, "%s byte", "%s bytes", plural_form);
    3063                 :             :         }
    3064                 :             :       else
    3065                 :             :         {
    3066                 :             :           /* Translators: the %s in "%s bits" will always be replaced by a number. */
    3067                 :           2 :           translated_format = g_dngettext (GETTEXT_PACKAGE, "%s bit", "%s bits", plural_form);
    3068                 :             :         }
    3069                 :           3 :       formatted_number = g_strdup_printf ("%'"G_GUINT64_FORMAT, size);
    3070                 :             : 
    3071                 :           3 :       g_string_append (string, " (");
    3072                 :           3 :       g_string_append_printf (string, translated_format, formatted_number);
    3073                 :           3 :       g_free (formatted_number);
    3074                 :           6 :       g_string_append (string, ")");
    3075                 :             :     }
    3076                 :             : 
    3077                 :          67 :   return g_string_free (string, FALSE);
    3078                 :             : }
    3079                 :             : 
    3080                 :             : #pragma GCC diagnostic pop
    3081                 :             : 
    3082                 :             : /**
    3083                 :             :  * g_format_size_for_display:
    3084                 :             :  * @size: a size in bytes
    3085                 :             :  *
    3086                 :             :  * Formats a size (for example the size of a file) into a human
    3087                 :             :  * readable string. Sizes are rounded to the nearest size prefix
    3088                 :             :  * (KB, MB, GB) and are displayed rounded to the nearest tenth.
    3089                 :             :  * E.g. the file size 3292528 bytes will be converted into the
    3090                 :             :  * string "3.1 MB".
    3091                 :             :  *
    3092                 :             :  * The prefix units base is 1024 (i.e. 1 KB is 1024 bytes).
    3093                 :             :  *
    3094                 :             :  * This string should be freed with g_free() when not needed any longer.
    3095                 :             :  *
    3096                 :             :  * Returns: (transfer full): a newly-allocated formatted string
    3097                 :             :  *   containing a human readable file size
    3098                 :             :  *
    3099                 :             :  * Since: 2.16
    3100                 :             :  *
    3101                 :             :  * Deprecated:2.30: This function is broken due to its use of SI
    3102                 :             :  *     suffixes to denote IEC units. Use g_format_size() instead.
    3103                 :             :  */
    3104                 :             : gchar *
    3105                 :           9 : g_format_size_for_display (goffset size)
    3106                 :             : {
    3107                 :           9 :   if (size < (goffset) KIBIBYTE_FACTOR)
    3108                 :           3 :     return g_strdup_printf (g_dngettext(GETTEXT_PACKAGE, "%u byte", "%u bytes",(guint) size), (guint) size);
    3109                 :             :   else
    3110                 :             :     {
    3111                 :             :       gdouble displayed_size;
    3112                 :             : 
    3113                 :           6 :       if (size < (goffset) MEBIBYTE_FACTOR)
    3114                 :             :         {
    3115                 :           1 :           displayed_size = (gdouble) size / (gdouble) KIBIBYTE_FACTOR;
    3116                 :             :           /* Translators: this is from the deprecated function g_format_size_for_display() which uses 'KB' to
    3117                 :             :            * mean 1024 bytes.  I am aware that 'KB' is not correct, but it has been preserved for reasons of
    3118                 :             :            * compatibility.  Users will not see this string unless a program is using this deprecated function.
    3119                 :             :            * Please translate as literally as possible.
    3120                 :             :            */
    3121                 :           1 :           return g_strdup_printf (_("%.1f KB"), displayed_size);
    3122                 :             :         }
    3123                 :           5 :       else if (size < (goffset) GIBIBYTE_FACTOR)
    3124                 :             :         {
    3125                 :           1 :           displayed_size = (gdouble) size / (gdouble) MEBIBYTE_FACTOR;
    3126                 :           1 :           return g_strdup_printf (_("%.1f MB"), displayed_size);
    3127                 :             :         }
    3128                 :           4 :       else if (size < (goffset) TEBIBYTE_FACTOR)
    3129                 :             :         {
    3130                 :           1 :           displayed_size = (gdouble) size / (gdouble) GIBIBYTE_FACTOR;
    3131                 :           1 :           return g_strdup_printf (_("%.1f GB"), displayed_size);
    3132                 :             :         }
    3133                 :           3 :       else if (size < (goffset) PEBIBYTE_FACTOR)
    3134                 :             :         {
    3135                 :           1 :           displayed_size = (gdouble) size / (gdouble) TEBIBYTE_FACTOR;
    3136                 :           1 :           return g_strdup_printf (_("%.1f TB"), displayed_size);
    3137                 :             :         }
    3138                 :           2 :       else if (size < (goffset) EXBIBYTE_FACTOR)
    3139                 :             :         {
    3140                 :           1 :           displayed_size = (gdouble) size / (gdouble) PEBIBYTE_FACTOR;
    3141                 :           1 :           return g_strdup_printf (_("%.1f PB"), displayed_size);
    3142                 :             :         }
    3143                 :             :       else
    3144                 :             :         {
    3145                 :           1 :           displayed_size = (gdouble) size / (gdouble) EXBIBYTE_FACTOR;
    3146                 :           1 :           return g_strdup_printf (_("%.1f EB"), displayed_size);
    3147                 :             :         }
    3148                 :             :     }
    3149                 :             : }
    3150                 :             : 
    3151                 :             : #if defined (G_OS_WIN32) && !defined (_WIN64)
    3152                 :             : 
    3153                 :             : /* Binary compatibility versions. Not for newly compiled code. */
    3154                 :             : 
    3155                 :             : _GLIB_EXTERN const gchar *g_get_user_name_utf8        (void);
    3156                 :             : _GLIB_EXTERN const gchar *g_get_real_name_utf8        (void);
    3157                 :             : _GLIB_EXTERN const gchar *g_get_home_dir_utf8         (void);
    3158                 :             : _GLIB_EXTERN const gchar *g_get_tmp_dir_utf8          (void);
    3159                 :             : _GLIB_EXTERN gchar       *g_find_program_in_path_utf8 (const gchar *program);
    3160                 :             : 
    3161                 :             : gchar *
    3162                 :             : g_find_program_in_path_utf8 (const gchar *program)
    3163                 :             : {
    3164                 :             :   return g_find_program_in_path (program);
    3165                 :             : }
    3166                 :             : 
    3167                 :             : const gchar *g_get_user_name_utf8 (void) { return g_get_user_name (); }
    3168                 :             : const gchar *g_get_real_name_utf8 (void) { return g_get_real_name (); }
    3169                 :             : const gchar *g_get_home_dir_utf8 (void) { return g_get_home_dir (); }
    3170                 :             : const gchar *g_get_tmp_dir_utf8 (void) { return g_get_tmp_dir (); }
    3171                 :             : 
    3172                 :             : #endif
    3173                 :             : 
    3174                 :             : /* Private API:
    3175                 :             :  *
    3176                 :             :  * Returns %TRUE if the current process was executed as setuid
    3177                 :             :  */ 
    3178                 :             : gboolean
    3179                 :        5117 : g_check_setuid (void)
    3180                 :             : {
    3181                 :             : #if defined(HAVE_SYS_AUXV_H) && defined(HAVE_GETAUXVAL) && defined(AT_SECURE)
    3182                 :             :   unsigned long value;
    3183                 :             :   int errsv;
    3184                 :             : 
    3185                 :        5117 :   errno = 0;
    3186                 :        5117 :   value = getauxval (AT_SECURE);
    3187                 :        5117 :   errsv = errno;
    3188                 :        5117 :   if (errsv)
    3189                 :           0 :     g_error ("getauxval () failed: %s", g_strerror (errsv));
    3190                 :        5117 :   return value;
    3191                 :             : #elif defined(HAVE_ISSETUGID) && !defined(__ANDROID__)
    3192                 :             :   /* BSD: http://www.freebsd.org/cgi/man.cgi?query=issetugid&sektion=2 */
    3193                 :             : 
    3194                 :             :   /* Android had it in older versions but the new 64 bit ABI does not
    3195                 :             :    * have it anymore, and some versions of the 32 bit ABI neither.
    3196                 :             :    * https://code.google.com/p/android-developer-preview/issues/detail?id=168
    3197                 :             :    */
    3198                 :             :   return issetugid ();
    3199                 :             : #elif defined(G_OS_UNIX)
    3200                 :             :   uid_t ruid, euid, suid; /* Real, effective and saved user ID's */
    3201                 :             :   gid_t rgid, egid, sgid; /* Real, effective and saved group ID's */
    3202                 :             : 
    3203                 :             :   static gsize check_setuid_initialised;
    3204                 :             :   static gboolean is_setuid;
    3205                 :             : 
    3206                 :             :   if (g_once_init_enter (&check_setuid_initialised))
    3207                 :             :     {
    3208                 :             : #ifdef HAVE_GETRESUID
    3209                 :             :       /* These aren't in the header files, so we prototype them here.
    3210                 :             :        */
    3211                 :             :       int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
    3212                 :             :       int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid);
    3213                 :             :       
    3214                 :             :       if (getresuid (&ruid, &euid, &suid) != 0 ||
    3215                 :             :           getresgid (&rgid, &egid, &sgid) != 0)
    3216                 :             : #endif /* HAVE_GETRESUID */
    3217                 :             :         {
    3218                 :             :           suid = ruid = getuid ();
    3219                 :             :           sgid = rgid = getgid ();
    3220                 :             :           euid = geteuid ();
    3221                 :             :           egid = getegid ();
    3222                 :             :         }
    3223                 :             : 
    3224                 :             :       is_setuid = (ruid != euid || ruid != suid ||
    3225                 :             :                    rgid != egid || rgid != sgid);
    3226                 :             : 
    3227                 :             :       g_once_init_leave (&check_setuid_initialised, 1);
    3228                 :             :     }
    3229                 :             :   return is_setuid;
    3230                 :             : #else
    3231                 :             :   return FALSE;
    3232                 :             : #endif
    3233                 :             : }
    3234                 :             : 
    3235                 :             : #ifdef G_OS_WIN32
    3236                 :             : /**
    3237                 :             :  * g_abort:
    3238                 :             :  *
    3239                 :             :  * A wrapper for the POSIX abort() function.
    3240                 :             :  *
    3241                 :             :  * On Windows it is a function that makes extra effort (including a call
    3242                 :             :  * to abort()) to ensure that a debugger-catchable exception is thrown
    3243                 :             :  * before the program terminates.
    3244                 :             :  *
    3245                 :             :  * See your C library manual for more details about abort().
    3246                 :             :  *
    3247                 :             :  * Since: 2.50
    3248                 :             :  */
    3249                 :             : void
    3250                 :             : g_abort (void)
    3251                 :             : {
    3252                 :             :   /* One call to break the debugger
    3253                 :             :    * We check if a debugger is actually attached to
    3254                 :             :    * avoid a windows error reporting popup window
    3255                 :             :    * when run in a test harness / on CI
    3256                 :             :    */
    3257                 :             :   if (IsDebuggerPresent ())
    3258                 :             :     DebugBreak ();
    3259                 :             :   /* One call in case CRT changes its abort() behaviour */
    3260                 :             :   abort ();
    3261                 :             :   /* And one call to bind them all and terminate the program for sure */
    3262                 :             :   ExitProcess (127);
    3263                 :             : }
    3264                 :             : #endif
        

Generated by: LCOV version 2.0-1