Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[menu] Add the abstract concept of a menu
Inspired-by: Robin Smidsrød <robin@smidsrod.no>
Tested-by: Robin Smidsrød <robin@smidsrod.no>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
  • Loading branch information
mcb30 committed Mar 29, 2012
1 parent 0b44527 commit 0d2fba2
Show file tree
Hide file tree
Showing 2 changed files with 224 additions and 0 deletions.
177 changes: 177 additions & 0 deletions src/core/menu.c
@@ -0,0 +1,177 @@
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

FILE_LICENCE ( GPL2_OR_LATER );

/** @file
*
* Menu selection
*
*/

#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <ipxe/list.h>
#include <ipxe/menu.h>

/** List of all menus */
static LIST_HEAD ( menus );

/**
* Create menu
*
* @v name Menu name, or NULL
* @v title Menu title, or NULL
* @ret menu Menu, or NULL on failure
*/
struct menu * create_menu ( const char *name, const char *title ) {
size_t name_len;
size_t title_len;
size_t len;
struct menu *menu;
char *name_copy;
char *title_copy;

/* Destroy any existing menu of this name */
menu = find_menu ( name );
if ( menu )
destroy_menu ( menu );

/* Use empty title if none given */
if ( ! title )
title = "";

/* Allocate menu */
name_len = ( name ? ( strlen ( name ) + 1 /* NUL */ ) : 0 );
title_len = ( strlen ( title ) + 1 /* NUL */ );
len = ( sizeof ( *menu ) + name_len + title_len );
menu = zalloc ( len );
if ( ! menu )
return NULL;
name_copy = ( ( void * ) ( menu + 1 ) );
title_copy = ( name_copy + name_len );

/* Initialise menu */
if ( name ) {
strcpy ( name_copy, name );
menu->name = name_copy;
}
strcpy ( title_copy, title );
menu->title = title_copy;
INIT_LIST_HEAD ( &menu->items );

/* Add to list of menus */
list_add_tail ( &menu->list, &menus );

DBGC ( menu, "MENU %s created with title \"%s\"\n",
menu->name, menu->title );

return menu;
}

/**
* Add menu item
*
* @v menu Menu
* @v label Label, or NULL
* @v text Text, or NULL
* @v shortcut Shortcut key
* @v is_default Item is the default item
* @ret item Menu item, or NULL on failure
*/
struct menu_item * add_menu_item ( struct menu *menu, const char *label,
const char *text, int shortcut,
int is_default ) {
size_t label_len;
size_t text_len;
size_t len;
struct menu_item *item;
char *label_copy;
char *text_copy;

/* Use empty text if none given */
if ( ! text )
text = "";

/* Allocate item */
label_len = ( label ? ( strlen ( label ) + 1 /* NUL */ ) : 0 );
text_len = ( strlen ( text ) + 1 /* NUL */ );
len = ( sizeof ( *item ) + label_len + text_len );
item = zalloc ( len );
if ( ! item )
return NULL;
label_copy = ( ( void * ) ( item + 1 ) );
text_copy = ( label_copy + label_len );

/* Initialise item */
if ( label ) {
strcpy ( label_copy, label );
item->label = label_copy;
}
strcpy ( text_copy, text );
item->text = text_copy;
item->shortcut = shortcut;
item->is_default = is_default;

/* Add to list of items */
list_add_tail ( &item->list, &menu->items );

return item;
}

/**
* Destroy menu
*
* @v menu Menu
*/
void destroy_menu ( struct menu *menu ) {
struct menu_item *item;
struct menu_item *tmp;

/* Remove from list of menus */
list_del ( &menu->list );

/* Free items */
list_for_each_entry_safe ( item, tmp, &menu->items, list ) {
list_del ( &item->list );
free ( item );
}

/* Free menu */
free ( menu );
}

/**
* Find menu
*
* @v name Menu name, or NULL
* @ret menu Menu, or NULL if not found
*/
struct menu * find_menu ( const char *name ) {
struct menu *menu;

list_for_each_entry ( menu, &menus, list ) {
if ( ( menu->name == name ) ||
( strcmp ( menu->name, name ) == 0 ) ) {
return menu;
}
}

return NULL;
}
47 changes: 47 additions & 0 deletions src/include/ipxe/menu.h
@@ -0,0 +1,47 @@
#ifndef _IPXE_MENU_H
#define _IPXE_MENU_H

/** @file
*
* Menu selection
*
*/

FILE_LICENCE ( GPL2_OR_LATER );

#include <ipxe/list.h>

/** A menu */
struct menu {
/** List of menus */
struct list_head list;
/** Name */
const char *name;
/** Title */
const char *title;
/** Menu items */
struct list_head items;
};

/** A menu item */
struct menu_item {
/** List of menu items */
struct list_head list;
/** Label */
const char *label;
/** Text */
const char *text;
/** Shortcut key */
int shortcut;
/** Is default item */
int is_default;
};

extern struct menu * create_menu ( const char *name, const char *title );
extern struct menu_item * add_menu_item ( struct menu *menu, const char *label,
const char *text, int shortcut,
int is_default );
extern void destroy_menu ( struct menu *menu );
extern struct menu * find_menu ( const char *name );

#endif /* _IPXE_MENU_H */

0 comments on commit 0d2fba2

Please sign in to comment.