Home | History | Annotate | Download | only in glib
      1 /* GLIB - Library of useful routines for C programming
      2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
      3  *
      4  * gdataset.c: Generic dataset mechanism, similar to GtkObject data.
      5  * Copyright (C) 1998 Tim Janik
      6  *
      7  * This library is free software; you can redistribute it and/or
      8  * modify it under the terms of the GNU Lesser General Public
      9  * License as published by the Free Software Foundation; either
     10  * version 2 of the License, or (at your option) any later version.
     11  *
     12  * This library is distributed in the hope that it will be useful,
     13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15  * Lesser General Public License for more details.
     16  *
     17  * You should have received a copy of the GNU Lesser General Public
     18  * License along with this library; if not, write to the Free Software
     19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
     20  */
     21 
     22 /*
     23  * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
     24  * file for a list of people on the GLib Team.  See the ChangeLog
     25  * files for a list of changes.  These files are distributed with
     26  * GLib at ftp://ftp.gtk.org/pub/gtk/.
     27  */
     28 
     29 /*
     30  * MT safe ; except for g_data*_foreach()
     31  */
     32 
     33 #include "config.h"
     34 
     35 #include <string.h>
     36 
     37 #include "glib.h"
     38 #include "gdatasetprivate.h"
     39 #include "galias.h"
     40 
     41 
     42 /* --- defines --- */
     43 #define	G_QUARK_BLOCK_SIZE			(512)
     44 
     45 /* datalist pointer accesses have to be carried out atomically */
     46 #define G_DATALIST_GET_POINTER(datalist)						\
     47   ((GData*) ((gsize) g_atomic_pointer_get (datalist) & ~(gsize) G_DATALIST_FLAGS_MASK))
     48 
     49 #define G_DATALIST_SET_POINTER(datalist, pointer)       G_STMT_START {                  \
     50   gpointer _oldv, _newv;                                                                \
     51   do {                                                                                  \
     52     _oldv = g_atomic_pointer_get (datalist);                                            \
     53     _newv = (gpointer) (((gsize) _oldv & G_DATALIST_FLAGS_MASK) | (gsize) pointer);     \
     54   } while (!g_atomic_pointer_compare_and_exchange ((void**) datalist, _oldv, _newv));   \
     55 } G_STMT_END
     56 
     57 /* --- structures --- */
     58 typedef struct _GDataset GDataset;
     59 struct _GData
     60 {
     61   GData *next;
     62   GQuark id;
     63   gpointer data;
     64   GDestroyNotify destroy_func;
     65 };
     66 
     67 struct _GDataset
     68 {
     69   gconstpointer location;
     70   GData        *datalist;
     71 };
     72 
     73 
     74 /* --- prototypes --- */
     75 static inline GDataset*	g_dataset_lookup		(gconstpointer	  dataset_location);
     76 static inline void	g_datalist_clear_i		(GData		**datalist);
     77 static void		g_dataset_destroy_internal	(GDataset	 *dataset);
     78 static inline gpointer	g_data_set_internal		(GData     	**datalist,
     79 							 GQuark   	  key_id,
     80 							 gpointer         data,
     81 							 GDestroyNotify   destroy_func,
     82 							 GDataset	 *dataset);
     83 static void		g_data_initialize		(void);
     84 static inline GQuark	g_quark_new			(gchar  	*string);
     85 
     86 
     87 /* --- variables --- */
     88 G_LOCK_DEFINE_STATIC (g_dataset_global);
     89 static GHashTable   *g_dataset_location_ht = NULL;
     90 static GDataset     *g_dataset_cached = NULL; /* should this be
     91 						 threadspecific? */
     92 G_LOCK_DEFINE_STATIC (g_quark_global);
     93 static GHashTable   *g_quark_ht = NULL;
     94 static gchar       **g_quarks = NULL;
     95 static GQuark        g_quark_seq_id = 0;
     96 
     97 /* --- functions --- */
     98 
     99 /* HOLDS: g_dataset_global_lock */
    100 static inline void
    101 g_datalist_clear_i (GData **datalist)
    102 {
    103   register GData *list;
    104 
    105   /* unlink *all* items before walking their destructors
    106    */
    107   list = G_DATALIST_GET_POINTER (datalist);
    108   G_DATALIST_SET_POINTER (datalist, NULL);
    109 
    110   while (list)
    111     {
    112       register GData *prev;
    113 
    114       prev = list;
    115       list = prev->next;
    116 
    117       if (prev->destroy_func)
    118 	{
    119 	  G_UNLOCK (g_dataset_global);
    120 	  prev->destroy_func (prev->data);
    121 	  G_LOCK (g_dataset_global);
    122 	}
    123 
    124       g_slice_free (GData, prev);
    125     }
    126 }
    127 
    128 void
    129 g_datalist_clear (GData **datalist)
    130 {
    131   g_return_if_fail (datalist != NULL);
    132 
    133   G_LOCK (g_dataset_global);
    134   if (!g_dataset_location_ht)
    135     g_data_initialize ();
    136 
    137   while (G_DATALIST_GET_POINTER (datalist))
    138     g_datalist_clear_i (datalist);
    139   G_UNLOCK (g_dataset_global);
    140 }
    141 
    142 /* HOLDS: g_dataset_global_lock */
    143 static inline GDataset*
    144 g_dataset_lookup (gconstpointer	dataset_location)
    145 {
    146   register GDataset *dataset;
    147 
    148   if (g_dataset_cached && g_dataset_cached->location == dataset_location)
    149     return g_dataset_cached;
    150 
    151   dataset = g_hash_table_lookup (g_dataset_location_ht, dataset_location);
    152   if (dataset)
    153     g_dataset_cached = dataset;
    154 
    155   return dataset;
    156 }
    157 
    158 /* HOLDS: g_dataset_global_lock */
    159 static void
    160 g_dataset_destroy_internal (GDataset *dataset)
    161 {
    162   register gconstpointer dataset_location;
    163 
    164   dataset_location = dataset->location;
    165   while (dataset)
    166     {
    167       if (!dataset->datalist)
    168 	{
    169 	  if (dataset == g_dataset_cached)
    170 	    g_dataset_cached = NULL;
    171 	  g_hash_table_remove (g_dataset_location_ht, dataset_location);
    172 	  g_slice_free (GDataset, dataset);
    173 	  break;
    174 	}
    175 
    176       g_datalist_clear_i (&dataset->datalist);
    177       dataset = g_dataset_lookup (dataset_location);
    178     }
    179 }
    180 
    181 void
    182 g_dataset_destroy (gconstpointer  dataset_location)
    183 {
    184   g_return_if_fail (dataset_location != NULL);
    185 
    186   G_LOCK (g_dataset_global);
    187   if (g_dataset_location_ht)
    188     {
    189       register GDataset *dataset;
    190 
    191       dataset = g_dataset_lookup (dataset_location);
    192       if (dataset)
    193 	g_dataset_destroy_internal (dataset);
    194     }
    195   G_UNLOCK (g_dataset_global);
    196 }
    197 
    198 /* HOLDS: g_dataset_global_lock */
    199 static inline gpointer
    200 g_data_set_internal (GData	  **datalist,
    201 		     GQuark         key_id,
    202 		     gpointer       data,
    203 		     GDestroyNotify destroy_func,
    204 		     GDataset	   *dataset)
    205 {
    206   register GData *list;
    207 
    208   list = G_DATALIST_GET_POINTER (datalist);
    209   if (!data)
    210     {
    211       register GData *prev;
    212 
    213       prev = NULL;
    214       while (list)
    215 	{
    216 	  if (list->id == key_id)
    217 	    {
    218 	      gpointer ret_data = NULL;
    219 
    220 	      if (prev)
    221 		prev->next = list->next;
    222 	      else
    223 		{
    224 		  G_DATALIST_SET_POINTER (datalist, list->next);
    225 
    226 		  /* the dataset destruction *must* be done
    227 		   * prior to invocation of the data destroy function
    228 		   */
    229 		  if (!list->next && dataset)
    230 		    g_dataset_destroy_internal (dataset);
    231 		}
    232 
    233 	      /* the GData struct *must* already be unlinked
    234 	       * when invoking the destroy function.
    235 	       * we use (data==NULL && destroy_func!=NULL) as
    236 	       * a special hint combination to "steal"
    237 	       * data without destroy notification
    238 	       */
    239 	      if (list->destroy_func && !destroy_func)
    240 		{
    241 		  G_UNLOCK (g_dataset_global);
    242 		  list->destroy_func (list->data);
    243 		  G_LOCK (g_dataset_global);
    244 		}
    245 	      else
    246 		ret_data = list->data;
    247 
    248               g_slice_free (GData, list);
    249 
    250 	      return ret_data;
    251 	    }
    252 
    253 	  prev = list;
    254 	  list = list->next;
    255 	}
    256     }
    257   else
    258     {
    259       while (list)
    260 	{
    261 	  if (list->id == key_id)
    262 	    {
    263 	      if (!list->destroy_func)
    264 		{
    265 		  list->data = data;
    266 		  list->destroy_func = destroy_func;
    267 		}
    268 	      else
    269 		{
    270 		  register GDestroyNotify dfunc;
    271 		  register gpointer ddata;
    272 
    273 		  dfunc = list->destroy_func;
    274 		  ddata = list->data;
    275 		  list->data = data;
    276 		  list->destroy_func = destroy_func;
    277 
    278 		  /* we need to have updated all structures prior to
    279 		   * invocation of the destroy function
    280 		   */
    281 		  G_UNLOCK (g_dataset_global);
    282 		  dfunc (ddata);
    283 		  G_LOCK (g_dataset_global);
    284 		}
    285 
    286 	      return NULL;
    287 	    }
    288 
    289 	  list = list->next;
    290 	}
    291 
    292       list = g_slice_new (GData);
    293       list->next = G_DATALIST_GET_POINTER (datalist);
    294       list->id = key_id;
    295       list->data = data;
    296       list->destroy_func = destroy_func;
    297       G_DATALIST_SET_POINTER (datalist, list);
    298     }
    299 
    300   return NULL;
    301 }
    302 
    303 void
    304 g_dataset_id_set_data_full (gconstpointer  dataset_location,
    305 			    GQuark         key_id,
    306 			    gpointer       data,
    307 			    GDestroyNotify destroy_func)
    308 {
    309   register GDataset *dataset;
    310 
    311   g_return_if_fail (dataset_location != NULL);
    312   if (!data)
    313     g_return_if_fail (destroy_func == NULL);
    314   if (!key_id)
    315     {
    316       if (data)
    317 	g_return_if_fail (key_id > 0);
    318       else
    319 	return;
    320     }
    321 
    322   G_LOCK (g_dataset_global);
    323   if (!g_dataset_location_ht)
    324     g_data_initialize ();
    325 
    326   dataset = g_dataset_lookup (dataset_location);
    327   if (!dataset)
    328     {
    329       dataset = g_slice_new (GDataset);
    330       dataset->location = dataset_location;
    331       g_datalist_init (&dataset->datalist);
    332       g_hash_table_insert (g_dataset_location_ht,
    333 			   (gpointer) dataset->location,
    334 			   dataset);
    335     }
    336 
    337   g_data_set_internal (&dataset->datalist, key_id, data, destroy_func, dataset);
    338   G_UNLOCK (g_dataset_global);
    339 }
    340 
    341 void
    342 g_datalist_id_set_data_full (GData	  **datalist,
    343 			     GQuark         key_id,
    344 			     gpointer       data,
    345 			     GDestroyNotify destroy_func)
    346 {
    347   g_return_if_fail (datalist != NULL);
    348   if (!data)
    349     g_return_if_fail (destroy_func == NULL);
    350   if (!key_id)
    351     {
    352       if (data)
    353 	g_return_if_fail (key_id > 0);
    354       else
    355 	return;
    356     }
    357 
    358   G_LOCK (g_dataset_global);
    359   if (!g_dataset_location_ht)
    360     g_data_initialize ();
    361 
    362   g_data_set_internal (datalist, key_id, data, destroy_func, NULL);
    363   G_UNLOCK (g_dataset_global);
    364 }
    365 
    366 gpointer
    367 g_dataset_id_remove_no_notify (gconstpointer  dataset_location,
    368 			       GQuark         key_id)
    369 {
    370   gpointer ret_data = NULL;
    371 
    372   g_return_val_if_fail (dataset_location != NULL, NULL);
    373 
    374   G_LOCK (g_dataset_global);
    375   if (key_id && g_dataset_location_ht)
    376     {
    377       GDataset *dataset;
    378 
    379       dataset = g_dataset_lookup (dataset_location);
    380       if (dataset)
    381 	ret_data = g_data_set_internal (&dataset->datalist, key_id, NULL, (GDestroyNotify) 42, dataset);
    382     }
    383   G_UNLOCK (g_dataset_global);
    384 
    385   return ret_data;
    386 }
    387 
    388 gpointer
    389 g_datalist_id_remove_no_notify (GData	**datalist,
    390 				GQuark    key_id)
    391 {
    392   gpointer ret_data = NULL;
    393 
    394   g_return_val_if_fail (datalist != NULL, NULL);
    395 
    396   G_LOCK (g_dataset_global);
    397   if (key_id && g_dataset_location_ht)
    398     ret_data = g_data_set_internal (datalist, key_id, NULL, (GDestroyNotify) 42, NULL);
    399   G_UNLOCK (g_dataset_global);
    400 
    401   return ret_data;
    402 }
    403 
    404 gpointer
    405 g_dataset_id_get_data (gconstpointer  dataset_location,
    406 		       GQuark         key_id)
    407 {
    408   g_return_val_if_fail (dataset_location != NULL, NULL);
    409 
    410   G_LOCK (g_dataset_global);
    411   if (key_id && g_dataset_location_ht)
    412     {
    413       register GDataset *dataset;
    414 
    415       dataset = g_dataset_lookup (dataset_location);
    416       if (dataset)
    417 	{
    418 	  register GData *list;
    419 
    420 	  for (list = dataset->datalist; list; list = list->next)
    421 	    if (list->id == key_id)
    422 	      {
    423 		G_UNLOCK (g_dataset_global);
    424 		return list->data;
    425 	      }
    426 	}
    427     }
    428   G_UNLOCK (g_dataset_global);
    429 
    430   return NULL;
    431 }
    432 
    433 gpointer
    434 g_datalist_id_get_data (GData	 **datalist,
    435 			GQuark     key_id)
    436 {
    437   gpointer data = NULL;
    438   g_return_val_if_fail (datalist != NULL, NULL);
    439   if (key_id)
    440     {
    441       register GData *list;
    442       G_LOCK (g_dataset_global);
    443       for (list = G_DATALIST_GET_POINTER (datalist); list; list = list->next)
    444 	if (list->id == key_id)
    445 	  {
    446             data = list->data;
    447             break;
    448           }
    449       G_UNLOCK (g_dataset_global);
    450     }
    451   return data;
    452 }
    453 
    454 void
    455 g_dataset_foreach (gconstpointer    dataset_location,
    456 		   GDataForeachFunc func,
    457 		   gpointer         user_data)
    458 {
    459   register GDataset *dataset;
    460 
    461   g_return_if_fail (dataset_location != NULL);
    462   g_return_if_fail (func != NULL);
    463 
    464   G_LOCK (g_dataset_global);
    465   if (g_dataset_location_ht)
    466     {
    467       dataset = g_dataset_lookup (dataset_location);
    468       G_UNLOCK (g_dataset_global);
    469       if (dataset)
    470 	{
    471 	  register GData *list, *next;
    472 
    473 	  for (list = dataset->datalist; list; list = next)
    474 	    {
    475 	      next = list->next;
    476 	      func (list->id, list->data, user_data);
    477 	    }
    478 	}
    479     }
    480   else
    481     {
    482       G_UNLOCK (g_dataset_global);
    483     }
    484 }
    485 
    486 void
    487 g_datalist_foreach (GData	   **datalist,
    488 		    GDataForeachFunc func,
    489 		    gpointer         user_data)
    490 {
    491   register GData *list, *next;
    492 
    493   g_return_if_fail (datalist != NULL);
    494   g_return_if_fail (func != NULL);
    495 
    496   for (list = G_DATALIST_GET_POINTER (datalist); list; list = next)
    497     {
    498       next = list->next;
    499       func (list->id, list->data, user_data);
    500     }
    501 }
    502 
    503 void
    504 g_datalist_init (GData **datalist)
    505 {
    506   g_return_if_fail (datalist != NULL);
    507 
    508   g_atomic_pointer_set (datalist, NULL);
    509 }
    510 
    511 /**
    512  * g_datalist_set_flags:
    513  * @datalist: pointer to the location that holds a list
    514  * @flags: the flags to turn on. The values of the flags are
    515  *   restricted by %G_DATALIST_FLAGS_MASK (currently
    516  *   3; giving two possible boolean flags).
    517  *   A value for @flags that doesn't fit within the mask is
    518  *   an error.
    519  *
    520  * Turns on flag values for a data list. This function is used
    521  * to keep a small number of boolean flags in an object with
    522  * a data list without using any additional space. It is
    523  * not generally useful except in circumstances where space
    524  * is very tight. (It is used in the base #GObject type, for
    525  * example.)
    526  *
    527  * Since: 2.8
    528  **/
    529 void
    530 g_datalist_set_flags (GData **datalist,
    531 		      guint   flags)
    532 {
    533   gpointer oldvalue;
    534   g_return_if_fail (datalist != NULL);
    535   g_return_if_fail ((flags & ~G_DATALIST_FLAGS_MASK) == 0);
    536 
    537   do
    538     {
    539       oldvalue = g_atomic_pointer_get (datalist);
    540     }
    541   while (!g_atomic_pointer_compare_and_exchange ((void**) datalist, oldvalue,
    542                                                  (gpointer) ((gsize) oldvalue | flags)));
    543 }
    544 
    545 /**
    546  * g_datalist_unset_flags:
    547  * @datalist: pointer to the location that holds a list
    548  * @flags: the flags to turn off. The values of the flags are
    549  *   restricted by %G_DATALIST_FLAGS_MASK (currently
    550  *   3: giving two possible boolean flags).
    551  *   A value for @flags that doesn't fit within the mask is
    552  *   an error.
    553  *
    554  * Turns off flag values for a data list. See g_datalist_unset_flags()
    555  *
    556  * Since: 2.8
    557  **/
    558 void
    559 g_datalist_unset_flags (GData **datalist,
    560 			guint   flags)
    561 {
    562   gpointer oldvalue;
    563   g_return_if_fail (datalist != NULL);
    564   g_return_if_fail ((flags & ~G_DATALIST_FLAGS_MASK) == 0);
    565 
    566   do
    567     {
    568       oldvalue = g_atomic_pointer_get (datalist);
    569     }
    570   while (!g_atomic_pointer_compare_and_exchange ((void**) datalist, oldvalue,
    571                                                  (gpointer) ((gsize) oldvalue & ~(gsize) flags)));
    572 }
    573 
    574 /**
    575  * g_datalist_get_flags:
    576  * @datalist: pointer to the location that holds a list
    577  *
    578  * Gets flags values packed in together with the datalist.
    579  * See g_datalist_set_flags().
    580  *
    581  * Return value: the flags of the datalist
    582  *
    583  * Since: 2.8
    584  **/
    585 guint
    586 g_datalist_get_flags (GData **datalist)
    587 {
    588   g_return_val_if_fail (datalist != NULL, 0);
    589 
    590   return G_DATALIST_GET_FLAGS (datalist); /* atomic macro */
    591 }
    592 
    593 /* HOLDS: g_dataset_global_lock */
    594 static void
    595 g_data_initialize (void)
    596 {
    597   g_return_if_fail (g_dataset_location_ht == NULL);
    598 
    599   g_dataset_location_ht = g_hash_table_new (g_direct_hash, NULL);
    600   g_dataset_cached = NULL;
    601 }
    602 
    603 GQuark
    604 g_quark_try_string (const gchar *string)
    605 {
    606   GQuark quark = 0;
    607   g_return_val_if_fail (string != NULL, 0);
    608 
    609   G_LOCK (g_quark_global);
    610   if (g_quark_ht)
    611     quark = GPOINTER_TO_UINT (g_hash_table_lookup (g_quark_ht, string));
    612   G_UNLOCK (g_quark_global);
    613 
    614   return quark;
    615 }
    616 
    617 /* HOLDS: g_quark_global_lock */
    618 static inline GQuark
    619 g_quark_from_string_internal (const gchar *string,
    620 			      gboolean     duplicate)
    621 {
    622   GQuark quark = 0;
    623 
    624   if (g_quark_ht)
    625     quark = GPOINTER_TO_UINT (g_hash_table_lookup (g_quark_ht, string));
    626 
    627   if (!quark)
    628     quark = g_quark_new (duplicate ? g_strdup (string) : (gchar *)string);
    629 
    630   return quark;
    631 }
    632 
    633 GQuark
    634 g_quark_from_string (const gchar *string)
    635 {
    636   GQuark quark;
    637 
    638   if (!string)
    639     return 0;
    640 
    641   G_LOCK (g_quark_global);
    642   quark = g_quark_from_string_internal (string, TRUE);
    643   G_UNLOCK (g_quark_global);
    644 
    645   return quark;
    646 }
    647 
    648 GQuark
    649 g_quark_from_static_string (const gchar *string)
    650 {
    651   GQuark quark;
    652 
    653   if (!string)
    654     return 0;
    655 
    656   G_LOCK (g_quark_global);
    657   quark = g_quark_from_string_internal (string, FALSE);
    658   G_UNLOCK (g_quark_global);
    659 
    660   return quark;
    661 }
    662 
    663 G_CONST_RETURN gchar*
    664 g_quark_to_string (GQuark quark)
    665 {
    666   gchar* result = NULL;
    667 
    668   G_LOCK (g_quark_global);
    669   if (quark < g_quark_seq_id)
    670     result = g_quarks[quark];
    671   G_UNLOCK (g_quark_global);
    672 
    673   return result;
    674 }
    675 
    676 /* HOLDS: g_quark_global_lock */
    677 static inline GQuark
    678 g_quark_new (gchar *string)
    679 {
    680   GQuark quark;
    681 
    682   if (g_quark_seq_id % G_QUARK_BLOCK_SIZE == 0)
    683     g_quarks = g_renew (gchar*, g_quarks, g_quark_seq_id + G_QUARK_BLOCK_SIZE);
    684   if (!g_quark_ht)
    685     {
    686       g_assert (g_quark_seq_id == 0);
    687       g_quark_ht = g_hash_table_new (g_str_hash, g_str_equal);
    688       g_quarks[g_quark_seq_id++] = NULL;
    689     }
    690 
    691   quark = g_quark_seq_id++;
    692   g_quarks[quark] = string;
    693   g_hash_table_insert (g_quark_ht, string, GUINT_TO_POINTER (quark));
    694 
    695   return quark;
    696 }
    697 
    698 /**
    699  * g_intern_string:
    700  * @string: a string
    701  *
    702  * Returns a canonical representation for @string. Interned strings can
    703  * be compared for equality by comparing the pointers, instead of using strcmp().
    704  *
    705  * Returns: a canonical representation for the string
    706  *
    707  * Since: 2.10
    708  */
    709 G_CONST_RETURN gchar*
    710 g_intern_string (const gchar *string)
    711 {
    712   const gchar *result;
    713   GQuark quark;
    714 
    715   if (!string)
    716     return NULL;
    717 
    718   G_LOCK (g_quark_global);
    719   quark = g_quark_from_string_internal (string, TRUE);
    720   result = g_quarks[quark];
    721   G_UNLOCK (g_quark_global);
    722 
    723   return result;
    724 }
    725 
    726 /**
    727  * g_intern_static_string:
    728  * @string: a static string
    729  *
    730  * Returns a canonical representation for @string. Interned strings can
    731  * be compared for equality by comparing the pointers, instead of using strcmp().
    732  * g_intern_static_string() does not copy the string, therefore @string must
    733  * not be freed or modified.
    734  *
    735  * Returns: a canonical representation for the string
    736  *
    737  * Since: 2.10
    738  */
    739 G_CONST_RETURN gchar*
    740 g_intern_static_string (const gchar *string)
    741 {
    742   GQuark quark;
    743   const gchar *result;
    744 
    745   if (!string)
    746     return NULL;
    747 
    748   G_LOCK (g_quark_global);
    749   quark = g_quark_from_string_internal (string, FALSE);
    750   result = g_quarks[quark];
    751   G_UNLOCK (g_quark_global);
    752 
    753   return result;
    754 }
    755 
    756 
    757 
    758 #define __G_DATASET_C__
    759 #include "galiasdef.c"
    760