mail-notification

Fork of Jean-Yves Lefort's mail-notification, a tray icon to notify of new mail
git clone https://code.djc.id.au/git/mail-notification/

jbsrc/lib/src/core/jb-variable.c (14586B) - raw

      1 /*
      2  * JB, the Jean-Yves Lefort's Build System
      3  * Copyright (C) 2008 Jean-Yves Lefort <jylefort@brutele.be>
      4  *
      5  * This program is free software; you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License as published by
      7  * the Free Software Foundation; either version 3 of the License, or
      8  * (at your option) any later version.
      9  *
     10  * This program is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  * GNU General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU General Public License along
     16  * with this program; if not, write to the Free Software Foundation, Inc.,
     17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
     18  */
     19 
     20 #include <string.h>
     21 #include "jb-variable.h"
     22 #include "jb-util.h"
     23 
     24 static GHashTable *variable_types = NULL;
     25 static GHashTable *variables_hash_table = NULL;
     26 
     27 GSList *jb_variables = NULL;
     28 
     29 GSList *jb_variable_groups = NULL;
     30 
     31 JBVariableGroup *jb_variable_group_compiler_options = NULL;
     32 JBVariableGroup *jb_variable_group_installation_options = NULL;
     33 JBVariableGroup *jb_variable_group_external_programs = NULL;
     34 
     35 JBVariableType *jb_variable_type_bool = NULL;
     36 JBVariableType *jb_variable_type_string = NULL;
     37 JBVariableType *jb_variable_type_mode = NULL;
     38 
     39 static JBVariableType *
     40 variable_type_new (const char *name,
     41 		   GType gtype,
     42 		   gboolean (*from_string) (const char *str, GValue *value, GError **err),
     43 		   char * (*to_string) (const GValue *value))
     44 {
     45   JBVariableType *self;
     46 
     47   self = g_new0(JBVariableType, 1);
     48   self->name = g_strdup(name);
     49   self->gtype = gtype;
     50   self->from_string = from_string;
     51   self->to_string = to_string;
     52 
     53   return self;
     54 }
     55 
     56 static JBVariableType *
     57 variable_type_add (const char *name,
     58 		   GType gtype,
     59 		   gboolean (*from_string) (const char *str, GValue *value, GError **err),
     60 		   char * (*to_string) (const GValue *value))
     61 {
     62   JBVariableType *type;
     63 
     64   type = variable_type_new(name, gtype, from_string, to_string);
     65 
     66   g_hash_table_insert(variable_types, type->name, type);
     67 
     68   return type;
     69 }
     70 
     71 static gboolean
     72 bool_from_string (const char *str, GValue *value, GError **err)
     73 {
     74   if (! strcmp(str, "yes"))
     75     g_value_set_boolean(value, TRUE);
     76   else if (! strcmp(str, "no"))
     77     g_value_set_boolean(value, FALSE);
     78   else
     79     {
     80       g_set_error(err, 0, 0, "\"yes\" or \"no\" expected");
     81       return FALSE;
     82     }
     83 
     84   return TRUE;
     85 }
     86 
     87 static char *
     88 bool_to_string (const GValue *value)
     89 {
     90   if (g_value_get_boolean(value))
     91     return g_strdup("yes");
     92   else
     93     return g_strdup("no");
     94 }
     95 
     96 static gboolean
     97 string_from_string (const char *str, GValue *value, GError **err)
     98 {
     99   g_value_set_string(value, *str == '\0' ? NULL : str);
    100 
    101   return TRUE;
    102 }
    103 
    104 static char *
    105 string_to_string (const GValue *value)
    106 {
    107   char *str;
    108 
    109   str = g_value_dup_string(value);
    110 
    111   return str == NULL ? g_strdup("") : str;
    112 }
    113 
    114 static gboolean
    115 mode_from_string (const char *str, GValue *value, GError **err)
    116 {
    117   guint32 mode;
    118 
    119   if (! jb_parse_uint32(str, 8, &mode, err))
    120     return FALSE;
    121 
    122   if ((mode & ~07777) != 0)
    123     {
    124       g_set_error(err, 0, 0, "mode out of range");
    125       return FALSE;
    126     }
    127 
    128   g_value_set_uint(value, mode);
    129   return TRUE;
    130 }
    131 
    132 static char *
    133 mode_to_string (const GValue *value)
    134 {
    135   unsigned int mode;
    136 
    137   mode = g_value_get_uint(value);
    138 
    139   return g_strdup_printf(JB_MODE_FORMAT, mode);
    140 }
    141 
    142 void
    143 jb_variable_init (void)
    144 {
    145   variable_types = g_hash_table_new(g_str_hash, g_str_equal);
    146   variables_hash_table = g_hash_table_new(g_str_hash, g_str_equal);
    147 
    148   jb_variable_group_compiler_options = jb_variable_add_group("Compiler options");
    149   jb_variable_group_installation_options = jb_variable_add_group("Installation options");
    150   jb_variable_group_external_programs = jb_variable_add_group("External programs");
    151 
    152   jb_variable_type_bool = variable_type_add("bool",
    153 					    G_TYPE_BOOLEAN,
    154 					    bool_from_string,
    155 					    bool_to_string);
    156   jb_variable_type_string = variable_type_add("string",
    157 					      G_TYPE_STRING,
    158 					      string_from_string,
    159 					      string_to_string);
    160   jb_variable_type_mode = variable_type_add("mode",
    161 					    G_TYPE_UINT,
    162 					    mode_from_string,
    163 					    mode_to_string);
    164 }
    165 
    166 JBVariableGroup *
    167 jb_variable_add_group (const char *name)
    168 {
    169   JBVariableGroup *group;
    170 
    171   group = g_new0(JBVariableGroup, 1);
    172   group->name = g_strdup(name);
    173 
    174   jb_variable_groups = g_slist_append(jb_variable_groups, group);
    175 
    176   return group;
    177 }
    178 
    179 JBVariableType *
    180 jb_variable_get_type (const char *name)
    181 {
    182   g_return_val_if_fail(name != NULL, NULL);
    183 
    184   return g_hash_table_lookup(variable_types, name);
    185 }
    186 
    187 static JBVariable *
    188 variable_new (JBVariableType *type,
    189 	      const char *name,
    190 	      const char *description,
    191 	      JBVariableGroup *group,
    192 	      JBVariableFlags flags)
    193 {
    194   JBVariable *variable;
    195 
    196   g_return_val_if_fail(type != NULL, NULL);
    197   g_return_val_if_fail(name != NULL, NULL);
    198 
    199   variable = g_new0(JBVariable, 1);
    200   variable->type = type;
    201   variable->name = g_strdup(name);
    202   variable->description = g_strdup(description);
    203   variable->group = group;
    204   variable->flags = flags;
    205 
    206   g_value_init(&variable->value, type->gtype);
    207 
    208   return variable;
    209 }
    210 
    211 static void
    212 add_variable (JBVariable *variable)
    213 {
    214   g_return_if_fail(variable != NULL);
    215   g_return_if_fail(g_hash_table_lookup(variables_hash_table, variable->name) == NULL);
    216 
    217   g_hash_table_insert(variables_hash_table, variable->name, variable);
    218   jb_variables = g_slist_append(jb_variables, variable);
    219 }
    220 
    221 JBVariable *
    222 jb_variable_get_variable (const char *name)
    223 {
    224   g_return_val_if_fail(name != NULL, NULL);
    225 
    226   return g_hash_table_lookup(variables_hash_table, name);
    227 }
    228 
    229 JBVariable *
    230 jb_variable_get_variable_or_error (const char *name)
    231 {
    232   JBVariable *variable;
    233 
    234   g_return_val_if_fail(name != NULL, NULL);
    235 
    236   variable = jb_variable_get_variable(name);
    237   if (variable == NULL)
    238     g_error("variable \"%s\" does not exist", name);
    239 
    240   return variable;
    241 }
    242 
    243 JBVariable *
    244 ensure_variable (JBVariableType *type, const char *name)
    245 {
    246   JBVariable *variable;
    247 
    248   g_return_val_if_fail(name != NULL, NULL);
    249 
    250   variable = jb_variable_get_variable(name);
    251   if (variable == NULL)
    252     {
    253       variable = variable_new(type, name, NULL, NULL, 0);
    254       add_variable(variable);
    255     }
    256 
    257   return variable;
    258 }
    259 
    260 JBVariable *
    261 jb_variable_add (JBVariableType *type,
    262 		 const char *name,
    263 		 const char *description,
    264 		 JBVariableGroup *group,
    265 		 JBVariableFlags flags)
    266 {
    267   JBVariable *variable;
    268 
    269   g_return_val_if_fail(type != NULL, NULL);
    270   g_return_val_if_fail(name != NULL, NULL);
    271 
    272   variable = variable_new(type, name, description, group, flags | JB_VARIABLE_USER_SETTABLE);
    273 
    274   add_variable(variable);
    275 
    276   return variable;
    277 }
    278 
    279 void
    280 jb_variable_add_bool (const char *name,
    281 		      const char *description,
    282 		      JBVariableGroup *group,
    283 		      JBVariableFlags flags,
    284 		      gboolean default_value)
    285 {
    286   JBVariable *variable;
    287 
    288   g_return_if_fail(name != NULL);
    289 
    290   variable = jb_variable_add(jb_variable_type_bool, name, description, group, flags);
    291 
    292   g_value_set_boolean(&variable->value, default_value);
    293 }
    294 
    295 void
    296 jb_variable_add_string (const char *name,
    297 			const char *description,
    298 			JBVariableGroup *group,
    299 			JBVariableFlags flags,
    300 			const char *default_value)
    301 {
    302   JBVariable *variable;
    303 
    304   g_return_if_fail(name != NULL);
    305 
    306   variable = jb_variable_add(jb_variable_type_string, name, description, group, flags);
    307 
    308   g_value_set_string(&variable->value, default_value);
    309 }
    310 
    311 void
    312 jb_variable_add_mode (const char *name,
    313 		      const char *description,
    314 		      JBVariableGroup *group,
    315 		      JBVariableFlags flags,
    316 		      mode_t default_value)
    317 {
    318   JBVariable *variable;
    319 
    320   g_return_if_fail(name != NULL);
    321 
    322   variable = jb_variable_add(jb_variable_type_mode, name, description, group, flags);
    323 
    324   g_value_set_uint(&variable->value, default_value);
    325 }
    326 
    327 gboolean
    328 jb_variable_get_bool (const char *name)
    329 {
    330   JBVariable *variable;
    331 
    332   g_return_val_if_fail(name != NULL, FALSE);
    333 
    334   variable = jb_variable_get_variable_or_error(name);
    335   g_return_val_if_fail(variable->type == jb_variable_type_bool, FALSE);
    336 
    337   return g_value_get_boolean(&variable->value);
    338 }
    339 
    340 void
    341 jb_variable_set_bool (const char *name, gboolean value)
    342 {
    343   JBVariable *variable;
    344 
    345   g_return_if_fail(name != NULL);
    346 
    347   variable = ensure_variable(jb_variable_type_bool, name);
    348 
    349   g_value_set_boolean(&variable->value, value);
    350 }
    351 
    352 const char *
    353 jb_variable_get_string (const char *name)
    354 {
    355   const char *value;
    356 
    357   g_return_val_if_fail(name != NULL, FALSE);
    358 
    359   value = jb_variable_get_string_or_null(name);
    360 
    361   return value != NULL ? value : "";
    362 }
    363 
    364 const char *
    365 jb_variable_get_string_or_null (const char *name)
    366 {
    367   JBVariable *variable;
    368 
    369   g_return_val_if_fail(name != NULL, FALSE);
    370 
    371   variable = jb_variable_get_variable_or_error(name);
    372   g_return_val_if_fail(variable->type == jb_variable_type_string, FALSE);
    373 
    374   return g_value_get_string(&variable->value);
    375 }
    376 
    377 void
    378 jb_variable_set_string (const char *name, const char *value)
    379 {
    380   JBVariable *variable;
    381 
    382   g_return_if_fail(name != NULL);
    383 
    384   variable = ensure_variable(jb_variable_type_string, name);
    385 
    386   g_value_set_string(&variable->value, value);
    387 }
    388 
    389 mode_t
    390 jb_variable_get_mode (const char *name)
    391 {
    392   JBVariable *variable;
    393 
    394   g_return_val_if_fail(name != NULL, FALSE);
    395 
    396   variable = jb_variable_get_variable_or_error(name);
    397   g_return_val_if_fail(variable->type == jb_variable_type_mode, FALSE);
    398 
    399   return g_value_get_uint(&variable->value);
    400 }
    401 
    402 void
    403 jb_variable_set_mode (const char *name, mode_t value)
    404 {
    405   JBVariable *variable;
    406 
    407   g_return_if_fail(name != NULL);
    408 
    409   variable = ensure_variable(jb_variable_type_mode, name);
    410 
    411   g_value_set_uint(&variable->value, value);
    412 }
    413 
    414 void
    415 jb_variable_set_package_flags (const char *name,
    416 			       const char *cflags,
    417 			       const char *cppflags,
    418 			       const char *ldflags,
    419 			       const char *libs)
    420 {
    421   char *cflags_var;
    422   char *cppflags_var;
    423   char *ldflags_var;
    424   char *libs_var;
    425 
    426   g_return_if_fail(name != NULL);
    427 
    428   cflags_var = g_strdup_printf("%s-cflags", name);
    429   jb_variable_set_string(cflags_var, cflags);
    430   g_free(cflags_var);
    431 
    432   cppflags_var = g_strdup_printf("%s-cppflags", name);
    433   jb_variable_set_string(cppflags_var, cppflags);
    434   g_free(cppflags_var);
    435 
    436   ldflags_var = g_strdup_printf("%s-ldflags", name);
    437   jb_variable_set_string(ldflags_var, ldflags);
    438   g_free(ldflags_var);
    439 
    440   libs_var = g_strdup_printf("%s-libs", name);
    441   jb_variable_set_string(libs_var, libs);
    442   g_free(libs_var);
    443 }
    444 
    445 gboolean
    446 jb_variable_set_from_string (JBVariable *self, const char *value, GError **err)
    447 {
    448   g_return_val_if_fail(self != NULL, FALSE);
    449   g_return_val_if_fail(value != NULL, FALSE);
    450 
    451   return self->type->from_string(value, &self->value, err);
    452 }
    453 
    454 char *
    455 jb_variable_to_string (JBVariable *self)
    456 {
    457   g_return_val_if_fail(self != NULL, NULL);
    458 
    459   return self->type->to_string(&self->value);
    460 }
    461 
    462 static char *
    463 get_expansion (const char *varname, GHashTable *extra_variables)
    464 {
    465   JBVariable *variable;
    466 
    467   if (extra_variables != NULL)
    468     {
    469       const char *extra_value;
    470 
    471       if (g_hash_table_lookup_extended(extra_variables, varname, NULL, (gpointer) &extra_value))
    472 	return g_strdup(extra_value != NULL ? extra_value : "");
    473     }
    474 
    475   variable = jb_variable_get_variable(varname);
    476   if (variable != NULL)
    477     return jb_variable_evaluate(variable);
    478 
    479   jb_error("unknown variable \"%s\"", varname);
    480 }
    481 
    482 static char *
    483 expand_real (const char *str, GHashTable *extra_variables)
    484 {
    485   GString *result;
    486   const char *p;
    487 
    488   g_return_val_if_fail(str != NULL, NULL);
    489 
    490   result = g_string_new(NULL);
    491 
    492   for (p = str; *p != '\0';)
    493     {
    494       char c = *p;
    495 
    496       if (c == '$')
    497 	{
    498 	  char *name;
    499 	  char *value;
    500 	  char *expanded_value;
    501 
    502 	  if (p[1] == '$')
    503 	    {
    504 	      g_string_append_c(result, '$');
    505 	      p += 2;
    506 	      continue;
    507 	    }
    508 
    509 	  if (p[1] == '{')
    510 	    {
    511 	      char *end;
    512 
    513 	      p += 2;
    514 
    515 	      end = strchr(p, '}');
    516 	      if (end == NULL)
    517 		jb_error("unterminated variable reference");
    518 
    519 	      if (end == p + 1)
    520 		jb_error("empty variable reference");
    521 
    522 	      name = g_strndup(p, end - p);
    523 	      p = end + 1;
    524 	    }
    525 	  else
    526 	    {
    527 	      const char *end;
    528 
    529 	      p++;
    530 
    531 	      end = p + 1;
    532 	      while (g_ascii_isalnum(*end) || *end == '-')
    533 		end++;
    534 
    535 	      if (end == p)
    536 		jb_error("empty variable reference");
    537 
    538 	      name = g_strndup(p, end - p);
    539 	      p = end;
    540 	    }
    541 
    542 	  value = get_expansion(name, extra_variables);
    543 
    544 	  /* do not pass the extra variables to the recursive expansion */
    545 	  expanded_value = expand_real(value, NULL);
    546 	  g_free(value);
    547 
    548 	  g_string_append(result, expanded_value);
    549 	  g_free(expanded_value);
    550 	}
    551       else
    552 	{
    553 	  g_string_append_c(result, c);
    554 	  p++;
    555 	}
    556     }
    557 
    558   return g_string_free(result, FALSE);
    559 }
    560 
    561 char *
    562 jb_variable_evaluate (JBVariable *variable)
    563 {
    564   static GSList *evaluation_stack = NULL;
    565   char *str;
    566   char *value;
    567 
    568   g_return_val_if_fail(variable != NULL, NULL);
    569 
    570   if (evaluation_stack != NULL && evaluation_stack->data == variable)
    571     jb_error("variable \"%s\" references itself", variable->name);
    572 
    573   if (g_slist_find(evaluation_stack, variable) != NULL)
    574     jb_error("variable \"%s\" indirectly references itself", variable->name);
    575 
    576   evaluation_stack = g_slist_prepend(evaluation_stack, variable);
    577 
    578   str = jb_variable_to_string(variable);
    579   value = expand_real(str, NULL);
    580   g_free(str);
    581 
    582   evaluation_stack = g_slist_delete_link(evaluation_stack, evaluation_stack);
    583 
    584   return value;
    585 }
    586 
    587 char *
    588 jb_variable_expand (const char *str, ...)
    589 {
    590   va_list args;
    591   char *expanded;
    592 
    593   va_start(args, str);
    594   expanded = jb_variable_expandv(str, args);
    595   va_end(args);
    596 
    597   return expanded;
    598 }
    599 
    600 char *
    601 jb_variable_expandv (const char *str, va_list args)
    602 {
    603   GHashTable *extra_variables;
    604   const char *extra_name;
    605   char *expanded;
    606 
    607   g_return_val_if_fail(str != NULL, NULL);
    608 
    609   extra_variables = g_hash_table_new(g_str_hash, g_str_equal);
    610 
    611   while ((extra_name = va_arg(args, const char *)) != NULL)
    612     {
    613       const char *extra_value;
    614 
    615       extra_value = va_arg(args, const char *);
    616       /*
    617        * For consistency, extra_value can be NULL, since variables can
    618        * be NULL as well.
    619        */
    620 
    621       if (g_hash_table_lookup(extra_variables, extra_name) != NULL)
    622 	g_error("extra variable \"%s\" specified twice", extra_name);
    623 
    624       g_hash_table_insert(extra_variables, (gpointer) extra_name, (gpointer) extra_value);
    625     }
    626 
    627   expanded = expand_real(str, extra_variables);
    628   g_hash_table_destroy(extra_variables);
    629 
    630   return expanded;
    631 }
    632 
    633 const char *
    634 jb_variable_get_type_name (JBVariable *self)
    635 {
    636   g_return_val_if_fail(self != NULL, NULL);
    637 
    638   return self->type->name;
    639 }