Home | History | Annotate | Line # | Download | only in libform
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