Logo Search packages:      
Sourcecode: gambas version File versions  Download package

gbx_c_settings.c

/***************************************************************************

  gbx_c_settings.c

  (c) 2000-2004 Benoît Minisini <gambas@users.sourceforge.net>

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 1, or (at your option)
  any later version.

  This program 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 General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

***************************************************************************/

#define __GBX_C_SETTINGS_C

#include "gb_common.h"

#include <pwd.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>

#include "gb_common_case.h"
#include "gb_error.h"
#include "gb_buffer.h"
#include "gb_file.h"
#include "gbx_api.h"
#include "gbx_project.h"
#include "gbx_local.h"
#include "gbx_number.h"
#include "gbx_exec.h"
#include "gbx_c_collection.h"
#include "gbx_c_settings.h"

/*#define DEBUG*/


static char *_data;
static long _ptr;
static long _len;

static char get_next_char(void)
{
  if (_ptr >= _len)
    return 0;
  else
    return _data[_ptr++];
}

static void next_line(void)
{
  char c;
  
  for(;;)
  {
    c = get_next_char();
    if (c == '\n' || c == 0)
      break;
  }
}


static void unquote_string(VALUE *result, char *str, long len)
{
  int i, j;
  char c;
  
  j = 0;
  for (i = 0; i < len; i++)
  {
    c = str[i];
    if (c == '\\')
    {
      i++;
      c = str[i];
      if (c == 'n')
        c = '\n';
    }
    
    str[j++] = c;
  }
  
  if (len > 0)
  {
    result->type = T_STRING;
    STRING_new_temp(&result->_string.addr, str, j);
    result->_string.start = 0;
    result->_string.len = j;
  }
  else
  {
    result->type = T_NULL;
  }
}


static void from_string(VALUE *value, const char *addr, long len)
{
  if (!DATE_from_string(addr, len, value, FALSE))
    return;
    
  if (!NUMBER_from_string(NB_READ_BOTH | NB_READ_HEX_BIN, addr, len, value))
    return;
    
  if (len == 0)
  {
    value->type = T_NULL;
    return;
  }
  
  value->type = T_BOOLEAN;
  value->_boolean.value = strchr("0FfNn", *addr) == NULL;
}


static bool check_key(const char *key, long len)
{
  int i;
  char c;
  
  for (i = 0; i < len; i++)
  {
    c = key[i];
    if (c <= ' ' || c == '=')
    {    
      GB_Error("Bad key");
      return TRUE;
    }
  }
  
  return FALSE;
}


static void read_line(CSETTINGS *_object)
{
  long p;
  char c;
  char *key;
  long key_len;
  char *val;
  long val_len;
  VALUE result;

  p = _ptr;
  
  for(;;)
  {
    c = get_next_char();
    if (c < ' ' || c == '=')
      break;
  }
  
  key = &_data[p];
  key_len = _ptr - p - 1;
  
  for(;;)
  {
    c = get_next_char();
    if ((c > ' ' && c != '=') || c == 0 || c == '\n')
      break;
  }
  
  p = _ptr - 1;
  next_line();
  
  val = &_data[p];
  val_len = _ptr - p - 1;
  
  #ifdef DEBUG
  fprintf(stderr, "%.*s = %.*s\n", (int)key_len, key, (int)val_len, val);
  #endif
  
  result.type = T_NULL;
  
  if (*val == '"')
  {
    val++;
    val_len--;
    
    if (val[val_len - 1] == '"')
      val_len--;
      
    unquote_string(&result, val, val_len);
  }
  else
  {
    result.type = T_CSTRING;
    result._string.addr = val;
    result._string.start = 0;
    result._string.len = val_len;
    
    from_string(&result, val, val_len);
  }

  if (result.type != T_NULL)
  {  
    VALUE_conv(&result, T_VARIANT);
    GB_CollectionSet(THIS->table, key, key_len, (GB_VARIANT *)&result);
  }
}


static void load_config(CSETTINGS *_object)
{
  char c;
  
  #ifdef DEBUG
  fprintf(stderr, "load_config: %s\n", THIS->path);
  #endif

  BUFFER_load_file(&_data, THIS->path);
  if (!_data)
    return;
    
  _ptr = 0;
  _len = BUFFER_length(_data);
  
  for(;;)
  {
    c = get_next_char();
    
    if (c == 0)
      break;
    if (c <= ' ')
      continue;
    if (c == '#')
    {
      next_line();
      continue;
    }
    
    _ptr--;
    
    read_line(THIS);
  }
  
  BUFFER_delete(&_data);
}


static void save_config(CSETTINGS *_object)
{
  FILE *f;
  HASH_ENUM iter;
  HASH_TABLE *hash;
  void *value;
  char *str;
  long len;
  VALUE res;
  int i;
  char c;

  if (!THIS->modified)
    return;
    
  #ifdef DEBUG
  fprintf(stderr, "save_config: %s\n", THIS->path);
  #endif
  
  f = fopen(THIS->path, "w");
  if (!f)
  {
    GB_Error((char *)E_OPEN, THIS->path, strerror(errno));
    return;
  }
  
  
  fprintf(f, "# Gambas configuration file 1.0\n");
  fprintf(f, "# for %s\n", PROJECT_name);
  
  hash = ((CCOLLECTION *)THIS->table)->hash_table;
  
  CLEAR(&iter);
  
  for(;;)
  {
    value = HASH_TABLE_next(hash, &iter);
    if (!value)
      break;
      
    HASH_TABLE_get_last_key(hash, &str, &len);
    /*for (i = 0; i < len; i++)
      fputc(tolower(str[i]), f);*/
    fprintf(f, "%.*s=", (int)len, str);
          
    #ifdef DEBUG
    fprintf(stderr, "%.*s\n", (int)len, str);
    #endif  
    
    VALUE_read(&res, value, T_VARIANT);
    VARIANT_undo(&res);
    
    if (TYPE_is_string(res.type))
    {
      VALUE_get_string(&res, &str, &len);
      fputc('"', f);
      for (i = 0; i < len; i++)
      {
        c = str[i];
        if (c == '\n')
          fprintf(f, "\\n");
        else if (c == '\\' || c == '"')
        {
          fputc('\\', f);
          fputc(c, f);
        }
        else
          fputc(c, f);
      }
      fputc('"', f);
    }
    else if (res.type == T_BOOLEAN)
    {
      fputc(res._boolean.value ? '1' : '0', f);
    }
    else
    {
      VALUE_conv(&res, T_STRING);
      VALUE_get_string(&res, &str, &len);
      fprintf(f, "%.*s", (int)len, str);
      RELEASE(&res);
    }
      
    fputc('\n', f);
  }
  
  fclose(f);
  
  THIS->modified = FALSE;
}


BEGIN_METHOD(CSETTINGS_new, GB_STRING path)

  char *path;
  struct passwd *info;
  
  if (MISSING(path))
  {
    info = getpwuid(getuid());
    if (!info)
    {
      GB_Error((char *)E_MEMORY);
      return;
    }
    
    mkdir(FILE_cat(info->pw_dir, ".gambas", NULL), S_IRWXU);
  
    STRING_new(&path, FILE_cat(info->pw_dir, ".gambas", PROJECT_name, NULL), 0);
    STRING_add(&path, ".conf", 0);
  }
  else
  {
    STRING_new(&path, STRING(path), LENGTH(path));
  }
  
  THIS->path = path;
  /*HASH_TABLE_create(&THIS->table, TYPE_sizeof(T_VARIANT), GB_COMP_TEXT);*/
  GB_CollectionNew(&THIS->table, GB_COMP_TEXT);
  GB_Ref(THIS->table);
  
  load_config(THIS);

END_METHOD


BEGIN_METHOD_VOID(CSETTINGS_free)

  save_config(THIS);
  STRING_free(&THIS->path);
  GB_Unref((void **)&THIS->table);

END_METHOD


BEGIN_METHOD_VOID(CSETTINGS_save)

  save_config(THIS);

END_METHOD


BEGIN_METHOD(CSETTINGS_get, GB_STRING key; GB_VALUE def)

  GB_VARIANT value;

  if (GB_CollectionGet(THIS->table, STRING(key), LENGTH(key), &value))
  {
    if (MISSING(def))
      GB_ReturnNull();
    else
      TEMP = *((VALUE *)ARG(def));
  }
  else  
    GB_ReturnPtr(T_VARIANT, &value.value);
  
END_METHOD


BEGIN_METHOD(CSETTINGS_put, GB_VARIANT value; GB_STRING key)

  VALUE *val;

  if (check_key(STRING(key), LENGTH(key)))
    return;

  val = (VALUE *)ARG(value);
  if (TYPE_is_object(val->type)
      || (TYPE_is_variant(val->type) && TYPE_is_object(val->_variant.vtype)))
  {
    GB_Error("Bad setting");
    return;
  }
    
  GB_CollectionSet(THIS->table, STRING(key), LENGTH(key), ARG(value));
  THIS->modified = TRUE;

END_METHOD


PUBLIC GB_DESC NATIVE_Settings[] =
{
  GB_DECLARE("Settings", sizeof(CSETTINGS)), 
  GB_AUTO_CREATABLE(),

  GB_METHOD("_new", NULL, CSETTINGS_new, "[(Path)s]"),
  GB_METHOD("_free", NULL, CSETTINGS_free, NULL),

  GB_METHOD("Save", NULL, CSETTINGS_save, NULL),
  GB_METHOD("_get", "v", CSETTINGS_get, "(Key)s[(Default)v]"),
  GB_METHOD("_put", NULL, CSETTINGS_put, "(Value)v(Key)s"),

  GB_END_DECLARE
};


Generated by  Doxygen 1.6.0   Back to index