xref: /netbsd/lib/libform/field_types.c (revision 51566e9c)
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
_formi_create_field_args(FIELDTYPE * type,char ** type_args,formi_type_link ** link,va_list * args,int * error)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 *
_formi_create_fieldtype(void)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
set_field_type(FIELD * fptr,FIELDTYPE * type,...)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 *
field_type(FIELD * fptr)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 *
field_arg(FIELD * fptr)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 *
new_fieldtype(int (* field_check)(FIELD *,char *),int (* char_check)(int,char *))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
free_fieldtype(FIELDTYPE * fieldtype)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
set_fieldtype_arg(FIELDTYPE * fieldtype,char * (* make_args)(va_list *),char * (* copy_args)(char *),void (* free_args)(char *))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
set_fieldtype_choice(FIELDTYPE * fieldtype,int (* next_choice)(FIELD *,char *),int (* prev_choice)(FIELD *,char *))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 *
link_fieldtype(FIELDTYPE * type1,FIELDTYPE * type2)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