選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

settings_ui.c 10KB

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