Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

settings_ui.c 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. /*
  2. * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation; either version 2 of the
  7. * License, or any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. */
  18. #include <stdio.h>
  19. #include <stdarg.h>
  20. #include <unistd.h>
  21. #include <string.h>
  22. #include <curses.h>
  23. #include <console.h>
  24. #include <gpxe/settings.h>
  25. #include <gpxe/editbox.h>
  26. #include <gpxe/keys.h>
  27. #include <gpxe/settings_ui.h>
  28. /** @file
  29. *
  30. * Option configuration console
  31. *
  32. */
  33. #include <gpxe/nvo.h>
  34. extern struct nvo_block *ugly_nvo_hack;
  35. /* Colour pairs */
  36. #define CPAIR_NORMAL 1
  37. #define CPAIR_SELECT 2
  38. #define CPAIR_EDIT 3
  39. #define CPAIR_ALERT 4
  40. /* Screen layout */
  41. #define TITLE_ROW 1
  42. #define SETTINGS_LIST_ROW 3
  43. #define SETTINGS_LIST_COL 1
  44. #define INFO_ROW 20
  45. #define ALERT_ROW 20
  46. #define INSTRUCTION_ROW 22
  47. #define INSTRUCTION_PAD " "
  48. /** Layout of text within a setting widget */
  49. struct setting_row {
  50. char start[0];
  51. char pad1[1];
  52. char name[15];
  53. char pad2[1];
  54. char value[60];
  55. char pad3[1];
  56. char nul;
  57. } __attribute__ (( packed ));
  58. /** A setting widget */
  59. struct setting_widget {
  60. /** Configuration context */
  61. struct config_context *context;
  62. /** Configuration setting */
  63. struct config_setting *setting;
  64. /** Screen row */
  65. unsigned int row;
  66. /** Screen column */
  67. unsigned int col;
  68. /** Edit box widget used for editing setting */
  69. struct edit_box editbox;
  70. /** Editing in progress flag */
  71. int editing;
  72. /** Buffer for setting's value */
  73. char value[256]; /* enough size for a DHCP string */
  74. };
  75. /** Registered configuration settings */
  76. static struct config_setting config_settings[0]
  77. __table_start ( struct config_setting, config_settings );
  78. static struct config_setting config_settings_end[0]
  79. __table_end ( struct config_setting, config_settings );
  80. #define NUM_SETTINGS ( ( unsigned ) ( config_settings_end - config_settings ) )
  81. static void load_setting ( struct setting_widget *widget ) __nonnull;
  82. static int save_setting ( struct setting_widget *widget ) __nonnull;
  83. static void init_setting ( struct setting_widget *widget,
  84. struct config_context *context,
  85. struct config_setting *setting,
  86. unsigned int row, unsigned int col ) __nonnull;
  87. static void draw_setting ( struct setting_widget *widget ) __nonnull;
  88. static int edit_setting ( struct setting_widget *widget, int key ) __nonnull;
  89. static void init_setting_index ( struct setting_widget *widget,
  90. struct config_context *context,
  91. unsigned int index ) __nonnull;
  92. static void vmsg ( unsigned int row, const char *fmt, va_list args ) __nonnull;
  93. static void msg ( unsigned int row, const char *fmt, ... ) __nonnull;
  94. static void valert ( const char *fmt, va_list args ) __nonnull;
  95. static void alert ( const char *fmt, ... ) __nonnull;
  96. static void draw_info_row ( struct config_setting *setting ) __nonnull;
  97. static int main_loop ( struct config_context *context ) __nonnull;
  98. /**
  99. * Load setting widget value from configuration context
  100. *
  101. * @v widget Setting widget
  102. *
  103. */
  104. static void load_setting ( struct setting_widget *widget ) {
  105. /* Mark as not editing */
  106. widget->editing = 0;
  107. /* Read current setting value */
  108. if ( show_setting ( widget->context, widget->setting,
  109. widget->value, sizeof ( widget->value ) ) != 0 ) {
  110. widget->value[0] = '\0';
  111. }
  112. /* Initialise edit box */
  113. init_editbox ( &widget->editbox, widget->value,
  114. sizeof ( widget->value ), NULL, widget->row,
  115. ( widget->col + offsetof ( struct setting_row, value )),
  116. sizeof ( ( ( struct setting_row * ) NULL )->value ) );
  117. }
  118. /**
  119. * Save setting widget value back to configuration context
  120. *
  121. * @v widget Setting widget
  122. */
  123. static int save_setting ( struct setting_widget *widget ) {
  124. return set_setting ( widget->context, widget->setting, widget->value );
  125. }
  126. /**
  127. * Initialise setting widget
  128. *
  129. * @v widget Setting widget
  130. * @v context Configuration context
  131. * @v setting Configuration setting
  132. * @v row Screen row
  133. * @v col Screen column
  134. */
  135. static void init_setting ( struct setting_widget *widget,
  136. struct config_context *context,
  137. struct config_setting *setting,
  138. unsigned int row, unsigned int col ) {
  139. /* Initialise widget structure */
  140. memset ( widget, 0, sizeof ( *widget ) );
  141. widget->context = context;
  142. widget->setting = setting;
  143. widget->row = row;
  144. widget->col = col;
  145. /* Read current setting value */
  146. load_setting ( widget );
  147. }
  148. /**
  149. * Draw setting widget
  150. *
  151. * @v widget Setting widget
  152. */
  153. static void draw_setting ( struct setting_widget *widget ) {
  154. struct setting_row row;
  155. unsigned int len;
  156. unsigned int curs_col;
  157. char *value;
  158. /* Fill row with spaces */
  159. memset ( &row, ' ', sizeof ( row ) );
  160. row.nul = '\0';
  161. /* Construct dot-padded name */
  162. memset ( row.name, '.', sizeof ( row.name ) );
  163. len = strlen ( widget->setting->name );
  164. if ( len > sizeof ( row.name ) )
  165. len = sizeof ( row.name );
  166. memcpy ( row.name, widget->setting->name, len );
  167. /* Construct space-padded value */
  168. value = widget->value;
  169. if ( ! *value )
  170. value = "<not specified>";
  171. len = strlen ( value );
  172. if ( len > sizeof ( row.value ) )
  173. len = sizeof ( row.value );
  174. memcpy ( row.value, value, len );
  175. curs_col = ( widget->col + offsetof ( typeof ( row ), value )
  176. + len );
  177. /* Print row */
  178. mvprintw ( widget->row, widget->col, "%s", row.start );
  179. move ( widget->row, curs_col );
  180. if ( widget->editing )
  181. draw_editbox ( &widget->editbox );
  182. }
  183. /**
  184. * Edit setting widget
  185. *
  186. * @v widget Setting widget
  187. * @v key Key pressed by user
  188. * @ret key Key returned to application, or zero
  189. */
  190. static int edit_setting ( struct setting_widget *widget, int key ) {
  191. widget->editing = 1;
  192. return edit_editbox ( &widget->editbox, key );
  193. }
  194. /**
  195. * Initialise setting widget by index
  196. *
  197. * @v widget Setting widget
  198. * @v context Configuration context
  199. * @v index Index of setting with settings list
  200. */
  201. static void init_setting_index ( struct setting_widget *widget,
  202. struct config_context *context,
  203. unsigned int index ) {
  204. init_setting ( widget, context, &config_settings[index],
  205. ( SETTINGS_LIST_ROW + index ), SETTINGS_LIST_COL );
  206. }
  207. /**
  208. * Print message centred on specified row
  209. *
  210. * @v row Row
  211. * @v fmt printf() format string
  212. * @v args printf() argument list
  213. */
  214. static void vmsg ( unsigned int row, const char *fmt, va_list args ) {
  215. char buf[COLS];
  216. size_t len;
  217. len = vsnprintf ( buf, sizeof ( buf ), fmt, args );
  218. mvprintw ( row, ( ( COLS - len ) / 2 ), "%s", buf );
  219. }
  220. /**
  221. * Print message centred on specified row
  222. *
  223. * @v row Row
  224. * @v fmt printf() format string
  225. * @v .. printf() arguments
  226. */
  227. static void msg ( unsigned int row, const char *fmt, ... ) {
  228. va_list args;
  229. va_start ( args, fmt );
  230. vmsg ( row, fmt, args );
  231. va_end ( args );
  232. }
  233. /**
  234. * Clear message on specified row
  235. *
  236. * @v row Row
  237. */
  238. static void clearmsg ( unsigned int row ) {
  239. move ( row, 0 );
  240. clrtoeol();
  241. }
  242. /**
  243. * Print alert message
  244. *
  245. * @v fmt printf() format string
  246. * @v args printf() argument list
  247. */
  248. static void valert ( const char *fmt, va_list args ) {
  249. clearmsg ( ALERT_ROW );
  250. color_set ( CPAIR_ALERT, NULL );
  251. vmsg ( ALERT_ROW, fmt, args );
  252. sleep ( 2 );
  253. color_set ( CPAIR_NORMAL, NULL );
  254. clearmsg ( ALERT_ROW );
  255. }
  256. /**
  257. * Print alert message
  258. *
  259. * @v fmt printf() format string
  260. * @v ... printf() arguments
  261. */
  262. static void alert ( const char *fmt, ... ) {
  263. va_list args;
  264. va_start ( args, fmt );
  265. valert ( fmt, args );
  266. va_end ( args );
  267. }
  268. /**
  269. * Draw title row
  270. */
  271. static void draw_title_row ( void ) {
  272. attron ( A_BOLD );
  273. msg ( TITLE_ROW, "gPXE option configuration console" );
  274. attroff ( A_BOLD );
  275. }
  276. /**
  277. * Draw information row
  278. *
  279. * @v setting Current configuration setting
  280. */
  281. static void draw_info_row ( struct config_setting *setting ) {
  282. clearmsg ( INFO_ROW );
  283. attron ( A_BOLD );
  284. msg ( INFO_ROW, "%s (%s) - %s", setting->name,
  285. setting->type->description, setting->description );
  286. attroff ( A_BOLD );
  287. }
  288. /**
  289. * Draw instruction row
  290. *
  291. * @v editing Editing in progress flag
  292. */
  293. static void draw_instruction_row ( int editing ) {
  294. clearmsg ( INSTRUCTION_ROW );
  295. if ( editing ) {
  296. msg ( INSTRUCTION_ROW,
  297. "Enter - accept changes" INSTRUCTION_PAD
  298. "Ctrl-C - discard changes" );
  299. } else {
  300. msg ( INSTRUCTION_ROW,
  301. "Ctrl-S - save configuration" );
  302. }
  303. }
  304. static int main_loop ( struct config_context *context ) {
  305. struct setting_widget widget;
  306. unsigned int current = 0;
  307. unsigned int next;
  308. int i;
  309. int key;
  310. int rc;
  311. /* Print initial screen content */
  312. draw_title_row();
  313. color_set ( CPAIR_NORMAL, NULL );
  314. for ( i = ( NUM_SETTINGS - 1 ) ; i >= 0 ; i-- ) {
  315. init_setting_index ( &widget, context, i );
  316. draw_setting ( &widget );
  317. }
  318. while ( 1 ) {
  319. /* Redraw information and instruction rows */
  320. draw_info_row ( widget.setting );
  321. draw_instruction_row ( widget.editing );
  322. /* Redraw current setting */
  323. color_set ( ( widget.editing ? CPAIR_EDIT : CPAIR_SELECT ),
  324. NULL );
  325. draw_setting ( &widget );
  326. color_set ( CPAIR_NORMAL, NULL );
  327. key = getkey();
  328. if ( widget.editing ) {
  329. key = edit_setting ( &widget, key );
  330. switch ( key ) {
  331. case CR:
  332. case LF:
  333. if ( ( rc = save_setting ( &widget ) ) != 0 ) {
  334. alert ( " Could not set %s: %s ",
  335. widget.setting->name,
  336. strerror ( rc ) );
  337. }
  338. /* Fall through */
  339. case CTRL_C:
  340. load_setting ( &widget );
  341. break;
  342. default:
  343. /* Do nothing */
  344. break;
  345. }
  346. } else {
  347. next = current;
  348. switch ( key ) {
  349. case KEY_DOWN:
  350. if ( next < ( NUM_SETTINGS - 1 ) )
  351. next++;
  352. break;
  353. case KEY_UP:
  354. if ( next > 0 )
  355. next--;
  356. break;
  357. case CTRL_S:
  358. if ( ( rc = nvo_save ( ugly_nvo_hack ) ) != 0){
  359. alert ( " Could not save options: %s ",
  360. strerror ( rc ) );
  361. }
  362. return rc;
  363. default:
  364. edit_setting ( &widget, key );
  365. break;
  366. }
  367. if ( next != current ) {
  368. draw_setting ( &widget );
  369. init_setting_index ( &widget, context, next );
  370. current = next;
  371. }
  372. }
  373. }
  374. }
  375. int settings_ui ( struct config_context *context ) {
  376. int rc;
  377. initscr();
  378. start_color();
  379. init_pair ( CPAIR_NORMAL, COLOR_WHITE, COLOR_BLUE );
  380. init_pair ( CPAIR_SELECT, COLOR_WHITE, COLOR_RED );
  381. init_pair ( CPAIR_EDIT, COLOR_BLACK, COLOR_CYAN );
  382. init_pair ( CPAIR_ALERT, COLOR_WHITE, COLOR_RED );
  383. color_set ( CPAIR_NORMAL, NULL );
  384. erase();
  385. rc = main_loop ( context );
  386. endwin();
  387. return rc;
  388. }