david/ipxe
Archived
1
0
This repository has been archived on 2020-12-06. You can view files and clone it, but cannot push or open issues or pull requests.
ipxe/src/hci/tui/settings_ui.c
Michael Brown 92d15eff30 [Settings] Remove assumption that all settings have DHCP tag values
Allow for settings to be described by something other than a DHCP option
tag if desirable.  Currently used only for the MAC address setting.

Separate out fake DHCP packet creation code from dhcp.c to fakedhcp.c.

Remove notion of settings from dhcppkt.c.

Rationalise dhcp.c to use settings API only for final registration of the
DHCP options, rather than using {store,fetch}_setting throughout.
2008-03-25 20:46:16 +00:00

428 lines
10 KiB
C

/*
* Copyright (C) 2006 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.
*/
#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>
#include <string.h>
#include <curses.h>
#include <console.h>
#include <gpxe/settings.h>
#include <gpxe/editbox.h>
#include <gpxe/keys.h>
#include <gpxe/settings_ui.h>
/** @file
*
* Option configuration console
*
*/
/* Colour pairs */
#define CPAIR_NORMAL 1
#define CPAIR_SELECT 2
#define CPAIR_EDIT 3
#define CPAIR_ALERT 4
/* Screen layout */
#define TITLE_ROW 1
#define SETTINGS_LIST_ROW 3
#define SETTINGS_LIST_COL 1
#define INFO_ROW 20
#define ALERT_ROW 20
#define INSTRUCTION_ROW 22
#define INSTRUCTION_PAD " "
/** Layout of text within a setting widget */
struct setting_row {
char start[0];
char pad1[1];
char name[15];
char pad2[1];
char value[60];
char pad3[1];
char nul;
} __attribute__ (( packed ));
/** A setting widget */
struct setting_widget {
/** Settings block */
struct settings *settings;
/** Configuration setting */
struct setting *setting;
/** Screen row */
unsigned int row;
/** Screen column */
unsigned int col;
/** Edit box widget used for editing setting */
struct edit_box editbox;
/** Editing in progress flag */
int editing;
/** Buffer for setting's value */
char value[256]; /* enough size for a DHCP string */
};
/** Registered configuration settings */
static struct setting all_settings[0]
__table_start ( struct setting, settings );
static struct setting all_settings_end[0]
__table_end ( struct setting, settings );
#define NUM_SETTINGS ( ( unsigned ) ( all_settings_end - all_settings ) )
static void load_setting ( struct setting_widget *widget ) __nonnull;
static int save_setting ( struct setting_widget *widget ) __nonnull;
static void init_setting ( struct setting_widget *widget,
struct settings *settings,
struct setting *setting,
unsigned int row, unsigned int col ) __nonnull;
static void draw_setting ( struct setting_widget *widget ) __nonnull;
static int edit_setting ( struct setting_widget *widget, int key ) __nonnull;
static void init_setting_index ( struct setting_widget *widget,
struct settings *settings,
unsigned int index ) __nonnull;
static void vmsg ( unsigned int row, const char *fmt, va_list args ) __nonnull;
static void msg ( unsigned int row, const char *fmt, ... ) __nonnull;
static void valert ( const char *fmt, va_list args ) __nonnull;
static void alert ( const char *fmt, ... ) __nonnull;
static void draw_info_row ( struct setting *setting ) __nonnull;
static int main_loop ( struct settings *settings ) __nonnull;
/**
* Load setting widget value from configuration settings
*
* @v widget Setting widget
*
*/
static void load_setting ( struct setting_widget *widget ) {
/* Mark as not editing */
widget->editing = 0;
/* Read current setting value */
if ( fetchf_setting ( widget->settings, widget->setting,
widget->value, sizeof ( widget->value ) ) < 0 ) {
widget->value[0] = '\0';
}
/* Initialise edit box */
init_editbox ( &widget->editbox, widget->value,
sizeof ( widget->value ), NULL, widget->row,
( widget->col + offsetof ( struct setting_row, value )),
sizeof ( ( ( struct setting_row * ) NULL )->value ) );
}
/**
* Save setting widget value back to configuration settings
*
* @v widget Setting widget
*/
static int save_setting ( struct setting_widget *widget ) {
return storef_setting ( widget->settings, widget->setting,
widget->value );
}
/**
* Initialise setting widget
*
* @v widget Setting widget
* @v settings Settings block
* @v setting Configuration setting
* @v row Screen row
* @v col Screen column
*/
static void init_setting ( struct setting_widget *widget,
struct settings *settings,
struct setting *setting,
unsigned int row, unsigned int col ) {
/* Initialise widget structure */
memset ( widget, 0, sizeof ( *widget ) );
widget->settings = settings;
widget->setting = setting;
widget->row = row;
widget->col = col;
/* Read current setting value */
load_setting ( widget );
}
/**
* Draw setting widget
*
* @v widget Setting widget
*/
static void draw_setting ( struct setting_widget *widget ) {
struct setting_row row;
unsigned int len;
unsigned int curs_col;
char *value;
/* Fill row with spaces */
memset ( &row, ' ', sizeof ( row ) );
row.nul = '\0';
/* Construct dot-padded name */
memset ( row.name, '.', sizeof ( row.name ) );
len = strlen ( widget->setting->name );
if ( len > sizeof ( row.name ) )
len = sizeof ( row.name );
memcpy ( row.name, widget->setting->name, len );
/* Construct space-padded value */
value = widget->value;
if ( ! *value )
value = "<not specified>";
len = strlen ( value );
if ( len > sizeof ( row.value ) )
len = sizeof ( row.value );
memcpy ( row.value, value, len );
curs_col = ( widget->col + offsetof ( typeof ( row ), value )
+ len );
/* Print row */
mvprintw ( widget->row, widget->col, "%s", row.start );
move ( widget->row, curs_col );
if ( widget->editing )
draw_editbox ( &widget->editbox );
}
/**
* Edit setting widget
*
* @v widget Setting widget
* @v key Key pressed by user
* @ret key Key returned to application, or zero
*/
static int edit_setting ( struct setting_widget *widget, int key ) {
widget->editing = 1;
return edit_editbox ( &widget->editbox, key );
}
/**
* Initialise setting widget by index
*
* @v widget Setting widget
* @v settings Settings block
* @v index Index of setting with settings list
*/
static void init_setting_index ( struct setting_widget *widget,
struct settings *settings,
unsigned int index ) {
init_setting ( widget, settings, &all_settings[index],
( SETTINGS_LIST_ROW + index ), SETTINGS_LIST_COL );
}
/**
* Print message centred on specified row
*
* @v row Row
* @v fmt printf() format string
* @v args printf() argument list
*/
static void vmsg ( unsigned int row, const char *fmt, va_list args ) {
char buf[COLS];
size_t len;
len = vsnprintf ( buf, sizeof ( buf ), fmt, args );
mvprintw ( row, ( ( COLS - len ) / 2 ), "%s", buf );
}
/**
* Print message centred on specified row
*
* @v row Row
* @v fmt printf() format string
* @v .. printf() arguments
*/
static void msg ( unsigned int row, const char *fmt, ... ) {
va_list args;
va_start ( args, fmt );
vmsg ( row, fmt, args );
va_end ( args );
}
/**
* Clear message on specified row
*
* @v row Row
*/
static void clearmsg ( unsigned int row ) {
move ( row, 0 );
clrtoeol();
}
/**
* Print alert message
*
* @v fmt printf() format string
* @v args printf() argument list
*/
static void valert ( const char *fmt, va_list args ) {
clearmsg ( ALERT_ROW );
color_set ( CPAIR_ALERT, NULL );
vmsg ( ALERT_ROW, fmt, args );
sleep ( 2 );
color_set ( CPAIR_NORMAL, NULL );
clearmsg ( ALERT_ROW );
}
/**
* Print alert message
*
* @v fmt printf() format string
* @v ... printf() arguments
*/
static void alert ( const char *fmt, ... ) {
va_list args;
va_start ( args, fmt );
valert ( fmt, args );
va_end ( args );
}
/**
* Draw title row
*/
static void draw_title_row ( void ) {
attron ( A_BOLD );
msg ( TITLE_ROW, "gPXE option configuration console" );
attroff ( A_BOLD );
}
/**
* Draw information row
*
* @v setting Current configuration setting
*/
static void draw_info_row ( struct setting *setting ) {
clearmsg ( INFO_ROW );
attron ( A_BOLD );
msg ( INFO_ROW, "%s - %s", setting->name, setting->description );
attroff ( A_BOLD );
}
/**
* Draw instruction row
*
* @v editing Editing in progress flag
*/
static void draw_instruction_row ( int editing ) {
clearmsg ( INSTRUCTION_ROW );
if ( editing ) {
msg ( INSTRUCTION_ROW,
"Enter - accept changes" INSTRUCTION_PAD
"Ctrl-C - discard changes" );
} else {
msg ( INSTRUCTION_ROW,
"Ctrl-X - exit configuration utility" );
}
}
static int main_loop ( struct settings *settings ) {
struct setting_widget widget;
unsigned int current = 0;
unsigned int next;
int i;
int key;
int rc;
/* Print initial screen content */
draw_title_row();
color_set ( CPAIR_NORMAL, NULL );
for ( i = ( NUM_SETTINGS - 1 ) ; i >= 0 ; i-- ) {
init_setting_index ( &widget, settings, i );
draw_setting ( &widget );
}
while ( 1 ) {
/* Redraw information and instruction rows */
draw_info_row ( widget.setting );
draw_instruction_row ( widget.editing );
/* Redraw current setting */
color_set ( ( widget.editing ? CPAIR_EDIT : CPAIR_SELECT ),
NULL );
draw_setting ( &widget );
color_set ( CPAIR_NORMAL, NULL );
key = getkey();
if ( widget.editing ) {
key = edit_setting ( &widget, key );
switch ( key ) {
case CR:
case LF:
if ( ( rc = save_setting ( &widget ) ) != 0 ) {
alert ( " Could not set %s: %s ",
widget.setting->name,
strerror ( rc ) );
}
/* Fall through */
case CTRL_C:
load_setting ( &widget );
break;
default:
/* Do nothing */
break;
}
} else {
next = current;
switch ( key ) {
case KEY_DOWN:
if ( next < ( NUM_SETTINGS - 1 ) )
next++;
break;
case KEY_UP:
if ( next > 0 )
next--;
break;
case CTRL_X:
return 0;
default:
edit_setting ( &widget, key );
break;
}
if ( next != current ) {
draw_setting ( &widget );
init_setting_index ( &widget, settings, next );
current = next;
}
}
}
}
int settings_ui ( struct settings *settings ) {
int rc;
initscr();
start_color();
init_pair ( CPAIR_NORMAL, COLOR_WHITE, COLOR_BLUE );
init_pair ( CPAIR_SELECT, COLOR_WHITE, COLOR_RED );
init_pair ( CPAIR_EDIT, COLOR_BLACK, COLOR_CYAN );
init_pair ( CPAIR_ALERT, COLOR_WHITE, COLOR_RED );
color_set ( CPAIR_NORMAL, NULL );
erase();
rc = main_loop ( settings );
endwin();
return rc;
}