1 /*-----------------------------------------------------------------------------+
2 | The ncurses menu library is Copyright (C) 1995-1997 |
3 | by Juergen Pfeifer <Juergen.Pfeifer@T-Online.de> |
4 | All Rights Reserved. |
6 | Permission to use, copy, modify, and distribute this software and its |
7 | documentation for any purpose and without fee is hereby granted, provided |
8 | that the above copyright notice appear in all copies and that both that |
9 | copyright notice and this permission notice appear in supporting |
10 | documentation, and that the name of the above listed copyright holder(s) not |
11 | be used in advertising or publicity pertaining to distribution of the |
12 | software without specific, written prior permission. |
14 | THE ABOVE LISTED COPYRIGHT HOLDER(S) DISCLAIM ALL WARRANTIES WITH REGARD TO |
15 | THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- |
16 | NESS, IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR |
17 | ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RE- |
18 | SULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, |
19 | NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH |
20 | THE USE OR PERFORMANCE OF THIS SOFTWARE. |
21 +-----------------------------------------------------------------------------*/
23 /***************************************************************************
24 * Module menu_driver and menu_pattern *
25 * Central dispatching routine and pattern matching handling *
26 ***************************************************************************/
28 #include "menu.priv.h"
30 MODULE_ID("$Id: m_driver.c,v 1.8 1997/05/01 16:47:26 juergen Exp $")
34 /* Remove the last character from the match pattern buffer */
35 #define Remove_Character_From_Pattern(menu) \
36 (menu)->pattern[--((menu)->pindex)] = '\0'
38 /* Add a new character to the match pattern buffer */
39 #define Add_Character_To_Pattern(menu,ch) \
40 { (menu)->pattern[((menu)->pindex)++] = (ch);\
41 (menu)->pattern[(menu)->pindex] = '\0'; }
43 /*---------------------------------------------------------------------------
45 | Function : static bool Is_Sub_String(
46 | bool IgnoreCaseFlag,
50 | Description : Checks whether or not part is a substring of string.
52 | Return Values : TRUE - if it is a substring
53 | FALSE - if it is not a substring
54 +--------------------------------------------------------------------------*/
55 static bool Is_Sub_String(
61 assert( part && string );
64 while(*string && *part)
66 if (toupper(*string++)!=toupper(*part)) break;
72 while( *string && *part )
73 if (*part != *string++) break;
76 return ( (*part) ? FALSE : TRUE );
79 /*---------------------------------------------------------------------------
81 | Function : static int Match_Next_Character_In_Item_Name(
86 | Description : This internal routine is called for a menu positioned
87 | at an item with three different classes of characters:
88 | - a printable character; the character is added to
89 | the current pattern and the next item matching
90 | this pattern is searched.
91 | - NUL; the pattern stays as it is and the next item
92 | matching the pattern is searched
93 | - BS; the pattern stays as it is and the previous
94 | item matching the pattern is searched
96 | The item parameter contains on call a pointer to
97 | the item where the search starts. On return - if
98 | a match was found - it contains a pointer to the
101 | Return Values : E_OK - an item matching the pattern was found
102 | E_NO_MATCH - nothing found
103 +--------------------------------------------------------------------------*/
104 static int Match_Next_Character_In_Item_Name(MENU *menu, int ch, ITEM **item)
106 bool found = FALSE, passed = FALSE;
109 assert( menu && item && *item);
110 idx = (*item)->index;
114 /* if we become to long, we need no further checking : there can't be
116 if ((menu->pindex+1) > menu->namelen)
119 Add_Character_To_Pattern(menu,ch);
120 /* we artificially position one item back, because in the do...while
121 loop we start with the next item. This means, that with a new
122 pattern search we always start the scan with the actual item. If
123 we do a NEXT_PATTERN oder PREV_PATTERN search, we start with the
124 one after or before the actual item. */
126 idx = menu->nitems-1;
129 last = idx; /* this closes the cycle */
133 { /* we have to go backward */
135 idx = menu->nitems-1;
138 { /* otherwise we always go forward */
139 if (++idx >= menu->nitems)
142 if (Is_Sub_String((menu->opt & O_IGNORECASE) != 0,
144 menu->items[idx]->name.str)
149 } while (!found && (idx != last));
153 if (!((idx==(*item)->index) && passed))
155 *item = menu->items[idx];
158 /* This point is reached, if we fully cycled through the item list
159 and the only match we found is the starting item. With a NEXT_PATTERN
160 or PREV_PATTERN scan this means, that there was no additional match.
161 If we searched with an expanded new pattern, we should never reach
162 this point, because if the expanded pattern matches also the actual
163 item we will find it in the first attempt (passed==FALSE) and we
164 will never cycle through the whole item array.
166 assert( ch==0 || ch==BS );
170 if (ch && ch!=BS && menu->pindex>0)
172 /* if we had no match with a new pattern, we have to restore it */
173 Remove_Character_From_Pattern(menu);
179 /*---------------------------------------------------------------------------
180 | Facility : libnmenu
181 | Function : char *menu_pattern(const MENU *menu)
183 | Description : Return the value of the pattern buffer.
185 | Return Values : NULL - if there is no pattern buffer allocated
186 | EmptyString - if there is a pattern buffer but no
188 | PatternString - as expected
189 +--------------------------------------------------------------------------*/
190 char *menu_pattern(const MENU * menu)
192 return (menu ? (menu->pattern ? menu->pattern : "") : (char *)0);
195 /*---------------------------------------------------------------------------
196 | Facility : libnmenu
197 | Function : int set_menu_pattern(MENU *menu, const char *p)
199 | Description : Set the match pattern for a menu and position to the
200 | first item that matches.
202 | Return Values : E_OK - success
203 | E_BAD_ARGUMENT - invalid menu or pattern pointer
204 | E_NOT_CONNECTED - no items connected to menu
205 | E_BAD_STATE - menu in user hook routine
206 | E_NO_MATCH - no item matches pattern
207 +--------------------------------------------------------------------------*/
208 int set_menu_pattern(MENU *menu, const char *p)
214 RETURN(E_BAD_ARGUMENT);
217 RETURN(E_NOT_CONNECTED);
219 if ( menu->status & _IN_DRIVER )
226 pos_menu_cursor(menu);
230 if (menu->status & _LINK_NEEDED)
231 _nc_Link_Items(menu);
233 matchpos = menu->toprow;
234 matchitem = menu->curitem;
240 (Match_Next_Character_In_Item_Name(menu,*p,&matchitem) != E_OK) )
243 pos_menu_cursor(menu);
249 /* This is reached if there was a match. So we position to the new item */
250 Adjust_Current_Item(menu,matchpos,matchitem);
254 /*---------------------------------------------------------------------------
255 | Facility : libnmenu
256 | Function : int menu_driver(MENU *menu, int c)
258 | Description : Central dispatcher for the menu. Translates the logical
259 | request 'c' into a menu action.
261 | Return Values : E_OK - success
262 | E_BAD_ARGUMENT - invalid menu pointer
263 | E_BAD_STATE - menu is in user hook routine
264 | E_NOT_POSTED - menu is not posted
265 +--------------------------------------------------------------------------*/
266 int menu_driver(MENU * menu, int c)
268 #define NAVIGATE(dir) \
270 result = E_REQUEST_DENIED;\
276 int my_top_row, rdiff;
279 RETURN(E_BAD_ARGUMENT);
281 if ( menu->status & _IN_DRIVER )
283 if ( !( menu->status & _POSTED ) )
284 RETURN(E_NOT_POSTED);
286 my_top_row = menu->toprow;
287 item = menu->curitem;
290 if ((c > KEY_MAX) && (c<=MAX_MENU_COMMAND))
292 if (!((c==REQ_BACK_PATTERN)
293 || (c==REQ_NEXT_MATCH) || (c==REQ_PREV_MATCH)))
295 assert( menu->pattern );
302 /*=================*/
307 /*==================*/
317 /*=================*/
322 /*=================*/
324 result = E_REQUEST_DENIED;
333 /*=================*/
335 if ((menu->rows - menu->arows)>0)
337 /* only if the menu has less items than rows, we can deny the
338 request. Otherwise the epilogue of this routine adjusts the
339 top row if necessary */
341 result = E_REQUEST_DENIED;
348 /*=================*/
349 rdiff = menu->rows - menu->arows - my_top_row;
350 if (rdiff > menu->arows)
353 result = E_REQUEST_DENIED;
363 /*=================*/
364 rdiff = (menu->arows < my_top_row) ?
365 menu->arows : my_top_row;
367 result = E_REQUEST_DENIED;
377 /*==================*/
378 item = menu->items[0];
382 /*=================*/
383 item = menu->items[menu->nitems-1];
387 /*=================*/
388 if ((item->index+1)>=menu->nitems)
390 if (menu->opt & O_NONCYCLIC)
391 result = E_REQUEST_DENIED;
393 item = menu->items[0];
396 item = menu->items[item->index + 1];
400 /*=================*/
403 if (menu->opt & O_NONCYCLIC)
404 result = E_REQUEST_DENIED;
406 item = menu->items[menu->nitems-1];
409 item = menu->items[item->index - 1];
412 case REQ_TOGGLE_ITEM:
413 /*===================*/
414 if (menu->opt & O_ONEVALUE)
416 result = E_REQUEST_DENIED;
420 if (menu->curitem->opt & O_SELECTABLE)
422 menu->curitem->value = !menu->curitem->value;
423 Move_And_Post_Item(menu,menu->curitem);
427 result = E_NOT_SELECTABLE;
431 case REQ_CLEAR_PATTERN:
432 /*=====================*/
433 /* already cleared in prologue */
436 case REQ_BACK_PATTERN:
437 /*====================*/
440 assert(menu->pattern);
441 Remove_Character_From_Pattern(menu);
442 pos_menu_cursor( menu );
445 result = E_REQUEST_DENIED;
449 /*==================*/
450 assert(menu->pattern);
451 if (menu->pattern[0])
452 result = Match_Next_Character_In_Item_Name(menu,0,&item);
455 if ((item->index+1)<menu->nitems)
456 item=menu->items[item->index+1];
459 if (menu->opt & O_NONCYCLIC)
460 result = E_REQUEST_DENIED;
462 item = menu->items[0];
468 /*==================*/
469 assert(menu->pattern);
470 if (menu->pattern[0])
471 result = Match_Next_Character_In_Item_Name(menu,BS,&item);
475 item = menu->items[item->index-1];
478 if (menu->opt & O_NONCYCLIC)
479 result = E_REQUEST_DENIED;
481 item = menu->items[menu->nitems-1];
488 result = E_UNKNOWN_COMMAND;
493 { /* not a command */
494 if ( !(c & ~((int)MAX_REGULAR_CHARACTER)) && isprint(c) )
495 result = Match_Next_Character_In_Item_Name( menu, c, &item );
497 result = E_UNKNOWN_COMMAND;
500 /* Adjust the top row if it turns out that the current item unfortunately
501 doesn't appear in the menu window */
502 if ( item->y < my_top_row )
503 my_top_row = item->y;
504 else if ( item->y >= (my_top_row + menu->arows) )
505 my_top_row = item->y - menu->arows + 1;
507 _nc_New_TopRow_and_CurrentItem( menu, my_top_row, item );
512 /* m_driver.c ends here */