1 1.9 lukem /* $NetBSD: driver.c,v 1.9 2003/03/09 01:08:48 lukem Exp $ */ 2 1.1 blymn 3 1.1 blymn /*- 4 1.3 blymn * Copyright (c) 1998-1999 Brett Lymn (blymn (at) baea.com.au, brett_lymn (at) yahoo.com.au) 5 1.1 blymn * All rights reserved. 6 1.1 blymn * 7 1.1 blymn * Redistribution and use in source and binary forms, with or without 8 1.1 blymn * modification, are permitted provided that the following conditions 9 1.1 blymn * are met: 10 1.1 blymn * 1. Redistributions of source code must retain the above copyright 11 1.1 blymn * notice, this list of conditions and the following disclaimer. 12 1.1 blymn * 2. The name of the author may not be used to endorse or promote products 13 1.7 wiz * derived from this software without specific prior written permission 14 1.1 blymn * 15 1.1 blymn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 1.1 blymn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 1.1 blymn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 1.1 blymn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 1.1 blymn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 1.1 blymn * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 1.1 blymn * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 1.1 blymn * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 1.1 blymn * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 1.1 blymn * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 1.1 blymn * 26 1.1 blymn * 27 1.1 blymn */ 28 1.9 lukem 29 1.9 lukem #include <sys/cdefs.h> 30 1.9 lukem __RCSID("$NetBSD: driver.c,v 1.9 2003/03/09 01:08:48 lukem Exp $"); 31 1.1 blymn 32 1.1 blymn #include <menu.h> 33 1.1 blymn #include <ctype.h> 34 1.1 blymn #include <stdlib.h> 35 1.1 blymn #include "internals.h" 36 1.1 blymn 37 1.1 blymn /* 38 1.1 blymn * The guts of the menu library. This function processes the character 39 1.1 blymn * in c and performs actions based on the value of the character. If the 40 1.1 blymn * character is a normal one then the driver attempts to match the character 41 1.1 blymn * against the items. If the character is a recognised request then the 42 1.1 blymn * request is processed by the driver, if the character is not a recognised 43 1.1 blymn * request and is not printable then it assumed to be a user defined command. 44 1.1 blymn */ 45 1.1 blymn int 46 1.5 blymn menu_driver(MENU *menu, int c) 47 1.1 blymn { 48 1.8 blymn int drv_top_row, drv_scroll, i, it, status = E_OK; 49 1.3 blymn ITEM *drv_new_item; 50 1.8 blymn 51 1.8 blymn i = 0; 52 1.1 blymn 53 1.1 blymn if (menu == NULL) 54 1.1 blymn return E_BAD_ARGUMENT; 55 1.1 blymn if (menu->posted == 0) 56 1.1 blymn return E_NOT_POSTED; 57 1.1 blymn if (menu->items == NULL) 58 1.1 blymn return E_NOT_CONNECTED; 59 1.1 blymn if (*menu->items == NULL) 60 1.1 blymn return E_NOT_CONNECTED; 61 1.1 blymn if (menu->in_init == 1) 62 1.1 blymn return E_BAD_STATE; 63 1.1 blymn 64 1.1 blymn /* this one should never happen but just in case.... */ 65 1.3 blymn if (menu->items[menu->cur_item] == NULL) 66 1.3 blymn return E_SYSTEM_ERROR; 67 1.1 blymn 68 1.3 blymn drv_new_item = menu->items[menu->cur_item]; 69 1.1 blymn it = menu->cur_item; 70 1.3 blymn drv_top_row = menu->top_row; 71 1.1 blymn 72 1.1 blymn if ((c > REQ_BASE_NUM) && (c <= MAX_COMMAND)) { 73 1.1 blymn /* is a known driver request - first check if the pattern 74 1.1 blymn * buffer needs to be cleared, we do this on non-search 75 1.1 blymn * type requests. 76 1.1 blymn */ 77 1.1 blymn if (! ((c == REQ_BACK_PATTERN) || (c == REQ_NEXT_MATCH) || 78 1.1 blymn (c == REQ_PREV_MATCH))) { 79 1.1 blymn if ((c == REQ_CLEAR_PATTERN) 80 1.1 blymn && (menu->pattern == NULL)) 81 1.1 blymn return E_REQUEST_DENIED; 82 1.1 blymn free(menu->pattern); 83 1.1 blymn menu->pattern = NULL; 84 1.1 blymn menu->plen = 0; 85 1.1 blymn menu->match_len = 0; 86 1.1 blymn } 87 1.1 blymn 88 1.1 blymn switch (c) { 89 1.1 blymn case REQ_LEFT_ITEM: 90 1.3 blymn drv_new_item = drv_new_item->left; 91 1.1 blymn break; 92 1.1 blymn case REQ_RIGHT_ITEM: 93 1.3 blymn drv_new_item = drv_new_item->right; 94 1.1 blymn break; 95 1.1 blymn case REQ_UP_ITEM: 96 1.3 blymn drv_new_item = drv_new_item->up; 97 1.1 blymn break; 98 1.1 blymn case REQ_DOWN_ITEM: 99 1.3 blymn drv_new_item = drv_new_item->down; 100 1.1 blymn break; 101 1.1 blymn case REQ_SCR_ULINE: 102 1.3 blymn if (drv_top_row == 0) 103 1.1 blymn return E_REQUEST_DENIED; 104 1.3 blymn drv_top_row--; 105 1.3 blymn drv_new_item = drv_new_item->up; 106 1.1 blymn break; 107 1.1 blymn case REQ_SCR_DLINE: 108 1.3 blymn drv_top_row++; 109 1.3 blymn if ((drv_top_row + menu->rows - 1)> menu->item_rows) 110 1.1 blymn return E_REQUEST_DENIED; 111 1.3 blymn drv_new_item = drv_new_item->down; 112 1.1 blymn break; 113 1.1 blymn case REQ_SCR_DPAGE: 114 1.3 blymn drv_scroll = menu->item_rows - menu->rows 115 1.1 blymn - menu->top_row; 116 1.3 blymn if (drv_scroll > menu->rows) { 117 1.3 blymn drv_scroll = menu->rows; 118 1.1 blymn } 119 1.1 blymn 120 1.3 blymn if (drv_scroll <= 0) { 121 1.1 blymn return E_REQUEST_DENIED; 122 1.1 blymn } else { 123 1.3 blymn drv_top_row += drv_scroll; 124 1.3 blymn while (drv_scroll-- > 0) 125 1.3 blymn drv_new_item = drv_new_item->down; 126 1.1 blymn } 127 1.1 blymn break; 128 1.1 blymn case REQ_SCR_UPAGE: 129 1.1 blymn if (menu->rows < menu->top_row) { 130 1.3 blymn drv_scroll = menu->rows; 131 1.1 blymn } else { 132 1.3 blymn drv_scroll = menu->top_row; 133 1.1 blymn } 134 1.3 blymn if (drv_scroll == 0) 135 1.1 blymn return E_REQUEST_DENIED; 136 1.1 blymn 137 1.3 blymn drv_top_row -= drv_scroll; 138 1.3 blymn while (drv_scroll-- > 0) 139 1.3 blymn drv_new_item = drv_new_item->up; 140 1.1 blymn break; 141 1.1 blymn case REQ_FIRST_ITEM: 142 1.3 blymn drv_new_item = menu->items[0]; 143 1.1 blymn break; 144 1.1 blymn case REQ_LAST_ITEM: 145 1.3 blymn drv_new_item = menu->items[menu->item_count - 1]; 146 1.1 blymn break; 147 1.1 blymn case REQ_NEXT_ITEM: 148 1.1 blymn if ((menu->cur_item + 1) >= menu->item_count) { 149 1.1 blymn if ((menu->opts & O_NONCYCLIC) 150 1.1 blymn == O_NONCYCLIC) { 151 1.1 blymn return E_REQUEST_DENIED; 152 1.1 blymn } else { 153 1.3 blymn drv_new_item = menu->items[0]; 154 1.1 blymn } 155 1.1 blymn } else { 156 1.3 blymn drv_new_item = 157 1.3 blymn menu->items[menu->cur_item + 1]; 158 1.1 blymn } 159 1.1 blymn break; 160 1.1 blymn case REQ_PREV_ITEM: 161 1.1 blymn if (menu->cur_item == 0) { 162 1.1 blymn if ((menu->opts & O_NONCYCLIC) 163 1.1 blymn == O_NONCYCLIC) { 164 1.1 blymn return E_REQUEST_DENIED; 165 1.1 blymn } else { 166 1.3 blymn drv_new_item = menu->items[ 167 1.1 blymn menu->item_count - 1]; 168 1.1 blymn } 169 1.1 blymn } else { 170 1.3 blymn drv_new_item = 171 1.3 blymn menu->items[menu->cur_item - 1]; 172 1.1 blymn } 173 1.1 blymn break; 174 1.1 blymn case REQ_TOGGLE_ITEM: 175 1.8 blymn if ((menu->opts & (O_RADIO | O_ONEVALUE)) != 0) { 176 1.8 blymn if ((menu->opts & O_RADIO) == O_RADIO) { 177 1.8 blymn if ((drv_new_item->opts & O_SELECTABLE) 178 1.8 blymn != O_SELECTABLE) 179 1.8 blymn return E_NOT_SELECTABLE; 180 1.8 blymn 181 1.8 blymn /* don't deselect selected item */ 182 1.8 blymn if (drv_new_item->selected == 1) 183 1.8 blymn return E_REQUEST_DENIED; 184 1.8 blymn 185 1.8 blymn /* deselect all items */ 186 1.8 blymn for (i = 0; i < menu->item_count; i++) { 187 1.8 blymn if ((menu->items[i]->selected) && 188 1.8 blymn (drv_new_item->index != i)) { 189 1.8 blymn menu->items[i]->selected ^= 1; 190 1.8 blymn _menui_draw_item(menu, 191 1.8 blymn menu->items[i]->index); 192 1.8 blymn } 193 1.8 blymn } 194 1.8 blymn 195 1.8 blymn /* turn on selected item */ 196 1.8 blymn drv_new_item->selected ^= 1; 197 1.8 blymn _menui_draw_item(menu, drv_new_item->index); 198 1.8 blymn } else { 199 1.8 blymn return E_REQUEST_DENIED; 200 1.8 blymn } 201 1.1 blymn } else { 202 1.3 blymn if ((drv_new_item->opts 203 1.1 blymn & O_SELECTABLE) == O_SELECTABLE) { 204 1.1 blymn /* toggle select flag */ 205 1.3 blymn drv_new_item->selected ^= 1; 206 1.1 blymn /* update item in menu */ 207 1.3 blymn _menui_draw_item(menu, 208 1.8 blymn drv_new_item->index); 209 1.1 blymn } else { 210 1.1 blymn return E_NOT_SELECTABLE; 211 1.1 blymn } 212 1.1 blymn } 213 1.1 blymn break; 214 1.1 blymn case REQ_CLEAR_PATTERN: 215 1.1 blymn /* this action is taken before the 216 1.1 blymn case statement */ 217 1.1 blymn break; 218 1.1 blymn case REQ_BACK_PATTERN: 219 1.1 blymn if (menu->pattern == NULL) 220 1.1 blymn return E_REQUEST_DENIED; 221 1.1 blymn 222 1.1 blymn if (menu->plen == 0) 223 1.1 blymn return E_REQUEST_DENIED; 224 1.1 blymn menu->pattern[menu->plen--] = '\0'; 225 1.1 blymn break; 226 1.1 blymn case REQ_NEXT_MATCH: 227 1.1 blymn if (menu->pattern == NULL) 228 1.1 blymn return E_REQUEST_DENIED; 229 1.1 blymn 230 1.3 blymn status = _menui_match_pattern(menu, 0, 231 1.1 blymn MATCH_NEXT_FORWARD, 232 1.1 blymn &it); 233 1.3 blymn drv_new_item = menu->items[it]; 234 1.1 blymn break; 235 1.1 blymn case REQ_PREV_MATCH: 236 1.1 blymn if (menu->pattern == NULL) 237 1.1 blymn return E_REQUEST_DENIED; 238 1.1 blymn 239 1.3 blymn status = _menui_match_pattern(menu, 0, 240 1.1 blymn MATCH_NEXT_REVERSE, 241 1.1 blymn &it); 242 1.3 blymn drv_new_item = menu->items[it]; 243 1.1 blymn break; 244 1.1 blymn } 245 1.1 blymn } else if (c > MAX_COMMAND) { 246 1.1 blymn /* must be a user command */ 247 1.1 blymn return E_UNKNOWN_COMMAND; 248 1.6 itohy } else if (isprint((unsigned char) c)) { 249 1.1 blymn /* otherwise search items for the character. */ 250 1.6 itohy status = _menui_match_pattern(menu, (unsigned char) c, 251 1.6 itohy MATCH_FORWARD, &it); 252 1.3 blymn drv_new_item = menu->items[it]; 253 1.1 blymn 254 1.1 blymn /* update the position of the cursor if we are doing 255 1.1 blymn * show match and the current item has not changed. If 256 1.1 blymn * we don't do this here it won't get done since the 257 1.1 blymn * display will not be updated due to the current item 258 1.1 blymn * not changing. 259 1.1 blymn */ 260 1.3 blymn if ((drv_new_item->index == menu->cur_item) 261 1.1 blymn && ((menu->opts & O_SHOWMATCH) == O_SHOWMATCH)) { 262 1.1 blymn pos_menu_cursor(menu); 263 1.1 blymn } 264 1.1 blymn 265 1.1 blymn 266 1.1 blymn } else { 267 1.1 blymn /* bad character */ 268 1.1 blymn return E_BAD_ARGUMENT; 269 1.1 blymn } 270 1.1 blymn 271 1.3 blymn if (drv_new_item == NULL) 272 1.3 blymn return E_REQUEST_DENIED; 273 1.1 blymn 274 1.3 blymn if (drv_new_item->row < drv_top_row) drv_top_row = drv_new_item->row; 275 1.3 blymn if (drv_new_item->row >= (drv_top_row + menu->rows)) 276 1.3 blymn drv_top_row = drv_new_item->row - menu->rows + 1; 277 1.1 blymn 278 1.3 blymn if ((drv_new_item->index != menu->cur_item) 279 1.3 blymn || (drv_top_row != menu->top_row)) 280 1.3 blymn _menui_goto_item(menu, drv_new_item, drv_top_row); 281 1.1 blymn 282 1.1 blymn return status; 283 1.1 blymn } 284 1.1 blymn 285 1.1 blymn 286 1.1 blymn 287 1.1 blymn 288 1.1 blymn 289