1 /* $NetBSD: field_types.c,v 1.3 2001/06/13 10:45:58 wiz 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 <stdlib.h> 33 #include <stdarg.h> 34 #include "form.h" 35 #include "internals.h" 36 37 extern FIELD _formi_default_field; 38 39 /* function prototypes.... */ 40 static void 41 _formi_create_field_args(FIELDTYPE *type, char **type_args, 42 formi_type_link **link, va_list *args, int *error); 43 static FIELDTYPE * 44 _formi_create_fieldtype(void); 45 46 /* 47 * Process the arguments, if any, for the field type. 48 */ 49 static void 50 _formi_create_field_args(FIELDTYPE *type, char **type_args, 51 formi_type_link **link, va_list *args, int *error) 52 { 53 formi_type_link *l; 54 55 l = NULL; 56 if ((type != NULL) 57 && ((type->flags & _TYPE_HAS_ARGS) == _TYPE_HAS_ARGS)) { 58 if ((type->flags & _TYPE_IS_LINKED) == _TYPE_IS_LINKED) { 59 l = (formi_type_link *) 60 malloc(sizeof(formi_type_link)); 61 if (l != NULL) { 62 _formi_create_field_args(type->link->next, 63 type_args, 64 &type->link->next->link, 65 args, 66 error); 67 _formi_create_field_args(type->link->prev, 68 type_args, 69 &type->link->prev->link, 70 args, 71 error); 72 (*link) = l; 73 } 74 75 (*error)++; 76 } else { 77 if ((*type_args = (char *) type->make_args(args)) 78 == NULL) 79 (*error)++; 80 } 81 } 82 } 83 84 /* 85 * Allocate a new fieldtype structure, initialise it and return the 86 * struct to the caller. 87 */ 88 static FIELDTYPE * 89 _formi_create_fieldtype(void) 90 { 91 FIELDTYPE *new; 92 93 if ((new = (FIELDTYPE *) malloc(sizeof(FIELDTYPE))) == NULL) 94 return NULL; 95 96 new->flags = _TYPE_NO_FLAGS; 97 new->refcount = 0; 98 new->link = NULL; 99 new->make_args = NULL; 100 new->copy_args = NULL; 101 new->free_args = NULL; 102 new->field_check = NULL; 103 new->char_check = NULL; 104 new->next_choice = NULL; 105 new->prev_choice = NULL; 106 107 return new; 108 } 109 110 /* 111 * Set the field type of the field to be the one given. 112 */ 113 int 114 set_field_type(FIELD *fptr, FIELDTYPE *type, ...) 115 { 116 va_list args; 117 FIELD *field; 118 int error = 0; 119 120 va_start(args, type); 121 122 field = (fptr == NULL)? &_formi_default_field : fptr; 123 124 field->type = type; 125 _formi_create_field_args(type, &fptr->args, &type->link, &args, 126 &error); 127 va_end(args); 128 129 if (error) 130 return E_BAD_ARGUMENT; 131 132 return E_OK; 133 } 134 135 /* 136 * Return the field type associated with the given field 137 */ 138 FIELDTYPE * 139 field_type(FIELD *fptr) 140 { 141 FIELD *field; 142 143 field = (fptr == NULL)? &_formi_default_field : fptr; 144 145 return field->type; 146 } 147 148 149 /* 150 * Return the field arguments for the given field. 151 */ 152 char * 153 field_arg(FIELD *fptr) 154 { 155 FIELD *field; 156 157 field = (fptr == NULL)? &_formi_default_field : fptr; 158 159 return field->args; 160 } 161 162 /* 163 * Create a new field type. Caller must specify a field_check routine 164 * and char_check routine. 165 */ 166 FIELDTYPE * 167 new_fieldtype(int (*field_check)(FIELD *, char *), 168 int (*char_check)(int, char *)) 169 { 170 FIELDTYPE *new; 171 172 if ((field_check == NULL) || (char_check == NULL)) 173 return NULL; 174 175 if ((new = _formi_create_fieldtype()) != NULL) { 176 new->field_check = field_check; 177 new->char_check = char_check; 178 } 179 180 return new; 181 } 182 183 /* 184 * Free the storage used by the fieldtype. 185 */ 186 int 187 free_fieldtype(FIELDTYPE *fieldtype) 188 { 189 if (fieldtype == NULL) 190 return E_BAD_ARGUMENT; 191 192 if (fieldtype->refcount > 0) 193 return E_CONNECTED; 194 195 if ((fieldtype->flags & _TYPE_IS_BUILTIN) == _TYPE_IS_BUILTIN) 196 return E_BAD_ARGUMENT; /* don't delete builtin types! */ 197 198 if ((fieldtype->flags & _TYPE_IS_LINKED) == _TYPE_IS_LINKED) 199 { 200 fieldtype->link->next->refcount--; 201 fieldtype->link->prev->refcount--; 202 } 203 204 free(fieldtype); 205 206 return E_OK; 207 } 208 209 /* 210 * Set the field type arguments for the given field type. 211 */ 212 int 213 set_fieldtype_arg(FIELDTYPE *fieldtype, char * (*make_args)(va_list *), 214 char * (*copy_args)(char*), void (*free_args)(char *)) 215 { 216 if ((fieldtype == NULL) || (make_args == NULL) 217 || (copy_args == NULL) || (free_args == NULL)) 218 return E_BAD_ARGUMENT; 219 220 fieldtype->make_args = make_args; 221 fieldtype->copy_args = copy_args; 222 fieldtype->free_args = free_args; 223 224 return E_OK; 225 } 226 227 /* 228 * Set up the choice list functions for the given fieldtype. 229 */ 230 int 231 set_fieldtype_choice(FIELDTYPE *fieldtype, int (*next_choice)(FIELD *, char *), 232 int (*prev_choice)(FIELD *, char *)) 233 { 234 if ((fieldtype == NULL) || (next_choice == NULL) 235 || (prev_choice == NULL)) 236 return E_BAD_ARGUMENT; 237 238 fieldtype->next_choice = next_choice; 239 fieldtype->prev_choice = prev_choice; 240 241 return E_OK; 242 } 243 244 /* 245 * Link the two given types to produce a new type, return this new type. 246 */ 247 FIELDTYPE * 248 link_fieldtype(FIELDTYPE *type1, FIELDTYPE *type2) 249 { 250 FIELDTYPE *new; 251 252 if ((type1 == NULL) || (type2 == NULL)) 253 return NULL; 254 255 if ((new = _formi_create_fieldtype()) == NULL) 256 return NULL; 257 258 new->flags = _TYPE_IS_LINKED; 259 new->flags |= ((type1->flags & _TYPE_HAS_ARGS) 260 | (type2->flags & _TYPE_HAS_ARGS)); 261 if ((new->link = (_FORMI_TYPE_LINK*) malloc(sizeof(_FORMI_TYPE_LINK))) == NULL) 262 return NULL; 263 264 new->link->prev = type1; 265 new->link->next = type2; 266 type1->refcount++; 267 type2->refcount++; 268 269 return new; 270 } 271