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@baea.com.au, brett_lymn@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