#include <sys/cdefs.h>
__RCSID("$NetBSD: field_types.c,v 1.7 2006/03/19 20:02:27 christos Exp $");
#include <stdlib.h>
#include <stdarg.h>
#include "form.h"
#include "internals.h"
extern FIELD _formi_default_field;
static void
_formi_create_field_args(FIELDTYPE *type, char **type_args,
formi_type_link **link, va_list *args, int *error);
static FIELDTYPE *
_formi_create_fieldtype(void);
static void
_formi_create_field_args(FIELDTYPE *type, char **type_args,
formi_type_link **link, va_list *args, int *error)
{
formi_type_link *l;
l = NULL;
if ((type != NULL)
&& ((type->flags & _TYPE_HAS_ARGS) == _TYPE_HAS_ARGS)) {
if ((type->flags & _TYPE_IS_LINKED) == _TYPE_IS_LINKED) {
l = malloc(sizeof(*l));
if (l != NULL) {
_formi_create_field_args(type->link->next,
type_args,
&type->link->next->link,
args,
error);
_formi_create_field_args(type->link->prev,
type_args,
&type->link->prev->link,
args,
error);
(*link) = l;
}
(*error)++;
} else {
if ((*type_args = (char *) type->make_args(args))
== NULL)
(*error)++;
}
}
}
static FIELDTYPE *
_formi_create_fieldtype(void)
{
FIELDTYPE *new;
if ((new = malloc(sizeof(*new))) == NULL)
return NULL;
new->flags = _TYPE_NO_FLAGS;
new->refcount = 0;
new->link = NULL;
new->make_args = NULL;
new->copy_args = NULL;
new->free_args = NULL;
new->field_check = NULL;
new->char_check = NULL;
new->next_choice = NULL;
new->prev_choice = NULL;
return new;
}
int
set_field_type(FIELD *fptr, FIELDTYPE *type, ...)
{
va_list args;
FIELD *field;
int error = 0;
va_start(args, type);
field = (fptr == NULL)? &_formi_default_field : fptr;
field->type = type;
_formi_create_field_args(type, &field->args, &type->link, &args,
&error);
va_end(args);
if (error)
return E_BAD_ARGUMENT;
return E_OK;
}
FIELDTYPE *
field_type(FIELD *fptr)
{
FIELD *field;
field = (fptr == NULL)? &_formi_default_field : fptr;
return field->type;
}
char *
field_arg(FIELD *fptr)
{
FIELD *field;
field = (fptr == NULL)? &_formi_default_field : fptr;
return field->args;
}
FIELDTYPE *
new_fieldtype(int (*field_check)(FIELD *, char *),
int (*char_check)(int, char *))
{
FIELDTYPE *new;
if ((field_check == NULL) && (char_check == NULL))
return NULL;
if ((new = _formi_create_fieldtype()) != NULL) {
new->field_check = field_check;
new->char_check = char_check;
}
return new;
}
int
free_fieldtype(FIELDTYPE *fieldtype)
{
if (fieldtype == NULL)
return E_BAD_ARGUMENT;
if (fieldtype->refcount > 0)
return E_CONNECTED;
if ((fieldtype->flags & _TYPE_IS_BUILTIN) == _TYPE_IS_BUILTIN)
return E_BAD_ARGUMENT;
if ((fieldtype->flags & _TYPE_IS_LINKED) == _TYPE_IS_LINKED)
{
fieldtype->link->next->refcount--;
fieldtype->link->prev->refcount--;
}
free(fieldtype);
return E_OK;
}
int
set_fieldtype_arg(FIELDTYPE *fieldtype, char * (*make_args)(va_list *),
char * (*copy_args)(char*), void (*free_args)(char *))
{
if ((fieldtype == NULL) || (make_args == NULL)
|| (copy_args == NULL) || (free_args == NULL))
return E_BAD_ARGUMENT;
fieldtype->make_args = make_args;
fieldtype->copy_args = copy_args;
fieldtype->free_args = free_args;
return E_OK;
}
int
set_fieldtype_choice(FIELDTYPE *fieldtype, int (*next_choice)(FIELD *, char *),
int (*prev_choice)(FIELD *, char *))
{
if ((fieldtype == NULL) || (next_choice == NULL)
|| (prev_choice == NULL))
return E_BAD_ARGUMENT;
fieldtype->next_choice = next_choice;
fieldtype->prev_choice = prev_choice;
return E_OK;
}
FIELDTYPE *
link_fieldtype(FIELDTYPE *type1, FIELDTYPE *type2)
{
FIELDTYPE *new;
if ((type1 == NULL) || (type2 == NULL))
return NULL;
if ((new = _formi_create_fieldtype()) == NULL)
return NULL;
new->flags = _TYPE_IS_LINKED;
new->flags |= ((type1->flags & _TYPE_HAS_ARGS)
| (type2->flags & _TYPE_HAS_ARGS));
if ((new->link = malloc(sizeof(*new->link))) == NULL) {
free(new);
return NULL;
}
new->link->prev = type1;
new->link->next = type2;
type1->refcount++;
type2->refcount++;
return new;
}