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

#include <cparser/ast/ast_t.h>
#include <cparser/ast/entity_t.h>
#include <cparser/ast/symbol_t.h>

#include <apimagic/apimagic.h>

static const struct amgc_entity * enumval_vector_entity(
	const struct amgc_unit_ctx *	uctx,
	const union entity_t *		entity)
{
	const struct amgc_entity * aentity;

	aentity = uctx->entities->enumvals;

	for (; aentity->entity; aentity++)
		if (aentity->entity == entity)
			return aentity;

	return 0;
}

static int enumval_cmp(const void * ptra, const void * ptrb)
{
	struct amgc_entity * entitya = (struct amgc_entity *)ptra;
	struct amgc_entity * entityb = (struct amgc_entity *)ptrb;

	if (entitya->enumval == entityb->enumval)
		return (strcmp(
				entitya->altname
					? entitya->altname
					: entitya->entity->base.symbol->string,
				entityb->altname
					? entityb->altname
					: entityb->entity->base.symbol->string));
	else if ((entitya->enumval <= -128) && (entityb->enumval >= 0))
		return 1;
	else if ((entityb->enumval <= -128) && (entitya->enumval >= 0))
		return -1;
	else if ((entitya->enumval < entityb->enumval)
			&& (entitya->enumval > -128)
			&& (entityb->enumval > -128))
		return -1;
	else
		return 1;
}

int amgc_get_enum_members(
	const struct amgc_unit_ctx *	uctx,
	const union entity_t *		penum,
	struct amgc_entity **		pmembers)
{
	int				nmembers;
	struct amgc_entity *		buffer;
	struct amgc_entity *		pentity;
	const struct amgc_entity *	aentity;
	const union entity_t *		entity;

	if (penum->base.kind != ENTITY_ENUM)
		return -1;

	entity	= penum->enume.first_value;
	nmembers= 0;

	for (; entity && (entity->base.kind == ENTITY_ENUM_VALUE); ) {
		if (!(aentity = enumval_vector_entity(uctx,entity)))
			return -1;

		if (!aentity->fexclude)
			nmembers++;

		entity = entity->base.next;
	}

	/* use first element as a guard */
	if (!(buffer = calloc(1+nmembers+1,sizeof(*buffer))))
		return -1;

	pentity = &buffer[1];
	entity	= penum->enume.first_value;

	for (; entity && (entity->base.kind == ENTITY_ENUM_VALUE); ) {
		aentity = enumval_vector_entity(uctx,entity);

		if (!aentity->fexclude)
			memcpy(pentity++,aentity,sizeof(*pentity));

		entity = entity->base.next;
	}

	*pmembers = &buffer[1];
	qsort(*pmembers,nmembers,sizeof(struct amgc_entity),enumval_cmp);

	return 0;
}

void amgc_free_enum_members(struct amgc_entity * members)
{
	/* first element is a guard */
	if (members)
		free(--members);
}