1*f1abc9f9Schristos /* $NetBSD: driver.c,v 1.18 2013/11/26 01:17:00 christos Exp $ */
241859428Sblymn
341859428Sblymn /*-
441859428Sblymn * Copyright (c) 1998-1999 Brett Lymn
541859428Sblymn * (blymn@baea.com.au, brett_lymn@yahoo.com.au)
641859428Sblymn * All rights reserved.
741859428Sblymn *
841859428Sblymn * This code has been donated to The NetBSD Foundation by the Author.
941859428Sblymn *
1041859428Sblymn * Redistribution and use in source and binary forms, with or without
1141859428Sblymn * modification, are permitted provided that the following conditions
1241859428Sblymn * are met:
1341859428Sblymn * 1. Redistributions of source code must retain the above copyright
1441859428Sblymn * notice, this list of conditions and the following disclaimer.
1541859428Sblymn * 2. The name of the author may not be used to endorse or promote products
16c03a48d6Swiz * derived from this software without specific prior written permission
1741859428Sblymn *
1841859428Sblymn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1941859428Sblymn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2041859428Sblymn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2141859428Sblymn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2241859428Sblymn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2341859428Sblymn * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2441859428Sblymn * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2541859428Sblymn * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2641859428Sblymn * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2741859428Sblymn * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2841859428Sblymn *
2941859428Sblymn *
3041859428Sblymn */
3141859428Sblymn
32a2ed7b2dSlukem #include <sys/cdefs.h>
33*f1abc9f9Schristos __RCSID("$NetBSD: driver.c,v 1.18 2013/11/26 01:17:00 christos Exp $");
34a2ed7b2dSlukem
3541859428Sblymn #include <ctype.h>
3641859428Sblymn #include "form.h"
3741859428Sblymn #include "internals.h"
3841859428Sblymn
3941859428Sblymn static int
4041859428Sblymn traverse_form_links(FORM *form, int direction);
4141859428Sblymn
4241859428Sblymn /*
4341859428Sblymn * Traverse the links of the current field in the given direction until
4441859428Sblymn * either a active & visible field is found or we return to the current
4541859428Sblymn * field. Direction is the REQ_{LEFT,RIGHT,UP,DOWN}_FIELD driver commands.
4641859428Sblymn * The function returns E_OK if a valid field is found, E_REQUEST_DENIED
4741859428Sblymn * otherwise.
4841859428Sblymn */
4941859428Sblymn static int
traverse_form_links(FORM * form,int direction)5041859428Sblymn traverse_form_links(FORM *form, int direction)
5141859428Sblymn {
52c64b324aSthorpej unsigned idx;
5341859428Sblymn
54c64b324aSthorpej idx = form->cur_field;
5541859428Sblymn
5641859428Sblymn do {
5741859428Sblymn switch (direction) {
5841859428Sblymn case REQ_LEFT_FIELD:
59c64b324aSthorpej if (form->fields[idx]->left == NULL)
6041859428Sblymn return E_REQUEST_DENIED;
61c64b324aSthorpej idx = form->fields[idx]->left->index;
6241859428Sblymn break;
6341859428Sblymn
6441859428Sblymn case REQ_RIGHT_FIELD:
65c64b324aSthorpej if (form->fields[idx]->right == NULL)
6641859428Sblymn return E_REQUEST_DENIED;
67c64b324aSthorpej idx = form->fields[idx]->right->index;
6841859428Sblymn break;
6941859428Sblymn
7041859428Sblymn case REQ_UP_FIELD:
71c64b324aSthorpej if (form->fields[idx]->up == NULL)
7241859428Sblymn return E_REQUEST_DENIED;
73c64b324aSthorpej idx = form->fields[idx]->up->index;
7441859428Sblymn break;
7541859428Sblymn
7641859428Sblymn case REQ_DOWN_FIELD:
77c64b324aSthorpej if (form->fields[idx]->down == NULL)
7841859428Sblymn return E_REQUEST_DENIED;
79c64b324aSthorpej idx = form->fields[idx]->down->index;
8041859428Sblymn break;
8141859428Sblymn
8241859428Sblymn default:
8341859428Sblymn return E_REQUEST_DENIED;
8441859428Sblymn }
8541859428Sblymn
86c64b324aSthorpej if ((form->fields[idx]->opts & (O_ACTIVE | O_VISIBLE))
8741859428Sblymn == (O_ACTIVE | O_VISIBLE)) {
88c64b324aSthorpej form->cur_field = idx;
8941859428Sblymn return E_OK;
9041859428Sblymn }
91c64b324aSthorpej } while (idx != form->cur_field);
9241859428Sblymn
9341859428Sblymn return E_REQUEST_DENIED;
9441859428Sblymn }
9541859428Sblymn
9641859428Sblymn int
form_driver(FORM * form,int c)9741859428Sblymn form_driver(FORM *form, int c)
9841859428Sblymn {
9941859428Sblymn FIELD *fieldp;
10041859428Sblymn int update_page, update_field, old_field, old_page, status;
101ab600f6aSblymn int start_field;
10241859428Sblymn unsigned int pos;
10341859428Sblymn
10441859428Sblymn if (form == NULL)
10541859428Sblymn return E_BAD_ARGUMENT;
10641859428Sblymn
10741859428Sblymn if ((form->fields == NULL) || (*(form->fields) == NULL))
10841859428Sblymn return E_INVALID_FIELD;
10941859428Sblymn
11041859428Sblymn if (form->posted != 1)
11141859428Sblymn return E_NOT_POSTED;
11241859428Sblymn
11341859428Sblymn if (form->in_init == 1)
11441859428Sblymn return E_BAD_STATE;
11541859428Sblymn
11641859428Sblymn
117ab600f6aSblymn old_field = start_field = form->cur_field;
11899af4c10Sblymn fieldp = form->fields[form->cur_field];
11941859428Sblymn update_page = update_field = 0;
12099af4c10Sblymn status = E_OK;
12141859428Sblymn
12241859428Sblymn if (c < REQ_MIN_REQUEST) {
123759e545dSblymn if (isprint(c) || isblank(c)) {
12469869e5cSblymn do {
12519f07fb2Sblymn pos = fieldp->start_char + fieldp->row_xpos;
12641859428Sblymn
127c0219226Sblymn /* check if we are allowed to edit this field */
128c0219226Sblymn if ((fieldp->opts & O_EDIT) != O_EDIT)
129c0219226Sblymn return E_REQUEST_DENIED;
130c0219226Sblymn
13169869e5cSblymn if ((status =
13269869e5cSblymn (_formi_add_char(fieldp, pos, c)))
13369869e5cSblymn == E_REQUEST_DENIED) {
13469869e5cSblymn
13541859428Sblymn /*
13669869e5cSblymn * Need to check here if we
13769869e5cSblymn * want to autoskip. we
13869869e5cSblymn * call the form driver
13969869e5cSblymn * recursively to pos us on
14069869e5cSblymn * the next field and then
14169869e5cSblymn * we loop back to ensure
14269869e5cSblymn * the next field selected
14369869e5cSblymn * can have data added to it
14441859428Sblymn */
14569869e5cSblymn if ((fieldp->opts & O_AUTOSKIP)
14669869e5cSblymn != O_AUTOSKIP)
14741859428Sblymn return E_REQUEST_DENIED;
14869869e5cSblymn status = form_driver(form,
14969869e5cSblymn REQ_NEXT_FIELD);
15041859428Sblymn if (status != E_OK)
15141859428Sblymn return status;
152ab600f6aSblymn
153ab600f6aSblymn /*
154ab600f6aSblymn * check if we have looped
155ab600f6aSblymn * around all the fields.
156ab600f6aSblymn * This can easily happen if
157ab600f6aSblymn * all the fields are full.
158ab600f6aSblymn */
159ab600f6aSblymn if (start_field == form->cur_field)
160ab600f6aSblymn return E_REQUEST_DENIED;
161ab600f6aSblymn
16241859428Sblymn old_field = form->cur_field;
163043f30d2Sblymn fieldp = form->fields[form->cur_field];
164ab600f6aSblymn status = _formi_add_char(fieldp,
165ab600f6aSblymn fieldp->start_char
166ab600f6aSblymn + fieldp->cursor_xpos,
167ab600f6aSblymn c);
16869869e5cSblymn } else if (status == E_INVALID_FIELD)
16969869e5cSblymn /* char failed validation, just
17069869e5cSblymn * return the status.
17169869e5cSblymn */
17269869e5cSblymn return status;
1733f76420bSblymn else if (status == E_NO_ROOM)
1743f76420bSblymn /* we will get this if the line
1753f76420bSblymn * wrapping fails. Deny the
1763f76420bSblymn * request.
1773f76420bSblymn */
1783f76420bSblymn return E_REQUEST_DENIED;
17941859428Sblymn }
18069869e5cSblymn while (status != E_OK);
18169869e5cSblymn update_field = (status == E_OK);
18241859428Sblymn } else
18341859428Sblymn return E_REQUEST_DENIED;
18441859428Sblymn } else {
18541859428Sblymn if (c > REQ_MAX_COMMAND)
18641859428Sblymn return E_UNKNOWN_COMMAND;
18741859428Sblymn
18899af4c10Sblymn if ((c >= REQ_NEXT_PAGE) && (c <= REQ_DOWN_FIELD)) {
18999af4c10Sblymn /* first check the field we are in is ok */
19099af4c10Sblymn if (_formi_validate_field(form) != E_OK)
19199af4c10Sblymn return E_INVALID_FIELD;
19299af4c10Sblymn
19399af4c10Sblymn if (form->field_term != NULL)
19499af4c10Sblymn form->field_term(form);
19599af4c10Sblymn
19699af4c10Sblymn /*
19799af4c10Sblymn * if we have a page movement then the form term
19899af4c10Sblymn * needs to be called too
19999af4c10Sblymn */
20099af4c10Sblymn if ((c <= REQ_LAST_PAGE) && (form->form_term != NULL))
20199af4c10Sblymn form->form_term(form);
20299af4c10Sblymn }
20399af4c10Sblymn
20499af4c10Sblymn
20541859428Sblymn switch (c) {
20641859428Sblymn case REQ_NEXT_PAGE:
20741859428Sblymn if (form->page < form->max_page) {
20841859428Sblymn old_page = form->page;
20941859428Sblymn form->page++;
21041859428Sblymn update_page = 1;
21141859428Sblymn if (_formi_pos_first_field(form) != E_OK) {
21241859428Sblymn form->page = old_page;
21399af4c10Sblymn status = E_REQUEST_DENIED;
21441859428Sblymn }
21541859428Sblymn } else
21699af4c10Sblymn status = E_REQUEST_DENIED;
21741859428Sblymn break;
21841859428Sblymn
21941859428Sblymn case REQ_PREV_PAGE:
22041859428Sblymn if (form->page > 0) {
22141859428Sblymn old_page = form->page;
22241859428Sblymn form->page--;
22341859428Sblymn update_page = 1;
22441859428Sblymn if (_formi_pos_first_field(form) != E_OK) {
22541859428Sblymn form->page = old_page;
22699af4c10Sblymn status = E_REQUEST_DENIED;
22741859428Sblymn }
22841859428Sblymn } else
22999af4c10Sblymn status = E_REQUEST_DENIED;
23041859428Sblymn break;
23141859428Sblymn
23241859428Sblymn case REQ_FIRST_PAGE:
23341859428Sblymn old_page = form->page;
23441859428Sblymn form->page = 0;
23541859428Sblymn update_page = 1;
23641859428Sblymn if (_formi_pos_first_field(form) != E_OK) {
23741859428Sblymn form->page = old_page;
23899af4c10Sblymn status = E_REQUEST_DENIED;
23941859428Sblymn }
24041859428Sblymn break;
24141859428Sblymn
24241859428Sblymn case REQ_LAST_PAGE:
24341859428Sblymn old_page = form->page;
24441859428Sblymn form->page = form->max_page - 1;
24541859428Sblymn update_page = 1;
24641859428Sblymn if (_formi_pos_first_field(form) != E_OK) {
24741859428Sblymn form->page = old_page;
24899af4c10Sblymn status = E_REQUEST_DENIED;
24941859428Sblymn }
25041859428Sblymn break;
25141859428Sblymn
25241859428Sblymn case REQ_NEXT_FIELD:
25341859428Sblymn status = _formi_pos_new_field(form, _FORMI_FORWARD,
25441859428Sblymn FALSE);
25541859428Sblymn update_field = 1;
25641859428Sblymn break;
25741859428Sblymn
25841859428Sblymn case REQ_PREV_FIELD:
25941859428Sblymn status = _formi_pos_new_field(form, _FORMI_BACKWARD,
26041859428Sblymn FALSE);
26141859428Sblymn update_field = 1;
26241859428Sblymn break;
26341859428Sblymn
26441859428Sblymn case REQ_FIRST_FIELD:
26541859428Sblymn form->cur_field = 0;
26641859428Sblymn update_field = 1;
26741859428Sblymn break;
26841859428Sblymn
26941859428Sblymn case REQ_LAST_FIELD:
27041859428Sblymn form->cur_field = form->field_count - 1;
27141859428Sblymn update_field = 1;
27241859428Sblymn break;
27341859428Sblymn
27441859428Sblymn case REQ_SNEXT_FIELD:
27541859428Sblymn status = _formi_pos_new_field(form, _FORMI_FORWARD,
27641859428Sblymn TRUE);
27741859428Sblymn update_field = 1;
27841859428Sblymn break;
27941859428Sblymn
28041859428Sblymn case REQ_SPREV_FIELD:
28141859428Sblymn status = _formi_pos_new_field(form, _FORMI_BACKWARD,
28241859428Sblymn TRUE);
28341859428Sblymn update_field = 1;
28441859428Sblymn break;
28541859428Sblymn
28641859428Sblymn case REQ_SFIRST_FIELD:
287*f1abc9f9Schristos fieldp = TAILQ_FIRST(&form->sorted_fields);
28841859428Sblymn form->cur_field = fieldp->index;
28941859428Sblymn update_field = 1;
29041859428Sblymn break;
29141859428Sblymn
29241859428Sblymn case REQ_SLAST_FIELD:
293*f1abc9f9Schristos fieldp = TAILQ_LAST(&form->sorted_fields,
294*f1abc9f9Schristos _formi_sort_head);
29541859428Sblymn form->cur_field = fieldp->index;
29641859428Sblymn update_field = 1;
29741859428Sblymn break;
29841859428Sblymn
29941859428Sblymn /*
30041859428Sblymn * The up, down, left and right field traversals
30141859428Sblymn * are rolled up into a single function, allow a
30241859428Sblymn * fall through to that function.
30341859428Sblymn */
30441859428Sblymn case REQ_LEFT_FIELD:
30541859428Sblymn case REQ_RIGHT_FIELD:
30641859428Sblymn case REQ_UP_FIELD:
30741859428Sblymn case REQ_DOWN_FIELD:
30841859428Sblymn status = traverse_form_links(form, c);
30941859428Sblymn update_field = 1;
31041859428Sblymn break;
31141859428Sblymn
31241859428Sblymn /* the following commands modify the buffer, check if
31341859428Sblymn this is allowed first before falling through. */
31419f07fb2Sblymn
3156334f191Sblymn case REQ_DEL_PREV:
3166334f191Sblymn /*
3176334f191Sblymn * need to check for the overloading of this
3186334f191Sblymn * request. If overload flag set and we are
3196334f191Sblymn * at the start of field this request turns
3206334f191Sblymn * into a previous field request. Otherwise
3216334f191Sblymn * fallthrough to the field handler.
3226334f191Sblymn */
3236334f191Sblymn if ((form->opts & O_BS_OVERLOAD) == O_BS_OVERLOAD) {
3246334f191Sblymn if ((fieldp->start_char == 0) &&
3256334f191Sblymn (fieldp->start_line == 0) &&
326d0d41d9fSblymn (fieldp->row_xpos == 0)) {
3276334f191Sblymn update_field =
3286334f191Sblymn _formi_manipulate_field(form,
3296334f191Sblymn REQ_PREV_FIELD);
3306334f191Sblymn break;
3316334f191Sblymn }
3326334f191Sblymn }
3336334f191Sblymn
3346334f191Sblymn /* FALLTHROUGH */
3356334f191Sblymn case REQ_NEW_LINE:
3366334f191Sblymn /*
3376334f191Sblymn * need to check for the overloading of this
3386334f191Sblymn * request. If overload flag set and we are
3396334f191Sblymn * at the start of field this request turns
3406334f191Sblymn * into a next field request. Otherwise
3416334f191Sblymn * fallthrough to the field handler.
3426334f191Sblymn */
3436334f191Sblymn if ((form->opts & O_NL_OVERLOAD) == O_NL_OVERLOAD) {
3446334f191Sblymn if ((fieldp->start_char == 0) &&
3456334f191Sblymn (fieldp->start_line == 0) &&
346d0d41d9fSblymn (fieldp->row_xpos == 0)) {
3476334f191Sblymn update_field =
3486334f191Sblymn _formi_manipulate_field(form,
3496334f191Sblymn REQ_NEXT_FIELD);
3506334f191Sblymn break;
3516334f191Sblymn }
3526334f191Sblymn }
3536334f191Sblymn
3546334f191Sblymn /* FALLTHROUGH */
35541859428Sblymn case REQ_INS_CHAR:
35641859428Sblymn case REQ_INS_LINE:
35741859428Sblymn case REQ_DEL_CHAR:
35841859428Sblymn case REQ_DEL_LINE:
35941859428Sblymn case REQ_DEL_WORD:
36041859428Sblymn case REQ_CLR_EOL:
36141859428Sblymn case REQ_CLR_EOF:
36241859428Sblymn case REQ_CLR_FIELD:
36341859428Sblymn case REQ_OVL_MODE:
36441859428Sblymn case REQ_INS_MODE:
36541859428Sblymn /* check if we are allowed to edit the field and fall
36641859428Sblymn * through if we are.
36741859428Sblymn */
36841859428Sblymn if ((form->fields[form->cur_field]->opts & O_EDIT) != O_EDIT)
36941859428Sblymn return E_REQUEST_DENIED;
37041859428Sblymn
37141859428Sblymn /* the following manipulate the field contents, bundle
37241859428Sblymn them into one function.... */
37341859428Sblymn /* FALLTHROUGH */
37441859428Sblymn case REQ_NEXT_CHAR:
37541859428Sblymn case REQ_PREV_CHAR:
37641859428Sblymn case REQ_NEXT_LINE:
37741859428Sblymn case REQ_PREV_LINE:
37841859428Sblymn case REQ_NEXT_WORD:
37941859428Sblymn case REQ_PREV_WORD:
38041859428Sblymn case REQ_BEG_FIELD:
38141859428Sblymn case REQ_END_FIELD:
38241859428Sblymn case REQ_BEG_LINE:
38341859428Sblymn case REQ_END_LINE:
38441859428Sblymn case REQ_LEFT_CHAR:
38541859428Sblymn case REQ_RIGHT_CHAR:
38641859428Sblymn case REQ_UP_CHAR:
38741859428Sblymn case REQ_DOWN_CHAR:
38841859428Sblymn case REQ_SCR_FLINE:
38941859428Sblymn case REQ_SCR_BLINE:
39041859428Sblymn case REQ_SCR_FPAGE:
39141859428Sblymn case REQ_SCR_BPAGE:
39241859428Sblymn case REQ_SCR_FHPAGE:
39341859428Sblymn case REQ_SCR_BHPAGE:
39441859428Sblymn case REQ_SCR_FCHAR:
39541859428Sblymn case REQ_SCR_BCHAR:
39641859428Sblymn case REQ_SCR_HFLINE:
39741859428Sblymn case REQ_SCR_HBLINE:
39841859428Sblymn case REQ_SCR_HFHALF:
39941859428Sblymn case REQ_SCR_HBHALF:
40041859428Sblymn update_field = _formi_manipulate_field(form, c);
40141859428Sblymn break;
40241859428Sblymn
40341859428Sblymn case REQ_VALIDATION:
40441859428Sblymn return _formi_validate_field(form);
40541859428Sblymn /* NOTREACHED */
40641859428Sblymn break;
40741859428Sblymn
40841859428Sblymn case REQ_PREV_CHOICE:
40941859428Sblymn case REQ_NEXT_CHOICE:
41041859428Sblymn update_field = _formi_field_choice(form, c);
411d0d41d9fSblymn /* reinit the cursor pos just in case */
412d0d41d9fSblymn if (update_field == 1) {
413d0d41d9fSblymn _formi_init_field_xpos(fieldp);
414d0d41d9fSblymn fieldp->row_xpos = 0;
415d0d41d9fSblymn }
41641859428Sblymn break;
41741859428Sblymn
41841859428Sblymn default: /* should not need to do this, but.... */
41941859428Sblymn return E_UNKNOWN_COMMAND;
42041859428Sblymn /* NOTREACHED */
42141859428Sblymn break;
42241859428Sblymn }
42341859428Sblymn }
42441859428Sblymn
42599af4c10Sblymn /* call the field and form init functions if required. */
42699af4c10Sblymn if ((c >= REQ_NEXT_PAGE) && (c <= REQ_DOWN_FIELD)) {
42799af4c10Sblymn if (form->field_init != NULL)
42899af4c10Sblymn form->field_init(form);
42999af4c10Sblymn
43099af4c10Sblymn /*
43199af4c10Sblymn * if we have a page movement then the form init
43299af4c10Sblymn * needs to be called too
43399af4c10Sblymn */
43499af4c10Sblymn if ((c <= REQ_LAST_PAGE) && (form->form_init != NULL))
43599af4c10Sblymn form->form_init(form);
43699af4c10Sblymn
43799af4c10Sblymn /*
43899af4c10Sblymn * if there was an error just return now...
43999af4c10Sblymn */
44099af4c10Sblymn if (status != E_OK)
44199af4c10Sblymn return status;
442043f30d2Sblymn
443043f30d2Sblymn /* if we have no error, reset the various offsets */
444043f30d2Sblymn fieldp = form->fields[form->cur_field];
445043f30d2Sblymn fieldp->start_char = 0;
44698eb8895Sroy fieldp->start_line = fieldp->alines;
44798eb8895Sroy fieldp->cur_line = fieldp->alines;
448759e545dSblymn fieldp->row_xpos = 0;
449043f30d2Sblymn fieldp->cursor_ypos = 0;
450d0d41d9fSblymn _formi_init_field_xpos(fieldp);
45199af4c10Sblymn }
45299af4c10Sblymn
45341859428Sblymn if (update_field < 0)
45441859428Sblymn return update_field;
45541859428Sblymn
45641859428Sblymn if (update_field == 1)
45741859428Sblymn update_page |= _formi_update_field(form, old_field);
45841859428Sblymn
45941859428Sblymn if (update_page == 1)
46041859428Sblymn _formi_draw_page(form);
46141859428Sblymn
46241859428Sblymn pos_form_cursor(form);
463a5ab8107Sblymn
464a5ab8107Sblymn if ((update_page == 1) || (update_field == 1))
465a5ab8107Sblymn wrefresh(form->scrwin);
466a5ab8107Sblymn
46741859428Sblymn return E_OK;
46841859428Sblymn }
469