xref: /netbsd-src/lib/libform/driver.c (revision 5aefcfdc06931dd97e76246d2fe0302f7b3fe094)
1 /*	$NetBSD: driver.c,v 1.1 2000/12/17 12:04:30 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 			  /*
127 			   * Need to check here if we want to autoskip.
128 			   * we call the form driver recursively to pos
129 			   * us on the next field and then we loop back to
130 			   * ensure the next field selected can have data
131 			   * added to it
132 			   */
133 			if ((((fieldp->opts & O_STATIC) == O_STATIC) &&
134 			     (buf.length >= fieldp->cols)) ||
135 			    (((fieldp->opts & O_STATIC) != O_STATIC) &&
136 			     ((fieldp->max > 0) &&
137 			      (buf.length >= fieldp->max)))) {
138 				if ((fieldp->opts & O_AUTOSKIP) != O_AUTOSKIP)
139 					return E_REQUEST_DENIED;
140 				status = form_driver(form, REQ_NEXT_FIELD);
141 				if (status != E_OK)
142 					return status;
143 				old_field = form->cur_field;
144 				goto next_field;
145 			}
146 
147 
148 			if (fieldp->start_char > 0)
149   				pos--;
150 
151 			update_field = _formi_add_char(fieldp, pos, c);
152 
153 		} else
154 			return E_REQUEST_DENIED;
155 	} else {
156 		if (c > REQ_MAX_COMMAND)
157 			return E_UNKNOWN_COMMAND;
158 
159 		switch (c) {
160 		case REQ_NEXT_PAGE:
161 			if (form->page < form->max_page) {
162 				old_page = form->page;
163 				form->page++;
164 				update_page = 1;
165 				if (_formi_pos_first_field(form) != E_OK) {
166 					form->page = old_page;
167 					return E_REQUEST_DENIED;
168 				}
169 			} else
170 				return E_REQUEST_DENIED;
171 			break;
172 
173 		case REQ_PREV_PAGE:
174 			if (form->page > 0) {
175 				old_page = form->page;
176 				form->page--;
177 				update_page = 1;
178 				if (_formi_pos_first_field(form) != E_OK) {
179 					form->page = old_page;
180 					return E_REQUEST_DENIED;
181 				}
182 			} else
183 				return E_REQUEST_DENIED;
184 			break;
185 
186 		case REQ_FIRST_PAGE:
187 			old_page = form->page;
188 			form->page = 0;
189 			update_page = 1;
190 			if (_formi_pos_first_field(form) != E_OK) {
191 				form->page = old_page;
192 				return E_REQUEST_DENIED;
193 			}
194 			break;
195 
196 		case REQ_LAST_PAGE:
197 			old_page = form->page;
198 			form->page = form->max_page - 1;
199 			update_page = 1;
200 			if (_formi_pos_first_field(form) != E_OK) {
201 				form->page = old_page;
202 				return E_REQUEST_DENIED;
203 			}
204 			break;
205 
206 		case REQ_NEXT_FIELD:
207 			status = _formi_pos_new_field(form, _FORMI_FORWARD,
208 						      FALSE);
209 			if (status != E_OK) {
210 				return status;
211 			}
212 
213 			update_field = 1;
214 			break;
215 
216 		case REQ_PREV_FIELD:
217 			status = _formi_pos_new_field(form, _FORMI_BACKWARD,
218 						      FALSE);
219 
220 			if (status != E_OK)
221 				return status;
222 
223 			update_field = 1;
224 			break;
225 
226 		case REQ_FIRST_FIELD:
227 			form->cur_field = 0;
228 			update_field = 1;
229 			break;
230 
231 		case REQ_LAST_FIELD:
232 			form->cur_field = form->field_count - 1;
233 			update_field = 1;
234 			break;
235 
236 		case REQ_SNEXT_FIELD:
237 			status = _formi_pos_new_field(form, _FORMI_FORWARD,
238 						      TRUE);
239 			if (status != E_OK)
240 				return status;
241 
242 			update_field = 1;
243 			break;
244 
245 		case REQ_SPREV_FIELD:
246 			status = _formi_pos_new_field(form, _FORMI_BACKWARD,
247 						      TRUE);
248 			if (status != E_OK)
249 				return status;
250 
251 			update_field = 1;
252 			break;
253 
254 		case REQ_SFIRST_FIELD:
255 			fieldp = CIRCLEQ_FIRST(&form->sorted_fields);
256 			form->cur_field = fieldp->index;
257 			update_field = 1;
258 			break;
259 
260 		case REQ_SLAST_FIELD:
261 			fieldp = CIRCLEQ_LAST(&form->sorted_fields);
262 			form->cur_field = fieldp->index;
263 			update_field = 1;
264 			break;
265 
266 			  /*
267 			   * The up, down, left and right field traversals
268 			   * are rolled up into a single function, allow a
269 			   * fall through to that function.
270 			   */
271 			  /* FALLTHROUGH */
272 		case REQ_LEFT_FIELD:
273 		case REQ_RIGHT_FIELD:
274 		case REQ_UP_FIELD:
275 		case REQ_DOWN_FIELD:
276 			status = traverse_form_links(form, c);
277 			if (status != E_OK)
278 				return status;
279 
280 			update_field = 1;
281 			break;
282 
283 			  /* the following commands modify the buffer, check if
284 			     this is allowed first before falling through. */
285 			  /* FALLTHROUGH */
286 		case REQ_INS_CHAR:
287 		case REQ_INS_LINE:
288 		case REQ_DEL_CHAR:
289 		case REQ_DEL_PREV:
290 		case REQ_DEL_LINE:
291 		case REQ_DEL_WORD:
292 		case REQ_CLR_EOL:
293 		case REQ_CLR_EOF:
294 		case REQ_CLR_FIELD:
295 		case REQ_OVL_MODE:
296 		case REQ_INS_MODE:
297 		case REQ_NEW_LINE:
298 			  /* check if we are allowed to edit the field and fall
299 			   * through if we are.
300 			   */
301 			if ((form->fields[form->cur_field]->opts & O_EDIT) != O_EDIT)
302 				return E_REQUEST_DENIED;
303 
304 			  /* the following manipulate the field contents, bundle
305 			     them into one function.... */
306 			  /* FALLTHROUGH */
307 		case REQ_NEXT_CHAR:
308 		case REQ_PREV_CHAR:
309 		case REQ_NEXT_LINE:
310 		case REQ_PREV_LINE:
311 		case REQ_NEXT_WORD:
312 		case REQ_PREV_WORD:
313 		case REQ_BEG_FIELD:
314 		case REQ_END_FIELD:
315 		case REQ_BEG_LINE:
316 		case REQ_END_LINE:
317 		case REQ_LEFT_CHAR:
318 		case REQ_RIGHT_CHAR:
319 		case REQ_UP_CHAR:
320 		case REQ_DOWN_CHAR:
321 		case REQ_SCR_FLINE:
322 		case REQ_SCR_BLINE:
323 		case REQ_SCR_FPAGE:
324 		case REQ_SCR_BPAGE:
325 		case REQ_SCR_FHPAGE:
326 		case REQ_SCR_BHPAGE:
327 		case REQ_SCR_FCHAR:
328 		case REQ_SCR_BCHAR:
329 		case REQ_SCR_HFLINE:
330 		case REQ_SCR_HBLINE:
331 		case REQ_SCR_HFHALF:
332 		case REQ_SCR_HBHALF:
333 			update_field = _formi_manipulate_field(form, c);
334 			break;
335 
336 		case REQ_VALIDATION:
337 			return _formi_validate_field(form);
338 			  /* NOTREACHED */
339 			break;
340 
341 		case REQ_PREV_CHOICE:
342 		case REQ_NEXT_CHOICE:
343 			update_field = _formi_field_choice(form, c);
344 			break;
345 
346 		default: /* should not need to do this, but.... */
347 			return E_UNKNOWN_COMMAND;
348 			  /* NOTREACHED */
349 			break;
350 		}
351 	}
352 
353 	if (update_field < 0)
354 		return update_field;
355 
356 	if (update_field == 1)
357 		update_page |= _formi_update_field(form, old_field);
358 
359 	if (update_page == 1)
360 		_formi_draw_page(form);
361 
362 	pos_form_cursor(form);
363 	return E_OK;
364 }
365 
366