183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2b69bf52dSJason Hobbs /*
3b69bf52dSJason Hobbs * Copyright 2010-2011 Calxeda, Inc.
4b69bf52dSJason Hobbs */
5b69bf52dSJason Hobbs
6b69bf52dSJason Hobbs #include <common.h>
718d66533SSimon Glass #include <cli.h>
8b69bf52dSJason Hobbs #include <malloc.h>
9b69bf52dSJason Hobbs #include <errno.h>
10b69bf52dSJason Hobbs #include <linux/list.h>
11b69bf52dSJason Hobbs
12b69bf52dSJason Hobbs #include "menu.h"
13b69bf52dSJason Hobbs
14b69bf52dSJason Hobbs /*
15b69bf52dSJason Hobbs * Internally, each item in a menu is represented by a struct menu_item.
16b69bf52dSJason Hobbs *
17b69bf52dSJason Hobbs * These items will be alloc'd and initialized by menu_item_add and destroyed
18b69bf52dSJason Hobbs * by menu_item_destroy, and the consumer of the interface never sees that
19b69bf52dSJason Hobbs * this struct is used at all.
20b69bf52dSJason Hobbs */
21b69bf52dSJason Hobbs struct menu_item {
22b69bf52dSJason Hobbs char *key;
23b69bf52dSJason Hobbs void *data;
24b69bf52dSJason Hobbs struct list_head list;
25b69bf52dSJason Hobbs };
26b69bf52dSJason Hobbs
27b69bf52dSJason Hobbs /*
28b69bf52dSJason Hobbs * The menu is composed of a list of items along with settings and callbacks
29b69bf52dSJason Hobbs * provided by the user. An incomplete definition of this struct is available
30b69bf52dSJason Hobbs * in menu.h, but the full definition is here to prevent consumers from
31b69bf52dSJason Hobbs * relying on its contents.
32b69bf52dSJason Hobbs */
33b69bf52dSJason Hobbs struct menu {
34b69bf52dSJason Hobbs struct menu_item *default_item;
35b41bc5a8SJason Hobbs int timeout;
36b69bf52dSJason Hobbs char *title;
37b69bf52dSJason Hobbs int prompt;
38b69bf52dSJason Hobbs void (*item_data_print)(void *);
39fc9d64ffSPali Rohár char *(*item_choice)(void *);
40fc9d64ffSPali Rohár void *item_choice_data;
41b69bf52dSJason Hobbs struct list_head items;
42b69bf52dSJason Hobbs };
43b69bf52dSJason Hobbs
44b69bf52dSJason Hobbs /*
45b69bf52dSJason Hobbs * An iterator function for menu items. callback will be called for each item
46b69bf52dSJason Hobbs * in m, with m, a pointer to the item, and extra being passed to callback. If
47b69bf52dSJason Hobbs * callback returns a value other than NULL, iteration stops and the value
48b69bf52dSJason Hobbs * return by callback is returned from menu_items_iter. This allows it to be
49b69bf52dSJason Hobbs * used for search type operations. It is also safe for callback to remove the
50b69bf52dSJason Hobbs * item from the list of items.
51b69bf52dSJason Hobbs */
menu_items_iter(struct menu * m,void * (* callback)(struct menu *,struct menu_item *,void *),void * extra)52b69bf52dSJason Hobbs static inline void *menu_items_iter(struct menu *m,
53b69bf52dSJason Hobbs void *(*callback)(struct menu *, struct menu_item *, void *),
54b69bf52dSJason Hobbs void *extra)
55b69bf52dSJason Hobbs {
56b69bf52dSJason Hobbs struct list_head *pos, *n;
57b69bf52dSJason Hobbs struct menu_item *item;
58b69bf52dSJason Hobbs void *ret;
59b69bf52dSJason Hobbs
60b69bf52dSJason Hobbs list_for_each_safe(pos, n, &m->items) {
61b69bf52dSJason Hobbs item = list_entry(pos, struct menu_item, list);
62b69bf52dSJason Hobbs
63b69bf52dSJason Hobbs ret = callback(m, item, extra);
64b69bf52dSJason Hobbs
65b69bf52dSJason Hobbs if (ret)
66b69bf52dSJason Hobbs return ret;
67b69bf52dSJason Hobbs }
68b69bf52dSJason Hobbs
69b69bf52dSJason Hobbs return NULL;
70b69bf52dSJason Hobbs }
71b69bf52dSJason Hobbs
72b69bf52dSJason Hobbs /*
73b69bf52dSJason Hobbs * Print a menu_item. If the consumer provided an item_data_print function
74b69bf52dSJason Hobbs * when creating the menu, call it with a pointer to the item's private data.
75b69bf52dSJason Hobbs * Otherwise, print the key of the item.
76b69bf52dSJason Hobbs */
menu_item_print(struct menu * m,struct menu_item * item,void * extra)77b69bf52dSJason Hobbs static inline void *menu_item_print(struct menu *m,
78b69bf52dSJason Hobbs struct menu_item *item,
79b69bf52dSJason Hobbs void *extra)
80b69bf52dSJason Hobbs {
81d887ad54SWolfgang Denk if (!m->item_data_print) {
8221574976SAnatolij Gustschin puts(item->key);
83d887ad54SWolfgang Denk putc('\n');
84d887ad54SWolfgang Denk } else {
85b69bf52dSJason Hobbs m->item_data_print(item->data);
86d887ad54SWolfgang Denk }
87b69bf52dSJason Hobbs
88b69bf52dSJason Hobbs return NULL;
89b69bf52dSJason Hobbs }
90b69bf52dSJason Hobbs
91b69bf52dSJason Hobbs /*
92b69bf52dSJason Hobbs * Free the memory used by a menu item. This includes the memory used by its
93b69bf52dSJason Hobbs * key.
94b69bf52dSJason Hobbs */
menu_item_destroy(struct menu * m,struct menu_item * item,void * extra)95b69bf52dSJason Hobbs static inline void *menu_item_destroy(struct menu *m,
96b69bf52dSJason Hobbs struct menu_item *item,
97b69bf52dSJason Hobbs void *extra)
98b69bf52dSJason Hobbs {
99b69bf52dSJason Hobbs if (item->key)
100b69bf52dSJason Hobbs free(item->key);
101b69bf52dSJason Hobbs
102b69bf52dSJason Hobbs free(item);
103b69bf52dSJason Hobbs
104b69bf52dSJason Hobbs return NULL;
105b69bf52dSJason Hobbs }
106b69bf52dSJason Hobbs
menu_display_statusline(struct menu * m)107002ad7b8SJeroen Hofstee __weak void menu_display_statusline(struct menu *m)
108e0611dd9SHeiko Schocher {
109e0611dd9SHeiko Schocher }
110e0611dd9SHeiko Schocher
111b69bf52dSJason Hobbs /*
112b69bf52dSJason Hobbs * Display a menu so the user can make a choice of an item. First display its
113b69bf52dSJason Hobbs * title, if any, and then each item in the menu.
114b69bf52dSJason Hobbs */
menu_display(struct menu * m)115b69bf52dSJason Hobbs static inline void menu_display(struct menu *m)
116b69bf52dSJason Hobbs {
117d887ad54SWolfgang Denk if (m->title) {
118d887ad54SWolfgang Denk puts(m->title);
119d887ad54SWolfgang Denk putc('\n');
120d887ad54SWolfgang Denk }
121e0611dd9SHeiko Schocher menu_display_statusline(m);
122b69bf52dSJason Hobbs
123b69bf52dSJason Hobbs menu_items_iter(m, menu_item_print, NULL);
124b69bf52dSJason Hobbs }
125b69bf52dSJason Hobbs
126b69bf52dSJason Hobbs /*
127b69bf52dSJason Hobbs * Check if an item's key matches a provided string, pointed to by extra. If
128b69bf52dSJason Hobbs * extra is NULL, an item with a NULL key will match. Otherwise, the item's
129b69bf52dSJason Hobbs * key has to match according to strcmp.
130b69bf52dSJason Hobbs *
131b69bf52dSJason Hobbs * This is called via menu_items_iter, so it returns a pointer to the item if
132b69bf52dSJason Hobbs * the key matches, and returns NULL otherwise.
133b69bf52dSJason Hobbs */
menu_item_key_match(struct menu * m,struct menu_item * item,void * extra)134b69bf52dSJason Hobbs static inline void *menu_item_key_match(struct menu *m,
135b69bf52dSJason Hobbs struct menu_item *item, void *extra)
136b69bf52dSJason Hobbs {
137b69bf52dSJason Hobbs char *item_key = extra;
138b69bf52dSJason Hobbs
139b69bf52dSJason Hobbs if (!item_key || !item->key) {
140b69bf52dSJason Hobbs if (item_key == item->key)
141b69bf52dSJason Hobbs return item;
142b69bf52dSJason Hobbs
143b69bf52dSJason Hobbs return NULL;
144b69bf52dSJason Hobbs }
145b69bf52dSJason Hobbs
146b69bf52dSJason Hobbs if (strcmp(item->key, item_key) == 0)
147b69bf52dSJason Hobbs return item;
148b69bf52dSJason Hobbs
149b69bf52dSJason Hobbs return NULL;
150b69bf52dSJason Hobbs }
151b69bf52dSJason Hobbs
152b69bf52dSJason Hobbs /*
153b69bf52dSJason Hobbs * Find the first item with a key matching item_key, if any exists.
154b69bf52dSJason Hobbs */
menu_item_by_key(struct menu * m,char * item_key)155b69bf52dSJason Hobbs static inline struct menu_item *menu_item_by_key(struct menu *m,
156b69bf52dSJason Hobbs char *item_key)
157b69bf52dSJason Hobbs {
158b69bf52dSJason Hobbs return menu_items_iter(m, menu_item_key_match, item_key);
159b69bf52dSJason Hobbs }
160b69bf52dSJason Hobbs
161b69bf52dSJason Hobbs /*
162b69bf52dSJason Hobbs * Set *choice to point to the default item's data, if any default item was
163b69bf52dSJason Hobbs * set, and returns 1. If no default item was set, returns -ENOENT.
164b69bf52dSJason Hobbs */
menu_default_choice(struct menu * m,void ** choice)1656a3439fdSAnatolij Gustschin int menu_default_choice(struct menu *m, void **choice)
166b69bf52dSJason Hobbs {
167b69bf52dSJason Hobbs if (m->default_item) {
168b69bf52dSJason Hobbs *choice = m->default_item->data;
169b69bf52dSJason Hobbs return 1;
170b69bf52dSJason Hobbs }
171b69bf52dSJason Hobbs
172b69bf52dSJason Hobbs return -ENOENT;
173b69bf52dSJason Hobbs }
174b69bf52dSJason Hobbs
175b69bf52dSJason Hobbs /*
176b69bf52dSJason Hobbs * Displays the menu and asks the user to choose an item. *choice will point
177b69bf52dSJason Hobbs * to the private data of the item the user chooses. The user makes a choice
178b69bf52dSJason Hobbs * by inputting a string matching the key of an item. Invalid choices will
179b69bf52dSJason Hobbs * cause the user to be prompted again, repeatedly, until the user makes a
180b69bf52dSJason Hobbs * valid choice. The user can exit the menu without making a choice via ^c.
181b69bf52dSJason Hobbs *
182b69bf52dSJason Hobbs * Returns 1 if the user made a choice, or -EINTR if they bail via ^c.
183b69bf52dSJason Hobbs */
menu_interactive_choice(struct menu * m,void ** choice)184b69bf52dSJason Hobbs static inline int menu_interactive_choice(struct menu *m, void **choice)
185b69bf52dSJason Hobbs {
186b69bf52dSJason Hobbs char cbuf[CONFIG_SYS_CBSIZE];
187b69bf52dSJason Hobbs struct menu_item *choice_item = NULL;
188b69bf52dSJason Hobbs int readret;
189b69bf52dSJason Hobbs
190b69bf52dSJason Hobbs while (!choice_item) {
191b69bf52dSJason Hobbs cbuf[0] = '\0';
192b69bf52dSJason Hobbs
193b69bf52dSJason Hobbs menu_display(m);
194b69bf52dSJason Hobbs
195fc9d64ffSPali Rohár if (!m->item_choice) {
196e1bf824dSSimon Glass readret = cli_readline_into_buffer("Enter choice: ",
197*86fbad24SMasahiro Yamada cbuf, m->timeout);
198b69bf52dSJason Hobbs
199b69bf52dSJason Hobbs if (readret >= 0) {
200b69bf52dSJason Hobbs choice_item = menu_item_by_key(m, cbuf);
201fc9d64ffSPali Rohár if (!choice_item)
202b69bf52dSJason Hobbs printf("%s not found\n", cbuf);
2039b081d88STuomas Tynkkynen } else if (readret == -1) {
2049b081d88STuomas Tynkkynen printf("<INTERRUPT>\n");
2059b081d88STuomas Tynkkynen return -EINTR;
206fc9d64ffSPali Rohár } else {
2078594753bSRob Herring return menu_default_choice(m, choice);
208b69bf52dSJason Hobbs }
209fc9d64ffSPali Rohár } else {
210fc9d64ffSPali Rohár char *key = m->item_choice(m->item_choice_data);
211fc9d64ffSPali Rohár
212fc9d64ffSPali Rohár if (key)
213fc9d64ffSPali Rohár choice_item = menu_item_by_key(m, key);
214fc9d64ffSPali Rohár }
215fc9d64ffSPali Rohár
216fc9d64ffSPali Rohár if (!choice_item)
217fc9d64ffSPali Rohár m->timeout = 0;
218fc9d64ffSPali Rohár }
219b69bf52dSJason Hobbs
220b69bf52dSJason Hobbs *choice = choice_item->data;
221b69bf52dSJason Hobbs
222b69bf52dSJason Hobbs return 1;
223b69bf52dSJason Hobbs }
224b69bf52dSJason Hobbs
225b69bf52dSJason Hobbs /*
226b69bf52dSJason Hobbs * menu_default_set() - Sets the default choice for the menu. This is safe to
227b69bf52dSJason Hobbs * call more than once on a menu.
228b69bf52dSJason Hobbs *
229b69bf52dSJason Hobbs * m - Points to a menu created by menu_create().
230b69bf52dSJason Hobbs *
231b69bf52dSJason Hobbs * item_key - Points to a string that, when compared using strcmp, matches the
232b69bf52dSJason Hobbs * key for an existing item in the menu.
233b69bf52dSJason Hobbs *
234b69bf52dSJason Hobbs * Returns 1 if successful, -EINVAL if m is NULL, or -ENOENT if no item with a
235b69bf52dSJason Hobbs * key matching item_key is found.
236b69bf52dSJason Hobbs */
menu_default_set(struct menu * m,char * item_key)237b69bf52dSJason Hobbs int menu_default_set(struct menu *m, char *item_key)
238b69bf52dSJason Hobbs {
239b69bf52dSJason Hobbs struct menu_item *item;
240b69bf52dSJason Hobbs
241b69bf52dSJason Hobbs if (!m)
242b69bf52dSJason Hobbs return -EINVAL;
243b69bf52dSJason Hobbs
244b69bf52dSJason Hobbs item = menu_item_by_key(m, item_key);
245b69bf52dSJason Hobbs
246b69bf52dSJason Hobbs if (!item)
247b69bf52dSJason Hobbs return -ENOENT;
248b69bf52dSJason Hobbs
249b69bf52dSJason Hobbs m->default_item = item;
250b69bf52dSJason Hobbs
251b69bf52dSJason Hobbs return 1;
252b69bf52dSJason Hobbs }
253b69bf52dSJason Hobbs
254b69bf52dSJason Hobbs /*
255b69bf52dSJason Hobbs * menu_get_choice() - Returns the user's selected menu entry, or the default
256b41bc5a8SJason Hobbs * if the menu is set to not prompt or the timeout expires. This is safe to
257b41bc5a8SJason Hobbs * call more than once.
258b69bf52dSJason Hobbs *
259b69bf52dSJason Hobbs * m - Points to a menu created by menu_create().
260b69bf52dSJason Hobbs *
261b69bf52dSJason Hobbs * choice - Points to a location that will store a pointer to the selected
262b69bf52dSJason Hobbs * menu item. If no item is selected or there is an error, no value will be
263b69bf52dSJason Hobbs * written at the location it points to.
264b69bf52dSJason Hobbs *
265b69bf52dSJason Hobbs * Returns 1 if successful, -EINVAL if m or choice is NULL, -ENOENT if no
266b41bc5a8SJason Hobbs * default has been set and the menu is set to not prompt or the timeout
267b41bc5a8SJason Hobbs * expires, or -EINTR if the user exits the menu via ^c.
268b69bf52dSJason Hobbs */
menu_get_choice(struct menu * m,void ** choice)269b69bf52dSJason Hobbs int menu_get_choice(struct menu *m, void **choice)
270b69bf52dSJason Hobbs {
271b69bf52dSJason Hobbs if (!m || !choice)
272b69bf52dSJason Hobbs return -EINVAL;
273b69bf52dSJason Hobbs
2748594753bSRob Herring if (!m->prompt)
275b69bf52dSJason Hobbs return menu_default_choice(m, choice);
276b69bf52dSJason Hobbs
277b69bf52dSJason Hobbs return menu_interactive_choice(m, choice);
278b69bf52dSJason Hobbs }
279b69bf52dSJason Hobbs
280b69bf52dSJason Hobbs /*
281b69bf52dSJason Hobbs * menu_item_add() - Adds or replaces a menu item. Note that this replaces the
282b69bf52dSJason Hobbs * data of an item if it already exists, but doesn't change the order of the
283b69bf52dSJason Hobbs * item.
284b69bf52dSJason Hobbs *
285b69bf52dSJason Hobbs * m - Points to a menu created by menu_create().
286b69bf52dSJason Hobbs *
287b69bf52dSJason Hobbs * item_key - Points to a string that will uniquely identify the item. The
288b69bf52dSJason Hobbs * string will be copied to internal storage, and is safe to discard after
289b69bf52dSJason Hobbs * passing to menu_item_add.
290b69bf52dSJason Hobbs *
291b69bf52dSJason Hobbs * item_data - An opaque pointer associated with an item. It is never
292b69bf52dSJason Hobbs * dereferenced internally, but will be passed to the item_data_print, and
293b69bf52dSJason Hobbs * will be returned from menu_get_choice if the menu item is selected.
294b69bf52dSJason Hobbs *
295b69bf52dSJason Hobbs * Returns 1 if successful, -EINVAL if m is NULL, or -ENOMEM if there is
296b69bf52dSJason Hobbs * insufficient memory to add the menu item.
297b69bf52dSJason Hobbs */
menu_item_add(struct menu * m,char * item_key,void * item_data)298b69bf52dSJason Hobbs int menu_item_add(struct menu *m, char *item_key, void *item_data)
299b69bf52dSJason Hobbs {
300b69bf52dSJason Hobbs struct menu_item *item;
301b69bf52dSJason Hobbs
302b69bf52dSJason Hobbs if (!m)
303b69bf52dSJason Hobbs return -EINVAL;
304b69bf52dSJason Hobbs
305b69bf52dSJason Hobbs item = menu_item_by_key(m, item_key);
306b69bf52dSJason Hobbs
307b69bf52dSJason Hobbs if (item) {
308b69bf52dSJason Hobbs item->data = item_data;
309b69bf52dSJason Hobbs return 1;
310b69bf52dSJason Hobbs }
311b69bf52dSJason Hobbs
312b69bf52dSJason Hobbs item = malloc(sizeof *item);
313b69bf52dSJason Hobbs if (!item)
314b69bf52dSJason Hobbs return -ENOMEM;
315b69bf52dSJason Hobbs
316b69bf52dSJason Hobbs item->key = strdup(item_key);
317b69bf52dSJason Hobbs
318b69bf52dSJason Hobbs if (!item->key) {
319b69bf52dSJason Hobbs free(item);
320b69bf52dSJason Hobbs return -ENOMEM;
321b69bf52dSJason Hobbs }
322b69bf52dSJason Hobbs
323b69bf52dSJason Hobbs item->data = item_data;
324b69bf52dSJason Hobbs
325b69bf52dSJason Hobbs list_add_tail(&item->list, &m->items);
326b69bf52dSJason Hobbs
327b69bf52dSJason Hobbs return 1;
328b69bf52dSJason Hobbs }
329b69bf52dSJason Hobbs
330b69bf52dSJason Hobbs /*
331b69bf52dSJason Hobbs * menu_create() - Creates a menu handle with default settings
332b69bf52dSJason Hobbs *
333b69bf52dSJason Hobbs * title - If not NULL, points to a string that will be displayed before the
334b69bf52dSJason Hobbs * list of menu items. It will be copied to internal storage, and is safe to
335b69bf52dSJason Hobbs * discard after passing to menu_create().
336b69bf52dSJason Hobbs *
337b41bc5a8SJason Hobbs * timeout - A delay in seconds to wait for user input. If 0, timeout is
338b41bc5a8SJason Hobbs * disabled, and the default choice will be returned unless prompt is 1.
339b41bc5a8SJason Hobbs *
340b41bc5a8SJason Hobbs * prompt - If 0, don't ask for user input unless there is an interrupted
341b41bc5a8SJason Hobbs * timeout. If 1, the user will be prompted for input regardless of the value
342b41bc5a8SJason Hobbs * of timeout.
343b69bf52dSJason Hobbs *
344b69bf52dSJason Hobbs * item_data_print - If not NULL, will be called for each item when the menu
345b69bf52dSJason Hobbs * is displayed, with the pointer to the item's data passed as the argument.
346b69bf52dSJason Hobbs * If NULL, each item's key will be printed instead. Since an item's key is
347b69bf52dSJason Hobbs * what must be entered to select an item, the item_data_print function should
348b69bf52dSJason Hobbs * make it obvious what the key for each entry is.
349b69bf52dSJason Hobbs *
350fc9d64ffSPali Rohár * item_choice - If not NULL, will be called when asking the user to choose an
351dd8d8da3SAlexander Merkle * item. Returns a key string corresponding to the chosen item or NULL if
352fc9d64ffSPali Rohár * no item has been selected.
353fc9d64ffSPali Rohár *
354fc9d64ffSPali Rohár * item_choice_data - Will be passed as the argument to the item_choice function
355fc9d64ffSPali Rohár *
356b69bf52dSJason Hobbs * Returns a pointer to the menu if successful, or NULL if there is
357b69bf52dSJason Hobbs * insufficient memory available to create the menu.
358b69bf52dSJason Hobbs */
menu_create(char * title,int timeout,int prompt,void (* item_data_print)(void *),char * (* item_choice)(void *),void * item_choice_data)359b41bc5a8SJason Hobbs struct menu *menu_create(char *title, int timeout, int prompt,
360fc9d64ffSPali Rohár void (*item_data_print)(void *),
361fc9d64ffSPali Rohár char *(*item_choice)(void *),
362fc9d64ffSPali Rohár void *item_choice_data)
363b69bf52dSJason Hobbs {
364b69bf52dSJason Hobbs struct menu *m;
365b69bf52dSJason Hobbs
366b69bf52dSJason Hobbs m = malloc(sizeof *m);
367b69bf52dSJason Hobbs
368b69bf52dSJason Hobbs if (!m)
369b69bf52dSJason Hobbs return NULL;
370b69bf52dSJason Hobbs
371b69bf52dSJason Hobbs m->default_item = NULL;
372b69bf52dSJason Hobbs m->prompt = prompt;
373b41bc5a8SJason Hobbs m->timeout = timeout;
374b69bf52dSJason Hobbs m->item_data_print = item_data_print;
375fc9d64ffSPali Rohár m->item_choice = item_choice;
376fc9d64ffSPali Rohár m->item_choice_data = item_choice_data;
377b69bf52dSJason Hobbs
378b69bf52dSJason Hobbs if (title) {
379b69bf52dSJason Hobbs m->title = strdup(title);
380b69bf52dSJason Hobbs if (!m->title) {
381b69bf52dSJason Hobbs free(m);
382b69bf52dSJason Hobbs return NULL;
383b69bf52dSJason Hobbs }
384b69bf52dSJason Hobbs } else
385b69bf52dSJason Hobbs m->title = NULL;
386b69bf52dSJason Hobbs
387b69bf52dSJason Hobbs
388b69bf52dSJason Hobbs INIT_LIST_HEAD(&m->items);
389b69bf52dSJason Hobbs
390b69bf52dSJason Hobbs return m;
391b69bf52dSJason Hobbs }
392b69bf52dSJason Hobbs
393b69bf52dSJason Hobbs /*
394b69bf52dSJason Hobbs * menu_destroy() - frees the memory used by a menu and its items.
395b69bf52dSJason Hobbs *
396b69bf52dSJason Hobbs * m - Points to a menu created by menu_create().
397b69bf52dSJason Hobbs *
398b69bf52dSJason Hobbs * Returns 1 if successful, or -EINVAL if m is NULL.
399b69bf52dSJason Hobbs */
menu_destroy(struct menu * m)400b69bf52dSJason Hobbs int menu_destroy(struct menu *m)
401b69bf52dSJason Hobbs {
402b69bf52dSJason Hobbs if (!m)
403b69bf52dSJason Hobbs return -EINVAL;
404b69bf52dSJason Hobbs
405b69bf52dSJason Hobbs menu_items_iter(m, menu_item_destroy, NULL);
406b69bf52dSJason Hobbs
407b69bf52dSJason Hobbs if (m->title)
408b69bf52dSJason Hobbs free(m->title);
409b69bf52dSJason Hobbs
410b69bf52dSJason Hobbs free(m);
411b69bf52dSJason Hobbs
412b69bf52dSJason Hobbs return 1;
413b69bf52dSJason Hobbs }
414