packages feed

pbc4hs-0.1.0.0: cbits/proto.c

#include "pbc.h"
#include "proto.h"
#include "pattern.h"
#include "map.h"
#include "alloc.h"
#include "stringpool.h"
#include "bootstrap.h"

#include <stdlib.h>
#include <string.h>

const char * 
pbc_error(struct pbc_env * p) {
	const char *err = p->lasterror;
	p->lasterror = "";
	return err;
}

struct _message * 
_pbcP_get_message(struct pbc_env * p , const char *name) {
	return (struct _message *)_pbcM_sp_query(p->msgs, name);
}

struct pbc_env * 
pbc_new(void) {
	struct pbc_env * p = (struct pbc_env *)malloc(sizeof(*p));
	p->files = _pbcM_sp_new(0 , NULL);
	p->enums = _pbcM_sp_new(0 , NULL);
	p->msgs = _pbcM_sp_new(0 , NULL);
	p->lasterror = "";

	_pbcB_init(p);

	return p;
}

static void
free_enum(void *p) {
	struct _enum * e = (struct _enum *)p;
	_pbcM_ip_delete(e->id);
	_pbcM_si_delete(e->name);

	free(p);
}

static void
free_stringpool(void *p) {
	_pbcS_delete((struct _stringpool *)p);
}

static void
free_msg(void *p) {
	struct _message * m = (struct _message *)p;
	if (m->id)
		_pbcM_ip_delete(m->id);
	free(m->def);
	_pbcM_sp_foreach(m->name, free);
	_pbcM_sp_delete(m->name);
	free(p);
}

void 
pbc_delete(struct pbc_env *p) {
	_pbcM_sp_foreach(p->enums, free_enum);
	_pbcM_sp_delete(p->enums);

	_pbcM_sp_foreach(p->msgs, free_msg);
	_pbcM_sp_delete(p->msgs);

	_pbcM_sp_foreach(p->files, free_stringpool);
	_pbcM_sp_delete(p->files);

	free(p);
}

struct _enum *
_pbcP_push_enum(struct pbc_env * p, const char *name, struct map_kv *table, int sz) {
	void * check = _pbcM_sp_query(p->enums, name);
	if (check)
		return NULL;
	struct _enum * v = (struct _enum *)malloc(sizeof(*v));
	v->key = name;
	v->id = _pbcM_ip_new(table,sz);
	v->name = _pbcM_si_new(table,sz);
	v->default_v->e.id = table[0].id;
	v->default_v->e.name = (const char *)table[0].pointer;

	_pbcM_sp_insert(p->enums, name , v);
	return v;
}

void 
_pbcP_push_message(struct pbc_env * p, const char *name, struct _field *f , pbc_array queue) {
	struct _message * m = (struct _message *)_pbcM_sp_query(p->msgs, name);
	if (m==NULL) {
		m = (struct _message *)malloc(sizeof(*m));
		m->def = NULL;
		m->key = name;
		m->id = NULL;
		m->name = _pbcM_sp_new(0 , NULL);
		m->env = p;
		_pbcM_sp_insert(p->msgs, name, m);
	}
	struct _field * field = (struct _field *)malloc(sizeof(*field));
	memcpy(field,f,sizeof(*f));
	_pbcM_sp_insert(m->name, field->name, field); 
	pbc_var atom;
	atom->m.buffer = field;
	if (f->type == PTYPE_MESSAGE || f->type == PTYPE_ENUM) {
		_pbcA_push(queue, atom);
	}
}

struct _iter {
	int count;
	struct map_kv * table;
};

static void
_count(void *p, void *ud) {
	struct _iter *iter = (struct _iter *)ud;
	iter->count ++;
}

static void
_set_table(void *p, void *ud) {
	struct _field * field = (struct _field *)p;
	struct _iter *iter = (struct _iter *)ud;
	iter->table[iter->count].id = field->id;
	iter->table[iter->count].pointer = field;
	++iter->count;
}

struct _message * 
_pbcP_init_message(struct pbc_env * p, const char *name) {
	struct _message * m = (struct _message *)_pbcM_sp_query(p->msgs, name);
	if (m == NULL) {
		m = (struct _message *)malloc(sizeof(*m));
		m->def = NULL;
		m->key = name;
		m->id = NULL;
		m->name = _pbcM_sp_new(0 , NULL);
		m->env = p;
		_pbcM_sp_insert(p->msgs, name, m);

		return m;
	}
	if (m->id) {
		// extend message, delete old id map.
		_pbcM_ip_delete(m->id);
	}
	struct _iter iter = { 0, NULL };
	_pbcM_sp_foreach_ud(m->name, _count, &iter);
	iter.table = (struct map_kv *)malloc(iter.count * sizeof(struct map_kv));
	iter.count = 0;
	_pbcM_sp_foreach_ud(m->name, _set_table, &iter);

	m->id = _pbcM_ip_new(iter.table , iter.count);

	free(iter.table);

	return m;
}

int 
_pbcP_message_default(struct _message * m, const char * name, pbc_var defv) {
	struct _field * f= (struct _field *)_pbcM_sp_query(m->name, name);
	if (f==NULL) {
		// invalid key
		defv->p[0] = NULL;
		defv->p[1] = NULL;
		return -1;
	}
	*defv = *(f->default_v);
	return f->type;
}

int 
_pbcP_type(struct _field * field, const char ** type) {
	if (field == NULL) {
		return 0;
	}
	int ret = 0;
	switch (field->type) {
	case PTYPE_DOUBLE:
	case PTYPE_FLOAT:
		ret = PBC_REAL;
		break;
	case PTYPE_INT64:
	case PTYPE_SINT64:  
		ret = PBC_INT64;
		break;
	case PTYPE_INT32:
	case PTYPE_SINT32:  
		ret = PBC_INT;
		break;
	case PTYPE_UINT32:
	case PTYPE_UINT64:
		ret = PBC_UINT;
		break;
	case PTYPE_FIXED32:
	case PTYPE_SFIXED32:
		ret = PBC_FIXED32;
		break;
	case PTYPE_SFIXED64:
	case PTYPE_FIXED64:
		ret = PBC_FIXED64;
		break;
	case PTYPE_BOOL:
		ret = PBC_BOOL;
		break;
	case PTYPE_STRING:
		ret = PBC_STRING;
		break;
	case PTYPE_BYTES:  
		ret = PBC_BYTES;
		break;
	case PTYPE_ENUM:
		ret = PBC_ENUM;
		if (type) {
			*type = field->type_name.e->key;
		}
		break;
	case PTYPE_MESSAGE:
		ret = PBC_MESSAGE;
		if (type) {
			*type = field->type_name.m->key;
		}
		break;
	default:
		return 0;
	}
	if (field->label == LABEL_REPEATED ||
		field->label == LABEL_PACKED) {
		ret |= PBC_REPEATED;
	}

	return ret;
}

int 
pbc_type(struct pbc_env * p, const char * type_name , const char * key , const char ** type) {
	struct _message *m = _pbcP_get_message(p, type_name);
	if (m==NULL) {
		return 0;
	}
	if (key == NULL) {
		return PBC_NOEXIST;
	}
	struct _field * field = (struct _field *)_pbcM_sp_query(m->name, key);
	return _pbcP_type(field, type);
}