/* $NetBSD: field_types.c,v 1.7 2006/03/19 20:02:27 christos Exp $ */ /*- * Copyright (c) 1998-1999 Brett Lymn * (blymn@baea.com.au, brett_lymn@yahoo.com.au) * All rights reserved. * * This code has been donated to The NetBSD Foundation by the Author. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * */ #include __RCSID("$NetBSD: field_types.c,v 1.7 2006/03/19 20:02:27 christos Exp $"); #include #include #include "form.h" #include "internals.h" extern FIELD _formi_default_field; /* function prototypes.... */ 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); /* * Process the arguments, if any, for the field type. */ 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)++; } } } /* * Allocate a new fieldtype structure, initialise it and return the * struct to the caller. */ 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; } /* * Set the field type of the field to be the one given. */ 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; } /* * Return the field type associated with the given field */ FIELDTYPE * field_type(FIELD *fptr) { FIELD *field; field = (fptr == NULL)? &_formi_default_field : fptr; return field->type; } /* * Return the field arguments for the given field. */ char * field_arg(FIELD *fptr) { FIELD *field; field = (fptr == NULL)? &_formi_default_field : fptr; return field->args; } /* * Create a new field type. Caller must specify a field_check routine * and char_check routine. */ 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; } /* * Free the storage used by the fieldtype. */ 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; /* don't delete builtin types! */ if ((fieldtype->flags & _TYPE_IS_LINKED) == _TYPE_IS_LINKED) { fieldtype->link->next->refcount--; fieldtype->link->prev->refcount--; } free(fieldtype); return E_OK; } /* * Set the field type arguments for the given field type. */ 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; } /* * Set up the choice list functions for the given fieldtype. */ 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; } /* * Link the two given types to produce a new type, return this new type. */ 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; }