driver.c revision 1.2 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 (at) baea.com.au, brett_lymn (at) 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