Home | History | Annotate | Line # | Download | only in libform
driver.c revision 1.7
      1 /*	$NetBSD: driver.c,v 1.7 2001/04/06 04:40:43 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 	int update_page, update_field, old_field, old_page, status;
     98 	int start_field;
     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 = start_field = form->cur_field;
    115 	fieldp = form->fields[form->cur_field];
    116 	update_page = update_field = 0;
    117 	status = E_OK;
    118 
    119 	if (c < REQ_MIN_REQUEST) {
    120 		if (isprint(c)) {
    121 			do {
    122 				pos = fieldp->start_char + fieldp->cursor_xpos;
    123 
    124 			      /* check if we are allowed to edit this field */
    125 				if ((fieldp->opts & O_EDIT) != O_EDIT)
    126 					return E_REQUEST_DENIED;
    127 
    128 				if ((status =
    129 				     (_formi_add_char(fieldp, pos, c)))
    130 				    == E_REQUEST_DENIED) {
    131 
    132 					  /*
    133 					   * Need to check here if we
    134 					   * want to autoskip.  we
    135 					   * call the form driver
    136 					   * recursively to pos us on
    137 					   * the next field and then
    138 					   * we loop back to ensure
    139 					   * the next field selected
    140 					   * can have data added to it
    141 					   */
    142 					if ((fieldp->opts & O_AUTOSKIP)
    143 					    != O_AUTOSKIP)
    144 						return E_REQUEST_DENIED;
    145 					status = form_driver(form,
    146 							     REQ_NEXT_FIELD);
    147 					if (status != E_OK)
    148 						return status;
    149 
    150 					  /*
    151 					   * check if we have looped
    152                                            * around all the fields.
    153                                            * This can easily happen if
    154                                            * all the fields are full.
    155 					   */
    156 					if (start_field == form->cur_field)
    157 						return E_REQUEST_DENIED;
    158 
    159 					old_field = form->cur_field;
    160 					fieldp = form->fields[form->cur_field];
    161 					status = _formi_add_char(fieldp,
    162 							fieldp->start_char
    163 							+ fieldp->cursor_xpos,
    164 							c);
    165 				} else if (status == E_INVALID_FIELD)
    166 					  /* char failed validation, just
    167 					   * return the status.
    168 					   */
    169 					return status;
    170 			}
    171 			while (status != E_OK);
    172 			update_field = (status == E_OK);
    173 		} else
    174 			return E_REQUEST_DENIED;
    175 	} else {
    176 		if (c > REQ_MAX_COMMAND)
    177 			return E_UNKNOWN_COMMAND;
    178 
    179 		if ((c >= REQ_NEXT_PAGE) && (c <= REQ_DOWN_FIELD)) {
    180 			  /* first check the field we are in is ok */
    181 			if (_formi_validate_field(form) != E_OK)
    182 				return E_INVALID_FIELD;
    183 
    184 			if (form->field_term != NULL)
    185 				form->field_term(form);
    186 
    187 			  /*
    188 			   * if we have a page movement then the form term
    189 			   * needs to be called too
    190 			   */
    191 			if ((c <= REQ_LAST_PAGE) && (form->form_term != NULL))
    192 				form->form_term(form);
    193 		}
    194 
    195 
    196 		switch (c) {
    197 		case REQ_NEXT_PAGE:
    198 			if (form->page < form->max_page) {
    199 				old_page = form->page;
    200 				form->page++;
    201 				update_page = 1;
    202 				if (_formi_pos_first_field(form) != E_OK) {
    203 					form->page = old_page;
    204 					status = E_REQUEST_DENIED;
    205 				}
    206 			} else
    207 				status = E_REQUEST_DENIED;
    208 			break;
    209 
    210 		case REQ_PREV_PAGE:
    211 			if (form->page > 0) {
    212 				old_page = form->page;
    213 				form->page--;
    214 				update_page = 1;
    215 				if (_formi_pos_first_field(form) != E_OK) {
    216 					form->page = old_page;
    217 					status = E_REQUEST_DENIED;
    218 				}
    219 			} else
    220 				status = E_REQUEST_DENIED;
    221 			break;
    222 
    223 		case REQ_FIRST_PAGE:
    224 			old_page = form->page;
    225 			form->page = 0;
    226 			update_page = 1;
    227 			if (_formi_pos_first_field(form) != E_OK) {
    228 				form->page = old_page;
    229 				status = E_REQUEST_DENIED;
    230 			}
    231 			break;
    232 
    233 		case REQ_LAST_PAGE:
    234 			old_page = form->page;
    235 			form->page = form->max_page - 1;
    236 			update_page = 1;
    237 			if (_formi_pos_first_field(form) != E_OK) {
    238 				form->page = old_page;
    239 				status = E_REQUEST_DENIED;
    240 			}
    241 			break;
    242 
    243 		case REQ_NEXT_FIELD:
    244 			status = _formi_pos_new_field(form, _FORMI_FORWARD,
    245 						      FALSE);
    246 			update_field = 1;
    247 			break;
    248 
    249 		case REQ_PREV_FIELD:
    250 			status = _formi_pos_new_field(form, _FORMI_BACKWARD,
    251 						      FALSE);
    252 			update_field = 1;
    253 			break;
    254 
    255 		case REQ_FIRST_FIELD:
    256 			form->cur_field = 0;
    257 			update_field = 1;
    258 			break;
    259 
    260 		case REQ_LAST_FIELD:
    261 			form->cur_field = form->field_count - 1;
    262 			update_field = 1;
    263 			break;
    264 
    265 		case REQ_SNEXT_FIELD:
    266 			status = _formi_pos_new_field(form, _FORMI_FORWARD,
    267 						      TRUE);
    268 			update_field = 1;
    269 			break;
    270 
    271 		case REQ_SPREV_FIELD:
    272 			status = _formi_pos_new_field(form, _FORMI_BACKWARD,
    273 						      TRUE);
    274 			update_field = 1;
    275 			break;
    276 
    277 		case REQ_SFIRST_FIELD:
    278 			fieldp = CIRCLEQ_FIRST(&form->sorted_fields);
    279 			form->cur_field = fieldp->index;
    280 			update_field = 1;
    281 			break;
    282 
    283 		case REQ_SLAST_FIELD:
    284 			fieldp = CIRCLEQ_LAST(&form->sorted_fields);
    285 			form->cur_field = fieldp->index;
    286 			update_field = 1;
    287 			break;
    288 
    289 			  /*
    290 			   * The up, down, left and right field traversals
    291 			   * are rolled up into a single function, allow a
    292 			   * fall through to that function.
    293 			   */
    294 			  /* FALLTHROUGH */
    295 		case REQ_LEFT_FIELD:
    296 		case REQ_RIGHT_FIELD:
    297 		case REQ_UP_FIELD:
    298 		case REQ_DOWN_FIELD:
    299 			status = traverse_form_links(form, c);
    300 			update_field = 1;
    301 			break;
    302 
    303 			  /* the following commands modify the buffer, check if
    304 			     this is allowed first before falling through. */
    305 			  /* FALLTHROUGH */
    306 		case REQ_DEL_PREV:
    307 			  /*
    308 			   * need to check for the overloading of this
    309 			   * request.  If overload flag set and we are
    310 			   * at the start of field this request turns
    311 			   * into a previous field request. Otherwise
    312 			   * fallthrough to the field handler.
    313 			   */
    314 			if ((form->opts & O_BS_OVERLOAD) == O_BS_OVERLOAD) {
    315 				if ((fieldp->start_char == 0) &&
    316 				    (fieldp->start_line == 0) &&
    317 				    (fieldp->cursor_xpos == 0)) {
    318 					update_field =
    319 						_formi_manipulate_field(form,
    320 							REQ_PREV_FIELD);
    321 					break;
    322 				}
    323 			}
    324 
    325 			  /* FALLTHROUGH */
    326 		case REQ_NEW_LINE:
    327 			  /*
    328 			   * need to check for the overloading of this
    329 			   * request.  If overload flag set and we are
    330 			   * at the start of field this request turns
    331 			   * into a next field request. Otherwise
    332 			   * fallthrough to the field handler.
    333 			   */
    334 			if ((form->opts & O_NL_OVERLOAD) == O_NL_OVERLOAD) {
    335 				if ((fieldp->start_char == 0) &&
    336 				    (fieldp->start_line == 0) &&
    337 				    (fieldp->cursor_xpos == 0)) {
    338 					update_field =
    339 						_formi_manipulate_field(form,
    340 							REQ_NEXT_FIELD);
    341 					break;
    342 				}
    343 			}
    344 
    345 			  /* FALLTHROUGH */
    346 		case REQ_INS_CHAR:
    347 		case REQ_INS_LINE:
    348 		case REQ_DEL_CHAR:
    349 		case REQ_DEL_LINE:
    350 		case REQ_DEL_WORD:
    351 		case REQ_CLR_EOL:
    352 		case REQ_CLR_EOF:
    353 		case REQ_CLR_FIELD:
    354 		case REQ_OVL_MODE:
    355 		case REQ_INS_MODE:
    356 			  /* check if we are allowed to edit the field and fall
    357 			   * through if we are.
    358 			   */
    359 			if ((form->fields[form->cur_field]->opts & O_EDIT) != O_EDIT)
    360 				return E_REQUEST_DENIED;
    361 
    362 			  /* the following manipulate the field contents, bundle
    363 			     them into one function.... */
    364 			  /* FALLTHROUGH */
    365 		case REQ_NEXT_CHAR:
    366 		case REQ_PREV_CHAR:
    367 		case REQ_NEXT_LINE:
    368 		case REQ_PREV_LINE:
    369 		case REQ_NEXT_WORD:
    370 		case REQ_PREV_WORD:
    371 		case REQ_BEG_FIELD:
    372 		case REQ_END_FIELD:
    373 		case REQ_BEG_LINE:
    374 		case REQ_END_LINE:
    375 		case REQ_LEFT_CHAR:
    376 		case REQ_RIGHT_CHAR:
    377 		case REQ_UP_CHAR:
    378 		case REQ_DOWN_CHAR:
    379 		case REQ_SCR_FLINE:
    380 		case REQ_SCR_BLINE:
    381 		case REQ_SCR_FPAGE:
    382 		case REQ_SCR_BPAGE:
    383 		case REQ_SCR_FHPAGE:
    384 		case REQ_SCR_BHPAGE:
    385 		case REQ_SCR_FCHAR:
    386 		case REQ_SCR_BCHAR:
    387 		case REQ_SCR_HFLINE:
    388 		case REQ_SCR_HBLINE:
    389 		case REQ_SCR_HFHALF:
    390 		case REQ_SCR_HBHALF:
    391 			update_field = _formi_manipulate_field(form, c);
    392 			break;
    393 
    394 		case REQ_VALIDATION:
    395 			return _formi_validate_field(form);
    396 			  /* NOTREACHED */
    397 			break;
    398 
    399 		case REQ_PREV_CHOICE:
    400 		case REQ_NEXT_CHOICE:
    401 			update_field = _formi_field_choice(form, c);
    402 			break;
    403 
    404 		default: /* should not need to do this, but.... */
    405 			return E_UNKNOWN_COMMAND;
    406 			  /* NOTREACHED */
    407 			break;
    408 		}
    409 	}
    410 
    411 	  /* call the field and form init functions if required. */
    412 	if ((c >= REQ_NEXT_PAGE) && (c <= REQ_DOWN_FIELD)) {
    413 		if (form->field_init != NULL)
    414 			form->field_init(form);
    415 
    416 		  /*
    417 		   * if we have a page movement then the form init
    418 		   * needs to be called too
    419 		   */
    420 		if ((c <= REQ_LAST_PAGE) && (form->form_init != NULL))
    421 			form->form_init(form);
    422 
    423 		  /*
    424 		   * if there was an error just return now...
    425 		   */
    426 		if (status != E_OK)
    427 			return status;
    428 
    429 		  /* if we have no error, reset the various offsets */
    430 		fieldp = form->fields[form->cur_field];
    431 		fieldp->start_char = 0;
    432 		fieldp->start_line = 0;
    433 		fieldp->cursor_xpos = 0;
    434 		fieldp->cursor_ypos = 0;
    435 	}
    436 
    437 	if (update_field < 0)
    438 		return update_field;
    439 
    440 	if (update_field == 1)
    441 		update_page |= _formi_update_field(form, old_field);
    442 
    443 	if (update_page == 1)
    444 		_formi_draw_page(form);
    445 
    446 	pos_form_cursor(form);
    447 	return E_OK;
    448 }
    449 
    450