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

gbx_class_load.c

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

  class_load.c

  Gambas class loader

  (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_CLASS_LOAD_C

#include "gb_common.h"
#include "gb_common_case.h"
#include "gb_common_buffer.h"
#include "gb_common_swap.h"
#include "gb_alloc.h"
#include "gb_error.h"
#include "gb_limit.h"

#include <ctype.h>

#include "gb_buffer.h"
#include "gb_file.h"
#include "gbx_type.h"
#include "gbx_exec.h"
#include "gbx_debug.h"
#include "gb_magic.h"
#include "gbx_stream.h"

#include "gbx_string.h"
#include "gbx_object.h"
#include "gbx_variant.h"
#include "gbx_number.h"

#include "gambas.h"

#include "gbx_class.h"

/*
#define DEBUG
#define DEBUG_LOAD 1
*/


PRIVATE const char *ClassName;
PRIVATE bool _swap;


/*
PRIVATE void CLASS_new(void **ptr, CLASS *class, char *name, OBJECT *parent)
{
  VALUE_FUNCTION exec;

  OBJECT_new(ptr, class, name, parent);

  exec.class = class;
  exec.object = *ptr;
  exec.function = FUNC_INIT_DYNAMIC;

  #if DEBUG_EVENT
  printf("CLASS_new (%s %p) parent (%s %p)\n", ((OBJECT *)*ptr)->class->name, *ptr, parent->class->name, parent);
  #endif

  EXEC_function(&exec, 0);
}
*/

#ifdef DEBUG
PRIVATE CLASS *Class;
PRIVATE int NSection;
#endif

#define RELOCATE(_ptr) (_ptr = (char *)&class->string[(long)(_ptr)])


PRIVATE char *get_section(char *sec_name, char **section, long one, short *psize, char *swapcode)
{
  char *current = *section + sizeof(long);
  long section_size = *((long *)(*section));
  long i, n;
  char *p;
  char *ps;
  size_t ss;
  void (*func)();
  short size;

  if (_swap)
    SWAP_long(&section_size);

  #ifdef DEBUG
  NSection++;
  printf("Section #%d %s %08lX %ld %ld\n", NSection + 1, sec_name, (long)(current - (char *)Class->data), one, section_size);
  #endif

  /*
  if (section_size == 0)
    THROW(E_FORMAT);
  */

  *section += section_size + sizeof(long);

  if (section_size % one)
    THROW(E_CLASS, ClassName, "Bad format in ", sec_name);

  size = section_size / one;
  if (psize)
    *psize = size;

  if (_swap && swapcode)
  {
    p = current;

    if (one == sizeof(short))
    {
      for (i = 0; i < size; i++)
      {
        SWAP_short((short *)p);
        p += sizeof(short);
      }
    }
    else if (one == sizeof(long))
    {
      for (i = 0; i < size; i++)
      {
        SWAP_long((long *)p);
        p += sizeof(long);
      }
    }
    else
    {
      for (i = 0; i < size; i++)
      {
        p = current + i * one;

        ps = swapcode;
        while (*ps)
        {
          if (*ps == 's')
          {
            func = SWAP_short;
            ss = sizeof(short);
          }
          else
          {
            func = SWAP_long;
            ss = sizeof(long);
          }
          ps++;

          if (isdigit(*ps))
          {
            n = *ps - '0';
            ps++;
          }
          else if (*ps == '*')
          {
            n = one / ss;
            ps++;
          }
          else
            n = 1;

          while (n)
          {
            (*func)(p);
            p += ss;
            n--;
          }
        }
      }
    }
  }

  return current;
}


PRIVATE void conv_type(CLASS *class, void *ptype)
{
  CTYPE *ctype = (CTYPE *)ptype;
  TYPE type = *((TYPE *)ptype);

  if (ctype->id == T_OBJECT && ctype->value >= 0)
    type = (TYPE)(class->load->class_ref[ctype->value]);
  else if (ctype->id == T_ARRAY || ctype->id == T_STRUCT)
    ERROR_panic("conv_type: bad type");
  else
    type = (TYPE)(ctype->id);

  *((TYPE *)ptype) = type;
}


PUBLIC void CLASS_load_without_init(CLASS *class)
{
  char *section;
  CLASS_HEADER *header;
  CLASS_INFO *info;
  int i, j;
  CLASS_LOCAL *local;
  FUNCTION *func;
  CLASS_DESC *desc;
  CLASS_DESC *start;
  short n_class_ref;
  short n_unknown;
  CLASS_CONST *cc;
  CLASS_VAR *var;
  int len;
  CLASS_EVENT *event;
  short n_array;
  VALUE value;
  long len_data;
  long first;
  short n_desc;
  long offset;
  int first_event;
  FUNC_DEBUG *debug;

  if (class->state >= CS_LOADED)
    return;

  #if DEBUG_LOAD
    printf("Loading class %s (%p)...\n", class->name, class);
  #endif

  #ifdef DEBUG
    Class = class;
    NSection = 0;
  #endif

  ClassName = class->name;

  if (class->in_load)
    THROW(E_CLASS, ClassName, "Circular reference", "");

  ARCHIVE_last = NULL;
  len = strlen(class->name);

  {
    char name[len + 9];
    char *p;

    strcpy(name, ".gambas/");
    p = &name[8];

    for (i = 0; i < len; i++)
      *p++ = toupper(class->name[i]);
    *p = 0;

    TRY
    {
      STREAM_load(name, &class->data, &len_data);
    }
    CATCH
    {
      THROW(E_CLASS, class->name, "Unable to load class file", "");
    }
    END_TRY

    /*if (BUFFER_load_file(&class->data, FILE_get(name)))
      THROW(E_CLASS, ClassName, "Unable to load class file", "");*/
  }

  class->in_load = TRUE;
  class->belong = ARCHIVE_last;

  ALLOC_ZERO(&class->load, sizeof(CLASS_LOAD), "CLASS_load");

  /* header */

  section = class->data;

  header = (CLASS_HEADER *)section;
  section += sizeof(CLASS_HEADER);

  _swap = header->endian != OUTPUT_ENDIAN;
  /*if (_swap)
    fprintf(stderr, "Swapping class %s\n", class->name);*/

  if (_swap)
  {
    SWAP_long((long *)&header->magic);
    SWAP_long((long *)&header->version);
    SWAP_long((long *)&header->flag);
  }

  if (header->magic != OUTPUT_MAGIC)
    THROW(E_CLASS, ClassName, "Bad header", "");

  if (header->version != OUTPUT_VERSION)
    THROW(E_CLASS, ClassName, "Bad version", "");

  class->debug = header->flag & CF_DEBUG;


  /* Chargement des sections */

  #ifdef DEBUG
  Class = class;
  #endif

  info = (CLASS_INFO *)get_section("info section", &section, sizeof(CLASS_INFO), NULL, "s2l2");
  start = (CLASS_DESC *)get_section("description section", &section, sizeof(CLASS_DESC), &n_desc, "l*");
  class->load->cst = (CLASS_CONST *)get_section("constant section", &section, sizeof(CLASS_CONST), &class->load->n_cst, "l*");
  class->load->class_ref = (CLASS **)get_section("reference section", &section, sizeof(long), &n_class_ref, "l*");
  class->load->unknown = (char **)get_section("extern section", &section, sizeof(long), &n_unknown, "l*");
  class->load->stat = (CLASS_VAR *)get_section("static section", &section, sizeof(CLASS_VAR), &class->load->n_stat, "l*");
  class->load->dyn = (CLASS_VAR *)get_section("dynamic section", &section, sizeof(CLASS_VAR), &class->load->n_dyn, "l*");
  class->load->event = (CLASS_EVENT *)get_section("event section", &section, sizeof(CLASS_EVENT), &class->n_event, "ls2l2");
  class->load->func = (FUNCTION *)get_section("function section", &section, sizeof(FUNCTION), &class->load->n_func, "ls6l4");
  local = (CLASS_LOCAL *)get_section("local section", &section, sizeof(CLASS_LOCAL), NULL, "l*");
  class->load->array = (CLASS_ARRAY **)get_section("array section", &section, sizeof(long), &n_array, "l");

  /* Chargement du code */

  for (i = 0; i < class->load->n_func; i++)
  {
    func = &class->load->func[i];
    func->code = (ushort *)get_section("code section", &section, sizeof(ushort), NULL, "s");
  }

  /* Informations de débogage */

  if (class->debug)
  {
    class->load->global = (GLOBAL_SYMBOL *)
      get_section("global symbol section", &section, sizeof(GLOBAL_SYMBOL),
                  &class->load->n_global, "s2l3");

    debug = (FUNC_DEBUG *)get_section("debug method section", &section, sizeof(FUNC_DEBUG), NULL, "s2l3s2");

    for (i = 0; i < class->load->n_func; i++)
    {
      func = &class->load->func[i];
      func->debug = &debug[i];
    }

    for (i = 0; i < class->load->n_func; i++)
    {
      func = &class->load->func[i];
      func->debug->pos = (ushort *)get_section("line method section", &section, sizeof(ushort), NULL, "s");
    }

    for (i = 0; i < class->load->n_func; i++)
    {
      func = &class->load->func[i];
      func->debug->local = (LOCAL_SYMBOL *)get_section("local symbol section", &section, sizeof(LOCAL_SYMBOL), &func->debug->n_local, "s2l2");
    }
  }

  /* Nom du fichier source */

  if (class->debug)
    class->path = (char *)get_section("source file name section", &section, sizeof(char), NULL, NULL);

  /* chaînes de caractères */

  class->string = (char *)get_section("string section", &section, sizeof(char), NULL, NULL);

  /* Enregistrement des classes référencées */

  for (i = 0; i < n_class_ref; i++)
    class->load->class_ref[i] = CLASS_find(&class->string[(long)class->load->class_ref[i]]);

  /* conversion des types */

  for (i = 0; i < class->load->n_func; i++)
  {
    func = &class->load->func[i];
    conv_type(class, &func->type);

    if (func->n_param > 0)
    {
      func->param = (CLASS_PARAM *)local;

      for (j = 0; j < func->n_param; j++)
        conv_type(class, &func->param[j].type);

      local += func->n_param;
    }

    if (func->n_local > 0)
    {
      func->local = (CLASS_LOCAL *)local;

      /* Les types des variables locales sont conservés tels quels */
      /*
      for (j = 0; j < func->n_local; j++)
        conv_type(class, &func->local[j].type);
      */

      local += func->n_local;
    }
  }

  /* Initialisation des informations sur les évènements */

  for (i = 0; i < class->n_event; i++)
  {
    event = &class->load->event[i];

    conv_type(class, &event->type);

    if (event->n_param > 0)
    {
      event->param = (CLASS_PARAM *)local;

      for (j = 0; j < event->n_param; j++)
        conv_type(class, &event->param[j].type);

      local += event->n_param;
    }
  }

  /* On vérifie qu'on a bien atteint la fin du fichier */

  if (section != &class->data[len_data])
  {
    /*printf("%d\n", &class->load[BUFFER_length(class->load)] - section);*/
    THROW(E_CLASS, ClassName, "Unknown section", "");
  }


  /* relocation des définitions de tableaux */

  if (n_array > 0)
  {
    n_array = *((long *)class->load->array) / sizeof(long);

    for (i = 0; i < n_array; i++)
    {
      class->load->array[i] = (CLASS_ARRAY *)((char *)class->load->array + ((long *)class->load->array)[i]);
      conv_type(class, &(class->load->array[i]->type));
    }
  }

  /* relocation des chaînes de caractères */

  for (i = 0; i < n_desc; i++)
    RELOCATE(start[i].gambas.name);

  for (i = 0; i < n_unknown; i++)
    RELOCATE(class->load->unknown[i]);

  for (i = 0; i < class->n_event; i++)
    RELOCATE(class->load->event[i].name);

  if (class->debug)
  {
    for (i = 0; i < class->load->n_global; i++)
    {
      RELOCATE(class->load->global[i].sym.name);
      /*conv_type(class, &(class->load->global[i].type));*/
    }

    for (i = 0; i < class->load->n_func; i++)
    {
      func = &class->load->func[i];
      RELOCATE(func->debug->name);

      for (j = 0; j < func->debug->n_local; j++)
        RELOCATE(func->debug->local[j].sym.name);
    }
  }

  /* héritage */

  if (info->parent >= 0)
  {
    //printf("%s inherits %s\n", class->name, (class->load->class_ref[info->parent])->name);
    CLASS_inheritance(class, class->load->class_ref[info->parent]);
  }

  /* Callbacks d'instanciation (si la classe n'est pas statique) */

  if ((info->s_dynamic == 0) && (class->parent == NULL || class->parent->new == NULL))
  {
    class->new = NULL;
    class->free = (void (*)())CLASS_do_nothing;
    /*class->ref = (void (*)())CLASS_do_nothing;
    class->unref = (void (*)())CLASS_do_nothing;*/
    SET_IF_NULL(class->check, (int (*)())CLASS_return_zero);
  }
  else
  {
    class->new = (void (*)())OBJECT_new;
    class->free = (void (*)())OBJECT_release;
    /*class->ref = (void (*)())CLASS_ref;
    class->unref = (void (*)())CLASS_unref;*/
    SET_IF_NULL(class->check, (int (*)())CLASS_return_zero);
  }

  /* Descriptions */

  CLASS_make_description(class, start, n_desc, &first);

  /* Tailles et offsets */

  CLASS_calc_info(class, class->n_event, info->s_dynamic, FALSE, info->s_static);

  /* Initialisation des informations sur les variables statiques et dynamiques */

  if (class->parent)
    offset = class->parent->off_event;
  else
    offset = sizeof(OBJECT);

  for (i = 0; i < class->load->n_dyn; i++)
  {
    var = &class->load->dyn[i];
    var->pos += offset;
  }

  /* Conversion et relocation des constantes */

  for (i = 0; i < class->load->n_cst; i++)
  {
    cc = &class->load->cst[i];
    conv_type(class, &(cc->type));
    if (!TYPE_is_integer(cc->type))
      cc->_string.addr += (long)class->string;
    if (cc->type == T_FLOAT)
    {
      if (NUMBER_from_string(NB_READ_FLOAT,cc->_string.addr, strlen(cc->_string.addr), &value))
        THROW(E_CLASS, ClassName, "Bad constant", "");

      cc->_float.value = value._float.value;
    }
  }


  /* Traitement de la description */

  for (i = first; i < class->n_desc; i++)
  {
    desc = class->table[i].desc;

    switch (desc->gambas.val4)
    {
      case CD_PROPERTY_ID: desc->gambas.name = "p"; break;
      case CD_VARIABLE_ID: desc->gambas.name = "v"; break;
      case CD_METHOD_ID: desc->gambas.name = "m"; break;
      case CD_STATIC_PROPERTY_ID: desc->gambas.name = "P"; break;
      case CD_STATIC_VARIABLE_ID: desc->gambas.name = "V"; break;
      case CD_STATIC_METHOD_ID: desc->gambas.name = "M"; break;
      case CD_CONSTANT_ID: desc->gambas.name = "C"; break;
      case CD_EVENT_ID: desc->gambas.name = ":"; break;
    }

    conv_type(class, &desc->gambas.type);

    switch (CLASS_DESC_get_type(desc))
    {
      case CD_METHOD:
      case CD_STATIC_METHOD:

        func = &class->load->func[desc->gambas.val1];
        desc->method.exec = (void (*)())desc->gambas.val1;
        desc->method.npmin = func->npmin;
        desc->method.npmax = func->n_param;
        desc->method.signature = (TYPE *)func->param;
        //desc->method.help = NULL;
        desc->method.native = FALSE;

        break;

      case CD_PROPERTY:
      case CD_STATIC_PROPERTY:

        desc->property.read = (void (*)())desc->gambas.val1;
        desc->property.write = (void (*)())desc->gambas.val2;
        if ((long)desc->property.write == -1)
          desc->gambas.name = *desc->gambas.name == 'p' ? "r" : "R";
        desc->property.native = FALSE;

        break;

      case CD_VARIABLE:
      case CD_STATIC_VARIABLE:

        if (CLASS_DESC_get_type(desc) == CD_STATIC_VARIABLE)
          var = &class->load->stat[desc->gambas.val1];
        else
          var = &class->load->dyn[desc->gambas.val1];

        desc->variable.offset = var->pos;

        break;

      case CD_CONSTANT:

        cc = &class->load->cst[desc->gambas.val1];

        if (TYPE_is_integer(desc->constant.type))
          desc->constant.value._integer = cc->_integer.value;
        else if (desc->constant.type == T_FLOAT)
          desc->constant.value._float = cc->_float.value;
        else
        {
          desc->constant.type = T_CSTRING;
          desc->constant.value._string = cc->_string.addr;
        }

        break;

      case CD_EVENT:

        event = &class->load->event[desc->gambas.val1];
        desc->event.npmin = event->n_param;
        desc->event.npmax = event->n_param;
        desc->event.signature = (TYPE *)event->param;
        //desc->event.help = NULL;
        break;

      default:

        THROW(E_CLASS, ClassName, "Bad description", "");
    }
    
    desc->method.class = class;
  }

  /* description des événements stockée à part */

  CLASS_make_event(class, &first_event);

  if (first_event > 0)
    memcpy(&class->event[first_event], class->load->event, (class->n_event - first_event) * sizeof(CLASS_EVENT));

  /* Tri */

  CLASS_sort(class);

  /* Méthodes spéciales de la classe */

  class->special[SPEC_NEW] = CLASS_get_symbol_desc_kind(class, "_new", CD_METHOD, 0);
  class->special[SPEC_FREE] = CLASS_get_symbol_desc_kind(class, "_free", CD_METHOD, 0);
  class->special[SPEC_CALL] = CLASS_get_symbol_desc_kind(class, "_call", CD_METHOD, CD_STATIC_METHOD);

  /* Initialisation des données statiques */

  EXEC.native = FALSE;
  EXEC.class = class;
  EXEC.object = NULL;
  EXEC.nparam = 0;
  EXEC.index = FUNC_INIT_STATIC;
  //EXEC.func = &class->load->func[FUNC_INIT_STATIC];

  EXEC_function();

  /* On peut faire référence à la classe */

  class->in_load = FALSE;

  /* La classe est maintenant utilisable ! */

  class->state = CS_LOADED;
}


PUBLIC void CLASS_load_real(CLASS *class)
{
  CLASS_load_without_init(class);
  class->state = CS_READY;

  EXEC_public(class, NULL, "_init", 0);
}

Generated by  Doxygen 1.6.0   Back to index