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