Blob Blame History Raw
/**********************************************************/
/*  apimagic: cparser-based API normalization utility     */
/*  Copyright (C) 2015--2021  Z. Gilboa                   */
/*  Released under GPLv2 and GPLv3; see COPYING.APIMAGIC. */
/**********************************************************/

#include <cparser/ast/ast_t.h>
#include <cparser/ast/entity_t.h>
#include <cparser/ast/type_t.h>
#include <libfirm/tv.h>

#include <apimagic/apimagic.h>

struct amgc_unit_entities_impl {
	struct amgc_define *		adefines;
	struct amgc_entity *		aentities;
	struct amgc_unit_entities	entities;
};

static int amgc_free_unit_entities_impl(
	struct amgc_unit_entities_impl *entities,
	int				status)
{
	if (entities->adefines)
		free(entities->adefines);

	if (entities->aentities)
		free(entities->aentities);

	free (entities);
	return status;
}

int amgc_get_unit_entities(
	const struct amgc_unit_ctx *	uctx,
	struct amgc_unit_meta *		meta,
	struct amgc_unit_entities **	pentities)
{
	struct amgc_unit_meta		umeta;
	struct amgc_define *		adefine;
	struct amgc_entity *		aentity;
	struct amgc_unit_entities *	uentities;
	union entity_t *		entity;
	union type_t *			etype;
	struct amgc_unit_entities_impl *entities;
	size_t				ndefs;
	size_t				nelements;
	int				enumval;
	int				ptrdepth;

	if (!meta)
		meta = &umeta;

	if (amgc_init_unit_meta(uctx,meta))
		return -1;

	if (!(entities = calloc(1,sizeof(*entities))))
		return -1;

	/* use first element as a guard */
	ndefs  = 1;
	ndefs += meta->ndefines + 1;

	nelements  = 1;
	nelements += meta->nenums + 1;
	nelements += meta->nenumvals + 1;
	nelements += meta->ntypedefs + 1;
	nelements += meta->nstructs + 1;
	nelements += meta->nunions + 1;
	nelements += meta->nfunctions + 1;
	nelements += meta->ngenerated + 1;

	if (!(entities->adefines = calloc(ndefs,sizeof(struct amgc_define))))
		return amgc_free_unit_entities_impl(entities,-1);

	if (!(entities->aentities = calloc(nelements,sizeof(struct amgc_entity))))
		return amgc_free_unit_entities_impl(entities,-1);

	adefine = &entities->adefines[1];
	entities->entities.defines = adefine;

	aentity = &entities->aentities[1];
	entities->entities.enums = aentity;
	aentity += meta->nenums + 1;

	entities->entities.enumvals = aentity;
	aentity += meta->nenumvals + 1;

	entities->entities.typedefs = aentity;
	aentity += meta->ntypedefs + 1;

	entities->entities.structs = aentity;
	aentity += meta->nstructs + 1;

	entities->entities.unions = aentity;
	aentity += meta->nunions + 1;

	entities->entities.functions = aentity;
	aentity += meta->nfunctions + 1;

	entities->entities.generated = aentity;
	aentity += meta->ngenerated + 1;

	meta = &umeta;
	memset(meta,0,sizeof(*meta));

	entity    = uctx->ccunit->ast->scope.first_entity;
	uentities = &entities->entities;

	for (; entity; entity=entity->base.next) {
		if (strcmp(*uctx->path,entity->base.pos.input_name))
			continue;

		if ((is_declaration(entity)) &&  (entity->declaration.implicit))
			uentities->generated[meta->ngenerated++].entity = entity;

		else {
			switch (entity->kind) {
				case ENTITY_ENUM:
					uentities->enums[meta->nenums++].entity = entity;
					break;

				case ENTITY_ENUM_VALUE:
					enumval = (int)get_tarval_long(entity->enum_value.tv);
					uentities->enumvals[meta->nenumvals].entity  = entity;
					uentities->enumvals[meta->nenumvals].enumval = enumval;
					meta->nenumvals++;
					break;

				case ENTITY_TYPEDEF:
					etype = entity->declaration.type;
					ptrdepth = 0;

					for (; etype->kind == TYPE_POINTER; etype=etype->pointer.points_to)
						ptrdepth++;

					uentities->typedefs[meta->ntypedefs].entity = entity;
					uentities->typedefs[meta->ntypedefs].reftype = etype;
					uentities->typedefs[meta->ntypedefs].ptrdepth = ptrdepth;
					meta->ntypedefs++;
					break;

				case ENTITY_STRUCT:
					if (entity->base.symbol || entity->compound.alias)
						uentities->structs[meta->nstructs++].entity = entity;
					break;

				case ENTITY_UNION:
					if (entity->base.symbol || entity->compound.alias)
						uentities->unions[meta->nunions++].entity = entity;
					break;

				case ENTITY_FUNCTION:
					uentities->functions[meta->nfunctions++].entity = entity;
					break;

				default:
					break;
			}
		}
	}

	*pentities = uentities;
	return 0;
}

void amgc_free_unit_entities(struct amgc_unit_entities * ctx)
{
	struct amgc_unit_entities_impl *ictx;
	uintptr_t			addr;

	if (ctx) {
		addr = (uintptr_t)ctx - offsetof(struct amgc_unit_entities_impl,entities);
		ictx = (struct amgc_unit_entities_impl *)addr;
		amgc_free_unit_entities_impl(ictx,0);
	}
}