xref: /freebsd/contrib/bsddialog/utility/util_builders.c (revision 5ca8e32633c4ffbbcd6762e5888b6a4ba0708c6c)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2021-2023 Alfonso Sabato Siciliano
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <time.h>
32 #include <unistd.h>
33 
34 #include <bsddialog.h>
35 #include <bsddialog_theme.h>
36 
37 #include "util.h"
38 
39 #define NO_PRINT_VALUES(rv)                                                    \
40 (rv == BSDDIALOG_ERROR || rv == BSDDIALOG_CANCEL || rv == BSDDIALOG_ESC)
41 
42 /* message */
43 int infobox_builder(BUILDER_ARGS)
44 {
45 	if (argc > 0)
46 		error_args(opt->name, argc, argv);
47 
48 	return (bsddialog_infobox(conf, text, rows, cols));
49 }
50 
51 int msgbox_builder(BUILDER_ARGS)
52 {
53 	if (argc > 0)
54 		error_args(opt->name, argc, argv);
55 
56 	return (bsddialog_msgbox(conf, text, rows, cols));
57 }
58 
59 int yesno_builder(BUILDER_ARGS)
60 {
61 	if (argc > 0)
62 		error_args(opt->name, argc, argv);
63 
64 	return (bsddialog_yesno(conf, text, rows, cols));
65 }
66 
67 /* textbox */
68 int textbox_builder(BUILDER_ARGS)
69 {
70 	if (argc > 0)
71 		error_args(opt->name, argc, argv);
72 
73 	return (bsddialog_textbox(conf, text, rows, cols));
74 }
75 
76 /* bar */
77 int gauge_builder(BUILDER_ARGS)
78 {
79 	int output;
80 	unsigned int perc;
81 
82 	perc = 0;
83 	if (argc == 1) {
84 		perc = (u_int)strtoul(argv[0], NULL, 10);
85 		perc = perc > 100 ? 100 : perc;
86 	} else if (argc > 1) {
87 		error_args(opt->name, argc - 1, argv + 1);
88 	}
89 
90 	output = bsddialog_gauge(conf, text, rows, cols, perc, STDIN_FILENO,
91 	    "XXX", "EOF");
92 
93 	return (output);
94 }
95 
96 int mixedgauge_builder(BUILDER_ARGS)
97 {
98 	int output, *minipercs;
99 	unsigned int i, mainperc, nminibars;
100 	const char **minilabels;
101 
102 	if (argc < 1)
103 		exit_error(true, "%s missing <mainperc>", opt->name);
104 	if (((argc-1) % 2) != 0)
105 		exit_error(true,
106 		    "bad %s pair number [<minilabel> <miniperc>]", opt->name);
107 
108 	mainperc = (u_int)strtoul(argv[0], NULL, 10);
109 	mainperc = mainperc > 100 ? 100 : mainperc;
110 	argc--;
111 	argv++;
112 
113 	nminibars  = argc / 2;
114 	if ((minilabels = calloc(nminibars, sizeof(char*))) == NULL)
115 		exit_error(false, "Cannot allocate memory for minilabels");
116 	if ((minipercs = calloc(nminibars, sizeof(int))) == NULL)
117 		exit_error(false, "Cannot allocate memory for minipercs");
118 
119 	for (i = 0; i < nminibars; i++) {
120 		minilabels[i] = argv[i * 2];
121 		minipercs[i] = (int)strtol(argv[i * 2 + 1], NULL, 10);
122 	}
123 
124 	output = bsddialog_mixedgauge(conf, text, rows, cols, mainperc,
125 	    nminibars, minilabels, minipercs);
126 
127 	return (output);
128 }
129 
130 int pause_builder(BUILDER_ARGS)
131 {
132 	int output;
133 	unsigned int secs;
134 
135 	if (argc == 0)
136 		exit_error(true, "--pause missing <seconds>");
137 	if (argc > 1)
138 		error_args(opt->name, argc - 1, argv + 1);
139 
140 	secs = (u_int)strtoul(argv[0], NULL, 10);
141 	output = bsddialog_pause(conf, text, rows, cols, &secs);
142 
143 	return (output);
144 }
145 
146 int rangebox_builder(BUILDER_ARGS)
147 {
148 	int output, min, max, value;
149 
150 	if (argc < 2)
151 		exit_error(true, "--rangebox missing <min> <max> [<init>]");
152 	if (argc > 3)
153 		error_args("--rangebox", argc - 3, argv + 3);
154 
155 	min = (int)strtol(argv[0], NULL, 10);
156 	max = (int)strtol(argv[1], NULL, 10);
157 
158 	if (argc == 3) {
159 		value = (int)strtol(argv[2], NULL, 10);
160 		value = value < min ? min : value;
161 		value = value > max ? max : value;
162 	} else
163 		value = min;
164 
165 	output = bsddialog_rangebox(conf, text, rows, cols, min, max, &value);
166 	if (NO_PRINT_VALUES(output) == false)
167 		dprintf(opt->output_fd, "%d", value);
168 
169 	return (output);
170 }
171 
172 /* date and time */
173 static int date(BUILDER_ARGS)
174 {
175 	int rv;
176 	unsigned int yy, mm, dd;
177 	time_t cal;
178 	struct tm *localtm;
179 	char stringdate[1024];
180 
181 	time(&cal);
182 	localtm = localtime(&cal);
183 	yy = localtm->tm_year + 1900;
184 	mm = localtm->tm_mon + 1;
185 	dd = localtm->tm_mday;
186 
187 	if (argc > 3) {
188 		error_args(opt->name, argc - 3, argv + 3);
189 	} else if (argc == 3) {
190 		/* lib checks/sets max and min */
191 		dd = (u_int)strtoul(argv[0], NULL, 10);
192 		mm = (u_int)strtoul(argv[1], NULL, 10);
193 		yy = (u_int)strtoul(argv[2], NULL, 10);
194 	}
195 
196 	if (strcmp(opt->name, "--datebox") == 0)
197 		rv = bsddialog_datebox(conf, text, rows, cols, &yy, &mm, &dd);
198 	else
199 		rv = bsddialog_calendar(conf, text, rows, cols, &yy, &mm, &dd);
200 	if (NO_PRINT_VALUES(rv))
201 		return (rv);
202 
203 	if (opt->date_fmt != NULL) {
204 		time(&cal);
205 		localtm = localtime(&cal);
206 		localtm->tm_year = yy - 1900;
207 		localtm->tm_mon = mm - 1;
208 		localtm->tm_mday = dd;
209 		strftime(stringdate, 1024, opt->date_fmt, localtm);
210 		dprintf(opt->output_fd, "%s", stringdate);
211 	} else if (opt->bikeshed && ~dd & 1) {
212 		dprintf(opt->output_fd, "%u/%u/%u", dd, mm, yy);
213 	} else {
214 		dprintf(opt->output_fd, "%02u/%02u/%u", dd, mm, yy);
215 	}
216 
217 	return (rv);
218 }
219 
220 int calendar_builder(BUILDER_ARGS)
221 {
222 	/* Use height autosizing with rows = 2. Documented in bsddialog(1).
223 	 *
224 	 * f_dialog_calendar_size() in bsdconfig/share/dialog.subr:1352
225 	 * computes height 2 for `dialog --calendar', called by:
226 	 * 1) f_dialog_input_expire_password() in
227 	 * bsdconfig/usermgmt/share/user_input.subr:517 and
228 	 * 2) f_dialog_input_expire_account() in
229 	 * bsdconfig/usermgmt/share/user_input.subr:660.
230 	 *
231 	 * Then use height autosizing with 2 that is min height like dialog.
232 	 */
233 	if (rows == 2)
234 		rows = 0;
235 
236 	return (date(conf, text, rows, cols, argc, argv, opt));
237 }
238 
239 int datebox_builder(BUILDER_ARGS)
240 {
241 	return (date(conf, text, rows, cols, argc, argv, opt));
242 }
243 
244 int timebox_builder(BUILDER_ARGS)
245 {
246 	int output;
247 	unsigned int hh, mm, ss;
248 	time_t clock;
249 	struct tm *localtm;
250 	char stringtime[1024];
251 
252 	time(&clock);
253 	localtm = localtime(&clock);
254 	hh = localtm->tm_hour;
255 	mm = localtm->tm_min;
256 	ss = localtm->tm_sec;
257 
258 	if (argc > 3) {
259 		error_args("--timebox", argc - 3, argv + 3);
260 	} else if (argc == 3) {
261 		hh = (u_int)strtoul(argv[0], NULL, 10);
262 		mm = (u_int)strtoul(argv[1], NULL, 10);
263 		ss = (u_int)strtoul(argv[2], NULL, 10);
264 	}
265 
266 	output = bsddialog_timebox(conf, text, rows, cols, &hh, &mm, &ss);
267 	if (NO_PRINT_VALUES(output))
268 		return (output);
269 
270 	if (opt->time_fmt != NULL) {
271 		time(&clock);
272 		localtm = localtime(&clock);
273 		localtm->tm_hour = hh;
274 		localtm->tm_min = mm;
275 		localtm->tm_sec = ss;
276 		strftime(stringtime, 1024, opt->time_fmt, localtm);
277 		dprintf(opt->output_fd, "%s", stringtime);
278 	} else if (opt->bikeshed && ~ss & 1) {
279 		dprintf(opt->output_fd, "%u:%u:%u", hh, mm, ss);
280 	} else {
281 		dprintf(opt->output_fd, "%02u:%02u:%02u", hh, mm, ss);
282 	}
283 
284 	return (output);
285 }
286 
287 /* menu */
288 static void
289 get_menu_items(int argc, char **argv, bool setprefix, bool setdepth,
290     bool setname, bool setdesc, bool setstatus, bool sethelp,
291     unsigned int *nitems, struct bsddialog_menuitem **items, int *focusitem,
292     struct options *opt)
293 {
294 	unsigned int i, j, sizeitem;
295 
296 	*focusitem = -1;
297 
298 	sizeitem = 0;
299 	sizeitem += setprefix ? 1 : 0;
300 	sizeitem += setdepth  ? 1 : 0;
301 	sizeitem += setname   ? 1 : 0;
302 	sizeitem += setdesc   ? 1 : 0;
303 	sizeitem += setstatus ? 1 : 0;
304 	sizeitem += sethelp   ? 1 : 0;
305 	if ((argc % sizeitem) != 0)
306 		exit_error(true, "%s bad arguments items number", opt->name);
307 
308 	*nitems = argc / sizeitem;
309 	*items = calloc(*nitems, sizeof(struct bsddialog_menuitem));
310 	if (items == NULL)
311 		exit_error(false, "%s cannot allocate items", opt->name);
312 
313 	j = 0;
314 	for (i = 0; i < *nitems; i++) {
315 		(*items)[i].prefix = setprefix ? argv[j++] : "";
316 		(*items)[i].depth = setdepth ?
317 		    (u_int)strtoul(argv[j++], NULL, 0) : 0;
318 		(*items)[i].name = setname ? argv[j++] : "";
319 		(*items)[i].desc = setdesc ? argv[j++] : "";
320 		if (setstatus) {
321 			if (strcasecmp(argv[j], "on") == 0)
322 				(*items)[i].on = true;
323 			else if (strcasecmp(argv[j], "off") == 0)
324 				(*items)[i].on = false;
325 			else
326 				exit_error(true,
327 				    "\"%s\" (item %i) invalid status \"%s\"",
328 				    (*items)[i].name, i+1, argv[j]);
329 			j++;
330 		} else
331 			(*items)[i].on = false;
332 		(*items)[i].bottomdesc = sethelp ? argv[j++] : "";
333 
334 		if (opt->item_default != NULL && *focusitem == -1)
335 			if (strcmp((*items)[i].name, opt->item_default) == 0)
336 				*focusitem = i;
337 	}
338 }
339 
340 static void
341 print_menu_items(int output, int nitems, struct bsddialog_menuitem *items,
342     int focusitem, struct options *opt)
343 {
344 	bool sep, sepbefore, sepafter, sepsecond, toquote, ismenu, ischecklist;
345 	int i;
346 	char quotech;
347 	const char *focusname, *sepstr;
348 
349 	ismenu = (strcmp(opt->name, "--menu") == 0) ? true : false;
350 	ischecklist = (strcmp(opt->name, "--checklist") == 0) ? true : false;
351 	sep = false;
352 	quotech = opt->item_singlequote ? '\'' : '"';
353 
354 	if (NO_PRINT_VALUES(output))
355 		return;
356 
357 	if (output == BSDDIALOG_HELP) {
358 		dprintf(opt->output_fd, "HELP ");
359 
360 		if (focusitem >= 0) {
361 			focusname = items[focusitem].name;
362 			if (opt->item_bottomdesc &&
363 			    opt->help_print_item_name == false)
364 				focusname = items[focusitem].bottomdesc;
365 
366 			toquote = false;
367 			if (strchr(focusname, ' ') != NULL) {
368 				toquote = opt->item_always_quote;
369 				if (ismenu == false &&
370 				    opt->item_output_sepnl == false)
371 					toquote = true;
372 			}
373 			if (toquote) {
374 				dprintf(opt->output_fd, "%c%s%c",
375 				    quotech, focusname, quotech);
376 			} else
377 				dprintf(opt->output_fd, "%s", focusname);
378 		}
379 
380 		if (ismenu || opt->help_print_items == false)
381 			return;
382 		sep = true;
383 	}
384 
385 	sepbefore = false;
386 	sepsecond = false;
387 	if ((sepstr = opt->item_output_sep) == NULL) {
388 		if (opt->item_output_sepnl)
389 			sepstr = "\n";
390 		else {
391 			sepstr = " ";
392 			sepsecond = true;
393 		}
394 	} else
395 		sepbefore = true;
396 
397 	sepafter = false;
398 	if (opt->item_output_sepnl) {
399 		sepbefore = false;
400 		sepafter = true;
401 	}
402 
403 	for (i = 0; i < nitems; i++) {
404 		if (items[i].on == false)
405 			continue;
406 
407 		if (sep || sepbefore)
408 			dprintf(opt->output_fd, "%s", sepstr);
409 		sep = false;
410 		if (sepsecond)
411 			sep = true;
412 
413 		toquote = false;
414 		if (strchr(items[i].name, ' ') != NULL) {
415 			toquote = opt->item_always_quote;
416 			if (ischecklist && opt->item_output_sepnl == false)
417 				toquote = true;
418 		}
419 		if (toquote)
420 			dprintf(opt->output_fd, "%c%s%c",
421 			    quotech, items[i].name, quotech);
422 		else
423 			dprintf(opt->output_fd, "%s", items[i].name);
424 
425 		if (sepafter)
426 			dprintf(opt->output_fd, "%s", sepstr);
427 	}
428 }
429 
430 int checklist_builder(BUILDER_ARGS)
431 {
432 	int output, focusitem;
433 	unsigned int menurows, nitems;
434 	struct bsddialog_menuitem *items;
435 
436 	if (argc < 1)
437 		exit_error(true, "--checklist missing <menurows>");
438 	menurows = (u_int)strtoul(argv[0], NULL, 10);
439 
440 	get_menu_items(argc-1, argv+1, opt->item_prefix, opt->item_depth, true,
441 	    true, true, opt->item_bottomdesc, &nitems, &items, &focusitem, opt);
442 
443 	output = bsddialog_checklist(conf, text, rows, cols, menurows, nitems,
444 	    items, &focusitem);
445 
446 	print_menu_items(output, nitems, items, focusitem, opt);
447 	free(items);
448 
449 	if (output == BSDDIALOG_HELP && opt->item_bottomdesc)
450 		output = BSDDIALOG_ITEM_HELP;
451 
452 	return (output);
453 }
454 
455 int menu_builder(BUILDER_ARGS)
456 {
457 	int output, focusitem;
458 	unsigned int menurows, nitems;
459 	struct bsddialog_menuitem *items;
460 
461 	if (argc < 1)
462 		exit_error(true, "--menu missing <menurows>");
463 	menurows = (u_int)strtoul(argv[0], NULL, 10);
464 
465 	get_menu_items(argc-1, argv+1, opt->item_prefix, opt->item_depth, true,
466 	    true, false, opt->item_bottomdesc, &nitems, &items, &focusitem,
467 	    opt);
468 
469 	output = bsddialog_menu(conf, text, rows, cols, menurows, nitems,
470 	    items, &focusitem);
471 
472 	print_menu_items(output, nitems, items, focusitem, opt);
473 	free(items);
474 
475 	if (output == BSDDIALOG_HELP && opt->item_bottomdesc)
476 		output = BSDDIALOG_ITEM_HELP;
477 
478 	return (output);
479 }
480 
481 int radiolist_builder(BUILDER_ARGS)
482 {
483 	int output, focusitem;
484 	unsigned int menurows, nitems;
485 	struct bsddialog_menuitem *items;
486 
487 	if (argc < 1)
488 		exit_error(true, "--radiolist missing <menurows>");
489 	menurows = (u_int)strtoul(argv[0], NULL, 10);
490 
491 	get_menu_items(argc-1, argv+1, opt->item_prefix, opt->item_depth, true,
492 	    true, true, opt->item_bottomdesc, &nitems, &items, &focusitem, opt);
493 
494 	output = bsddialog_radiolist(conf, text, rows, cols, menurows, nitems,
495 	    items, &focusitem);
496 
497 	print_menu_items(output, nitems, items, focusitem, opt);
498 	free(items);
499 
500 	if (output == BSDDIALOG_HELP && opt->item_bottomdesc)
501 		output = BSDDIALOG_ITEM_HELP;
502 
503 	return (output);
504 }
505 
506 int treeview_builder(BUILDER_ARGS)
507 {
508 	int output, focusitem;
509 	unsigned int menurows, nitems;
510 	struct bsddialog_menuitem *items;
511 
512 	if (argc < 1)
513 		exit_error(true, "--treeview missing <menurows>");
514 	menurows = (u_int)strtoul(argv[0], NULL, 10);
515 
516 	get_menu_items(argc-1, argv+1, opt->item_prefix, true, true, true, true,
517 	    opt->item_bottomdesc, &nitems, &items, &focusitem, opt);
518 
519 	conf->menu.no_name = true;
520 	conf->menu.align_left = true;
521 
522 	output = bsddialog_radiolist(conf, text, rows, cols, menurows, nitems,
523 	    items, &focusitem);
524 
525 	print_menu_items(output, nitems, items, focusitem, opt);
526 	free(items);
527 
528 	if (output == BSDDIALOG_HELP && opt->item_bottomdesc)
529 		output = BSDDIALOG_ITEM_HELP;
530 
531 	return (output);
532 }
533 
534 /* form */
535 static void
536 print_form_items(int output, int nitems, struct bsddialog_formitem *items,
537     int focusitem, struct options *opt)
538 {
539 	int i;
540 	const char *helpname;
541 
542 	if (NO_PRINT_VALUES(output))
543 		return;
544 
545 	if (output == BSDDIALOG_HELP) {
546 		dprintf(opt->output_fd, "HELP");
547 		if (focusitem >= 0) {
548 			helpname = items[focusitem].label;
549 			if (opt->item_bottomdesc &&
550 			    opt->help_print_item_name == false)
551 				helpname = items[focusitem].bottomdesc;
552 			dprintf(opt->output_fd, " %s", helpname);
553 		}
554 		if(opt->help_print_items == false)
555 			return;
556 		dprintf(opt->output_fd, "\n");
557 	}
558 
559 	for (i = 0; i < nitems; i++) {
560 		dprintf(opt->output_fd, "%s\n", items[i].value);
561 		free(items[i].value);
562 	}
563 }
564 
565 int form_builder(BUILDER_ARGS)
566 {
567 	int output, fieldlen, valuelen, focusitem;
568 	unsigned int i, j, flags, formheight, nitems, sizeitem;
569 	struct bsddialog_formitem *items;
570 
571 	if (argc < 1)
572 		exit_error(true, "--form missing <formheight>");
573 	formheight = (u_int)strtoul(argv[0], NULL, 10);
574 
575 	argc--;
576 	argv++;
577 	sizeitem = opt->item_bottomdesc ? 9 : 8;
578 	if (argc % sizeitem != 0)
579 		exit_error(true, "--form bad number of arguments items");
580 
581 	nitems = argc / sizeitem;
582 	if ((items = calloc(nitems, sizeof(struct bsddialog_formitem))) == NULL)
583 		exit_error(false, "cannot allocate memory for form items");
584 	j = 0;
585 	for (i = 0; i < nitems; i++) {
586 		items[i].label	= argv[j++];
587 		items[i].ylabel = (u_int)strtoul(argv[j++], NULL, 10);
588 		items[i].xlabel = (u_int)strtoul(argv[j++], NULL, 10);
589 		items[i].init	= argv[j++];
590 		items[i].yfield	= (u_int)strtoul(argv[j++], NULL, 10);
591 		items[i].xfield	= (u_int)strtoul(argv[j++], NULL, 10);
592 
593 		fieldlen = (int)strtol(argv[j++], NULL, 10);
594 		items[i].fieldlen = abs(fieldlen);
595 
596 		valuelen = (int)strtol(argv[j++], NULL, 10);
597 		items[i].maxvaluelen = valuelen == 0 ? abs(fieldlen) : valuelen;
598 
599 		flags = (fieldlen < 0 ? BSDDIALOG_FIELDREADONLY : 0);
600 		items[i].flags = flags;
601 
602 		items[i].bottomdesc = opt->item_bottomdesc ? argv[j++] : "";
603 	}
604 
605 	focusitem = -1;
606 	output = bsddialog_form(conf, text, rows, cols, formheight, nitems,
607 	    items, &focusitem);
608 	print_form_items(output, nitems, items, focusitem, opt);
609 	free(items);
610 
611 	if (output == BSDDIALOG_HELP && opt->item_bottomdesc)
612 		output = BSDDIALOG_ITEM_HELP;
613 
614 	return (output);
615 }
616 
617 int inputbox_builder(BUILDER_ARGS)
618 {
619 	int output;
620 	struct bsddialog_formitem item;
621 
622 	if (argc > 1)
623 		error_args("--inputbox", argc - 1, argv + 1);
624 
625 	item.label	 = "";
626 	item.ylabel	 = 0;
627 	item.xlabel	 = 0;
628 	item.init	 = argc > 0 ? argv[0] : "";
629 	item.yfield	 = 0;
630 	item.xfield	 = 0;
631 	item.fieldlen    = 1;
632 	item.maxvaluelen = opt->max_input_form;
633 	item.flags	 = BSDDIALOG_FIELDNOCOLOR;
634 	item.flags      |= BSDDIALOG_FIELDCURSOREND;
635 	item.flags      |= BSDDIALOG_FIELDEXTEND;
636 	item.bottomdesc  = "";
637 
638 	output = bsddialog_form(conf, text, rows, cols, 1, 1, &item, NULL);
639 	print_form_items(output, 1, &item, -1, opt);
640 
641 	return (output);
642 }
643 
644 int mixedform_builder(BUILDER_ARGS)
645 {
646 	int output, focusitem;
647 	unsigned int i, j, formheight, nitems, sizeitem;
648 	struct bsddialog_formitem *items;
649 
650 	if (argc < 1)
651 		exit_error(true, "--mixedform missing <formheight>");
652 	formheight = (u_int)strtoul(argv[0], NULL, 10);
653 
654 	argc--;
655 	argv++;
656 	sizeitem = opt->item_bottomdesc ? 10 : 9;
657 	if (argc % sizeitem != 0)
658 		exit_error(true, "--mixedform bad number of arguments items");
659 
660 	nitems = argc / sizeitem;
661 	if ((items = calloc(nitems, sizeof(struct bsddialog_formitem))) == NULL)
662 		exit_error(false, "cannot allocate memory for form items");
663 	j = 0;
664 	for (i = 0; i < nitems; i++) {
665 		items[i].label	     = argv[j++];
666 		items[i].ylabel      = (u_int)strtoul(argv[j++], NULL, 10);
667 		items[i].xlabel      = (u_int)strtoul(argv[j++], NULL, 10);
668 		items[i].init	     = argv[j++];
669 		items[i].yfield	     = (u_int)strtoul(argv[j++], NULL, 10);
670 		items[i].xfield	     = (u_int)strtoul(argv[j++], NULL, 10);
671 		items[i].fieldlen    = (u_int)strtoul(argv[j++], NULL, 10);
672 		items[i].maxvaluelen = (u_int)strtoul(argv[j++], NULL, 10);
673 		items[i].flags       = (u_int)strtoul(argv[j++], NULL, 10);
674 		items[i].bottomdesc  = opt->item_bottomdesc ? argv[j++] : "";
675 	}
676 
677 	focusitem = -1;
678 	output = bsddialog_form(conf, text, rows, cols, formheight, nitems,
679 	    items, &focusitem);
680 	print_form_items(output, nitems, items, focusitem, opt);
681 	free(items);
682 
683 	if (output == BSDDIALOG_HELP && opt->item_bottomdesc)
684 		output = BSDDIALOG_ITEM_HELP;
685 
686 	return (output);
687 }
688 
689 int passwordbox_builder(BUILDER_ARGS)
690 {
691 	int output;
692 	struct bsddialog_formitem item;
693 
694 	if (argc > 1)
695 		error_args("--passwordbox", argc - 1, argv + 1);
696 
697 	item.label	 = "";
698 	item.ylabel	 = 0;
699 	item.xlabel	 = 0;
700 	item.init	 = argc > 0 ? argv[0] : "";
701 	item.yfield	 = 0;
702 	item.xfield	 = 0;
703 	item.fieldlen	 = 1;
704 	item.maxvaluelen = opt->max_input_form;
705 	item.flags       = BSDDIALOG_FIELDHIDDEN;
706 	item.flags      |= BSDDIALOG_FIELDNOCOLOR;
707 	item.flags      |= BSDDIALOG_FIELDCURSOREND;
708 	item.flags      |= BSDDIALOG_FIELDEXTEND;
709 	item.bottomdesc  = "";
710 
711 	output = bsddialog_form(conf, text, rows, cols, 1, 1, &item, NULL);
712 	print_form_items(output, 1, &item, -1, opt);
713 
714 	return (output);
715 }
716 
717 int passwordform_builder(BUILDER_ARGS)
718 {
719 	int output, fieldlen, valuelen, focusitem;
720 	unsigned int i, j, flags, formheight, nitems, sizeitem;
721 	struct bsddialog_formitem *items;
722 
723 	if (argc < 1)
724 		exit_error(true, "--passwordform missing <formheight>");
725 	formheight = (u_int)strtoul(argv[0], NULL, 10);
726 
727 	argc--;
728 	argv++;
729 	sizeitem = opt->item_bottomdesc ? 9 : 8;
730 	if (argc % sizeitem != 0)
731 		exit_error(true, "--passwordform bad arguments items number");
732 
733 	flags = BSDDIALOG_FIELDHIDDEN;
734 	nitems = argc / sizeitem;
735 	if ((items = calloc(nitems, sizeof(struct bsddialog_formitem))) == NULL)
736 		exit_error(false, "cannot allocate memory for form items");
737 	j = 0;
738 	for (i = 0; i < nitems; i++) {
739 		items[i].label	= argv[j++];
740 		items[i].ylabel = (u_int)strtoul(argv[j++], NULL, 10);
741 		items[i].xlabel = (u_int)strtoul(argv[j++], NULL, 10);
742 		items[i].init	= argv[j++];
743 		items[i].yfield	= (u_int)strtoul(argv[j++], NULL, 10);
744 		items[i].xfield	= (u_int)strtoul(argv[j++], NULL, 10);
745 
746 		fieldlen = (int)strtol(argv[j++], NULL, 10);
747 		items[i].fieldlen = abs(fieldlen);
748 
749 		valuelen = (int)strtol(argv[j++], NULL, 10);
750 		items[i].maxvaluelen = valuelen == 0 ? abs(fieldlen) : valuelen;
751 
752 		flags |= (fieldlen < 0 ? BSDDIALOG_FIELDREADONLY : 0);
753 		items[i].flags = flags;
754 
755 		items[i].bottomdesc  = opt->item_bottomdesc ? argv[j++] : "";
756 	}
757 
758 	focusitem = -1;
759 	output = bsddialog_form(conf, text, rows, cols, formheight, nitems,
760 	    items, &focusitem);
761 	print_form_items(output, nitems, items, focusitem, opt);
762 	free(items);
763 
764 	if (output == BSDDIALOG_HELP && opt->item_bottomdesc)
765 		output = BSDDIALOG_ITEM_HELP;
766 
767 	return (output);
768 }
769