1/*	$NetBSD: field_types.c,v 1.6 2003/03/09 00:57:17 lukem 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.6 2003/03/09 00:57:17 lukem Exp $");
34
35#include <stdlib.h>
36#include <stdarg.h>
37#include "form.h"
38#include "internals.h"
39
40extern FIELD _formi_default_field;
41
42/* function prototypes.... */
43static void
44_formi_create_field_args(FIELDTYPE *type, char **type_args,
45			 formi_type_link **link, va_list *args, int *error);
46static FIELDTYPE *
47_formi_create_fieldtype(void);
48
49/*
50 * Process the arguments, if any, for the field type.
51 */
52static 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 */
90static 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 */
115int
116set_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 */
140FIELDTYPE *
141field_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 */
154char *
155field_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 */
168FIELDTYPE *
169new_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 */
188int
189free_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 */
214int
215set_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 */
232int
233set_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 */
249FIELDTYPE *
250link_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