/* Support functions for general registry objects.

   Copyright (C) 2011-2013 Free Software Foundation, Inc.

   This file is part of GDB.

   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 3 of the License, 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, see <http://www.gnu.org/licenses/>.  */

#include "defs.h"
#include "registry.h"
#include "gdb_assert.h"
#include <string.h>

const struct registry_data *
register_data_with_cleanup (struct registry_data_registry *registry,
			    registry_data_callback save,
			    registry_data_callback free)
{
  struct registry_data_registration **curr;

  /* Append new registration.  */
  for (curr = &registry->registrations;
       *curr != NULL;
       curr = &(*curr)->next)
    ;

  *curr = XMALLOC (struct registry_data_registration);
  (*curr)->next = NULL;
  (*curr)->data = XMALLOC (struct registry_data);
  (*curr)->data->index = registry->num_registrations++;
  (*curr)->data->save = save;
  (*curr)->data->free = free;

  return (*curr)->data;
}

void
registry_alloc_data (struct registry_data_registry *registry,
		       struct registry_fields *fields)
{
  gdb_assert (fields->data == NULL);
  fields->num_data = registry->num_registrations;
  fields->data = XCALLOC (fields->num_data, void *);
}

void
registry_clear_data (struct registry_data_registry *data_registry,
		     registry_callback_adaptor adaptor,
		     struct registry_container *container,
		     struct registry_fields *fields)
{
  struct registry_data_registration *registration;
  int i;

  gdb_assert (fields->data != NULL);

  /* Process all the save handlers.  */

  for (registration = data_registry->registrations, i = 0;
       i < fields->num_data;
       registration = registration->next, i++)
    if (fields->data[i] != NULL && registration->data->save != NULL)
      adaptor (registration->data->save, container, fields->data[i]);

  /* Now process all the free handlers.  */

  for (registration = data_registry->registrations, i = 0;
       i < fields->num_data;
       registration = registration->next, i++)
    if (fields->data[i] != NULL && registration->data->free != NULL)
      adaptor (registration->data->free, container, fields->data[i]);

  memset (fields->data, 0, fields->num_data * sizeof (void *));
}

void
registry_container_free_data (struct registry_data_registry *data_registry,
			      registry_callback_adaptor adaptor,
			      struct registry_container *container,
			      struct registry_fields *fields)
{
  void ***rdata = &fields->data;
  gdb_assert (*rdata != NULL);
  registry_clear_data (data_registry, adaptor, container, fields);
  xfree (*rdata);
  *rdata = NULL;
}

void
registry_set_data (struct registry_fields *fields,
		   const struct registry_data *data,
		   void *value)
{
  gdb_assert (data->index < fields->num_data);
  fields->data[data->index] = value;
}

void *
registry_data (struct registry_fields *fields,
	       const struct registry_data *data)
{
  gdb_assert (data->index < fields->num_data);
  return fields->data[data->index];
}
