/**********************************************************/
/* apimagic: cparser-based API normalization utility */
/* Copyright (C) 2015--2021 SysDeer Technologies, LLC */
/* Released under GPLv2 and GPLv3; see COPYING.APIMAGIC. */
/**********************************************************/
#include <stdio.h>
#include <cparser/ast/ast_t.h>
#include <cparser/ast/type.h>
#include <cparser/ast/type_t.h>
#include <cparser/ast/entity_t.h>
#include <cparser/ast/symbol_t.h>
#include <apimagic/apimagic.h>
#include "apimagic_driver_impl.h"
static int output_string(
int * fdout,
const char * fmt,
const char * string,
const char * brace,
int * len)
{
int ret = fdout
? amgc_dprintf(*fdout,fmt,string,brace)
: snprintf(0,0,fmt,string,brace);
if (len && (ret > 0))
*len += ret;
return ret;
}
static int output_compound(
union entity_t const * entity,
int depth,
const struct amgc_layout * layout,
int * fdout)
{
struct compound_t const * compound;
type_qualifiers_t tquals;
union entity_t const * subentity;
const union type_t * type;
const struct declaration_t * decl;
const char * fmt;
const char * name;
const char * brace;
bool ftabs;
bool fspace;
int len;
int width;
int ptrdepth;
int symwidth;
int i;
if (entity->base.symbol && (depth == 0)) {
name = entity->base.symbol->string;
brace = " {";
} else {
name = "";
brace = "{";
}
compound = 0;
if (entity->kind == ENTITY_STRUCT)
fmt = "struct %s%s\n";
else if (entity->kind == ENTITY_UNION)
fmt = "union %s%s\n";
else if (entity->kind != ENTITY_COMPOUND_MEMBER)
return -1;
else if (entity->declaration.type->kind == TYPE_COMPOUND_STRUCT)
fmt = "struct %s%s\n";
else if (entity->declaration.type->kind == TYPE_COMPOUND_UNION)
fmt = "union %s%s\n";
else if (entity->declaration.type->kind == TYPE_POINTER) {
type = entity->declaration.type;
for (; type->kind == TYPE_POINTER; )
type = type->pointer.points_to;
compound = type->compound.compound;
entity = compound->members.first_entity;
if (type->kind == TYPE_COMPOUND_STRUCT)
fmt = "struct %s%s\n";
else if (type->kind == TYPE_COMPOUND_UNION)
fmt = "union %s%s\n";
else
return -1;
} else
return -1;
if (compound)
(void)0;
else if (entity->kind == ENTITY_COMPOUND_MEMBER) {
compound = entity->declaration.type->compound.compound;
entity = compound->members.first_entity;
} else {
compound = &entity->compound;
entity = compound->members.first_entity;
}
if (depth && fdout && (amgc_dprintf(*fdout,"\n") < 0))
return -1;
for (i=0; i<depth; i++)
if (output_string(fdout,"\t","","",0) < 0)
return -1;
if (output_string(fdout,fmt,name,brace,&len) < 0)
return -1;
for (width=0,depth++; entity; entity=entity->base.next) {
type = entity->declaration.type;
len = 0;
while (type->kind == TYPE_ARRAY)
type = type->array.element_type;
for (ptrdepth=0; type->kind==TYPE_POINTER; ptrdepth++)
type = type->pointer.points_to;
tquals = type->base.qualifiers;
ftabs = true;
switch (type->kind) {
case TYPE_TYPEDEF:
fmt = "%s ";
name = type->typedeft.typedefe->base.symbol->string;
break;
case TYPE_ATOMIC:
fmt = "%s ";
name = get_atomic_kind_name(type->atomic.akind);
break;
case TYPE_COMPOUND_STRUCT:
case TYPE_COMPOUND_UNION:
compound = type->compound.compound;
subentity = compound->members.first_entity;
decl = type->typedeft.typedefe;
if (!subentity || decl->base.symbol) {
name = decl->base.symbol->string;
fmt = (type->kind == TYPE_COMPOUND_STRUCT)
? "struct %s " : "union %s ";
} else {
ftabs = false;
name = "";
fmt = "";
if (output_compound(
entity,depth,
layout,fdout) < 0)
return -1;
}
break;
case TYPE_VOID:
fmt = "%s ";
name = "void";
break;
default:
fmt = "";
name = "";
if (fdout)
amgc_dprintf(
*fdout,
"UNHANDLED TYPE! %d ",
type->kind);
break;
}
if (ftabs)
for (i=0; i<depth; i++)
if (output_string(fdout,"\t","","",0) < 0)
return -1;
if (tquals & TYPE_QUALIFIER_CONST)
if (output_string(fdout,"const ","","",&len) < 0)
return -1;
if (output_string(fdout,fmt,name,"",&len) < 0)
return -1;
for (fspace=ptrdepth; ptrdepth; ptrdepth--) {
type = entity->declaration.type;
while (type->kind == TYPE_ARRAY)
type = type->array.element_type;
for (i=0; i<ptrdepth; i++)
type = type->pointer.points_to;
if (type->base.qualifiers & TYPE_QUALIFIER_CONST)
if (type->kind == TYPE_POINTER)
if (output_string(fdout," const ",
"","",&len) < 0)
return -1;
if (output_string(fdout,"*","","",&len) < 0)
return -1;
}
if (fspace)
len++;
if (fdout) {
symwidth = layout->symwidth;
symwidth += layout->tabwidth;
symwidth &= (~(layout->tabwidth-1));
len &= (~(layout->tabwidth-1));
while (len < symwidth) {
if (amgc_dprintf(*fdout,"\t") < 0)
return -1;
else
len += layout->tabwidth;
}
} else if (len > width)
width = len;
if (output_string(fdout,"%s",
entity->base.symbol->string,
"",0) < 0)
return -1;
type = entity->declaration.type;
while (fdout && type->kind == TYPE_ARRAY) {
if (amgc_dprintf(
*fdout,
type->array.size ? "[%zu]" : "[]",
type->array.size) < 0)
return -1;
type = type->array.element_type;
}
if (fdout && amgc_dprintf(*fdout,";\n") < 0)
return -1;
if (!ftabs && fdout && entity->base.next)
if (amgc_dprintf(*fdout,"\n") < 0)
return -1;
}
if (!fdout)
return width;
if (--depth) {
for (i=0; i<depth; i++)
if (output_string(fdout,"\t","","",0) < 0)
return -1;
if (output_string(fdout,"} ","","",0) < 0)
return -1;
} else {
if (output_string(fdout,"};\n","","",0) < 0)
return -1;
}
return 0;
}
static int output_compound_entity(
const struct amgc_driver_ctx * dctx,
const struct amgc_unit_ctx * uctx,
const struct amgc_entity * aentity,
const struct amgc_layout * layout)
{
struct amgc_layout elayout;
int fdout = amgc_driver_fdout(dctx);
(void)uctx;
if (layout && layout->symwidth)
return output_compound(aentity->entity,0,layout,&fdout);
if (layout)
memcpy(&elayout,layout,sizeof(elayout));
else
memset(&elayout,0,sizeof(elayout));
if ((elayout.symwidth = output_compound(aentity->entity,0,layout,0)) < 0)
return -1;
if (elayout.tabwidth == 0)
elayout.tabwidth = AMGC_TAB_WIDTH;
if (output_compound(aentity->entity,0,&elayout,&fdout) < 0)
return -1;
return 0;
}
int amgc_output_compound(
const struct amgc_driver_ctx * dctx,
const struct amgc_unit_ctx * uctx,
const struct amgc_entity * aentity,
const struct amgc_layout * layout)
{
union entity_t const * entity;
entity = aentity->entity;
return ((entity->kind == ENTITY_STRUCT) || (entity->kind == ENTITY_UNION))
? output_compound_entity(dctx,uctx,aentity,layout)
: -1;
}
int amgc_output_struct(
const struct amgc_driver_ctx * dctx,
const struct amgc_unit_ctx * uctx,
const struct amgc_entity * aentity,
const struct amgc_layout * layout)
{
union entity_t const * entity;
entity = aentity->entity;
return (entity->kind == ENTITY_STRUCT)
? output_compound_entity(dctx,uctx,aentity,layout)
: -1;
}
int amgc_output_union(
const struct amgc_driver_ctx * dctx,
const struct amgc_unit_ctx * uctx,
const struct amgc_entity * aentity,
const struct amgc_layout * layout)
{
union entity_t const * entity;
entity = aentity->entity;
return (entity->kind == ENTITY_UNION)
? output_compound_entity(dctx,uctx,aentity,layout)
: -1;
}
int amgc_output_unit_structs(
const struct amgc_driver_ctx * dctx,
const struct amgc_unit_ctx * uctx,
const struct amgc_layout * layout)
{
const struct amgc_entity * aentity;
for (aentity=uctx->entities->structs; aentity->entity; aentity++)
if (output_compound_entity(dctx,uctx,aentity,layout) < 0)
return -1;
return 0;
}
int amgc_output_unit_unions(
const struct amgc_driver_ctx * dctx,
const struct amgc_unit_ctx * uctx,
const struct amgc_layout * layout)
{
const struct amgc_entity * aentity;
for (aentity=uctx->entities->unions; aentity->entity; aentity++)
if (output_compound_entity(dctx,uctx,aentity,layout) < 0)
return -1;
return 0;
}