xref: /netbsd-src/lib/libform/driver.c (revision bcc8ec9959e7b01e313d813067bfb43a3ad70551)
1 /*	$NetBSD: driver.c,v 1.2 2001/01/16 01:02:47 blymn Exp $	*/
2 
3 /*-
4  * Copyright (c) 1998-1999 Brett Lymn
5  *                         (blymn@baea.com.au, brett_lymn@yahoo.com.au)
6  * All rights reserved.
7  *
8  * This code has been donated to The NetBSD Foundation by the Author.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. The name of the author may not be used to endorse or promote products
16  *    derived from this software withough specific prior written permission
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  *
30  */
31 
32 #include <ctype.h>
33 #include "form.h"
34 #include "internals.h"
35 
36 static int
37 traverse_form_links(FORM *form, int direction);
38 
39 /*
40  * Traverse the links of the current field in the given direction until
41  * either a active & visible field is found or we return to the current
42  * field.  Direction is the REQ_{LEFT,RIGHT,UP,DOWN}_FIELD driver commands.
43  * The function returns E_OK if a valid field is found, E_REQUEST_DENIED
44  * otherwise.
45  */
46 static int
47 traverse_form_links(FORM *form, int direction)
48 {
49 	unsigned index;
50 
51 	index = form->cur_field;
52 
53 	do {
54 		switch (direction) {
55 		case REQ_LEFT_FIELD:
56 			if (form->fields[index]->left == NULL)
57 				return E_REQUEST_DENIED;
58 			index = form->fields[index]->left->index;
59 			break;
60 
61 		case REQ_RIGHT_FIELD:
62 			if (form->fields[index]->right == NULL)
63 				return E_REQUEST_DENIED;
64 			index = form->fields[index]->right->index;
65 			break;
66 
67 		case REQ_UP_FIELD:
68 			if (form->fields[index]->up == NULL)
69 				return E_REQUEST_DENIED;
70 			index = form->fields[index]->up->index;
71 			break;
72 
73 		case REQ_DOWN_FIELD:
74 			if (form->fields[index]->down == NULL)
75 				return E_REQUEST_DENIED;
76 			index = form->fields[index]->down->index;
77 			break;
78 
79 		default:
80 			return E_REQUEST_DENIED;
81 		}
82 
83 		if ((form->fields[index]->opts & (O_ACTIVE | O_VISIBLE))
84 		    == (O_ACTIVE | O_VISIBLE)) {
85 			form->cur_field = index;
86 			return E_OK;
87 		}
88 	} while (index != form->cur_field);
89 
90 	return E_REQUEST_DENIED;
91 }
92 
93 int
94 form_driver(FORM *form, int c)
95 {
96 	FIELD *fieldp;
97 	FORM_STR buf;
98 	int update_page, update_field, old_field, old_page, status;
99 	unsigned int pos;
100 
101 	if (form == NULL)
102 		return E_BAD_ARGUMENT;
103 
104 	if ((form->fields == NULL) || (*(form->fields) == NULL))
105 		return E_INVALID_FIELD;
106 
107 	if (form->posted != 1)
108 		return E_NOT_POSTED;
109 
110 	if (form->in_init == 1)
111 		return E_BAD_STATE;
112 
113 
114 	old_field = form->cur_field;
115 	update_page = update_field = 0;
116 
117 	if (c < REQ_MIN_REQUEST) {
118 		if (isprint(c)) {
119 		  next_field:
120 			fieldp = form->fields[form->cur_field];
121 			buf = fieldp->buffers[0];
122 
123 			pos = fieldp->start_char + fieldp->cursor_xpos
124 				+ fieldp->hscroll;
125 
126 			  /* check if we are allowed to edit this field */
127 			if ((fieldp->opts & O_EDIT) != O_EDIT)
128 				return E_REQUEST_DENIED;
129 
130 			  /*
131 			   * Need to check here if we want to autoskip.
132 			   * we call the form driver recursively to pos
133 			   * us on the next field and then we loop back to
134 			   * ensure the next field selected can have data
135 			   * added to it
136 			   */
137 			if ((((fieldp->opts & O_STATIC) == O_STATIC) &&
138 			     (buf.length >= fieldp->cols)) ||
139 			    (((fieldp->opts & O_STATIC) != O_STATIC) &&
140 			     ((fieldp->max > 0) &&
141 			      (buf.length >= fieldp->max)))) {
142 				if ((fieldp->opts & O_AUTOSKIP) != O_AUTOSKIP)
143 					return E_REQUEST_DENIED;
144 				status = form_driver(form, REQ_NEXT_FIELD);
145 				if (status != E_OK)
146 					return status;
147 				old_field = form->cur_field;
148 				goto next_field;
149 			}
150 
151 
152 			if (fieldp->start_char > 0)
153   				pos--;
154 
155 			update_field = _formi_add_char(fieldp, pos, c);
156 
157 		} else
158 			return E_REQUEST_DENIED;
159 	} else {
160 		if (c > REQ_MAX_COMMAND)
161 			return E_UNKNOWN_COMMAND;
162 
163 		switch (c) {
164 		case REQ_NEXT_PAGE:
165 			if (form->page < form->max_page) {
166 				old_page = form->page;
167 				form->page++;
168 				update_page = 1;
169 				if (_formi_pos_first_field(form) != E_OK) {
170 					form->page = old_page;
171 					return E_REQUEST_DENIED;
172 				}
173 			} else
174 				return E_REQUEST_DENIED;
175 			break;
176 
177 		case REQ_PREV_PAGE:
178 			if (form->page > 0) {
179 				old_page = form->page;
180 				form->page--;
181 				update_page = 1;
182 				if (_formi_pos_first_field(form) != E_OK) {
183 					form->page = old_page;
184 					return E_REQUEST_DENIED;
185 				}
186 			} else
187 				return E_REQUEST_DENIED;
188 			break;
189 
190 		case REQ_FIRST_PAGE:
191 			old_page = form->page;
192 			form->page = 0;
193 			update_page = 1;
194 			if (_formi_pos_first_field(form) != E_OK) {
195 				form->page = old_page;
196 				return E_REQUEST_DENIED;
197 			}
198 			break;
199 
200 		case REQ_LAST_PAGE:
201 			old_page = form->page;
202 			form->page = form->max_page - 1;
203 			update_page = 1;
204 			if (_formi_pos_first_field(form) != E_OK) {
205 				form->page = old_page;
206 				return E_REQUEST_DENIED;
207 			}
208 			break;
209 
210 		case REQ_NEXT_FIELD:
211 			status = _formi_pos_new_field(form, _FORMI_FORWARD,
212 						      FALSE);
213 			if (status != E_OK) {
214 				return status;
215 			}
216 
217 			update_field = 1;
218 			break;
219 
220 		case REQ_PREV_FIELD:
221 			status = _formi_pos_new_field(form, _FORMI_BACKWARD,
222 						      FALSE);
223 
224 			if (status != E_OK)
225 				return status;
226 
227 			update_field = 1;
228 			break;
229 
230 		case REQ_FIRST_FIELD:
231 			form->cur_field = 0;
232 			update_field = 1;
233 			break;
234 
235 		case REQ_LAST_FIELD:
236 			form->cur_field = form->field_count - 1;
237 			update_field = 1;
238 			break;
239 
240 		case REQ_SNEXT_FIELD:
241 			status = _formi_pos_new_field(form, _FORMI_FORWARD,
242 						      TRUE);
243 			if (status != E_OK)
244 				return status;
245 
246 			update_field = 1;
247 			break;
248 
249 		case REQ_SPREV_FIELD:
250 			status = _formi_pos_new_field(form, _FORMI_BACKWARD,
251 						      TRUE);
252 			if (status != E_OK)
253 				return status;
254 
255 			update_field = 1;
256 			break;
257 
258 		case REQ_SFIRST_FIELD:
259 			fieldp = CIRCLEQ_FIRST(&form->sorted_fields);
260 			form->cur_field = fieldp->index;
261 			update_field = 1;
262 			break;
263 
264 		case REQ_SLAST_FIELD:
265 			fieldp = CIRCLEQ_LAST(&form->sorted_fields);
266 			form->cur_field = fieldp->index;
267 			update_field = 1;
268 			break;
269 
270 			  /*
271 			   * The up, down, left and right field traversals
272 			   * are rolled up into a single function, allow a
273 			   * fall through to that function.
274 			   */
275 			  /* FALLTHROUGH */
276 		case REQ_LEFT_FIELD:
277 		case REQ_RIGHT_FIELD:
278 		case REQ_UP_FIELD:
279 		case REQ_DOWN_FIELD:
280 			status = traverse_form_links(form, c);
281 			if (status != E_OK)
282 				return status;
283 
284 			update_field = 1;
285 			break;
286 
287 			  /* the following commands modify the buffer, check if
288 			     this is allowed first before falling through. */
289 			  /* FALLTHROUGH */
290 		case REQ_INS_CHAR:
291 		case REQ_INS_LINE:
292 		case REQ_DEL_CHAR:
293 		case REQ_DEL_PREV:
294 		case REQ_DEL_LINE:
295 		case REQ_DEL_WORD:
296 		case REQ_CLR_EOL:
297 		case REQ_CLR_EOF:
298 		case REQ_CLR_FIELD:
299 		case REQ_OVL_MODE:
300 		case REQ_INS_MODE:
301 		case REQ_NEW_LINE:
302 			  /* check if we are allowed to edit the field and fall
303 			   * through if we are.
304 			   */
305 			if ((form->fields[form->cur_field]->opts & O_EDIT) != O_EDIT)
306 				return E_REQUEST_DENIED;
307 
308 			  /* the following manipulate the field contents, bundle
309 			     them into one function.... */
310 			  /* FALLTHROUGH */
311 		case REQ_NEXT_CHAR:
312 		case REQ_PREV_CHAR:
313 		case REQ_NEXT_LINE:
314 		case REQ_PREV_LINE:
315 		case REQ_NEXT_WORD:
316 		case REQ_PREV_WORD:
317 		case REQ_BEG_FIELD:
318 		case REQ_END_FIELD:
319 		case REQ_BEG_LINE:
320 		case REQ_END_LINE:
321 		case REQ_LEFT_CHAR:
322 		case REQ_RIGHT_CHAR:
323 		case REQ_UP_CHAR:
324 		case REQ_DOWN_CHAR:
325 		case REQ_SCR_FLINE:
326 		case REQ_SCR_BLINE:
327 		case REQ_SCR_FPAGE:
328 		case REQ_SCR_BPAGE:
329 		case REQ_SCR_FHPAGE:
330 		case REQ_SCR_BHPAGE:
331 		case REQ_SCR_FCHAR:
332 		case REQ_SCR_BCHAR:
333 		case REQ_SCR_HFLINE:
334 		case REQ_SCR_HBLINE:
335 		case REQ_SCR_HFHALF:
336 		case REQ_SCR_HBHALF:
337 			update_field = _formi_manipulate_field(form, c);
338 			break;
339 
340 		case REQ_VALIDATION:
341 			return _formi_validate_field(form);
342 			  /* NOTREACHED */
343 			break;
344 
345 		case REQ_PREV_CHOICE:
346 		case REQ_NEXT_CHOICE:
347 			update_field = _formi_field_choice(form, c);
348 			break;
349 
350 		default: /* should not need to do this, but.... */
351 			return E_UNKNOWN_COMMAND;
352 			  /* NOTREACHED */
353 			break;
354 		}
355 	}
356 
357 	if (update_field < 0)
358 		return update_field;
359 
360 	if (update_field == 1)
361 		update_page |= _formi_update_field(form, old_field);
362 
363 	if (update_page == 1)
364 		_formi_draw_page(form);
365 
366 	pos_form_cursor(form);
367 	return E_OK;
368 }
369 
370