Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
util.c
Go to the documentation of this file.
1 /*
2  * util.c
3  *
4  * ORIGINAL AUTHOR: Savio Lam ([email protected])
5  * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap ([email protected])
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21 
22 #include <stdarg.h>
23 
24 #include "dialog.h"
25 
26 /* Needed in signal handler in mconf.c */
28 
30 
31 static void set_mono_theme(void)
32 {
33  dlg.screen.atr = A_NORMAL;
34  dlg.shadow.atr = A_NORMAL;
35  dlg.dialog.atr = A_NORMAL;
36  dlg.title.atr = A_BOLD;
37  dlg.border.atr = A_NORMAL;
38  dlg.button_active.atr = A_REVERSE;
39  dlg.button_inactive.atr = A_DIM;
40  dlg.button_key_active.atr = A_REVERSE;
41  dlg.button_key_inactive.atr = A_BOLD;
42  dlg.button_label_active.atr = A_REVERSE;
43  dlg.button_label_inactive.atr = A_NORMAL;
44  dlg.inputbox.atr = A_NORMAL;
45  dlg.inputbox_border.atr = A_NORMAL;
46  dlg.searchbox.atr = A_NORMAL;
47  dlg.searchbox_title.atr = A_BOLD;
48  dlg.searchbox_border.atr = A_NORMAL;
49  dlg.position_indicator.atr = A_BOLD;
50  dlg.menubox.atr = A_NORMAL;
51  dlg.menubox_border.atr = A_NORMAL;
52  dlg.item.atr = A_NORMAL;
53  dlg.item_selected.atr = A_REVERSE;
54  dlg.tag.atr = A_BOLD;
55  dlg.tag_selected.atr = A_REVERSE;
56  dlg.tag_key.atr = A_BOLD;
57  dlg.tag_key_selected.atr = A_REVERSE;
58  dlg.check.atr = A_BOLD;
59  dlg.check_selected.atr = A_REVERSE;
60  dlg.uarrow.atr = A_BOLD;
61  dlg.darrow.atr = A_BOLD;
62 }
63 
64 #define DLG_COLOR(dialog, f, b, h) \
65 do { \
66  dlg.dialog.fg = (f); \
67  dlg.dialog.bg = (b); \
68  dlg.dialog.hl = (h); \
69 } while (0)
70 
71 static void set_classic_theme(void)
72 {
76  DLG_COLOR(title, COLOR_YELLOW, COLOR_WHITE, true);
82  DLG_COLOR(button_label_active, COLOR_YELLOW, COLOR_BLUE, true);
87  DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_WHITE, true);
89  DLG_COLOR(position_indicator, COLOR_YELLOW, COLOR_WHITE, true);
94  DLG_COLOR(tag, COLOR_YELLOW, COLOR_WHITE, true);
95  DLG_COLOR(tag_selected, COLOR_YELLOW, COLOR_BLUE, true);
96  DLG_COLOR(tag_key, COLOR_YELLOW, COLOR_WHITE, true);
97  DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_BLUE, true);
102 }
103 
104 static void set_blackbg_theme(void)
105 {
111 
112  DLG_COLOR(button_active, COLOR_YELLOW, COLOR_RED, false);
113  DLG_COLOR(button_inactive, COLOR_YELLOW, COLOR_BLACK, false);
114  DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_RED, true);
118 
119  DLG_COLOR(inputbox, COLOR_YELLOW, COLOR_BLACK, false);
120  DLG_COLOR(inputbox_border, COLOR_YELLOW, COLOR_BLACK, false);
121 
122  DLG_COLOR(searchbox, COLOR_YELLOW, COLOR_BLACK, false);
123  DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_BLACK, true);
125 
127 
128  DLG_COLOR(menubox, COLOR_YELLOW, COLOR_BLACK, false);
130 
133 
135  DLG_COLOR(tag_selected, COLOR_YELLOW, COLOR_RED, true);
137  DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_RED, true);
138 
139  DLG_COLOR(check, COLOR_YELLOW, COLOR_BLACK, false);
140  DLG_COLOR(check_selected, COLOR_YELLOW, COLOR_RED, true);
141 
144 }
145 
146 static void set_bluetitle_theme(void)
147 {
148  set_classic_theme();
150  DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_BLUE, true);
156 
157 }
158 
159 /*
160  * Select color theme
161  */
162 static int set_theme(const char *theme)
163 {
164  int use_color = 1;
165  if (!theme)
166  set_bluetitle_theme();
167  else if (strcmp(theme, "classic") == 0)
168  set_classic_theme();
169  else if (strcmp(theme, "bluetitle") == 0)
170  set_bluetitle_theme();
171  else if (strcmp(theme, "blackbg") == 0)
172  set_blackbg_theme();
173  else if (strcmp(theme, "mono") == 0)
174  use_color = 0;
175 
176  return use_color;
177 }
178 
179 static void init_one_color(struct dialog_color *color)
180 {
181  static int pair = 0;
182 
183  pair++;
184  init_pair(pair, color->fg, color->bg);
185  if (color->hl)
186  color->atr = A_BOLD | COLOR_PAIR(pair);
187  else
188  color->atr = COLOR_PAIR(pair);
189 }
190 
191 static void init_dialog_colors(void)
192 {
193  init_one_color(&dlg.screen);
194  init_one_color(&dlg.shadow);
195  init_one_color(&dlg.dialog);
196  init_one_color(&dlg.title);
197  init_one_color(&dlg.border);
198  init_one_color(&dlg.button_active);
199  init_one_color(&dlg.button_inactive);
200  init_one_color(&dlg.button_key_active);
201  init_one_color(&dlg.button_key_inactive);
202  init_one_color(&dlg.button_label_active);
203  init_one_color(&dlg.button_label_inactive);
204  init_one_color(&dlg.inputbox);
205  init_one_color(&dlg.inputbox_border);
206  init_one_color(&dlg.searchbox);
207  init_one_color(&dlg.searchbox_title);
208  init_one_color(&dlg.searchbox_border);
209  init_one_color(&dlg.position_indicator);
210  init_one_color(&dlg.menubox);
211  init_one_color(&dlg.menubox_border);
212  init_one_color(&dlg.item);
213  init_one_color(&dlg.item_selected);
214  init_one_color(&dlg.tag);
215  init_one_color(&dlg.tag_selected);
216  init_one_color(&dlg.tag_key);
217  init_one_color(&dlg.tag_key_selected);
218  init_one_color(&dlg.check);
219  init_one_color(&dlg.check_selected);
220  init_one_color(&dlg.uarrow);
221  init_one_color(&dlg.darrow);
222 }
223 
224 /*
225  * Setup for color display
226  */
227 static void color_setup(const char *theme)
228 {
229  int use_color;
230 
231  use_color = set_theme(theme);
232  if (use_color && has_colors()) {
233  start_color();
234  init_dialog_colors();
235  } else
236  set_mono_theme();
237 }
238 
239 /*
240  * Set window to attribute 'attr'
241  */
242 void attr_clear(WINDOW * win, int height, int width, chtype attr)
243 {
244  int i, j;
245 
246  wattrset(win, attr);
247  for (i = 0; i < height; i++) {
248  wmove(win, i, 0);
249  for (j = 0; j < width; j++)
250  waddch(win, ' ');
251  }
252  touchwin(win);
253 }
254 
255 void dialog_clear(void)
256 {
257  attr_clear(stdscr, LINES, COLS, dlg.screen.atr);
258  /* Display background title if it exists ... - SLH */
259  if (dlg.backtitle != NULL) {
260  int i;
261 
262  wattrset(stdscr, dlg.screen.atr);
263  mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle);
264  wmove(stdscr, 1, 1);
265  for (i = 1; i < COLS - 1; i++)
266  waddch(stdscr, ACS_HLINE);
267  }
268  wnoutrefresh(stdscr);
269 }
270 
271 /*
272  * Do some initialization for dialog
273  */
274 int init_dialog(const char *backtitle)
275 {
276  int height, width;
277 
278  initscr(); /* Init curses */
279 
280  /* Get current cursor position for signal handler in mconf.c */
281  getyx(stdscr, saved_y, saved_x);
282 
283  getmaxyx(stdscr, height, width);
284  if (height < 19 || width < 80) {
285  endwin();
286  return -ERRDISPLAYTOOSMALL;
287  }
288 
289  dlg.backtitle = backtitle;
290  color_setup(getenv("MENUCONFIG_COLOR"));
291 
292  keypad(stdscr, TRUE);
293  cbreak();
294  noecho();
295  dialog_clear();
296 
297  return 0;
298 }
299 
301 {
302  dlg.backtitle = backtitle;
303 }
304 
305 /*
306  * End using dialog functions.
307  */
308 void end_dialog(int x, int y)
309 {
310  /* move cursor back to original position */
311  move(y, x);
312  refresh();
313  endwin();
314 }
315 
316 /* Print the title of the dialog. Center the title and truncate
317  * tile if wider than dialog (- 2 chars).
318  **/
319 void print_title(WINDOW *dialog, const char *title, int width)
320 {
321  if (title) {
322  int tlen = MIN(width - 2, strlen(title));
323  wattrset(dialog, dlg.title.atr);
324  mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' ');
325  mvwaddnstr(dialog, 0, (width - tlen)/2, title, tlen);
326  waddch(dialog, ' ');
327  }
328 }
329 
330 /*
331  * Print a string of text in a window, automatically wrap around to the
332  * next line if the string is too long to fit on one line. Newline
333  * characters '\n' are replaced by spaces. We start on a new line
334  * if there is no room for at least 4 nonblanks following a double-space.
335  */
336 void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
337 {
338  int newl, cur_x, cur_y;
339  int i, prompt_len, room, wlen;
340  char tempstr[MAX_LEN + 1], *word, *sp, *sp2;
341 
342  strcpy(tempstr, prompt);
343 
344  prompt_len = strlen(tempstr);
345 
346  /*
347  * Remove newlines
348  */
349  for (i = 0; i < prompt_len; i++) {
350  if (tempstr[i] == '\n')
351  tempstr[i] = ' ';
352  }
353 
354  if (prompt_len <= width - x * 2) { /* If prompt is short */
355  wmove(win, y, (width - prompt_len) / 2);
356  waddstr(win, tempstr);
357  } else {
358  cur_x = x;
359  cur_y = y;
360  newl = 1;
361  word = tempstr;
362  while (word && *word) {
363  sp = strchr(word, ' ');
364  if (sp)
365  *sp++ = 0;
366 
367  /* Wrap to next line if either the word does not fit,
368  or it is the first word of a new sentence, and it is
369  short, and the next word does not fit. */
370  room = width - cur_x;
371  wlen = strlen(word);
372  if (wlen > room ||
373  (newl && wlen < 4 && sp
374  && wlen + 1 + strlen(sp) > room
375  && (!(sp2 = strchr(sp, ' '))
376  || wlen + 1 + (sp2 - sp) > room))) {
377  cur_y++;
378  cur_x = x;
379  }
380  wmove(win, cur_y, cur_x);
381  waddstr(win, word);
382  getyx(win, cur_y, cur_x);
383  cur_x++;
384  if (sp && *sp == ' ') {
385  cur_x++; /* double space */
386  while (*++sp == ' ') ;
387  newl = 1;
388  } else
389  newl = 0;
390  word = sp;
391  }
392  }
393 }
394 
395 /*
396  * Print a button
397  */
398 void print_button(WINDOW * win, const char *label, int y, int x, int selected)
399 {
400  int i, temp;
401 
402  wmove(win, y, x);
403  wattrset(win, selected ? dlg.button_active.atr
404  : dlg.button_inactive.atr);
405  waddstr(win, "<");
406  temp = strspn(label, " ");
407  label += temp;
408  wattrset(win, selected ? dlg.button_label_active.atr
409  : dlg.button_label_inactive.atr);
410  for (i = 0; i < temp; i++)
411  waddch(win, ' ');
412  wattrset(win, selected ? dlg.button_key_active.atr
413  : dlg.button_key_inactive.atr);
414  waddch(win, label[0]);
415  wattrset(win, selected ? dlg.button_label_active.atr
416  : dlg.button_label_inactive.atr);
417  waddstr(win, (char *)label + 1);
418  wattrset(win, selected ? dlg.button_active.atr
419  : dlg.button_inactive.atr);
420  waddstr(win, ">");
421  wmove(win, y, x + temp + 1);
422 }
423 
424 /*
425  * Draw a rectangular box with line drawing characters
426  */
427 void
428 draw_box(WINDOW * win, int y, int x, int height, int width,
429  chtype box, chtype border)
430 {
431  int i, j;
432 
433  wattrset(win, 0);
434  for (i = 0; i < height; i++) {
435  wmove(win, y + i, x);
436  for (j = 0; j < width; j++)
437  if (!i && !j)
438  waddch(win, border | ACS_ULCORNER);
439  else if (i == height - 1 && !j)
440  waddch(win, border | ACS_LLCORNER);
441  else if (!i && j == width - 1)
442  waddch(win, box | ACS_URCORNER);
443  else if (i == height - 1 && j == width - 1)
444  waddch(win, box | ACS_LRCORNER);
445  else if (!i)
446  waddch(win, border | ACS_HLINE);
447  else if (i == height - 1)
448  waddch(win, box | ACS_HLINE);
449  else if (!j)
450  waddch(win, border | ACS_VLINE);
451  else if (j == width - 1)
452  waddch(win, box | ACS_VLINE);
453  else
454  waddch(win, box | ' ');
455  }
456 }
457 
458 /*
459  * Draw shadows along the right and bottom edge to give a more 3D look
460  * to the boxes
461  */
462 void draw_shadow(WINDOW * win, int y, int x, int height, int width)
463 {
464  int i;
465 
466  if (has_colors()) { /* Whether terminal supports color? */
467  wattrset(win, dlg.shadow.atr);
468  wmove(win, y + height, x + 2);
469  for (i = 0; i < width; i++)
470  waddch(win, winch(win) & A_CHARTEXT);
471  for (i = y + 1; i < y + height + 1; i++) {
472  wmove(win, i, x + width);
473  waddch(win, winch(win) & A_CHARTEXT);
474  waddch(win, winch(win) & A_CHARTEXT);
475  }
476  wnoutrefresh(win);
477  }
478 }
479 
480 /*
481  * Return the position of the first alphabetic character in a string.
482  */
483 int first_alpha(const char *string, const char *exempt)
484 {
485  int i, in_paren = 0, c;
486 
487  for (i = 0; i < strlen(string); i++) {
488  c = tolower(string[i]);
489 
490  if (strchr("<[(", c))
491  ++in_paren;
492  if (strchr(">])", c) && in_paren > 0)
493  --in_paren;
494 
495  if ((!in_paren) && isalpha(c) && strchr(exempt, c) == 0)
496  return i;
497  }
498 
499  return 0;
500 }
501 
502 /*
503  * ncurses uses ESC to detect escaped char sequences. This resutl in
504  * a small timeout before ESC is actually delivered to the application.
505  * lxdialog suggest <ESC> <ESC> which is correctly translated to two
506  * times esc. But then we need to ignore the second esc to avoid stepping
507  * out one menu too much. Filter away all escaped key sequences since
508  * keypad(FALSE) turn off ncurses support for escape sequences - and thats
509  * needed to make notimeout() do as expected.
510  */
512 {
513  int key;
514  int key2;
515  int key3;
516 
517  nodelay(win, TRUE);
518  keypad(win, FALSE);
519  key = wgetch(win);
520  key2 = wgetch(win);
521  do {
522  key3 = wgetch(win);
523  } while (key3 != ERR);
524  nodelay(win, FALSE);
525  keypad(win, TRUE);
526  if (key == KEY_ESC && key2 == ERR)
527  return KEY_ESC;
528  else if (key != ERR && key != KEY_ESC && key2 == ERR)
529  ungetch(key);
530 
531  return -1;
532 }
533 
534 /* redraw screen in new size */
535 int on_key_resize(void)
536 {
537  dialog_clear();
538  return KEY_RESIZE;
539 }
540 
544 
545 void item_reset(void)
546 {
547  struct dialog_list *p, *next;
548 
549  for (p = item_head; p; p = next) {
550  next = p->next;
551  free(p);
552  }
553  item_head = NULL;
554  item_cur = &item_nil;
555 }
556 
557 void item_make(const char *fmt, ...)
558 {
559  va_list ap;
560  struct dialog_list *p = malloc(sizeof(*p));
561 
562  if (item_head)
563  item_cur->next = p;
564  else
565  item_head = p;
566  item_cur = p;
567  memset(p, 0, sizeof(*p));
568 
569  va_start(ap, fmt);
570  vsnprintf(item_cur->node.str, sizeof(item_cur->node.str), fmt, ap);
571  va_end(ap);
572 }
573 
574 void item_add_str(const char *fmt, ...)
575 {
576  va_list ap;
577  size_t avail;
578 
579  avail = sizeof(item_cur->node.str) - strlen(item_cur->node.str);
580 
581  va_start(ap, fmt);
582  vsnprintf(item_cur->node.str + strlen(item_cur->node.str),
583  avail, fmt, ap);
584  item_cur->node.str[sizeof(item_cur->node.str) - 1] = '\0';
585  va_end(ap);
586 }
587 
588 void item_set_tag(char tag)
589 {
590  item_cur->node.tag = tag;
591 }
592 void item_set_data(void *ptr)
593 {
594  item_cur->node.data = ptr;
595 }
596 
598 {
599  item_cur->node.selected = val;
600 }
601 
603 {
604  item_foreach()
605  if (item_is_selected())
606  return 1;
607  return 0;
608 }
609 
610 void *item_data(void)
611 {
612  return item_cur->node.data;
613 }
614 
615 char item_tag(void)
616 {
617  return item_cur->node.tag;
618 }
619 
620 int item_count(void)
621 {
622  int n = 0;
623  struct dialog_list *p;
624 
625  for (p = item_head; p; p = p->next)
626  n++;
627  return n;
628 }
629 
630 void item_set(int n)
631 {
632  int i = 0;
633  item_foreach()
634  if (i++ == n)
635  return;
636 }
637 
638 int item_n(void)
639 {
640  int n = 0;
641  struct dialog_list *p;
642 
643  for (p = item_head; p; p = p->next) {
644  if (p == item_cur)
645  return n;
646  n++;
647  }
648  return 0;
649 }
650 
651 const char *item_str(void)
652 {
653  return item_cur->node.str;
654 }
655 
657 {
658  return (item_cur->node.selected != 0);
659 }
660 
661 int item_is_tag(char tag)
662 {
663  return (item_cur->node.tag == tag);
664 }