xref: /dragonfly/usr.sbin/installer/libdfui/form.c (revision 9348a738)
1 /*
2  * Copyright (c)2004 Cat's Eye Technologies.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  *   Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  *
11  *   Redistributions in binary form must reproduce the above copyright
12  *   notice, this list of conditions and the following disclaimer in
13  *   the documentation and/or other materials provided with the
14  *   distribution.
15  *
16  *   Neither the name of Cat's Eye Technologies nor the names of its
17  *   contributors may be used to endorse or promote products derived
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31  * OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 /*
35  * form.c
36  * $Id: form.c,v 1.18 2005/03/04 21:26:20 cpressey Exp $
37  */
38 
39 #include <stdarg.h>
40 #include <stdlib.h>
41 #include <string.h>
42 
43 #include <libaura/mem.h>
44 
45 #define	NEEDS_DFUI_STRUCTURE_DEFINITIONS
46 #include "dfui.h"
47 #undef	NEEDS_DFUI_STRUCTURE_DEFINITIONS
48 #include "dump.h"
49 
50 /*** INFOS ***/
51 
52 struct dfui_info *
53 dfui_info_new(const char *name, const char *short_desc, const char *long_desc)
54 {
55 	struct dfui_info *i;
56 
57 	AURA_MALLOC(i, dfui_info);
58 	i->name = aura_strdup(name);
59 	i->short_desc = aura_strdup(short_desc);
60 	i->long_desc = aura_strdup(long_desc);
61 
62 	return(i);
63 }
64 
65 void
66 dfui_info_free(struct dfui_info *i)
67 {
68 	free(i->name);
69 	free(i->short_desc);
70 	free(i->long_desc);
71 	AURA_FREE(i, dfui_info);
72 }
73 
74 const char *
75 dfui_info_get_name(const struct dfui_info *i)
76 {
77 	if (i == NULL)
78 		return("");
79 	return(i->name);
80 }
81 
82 const char *
83 dfui_info_get_short_desc(const struct dfui_info *i)
84 {
85 	if (i == NULL)
86 		return("");
87 	return(i->short_desc);
88 }
89 
90 const char *
91 dfui_info_get_long_desc(const struct dfui_info *i)
92 {
93 	if (i == NULL)
94 		return("");
95 	return(i->long_desc);
96 }
97 
98 void
99 dfui_info_set_name(struct dfui_info *i, const char *name)
100 {
101 	if (i == NULL)
102 		return;
103 	if (i->name != NULL)
104 		free(i->name);
105 	i->name = aura_strdup(name);
106 }
107 
108 void
109 dfui_info_set_short_desc(struct dfui_info *i, const char *short_desc)
110 {
111 	if (i == NULL)
112 		return;
113 	if (i->short_desc != NULL)
114 		free(i->short_desc);
115 	i->short_desc = aura_strdup(short_desc);
116 }
117 
118 void
119 dfui_info_set_long_desc(struct dfui_info *i, const char *long_desc)
120 {
121 	if (i == NULL)
122 		return;
123 	if (i->long_desc != NULL)
124 		free(i->long_desc);
125 	i->long_desc = aura_strdup(long_desc);
126 }
127 
128 /*** PROPERTIES ***/
129 
130 struct dfui_property *
131 dfui_property_new(const char *name, const char *value)
132 {
133 	struct dfui_property *p;
134 
135 	AURA_MALLOC(p, dfui_property);
136 	p->name = aura_strdup(name);
137 	p->value = aura_strdup(value);
138 
139 	return(p);
140 }
141 
142 void
143 dfui_property_free(struct dfui_property *p)
144 {
145 	if (p == NULL)
146 		return;
147 	free(p->name);
148 	free(p->value);
149 	AURA_FREE(p, dfui_property);
150 }
151 
152 void
153 dfui_properties_free(struct dfui_property *head)
154 {
155 	struct dfui_property *p;
156 
157 	for (p = head; p != NULL; ) {
158 		head = p->next;
159 		dfui_property_free(p);
160 		p = head;
161 	}
162 }
163 
164 struct dfui_property *
165 dfui_property_find(struct dfui_property *head, const char *name)
166 {
167 	struct dfui_property *p;
168 
169 	for (p = head; p != NULL; p = p->next) {
170 		if (strcmp(name, p->name) == 0)
171 			return(p);
172 	}
173 
174 	return(NULL);
175 }
176 
177 const char *
178 dfui_property_get(struct dfui_property *head, const char *name)
179 {
180 	struct dfui_property *p;
181 
182 	if ((p = dfui_property_find(head, name)) != NULL)
183 		return(p->value);
184 	return("");
185 }
186 
187 struct dfui_property *
188 dfui_property_set(struct dfui_property **head, const char *name, const char *value)
189 {
190 	struct dfui_property *p;
191 
192 	if (head == NULL)
193 		return(NULL);
194 
195 	if ((p = dfui_property_find(*head, name)) != NULL) {
196 		free(p->value);
197 		p->value = aura_strdup(value);
198 		return(p);
199 	}
200 
201 	p = dfui_property_new(name, value);
202 	p->next = *head;
203 	*head = p;
204 
205 	return(p);
206 }
207 
208 const char *
209 dfui_property_get_name(const struct dfui_property *p)
210 {
211 	return(p->name);
212 }
213 
214 const char *
215 dfui_property_get_value(const struct dfui_property *p)
216 {
217 	return(p->value);
218 }
219 
220 /*** FIELDS ***/
221 
222 struct dfui_field *
223 dfui_field_new(const char *id, struct dfui_info *info)
224 {
225 	struct dfui_field *fi;
226 
227 	AURA_MALLOC(fi, dfui_field);
228 	fi->id = aura_strdup(id);
229 	fi->info = info;
230 	fi->option_head = NULL;
231 	fi->property_head = NULL;
232 	fi->next = NULL;
233 
234 	dfui_field_property_set(fi, "editable", "true");
235 
236 	return(fi);
237 }
238 
239 void
240 dfui_field_free(struct dfui_field *fi)
241 {
242 	free(fi->id);
243 	dfui_info_free(fi->info);
244 	dfui_options_free(fi->option_head);
245 	dfui_properties_free(fi->property_head);
246 	AURA_FREE(fi, dfui_field);
247 }
248 
249 void
250 dfui_fields_free(struct dfui_field *head)
251 {
252 	struct dfui_field *fi;
253 
254 	fi = head;
255 	while (fi != NULL) {
256 		head = fi->next;
257 		dfui_field_free(fi);
258 		fi = head;
259 	}
260 }
261 
262 struct dfui_field *
263 dfui_field_get_next(const struct dfui_field *fi)
264 {
265 	if (fi == NULL)
266 		return(NULL);
267 	return(fi->next);
268 }
269 
270 const char *
271 dfui_field_get_id(const struct dfui_field *fi)
272 {
273 	if (fi == NULL)
274 		return(NULL);
275 	return(fi->id);
276 }
277 
278 struct dfui_info *
279 dfui_field_get_info(const struct dfui_field *fi)
280 {
281 	if (fi == NULL)
282 		return(NULL);
283 	return(fi->info);
284 }
285 
286 struct dfui_option *
287 dfui_field_option_add(struct dfui_field *fi, const char *value)
288 {
289 	struct dfui_option *o;
290 
291 	if (fi == NULL)
292 		return(NULL);
293 	o = dfui_option_new(value);
294 	o->next = fi->option_head;
295 	fi->option_head = o;
296 
297 	return(o);
298 }
299 
300 struct dfui_option *
301 dfui_field_option_get_first(const struct dfui_field *fi)
302 {
303 	if (fi == NULL)
304 		return(NULL);
305 	return(fi->option_head);
306 }
307 
308 struct dfui_property *
309 dfui_field_property_set(struct dfui_field *fi, const char *name, const char *value)
310 {
311 	return(dfui_property_set(&fi->property_head, name, value));
312 }
313 
314 const char *
315 dfui_field_property_get(const struct dfui_field *fi, const char *name)
316 {
317 	return(dfui_property_get(fi->property_head, name));
318 }
319 
320 int
321 dfui_field_property_is(const struct dfui_field *fi, const char *name, const char *value)
322 {
323 	struct dfui_property *h;
324 
325 	if (fi == NULL)
326 		return(0);
327 	if ((h = dfui_property_find(fi->property_head, name)) == NULL)
328 		return(0);
329 	return(!strcmp(h->value, value));
330 }
331 
332 /*** OPTIONS ***/
333 
334 struct dfui_option *
335 dfui_option_new(const char *value)
336 {
337 	struct dfui_option *o;
338 
339 	AURA_MALLOC(o, dfui_option);
340 	o->value = aura_strdup(value);
341 	o->next = NULL;
342 
343 	return(o);
344 }
345 
346 void
347 dfui_option_free(struct dfui_option *o)
348 {
349 	if (o == NULL)
350 		return;
351 	free(o->value);
352 	AURA_FREE(o, dfui_option);
353 }
354 
355 void
356 dfui_options_free(struct dfui_option *head)
357 {
358 	struct dfui_option *o;
359 
360 	o = head;
361 	while (o != NULL) {
362 		head = o->next;
363 		dfui_option_free(o);
364 		o = head;
365 	}
366 }
367 
368 struct dfui_option *
369 dfui_option_get_next(const struct dfui_option *o)
370 {
371 	if (o == NULL)
372 		return(NULL);
373 	return(o->next);
374 }
375 
376 const char *
377 dfui_option_get_value(const struct dfui_option *o)
378 {
379 	if (o == NULL)
380 		return("");
381 	return(o->value);
382 }
383 
384 /*** ACTIONS ***/
385 
386 struct dfui_action *
387 dfui_action_new(const char *id, struct dfui_info *info)
388 {
389 	struct dfui_action *a;
390 
391 	AURA_MALLOC(a, dfui_action);
392 	a->id = aura_strdup(id);
393 	a->info = info;
394 	a->next = NULL;
395 	a->property_head = NULL;
396 
397 	return(a);
398 }
399 
400 void
401 dfui_action_free(struct dfui_action *a)
402 {
403 	free(a->id);
404 	dfui_info_free(a->info);
405 	dfui_properties_free(a->property_head);
406 	AURA_FREE(a, dfui_action);
407 }
408 
409 void
410 dfui_actions_free(struct dfui_action *head)
411 {
412 	struct dfui_action *a;
413 
414 	a = head;
415 	while (a != NULL) {
416 		head = a->next;
417 		dfui_action_free(a);
418 		a = head;
419 	}
420 }
421 
422 struct dfui_action *
423 dfui_action_get_next(const struct dfui_action *a)
424 {
425 	if (a == NULL)
426 		return(NULL);
427 	return(a->next);
428 }
429 
430 const char *
431 dfui_action_get_id(const struct dfui_action *a)
432 {
433 	if (a == NULL)
434 		return(NULL);
435 	return(a->id);
436 }
437 
438 struct dfui_info *
439 dfui_action_get_info(const struct dfui_action *a)
440 {
441 	if (a == NULL)
442 		return(NULL);
443 	return(a->info);
444 }
445 
446 struct dfui_property *
447 dfui_action_property_set(struct dfui_action *a, const char *name, const char *value)
448 {
449 	return(dfui_property_set(&a->property_head, name, value));
450 }
451 
452 const char *
453 dfui_action_property_get(const struct dfui_action *a, const char *name)
454 {
455 	return(dfui_property_get(a->property_head, name));
456 }
457 
458 int
459 dfui_action_property_is(const struct dfui_action *a, const char *name, const char *value)
460 {
461 	struct dfui_property *h;
462 
463 	if (a == NULL)
464 		return(0);
465 	if ((h = dfui_property_find(a->property_head, name)) == NULL)
466 		return(0);
467 	return(!strcmp(h->value, value));
468 }
469 
470 /*** FORMS ***/
471 
472 struct dfui_form *
473 dfui_form_new(const char *id, struct dfui_info *info)
474 {
475 	struct dfui_form *f;
476 
477 	AURA_MALLOC(f, dfui_form);
478 	f->id = aura_strdup(id);
479 	f->info = info;
480 	f->multiple = 0;
481 	f->extensible = 0;
482 	f->field_head = NULL;
483 	f->action_head = NULL;
484 	f->dataset_head = NULL;
485 	f->property_head = NULL;
486 
487 	return(f);
488 };
489 
490 /*
491  * Convenience function for creating a form.
492  * This function takes a list of any number of strings.
493  * This list MUST be terminated by a NULL pointer.
494  * The first four strings are the id, name, short description, and long
495  * description of the form.
496  * Each subsequent string determines what the strings following it represent:
497  *    "f": create a field (id, name, short desc, long desc).
498  *    "o": add an option to the last field (value).
499  *    "a": create an action (id, name, short desc, long desc).
500  *    "p": add a property to the last object (name, value).
501  */
502 struct dfui_form *
503 dfui_form_create(const char *id, const char *name,
504 		 const char *short_desc, const char *long_desc, ...)
505 {
506 #define DFUI_FORM_CREATE_FORM	0
507 #define DFUI_FORM_CREATE_FIELD	1
508 #define DFUI_FORM_CREATE_ACTION	2
509 
510 	struct dfui_form *f;
511 	struct dfui_info *i;
512 	va_list args;
513 	int state = DFUI_FORM_CREATE_FORM;
514 	char *arg;
515 	void *object = NULL;
516 	const char *a_id;
517 	char *a_name, *a_short_desc, *a_long_desc;
518 
519 	i = dfui_info_new(name, short_desc, long_desc);
520 	f = dfui_form_new(id, i);
521 
522 	va_start(args, long_desc);
523 	while ((arg = va_arg(args, char *)) != NULL) {
524 		switch (arg[0]) {
525 		case 'f':
526 			a_id = va_arg(args, const char *);
527 			a_name = va_arg(args, char *);
528 			a_short_desc = va_arg(args, char *);
529 			a_long_desc = va_arg(args, char *);
530 			i = dfui_info_new(a_name, a_short_desc, a_long_desc);
531 			object = (void *)dfui_form_field_add(f, a_id, i);
532 			state = DFUI_FORM_CREATE_FIELD;
533 			break;
534 		case 'a':
535 			a_id = va_arg(args, const char *);
536 			a_name = va_arg(args, char *);
537 			a_short_desc = va_arg(args, char *);
538 			a_long_desc = va_arg(args, char *);
539 			i = dfui_info_new(a_name, a_short_desc, a_long_desc);
540 			object = (void *)dfui_form_action_add(f, a_id, i);
541 			state = DFUI_FORM_CREATE_ACTION;
542 			break;
543 		case 'o':
544 			a_name = va_arg(args, char *);
545 			if (state == DFUI_FORM_CREATE_FIELD) {
546 				dfui_field_option_add(object, a_name);
547 			} else {
548 				dfui_debug("form_create: can't add option to non-field\n");
549 			}
550 			break;
551 		case 'h':
552 		case 'p':
553 			a_id = va_arg(args, char *);
554 			a_short_desc = va_arg(args, char *);
555 
556 			if (state == DFUI_FORM_CREATE_FIELD) {
557 				dfui_field_property_set(object, a_id, a_short_desc);
558 			} else if (state == DFUI_FORM_CREATE_ACTION) {
559 				dfui_action_property_set(object, a_id, a_short_desc);
560 			} else if (state == DFUI_FORM_CREATE_FORM) {
561 				dfui_form_property_set(f, a_id, a_short_desc);
562 			} else {
563 				dfui_debug("form_create: can't add property in this state\n");
564 			}
565 			break;
566 
567 		default:
568 			dfui_debug("form_create: unknown option `%c'\n", arg[0]);
569 			break;
570 		}
571 	}
572 
573 	va_end(args);
574 	return(f);
575 }
576 
577 void
578 dfui_form_free(struct dfui_form *f)
579 {
580 	free(f->id);
581 	dfui_info_free(f->info);
582 	dfui_fields_free(f->field_head);
583 	dfui_actions_free(f->action_head);
584 	dfui_datasets_free(f->dataset_head);
585 	dfui_properties_free(f->property_head);
586 	AURA_FREE(f, dfui_form);
587 }
588 
589 struct dfui_field *
590 dfui_form_field_add(struct dfui_form *f, const char *id, struct dfui_info *info)
591 {
592 	struct dfui_field *fi;
593 
594 	if (f == NULL)
595 		return(NULL);
596 	fi = dfui_field_new(id, info);
597 	fi->next = f->field_head;
598 	f->field_head = fi;
599 
600 	return(fi);
601 }
602 
603 struct dfui_field *
604 dfui_form_field_attach(struct dfui_form *f, struct dfui_field *fi)
605 {
606 	if (f == NULL)
607 		return(NULL);
608 	fi->next = f->field_head;
609 	f->field_head = fi;
610 
611 	return(fi);
612 }
613 
614 struct dfui_action *
615 dfui_form_action_add(struct dfui_form *f, const char *id, struct dfui_info *info)
616 {
617 	struct dfui_action *a;
618 
619 	if (f == NULL)
620 		return(NULL);
621 	a = dfui_action_new(id, info);
622 	a->next = f->action_head;
623 	f->action_head = a;
624 
625 	return(a);
626 }
627 
628 struct dfui_action *
629 dfui_form_action_attach(struct dfui_form *f, struct dfui_action *a)
630 {
631 	if (f == NULL)
632 		return(NULL);
633 	a->next = f->action_head;
634 	f->action_head = a;
635 
636 	return(a);
637 }
638 
639 void
640 dfui_form_dataset_add(struct dfui_form *f, struct dfui_dataset *ds)
641 {
642 	if (f == NULL || ds == NULL)
643 		return;
644 	ds->next = f->dataset_head;
645 	f->dataset_head = ds;
646 }
647 
648 struct dfui_dataset *
649 dfui_form_dataset_get_first(const struct dfui_form *f)
650 {
651 	if (f == NULL)
652 		return(NULL);
653 	return(f->dataset_head);
654 }
655 
656 int
657 dfui_form_dataset_count(const struct dfui_form *f)
658 {
659 	int n = 0;
660 	struct dfui_dataset *ds;
661 
662 	if (f == NULL)
663 		return(0);
664 
665 	ds = f->dataset_head;
666 	while (ds != NULL) {
667 		n++;
668 		ds = ds->next;
669 	}
670 
671 	return(n);
672 }
673 
674 void
675 dfui_form_datasets_free(struct dfui_form *f)
676 {
677 	if (f == NULL)
678 		return;
679 	dfui_datasets_free(f->dataset_head);
680 	f->dataset_head = NULL;
681 }
682 
683 struct dfui_field *
684 dfui_form_field_find(const struct dfui_form *f, const char *id)
685 {
686 	struct dfui_field *fi;
687 
688 	if (f == NULL)
689 		return(NULL);
690 
691 	fi = f->field_head;
692 	while (fi != NULL) {
693 		if (!strcmp(id, fi->id))
694 			return(fi);
695 		fi = fi->next;
696 	}
697 
698 	return(NULL);
699 }
700 
701 struct dfui_field *
702 dfui_form_field_get_first(const struct dfui_form *f)
703 {
704 	if (f == NULL)
705 		return(NULL);
706 	return(f->field_head);
707 }
708 
709 int
710 dfui_form_field_count(const struct dfui_form *f)
711 {
712 	int n = 0;
713 	struct dfui_field *fi;
714 
715 	if (f == NULL)
716 		return(0);
717 
718 	fi = f->field_head;
719 	while (fi != NULL) {
720 		n++;
721 		fi = fi->next;
722 	}
723 
724 	return(n);
725 }
726 
727 struct dfui_action *
728 dfui_form_action_find(const struct dfui_form *f, const char *id)
729 {
730 	struct dfui_action *a = f->action_head;
731 
732 	while (a != NULL) {
733 		if (!strcmp(id, a->id))
734 			return(a);
735 		a = a->next;
736 	}
737 
738 	return(NULL);
739 }
740 
741 struct dfui_action *
742 dfui_form_action_get_first(const struct dfui_form *f)
743 {
744 	if (f == NULL)
745 		return(NULL);
746 	return(f->action_head);
747 }
748 
749 int
750 dfui_form_action_count(const struct dfui_form *f)
751 {
752 	int n = 0;
753 	struct dfui_action *a;
754 
755 	if (f == NULL)
756 		return(0);
757 
758 	a = f->action_head;
759 	while (a != NULL) {
760 		n++;
761 		a = a->next;
762 	}
763 
764 	return(n);
765 }
766 
767 struct dfui_property *
768 dfui_form_property_set(struct dfui_form *f, const char *name, const char *value)
769 {
770 	return(dfui_property_set(&f->property_head, name, value));
771 }
772 
773 const char *
774 dfui_form_property_get(const struct dfui_form *f, const char *name)
775 {
776 	return(dfui_property_get(f->property_head, name));
777 }
778 
779 int
780 dfui_form_property_is(const struct dfui_form *f, const char *name, const char *value)
781 {
782 	struct dfui_property *h;
783 
784 	if (f == NULL)
785 		return(0);
786 	if ((h = dfui_property_find(f->property_head, name)) == NULL)
787 		return(0);
788 	return(!strcmp(h->value, value));
789 }
790 
791 const char *
792 dfui_form_get_id(const struct dfui_form *f)
793 {
794 	if (f == NULL)
795 		return(NULL);	/* XXX ? */
796 	return(f->id);
797 }
798 
799 struct dfui_info *
800 dfui_form_get_info(const struct dfui_form *f)
801 {
802 	if (f == NULL)
803 		return(NULL);
804 	return(f->info);
805 }
806 
807 void
808 dfui_form_set_multiple(struct dfui_form *f, int multiple)
809 {
810 	if (f == NULL)
811 		return;
812 	f->multiple = multiple;
813 }
814 
815 int
816 dfui_form_is_multiple(const struct dfui_form *f)
817 {
818 	if (f == NULL)
819 		return(0);
820 	return(f->multiple);
821 }
822 
823 void
824 dfui_form_set_extensible(struct dfui_form *f, int extensible)
825 {
826 	if (f == NULL)
827 		return;
828 	f->extensible = extensible;
829 }
830 
831 int
832 dfui_form_is_extensible(const struct dfui_form *f)
833 {
834 	if (f == NULL)
835 		return(0);
836 	return(f->extensible);
837 }
838 
839 /*** CELLDATAS ***/
840 
841 struct dfui_celldata *
842 dfui_celldata_new(const char *field_id, const char *value)
843 {
844 	struct dfui_celldata *c;
845 
846 	AURA_MALLOC(c, dfui_celldata);
847 	c->field_id = aura_strdup(field_id);
848 	c->value = aura_strdup(value);
849 
850 	return(c);
851 }
852 
853 void
854 dfui_celldata_free(struct dfui_celldata *c)
855 {
856 	if (c == NULL)
857 		return;
858 	free(c->field_id);
859 	free(c->value);
860 	AURA_FREE(c, dfui_celldata);
861 }
862 
863 void
864 dfui_celldatas_free(struct dfui_celldata *head)
865 {
866 	struct dfui_celldata *c;
867 
868 	c = head;
869 	while (c != NULL) {
870 		head = c->next;
871 		dfui_celldata_free(c);
872 		c = head;
873 	}
874 }
875 
876 struct dfui_celldata *
877 dfui_celldata_find(struct dfui_celldata *head, const char *id)
878 {
879 	struct dfui_celldata *c;
880 
881 	c = head;
882 	while (c != NULL) {
883 		if (!strcmp(id, c->field_id))
884 			return(c);
885 		c = c->next;
886 	}
887 
888 	return(NULL);
889 }
890 
891 struct dfui_celldata *
892 dfui_celldata_get_next(const struct dfui_celldata *cd)
893 {
894 	if (cd != NULL) {
895 		return(cd->next);
896 	} else {
897 		return(NULL);
898 	}
899 }
900 
901 const char *
902 dfui_celldata_get_field_id(const struct dfui_celldata *cd)
903 {
904 	if (cd != NULL) {
905 		return(cd->field_id);
906 	} else {
907 		return(NULL);
908 	}
909 }
910 
911 const char *
912 dfui_celldata_get_value(const struct dfui_celldata *cd)
913 {
914 	if (cd != NULL) {
915 		return(cd->value);
916 	} else {
917 		return("");
918 	}
919 }
920 
921 /*** DATASETS ***/
922 
923 struct dfui_dataset *
924 dfui_dataset_new(void)
925 {
926 	struct dfui_dataset *ds;
927 
928 	AURA_MALLOC(ds, dfui_dataset);
929 	ds->celldata_head = NULL;
930 	ds->next = NULL;
931 
932 	return(ds);
933 }
934 
935 struct dfui_dataset *
936 dfui_dataset_dup(const struct dfui_dataset *ds)
937 {
938 	struct dfui_dataset *nds;
939 	struct dfui_celldata *cd;
940 
941 	nds = dfui_dataset_new();
942 
943 	for (cd = ds->celldata_head; cd != NULL; cd = cd->next) {
944 		dfui_dataset_celldata_add(nds,
945 		    cd->field_id, cd->value);
946 	}
947 
948 	return(nds);
949 }
950 
951 void
952 dfui_dataset_free(struct dfui_dataset *ds)
953 {
954 	dfui_celldatas_free(ds->celldata_head);
955 	AURA_FREE(ds, dfui_dataset);
956 }
957 
958 void
959 dfui_datasets_free(struct dfui_dataset *head)
960 {
961 	struct dfui_dataset *ds;
962 
963 	ds = head;
964 	while (ds != NULL) {
965 		head = ds->next;
966 		dfui_dataset_free(ds);
967 		ds = head;
968 	}
969 }
970 
971 struct dfui_celldata *
972 dfui_dataset_celldata_add(struct dfui_dataset *ds, const char *field_id, const char *value)
973 {
974 	struct dfui_celldata *c;
975 
976 	if (ds == NULL)
977 		return(NULL);
978 
979 	c = dfui_celldata_new(field_id, value);
980 	c->next = ds->celldata_head;
981 	ds->celldata_head = c;
982 
983 	return(c);
984 }
985 
986 struct dfui_celldata *
987 dfui_dataset_celldata_get_first(const struct dfui_dataset *ds)
988 {
989 	if (ds == NULL)
990 		return(NULL);
991 	return(ds->celldata_head);
992 }
993 
994 struct dfui_celldata *
995 dfui_dataset_celldata_find(const struct dfui_dataset *ds, const char *field_id)
996 {
997 	if (ds == NULL)
998 		return(NULL);
999 	return(dfui_celldata_find(ds->celldata_head, field_id));
1000 }
1001 
1002 struct dfui_dataset *
1003 dfui_dataset_get_next(const struct dfui_dataset *ds)
1004 {
1005 	if (ds == NULL)
1006 		return(NULL);
1007 	return(ds->next);
1008 }
1009 
1010 /*
1011  * Returns the value of the celldata with the given id found in the
1012  * given dataset.  If no such celldata is found, a constant zero-length
1013  * string is returned.  As such, the return value of this function is
1014  * guaranteed to not be NULL and must NEVER be freed after use.
1015  */
1016 const char *
1017 dfui_dataset_get_value(const struct dfui_dataset *ds, const char *id)
1018 {
1019 	struct dfui_celldata *cd;
1020 
1021 	if ((cd = dfui_dataset_celldata_find(ds, id)) != NULL) {
1022 		return(dfui_celldata_get_value(cd));
1023 	} else {
1024 		return("");
1025 	}
1026 }
1027 
1028 /*
1029  * Allocates a string to hold the value of the celldata with the
1030  * given id found in the given dataset.  Even if no such celldata
1031  * is found, an allocated, zero-length string is returned.  As such,
1032  * the return value of this function is guaranteed to not be NULL,
1033  * and must ALWAYS be freed after use.
1034  */
1035 char *
1036 dfui_dataset_dup_value(const struct dfui_dataset *ds, const char *id)
1037 {
1038 	return(aura_strdup(dfui_dataset_get_value(ds, id)));
1039 }
1040 
1041 /*** RESPONSES ***/
1042 
1043 struct dfui_response *
1044 dfui_response_new(const char *form_id, const char *action_id)
1045 {
1046 	struct dfui_response *r;
1047 
1048 	AURA_MALLOC(r, dfui_response);
1049 	r->form_id = aura_strdup(form_id);
1050 	r->action_id = aura_strdup(action_id);
1051 	r->dataset_head = NULL;
1052 
1053 	return(r);
1054 }
1055 
1056 void
1057 dfui_response_free(struct dfui_response *r)
1058 {
1059 	free(r->form_id);
1060 	free(r->action_id);
1061 	dfui_datasets_free(r->dataset_head);
1062 	AURA_FREE(r, dfui_response);
1063 }
1064 
1065 void
1066 dfui_response_dataset_add(struct dfui_response *r, struct dfui_dataset *ds)
1067 {
1068 	if (ds == NULL || r == NULL)
1069 		return;
1070 	ds->next = r->dataset_head;
1071 	r->dataset_head = ds;
1072 }
1073 
1074 struct dfui_dataset *
1075 dfui_response_dataset_get_first(const struct dfui_response *r)
1076 {
1077 	if (r == NULL)
1078 		return(NULL);
1079 	return(r->dataset_head);
1080 }
1081 
1082 int
1083 dfui_response_dataset_count(const struct dfui_response *r)
1084 {
1085 	int n = 0;
1086 	struct dfui_dataset *ds;
1087 
1088 	if (r == NULL)
1089 		return(0);
1090 
1091 	ds = r->dataset_head;
1092 	while (ds != NULL) {
1093 		n++;
1094 		ds = ds->next;
1095 	}
1096 
1097 	return(n);
1098 }
1099 
1100 const char *
1101 dfui_response_get_form_id(const struct dfui_response *r)
1102 {
1103 	if (r == NULL)
1104 		return(NULL);	/* XXX ? */
1105 	return(r->form_id);
1106 }
1107 
1108 const char *
1109 dfui_response_get_action_id(const struct dfui_response *r)
1110 {
1111 	if (r == NULL)
1112 		return(NULL);	/* XXX ? */
1113 	return(r->action_id);
1114 }
1115 
1116 /* PROGRESS BARS */
1117 
1118 struct dfui_progress *
1119 dfui_progress_new(struct dfui_info *info, int amount)
1120 {
1121 	struct dfui_progress *pr;
1122 
1123 	AURA_MALLOC(pr, dfui_progress);
1124 	pr->info = info;
1125 	pr->amount = amount;
1126 	pr->streaming = 0;
1127 	pr->msg_line = NULL;
1128 
1129 	return(pr);
1130 }
1131 
1132 void
1133 dfui_progress_free(struct dfui_progress *pr)
1134 {
1135 	if (pr == NULL)
1136 		return;
1137 	dfui_info_free(pr->info);
1138 	if (pr->msg_line != NULL)
1139 		free(pr->msg_line);
1140 	AURA_FREE(pr, dfui_progress);
1141 }
1142 
1143 struct dfui_info *
1144 dfui_progress_get_info(const struct dfui_progress *pr)
1145 {
1146 	if (pr == NULL)
1147 		return(NULL);
1148 	return(pr->info);
1149 }
1150 
1151 void
1152 dfui_progress_set_amount(struct dfui_progress *pr, int amount)
1153 {
1154 	if (pr == NULL)
1155 		return;
1156 	pr->amount = amount;
1157 }
1158 
1159 int
1160 dfui_progress_get_amount(const struct dfui_progress *pr)
1161 {
1162 	if (pr == NULL)
1163 		return(0);
1164 	return(pr->amount);
1165 }
1166 
1167 void
1168 dfui_progress_set_streaming(struct dfui_progress *pr, int streaming)
1169 {
1170 	if (pr == NULL)
1171 		return;
1172 	pr->streaming = streaming;
1173 }
1174 
1175 int
1176 dfui_progress_get_streaming(const struct dfui_progress *pr)
1177 {
1178 	if (pr == NULL)
1179 		return(0);
1180 	return(pr->streaming);
1181 }
1182 
1183 void
1184 dfui_progress_set_msg_line(struct dfui_progress *pr, const char *msg_line)
1185 {
1186 	if (pr == NULL)
1187 		return;
1188 	if (pr->msg_line != NULL)
1189 		free(pr->msg_line);
1190 	pr->msg_line = aura_strdup(msg_line);
1191 }
1192 
1193 const char *
1194 dfui_progress_get_msg_line(const struct dfui_progress *pr)
1195 {
1196 	if (pr == NULL)
1197 		return("");
1198 	if (pr->msg_line == NULL)
1199 		return("");
1200 	return(pr->msg_line);
1201 }
1202