Skip to content
This repository has been archived by the owner on Aug 29, 2024. It is now read-only.

Commit

Permalink
[dynui] Generalise the concept of a menu to a dynamic user interface
Browse files Browse the repository at this point in the history
We currently have an abstract model of a dynamic menu as a list of
items, each of which has a name, a description, and assorted metadata
such as a shortcut key.  The "menu" and "item" commands construct
representations in this abstract model, and the "choose" command then
presents the items as a single-choice menu, with the selected item's
name used as the output value.

This same abstraction may be used to model a dynamic form as a list of
editable items, each of which has a corresponding setting name, an
optional description label, and assorted metadata such as a shortcut
key.  By defining a "form" command as an alias for the "menu" command,
we could construct and present forms using commands such as:

  #!ipxe
  form                     Login to ${url}
  item          username   Username or email address
  item --secret password   Password
  present

or

  #!ipxe
  form                Configure IPv4 networking for ${netX/ifname}
  item netX/ip        IPv4 address
  item netX/netmask   Subnet mask
  item netX/gateway   Gateway address
  item netX/dns       DNS server address
  present

Reusing the same abstract model for both menus and forms allows us to
minimise the increase in code size, since the implementation of the
"form" and "item" commands is essentially zero-cost.

Rename everything within the abstract data model from "menu" to
"dynamic user interface" to reflect this generalisation.

Signed-off-by: Michael Brown <[email protected]>
  • Loading branch information
mcb30 committed Jun 20, 2024
1 parent 122777f commit 5719cde
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 192 deletions.
2 changes: 1 addition & 1 deletion src/config/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ REQUIRE_OBJECT ( dhcp_cmd );
REQUIRE_OBJECT ( sanboot_cmd );
#endif
#ifdef MENU_CMD
REQUIRE_OBJECT ( menu_cmd );
REQUIRE_OBJECT ( dynui_cmd );
#endif
#ifdef LOGIN_CMD
REQUIRE_OBJECT ( login_cmd );
Expand Down
110 changes: 55 additions & 55 deletions src/core/menu.c → src/core/dynui.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,88 +25,88 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );

/** @file
*
* Menu selection
* Dynamic user interfaces
*
*/

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

/** List of all menus */
static LIST_HEAD ( menus );
/** List of all dynamic user interfaces */
static LIST_HEAD ( dynamic_uis );

/**
* Create menu
* Create dynamic user interface
*
* @v name Menu name, or NULL
* @v title Menu title, or NULL
* @ret menu Menu, or NULL on failure
* @v name User interface name, or NULL
* @v title User interface title, or NULL
* @ret dynui Dynamic user interface, or NULL on failure
*/
struct menu * create_menu ( const char *name, const char *title ) {
struct dynamic_ui * create_dynui ( const char *name, const char *title ) {
struct dynamic_ui *dynui;
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 );
/* Destroy any existing user interface of this name */
dynui = find_dynui ( name );
if ( dynui )
destroy_dynui ( dynui );

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

/* Allocate menu */
/* Allocate user interface */
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 )
len = ( sizeof ( *dynui ) + name_len + title_len );
dynui = zalloc ( len );
if ( ! dynui )
return NULL;
name_copy = ( ( void * ) ( menu + 1 ) );
name_copy = ( ( void * ) ( dynui + 1 ) );
title_copy = ( name_copy + name_len );

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

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

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

return menu;
return dynui;
}

/**
* Add menu item
* Add dynamic user interface item
*
* @v menu Menu
* @v dynui Dynamic user interface
* @v name Name, 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
* @ret item User interface item, or NULL on failure
*/
struct menu_item * add_menu_item ( struct menu *menu, const char *name,
const char *text, int shortcut,
int is_default ) {
struct dynamic_item * add_dynui_item ( struct dynamic_ui *dynui,
const char *name, const char *text,
int shortcut, int is_default ) {
struct dynamic_item *item;
size_t name_len;
size_t text_len;
size_t len;
struct menu_item *item;
char *name_copy;
char *text_copy;

Expand Down Expand Up @@ -135,46 +135,46 @@ struct menu_item * add_menu_item ( struct menu *menu, const char *name,
item->is_default = is_default;

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

return item;
}

/**
* Destroy menu
* Destroy dynamic user interface
*
* @v menu Menu
* @v dynui Dynamic user interface
*/
void destroy_menu ( struct menu *menu ) {
struct menu_item *item;
struct menu_item *tmp;
void destroy_dynui ( struct dynamic_ui *dynui ) {
struct dynamic_item *item;
struct dynamic_item *tmp;

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

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

/* Free menu */
free ( menu );
/* Free user interface */
free ( dynui );
}

/**
* Find menu
* Find dynamic user interface
*
* @v name Menu name, or NULL
* @ret menu Menu, or NULL if not found
* @v name User interface name, or NULL
* @ret dynui Dynamic user interface, or NULL if not found
*/
struct menu * find_menu ( const char *name ) {
struct menu *menu;
struct dynamic_ui * find_dynui ( const char *name ) {
struct dynamic_ui *dynui;

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

Expand Down
18 changes: 9 additions & 9 deletions src/core/parseopt.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <getopt.h>
#include <ipxe/uuid.h>
#include <ipxe/netdevice.h>
#include <ipxe/menu.h>
#include <ipxe/dynui.h>
#include <ipxe/settings.h>
#include <ipxe/params.h>
#include <ipxe/timer.h>
Expand Down Expand Up @@ -194,21 +194,21 @@ int parse_netdev_configurator ( char *text,
}

/**
* Parse menu name
* Parse dynamic user interface name
*
* @v text Text
* @ret menu Menu
* @ret dynui Dynamic user interface
* @ret rc Return status code
*/
int parse_menu ( char *text, struct menu **menu ) {
int parse_dynui ( char *text, struct dynamic_ui **dynui ) {

/* Find menu */
*menu = find_menu ( text );
if ( ! *menu ) {
/* Find user interface */
*dynui = find_dynui ( text );
if ( ! *dynui ) {
if ( text ) {
printf ( "\"%s\": no such menu\n", text );
printf ( "\"%s\": no such user interface\n", text );
} else {
printf ( "No default menu\n" );
printf ( "No default user interface\n" );
}
return -ENOENT;
}
Expand Down
Loading

0 comments on commit 5719cde

Please sign in to comment.