Home | History | Annotate | Line # | Download | only in libform
      1 /*	$NetBSD: field_types.c,v 1.7 2006/03/19 20:02:27 christos Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1998-1999 Brett Lymn
      5  *                         (blymn (at) baea.com.au, brett_lymn (at) yahoo.com.au)
      6  * All rights reserved.
      7  *
      8  * This code has been donated to The NetBSD Foundation by the Author.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. The name of the author may not be used to endorse or promote products
     16  *    derived from this software without specific prior written permission
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  *
     29  *
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 __RCSID("$NetBSD: field_types.c,v 1.7 2006/03/19 20:02:27 christos Exp $");
     34 
     35 #include <stdlib.h>
     36 #include <stdarg.h>
     37 #include "form.h"
     38 #include "internals.h"
     39 
     40 extern FIELD _formi_default_field;
     41 
     42 /* function prototypes.... */
     43 static void
     44 _formi_create_field_args(FIELDTYPE *type, char **type_args,
     45 			 formi_type_link **link, va_list *args, int *error);
     46 static FIELDTYPE *
     47 _formi_create_fieldtype(void);
     48 
     49 /*
     50  * Process the arguments, if any, for the field type.
     51  */
     52 static void
     53 _formi_create_field_args(FIELDTYPE *type, char **type_args,
     54 			 formi_type_link **link, va_list *args, int *error)
     55 {
     56 	formi_type_link *l;
     57 
     58 	l = NULL;
     59 	if ((type != NULL)
     60 	    && ((type->flags & _TYPE_HAS_ARGS) == _TYPE_HAS_ARGS)) {
     61 		if ((type->flags & _TYPE_IS_LINKED) == _TYPE_IS_LINKED) {
     62 			l = malloc(sizeof(*l));
     63 			if (l != NULL) {
     64 				_formi_create_field_args(type->link->next,
     65 							 type_args,
     66 							 &type->link->next->link,
     67 							 args,
     68 							 error);
     69 				_formi_create_field_args(type->link->prev,
     70 							 type_args,
     71 							 &type->link->prev->link,
     72 							 args,
     73 							 error);
     74 				(*link) = l;
     75 			}
     76 
     77 			(*error)++;
     78 		} else {
     79 			if ((*type_args = (char *) type->make_args(args))
     80 			    == NULL)
     81 				(*error)++;
     82 		}
     83 	}
     84 }
     85 
     86 /*
     87  * Allocate a new fieldtype structure, initialise it and return the
     88  * struct to the caller.
     89  */
     90 static FIELDTYPE *
     91 _formi_create_fieldtype(void)
     92 {
     93 	FIELDTYPE *new;
     94 
     95 	if ((new = malloc(sizeof(*new))) == NULL)
     96 		return NULL;
     97 
     98 	new->flags = _TYPE_NO_FLAGS;
     99 	new->refcount = 0;
    100 	new->link = NULL;
    101 	new->make_args = NULL;
    102 	new->copy_args = NULL;
    103 	new->free_args = NULL;
    104 	new->field_check = NULL;
    105 	new->char_check = NULL;
    106 	new->next_choice = NULL;
    107 	new->prev_choice = NULL;
    108 
    109 	return new;
    110 }
    111 
    112 /*
    113  * Set the field type of the field to be the one given.
    114  */
    115 int
    116 set_field_type(FIELD *fptr, FIELDTYPE *type, ...)
    117 {
    118 	va_list args;
    119 	FIELD *field;
    120 	int error = 0;
    121 
    122 	va_start(args, type);
    123 
    124 	field = (fptr == NULL)? &_formi_default_field : fptr;
    125 
    126 	field->type = type;
    127 	_formi_create_field_args(type, &field->args, &type->link, &args,
    128 				 &error);
    129 	va_end(args);
    130 
    131 	if (error)
    132 		return E_BAD_ARGUMENT;
    133 
    134 	return E_OK;
    135 }
    136 
    137 /*
    138  * Return the field type associated with the given field
    139  */
    140 FIELDTYPE *
    141 field_type(FIELD *fptr)
    142 {
    143 	FIELD *field;
    144 
    145 	field = (fptr == NULL)? &_formi_default_field : fptr;
    146 
    147 	return field->type;
    148 }
    149 
    150 
    151 /*
    152  * Return the field arguments for the given field.
    153  */
    154 char *
    155 field_arg(FIELD *fptr)
    156 {
    157 	FIELD *field;
    158 
    159 	field = (fptr == NULL)? &_formi_default_field : fptr;
    160 
    161 	return field->args;
    162 }
    163 
    164 /*
    165  * Create a new field type.  Caller must specify a field_check routine
    166  * and char_check routine.
    167  */
    168 FIELDTYPE *
    169 new_fieldtype(int (*field_check)(FIELD *, char *),
    170 	      int (*char_check)(int, char *))
    171 {
    172 	FIELDTYPE *new;
    173 
    174 	if ((field_check == NULL) && (char_check == NULL))
    175 		return NULL;
    176 
    177 	if ((new = _formi_create_fieldtype()) != NULL) {
    178 		new->field_check = field_check;
    179 		new->char_check = char_check;
    180 	}
    181 
    182 	return new;
    183 }
    184 
    185 /*
    186  * Free the storage used by the fieldtype.
    187  */
    188 int
    189 free_fieldtype(FIELDTYPE *fieldtype)
    190 {
    191 	if (fieldtype == NULL)
    192 		return E_BAD_ARGUMENT;
    193 
    194 	if (fieldtype->refcount > 0)
    195 		return E_CONNECTED;
    196 
    197 	if ((fieldtype->flags & _TYPE_IS_BUILTIN) == _TYPE_IS_BUILTIN)
    198 		return E_BAD_ARGUMENT; /* don't delete builtin types! */
    199 
    200 	if ((fieldtype->flags & _TYPE_IS_LINKED) == _TYPE_IS_LINKED)
    201 	{
    202 		fieldtype->link->next->refcount--;
    203 		fieldtype->link->prev->refcount--;
    204 	}
    205 
    206 	free(fieldtype);
    207 
    208 	return E_OK;
    209 }
    210 
    211 /*
    212  * Set the field type arguments for the given field type.
    213  */
    214 int
    215 set_fieldtype_arg(FIELDTYPE *fieldtype, char * (*make_args)(va_list *),
    216 		  char * (*copy_args)(char*), void (*free_args)(char *))
    217 {
    218 	if ((fieldtype == NULL) || (make_args == NULL)
    219 	    || (copy_args == NULL) || (free_args == NULL))
    220 		return E_BAD_ARGUMENT;
    221 
    222 	fieldtype->make_args = make_args;
    223 	fieldtype->copy_args = copy_args;
    224 	fieldtype->free_args = free_args;
    225 
    226 	return E_OK;
    227 }
    228 
    229 /*
    230  * Set up the choice list functions for the given fieldtype.
    231  */
    232 int
    233 set_fieldtype_choice(FIELDTYPE *fieldtype, int (*next_choice)(FIELD *, char *),
    234 		     int (*prev_choice)(FIELD *, char *))
    235 {
    236 	if ((fieldtype == NULL) || (next_choice == NULL)
    237 	    || (prev_choice == NULL))
    238 		return E_BAD_ARGUMENT;
    239 
    240 	fieldtype->next_choice = next_choice;
    241 	fieldtype->prev_choice = prev_choice;
    242 
    243 	return E_OK;
    244 }
    245 
    246 /*
    247  * Link the two given types to produce a new type, return this new type.
    248  */
    249 FIELDTYPE *
    250 link_fieldtype(FIELDTYPE *type1, FIELDTYPE *type2)
    251 {
    252 	FIELDTYPE *new;
    253 
    254 	if ((type1 == NULL) || (type2 == NULL))
    255 		return NULL;
    256 
    257 	if ((new = _formi_create_fieldtype()) == NULL)
    258 		return NULL;
    259 
    260 	new->flags = _TYPE_IS_LINKED;
    261 	new->flags |= ((type1->flags & _TYPE_HAS_ARGS)
    262 		       | (type2->flags & _TYPE_HAS_ARGS));
    263 	if ((new->link = malloc(sizeof(*new->link))) == NULL) {
    264 		free(new);
    265 		return NULL;
    266 	}
    267 
    268 	new->link->prev = type1;
    269 	new->link->next = type2;
    270 	type1->refcount++;
    271 	type2->refcount++;
    272 
    273 	return new;
    274 }
    275