<commit_before>/* Pango
 * modules.c:
 *
 * Copyright (C) 1999 Red Hat Software
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include "config.h"

#include <string.h>
#include <limits.h>
#include <errno.h>

#include <gmodule.h>
#include <glib/gstdio.h>

#include "pango-enum-types.h"
#include "pango-modules.h"
#include "pango-impl-utils.h"
#include "modules.h"

typedef struct _PangoModule      PangoModule;
typedef struct _PangoModuleClass PangoModuleClass;

#define PANGO_TYPE_MODULE           (pango_module_get_type ())
#define PANGO_MODULE(module) (G_TYPE_CHECK_INSTANCE_CAST ((module), PANGO_TYPE_MODULE, PangoModule))
#define PANGO_IS_MODULE(module)  (G_TYPE_CHECK_INSTANCE_TYPE ((module), PANGO_TYPE_MODULE))

typedef struct _PangoMapInfo PangoMapInfo;
typedef struct _PangoEnginePair PangoEnginePair;
typedef struct _PangoSubmap PangoSubmap;

struct _PangoMap
{
  GArray *entries;
};

struct _PangoMapEntry
{
  GSList *exact;
  GSList *fallback;
};

struct _PangoMapInfo
{
  PangoLanguage *language;
  guint engine_type_id;
  guint render_type_id;
  PangoMap *map;
};

struct _PangoEnginePair
{
  PangoEngineInfo info;
  PangoModule *module;
  PangoEngine *engine;
};

struct _PangoModule
{
  GTypeModule parent_instance;

  char *path;
  GModule *library;

  void         (*list)   (PangoEngineInfo **engines, gint *n_engines);
  void         (*init)   (GTypeModule *module);
  void         (*exit)   (void);
  PangoEngine *(*create) (const gchar *id);
};

struct _PangoModuleClass
{
  GTypeModuleClass parent_class;
};

G_LOCK_DEFINE_STATIC (maps);
static GList *maps = NULL;
/* the following are readonly after init_modules */
static GSList *registered_engines = NULL;
static GSList *dlloaded_engines = NULL;
static GHashTable *dlloaded_modules;

static void build_map    (PangoMapInfo *info);
static void init_modules (void);

static GType pango_module_get_type (void);

/* If a module cannot be used, or does not create an engine
 * correctly, we print out an error containing module name and id,
 * but to not flood the terminal with zillions of the message, we
 * set a flag on the module to only err once per module.
 */
static GQuark
get_warned_quark (void)
{
  static GQuark warned_quark = 0; /* MT-safe */

  if (G_UNLIKELY (!warned_quark))
    warned_quark = g_quark_from_static_string ("pango-module-warned");

  return warned_quark;
}

/**
 * pango_find_map:
 * @language: the language tag for which to find the map
 * @engine_type_id: the engine type for the map to find
 * @render_type_id: the render type for the map to find
 *
 * Locate a #PangoMap for a particular engine type and render
 * type. The resulting map can be used to determine the engine
 * for each character.
 *
 * Return value: the suitable #PangoMap.
 **/
PangoMap *
pango_find_map (PangoLanguage *language,
		guint          engine_type_id,
		guint          render_type_id)
{
  GList *tmp_list;
  PangoMapInfo *map_info = NULL;
  gboolean found_earlier = FALSE;

  G_LOCK (maps);

  tmp_list = maps;
  while (tmp_list)
    {
      map_info = tmp_list->data;
      if (map_info->engine_type_id == engine_type_id &&
	  map_info->render_type_id == render_type_id)
	{
	  if (map_info->language == language)
	    break;
	  else
	    found_earlier = TRUE;
	}

      tmp_list = tmp_list->next;
    }

  if (!tmp_list)
    {
      map_info = g_slice_new (PangoMapInfo);
      map_info->language = language;
      map_info->engine_type_id = engine_type_id;
      map_info->render_type_id = render_type_id;

      build_map (map_info);

      maps = g_list_prepend (maps, map_info);
    }
  else if (found_earlier)
    {
      /* Move the found map to the beginning of the list
       * for speed next time around if we had to do
       * any failing comparison. (No longer so important,
       * since we don't strcmp.)
       */
      maps = g_list_remove_link(maps, tmp_list);
      maps = g_list_prepend(maps, tmp_list->data);
      g_list_free_1(tmp_list);
    }

  G_UNLOCK (maps);

  return map_info->map;
}

G_DEFINE_TYPE (PangoModule, pango_module, G_TYPE_TYPE_MODULE);

static gboolean
pango_module_load (GTypeModule *module)
{
  PangoModule *pango_module = PANGO_MODULE (module);

  if (pango_module->path)
    {
      pango_module->library = g_module_open (pango_module->path, G_MODULE_BIND_LOCAL);
      if (!pango_module->library)
	{
	  GQuark warned_quark = get_warned_quark ();
	  if (!g_object_get_qdata (G_OBJECT (pango_module), warned_quark))
	    {
	      g_warning ("%s", g_module_error());
	      g_object_set_qdata_full (G_OBJECT (pango_module), warned_quark,
				       GINT_TO_POINTER (1), NULL);
	    }
	  return FALSE;
	}

      /* extract symbols from the lib */
      if (!g_module_symbol (pango_module->library, "script_engine_init",
			    (gpointer *)(void *)&pango_module->init) ||
	  !g_module_symbol (pango_module->library, "script_engine_exit",
			    (gpointer *)(void *)&pango_module->exit) ||
	  !g_module_symbol (pango_module->library, "script_engine_list",
			    (gpointer *)(void *)&pango_module->list) ||
	  !g_module_symbol (pango_module->library, "script_engine_create",
			    (gpointer *)(void *)&pango_module->create))
	{
	  GQuark warned_quark = get_warned_quark ();
	  if (!g_object_get_qdata (G_OBJECT (pango_module), warned_quark))
	    {
	      g_warning ("%s", g_module_error());
	      g_object_set_qdata_full (G_OBJECT (pango_module), warned_quark,
				       GINT_TO_POINTER (1), NULL);
	    }

	  g_module_close (pango_module->library);

	  return FALSE;
	}
    }

  /* call the module's init function to let it */
  /* setup anything it needs to set up. */
  pango_module->init (module);

  return TRUE;
}

static void
pango_module_unload (GTypeModule *module)
{
  PangoModule *pango_module = PANGO_MODULE (module);

  pango_module->exit();

  if (pango_module->path)
    {
      g_module_close (pango_module->library);
      pango_module->library = NULL;

      pango_module->init = NULL;
      pango_module->exit = NULL;
      pango_module->list = NULL;
      pango_module->create = NULL;
    }
}

/* This only will ever be called if an error occurs during
 * initialization
 */
static void
pango_module_finalize (GObject *object)
{
  PangoModule *module = PANGO_MODULE (object);

  g_free (module->path);

  G_OBJECT_CLASS (pango_module_parent_class)->finalize (object);
}

static void
pango_module_init (PangoModule *self)
{
}

static void
pango_module_class_init (PangoModuleClass *class)
{
  GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (class);
  GObjectClass *gobject_class = G_OBJECT_CLASS (class);

  module_class->load = pango_module_load;
  module_class->unload = pango_module_unload;

  gobject_class->finalize = pango_module_finalize;
}

G_LOCK_DEFINE_STATIC (engine);

static PangoEngine *
pango_engine_pair_get_engine (PangoEnginePair *pair)
{
  G_LOCK (engine);

  if (!pair->engine)
    {
      if (g_type_module_use (G_TYPE_MODULE (pair->module)))
	{
	  pair->engine = pair->module->create (pair->info.id);
	  g_type_module_unuse (G_TYPE_MODULE (pair->module));
	}

      if (!pair->engine)
	{
	  GQuark warned_quark = get_warned_quark ();
	  if (!g_object_get_qdata (G_OBJECT (pair->module), warned_quark))
	    {
	      g_warning ("Failed to load Pango module '%s' for id '%s'", pair->module->path, pair->info.id);

	      g_object_set_qdata_full (G_OBJECT (pair->module), warned_quark,
				       GINT_TO_POINTER (1), NULL);
	    }
	}
    }

  G_UNLOCK (engine);

  return pair->engine;
}

static void
handle_included_module (PangoIncludedModule *included_module,
			GSList             **engine_list)
{
  PangoModule *module = g_object_new (PANGO_TYPE_MODULE, NULL);
  PangoEngineInfo *engine_info;
  int n_engines;
  int i;

  module->list = included_module->list;
  module->init = included_module->init;
  module->exit = included_module->exit;
  module->create = included_module->create;

  module->list (&engine_info, &n_engines);

  for (i = 0; i < n_engines; i++)
    {
      PangoEnginePair *pair = g_slice_new (PangoEnginePair);

      pair->info = engine_info[i];
      pair->module = module;
      pair->engine = NULL;

      *engine_list = g_slist_prepend (*engine_list, pair);
    }
}

static PangoModule *
find_or_create_module (const char *raw_path)
{
  PangoModule *module;
  char *path;

#if defined(G_OS_WIN32) && defined(LIBDIR)
  if (strncmp (raw_path,
	       LIBDIR "/pango/" MODULE_VERSION "/modules/",
	       strlen (LIBDIR "/pango/" MODULE_VERSION "/modules/")) == 0)
    {
      /* This is an entry put there by make install on the
       * packager's system. On Windows a prebuilt Pango
       * package can be installed in a random
       * location. The pango.modules file distributed in
       * such a package contains paths from the package
       * builder's machine. Replace the path with the real
       * one on this machine. */
      path =
	g_strconcat (pango_get_lib_subdirectory (),
		     "\\" MODULE_VERSION "\\modules\\",
		     raw_path + strlen (LIBDIR "/pango/" MODULE_VERSION "/modules/"),
		     NULL);
    }
  else
#endif
    {
      path = g_strdup (raw_path);
    }

  module = g_hash_table_lookup (dlloaded_modules, path);
  if (module)
    g_free (path);
  else
    {
      module = g_object_new (PANGO_TYPE_MODULE, NULL);
      module->path = path;
      g_hash_table_insert (dlloaded_modules, path, module);
    }

  return module;
}

static PangoScript
script_from_string (const char *str)
{
  static GEnumClass *class = NULL;
  GEnumValue *value;
  if (g_once_init_enter (&class))
    g_once_init_leave (&class, g_type_class_ref (PANGO_TYPE_SCRIPT));

  value = g_enum_get_value_by_nick (class, str);
  if (!value)
    return PANGO_SCRIPT_INVALID_CODE;

  return value->value;
}

static void
script_info_free (PangoEngineScriptInfo *script_info,
		  gpointer data G_GNUC_UNUSED)
{
  g_slice_free (PangoEngineScriptInfo, script_info);
}

static gboolean /* Returns true if succeeded, false if failed */
process_module_file (FILE *module_file, const gchar *module_file_dir)
{
  GString *line_buf = g_string_new (NULL);
  GString *tmp_buf = g_string_new (NULL);
  gboolean have_error = FALSE;

  while (pango_read_line (module_file, line_buf))
    {
      PangoEnginePair *pair = g_slice_new (PangoEnginePair);
      PangoEngineScriptInfo *script_info;
      PangoScript script;
      GList *scripts = NULL;
      GList *tmp_list;

      const char *p;
      char *q;
      int i;

      p = line_buf->str;

      if (!pango_skip_space (&p))
	{
	  g_slice_free (PangoEnginePair, pair);
	  continue;
	}

      i = 0;
      while (1)
	{
	  if (!pango_scan_string (&p, tmp_buf))
	    {
	      have_error = TRUE;
	      goto error;
	    }

	  switch (i)
	    {
	    case 0:
	      if (!g_path_is_absolute (tmp_buf->str))
		{
		  const gchar *lib_dir = pango_get_lib_subdirectory ();
		  const gchar *abs_file_name = g_build_filename (lib_dir,
								 MODULE_VERSION,
								 "modules",
								 tmp_buf->str,
								 NULL);
		  g_string_assign (tmp_buf, abs_file_name);
		  g_free ((gpointer) abs_file_name);
		}
	      pair->module = find_or_create_module (tmp_buf->str);
	      break;
	    case 1:<commit_msg>Bug 690279 - broken relocation of modules<commit_after>/* Pango
 * modules.c:
 *
 * Copyright (C) 1999 Red Hat Software
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include "config.h"

#include <string.h>
#include <limits.h>
#include <errno.h>

#include <gmodule.h>
#include <glib/gstdio.h>

#include "pango-enum-types.h"
#include "pango-modules.h"
#include "pango-impl-utils.h"
#include "modules.h"

typedef struct _PangoModule      PangoModule;
typedef struct _PangoModuleClass PangoModuleClass;

#define PANGO_TYPE_MODULE           (pango_module_get_type ())
#define PANGO_MODULE(module) (G_TYPE_CHECK_INSTANCE_CAST ((module), PANGO_TYPE_MODULE, PangoModule))
#define PANGO_IS_MODULE(module)  (G_TYPE_CHECK_INSTANCE_TYPE ((module), PANGO_TYPE_MODULE))

typedef struct _PangoMapInfo PangoMapInfo;
typedef struct _PangoEnginePair PangoEnginePair;
typedef struct _PangoSubmap PangoSubmap;

struct _PangoMap
{
  GArray *entries;
};

struct _PangoMapEntry
{
  GSList *exact;
  GSList *fallback;
};

struct _PangoMapInfo
{
  PangoLanguage *language;
  guint engine_type_id;
  guint render_type_id;
  PangoMap *map;
};

struct _PangoEnginePair
{
  PangoEngineInfo info;
  PangoModule *module;
  PangoEngine *engine;
};

struct _PangoModule
{
  GTypeModule parent_instance;

  char *path;
  GModule *library;

  void         (*list)   (PangoEngineInfo **engines, gint *n_engines);
  void         (*init)   (GTypeModule *module);
  void         (*exit)   (void);
  PangoEngine *(*create) (const gchar *id);
};

struct _PangoModuleClass
{
  GTypeModuleClass parent_class;
};

G_LOCK_DEFINE_STATIC (maps);
static GList *maps = NULL;
/* the following are readonly after init_modules */
static GSList *registered_engines = NULL;
static GSList *dlloaded_engines = NULL;
static GHashTable *dlloaded_modules;

static void build_map    (PangoMapInfo *info);
static void init_modules (void);

static GType pango_module_get_type (void);

/* If a module cannot be used, or does not create an engine
 * correctly, we print out an error containing module name and id,
 * but to not flood the terminal with zillions of the message, we
 * set a flag on the module to only err once per module.
 */
static GQuark
get_warned_quark (void)
{
  static GQuark warned_quark = 0; /* MT-safe */

  if (G_UNLIKELY (!warned_quark))
    warned_quark = g_quark_from_static_string ("pango-module-warned");

  return warned_quark;
}

/**
 * pango_find_map:
 * @language: the language tag for which to find the map
 * @engine_type_id: the engine type for the map to find
 * @render_type_id: the render type for the map to find
 *
 * Locate a #PangoMap for a particular engine type and render
 * type. The resulting map can be used to determine the engine
 * for each character.
 *
 * Return value: the suitable #PangoMap.
 **/
PangoMap *
pango_find_map (PangoLanguage *language,
		guint          engine_type_id,
		guint          render_type_id)
{
  GList *tmp_list;
  PangoMapInfo *map_info = NULL;
  gboolean found_earlier = FALSE;

  G_LOCK (maps);

  tmp_list = maps;
  while (tmp_list)
    {
      map_info = tmp_list->data;
      if (map_info->engine_type_id == engine_type_id &&
	  map_info->render_type_id == render_type_id)
	{
	  if (map_info->language == language)
	    break;
	  else
	    found_earlier = TRUE;
	}

      tmp_list = tmp_list->next;
    }

  if (!tmp_list)
    {
      map_info = g_slice_new (PangoMapInfo);
      map_info->language = language;
      map_info->engine_type_id = engine_type_id;
      map_info->render_type_id = render_type_id;

      build_map (map_info);

      maps = g_list_prepend (maps, map_info);
    }
  else if (found_earlier)
    {
      /* Move the found map to the beginning of the list
       * for speed next time around if we had to do
       * any failing comparison. (No longer so important,
       * since we don't strcmp.)
       */
      maps = g_list_remove_link(maps, tmp_list);
      maps = g_list_prepend(maps, tmp_list->data);
      g_list_free_1(tmp_list);
    }

  G_UNLOCK (maps);

  return map_info->map;
}

G_DEFINE_TYPE (PangoModule, pango_module, G_TYPE_TYPE_MODULE);

static gboolean
pango_module_load (GTypeModule *module)
{
  PangoModule *pango_module = PANGO_MODULE (module);

  if (pango_module->path)
    {
      pango_module->library = g_module_open (pango_module->path, G_MODULE_BIND_LOCAL);
      if (!pango_module->library)
	{
	  GQuark warned_quark = get_warned_quark ();
	  if (!g_object_get_qdata (G_OBJECT (pango_module), warned_quark))
	    {
	      g_warning ("%s", g_module_error());
	      g_object_set_qdata_full (G_OBJECT (pango_module), warned_quark,
				       GINT_TO_POINTER (1), NULL);
	    }
	  return FALSE;
	}

      /* extract symbols from the lib */
      if (!g_module_symbol (pango_module->library, "script_engine_init",
			    (gpointer *)(void *)&pango_module->init) ||
	  !g_module_symbol (pango_module->library, "script_engine_exit",
			    (gpointer *)(void *)&pango_module->exit) ||
	  !g_module_symbol (pango_module->library, "script_engine_list",
			    (gpointer *)(void *)&pango_module->list) ||
	  !g_module_symbol (pango_module->library, "script_engine_create",
			    (gpointer *)(void *)&pango_module->create))
	{
	  GQuark warned_quark = get_warned_quark ();
	  if (!g_object_get_qdata (G_OBJECT (pango_module), warned_quark))
	    {
	      g_warning ("%s", g_module_error());
	      g_object_set_qdata_full (G_OBJECT (pango_module), warned_quark,
				       GINT_TO_POINTER (1), NULL);
	    }

	  g_module_close (pango_module->library);

	  return FALSE;
	}
    }

  /* call the module's init function to let it */
  /* setup anything it needs to set up. */
  pango_module->init (module);

  return TRUE;
}

static void
pango_module_unload (GTypeModule *module)
{
  PangoModule *pango_module = PANGO_MODULE (module);

  pango_module->exit();

  if (pango_module->path)
    {
      g_module_close (pango_module->library);
      pango_module->library = NULL;

      pango_module->init = NULL;
      pango_module->exit = NULL;
      pango_module->list = NULL;
      pango_module->create = NULL;
    }
}

/* This only will ever be called if an error occurs during
 * initialization
 */
static void
pango_module_finalize (GObject *object)
{
  PangoModule *module = PANGO_MODULE (object);

  g_free (module->path);

  G_OBJECT_CLASS (pango_module_parent_class)->finalize (object);
}

static void
pango_module_init (PangoModule *self)
{
}

static void
pango_module_class_init (PangoModuleClass *class)
{
  GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (class);
  GObjectClass *gobject_class = G_OBJECT_CLASS (class);

  module_class->load = pango_module_load;
  module_class->unload = pango_module_unload;

  gobject_class->finalize = pango_module_finalize;
}

G_LOCK_DEFINE_STATIC (engine);

static PangoEngine *
pango_engine_pair_get_engine (PangoEnginePair *pair)
{
  G_LOCK (engine);

  if (!pair->engine)
    {
      if (g_type_module_use (G_TYPE_MODULE (pair->module)))
	{
	  pair->engine = pair->module->create (pair->info.id);
	  g_type_module_unuse (G_TYPE_MODULE (pair->module));
	}

      if (!pair->engine)
	{
	  GQuark warned_quark = get_warned_quark ();
	  if (!g_object_get_qdata (G_OBJECT (pair->module), warned_quark))
	    {
	      g_warning ("Failed to load Pango module '%s' for id '%s'", pair->module->path, pair->info.id);

	      g_object_set_qdata_full (G_OBJECT (pair->module), warned_quark,
				       GINT_TO_POINTER (1), NULL);
	    }
	}
    }

  G_UNLOCK (engine);

  return pair->engine;
}

static void
handle_included_module (PangoIncludedModule *included_module,
			GSList             **engine_list)
{
  PangoModule *module = g_object_new (PANGO_TYPE_MODULE, NULL);
  PangoEngineInfo *engine_info;
  int n_engines;
  int i;

  module->list = included_module->list;
  module->init = included_module->init;
  module->exit = included_module->exit;
  module->create = included_module->create;

  module->list (&engine_info, &n_engines);

  for (i = 0; i < n_engines; i++)
    {
      PangoEnginePair *pair = g_slice_new (PangoEnginePair);

      pair->info = engine_info[i];
      pair->module = module;
      pair->engine = NULL;

      *engine_list = g_slist_prepend (*engine_list, pair);
    }
}

static PangoModule *
find_or_create_module (const char *raw_path)
{
  PangoModule *module;
  char *path;

#if defined(G_OS_WIN32) && defined(LIBDIR)
  if (strncmp (raw_path,
	       LIBDIR "/pango/" MODULE_VERSION "/modules/",
	       strlen (LIBDIR "/pango/" MODULE_VERSION "/modules/")) == 0)
    {
      /* This is an entry put there by make install on the
       * packager's system. On Windows a prebuilt Pango
       * package can be installed in a random
       * location. The pango.modules file distributed in
       * such a package contains paths from the package
       * builder's machine. Replace the path with the real
       * one on this machine. */
      path =
	g_strconcat (pango_get_lib_subdirectory (),
		     "\\" MODULE_VERSION "\\modules\\",
		     raw_path + strlen (LIBDIR "/pango/" MODULE_VERSION "/modules/"),
		     NULL);
    }
  else
#endif
    {
      path = g_strdup (raw_path);
    }

  module = g_hash_table_lookup (dlloaded_modules, path);
  if (module)
    g_free (path);
  else
    {
      module = g_object_new (PANGO_TYPE_MODULE, NULL);
      module->path = path;
      g_hash_table_insert (dlloaded_modules, path, module);
    }

  return module;
}

static PangoScript
script_from_string (const char *str)
{
  static GEnumClass *class = NULL;
  GEnumValue *value;
  if (g_once_init_enter (&class))
    g_once_init_leave (&class, g_type_class_ref (PANGO_TYPE_SCRIPT));

  value = g_enum_get_value_by_nick (class, str);
  if (!value)
    return PANGO_SCRIPT_INVALID_CODE;

  return value->value;
}

static void
script_info_free (PangoEngineScriptInfo *script_info,
		  gpointer data G_GNUC_UNUSED)
{
  g_slice_free (PangoEngineScriptInfo, script_info);
}

static gboolean /* Returns true if succeeded, false if failed */
process_module_file (FILE *module_file, const gchar *module_file_dir)
{
  GString *line_buf = g_string_new (NULL);
  GString *tmp_buf = g_string_new (NULL);
  gboolean have_error = FALSE;

  while (pango_read_line (module_file, line_buf))
    {
      PangoEnginePair *pair = g_slice_new (PangoEnginePair);
      PangoEngineScriptInfo *script_info;
      PangoScript script;
      GList *scripts = NULL;
      GList *tmp_list;

      const char *p;
      char *q;
      int i;

      p = line_buf->str;

      if (!pango_skip_space (&p))
	{
	  g_slice_free (PangoEnginePair, pair);
	  continue;
	}

      i = 0;
      while (1)
	{
	  if (!pango_scan_string (&p, tmp_buf))
	    {
	      have_error = TRUE;
	      goto error;
	    }

	  switch (i)
	    {
	    case 0:
	      if (!g_path_is_absolute (tmp_buf->str)
#ifdef __APPLE__
	          && strncmp (tmp_buf->str, "@executable_path/", 17)
	          && strncmp (tmp_buf->str, "@loader_path/", 13)
	          && strncmp (tmp_buf->str, "@rpath/", 7)
#endif
	         )
		{
		  const gchar *lib_dir = pango_get_lib_subdirectory ();
		  const gchar *abs_file_name = g_build_filename (lib_dir,
								 MODULE_VERSION,
								 "modules",
								 tmp_buf->str,
								 NULL);
		  g_string_assign (tmp_buf, abs_file_name);
		  g_free ((gpointer) abs_file_name);
		}
	      pair->module = find_or_create_module (tmp_buf->str);
	      break;
	    case 1:
{'fraction_non_alphanumeric': 0.10449071751128951, 'fraction_numerical': 0.003135975915704967, 'mean_word_length': 3.4906120916259855, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 156, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1251885', 'n_tokens_mistral': 8606, 'n_tokens_neox': 8094, 'n_words': 2105}