1 /*        $NetBSD: item.c,v 1.12 2012/03/21 05:33:27 matt Exp $       */
2 
3 /*-
4  * Copyright (c) 1998-1999 Brett Lymn (blymn@baea.com.au, brett_lymn@yahoo.com.au)
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. The name of the author may not be used to endorse or promote products
13  *    derived from this software without specific prior written permission
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  *
27  */
28 
29 #include <sys/cdefs.h>
30 __RCSID("$NetBSD: item.c,v 1.12 2012/03/21 05:33:27 matt Exp $");
31 
32 #include <menu.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include "internals.h"
36 
37 /* the following is defined in menu.c - it is the default menu struct */
38 extern MENU _menui_default_menu;
39 
40 /* keep default item options for setting in new_item */
41 ITEM _menui_default_item = {
42           {NULL, 0}, /* item name struct */
43           {NULL, 0}, /* item description struct */
44           NULL, /* user pointer */
45           0, /* is item visible? */
46           0, /* is item selected? */
47           0, /* row item is on */
48           0, /* column item is on */
49           O_SELECTABLE, /* item options */
50           NULL, /* parent menu item is bound to */
51           -1, /* index number if item attached to a menu */
52           NULL, /* left neighbour */
53           NULL, /* right neighbour */
54           NULL, /* up neighbour */
55           NULL /* down neighbour */
56 };
57 
58 /*
59  * Return the item visibility flag
60  */
61 int
item_visible(ITEM * item)62 item_visible(ITEM *item)
63 {
64           if (item == NULL)
65                     return E_BAD_ARGUMENT;
66           if (item->parent == NULL)
67                     return E_NOT_CONNECTED;
68 
69         return item->visible;
70 }
71 
72 /*
73  * Return the pointer to the item name
74  */
75 char *
item_name(ITEM * item)76 item_name(ITEM *item)
77 {
78           if (item == NULL)
79                     return NULL;
80 
81         return item->name.string;
82 }
83 
84 /*
85  * Return the pointer to the item description
86  */
87 char *
item_description(ITEM * item)88 item_description(ITEM *item)
89 {
90           if (item == NULL)
91                     return NULL;
92 
93         return item->description.string;
94 }
95 
96 /*
97  * Set the application defined function called when the menu is posted or
98  * just after the current item changes.
99  */
100 int
set_item_init(MENU * menu,Menu_Hook func)101 set_item_init(MENU *menu, Menu_Hook func)
102 {
103           if (menu == NULL)
104                     _menui_default_menu.item_init = func;
105           else
106                     menu->item_init = func;
107         return E_OK;
108 }
109 
110 
111 /*
112  * Return a pointer to the item initialisation routine.
113  */
114 Menu_Hook
item_init(MENU * menu)115 item_init(MENU *menu)
116 {
117           if (menu == NULL)
118                     return _menui_default_menu.item_init;
119           else
120                     return menu->item_init;
121 }
122 
123 /*
124  * Set the user defined function to be called when menu is unposted or just
125  * before the current item changes.
126  */
127 int
set_item_term(MENU * menu,Menu_Hook func)128 set_item_term(MENU *menu, Menu_Hook func)
129 {
130           if (menu == NULL)
131                     _menui_default_menu.item_term = func;
132           else
133                     menu->item_term = func;
134         return E_OK;
135 }
136 
137 /*
138  * Return a pointer to the termination function
139  */
140 Menu_Hook
item_term(MENU * menu)141 item_term(MENU *menu)
142 {
143           if (menu == NULL)
144                     return _menui_default_menu.item_term;
145           else
146                     return menu->item_term;
147 }
148 
149 /*
150  * Returns the number of items that are selected.
151  * The index numbers of the items are placed in the dynamically allocated
152  * int array *sel.
153  */
154 int
item_selected(MENU * menu,int ** sel)155 item_selected(MENU *menu, int **sel)
156 {
157           int i, j;
158 
159           if (menu == NULL)
160                     return E_BAD_ARGUMENT;
161 
162           /* count selected */
163           for (i = 0, j = 0; i < menu->item_count; i++)
164                     if (menu->items[i]->selected)
165                               j++;
166 
167           if (j == 0) {
168                     *sel = NULL;
169                     return 0;
170           }
171 
172           if ( (*sel = malloc(sizeof(int) * j)) == NULL)
173                     return E_SYSTEM_ERROR;
174 
175           for (i = 0, j = 0; i < menu->item_count; i++)
176                     if (menu->items[i]->selected)
177                               (*sel)[j++] = i;
178 
179           return j;
180 }
181 
182 /*
183  * Set the item options.  We keep a global copy of the current item options
184  * as subsequent new_item calls will use the updated options as their
185  * defaults.
186  */
187 int
set_item_opts(ITEM * item,OPTIONS opts)188 set_item_opts(ITEM *item, OPTIONS opts)
189 {
190           /* selectable seems to be the only allowable item opt! */
191         if (opts != O_SELECTABLE)
192                 return E_SYSTEM_ERROR;
193 
194           if (item == NULL)
195                     _menui_default_item.opts = opts;
196           else
197                     item->opts = opts;
198         return E_OK;
199 }
200 
201 /*
202  * Set item options on.
203  */
204 int
item_opts_on(ITEM * item,OPTIONS opts)205 item_opts_on(ITEM *item, OPTIONS opts)
206 {
207         if (opts != O_SELECTABLE)
208                 return E_SYSTEM_ERROR;
209 
210         if (item == NULL)
211                     _menui_default_item.opts |= opts;
212           else
213                     item->opts |= opts;
214         return E_OK;
215 }
216 
217 /*
218  * Turn off the named options.
219  */
220 int
item_opts_off(ITEM * item,OPTIONS opts)221 item_opts_off(ITEM *item, OPTIONS opts)
222 {
223         if (opts != O_SELECTABLE)
224                 return E_SYSTEM_ERROR;
225 
226           if (item == NULL)
227                     _menui_default_item.opts &= ~(opts);
228           else
229                     item->opts &= ~(opts);
230         return E_OK;
231 }
232 
233 /*
234  * Return the current options set in item.
235  */
236 OPTIONS
item_opts(ITEM * item)237 item_opts(ITEM *item)
238 {
239           if (item == NULL)
240                     return _menui_default_item.opts;
241           else
242                     return item->opts;
243 }
244 
245 /*
246  * Set the selected flag of the item iff the menu options allow it.
247  */
248 int
set_item_value(ITEM * param_item,int flag)249 set_item_value(ITEM *param_item, int flag)
250 {
251           ITEM *item = (param_item != NULL) ? param_item : &_menui_default_item;
252 
253           /* not bound to a menu */
254         if (item->parent == NULL)
255                 return E_NOT_CONNECTED;
256 
257           /* menu options do not allow multi-selection */
258         if ((item->parent->opts & O_ONEVALUE) == O_ONEVALUE)
259                 return E_REQUEST_DENIED;
260 
261         item->selected = flag;
262           _menui_draw_item(item->parent, item->index);
263         return E_OK;
264 }
265 
266 /*
267  * Return the item value of the item.
268  */
269 int
item_value(ITEM * item)270 item_value(ITEM *item)
271 {
272           if (item == NULL)
273                     return _menui_default_item.selected;
274           else
275                     return item->selected;
276 }
277 
278 /*
279  * Allocate a new item and return the pointer to the newly allocated
280  * structure.
281  */
282 ITEM *
new_item(char * name,char * description)283 new_item(char *name, char *description)
284 {
285         ITEM *new_one;
286 
287           if (name == NULL)
288                     return NULL;
289 
290             /* allocate a new item structure for ourselves */
291         if ((new_one = (ITEM *)malloc(sizeof(ITEM))) == NULL)
292                 return NULL;
293 
294             /* copy in the defaults for the item */
295           (void)memcpy(new_one, &_menui_default_item, sizeof(ITEM));
296 
297             /* fill in the name structure - first the length and then
298                allocate room for the string & copy that. */
299           new_one->name.length = strlen(name);
300         if ((new_one->name.string = (char *)
301              malloc(sizeof(char) * new_one->name.length + 1)) == NULL) {
302                       /* uh oh malloc failed - clean up & exit */
303                     free(new_one);
304                 return NULL;
305         }
306 
307         strcpy(new_one->name.string, name);
308 
309           if (description == NULL)
310                     new_one->description.length = 0;
311           else {
312             /* fill in the description structure, stash the length then
313                allocate room for description string and copy it in */
314           new_one->description.length = strlen(description);
315           if ((new_one->description.string =
316                         (char *) malloc(sizeof(char) *
317                         new_one->description.length + 1)) == NULL) {
318                               /*
319                                * malloc has failed
320                                * - free up allocated memory and return
321                                */
322                               free(new_one->name.string);
323                               free(new_one);
324                               return NULL;
325                     }
326 
327                     strcpy(new_one->description.string, description);
328           }
329 
330           return new_one;
331 }
332 
333 /*
334  * Free the allocated storage associated with item.
335  */
336 int
free_item(ITEM * item)337 free_item(ITEM *item)
338 {
339           if (item == NULL)
340                     return E_BAD_ARGUMENT;
341 
342             /* check for connection to menu */
343           if (item->parent != NULL)
344                     return E_CONNECTED;
345 
346             /* no connections, so free storage starting with the strings */
347           free(item->name.string);
348           if (item->description.length)
349                     free(item->description.string);
350           free(item);
351           return E_OK;
352 }
353 
354 /*
355  * Set the menu's current item to the one given.
356  */
357 int
set_current_item(MENU * param_menu,ITEM * item)358 set_current_item(MENU *param_menu, ITEM *item)
359 {
360           MENU *menu = (param_menu != NULL) ? param_menu : &_menui_default_menu;
361           int i = 0;
362 
363             /* check if we have been called from an init type function */
364           if (menu->in_init == 1)
365                     return E_BAD_STATE;
366 
367             /* check we have items in the menu */
368           if (menu->items == NULL)
369                     return E_NOT_CONNECTED;
370 
371           if ((i = item_index(item)) < 0)
372                       /* item must not be a part of this menu */
373                     return E_BAD_ARGUMENT;
374 
375           menu->cur_item = i;
376           return E_OK;
377 }
378 
379 /*
380  * Return a pointer to the current item for the menu
381  */
382 ITEM *
current_item(MENU * menu)383 current_item(MENU *menu)
384 {
385           if (menu == NULL)
386                     return NULL;
387 
388           if (menu->items == NULL)
389                     return NULL;
390 
391           return menu->items[menu->cur_item];
392 }
393 
394 /*
395  * Return the index into the item array that matches item.
396  */
397 int
item_index(ITEM * item)398 item_index(ITEM *item)
399 {
400           if (item == NULL)
401                     return _menui_default_item.index;
402           else
403                     return item->index;
404 }
405