xref: /freebsd-src/contrib/bsddialog/lib/formbox.c (revision d93b4d32034df7cd70e80b496e8fe8c1bc57c629)
1c76f0793SBaptiste Daroussin /*-
2c76f0793SBaptiste Daroussin  * SPDX-License-Identifier: BSD-2-Clause
3c76f0793SBaptiste Daroussin  *
4c76f0793SBaptiste Daroussin  * Copyright (c) 2021 Alfonso Sabato Siciliano
5c76f0793SBaptiste Daroussin  *
6c76f0793SBaptiste Daroussin  * Redistribution and use in source and binary forms, with or without
7c76f0793SBaptiste Daroussin  * modification, are permitted provided that the following conditions
8c76f0793SBaptiste Daroussin  * are met:
9c76f0793SBaptiste Daroussin  * 1. Redistributions of source code must retain the above copyright
10c76f0793SBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer.
11c76f0793SBaptiste Daroussin  * 2. Redistributions in binary form must reproduce the above copyright
12c76f0793SBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer in the
13c76f0793SBaptiste Daroussin  *    documentation and/or other materials provided with the distribution.
14c76f0793SBaptiste Daroussin  *
15c76f0793SBaptiste Daroussin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16c76f0793SBaptiste Daroussin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17c76f0793SBaptiste Daroussin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18c76f0793SBaptiste Daroussin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19c76f0793SBaptiste Daroussin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20c76f0793SBaptiste Daroussin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21c76f0793SBaptiste Daroussin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22c76f0793SBaptiste Daroussin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23c76f0793SBaptiste Daroussin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24c76f0793SBaptiste Daroussin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25c76f0793SBaptiste Daroussin  * SUCH DAMAGE.
26c76f0793SBaptiste Daroussin  */
27c76f0793SBaptiste Daroussin 
28f499134dSBaptiste Daroussin #include <sys/param.h>
29f499134dSBaptiste Daroussin 
30f499134dSBaptiste Daroussin #include <ctype.h>
31c76f0793SBaptiste Daroussin #ifdef PORTNCURSES
32c76f0793SBaptiste Daroussin #include <ncurses/form.h>
33c76f0793SBaptiste Daroussin #else
34c76f0793SBaptiste Daroussin #include <form.h>
35c76f0793SBaptiste Daroussin #endif
36*d93b4d32SBaptiste Daroussin #include <stdlib.h>
37*d93b4d32SBaptiste Daroussin #include <string.h>
38c76f0793SBaptiste Daroussin 
39c76f0793SBaptiste Daroussin #include "bsddialog.h"
40c76f0793SBaptiste Daroussin #include "lib_util.h"
41c76f0793SBaptiste Daroussin #include "bsddialog_theme.h"
42c76f0793SBaptiste Daroussin 
43f499134dSBaptiste Daroussin #define REDRAWFORM 14021986 /* magic number */
44f499134dSBaptiste Daroussin #define ISFIELDHIDDEN(item)   (item.flags & BSDDIALOG_FIELDHIDDEN)
45f499134dSBaptiste Daroussin #define ISFIELDREADONLY(item) (item.flags & BSDDIALOG_FIELDREADONLY)
46f499134dSBaptiste Daroussin 
47c76f0793SBaptiste Daroussin /* "Form": inputbox - passwordbox - form - passwordform - mixedform */
48c76f0793SBaptiste Daroussin 
49c76f0793SBaptiste Daroussin extern struct bsddialog_theme t;
50c76f0793SBaptiste Daroussin 
51f499134dSBaptiste Daroussin /* util struct for private buffer and view options */
52f499134dSBaptiste Daroussin struct myfield {
53*d93b4d32SBaptiste Daroussin 	int buflen;
54f499134dSBaptiste Daroussin 	char *buf;
55f499134dSBaptiste Daroussin 	int pos;
56*d93b4d32SBaptiste Daroussin 	int maxpos;
57f499134dSBaptiste Daroussin 	bool secure;
58f499134dSBaptiste Daroussin 	int securech;
598c4f4028SBaptiste Daroussin 	char *bottomdesc;
60f499134dSBaptiste Daroussin };
61f499134dSBaptiste Daroussin #define GETMYFIELD(field) ((struct myfield*)field_userptr(field))
62f499134dSBaptiste Daroussin #define GETMYFIELD2(form) ((struct myfield*)field_userptr(current_field(form)))
63f499134dSBaptiste Daroussin 
64f499134dSBaptiste Daroussin static void insertch(struct myfield *mf, int ch)
65c76f0793SBaptiste Daroussin {
66f499134dSBaptiste Daroussin 	int i;
67f499134dSBaptiste Daroussin 
68*d93b4d32SBaptiste Daroussin 	if (mf->buflen > mf->maxpos)
69f499134dSBaptiste Daroussin 		return;
70f499134dSBaptiste Daroussin 
71*d93b4d32SBaptiste Daroussin 	for (i = mf->buflen; i >= mf->pos; i--) {
72f499134dSBaptiste Daroussin 		mf->buf[i+1] = mf->buf[i];
73c76f0793SBaptiste Daroussin 	}
74c76f0793SBaptiste Daroussin 
75f499134dSBaptiste Daroussin 	mf->buf[mf->pos] = ch;
76f499134dSBaptiste Daroussin 	mf->pos += 1;
77*d93b4d32SBaptiste Daroussin 	if (mf->pos > mf->maxpos)
78*d93b4d32SBaptiste Daroussin 		mf->pos = mf->maxpos;
79*d93b4d32SBaptiste Daroussin 	mf->buflen += 1;
80*d93b4d32SBaptiste Daroussin 	mf->buf[mf->buflen] = '\0';
81f499134dSBaptiste Daroussin }
82f499134dSBaptiste Daroussin 
83f499134dSBaptiste Daroussin static void shiftleft(struct myfield *mf)
84f499134dSBaptiste Daroussin {
85f499134dSBaptiste Daroussin 	int i, last;
86f499134dSBaptiste Daroussin 
87*d93b4d32SBaptiste Daroussin 	for (i = mf->pos; i < mf->buflen -1; i++) {
88f499134dSBaptiste Daroussin 		mf->buf[i] = mf->buf[i+1];
89f499134dSBaptiste Daroussin 	}
90f499134dSBaptiste Daroussin 
91*d93b4d32SBaptiste Daroussin 	last = mf->buflen > 0 ? mf->buflen -1 : 0;
92f499134dSBaptiste Daroussin 	mf->buf[last] = '\0';
93*d93b4d32SBaptiste Daroussin 		mf->buflen = last;
94f499134dSBaptiste Daroussin }
95c76f0793SBaptiste Daroussin 
968c4f4028SBaptiste Daroussin static void print_bottomdesc(struct myfield *mf)
978c4f4028SBaptiste Daroussin {
988c4f4028SBaptiste Daroussin 
998c4f4028SBaptiste Daroussin 	move(LINES-1, 2);
1008c4f4028SBaptiste Daroussin 	clrtoeol();
1018c4f4028SBaptiste Daroussin 	if (mf->bottomdesc != NULL) {
1028c4f4028SBaptiste Daroussin 		addstr(mf->bottomdesc);
1038c4f4028SBaptiste Daroussin 		refresh();
1048c4f4028SBaptiste Daroussin 	}
1058c4f4028SBaptiste Daroussin }
1068c4f4028SBaptiste Daroussin 
107*d93b4d32SBaptiste Daroussin int
108*d93b4d32SBaptiste Daroussin return_values(struct bsddialog_conf *conf, struct buttons bs, int nitems,
109*d93b4d32SBaptiste Daroussin     struct bsddialog_formitem *items, FORM *form, FIELD **cfield)
110*d93b4d32SBaptiste Daroussin {
111*d93b4d32SBaptiste Daroussin 	int i, output;
112*d93b4d32SBaptiste Daroussin 	struct myfield *mf;
113*d93b4d32SBaptiste Daroussin 
114*d93b4d32SBaptiste Daroussin 	output = bs.value[bs.curr];
115*d93b4d32SBaptiste Daroussin 	if (output == BSDDIALOG_HELP && conf->form.value_withhelp == false)
116*d93b4d32SBaptiste Daroussin 		return output;
117*d93b4d32SBaptiste Daroussin 	if (output == BSDDIALOG_EXTRA && conf->form.value_withextra == false)
118*d93b4d32SBaptiste Daroussin 		return output;
119*d93b4d32SBaptiste Daroussin 	if (output == BSDDIALOG_CANCEL && conf->form.value_withcancel == false)
120*d93b4d32SBaptiste Daroussin 		return output;
121*d93b4d32SBaptiste Daroussin 	if (output == BSDDIALOG_GENERIC1 || output == BSDDIALOG_GENERIC2)
122*d93b4d32SBaptiste Daroussin 		return output;
123*d93b4d32SBaptiste Daroussin 
124*d93b4d32SBaptiste Daroussin 	/* BSDDIALOG_OK */
125*d93b4d32SBaptiste Daroussin 	form_driver(form, REQ_NEXT_FIELD);
126*d93b4d32SBaptiste Daroussin 	form_driver(form, REQ_PREV_FIELD);
127*d93b4d32SBaptiste Daroussin 	for (i=0; i<nitems; i++) {
128*d93b4d32SBaptiste Daroussin 		mf = GETMYFIELD(cfield[i]);
129*d93b4d32SBaptiste Daroussin 		items[i].value = strdup(mf->buf);
130*d93b4d32SBaptiste Daroussin 		if (items[i].value == NULL)
131*d93b4d32SBaptiste Daroussin 			RETURN_ERROR("Cannot allocate memory for form value");
132*d93b4d32SBaptiste Daroussin 	}
133*d93b4d32SBaptiste Daroussin 
134*d93b4d32SBaptiste Daroussin 	return (output);
135*d93b4d32SBaptiste Daroussin }
136*d93b4d32SBaptiste Daroussin 
137c76f0793SBaptiste Daroussin static int
138f499134dSBaptiste Daroussin form_handler(struct bsddialog_conf *conf, WINDOW *widget, int y, int cols,
139f499134dSBaptiste Daroussin     struct buttons bs, WINDOW *formwin, FORM *form, FIELD **cfield, int nitems,
140f499134dSBaptiste Daroussin     struct bsddialog_formitem *items)
141c76f0793SBaptiste Daroussin {
142f499134dSBaptiste Daroussin 	bool loop, buttupdate, informwin = true;
143f499134dSBaptiste Daroussin 	int i, input, output;
144f499134dSBaptiste Daroussin 	struct myfield *mf;
145c76f0793SBaptiste Daroussin 
146f499134dSBaptiste Daroussin 	mf = GETMYFIELD2(form);
1478c4f4028SBaptiste Daroussin 	print_bottomdesc(mf);
148*d93b4d32SBaptiste Daroussin 	pos_form_cursor(form);
149*d93b4d32SBaptiste Daroussin 	form_driver(form, REQ_END_LINE);
150*d93b4d32SBaptiste Daroussin 	mf->pos = MIN(mf->buflen, mf->maxpos);
151*d93b4d32SBaptiste Daroussin 	curs_set(2);
152*d93b4d32SBaptiste Daroussin 	bs.curr = -1;
153*d93b4d32SBaptiste Daroussin 	loop = buttupdate = true;
154c76f0793SBaptiste Daroussin 	while(loop) {
155c76f0793SBaptiste Daroussin 		if (buttupdate) {
156f499134dSBaptiste Daroussin 			draw_buttons(widget, y, cols, bs, !informwin);
157c76f0793SBaptiste Daroussin 			wrefresh(widget);
158c76f0793SBaptiste Daroussin 			buttupdate = false;
159c76f0793SBaptiste Daroussin 		}
160f499134dSBaptiste Daroussin 		wrefresh(formwin);
161c76f0793SBaptiste Daroussin 		input = getch();
162c76f0793SBaptiste Daroussin 		switch(input) {
163f499134dSBaptiste Daroussin 		case KEY_ENTER:
164f499134dSBaptiste Daroussin 		case 10: /* Enter */
165f499134dSBaptiste Daroussin 			if (informwin)
166c76f0793SBaptiste Daroussin 				break;
1678c4f4028SBaptiste Daroussin 			loop = false;
168*d93b4d32SBaptiste Daroussin 			output = return_values(conf, bs, nitems, items, form, cfield);
169c76f0793SBaptiste Daroussin 			break;
170c76f0793SBaptiste Daroussin 		case 27: /* Esc */
171c76f0793SBaptiste Daroussin 			output = BSDDIALOG_ESC;
172c76f0793SBaptiste Daroussin 			loop = false;
173c76f0793SBaptiste Daroussin 			break;
174f499134dSBaptiste Daroussin 		case '\t': /* TAB */
175f499134dSBaptiste Daroussin 			if (informwin) {
176c76f0793SBaptiste Daroussin 				bs.curr = 0;
177f499134dSBaptiste Daroussin 				informwin = false;
178c76f0793SBaptiste Daroussin 				curs_set(0);
179c76f0793SBaptiste Daroussin 			} else {
180c76f0793SBaptiste Daroussin 				bs.curr++;
181f499134dSBaptiste Daroussin 				informwin = bs.curr >= (int) bs.nbuttons ?
182f499134dSBaptiste Daroussin 				    true : false;
183f499134dSBaptiste Daroussin 				if (informwin) {
184c76f0793SBaptiste Daroussin 					curs_set(2);
185c76f0793SBaptiste Daroussin 					pos_form_cursor(form);
186c76f0793SBaptiste Daroussin 				}
187c76f0793SBaptiste Daroussin 			}
188c76f0793SBaptiste Daroussin 			buttupdate = true;
189c76f0793SBaptiste Daroussin 			break;
190c76f0793SBaptiste Daroussin 		case KEY_LEFT:
191f499134dSBaptiste Daroussin 			if (informwin) {
192c76f0793SBaptiste Daroussin 				form_driver(form, REQ_PREV_CHAR);
193f499134dSBaptiste Daroussin 				mf = GETMYFIELD2(form);
194f499134dSBaptiste Daroussin 				if (mf->pos > 0)
195f499134dSBaptiste Daroussin 					mf->pos -= 1;
196c76f0793SBaptiste Daroussin 			} else {
197c76f0793SBaptiste Daroussin 				if (bs.curr > 0) {
198c76f0793SBaptiste Daroussin 					bs.curr--;
199c76f0793SBaptiste Daroussin 					buttupdate = true;
200c76f0793SBaptiste Daroussin 				}
201c76f0793SBaptiste Daroussin 			}
202c76f0793SBaptiste Daroussin 			break;
203c76f0793SBaptiste Daroussin 		case KEY_RIGHT:
204f499134dSBaptiste Daroussin 			if (informwin) {
205f499134dSBaptiste Daroussin 				mf = GETMYFIELD2(form);
206*d93b4d32SBaptiste Daroussin 				if (mf->pos >= mf->buflen)
207f499134dSBaptiste Daroussin 					break;
208f499134dSBaptiste Daroussin 				mf->pos += 1;
209c76f0793SBaptiste Daroussin 				form_driver(form, REQ_NEXT_CHAR);
210c76f0793SBaptiste Daroussin 			} else {
211c76f0793SBaptiste Daroussin 				if (bs.curr < (int) bs.nbuttons - 1) {
212c76f0793SBaptiste Daroussin 					bs.curr++;
213c76f0793SBaptiste Daroussin 					buttupdate = true;
214c76f0793SBaptiste Daroussin 				}
215c76f0793SBaptiste Daroussin 			}
216c76f0793SBaptiste Daroussin 			break;
217c76f0793SBaptiste Daroussin 		case KEY_UP:
218c76f0793SBaptiste Daroussin 			if (nitems < 2)
219c76f0793SBaptiste Daroussin 				break;
220f499134dSBaptiste Daroussin 			set_field_fore(current_field(form), t.form.fieldcolor);
221f499134dSBaptiste Daroussin 			set_field_back(current_field(form), t.form.fieldcolor);
222c76f0793SBaptiste Daroussin 			form_driver(form, REQ_PREV_FIELD);
223c76f0793SBaptiste Daroussin 			form_driver(form, REQ_END_LINE);
224f499134dSBaptiste Daroussin 			mf = GETMYFIELD2(form);
2258c4f4028SBaptiste Daroussin 			print_bottomdesc(mf);
226*d93b4d32SBaptiste Daroussin 			mf->pos = MIN(mf->buflen, mf->maxpos);
227f499134dSBaptiste Daroussin 			set_field_fore(current_field(form), t.form.f_fieldcolor);
228f499134dSBaptiste Daroussin 			set_field_back(current_field(form), t.form.f_fieldcolor);
229c76f0793SBaptiste Daroussin 			break;
230c76f0793SBaptiste Daroussin 		case KEY_DOWN:
231c76f0793SBaptiste Daroussin 			if (nitems < 2)
232c76f0793SBaptiste Daroussin 				break;
233f499134dSBaptiste Daroussin 			set_field_fore(current_field(form), t.form.fieldcolor);
234f499134dSBaptiste Daroussin 			set_field_back(current_field(form), t.form.fieldcolor);
235c76f0793SBaptiste Daroussin 			form_driver(form, REQ_NEXT_FIELD);
236c76f0793SBaptiste Daroussin 			form_driver(form, REQ_END_LINE);
237f499134dSBaptiste Daroussin 			mf = GETMYFIELD2(form);
2388c4f4028SBaptiste Daroussin 			print_bottomdesc(mf);
239*d93b4d32SBaptiste Daroussin 			mf->pos = MIN(mf->buflen, mf->maxpos);
240f499134dSBaptiste Daroussin 			set_field_fore(current_field(form), t.form.f_fieldcolor);
241f499134dSBaptiste Daroussin 			set_field_back(current_field(form), t.form.f_fieldcolor);
242c76f0793SBaptiste Daroussin 			break;
243c76f0793SBaptiste Daroussin 		case KEY_BACKSPACE:
244f499134dSBaptiste Daroussin 		case 127: /* Backspace */
245f499134dSBaptiste Daroussin 			mf = GETMYFIELD2(form);
246f499134dSBaptiste Daroussin 			if (mf->pos <= 0)
247f499134dSBaptiste Daroussin 				break;
248c76f0793SBaptiste Daroussin 			form_driver(form, REQ_DEL_PREV);
249*d93b4d32SBaptiste Daroussin 			form_driver(form, REQ_BEG_LINE);
250*d93b4d32SBaptiste Daroussin 			mf->pos = mf->pos - 1;
251*d93b4d32SBaptiste Daroussin 			for (i=0; i<mf->pos; i++)
252*d93b4d32SBaptiste Daroussin 				form_driver(form, REQ_NEXT_CHAR);
253f499134dSBaptiste Daroussin 			shiftleft(mf);
254c76f0793SBaptiste Daroussin 			break;
255c76f0793SBaptiste Daroussin 		case KEY_DC:
256c76f0793SBaptiste Daroussin 			form_driver(form, REQ_DEL_CHAR);
257f499134dSBaptiste Daroussin 			mf = GETMYFIELD2(form);
258*d93b4d32SBaptiste Daroussin 			if (mf->pos < mf->buflen)
259f499134dSBaptiste Daroussin 				shiftleft(mf);
260f499134dSBaptiste Daroussin 			break;
261f499134dSBaptiste Daroussin 		case KEY_F(1):
2628c4f4028SBaptiste Daroussin 			if (conf->f1_file == NULL && conf->f1_message == NULL)
263f499134dSBaptiste Daroussin 				break;
264f499134dSBaptiste Daroussin 			if (f1help(conf) != 0)
265f499134dSBaptiste Daroussin 				return BSDDIALOG_ERROR;
266f499134dSBaptiste Daroussin 			/* No Break */
267f499134dSBaptiste Daroussin 		case KEY_RESIZE:
268f499134dSBaptiste Daroussin 			output = REDRAWFORM;
269f499134dSBaptiste Daroussin 			loop = false;
270c76f0793SBaptiste Daroussin 			break;
271c76f0793SBaptiste Daroussin 		default:
272f499134dSBaptiste Daroussin 			/*
273f499134dSBaptiste Daroussin 			 * user input, add unicode chars to "public" buffer
274f499134dSBaptiste Daroussin 			 */
275f499134dSBaptiste Daroussin 			if (informwin) {
276f499134dSBaptiste Daroussin 				mf = GETMYFIELD2(form);
277f499134dSBaptiste Daroussin 				if (mf->secure)
278f499134dSBaptiste Daroussin 					form_driver(form, mf->securech);
279f499134dSBaptiste Daroussin 				else
280c76f0793SBaptiste Daroussin 					form_driver(form, input);
281f499134dSBaptiste Daroussin 				insertch(mf, input);
282f499134dSBaptiste Daroussin 			}
283f499134dSBaptiste Daroussin 			else {
284f499134dSBaptiste Daroussin 				for (i = 0; i < (int) bs.nbuttons; i++) {
285f499134dSBaptiste Daroussin 					if (tolower(input) ==
286f499134dSBaptiste Daroussin 					    tolower((bs.label[i])[0])) {
287*d93b4d32SBaptiste Daroussin 						bs.curr = i;
288*d93b4d32SBaptiste Daroussin 						output = return_values(conf, bs,
289*d93b4d32SBaptiste Daroussin 						    nitems, items, form, cfield);
290f499134dSBaptiste Daroussin 						loop = false;
291f499134dSBaptiste Daroussin 					}
292f499134dSBaptiste Daroussin 				}
293c76f0793SBaptiste Daroussin 			}
294c76f0793SBaptiste Daroussin 			break;
295c76f0793SBaptiste Daroussin 		}
296c76f0793SBaptiste Daroussin 	}
297c76f0793SBaptiste Daroussin 
298c76f0793SBaptiste Daroussin 	curs_set(0);
299c76f0793SBaptiste Daroussin 
300c76f0793SBaptiste Daroussin 	return output;
301c76f0793SBaptiste Daroussin }
302c76f0793SBaptiste Daroussin 
303f499134dSBaptiste Daroussin static void
304f499134dSBaptiste Daroussin form_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w,
305f499134dSBaptiste Daroussin     char *text, int linelen, unsigned int *formheight, int nitems,
306f499134dSBaptiste Daroussin     struct buttons bs)
307c76f0793SBaptiste Daroussin {
308f499134dSBaptiste Daroussin 	int textrow, menusize;
309f499134dSBaptiste Daroussin 
310f499134dSBaptiste Daroussin 	textrow = text != NULL && strlen(text) > 0 ? 1 : 0;
311f499134dSBaptiste Daroussin 
312f499134dSBaptiste Daroussin 	if (cols == BSDDIALOG_AUTOSIZE) {
313f499134dSBaptiste Daroussin 		*w = VBORDERS;
314f499134dSBaptiste Daroussin 		/* buttons size */
315f499134dSBaptiste Daroussin 		*w += bs.nbuttons * bs.sizebutton;
316f499134dSBaptiste Daroussin 		*w += bs.nbuttons > 0 ? (bs.nbuttons-1) * t.button.space : 0;
317f499134dSBaptiste Daroussin 		/* line size */
318f499134dSBaptiste Daroussin 		*w = MAX(*w, linelen + 3);
3198c4f4028SBaptiste Daroussin 		/* conf.auto_minwidth */
3208c4f4028SBaptiste Daroussin 		*w = MAX(*w, (int)conf->auto_minwidth);
321f499134dSBaptiste Daroussin 		/*
322f499134dSBaptiste Daroussin 		* avoid terminal overflow,
323f499134dSBaptiste Daroussin 		* -1 fix false negative with big menu over the terminal and
324f499134dSBaptiste Daroussin 		* autosize, for example "portconfig /usr/ports/www/apache24/".
325f499134dSBaptiste Daroussin 		*/
326f499134dSBaptiste Daroussin 		*w = MIN(*w, widget_max_width(conf)-1);
327f499134dSBaptiste Daroussin 	}
328f499134dSBaptiste Daroussin 
329f499134dSBaptiste Daroussin 	if (rows == BSDDIALOG_AUTOSIZE) {
330f499134dSBaptiste Daroussin 		*h = HBORDERS + 2 /* buttons */ + textrow;
331f499134dSBaptiste Daroussin 
332f499134dSBaptiste Daroussin 		if (*formheight == 0) {
333f499134dSBaptiste Daroussin 			*h += nitems + 2;
334f499134dSBaptiste Daroussin 			*h = MIN(*h, widget_max_height(conf));
335f499134dSBaptiste Daroussin 			menusize = MIN(nitems + 2, *h - (HBORDERS + 2 + textrow));
336f499134dSBaptiste Daroussin 			menusize -=2;
337f499134dSBaptiste Daroussin 			*formheight = menusize < 0 ? 0 : menusize;
338f499134dSBaptiste Daroussin 		}
339f499134dSBaptiste Daroussin 		else /* h autosize with a fixed formheight */
340f499134dSBaptiste Daroussin 			*h = *h + *formheight + 2;
341f499134dSBaptiste Daroussin 
3428c4f4028SBaptiste Daroussin 		/* conf.auto_minheight */
3438c4f4028SBaptiste Daroussin 		*h = MAX(*h, (int)conf->auto_minheight);
344f499134dSBaptiste Daroussin 		/* avoid terminal overflow */
345f499134dSBaptiste Daroussin 		*h = MIN(*h, widget_max_height(conf));
346f499134dSBaptiste Daroussin 	}
347f499134dSBaptiste Daroussin 	else {
348f499134dSBaptiste Daroussin 		if (*formheight == 0)
349f499134dSBaptiste Daroussin 			*formheight = MIN(rows-6-textrow, nitems);
350f499134dSBaptiste Daroussin 	}
351f499134dSBaptiste Daroussin }
352f499134dSBaptiste Daroussin 
353f499134dSBaptiste Daroussin static int
354f499134dSBaptiste Daroussin form_checksize(int rows, int cols, char *text, int formheight, int nitems,
355f499134dSBaptiste Daroussin     struct buttons bs)
356f499134dSBaptiste Daroussin {
357f499134dSBaptiste Daroussin 	int mincols, textrow, formrows;
358f499134dSBaptiste Daroussin 
359f499134dSBaptiste Daroussin 	mincols = VBORDERS;
360f499134dSBaptiste Daroussin 	/* buttons */
361f499134dSBaptiste Daroussin 	mincols += bs.nbuttons * bs.sizebutton;
362f499134dSBaptiste Daroussin 	mincols += bs.nbuttons > 0 ? (bs.nbuttons-1) * t.button.space : 0;
363f499134dSBaptiste Daroussin 	/* line, comment to permet some cols hidden */
364f499134dSBaptiste Daroussin 	/* mincols = MAX(mincols, linelen); */
365f499134dSBaptiste Daroussin 
366f499134dSBaptiste Daroussin 	if (cols < mincols)
367f499134dSBaptiste Daroussin 		RETURN_ERROR("Few cols, width < size buttons or "\
368f499134dSBaptiste Daroussin 		    "labels + forms");
369f499134dSBaptiste Daroussin 
370f499134dSBaptiste Daroussin 	textrow = text != NULL && strlen(text) > 0 ? 1 : 0;
371f499134dSBaptiste Daroussin 
372f499134dSBaptiste Daroussin 	if (nitems > 0 && formheight == 0)
373f499134dSBaptiste Daroussin 		RETURN_ERROR("fields > 0 but formheight == 0, probably "\
374f499134dSBaptiste Daroussin 		    "terminal too small");
375f499134dSBaptiste Daroussin 
376f499134dSBaptiste Daroussin 	formrows = nitems > 0 ? 3 : 0;
377f499134dSBaptiste Daroussin 	if (rows < 2  + 2 + formrows + textrow)
378f499134dSBaptiste Daroussin 		RETURN_ERROR("Few lines for this menus");
379f499134dSBaptiste Daroussin 
380f499134dSBaptiste Daroussin 	return 0;
381f499134dSBaptiste Daroussin }
382f499134dSBaptiste Daroussin 
383f499134dSBaptiste Daroussin int
384f499134dSBaptiste Daroussin bsddialog_form(struct bsddialog_conf *conf, char* text, int rows, int cols,
385f499134dSBaptiste Daroussin     unsigned int formheight, unsigned int nitems,
386f499134dSBaptiste Daroussin     struct bsddialog_formitem *items)
387f499134dSBaptiste Daroussin {
388f499134dSBaptiste Daroussin 	WINDOW *widget, *formwin, *textpad, *shadow;
389f499134dSBaptiste Daroussin 	int i, output, color, y, x, h, w, htextpad;
390f499134dSBaptiste Daroussin 	FIELD **cfield;
391c76f0793SBaptiste Daroussin 	FORM *form;
392c76f0793SBaptiste Daroussin 	struct buttons bs;
393f499134dSBaptiste Daroussin 	struct myfield *myfields;
394f499134dSBaptiste Daroussin 	unsigned long maxline;
395c76f0793SBaptiste Daroussin 
396f499134dSBaptiste Daroussin 	/* disable form scrolling like dialog */
397f499134dSBaptiste Daroussin 	if (formheight < nitems)
398f499134dSBaptiste Daroussin 		formheight = nitems;
399c76f0793SBaptiste Daroussin 
400*d93b4d32SBaptiste Daroussin 	for (i = 0; i < (int)nitems; i++) {
401*d93b4d32SBaptiste Daroussin 		if (items[i].maxvaluelen == 0)
402*d93b4d32SBaptiste Daroussin 			RETURN_ERROR("maxvaluelen cannot be zero");
403*d93b4d32SBaptiste Daroussin 		if (items[i].fieldlen == 0)
404*d93b4d32SBaptiste Daroussin 			RETURN_ERROR("fieldlen cannot be zero");
405*d93b4d32SBaptiste Daroussin 		if (items[i].fieldlen > items[i].maxvaluelen)
406*d93b4d32SBaptiste Daroussin 			RETURN_ERROR("fieldlen cannot be > maxvaluelen");
407*d93b4d32SBaptiste Daroussin 	}
408*d93b4d32SBaptiste Daroussin 
409f499134dSBaptiste Daroussin 	maxline = 0;
410f499134dSBaptiste Daroussin 	myfields = malloc(nitems * sizeof(struct myfield));
411f499134dSBaptiste Daroussin 	cfield = calloc(nitems + 1, sizeof(FIELD*));
412f499134dSBaptiste Daroussin 	for (i=0; i < (int)nitems; i++) {
413f499134dSBaptiste Daroussin 		cfield[i] = new_field(1, items[i].fieldlen, items[i].yfield-1,
414f499134dSBaptiste Daroussin 		    items[i].xfield-1, 0, 0);
415f499134dSBaptiste Daroussin 		field_opts_off(cfield[i], O_STATIC);
416f499134dSBaptiste Daroussin 		set_max_field(cfield[i], items[i].maxvaluelen);
417f499134dSBaptiste Daroussin 		set_field_buffer(cfield[i], 0, items[i].init);
418f499134dSBaptiste Daroussin 
419*d93b4d32SBaptiste Daroussin 		myfields[i].buf = malloc(items[i].maxvaluelen + 1);
420*d93b4d32SBaptiste Daroussin 		memset(myfields[i].buf, 0, items[i].maxvaluelen + 1); // end with '\0' for strdup
421*d93b4d32SBaptiste Daroussin 		strncpy(myfields[i].buf, items[i].init, items[i].maxvaluelen);
422*d93b4d32SBaptiste Daroussin 
423*d93b4d32SBaptiste Daroussin 		myfields[i].buflen = strlen(myfields[i].buf);
424*d93b4d32SBaptiste Daroussin 
425*d93b4d32SBaptiste Daroussin 		myfields[i].maxpos = items[i].maxvaluelen -1;
426*d93b4d32SBaptiste Daroussin 		myfields[i].pos = MIN(myfields[i].buflen, myfields[i].maxpos);
427*d93b4d32SBaptiste Daroussin 
4288c4f4028SBaptiste Daroussin 		myfields[i].bottomdesc = items[i].bottomdesc;
429f499134dSBaptiste Daroussin 		set_field_userptr(cfield[i], &myfields[i]);
430f499134dSBaptiste Daroussin 
431f499134dSBaptiste Daroussin 		field_opts_off(cfield[i], O_AUTOSKIP);
432f499134dSBaptiste Daroussin 		field_opts_off(cfield[i], O_BLANK);
433f499134dSBaptiste Daroussin 		/* field_opts_off(field[i], O_BS_OVERLOAD); */
434f499134dSBaptiste Daroussin 
435f499134dSBaptiste Daroussin 		if (ISFIELDHIDDEN(items[i])) {
436f499134dSBaptiste Daroussin 			/* field_opts_off(field[i], O_PUBLIC); old hidden */
437f499134dSBaptiste Daroussin 			myfields[i].secure = true;
438f499134dSBaptiste Daroussin 			myfields[i].securech = ' ';
439f499134dSBaptiste Daroussin 			if (conf->form.securech != '\0')
440f499134dSBaptiste Daroussin 				myfields[i].securech = conf->form.securech;
441f499134dSBaptiste Daroussin 		}
442f499134dSBaptiste Daroussin 		else myfields[i].secure = false;
443f499134dSBaptiste Daroussin 
444f499134dSBaptiste Daroussin 		if (ISFIELDREADONLY(items[i])) {
445f499134dSBaptiste Daroussin 			field_opts_off(cfield[i], O_EDIT);
446f499134dSBaptiste Daroussin 			field_opts_off(cfield[i], O_ACTIVE);
447f499134dSBaptiste Daroussin 			color = t.form.readonlycolor;
448f499134dSBaptiste Daroussin 		} else {
449f499134dSBaptiste Daroussin 			color = i == 0 ? t.form.f_fieldcolor : t.form.fieldcolor;
450f499134dSBaptiste Daroussin 		}
451f499134dSBaptiste Daroussin 		set_field_fore(cfield[i], color);
452f499134dSBaptiste Daroussin 		set_field_back(cfield[i], color);
453f499134dSBaptiste Daroussin 
454f499134dSBaptiste Daroussin 		maxline = MAX(maxline, items[i].xlabel + strlen(items[i].label));
455f499134dSBaptiste Daroussin 		maxline = MAX(maxline, items[i].xfield + items[i].fieldlen);
456f499134dSBaptiste Daroussin 	}
457f499134dSBaptiste Daroussin 	cfield[i] = NULL;
458f499134dSBaptiste Daroussin 
459f499134dSBaptiste Daroussin 	 /* disable focus with 1 item (inputbox or passwordbox) */
460f499134dSBaptiste Daroussin 	if (formheight == 1 && nitems == 1 && strlen(items[0].label) == 0 &&
461f499134dSBaptiste Daroussin 	    items[0].xfield == 1 ) {
4628c4f4028SBaptiste Daroussin 		set_field_fore(cfield[0], t.dialog.color);
4638c4f4028SBaptiste Daroussin 		set_field_back(cfield[0], t.dialog.color);
464f499134dSBaptiste Daroussin 	}
465c76f0793SBaptiste Daroussin 
466c76f0793SBaptiste Daroussin 	get_buttons(conf, &bs, BUTTONLABEL(ok_label), BUTTONLABEL(extra_label),
467c76f0793SBaptiste Daroussin 	    BUTTONLABEL(cancel_label), BUTTONLABEL(help_label));
468c76f0793SBaptiste Daroussin 
469f499134dSBaptiste Daroussin 	if (set_widget_size(conf, rows, cols, &h, &w) != 0)
470f499134dSBaptiste Daroussin 		return BSDDIALOG_ERROR;
471f499134dSBaptiste Daroussin 	form_autosize(conf, rows, cols, &h, &w, text, maxline, &formheight,
472f499134dSBaptiste Daroussin 	    nitems, bs);
473f499134dSBaptiste Daroussin 	if (form_checksize(h, w, text, formheight, nitems, bs) != 0)
474f499134dSBaptiste Daroussin 		return BSDDIALOG_ERROR;
475f499134dSBaptiste Daroussin 	if (set_widget_position(conf, &y, &x, h, w) != 0)
476f499134dSBaptiste Daroussin 		return BSDDIALOG_ERROR;
477c76f0793SBaptiste Daroussin 
478f499134dSBaptiste Daroussin 	if (new_widget_withtextpad(conf, &shadow, &widget, y, x, h, w, RAISED,
479f499134dSBaptiste Daroussin 	    &textpad, &htextpad, text, true) != 0)
480f499134dSBaptiste Daroussin 		return BSDDIALOG_ERROR;
481c76f0793SBaptiste Daroussin 
482f499134dSBaptiste Daroussin 	prefresh(textpad, 0, 0, y + 1, x + 1 + t.text.hmargin,
483f499134dSBaptiste Daroussin 	    y + h - formheight, x + 1 + w - t.text.hmargin);
484c76f0793SBaptiste Daroussin 
485f499134dSBaptiste Daroussin 	formwin = new_boxed_window(conf, y + h - 3 - formheight -2, x +1,
486f499134dSBaptiste Daroussin 	    formheight+2, w-2, LOWERED);
487c76f0793SBaptiste Daroussin 
488f499134dSBaptiste Daroussin 	form = new_form(cfield);
489f499134dSBaptiste Daroussin 	set_form_win(form, formwin);
490f499134dSBaptiste Daroussin 	/* should be formheight */
491f499134dSBaptiste Daroussin 	set_form_sub(form, derwin(formwin, nitems, w-4, 1, 1));
492c76f0793SBaptiste Daroussin 	post_form(form);
493c76f0793SBaptiste Daroussin 
494f499134dSBaptiste Daroussin 	for (i=0; i < (int)nitems; i++)
495f499134dSBaptiste Daroussin 		mvwaddstr(formwin, items[i].ylabel, items[i].xlabel, items[i].label);
496c76f0793SBaptiste Daroussin 
497f499134dSBaptiste Daroussin 	wrefresh(formwin);
498c76f0793SBaptiste Daroussin 
499f499134dSBaptiste Daroussin 	do {
500f499134dSBaptiste Daroussin 		output = form_handler(conf, widget, h-2, w, bs, formwin, form,
501f499134dSBaptiste Daroussin 		    cfield, nitems, items);
502f499134dSBaptiste Daroussin 
503f499134dSBaptiste Daroussin 		if(update_widget_withtextpad(conf, shadow, widget, h, w,
504f499134dSBaptiste Daroussin 		    RAISED, textpad, &htextpad, text, true) != 0)
505f499134dSBaptiste Daroussin 		return BSDDIALOG_ERROR;
506f499134dSBaptiste Daroussin 
507f499134dSBaptiste Daroussin 		draw_buttons(widget, h-2, w, bs, true);
508f499134dSBaptiste Daroussin 		wrefresh(widget);
509f499134dSBaptiste Daroussin 
510f499134dSBaptiste Daroussin 		prefresh(textpad, 0, 0, y + 1, x + 1 + t.text.hmargin,
511f499134dSBaptiste Daroussin 		    y + h - formheight, x + 1 + w - t.text.hmargin);
512f499134dSBaptiste Daroussin 
513f499134dSBaptiste Daroussin 		draw_borders(conf, formwin, formheight+2, w-2, LOWERED);
514f499134dSBaptiste Daroussin 		/* wrefresh(formwin); */
515f499134dSBaptiste Daroussin 	} while (output == REDRAWFORM);
516c76f0793SBaptiste Daroussin 
517c76f0793SBaptiste Daroussin 	unpost_form(form);
518c76f0793SBaptiste Daroussin 	free_form(form);
519f499134dSBaptiste Daroussin 	for (i=0; i < (int)nitems; i++) {
520f499134dSBaptiste Daroussin 		free_field(cfield[i]);
521f499134dSBaptiste Daroussin 		free(myfields[i].buf);
522f499134dSBaptiste Daroussin 	}
523f499134dSBaptiste Daroussin 	free(cfield);
524f499134dSBaptiste Daroussin 	free(myfields);
525c76f0793SBaptiste Daroussin 
526f499134dSBaptiste Daroussin 	delwin(formwin);
527f499134dSBaptiste Daroussin 	end_widget_withtextpad(conf, widget, h, w, textpad, shadow);
528c76f0793SBaptiste Daroussin 
529c76f0793SBaptiste Daroussin 	return output;
530c76f0793SBaptiste Daroussin }
531