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