]> git.ipfire.org Git - thirdparty/util-linux.git/blame - fdisks/cfdisk.c
cfdisk: reorder abstract PT according to output
[thirdparty/util-linux.git] / fdisks / cfdisk.c
CommitLineData
6dbe3af9
KZ
1#include <stdlib.h>
2#include <stdio.h>
6dbe3af9 3#include <errno.h>
8c3a5a44 4#include <signal.h>
00b4f26a 5#include <ctype.h>
541e6934
KZ
6
7#ifdef HAVE_SLANG_H
8#include <slang.h>
9#elif defined(HAVE_SLANG_SLANG_H)
10#include <slang/slang.h>
11#endif
12
48d7b13a
KZ
13#ifdef HAVE_SLCURSES_H
14#include <slcurses.h>
15#elif defined(HAVE_SLANG_SLCURSES_H)
16#include <slang/slcurses.h>
30c97bb8
MF
17#elif defined(HAVE_NCURSESW_NCURSES_H) && defined(HAVE_WIDECHAR)
18#include <ncursesw/ncurses.h>
48d7b13a
KZ
19#elif defined(HAVE_NCURSES_H)
20#include <ncurses.h>
21#elif defined(HAVE_NCURSES_NCURSES_H)
22#include <ncurses/ncurses.h>
2b6fc908 23#endif
541e6934 24
5f94ca33
KZ
25#ifdef HAVE_WIDECHAR
26#include <wctype.h>
27#endif
28
8c3a5a44 29#include "c.h"
b2d28533 30#include "closestream.h"
7eda085c 31#include "nls.h"
8abcf290 32#include "strutils.h"
8c3a5a44 33#include "xalloc.h"
5f94ca33 34#include "mbsalign.h"
6dbe3af9 35
8c3a5a44
KZ
36#include "fdiskP.h"
37
38#define ARROW_CURSOR_STRING ">>> "
39#define ARROW_CURSOR_DUMMY " "
40#define ARROW_CURSOR_WIDTH (sizeof(ARROW_CURSOR_STRING) - 1)
41
42#define MENU_PADDING 2
43#define TABLE_START_LINE 4
44#define MENU_START_LINE (LINES - 5)
1af8003b 45#define INFO_LINE (LINES - 2)
b1f58330
KZ
46#define HINT_LINE (LINES - 1)
47
48#define CFDISK_ERR_ESC 5000
49
50#ifndef KEY_ESC
51# define KEY_ESC '\033'
52#endif
53#ifndef KEY_DELETE
54# define KEY_DELETE '\177'
55#endif
1af8003b
KZ
56
57/* colors */
58enum {
59 CFDISK_CL_NONE = 0,
45333e9d
KZ
60 CFDISK_CL_WARNING,
61 CFDISK_CL_FREESPACE,
1af8003b
KZ
62};
63static const int color_pairs[][2] = {
64 /* color foreground, background */
45333e9d
KZ
65 [CFDISK_CL_WARNING] = { COLOR_RED, -1 },
66 [CFDISK_CL_FREESPACE] = { COLOR_GREEN, -1 }
1af8003b 67};
8c3a5a44 68
8460875d
KZ
69struct cfdisk;
70typedef int (menu_callback_t)(struct cfdisk *, int);
71
72static int menu_cb_main(struct cfdisk *cf, int key);
83fa0f80
KZ
73static struct cfdisk_menudesc *menu_get_menuitem(struct cfdisk *cf, size_t idx);
74static struct cfdisk_menudesc *menu_get_menuitem_by_key(struct cfdisk *cf, int key, size_t *idx);
b1f58330
KZ
75static struct cfdisk_menu *menu_push(struct cfdisk *cf, size_t id, struct cfdisk_menudesc *desc);
76static struct cfdisk_menu *menu_pop(struct cfdisk *cf);
83fa0f80 77
1af8003b 78static int ui_refresh(struct cfdisk *cf);
83fa0f80
KZ
79static void ui_warnx(const char *fmt, ...);
80static void ui_warn(const char *fmt, ...);
81static void ui_info(const char *fmt, ...);
b1f58330
KZ
82static void ui_draw_menu(struct cfdisk *cf);
83static void ui_menu_goto(struct cfdisk *cf, int where);
84static int ui_get_size(struct cfdisk *cf, const char *prompt, uintmax_t *res,
85 uintmax_t low, uintmax_t up);
8460875d 86
83fa0f80 87static int ui_enabled;
8c3a5a44
KZ
88
89struct cfdisk_menudesc {
90 int key; /* keyboard shortcut */
91 const char *name; /* item name */
92 const char *desc; /* item description */
749af4b6
KZ
93};
94
8c3a5a44
KZ
95struct cfdisk_menu {
96 struct cfdisk_menudesc *desc;
97 char *ignore;
98 size_t id;
99 size_t width;
100 size_t nitems;
8460875d
KZ
101
102 menu_callback_t *callback;
103
8c3a5a44 104 struct cfdisk_menu *prev;
749af4b6
KZ
105};
106
8c3a5a44
KZ
107static struct cfdisk_menudesc menu_main[] = {
108 { 'b', N_("Bootable"), N_("Toggle bootable flag of the current partition") },
109 { 'd', N_("Delete"), N_("Delete the current partition") },
110// { 'g', N_("Geometry"), N_("Change disk geometry (experts only)") },
111// { 'h', N_("Help"), N_("Print help screen") },
112// { 'm', N_("Maximize"), N_("Maximize disk usage of the current partition (experts only)") },
113 { 'n', N_("New"), N_("Create new partition from free space") },
114// { 'p', N_("Print"), N_("Print partition table to the screen or to a file") },
115 { 'q', N_("Quit"), N_("Quit program without writing partition table") },
116 { 't', N_("Type"), N_("Change the partition type") },
117// { 'u', N_("Units"), N_("Change units of the partition size display (MB, sect, cyl)") },
118 { 'W', N_("Write"), N_("Write partition table to disk (this might destroy data)") },
119 { 0, NULL, NULL }
120};
6dbe3af9 121
8c3a5a44 122enum {
b1f58330
KZ
123 CFDISK_MENU_GENERATED = -1, /* used in libfdisk callback */
124
125 /* built-in menus */
8c3a5a44 126 CFDISK_MENU_MAIN = 0,
b1f58330 127
5c36a0eb
KZ
128};
129
8c3a5a44
KZ
130static struct cfdisk_menudesc *menus[] = {
131 [CFDISK_MENU_MAIN] = menu_main
132};
7eda085c 133
8460875d
KZ
134static menu_callback_t *menu_callbacks[] = {
135 [CFDISK_MENU_MAIN] = menu_cb_main
136};
137
138
8c3a5a44
KZ
139struct cfdisk {
140 struct fdisk_context *cxt; /* libfdisk context */
141 struct fdisk_table *table; /* partition table */
7eda085c 142
8c3a5a44
KZ
143 struct cfdisk_menu *menu; /* the current menu */
144 size_t menu_idx;
7eda085c 145
8c3a5a44
KZ
146 int *cols; /* output columns */
147 size_t ncols; /* number of columns */
7eda085c 148
8c3a5a44
KZ
149 char *linesbuf; /* table as string */
150 size_t linesbufsz; /* size of the tb_buf */
7eda085c 151
8c3a5a44
KZ
152 char **lines; /* array with lines */
153 size_t nlines; /* number of lines */
154 size_t lines_idx; /* current line <0..N>, exclude header */
8c3a5a44 155};
5c36a0eb 156
8c3a5a44
KZ
157static int cols_init(struct cfdisk *cf)
158{
159 assert(cf);
5c36a0eb 160
8c3a5a44
KZ
161 free(cf->cols);
162 cf->cols = NULL;
163 cf->ncols = 0;
5c36a0eb 164
8c3a5a44 165 return fdisk_get_columns(cf->cxt, 0, &cf->cols, &cf->ncols);
5c36a0eb
KZ
166}
167
8c3a5a44
KZ
168/* It would be possible to use fdisk_table_to_string(), but we want some
169 * extension to the output format, so let's do it without libfdisk
170 */
171static char *table_to_string(struct cfdisk *cf, struct fdisk_table *tb)
172{
8c3a5a44 173 const struct fdisk_column *col;
8903f7df 174 struct fdisk_partition *pa;
8c3a5a44
KZ
175 struct fdisk_label *lb;
176 struct fdisk_iter *itr = NULL;
177 struct tt *tt = NULL;
178 char *res = NULL;
8903f7df 179 size_t i;
45333e9d 180 int tree = 0;
d051ea93 181 struct tt_line *ln, *ln_cont = NULL;
8c3a5a44
KZ
182
183 DBG(FRONTEND, dbgprint("table: convert to string"));
184
185 assert(cf);
186 assert(cf->cxt);
187 assert(cf->cols);
188 assert(tb);
189
190 lb = fdisk_context_get_label(cf->cxt, NULL);
191 assert(lb);
192
8c3a5a44
KZ
193 itr = fdisk_new_iter(FDISK_ITER_FORWARD);
194 if (!itr)
195 goto done;
5c36a0eb 196
45333e9d
KZ
197 /* get container (e.g. extended partition) */
198 while (fdisk_table_next_partition(tb, itr, &pa) == 0) {
199 if (fdisk_partition_is_nested(pa)) {
200 DBG(FRONTEND, dbgprint("table: nested detected, using tree"));
45333e9d
KZ
201 tree = TT_FL_TREE;
202 break;
203 }
204 }
45333e9d
KZ
205
206 tt = tt_new_table(TT_FL_FREEDATA | TT_FL_MAX | tree);
207 if (!tt)
208 goto done;
209
8c3a5a44
KZ
210 /* headers */
211 for (i = 0; i < cf->ncols; i++) {
212 col = fdisk_label_get_column(lb, cf->cols[i]);
45333e9d
KZ
213 if (col) {
214 int fl = col->tt_flags;
45333e9d
KZ
215 if (tree && col->id == FDISK_COL_DEVICE)
216 fl |= TT_FL_TREE;
217 tt_define_column(tt, col->name, col->width, fl);
218 }
8c3a5a44
KZ
219 }
220
221 /* data */
8903f7df
KZ
222 fdisk_reset_iter(itr, FDISK_ITER_FORWARD);
223
8c3a5a44 224 while (fdisk_table_next_partition(tb, itr, &pa) == 0) {
8903f7df
KZ
225 struct tt_line *parent = fdisk_partition_is_nested(pa) ? ln_cont : NULL;
226
227 ln = tt_add_line(tt, parent);
8c3a5a44
KZ
228 if (!ln)
229 goto done;
230 for (i = 0; i < cf->ncols; i++) {
231 char *cdata = NULL;
8c3a5a44
KZ
232 col = fdisk_label_get_column(lb, cf->cols[i]);
233 if (!col)
234 continue;
235 if (fdisk_partition_to_string(pa, cf->cxt, col->id, &cdata))
236 continue;
237 tt_line_set_data(ln, i, cdata);
238 }
8903f7df 239 if (tree && fdisk_partition_is_container(pa))
45333e9d 240 ln_cont = ln;
d051ea93
KZ
241
242 tt_line_set_userdata(ln, (void *) pa);
243 fdisk_ref_partition(pa);
8c3a5a44 244 }
6dbe3af9 245
d051ea93
KZ
246 if (tt_is_empty(tt))
247 goto done;
248
249 tt_set_termreduce(tt, ARROW_CURSOR_WIDTH);
250 tt_print_table_to_string(tt, &res);
251
252 /* tt_* code might to reorder lines, let's reorder @tb according to the
253 * final output (it's no problem because partitions are addressed by
254 * parno stored within struct fdisk_partition) */
255
256 /* remove all */
257 fdisk_reset_iter(itr, FDISK_ITER_FORWARD);
258 while (fdisk_table_next_partition(tb, itr, &pa) == 0)
259 fdisk_table_remove_partition(tb, pa);
260
261 /* add all in the right order */
262 i = 0;
263 while (tt_get_output_line(tt, i++, &ln) == 0) {
264 struct fdisk_partition *pa = tt_line_get_userdata(ln);
265
266 fdisk_table_add_partition(tb, pa);
267 fdisk_unref_partition(pa);
8c3a5a44
KZ
268 }
269done:
270 tt_free_table(tt);
271 fdisk_free_iter(itr);
6dbe3af9 272
8c3a5a44 273 return res;
2b6fc908
KZ
274}
275
8460875d 276static int lines_refresh(struct cfdisk *cf)
8c3a5a44
KZ
277{
278 int rc;
279 char *p;
280 size_t i;
7eda085c 281
8c3a5a44 282 assert(cf);
2b6fc908 283
1af8003b 284 DBG(FRONTEND, dbgprint("refreshing buffer"));
c64061c9 285
8c3a5a44
KZ
286 free(cf->linesbuf);
287 free(cf->lines);
288 cf->linesbuf = NULL;
289 cf->linesbufsz = 0;
290 cf->lines = NULL;
291 cf->nlines = 0;
6dbe3af9 292
8c3a5a44 293 fdisk_unref_table(cf->table);
1af8003b 294 cf->table = NULL;
6dbe3af9 295
2cec7949
KZ
296 /* read partitions and free spaces into cf->table */
297 rc = fdisk_get_partitions(cf->cxt, &cf->table);
298 if (!rc)
299 rc = fdisk_get_freespaces(cf->cxt, &cf->table);
8c3a5a44
KZ
300 if (rc)
301 return rc;
0d8589c5 302
8c3a5a44
KZ
303 cf->linesbuf = table_to_string(cf, cf->table);
304 if (!cf->linesbuf)
305 return -ENOMEM;
6dbe3af9 306
8c3a5a44
KZ
307 cf->linesbufsz = strlen(cf->linesbuf);
308 cf->nlines = fdisk_table_get_nents(cf->table) + 1; /* 1 for header line */
6dbe3af9 309
8c3a5a44
KZ
310 cf->lines = calloc(cf->nlines, sizeof(char *));
311 if (!cf->lines)
312 return -ENOMEM;
6dbe3af9 313
8c3a5a44
KZ
314 for (p = cf->linesbuf, i = 0; p && i < cf->nlines; i++) {
315 cf->lines[i] = p;
316 p = strchr(p, '\n');
317 if (p) {
318 *p = '\0';
319 p++;
320 }
321 }
6dbe3af9 322
8c3a5a44 323 return 0;
6dbe3af9
KZ
324}
325
00b4f26a
KZ
326static struct fdisk_partition *get_current_partition(struct cfdisk *cf)
327{
328 assert(cf);
329 assert(cf->table);
330
331 return fdisk_table_get_partition(cf->table, cf->lines_idx);
332}
333
45333e9d
KZ
334static int is_freespace(struct cfdisk *cf, size_t i)
335{
336 struct fdisk_partition *pa;
337
338 assert(cf);
339 assert(cf->table);
340
341 pa = fdisk_table_get_partition(cf->table, i);
342 return fdisk_partition_is_freespace(pa);
343}
344
b1f58330
KZ
345/* converts libfdisk FDISK_ASKTYPE_MENU to cfdisk menu and returns user's
346 * responseback to libfdisk
347 */
348static int ask_menu(struct fdisk_ask *ask, struct cfdisk *cf)
349{
350 struct cfdisk_menudesc *d, *cm;
351 int key;
352 size_t i = 0, nitems;
353 const char *name, *desc;
354
355 assert(ask);
356 assert(cf);
357
358 /* create cfdisk menu according to libfdisk ask-menu, note that the
359 * last cm[] item has to be empty -- so nitems + 1 */
360 nitems = fdisk_ask_menu_get_nitems(ask);
361 cm = calloc(nitems + 1, sizeof(struct cfdisk_menudesc));
362 if (!cm)
363 return -ENOMEM;
364
365 for (i = 0; i < nitems; i++) {
366 if (fdisk_ask_menu_get_item(ask, i, &key, &name, &desc))
367 break;
368 cm[i].key = key;
369 cm[i].desc = desc;
370 cm[i].name = name;
371 }
372
373 /* make the new menu active */
374 menu_push(cf, CFDISK_MENU_GENERATED, cm);
375 ui_draw_menu(cf);
376 refresh();
377
378 /* wait for keys */
379 do {
380 switch (getch()) {
381 case KEY_LEFT:
382#ifdef KEY_BTAB
383 case KEY_BTAB:
384#endif
385 ui_menu_goto(cf, cf->menu_idx - 1);
386 break;
387 case KEY_RIGHT:
388 case '\t':
389 ui_menu_goto(cf, cf->menu_idx + 1);
390 break;
391 case KEY_ENTER:
392 case '\n':
393 case '\r':
394 d = menu_get_menuitem(cf, cf->menu_idx);
395 if (d)
396 fdisk_ask_menu_set_result(ask, d->key);
397 menu_pop(cf);
398 free(cm);
399 return 0;
400 }
401 } while (1);
402
403 menu_pop(cf);
404 free(cm);
405 return -1;
406}
407
408
8c3a5a44
KZ
409static int ask_callback(struct fdisk_context *cxt, struct fdisk_ask *ask,
410 void *data __attribute__((__unused__)))
411{
412 int rc = 0;
6dbe3af9 413
8c3a5a44
KZ
414 assert(cxt);
415 assert(ask);
6dbe3af9 416
8c3a5a44
KZ
417 switch(fdisk_ask_get_type(ask)) {
418 case FDISK_ASKTYPE_INFO:
83fa0f80 419 ui_info(fdisk_ask_print_get_mesg(ask));
8c3a5a44
KZ
420 break;
421 case FDISK_ASKTYPE_WARNX:
83fa0f80 422 ui_warnx(fdisk_ask_print_get_mesg(ask));
8c3a5a44
KZ
423 break;
424 case FDISK_ASKTYPE_WARN:
83fa0f80 425 ui_warn(fdisk_ask_print_get_mesg(ask));
8c3a5a44 426 break;
b1f58330
KZ
427 case FDISK_ASKTYPE_MENU:
428 ask_menu(ask, (struct cfdisk *) data);
429 break;
8c3a5a44 430 default:
83fa0f80
KZ
431 ui_warnx(_("internal error: unsupported dialog type %d"),
432 fdisk_ask_get_type(ask));
8c3a5a44
KZ
433 return -EINVAL;
434 }
435 return rc;
fd6b7a7f 436}
6dbe3af9 437
6dbe3af9 438
8c3a5a44
KZ
439static int ui_end(struct cfdisk *cf)
440{
83fa0f80 441 if (cf && !ui_enabled)
8c3a5a44
KZ
442 return -EINVAL;
443
48d7b13a 444#if defined(HAVE_SLCURSES_H) || defined(HAVE_SLANG_SLCURSES_H)
8c3a5a44
KZ
445 SLsmg_gotorc(LINES - 1, 0);
446 SLsmg_refresh();
2b6fc908 447#else
8c3a5a44 448 mvcur(0, COLS - 1, LINES-1, 0);
2b6fc908 449#endif
8c3a5a44
KZ
450 nl();
451 endwin();
452 printf("\n");
453 return 0;
6dbe3af9
KZ
454}
455
1af8003b 456static void ui_vprint_center(int line, int attrs, const char *fmt, va_list ap)
f609e92e 457{
8c3a5a44 458 size_t width;
8c3a5a44 459 char *buf = NULL;
f609e92e 460
8c3a5a44
KZ
461 move(line, 0);
462 clrtoeol();
f609e92e 463
8c3a5a44 464 xvasprintf(&buf, fmt, ap);
fd6b7a7f 465
b1f58330 466 width = mbs_safe_width(buf);
91ba41ca
KZ
467 if (width > (size_t) COLS) {
468 char *p = strrchr(buf + COLS, ' ');
469 if (!p)
470 p = buf + COLS;
471 *p = '\0';
472 if (line + 1 >= LINES)
473 line--;
474 attron(attrs);
475 mvaddstr(line, 0, buf);
476 mvaddstr(line + 1, 0, p+1);
477 attroff(attrs);
478 } else {
479 attron(attrs);
480 mvaddstr(line, (COLS - width) / 2, buf);
481 attroff(attrs);
482 }
8c3a5a44 483 free(buf);
6dbe3af9
KZ
484}
485
1af8003b
KZ
486static void ui_center(int line, const char *fmt, ...)
487{
488 va_list ap;
489 va_start(ap, fmt);
490 ui_vprint_center(line, 0, fmt, ap);
491 va_end(ap);
492}
493
83fa0f80
KZ
494static void ui_warnx(const char *fmt, ...)
495{
496 va_list ap;
497 va_start(ap, fmt);
498 if (ui_enabled)
499 ui_vprint_center(INFO_LINE, COLOR_PAIR(CFDISK_CL_WARNING), fmt, ap);
500 else
501 vfprintf(stderr, fmt, ap);
502 va_end(ap);
503}
504
505static void ui_warn(const char *fmt, ...)
1af8003b 506{
83fa0f80 507 char *fmt_m;
1af8003b 508 va_list ap;
83fa0f80
KZ
509
510 xasprintf(&fmt_m, "%s: %m", fmt);
511
1af8003b 512 va_start(ap, fmt);
83fa0f80
KZ
513 if (ui_enabled)
514 ui_vprint_center(INFO_LINE, COLOR_PAIR(CFDISK_CL_WARNING), fmt_m, ap);
515 else
516 vfprintf(stderr, fmt_m, ap);
1af8003b 517 va_end(ap);
83fa0f80 518 free(fmt_m);
1af8003b
KZ
519}
520
521static void ui_info(const char *fmt, ...)
522{
523 va_list ap;
524 va_start(ap, fmt);
83fa0f80
KZ
525 if (ui_enabled)
526 ui_vprint_center(INFO_LINE, A_BOLD, fmt, ap);
527 else
528 vfprintf(stdout, fmt, ap);
1af8003b
KZ
529 va_end(ap);
530}
531
532static void ui_clean_info(void)
533{
534 move(INFO_LINE, 0);
535 clrtoeol();
536}
6dbe3af9 537
b1f58330
KZ
538static void ui_hint(const char *fmt, ...)
539{
540 va_list ap;
541 va_start(ap, fmt);
542 if (ui_enabled)
543 ui_vprint_center(HINT_LINE, A_BOLD, fmt, ap);
544 else
545 vfprintf(stdout, fmt, ap);
546 va_end(ap);
547}
548
549static void ui_clean_hint(void)
550{
551 move(HINT_LINE, 0);
552 clrtoeol();
553}
554
8c3a5a44
KZ
555static void die_on_signal(int dummy __attribute__((__unused__)))
556{
557 ui_end(NULL);
558 exit(EXIT_FAILURE);
6dbe3af9
KZ
559}
560
8c3a5a44
KZ
561static void menu_update_ignore(struct cfdisk *cf)
562{
00b4f26a
KZ
563 char ignore[128] = { 0 };
564 int i = 0;
565 struct fdisk_partition *pa;
8c3a5a44 566 struct cfdisk_menu *m;
83fa0f80
KZ
567 struct cfdisk_menudesc *d, *org;
568 size_t idx;
6dbe3af9 569
8c3a5a44 570 assert(cf);
6dbe3af9 571
8c3a5a44 572 m = cf->menu;
83fa0f80
KZ
573 org = menu_get_menuitem(cf, cf->menu_idx);
574
8c3a5a44 575 DBG(FRONTEND, dbgprint("menu: update menu ignored keys"));
6dbe3af9 576
8c3a5a44
KZ
577 switch (m->id) {
578 case CFDISK_MENU_MAIN:
00b4f26a
KZ
579 pa = get_current_partition(cf);
580 if (!pa)
581 break;
582 if (fdisk_partition_is_freespace(pa)) {
583 ignore[i++] = 'd'; /* delete */
584 ignore[i++] = 't'; /* set type */
585 ignore[i++] = 'b'; /* set bootable */
83fa0f80 586 } else {
00b4f26a 587 ignore[i++] = 'n';
83fa0f80
KZ
588 if (!fdisk_is_disklabel(cf->cxt, DOS) &&
589 !fdisk_is_disklabel(cf->cxt, SGI))
590 ignore[i++] = 'b';
591 }
00b4f26a 592
8c3a5a44 593 break;
fd6b7a7f 594 }
6dbe3af9 595
00b4f26a
KZ
596 ignore[i] = '\0';
597
8c3a5a44 598 /* return if no change */
00b4f26a
KZ
599 if ( (!m->ignore && !*ignore)
600 || (m->ignore && *ignore && strcmp(m->ignore, ignore) == 0)) {
8c3a5a44 601 return;
fd6b7a7f 602 }
6dbe3af9 603
8c3a5a44 604 free(m->ignore);
8460875d 605 m->ignore = xstrdup(ignore);
8c3a5a44 606 m->nitems = 0;
6dbe3af9 607
8c3a5a44
KZ
608 for (d = m->desc; d->name; d++) {
609 if (m->ignore && strchr(m->ignore, d->key))
8460875d
KZ
610 continue;
611 m->nitems++;
8c3a5a44 612 }
83fa0f80
KZ
613
614 /* refresh menu index to be at the same menuitem or go to the first */
615 if (org && menu_get_menuitem_by_key(cf, org->key, &idx))
616 cf->menu_idx = idx;
617 else
618 cf->menu_idx = 0;
6dbe3af9
KZ
619}
620
b1f58330
KZ
621static struct cfdisk_menu *menu_push(
622 struct cfdisk *cf,
623 size_t id,
624 struct cfdisk_menudesc *desc)
8c3a5a44
KZ
625{
626 struct cfdisk_menu *m = xcalloc(1, sizeof(*m));
627 struct cfdisk_menudesc *d;
6dbe3af9 628
8c3a5a44 629 assert(cf);
6dbe3af9 630
8c3a5a44 631 DBG(FRONTEND, dbgprint("menu: new menu"));
6dbe3af9 632
8c3a5a44
KZ
633 m->prev = cf->menu;
634 m->id = id;
b1f58330 635 m->desc = desc ? desc : menus[id];
8460875d 636 m->callback = menu_callbacks[id];
6dbe3af9 637
8c3a5a44
KZ
638 for (d = m->desc; d->name; d++) {
639 const char *name = _(d->name);
b1f58330 640 size_t len = mbs_safe_width(name);
8c3a5a44
KZ
641 if (len > m->width)
642 m->width = len;
643 m->nitems++;
644 }
6dbe3af9 645
8c3a5a44
KZ
646 cf->menu = m;
647 return m;
6dbe3af9
KZ
648}
649
8c3a5a44 650static struct cfdisk_menu *menu_pop(struct cfdisk *cf)
6dbe3af9 651{
8c3a5a44 652 struct cfdisk_menu *m = NULL;
6dbe3af9 653
8c3a5a44 654 assert(cf);
7eda085c 655
8c3a5a44 656 DBG(FRONTEND, dbgprint("menu: rem menu"));
7eda085c 657
8c3a5a44
KZ
658 if (cf->menu) {
659 m = cf->menu->prev;
660 free(cf->menu->ignore);
661 free(cf->menu);
c07ebfa1 662 }
8c3a5a44
KZ
663 cf->menu = m;
664 return cf->menu;
6dbe3af9
KZ
665}
666
8460875d
KZ
667/* returns: error: < 0, success: 0, quit: 1 */
668static int menu_cb_main(struct cfdisk *cf, int key)
669{
83fa0f80 670 size_t n;
b1f58330 671 int ref = 0, rc;
83fa0f80 672 const char *info = NULL, *warn = NULL;
b1f58330 673 struct fdisk_partition *pa;
1af8003b
KZ
674
675 assert(cf);
676 assert(cf->cxt);
677 assert(key);
678
b1f58330 679 pa = get_current_partition(cf);
d80921ac 680 n = fdisk_partition_get_partno(pa);
83fa0f80 681
5139eca7
KZ
682 DBG(FRONTEND, dbgprint("menu action on %p", pa));
683
8460875d 684 switch (key) {
83fa0f80
KZ
685 case 'b': /* Bootable flag */
686 {
687 int fl = fdisk_is_disklabel(cf->cxt, DOS) ? DOS_FLAG_ACTIVE :
688 fdisk_is_disklabel(cf->cxt, SGI) ? SGI_FLAG_BOOT : 0;
689
690 if (fl && fdisk_partition_toggle_flag(cf->cxt, n, fl))
691 warn = _("Could not toggle the flag.");
692 else if (fl)
693 ref = 1;
694 break;
695 }
8460875d 696 case 'd': /* Delete */
83fa0f80
KZ
697 if (fdisk_delete_partition(cf->cxt, n) != 0)
698 warn = _("Could not delete partition %zu.");
1af8003b 699 else
83fa0f80
KZ
700 info = _("Partition %zu has been deleted.");
701 ref = 1;
8460875d
KZ
702 break;
703 case 'n': /* New */
b1f58330 704 {
872d2389 705 uint64_t start, size, dflt_size;
b1f58330
KZ
706 struct fdisk_partition *npa; /* the new partition */
707
708 if (!pa || !fdisk_partition_is_freespace(pa))
709 return -EINVAL;
710 npa = fdisk_new_partition();
711 if (!npa)
712 return -ENOMEM;
713 /* free space range */
714 start = fdisk_partition_get_start(pa);
872d2389 715 size = dflt_size = fdisk_partition_get_size(pa) * cf->cxt->sector_size;
b1f58330
KZ
716
717 if (ui_get_size(cf, _("Partition size: "), &size, 1, size)
718 == -CFDISK_ERR_ESC)
719 break;
872d2389
KZ
720
721 if (dflt_size == size) /* default is to fillin all free space */
722 fdisk_partition_end_follow_default(npa, 1);
723 else /* set relative size of the partition */
724 fdisk_partition_set_size(npa, size / cf->cxt->sector_size);
725
b1f58330 726 fdisk_partition_set_start(npa, start);
872d2389 727 fdisk_partition_partno_follow_default(npa, 1);
b1f58330
KZ
728 /* add to disk label -- libfdisk will ask for missing details */
729 rc = fdisk_add_partition(cf->cxt, npa);
730 fdisk_unref_partition(npa);
731 if (rc == 0)
732 ref = 1;
8460875d 733 break;
b1f58330 734 }
8460875d
KZ
735 case 'q': /* Quit */
736 return 1;
737 case 't': /* Type */
738 break;
739 case 'W': /* Write */
740 break;
8460875d 741 }
83fa0f80
KZ
742
743 if (ref) {
744 lines_refresh(cf);
745 ui_refresh(cf);
746 }
747 if (warn)
748 ui_warnx(warn, n);
749 else if (info)
750 ui_info(info, n);
751
8460875d
KZ
752 return 0;
753}
7eda085c 754
b1f58330 755static int ui_init(struct cfdisk *cf __attribute__((__unused__)))
8c3a5a44
KZ
756{
757 struct sigaction sa;
6dbe3af9 758
8c3a5a44 759 DBG(FRONTEND, dbgprint("ui: init"));
6dbe3af9 760
8c3a5a44
KZ
761 /* setup SIGCHLD handler */
762 sigemptyset(&sa.sa_mask);
763 sa.sa_flags = 0;
764 sa.sa_handler = die_on_signal;
765 sigaction(SIGINT, &sa, NULL);
766 sigaction(SIGTERM, &sa, NULL);
6dbe3af9 767
83fa0f80 768 ui_enabled = 1;
8c3a5a44 769 initscr();
6dbe3af9 770
1af8003b
KZ
771 if (has_colors()) {
772 size_t i;
773
774 start_color();
775 use_default_colors();
776
777 for (i = 1; i < ARRAY_SIZE(color_pairs); i++) /* yeah, start from 1! */
778 init_pair(i, color_pairs[i][0], color_pairs[i][1]);
779 }
780
8c3a5a44
KZ
781 cbreak();
782 noecho();
783 nonl();
784 curs_set(0);
785 keypad(stdscr, TRUE);
6dbe3af9 786
8c3a5a44 787 return 0;
7eda085c
KZ
788}
789
8c3a5a44
KZ
790static size_t menuitem_get_line(struct cfdisk *cf, size_t idx)
791{
792 size_t len = cf->menu->width + 4 + MENU_PADDING; /* item width */
793 size_t items = COLS / len; /* items per line */
7eda085c 794
8c3a5a44 795 return MENU_START_LINE + ((idx / items));
7eda085c
KZ
796}
797
8c3a5a44
KZ
798static int menuitem_get_column(struct cfdisk *cf, size_t idx)
799{
800 size_t len = cf->menu->width + 4 + MENU_PADDING; /* item width */
801 size_t items = COLS / len; /* items per line */
802 size_t extra = items < cf->menu->nitems ? /* extra space on line */
803 COLS % len : /* - multi-line menu */
804 COLS - (cf->menu->nitems * len); /* - one line menu */
df1dddf9 805
8c3a5a44 806 extra += MENU_PADDING; /* add padding after last item to extra */
e66ac5d3 807
8c3a5a44
KZ
808 if (idx < items)
809 return (idx * len) + (extra / 2);
810 return ((idx % items) * len) + (extra / 2);
df1dddf9
KZ
811}
812
8c3a5a44
KZ
813static struct cfdisk_menudesc *menu_get_menuitem(struct cfdisk *cf, size_t idx)
814{
815 struct cfdisk_menudesc *d;
816 size_t i;
7eda085c 817
8c3a5a44
KZ
818 for (i = 0, d = cf->menu->desc; d->name; d++) {
819 if (cf->menu->ignore && strchr(cf->menu->ignore, d->key))
820 continue;
821 if (i++ == idx)
822 return d;
d26aa358 823 }
7eda085c 824
8c3a5a44 825 return NULL;
6dbe3af9
KZ
826}
827
83fa0f80
KZ
828static struct cfdisk_menudesc *menu_get_menuitem_by_key(struct cfdisk *cf,
829 int key, size_t *idx)
830{
831 struct cfdisk_menudesc *d;
832
833 for (*idx = 0, d = cf->menu->desc; d->name; d++) {
834 if (cf->menu->ignore && strchr(cf->menu->ignore, d->key))
835 continue;
836 if (key == d->key)
837 return d;
838 (*idx)++;
839 }
840
841 return NULL;
842}
843
8c3a5a44
KZ
844static void ui_draw_menuitem(struct cfdisk *cf,
845 struct cfdisk_menudesc *d,
846 size_t idx)
847{
848 char buf[80 * MB_CUR_MAX];
849 const char *name;
850 size_t width = cf->menu->width + 2; /* 2 = blank around string */
851 int ln, cl;
852
853 name = _(d->name);
854 mbsalign(name, buf, sizeof(buf), &width, MBS_ALIGN_CENTER, 0);
855
856 ln = menuitem_get_line(cf, idx);
857 cl = menuitem_get_column(cf, idx);
858
859 DBG(FRONTEND, dbgprint("ui: menuitem: cl=%d, ln=%d, item='%s'",
860 cl, ln, buf));
861
862 if (cf->menu_idx == idx) {
863 standout();
864 mvprintw(ln, cl, "[%s]", buf);
865 standend();
866 if (d->desc)
b1f58330 867 ui_hint(d->desc);
8c3a5a44
KZ
868 } else
869 mvprintw(ln, cl, "[%s]", buf);
6dbe3af9
KZ
870}
871
8c3a5a44
KZ
872static void ui_draw_menu(struct cfdisk *cf)
873{
874 struct cfdisk_menudesc *d;
875 size_t i = 0;
7eda085c 876
8c3a5a44
KZ
877 assert(cf);
878 assert(cf->menu);
fd6b7a7f 879
8c3a5a44 880 DBG(FRONTEND, dbgprint("ui: menu: draw start"));
6dbe3af9 881
00b4f26a
KZ
882 for (i = MENU_START_LINE; i < (size_t) LINES - 1; i++) {
883 move(i, 0);
884 clrtoeol();
885 }
886
8c3a5a44 887 menu_update_ignore(cf);
6dbe3af9 888
00b4f26a 889 i = 0;
8c3a5a44
KZ
890 while ((d = menu_get_menuitem(cf, i)))
891 ui_draw_menuitem(cf, d, i++);
6dbe3af9 892
8c3a5a44 893 DBG(FRONTEND, dbgprint("ui: menu: draw end."));
6dbe3af9
KZ
894}
895
8c3a5a44
KZ
896static void ui_menu_goto(struct cfdisk *cf, int where)
897{
898 struct cfdisk_menudesc *d;
899 size_t old;
900
901 if (where < 0)
902 where = cf->menu->nitems - 1;
903 else if ((size_t) where > cf->menu->nitems - 1)
904 where = 0;
905 if ((size_t) where == cf->menu_idx)
906 return;
6dbe3af9 907
1af8003b
KZ
908 ui_clean_info();
909
8c3a5a44
KZ
910 old = cf->menu_idx;
911 cf->menu_idx = where;
6dbe3af9 912
8c3a5a44
KZ
913 d = menu_get_menuitem(cf, old);
914 ui_draw_menuitem(cf, d, old);
6dbe3af9 915
8c3a5a44
KZ
916 d = menu_get_menuitem(cf, where);
917 ui_draw_menuitem(cf, d, where);
6dbe3af9
KZ
918}
919
8460875d 920/* returns: error: < 0, success: 0, quit: 1 */
8c3a5a44
KZ
921static int ui_menu_action(struct cfdisk *cf, int key)
922{
8460875d
KZ
923 assert(cf);
924 assert(cf->menu);
925 assert(cf->menu->callback);
926
927 if (key == 0) {
928 struct cfdisk_menudesc *d = menu_get_menuitem(cf, cf->menu_idx);
929 if (!d)
930 return 0;
931 key = d->key;
00b4f26a
KZ
932
933 } else if (key != 'w' && key != 'W')
934 key = tolower(key); /* case insensitive except 'W'rite */
8460875d
KZ
935
936 DBG(FRONTEND, dbgprint("ui: menu action: key=%c", key));
937
938 if (cf->menu->ignore && strchr(cf->menu->ignore, key)) {
939 DBG(FRONTEND, dbgprint(" ignore '%c'", key));
940 return 0;
941 }
942
943 return cf->menu->callback(cf, key);
6dbe3af9
KZ
944}
945
8c3a5a44
KZ
946static void ui_draw_partition(struct cfdisk *cf, size_t i)
947{
948 int ln = TABLE_START_LINE + 1 + i; /* skip table header */
949 int cl = ARROW_CURSOR_WIDTH; /* we need extra space for cursor */
6dbe3af9 950
8c3a5a44 951 DBG(FRONTEND, dbgprint("ui: draw partition %zu", i));
6dbe3af9 952
8c3a5a44
KZ
953 if (cf->lines_idx == i) {
954 standout();
955 mvaddstr(ln, 0, ARROW_CURSOR_STRING);
956 mvaddstr(ln, cl, cf->lines[i + 1]);
957 standend();
6dbe3af9 958 } else {
45333e9d
KZ
959 int at = 0;
960
961 if (is_freespace(cf, i)) {
962 attron(COLOR_PAIR(CFDISK_CL_FREESPACE));
963 at = 1;
964 }
8c3a5a44
KZ
965 mvaddstr(ln, 0, ARROW_CURSOR_DUMMY);
966 mvaddstr(ln, cl, cf->lines[i + 1]);
45333e9d
KZ
967 if (at)
968 attroff(COLOR_PAIR(CFDISK_CL_FREESPACE));
6dbe3af9
KZ
969 }
970
6dbe3af9
KZ
971}
972
8c3a5a44
KZ
973static int ui_draw_table(struct cfdisk *cf)
974{
975 int cl = ARROW_CURSOR_WIDTH;
976 size_t i, nparts = fdisk_table_get_nents(cf->table);
7eda085c 977
8c3a5a44 978 DBG(FRONTEND, dbgprint("ui: draw table"));
6dbe3af9 979
8c3a5a44
KZ
980 if (cf->nlines - 2 < cf->lines_idx)
981 cf->lines_idx = cf->nlines - 2; /* don't count header */
6dbe3af9 982
8c3a5a44
KZ
983 /* print header */
984 attron(A_BOLD);
985 mvaddstr(TABLE_START_LINE, cl, cf->lines[0]);
986 attroff(A_BOLD);
6dbe3af9 987
8c3a5a44
KZ
988 /* print partitions */
989 for (i = 0; i < nparts; i++)
990 ui_draw_partition(cf, i);
6dbe3af9 991
8c3a5a44 992 return 0;
6dbe3af9
KZ
993}
994
8c3a5a44
KZ
995static int ui_table_goto(struct cfdisk *cf, int where)
996{
997 size_t old;
998 size_t nparts = fdisk_table_get_nents(cf->table);
6dbe3af9 999
8c3a5a44 1000 DBG(FRONTEND, dbgprint("ui: goto table %d", where));
6dbe3af9 1001
8c3a5a44
KZ
1002 if (where < 0)
1003 where = 0;
1004 else if ((size_t) where > nparts - 1)
1005 where = nparts - 1;
6dbe3af9 1006
8c3a5a44
KZ
1007 if ((size_t) where == cf->lines_idx)
1008 return 0;
6dbe3af9 1009
8c3a5a44
KZ
1010 old = cf->lines_idx;
1011 cf->lines_idx = where;
6dbe3af9 1012
8c3a5a44
KZ
1013 ui_draw_partition(cf, old); /* cleanup old */
1014 ui_draw_partition(cf, where); /* draw new */
1af8003b 1015 ui_clean_info();
8c3a5a44
KZ
1016 ui_draw_menu(cf);
1017 refresh();
1018 return 0;
6dbe3af9
KZ
1019}
1020
8c3a5a44
KZ
1021static int ui_refresh(struct cfdisk *cf)
1022{
1023 char *id = NULL;
1024 uint64_t bytes = cf->cxt->total_sectors * cf->cxt->sector_size;
1025 char *strsz = size_to_human_string(SIZE_SUFFIX_SPACE
1026 | SIZE_SUFFIX_3LETTER, bytes);
1027 erase();
1028
83fa0f80 1029 if (!ui_enabled)
8c3a5a44
KZ
1030 return -EINVAL;
1031
1032 /* header */
1033 attron(A_BOLD);
1af8003b 1034 ui_center(0, _("Disk: %s"), cf->cxt->dev_path);
8c3a5a44 1035 attroff(A_BOLD);
1af8003b 1036 ui_center(1, _("Size: %s, %ju bytes, %ju sectors"),
8c3a5a44
KZ
1037 strsz, bytes, (uintmax_t) cf->cxt->total_sectors);
1038 if (fdisk_get_disklabel_id(cf->cxt, &id) == 0 && id)
1af8003b 1039 ui_center(2, _("Label: %s, identifier: %s"),
8c3a5a44 1040 cf->cxt->label->name, id);
7eda085c 1041 else
1af8003b 1042 ui_center(2, _("Label: %s"));
8c3a5a44 1043 free(strsz);
6dbe3af9 1044
8c3a5a44
KZ
1045 ui_draw_table(cf);
1046 ui_draw_menu(cf);
6dbe3af9 1047 refresh();
8c3a5a44 1048 return 0;
6dbe3af9
KZ
1049}
1050
b1f58330
KZ
1051static ssize_t ui_get_string(struct cfdisk *cf, const char *prompt,
1052 const char *hint, char *buf, size_t len)
1053{
1054 size_t cells = 0;
1055 ssize_t i = 0, rc = -1;
1056 wint_t c;
1057 int ln = MENU_START_LINE, cl = 1;
1058
1059 assert(cf);
1060 assert(buf);
1061 assert(len);
1062
1063 move(ln, 0);
1064 clrtoeol();
1065
1066 if (prompt) {
1067 mvaddstr(ln, cl, prompt);
1068 cl += mbs_safe_width(prompt);
1069 }
1070
1071 /* default value */
1072 if (*buf) {
1073 i = strlen(buf);
1074 cells = mbs_safe_width(buf);
1075 mvaddstr(ln, cl, buf);
1076 }
1077
1078 if (hint)
1079 ui_hint(hint);
1080 else
1081 ui_clean_hint();
1082
1083 move(ln, cl + cells);
1084 curs_set(1);
1085 refresh();
1086
1087 while (1) {
1088#if !defined(HAVE_SLCURSES_H) && !defined(HAVE_SLANG_SLCURSES_H) && \
1089 defined(HAVE_LIBNCURSESW) && defined(HAVE_WIDECHAR)
1090 if (get_wch(&c) == ERR) {
1091#else
1092 if ((c = getch()) == ERR) {
1093#endif
1094 if (!isatty(STDIN_FILENO))
1095 exit(2);
1096 else
1097 goto done;
1098 }
1099 if (c == '\r' || c == '\n' || c == KEY_ENTER)
1100 break;
1101
1102 switch (c) {
1103 case KEY_ESC:
1104 rc = -CFDISK_ERR_ESC;
1105 goto done;
1106 case KEY_DELETE:
1107 case '\b':
1108 case KEY_BACKSPACE:
1109 if (i > 0) {
1110 cells--;
1111 i = mbs_truncate(buf, &cells);
1112 if (i < 0)
1113 goto done;
1114 mvaddch(ln, cl + cells, ' ');
1115 move(ln, cl + cells);
1116 } else
1117 beep();
1118 break;
1119 default:
1120#if defined(HAVE_LIBNCURSESW) && defined(HAVE_WIDECHAR)
1121 if (i + 1 < (ssize_t) len && iswprint(c)) {
1122 wchar_t wc = (wchar_t) c;
1123 char s[MB_CUR_MAX + 1];
1124 int sz = wctomb(s, wc);
1125
1126 if (sz > 0 && sz + i < (ssize_t) len) {
1127 s[sz] = '\0';
1128 mvaddnstr(ln, cl + cells, s, sz);
1129 memcpy(buf + i, s, sz);
1130 i += sz;
1131 buf[i] = '\0';
1132 cells += wcwidth(wc);
1133 } else
1134 beep();
1135 }
1136#else
1137 if (i + 1 < (ssize_t) len && isprint(c)) {
1138 mvaddch(ln, cl + cells, c);
1139 str[i++] = c;
1140 str[i] = '\0';
1141 cells++;
1142 }
1143#endif
1144 else
1145 beep();
1146 }
1147 refresh();
1148 }
1149
1150 rc = i; /* success */
1151done:
1152 move(ln, 0);
1153 clrtoeol();
1154 curs_set(0);
1155 refresh();
1156
1157 return rc;
1158}
1159
1160/* @res is default value as well as result in bytes */
1161static int ui_get_size(struct cfdisk *cf, const char *prompt, uintmax_t *res,
1162 uintmax_t low, uintmax_t up)
1163{
1164 char buf[128];
1165 uintmax_t user = 0;
1166 ssize_t rc;
1167 char *dflt = size_to_human_string(0, *res);
1168
1169 DBG(FRONTEND, dbgprint("ui: get_size (default=%ju)", *res));
1170
1171 ui_clean_info();
1172
1173 do {
91ba41ca 1174 int pwr = 0, insec = 0;
b1f58330
KZ
1175
1176 snprintf(buf, sizeof(buf), "%s", dflt);
1177 rc = ui_get_string(cf, prompt,
5139eca7 1178 _("May be followed by {M,B,G,T}iB "
91ba41ca 1179 "(the \"iB\" is optional) or S for sectors."),
b1f58330
KZ
1180 buf, sizeof(buf));
1181 if (rc == 0) {
1182 ui_warnx(_("Please, specify size."));
1183 continue; /* nothing specified */
1184 } else if (rc == -CFDISK_ERR_ESC)
1185 break; /* cancel dialog */
1186
91ba41ca
KZ
1187 if (strcmp(buf, dflt) == 0)
1188 user = *res, rc = 0; /* no change, use default */
1189 else {
1190 size_t len = strlen(buf);
1191 if (buf[len - 1] == 'S') {
1192 insec = 1;
1193 buf[len - 1] = '\0';
1194 }
1195 rc = parse_size(buf, &user, &pwr); /* parse */
1196 }
1197
b1f58330 1198 if (rc == 0) {
91ba41ca
KZ
1199 DBG(FRONTEND, dbgprint("ui: get_size user=%ju, power=%d, sectors=%s",
1200 user, pwr, insec ? "yes" : "no"));
1201 if (insec)
1202 user *= cf->cxt->sector_size;
b1f58330
KZ
1203 if (user < low) {
1204 ui_warnx(_("Minimal size is %ju"), low);
1205 rc = -ERANGE;
1206 }
1207 if (user > up && pwr && user < up + (1ULL << pwr * 10))
1208 /* ignore when the user specified size overflow
1209 * with in range specified by suffix (e.g. MiB) */
1210 user = up;
1211
1212 if (user > up) {
1213 ui_warnx(_("Maximal size is %ju bytes."), up);
1214 rc = -ERANGE;
1215 }
2cec7949
KZ
1216 } else
1217 ui_warnx(_("Failed to parse size."));
b1f58330
KZ
1218 } while (rc != 0);
1219
1220 if (rc == 0)
1221 *res = user;
1222 free(dflt);
1223
1224 DBG(FRONTEND, dbgprint("ui: get_size (result=%ju, rc=%zd)", *res, rc));
1225 return rc;
1226}
1227
1228
8c3a5a44
KZ
1229static int ui_run(struct cfdisk *cf)
1230{
1231 int rc;
6dbe3af9 1232
8c3a5a44 1233 DBG(FRONTEND, dbgprint("ui: start COLS=%d, LINES=%d", COLS, LINES));
6dbe3af9 1234
b1f58330 1235 menu_push(cf, CFDISK_MENU_MAIN, NULL);
6dbe3af9 1236
8c3a5a44
KZ
1237 rc = ui_refresh(cf);
1238 if (rc)
1239 return rc;
6dbe3af9 1240
8c3a5a44 1241 do {
8460875d 1242 int rc = 0, key = getch();
6dbe3af9 1243
8c3a5a44
KZ
1244 switch (key) {
1245 case KEY_DOWN:
1246 case '\016': /* ^N */
1247 case 'j': /* Vi-like alternative */
1248 ui_table_goto(cf, cf->lines_idx + 1);
1249 break;
1250 case KEY_UP:
1251 case '\020': /* ^P */
1252 case 'k': /* Vi-like alternative */
1253 ui_table_goto(cf, cf->lines_idx - 1);
1254 break;
1255 case KEY_HOME:
1256 ui_table_goto(cf, 0);
1257 break;
1258 case KEY_END:
1259 ui_table_goto(cf, cf->nlines - 1);
1260 break;
1261 ui_menu_action(cf, 0);
1262 break;
1263 case KEY_LEFT:
1264#ifdef KEY_BTAB
1265 case KEY_BTAB:
6dbe3af9 1266#endif
8c3a5a44
KZ
1267 ui_menu_goto(cf, cf->menu_idx - 1);
1268 break;
1269 case KEY_RIGHT:
1270 case '\t':
1271 ui_menu_goto(cf, cf->menu_idx + 1);
1272 break;
1273 case KEY_ENTER:
1274 case '\n':
1275 case '\r':
8460875d 1276 rc = ui_menu_action(cf, 0);
8c3a5a44
KZ
1277 break;
1278 default:
8460875d
KZ
1279 rc = ui_menu_action(cf, key);
1280 if (rc < 0)
8c3a5a44
KZ
1281 beep();
1282 break;
1283 }
8460875d
KZ
1284
1285 if (rc == 1)
1286 break; /* quit */
8c3a5a44 1287 } while (1);
6dbe3af9 1288
8c3a5a44 1289 menu_pop(cf);
6dbe3af9 1290
8c3a5a44
KZ
1291 DBG(FRONTEND, dbgprint("ui: end"));
1292
1293 return 0;
1294}
6dbe3af9 1295
8c3a5a44
KZ
1296int main(int argc, char *argv[])
1297{
1298 struct cfdisk _cf = { .lines_idx = 0 },
1299 *cf = &_cf;
6dbe3af9 1300
8c3a5a44
KZ
1301 setlocale(LC_ALL, "");
1302 bindtextdomain(PACKAGE, LOCALEDIR);
1303 textdomain(PACKAGE);
1304 atexit(close_stdout);
6dbe3af9 1305
8c3a5a44
KZ
1306 fdisk_init_debug(0);
1307 cf->cxt = fdisk_new_context();
1308 if (!cf->cxt)
1309 err(EXIT_FAILURE, _("failed to allocate libfdisk context"));
6dbe3af9 1310
8c3a5a44 1311 fdisk_context_set_ask(cf->cxt, ask_callback, (void *) cf);
6dbe3af9 1312
8c3a5a44
KZ
1313 if (argc != 2)
1314 err(EXIT_FAILURE, "usage: %s <device>", argv[0]);
6dbe3af9 1315
8c3a5a44
KZ
1316 if (fdisk_context_assign_device(cf->cxt, argv[optind], 0) != 0)
1317 err(EXIT_FAILURE, _("cannot open %s"), argv[optind]);
6dbe3af9 1318
8c3a5a44 1319 cols_init(cf);
fd6b7a7f 1320
8460875d 1321 if (lines_refresh(cf))
8c3a5a44 1322 errx(EXIT_FAILURE, _("failed to read partitions"));
6dbe3af9 1323
8c3a5a44
KZ
1324 /* Don't use err(), warn() from this point */
1325 ui_init(cf);
1326 ui_run(cf);
1327 ui_end(cf);
6dbe3af9 1328
8c3a5a44
KZ
1329 free(cf->lines);
1330 free(cf->linesbuf);
1331 fdisk_unref_table(cf->table);
1332 fdisk_free_context(cf->cxt);
1333 return EXIT_SUCCESS;
6dbe3af9 1334}