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@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 /* 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