9 #elif defined(HAVE_SLANG_SLANG_H)
10 #include <slang/slang.h>
13 #ifdef HAVE_SLCURSES_H
15 #elif defined(HAVE_SLANG_SLCURSES_H)
16 #include <slang/slcurses.h>
17 #elif defined(HAVE_NCURSESW_NCURSES_H) && defined(HAVE_WIDECHAR)
18 #include <ncursesw/ncurses.h>
19 #elif defined(HAVE_NCURSES_H)
21 #elif defined(HAVE_NCURSES_NCURSES_H)
22 #include <ncurses/ncurses.h>
30 #include "closestream.h"
38 #define ARROW_CURSOR_STRING ">>> "
39 #define ARROW_CURSOR_DUMMY " "
40 #define ARROW_CURSOR_WIDTH (sizeof(ARROW_CURSOR_STRING) - 1)
42 #define MENU_PADDING 2
43 #define TABLE_START_LINE 4
44 #define MENU_START_LINE (LINES - 5)
45 #define INFO_LINE (LINES - 2)
46 #define HINT_LINE (LINES - 1)
48 #define CFDISK_ERR_ESC 5000
51 # define KEY_ESC '\033'
54 # define KEY_DELETE '\177'
62 static const int color_pairs
[][2] = {
63 /* color foreground, background */
64 [CFDISK_CL_WARNING
] = { COLOR_RED
, -1 },
68 typedef int (menu_callback_t
)(struct cfdisk
*, int);
70 static int menu_cb_main(struct cfdisk
*cf
, int key
);
71 static struct cfdisk_menudesc
*menu_get_menuitem(struct cfdisk
*cf
, size_t idx
);
72 static struct cfdisk_menudesc
*menu_get_menuitem_by_key(struct cfdisk
*cf
, int key
, size_t *idx
);
73 static struct cfdisk_menu
*menu_push(struct cfdisk
*cf
, size_t id
, struct cfdisk_menudesc
*desc
);
74 static struct cfdisk_menu
*menu_pop(struct cfdisk
*cf
);
76 static int ui_refresh(struct cfdisk
*cf
);
77 static void ui_warnx(const char *fmt
, ...);
78 static void ui_warn(const char *fmt
, ...);
79 static void ui_info(const char *fmt
, ...);
80 static void ui_draw_menu(struct cfdisk
*cf
);
81 static void ui_menu_goto(struct cfdisk
*cf
, int where
);
82 static int ui_get_size(struct cfdisk
*cf
, const char *prompt
, uintmax_t *res
,
83 uintmax_t low
, uintmax_t up
);
85 static int ui_enabled
;
87 struct cfdisk_menudesc
{
88 int key
; /* keyboard shortcut */
89 const char *name
; /* item name */
90 const char *desc
; /* item description */
94 struct cfdisk_menudesc
*desc
;
100 menu_callback_t
*callback
;
102 struct cfdisk_menu
*prev
;
105 static struct cfdisk_menudesc menu_main
[] = {
106 { 'b', N_("Bootable"), N_("Toggle bootable flag of the current partition") },
107 { 'd', N_("Delete"), N_("Delete the current partition") },
108 // { 'g', N_("Geometry"), N_("Change disk geometry (experts only)") },
109 // { 'h', N_("Help"), N_("Print help screen") },
110 // { 'm', N_("Maximize"), N_("Maximize disk usage of the current partition (experts only)") },
111 { 'n', N_("New"), N_("Create new partition from free space") },
112 // { 'p', N_("Print"), N_("Print partition table to the screen or to a file") },
113 { 'q', N_("Quit"), N_("Quit program without writing partition table") },
114 { 't', N_("Type"), N_("Change the partition type") },
115 // { 'u', N_("Units"), N_("Change units of the partition size display (MB, sect, cyl)") },
116 { 'W', N_("Write"), N_("Write partition table to disk (this might destroy data)") },
121 CFDISK_MENU_GENERATED
= -1, /* used in libfdisk callback */
124 CFDISK_MENU_MAIN
= 0,
128 static struct cfdisk_menudesc
*menus
[] = {
129 [CFDISK_MENU_MAIN
] = menu_main
132 static menu_callback_t
*menu_callbacks
[] = {
133 [CFDISK_MENU_MAIN
] = menu_cb_main
138 struct fdisk_context
*cxt
; /* libfdisk context */
139 struct fdisk_table
*table
; /* partition table */
141 struct cfdisk_menu
*menu
; /* the current menu */
144 int *cols
; /* output columns */
145 size_t ncols
; /* number of columns */
147 char *linesbuf
; /* table as string */
148 size_t linesbufsz
; /* size of the tb_buf */
150 char **lines
; /* array with lines */
151 size_t nlines
; /* number of lines */
152 size_t lines_idx
; /* current line <0..N>, exclude header */
155 static int cols_init(struct cfdisk
*cf
)
163 return fdisk_get_columns(cf
->cxt
, 0, &cf
->cols
, &cf
->ncols
);
166 /* It would be possible to use fdisk_table_to_string(), but we want some
167 * extension to the output format, so let's do it without libfdisk
169 static char *table_to_string(struct cfdisk
*cf
, struct fdisk_table
*tb
)
171 struct fdisk_partition
*pa
;
172 const struct fdisk_column
*col
;
173 struct fdisk_label
*lb
;
174 struct fdisk_iter
*itr
= NULL
;
175 struct tt
*tt
= NULL
;
179 DBG(FRONTEND
, dbgprint("table: convert to string"));
186 lb
= fdisk_context_get_label(cf
->cxt
, NULL
);
189 tt
= tt_new_table(TT_FL_FREEDATA
| TT_FL_MAX
);
192 itr
= fdisk_new_iter(FDISK_ITER_FORWARD
);
197 for (i
= 0; i
< cf
->ncols
; i
++) {
198 col
= fdisk_label_get_column(lb
, cf
->cols
[i
]);
200 tt_define_column(tt
, col
->name
,
206 while (fdisk_table_next_partition(tb
, itr
, &pa
) == 0) {
207 struct tt_line
*ln
= tt_add_line(tt
, NULL
);
210 for (i
= 0; i
< cf
->ncols
; i
++) {
213 col
= fdisk_label_get_column(lb
, cf
->cols
[i
]);
216 if (fdisk_partition_to_string(pa
, cf
->cxt
, col
->id
, &cdata
))
218 tt_line_set_data(ln
, i
, cdata
);
222 if (!tt_is_empty(tt
)) {
223 tt_set_termreduce(tt
, ARROW_CURSOR_WIDTH
);
224 tt_print_table_to_string(tt
, &res
);
228 fdisk_free_iter(itr
);
233 static int lines_refresh(struct cfdisk
*cf
)
241 DBG(FRONTEND
, dbgprint("refreshing buffer"));
250 fdisk_unref_table(cf
->table
);
252 fdisk_context_enable_freespace(cf
->cxt
, 1);
254 rc
= fdisk_get_table(cf
->cxt
, &cf
->table
);
258 cf
->linesbuf
= table_to_string(cf
, cf
->table
);
262 cf
->linesbufsz
= strlen(cf
->linesbuf
);
263 cf
->nlines
= fdisk_table_get_nents(cf
->table
) + 1; /* 1 for header line */
265 cf
->lines
= calloc(cf
->nlines
, sizeof(char *));
269 for (p
= cf
->linesbuf
, i
= 0; p
&& i
< cf
->nlines
; i
++) {
281 static struct fdisk_partition
*get_current_partition(struct cfdisk
*cf
)
286 return fdisk_table_get_partition(cf
->table
, cf
->lines_idx
);
289 /* converts libfdisk FDISK_ASKTYPE_MENU to cfdisk menu and returns user's
290 * responseback to libfdisk
292 static int ask_menu(struct fdisk_ask
*ask
, struct cfdisk
*cf
)
294 struct cfdisk_menudesc
*d
, *cm
;
296 size_t i
= 0, nitems
;
297 const char *name
, *desc
;
302 /* create cfdisk menu according to libfdisk ask-menu, note that the
303 * last cm[] item has to be empty -- so nitems + 1 */
304 nitems
= fdisk_ask_menu_get_nitems(ask
);
305 cm
= calloc(nitems
+ 1, sizeof(struct cfdisk_menudesc
));
309 for (i
= 0; i
< nitems
; i
++) {
310 if (fdisk_ask_menu_get_item(ask
, i
, &key
, &name
, &desc
))
317 /* make the new menu active */
318 menu_push(cf
, CFDISK_MENU_GENERATED
, cm
);
329 ui_menu_goto(cf
, cf
->menu_idx
- 1);
333 ui_menu_goto(cf
, cf
->menu_idx
+ 1);
338 d
= menu_get_menuitem(cf
, cf
->menu_idx
);
340 fdisk_ask_menu_set_result(ask
, d
->key
);
353 static int ask_callback(struct fdisk_context
*cxt
, struct fdisk_ask
*ask
,
354 void *data
__attribute__((__unused__
)))
361 switch(fdisk_ask_get_type(ask
)) {
362 case FDISK_ASKTYPE_INFO
:
363 ui_info(fdisk_ask_print_get_mesg(ask
));
365 case FDISK_ASKTYPE_WARNX
:
366 ui_warnx(fdisk_ask_print_get_mesg(ask
));
368 case FDISK_ASKTYPE_WARN
:
369 ui_warn(fdisk_ask_print_get_mesg(ask
));
371 case FDISK_ASKTYPE_MENU
:
372 ask_menu(ask
, (struct cfdisk
*) data
);
375 ui_warnx(_("internal error: unsupported dialog type %d"),
376 fdisk_ask_get_type(ask
));
383 static int ui_end(struct cfdisk
*cf
)
385 if (cf
&& !ui_enabled
)
388 #if defined(HAVE_SLCURSES_H) || defined(HAVE_SLANG_SLCURSES_H)
389 SLsmg_gotorc(LINES
- 1, 0);
392 mvcur(0, COLS
- 1, LINES
-1, 0);
400 static void ui_vprint_center(int line
, int attrs
, const char *fmt
, va_list ap
)
408 xvasprintf(&buf
, fmt
, ap
);
410 width
= mbs_safe_width(buf
);
413 mvaddstr(line
, (COLS
- width
) / 2, buf
);
418 static void ui_center(int line
, const char *fmt
, ...)
422 ui_vprint_center(line
, 0, fmt
, ap
);
426 static void ui_warnx(const char *fmt
, ...)
431 ui_vprint_center(INFO_LINE
, COLOR_PAIR(CFDISK_CL_WARNING
), fmt
, ap
);
433 vfprintf(stderr
, fmt
, ap
);
437 static void ui_warn(const char *fmt
, ...)
442 xasprintf(&fmt_m
, "%s: %m", fmt
);
446 ui_vprint_center(INFO_LINE
, COLOR_PAIR(CFDISK_CL_WARNING
), fmt_m
, ap
);
448 vfprintf(stderr
, fmt_m
, ap
);
453 static void ui_info(const char *fmt
, ...)
458 ui_vprint_center(INFO_LINE
, A_BOLD
, fmt
, ap
);
460 vfprintf(stdout
, fmt
, ap
);
464 static void ui_clean_info(void)
470 static void ui_hint(const char *fmt
, ...)
475 ui_vprint_center(HINT_LINE
, A_BOLD
, fmt
, ap
);
477 vfprintf(stdout
, fmt
, ap
);
481 static void ui_clean_hint(void)
487 static void die_on_signal(int dummy
__attribute__((__unused__
)))
493 static void menu_update_ignore(struct cfdisk
*cf
)
495 char ignore
[128] = { 0 };
497 struct fdisk_partition
*pa
;
498 struct cfdisk_menu
*m
;
499 struct cfdisk_menudesc
*d
, *org
;
505 org
= menu_get_menuitem(cf
, cf
->menu_idx
);
507 DBG(FRONTEND
, dbgprint("menu: update menu ignored keys"));
510 case CFDISK_MENU_MAIN
:
511 pa
= get_current_partition(cf
);
514 if (fdisk_partition_is_freespace(pa
)) {
515 ignore
[i
++] = 'd'; /* delete */
516 ignore
[i
++] = 't'; /* set type */
517 ignore
[i
++] = 'b'; /* set bootable */
520 if (!fdisk_is_disklabel(cf
->cxt
, DOS
) &&
521 !fdisk_is_disklabel(cf
->cxt
, SGI
))
530 /* return if no change */
531 if ( (!m
->ignore
&& !*ignore
)
532 || (m
->ignore
&& *ignore
&& strcmp(m
->ignore
, ignore
) == 0)) {
537 m
->ignore
= xstrdup(ignore
);
540 for (d
= m
->desc
; d
->name
; d
++) {
541 if (m
->ignore
&& strchr(m
->ignore
, d
->key
))
546 /* refresh menu index to be at the same menuitem or go to the first */
547 if (org
&& menu_get_menuitem_by_key(cf
, org
->key
, &idx
))
553 static struct cfdisk_menu
*menu_push(
556 struct cfdisk_menudesc
*desc
)
558 struct cfdisk_menu
*m
= xcalloc(1, sizeof(*m
));
559 struct cfdisk_menudesc
*d
;
563 DBG(FRONTEND
, dbgprint("menu: new menu"));
567 m
->desc
= desc
? desc
: menus
[id
];
568 m
->callback
= menu_callbacks
[id
];
570 for (d
= m
->desc
; d
->name
; d
++) {
571 const char *name
= _(d
->name
);
572 size_t len
= mbs_safe_width(name
);
582 static struct cfdisk_menu
*menu_pop(struct cfdisk
*cf
)
584 struct cfdisk_menu
*m
= NULL
;
588 DBG(FRONTEND
, dbgprint("menu: rem menu"));
592 free(cf
->menu
->ignore
);
599 /* returns: error: < 0, success: 0, quit: 1 */
600 static int menu_cb_main(struct cfdisk
*cf
, int key
)
604 const char *info
= NULL
, *warn
= NULL
;
605 struct fdisk_partition
*pa
;
611 n
= cf
->lines_idx
; /* the current partition */
612 pa
= get_current_partition(cf
);
615 case 'b': /* Bootable flag */
617 int fl
= fdisk_is_disklabel(cf
->cxt
, DOS
) ? DOS_FLAG_ACTIVE
:
618 fdisk_is_disklabel(cf
->cxt
, SGI
) ? SGI_FLAG_BOOT
: 0;
620 if (fl
&& fdisk_partition_toggle_flag(cf
->cxt
, n
, fl
))
621 warn
= _("Could not toggle the flag.");
626 case 'd': /* Delete */
627 if (fdisk_delete_partition(cf
->cxt
, n
) != 0)
628 warn
= _("Could not delete partition %zu.");
630 info
= _("Partition %zu has been deleted.");
635 uint64_t start
, size
;
636 struct fdisk_partition
*npa
; /* the new partition */
638 if (!pa
|| !fdisk_partition_is_freespace(pa
))
640 npa
= fdisk_new_partition();
643 /* free space range */
644 start
= fdisk_partition_get_start(pa
);
645 size
= fdisk_partition_get_size(pa
) * cf
->cxt
->sector_size
;
647 if (ui_get_size(cf
, _("Partition size: "), &size
, 1, size
)
650 size
/= cf
->cxt
->sector_size
;
651 /* properties of the new partition */
652 fdisk_partition_set_start(npa
, start
);
653 fdisk_partition_set_size(npa
, size
);
654 fdisk_partition_partno_follow_default(npa
, 1);
655 /* add to disk label -- libfdisk will ask for missing details */
656 rc
= fdisk_add_partition(cf
->cxt
, npa
);
657 fdisk_unref_partition(npa
);
666 case 'W': /* Write */
682 static int ui_init(struct cfdisk
*cf
__attribute__((__unused__
)))
686 DBG(FRONTEND
, dbgprint("ui: init"));
688 /* setup SIGCHLD handler */
689 sigemptyset(&sa
.sa_mask
);
691 sa
.sa_handler
= die_on_signal
;
692 sigaction(SIGINT
, &sa
, NULL
);
693 sigaction(SIGTERM
, &sa
, NULL
);
702 use_default_colors();
704 for (i
= 1; i
< ARRAY_SIZE(color_pairs
); i
++) /* yeah, start from 1! */
705 init_pair(i
, color_pairs
[i
][0], color_pairs
[i
][1]);
712 keypad(stdscr
, TRUE
);
717 static size_t menuitem_get_line(struct cfdisk
*cf
, size_t idx
)
719 size_t len
= cf
->menu
->width
+ 4 + MENU_PADDING
; /* item width */
720 size_t items
= COLS
/ len
; /* items per line */
722 return MENU_START_LINE
+ ((idx
/ items
));
725 static int menuitem_get_column(struct cfdisk
*cf
, size_t idx
)
727 size_t len
= cf
->menu
->width
+ 4 + MENU_PADDING
; /* item width */
728 size_t items
= COLS
/ len
; /* items per line */
729 size_t extra
= items
< cf
->menu
->nitems
? /* extra space on line */
730 COLS
% len
: /* - multi-line menu */
731 COLS
- (cf
->menu
->nitems
* len
); /* - one line menu */
733 extra
+= MENU_PADDING
; /* add padding after last item to extra */
736 return (idx
* len
) + (extra
/ 2);
737 return ((idx
% items
) * len
) + (extra
/ 2);
740 static struct cfdisk_menudesc
*menu_get_menuitem(struct cfdisk
*cf
, size_t idx
)
742 struct cfdisk_menudesc
*d
;
745 for (i
= 0, d
= cf
->menu
->desc
; d
->name
; d
++) {
746 if (cf
->menu
->ignore
&& strchr(cf
->menu
->ignore
, d
->key
))
755 static struct cfdisk_menudesc
*menu_get_menuitem_by_key(struct cfdisk
*cf
,
756 int key
, size_t *idx
)
758 struct cfdisk_menudesc
*d
;
760 for (*idx
= 0, d
= cf
->menu
->desc
; d
->name
; d
++) {
761 if (cf
->menu
->ignore
&& strchr(cf
->menu
->ignore
, d
->key
))
771 static void ui_draw_menuitem(struct cfdisk
*cf
,
772 struct cfdisk_menudesc
*d
,
775 char buf
[80 * MB_CUR_MAX
];
777 size_t width
= cf
->menu
->width
+ 2; /* 2 = blank around string */
781 mbsalign(name
, buf
, sizeof(buf
), &width
, MBS_ALIGN_CENTER
, 0);
783 ln
= menuitem_get_line(cf
, idx
);
784 cl
= menuitem_get_column(cf
, idx
);
786 DBG(FRONTEND
, dbgprint("ui: menuitem: cl=%d, ln=%d, item='%s'",
789 if (cf
->menu_idx
== idx
) {
791 mvprintw(ln
, cl
, "[%s]", buf
);
796 mvprintw(ln
, cl
, "[%s]", buf
);
799 static void ui_draw_menu(struct cfdisk
*cf
)
801 struct cfdisk_menudesc
*d
;
807 DBG(FRONTEND
, dbgprint("ui: menu: draw start"));
809 for (i
= MENU_START_LINE
; i
< (size_t) LINES
- 1; i
++) {
814 menu_update_ignore(cf
);
817 while ((d
= menu_get_menuitem(cf
, i
)))
818 ui_draw_menuitem(cf
, d
, i
++);
820 DBG(FRONTEND
, dbgprint("ui: menu: draw end."));
823 static void ui_menu_goto(struct cfdisk
*cf
, int where
)
825 struct cfdisk_menudesc
*d
;
829 where
= cf
->menu
->nitems
- 1;
830 else if ((size_t) where
> cf
->menu
->nitems
- 1)
832 if ((size_t) where
== cf
->menu_idx
)
838 cf
->menu_idx
= where
;
840 d
= menu_get_menuitem(cf
, old
);
841 ui_draw_menuitem(cf
, d
, old
);
843 d
= menu_get_menuitem(cf
, where
);
844 ui_draw_menuitem(cf
, d
, where
);
847 /* returns: error: < 0, success: 0, quit: 1 */
848 static int ui_menu_action(struct cfdisk
*cf
, int key
)
852 assert(cf
->menu
->callback
);
855 struct cfdisk_menudesc
*d
= menu_get_menuitem(cf
, cf
->menu_idx
);
860 } else if (key
!= 'w' && key
!= 'W')
861 key
= tolower(key
); /* case insensitive except 'W'rite */
863 DBG(FRONTEND
, dbgprint("ui: menu action: key=%c", key
));
865 if (cf
->menu
->ignore
&& strchr(cf
->menu
->ignore
, key
)) {
866 DBG(FRONTEND
, dbgprint(" ignore '%c'", key
));
870 return cf
->menu
->callback(cf
, key
);
873 static void ui_draw_partition(struct cfdisk
*cf
, size_t i
)
875 int ln
= TABLE_START_LINE
+ 1 + i
; /* skip table header */
876 int cl
= ARROW_CURSOR_WIDTH
; /* we need extra space for cursor */
878 DBG(FRONTEND
, dbgprint("ui: draw partition %zu", i
));
880 if (cf
->lines_idx
== i
) {
882 mvaddstr(ln
, 0, ARROW_CURSOR_STRING
);
883 mvaddstr(ln
, cl
, cf
->lines
[i
+ 1]);
886 mvaddstr(ln
, 0, ARROW_CURSOR_DUMMY
);
887 mvaddstr(ln
, cl
, cf
->lines
[i
+ 1]);
892 static int ui_draw_table(struct cfdisk
*cf
)
894 int cl
= ARROW_CURSOR_WIDTH
;
895 size_t i
, nparts
= fdisk_table_get_nents(cf
->table
);
897 DBG(FRONTEND
, dbgprint("ui: draw table"));
899 if (cf
->nlines
- 2 < cf
->lines_idx
)
900 cf
->lines_idx
= cf
->nlines
- 2; /* don't count header */
904 mvaddstr(TABLE_START_LINE
, cl
, cf
->lines
[0]);
907 /* print partitions */
908 for (i
= 0; i
< nparts
; i
++)
909 ui_draw_partition(cf
, i
);
914 static int ui_table_goto(struct cfdisk
*cf
, int where
)
917 size_t nparts
= fdisk_table_get_nents(cf
->table
);
919 DBG(FRONTEND
, dbgprint("ui: goto table %d", where
));
923 else if ((size_t) where
> nparts
- 1)
926 if ((size_t) where
== cf
->lines_idx
)
930 cf
->lines_idx
= where
;
932 ui_draw_partition(cf
, old
); /* cleanup old */
933 ui_draw_partition(cf
, where
); /* draw new */
940 static int ui_refresh(struct cfdisk
*cf
)
943 uint64_t bytes
= cf
->cxt
->total_sectors
* cf
->cxt
->sector_size
;
944 char *strsz
= size_to_human_string(SIZE_SUFFIX_SPACE
945 | SIZE_SUFFIX_3LETTER
, bytes
);
953 ui_center(0, _("Disk: %s"), cf
->cxt
->dev_path
);
955 ui_center(1, _("Size: %s, %ju bytes, %ju sectors"),
956 strsz
, bytes
, (uintmax_t) cf
->cxt
->total_sectors
);
957 if (fdisk_get_disklabel_id(cf
->cxt
, &id
) == 0 && id
)
958 ui_center(2, _("Label: %s, identifier: %s"),
959 cf
->cxt
->label
->name
, id
);
961 ui_center(2, _("Label: %s"));
970 static ssize_t
ui_get_string(struct cfdisk
*cf
, const char *prompt
,
971 const char *hint
, char *buf
, size_t len
)
974 ssize_t i
= 0, rc
= -1;
976 int ln
= MENU_START_LINE
, cl
= 1;
986 mvaddstr(ln
, cl
, prompt
);
987 cl
+= mbs_safe_width(prompt
);
993 cells
= mbs_safe_width(buf
);
994 mvaddstr(ln
, cl
, buf
);
1002 move(ln
, cl
+ cells
);
1007 #if !defined(HAVE_SLCURSES_H) && !defined(HAVE_SLANG_SLCURSES_H) && \
1008 defined(HAVE_LIBNCURSESW) && defined(HAVE_WIDECHAR)
1009 if (get_wch(&c
) == ERR
) {
1011 if ((c
= getch()) == ERR
) {
1013 if (!isatty(STDIN_FILENO
))
1018 if (c
== '\r' || c
== '\n' || c
== KEY_ENTER
)
1023 rc
= -CFDISK_ERR_ESC
;
1030 i
= mbs_truncate(buf
, &cells
);
1033 mvaddch(ln
, cl
+ cells
, ' ');
1034 move(ln
, cl
+ cells
);
1039 #if defined(HAVE_LIBNCURSESW) && defined(HAVE_WIDECHAR)
1040 if (i
+ 1 < (ssize_t
) len
&& iswprint(c
)) {
1041 wchar_t wc
= (wchar_t) c
;
1042 char s
[MB_CUR_MAX
+ 1];
1043 int sz
= wctomb(s
, wc
);
1045 if (sz
> 0 && sz
+ i
< (ssize_t
) len
) {
1047 mvaddnstr(ln
, cl
+ cells
, s
, sz
);
1048 memcpy(buf
+ i
, s
, sz
);
1051 cells
+= wcwidth(wc
);
1056 if (i
+ 1 < (ssize_t
) len
&& isprint(c
)) {
1057 mvaddch(ln
, cl
+ cells
, c
);
1069 rc
= i
; /* success */
1079 /* @res is default value as well as result in bytes */
1080 static int ui_get_size(struct cfdisk
*cf
, const char *prompt
, uintmax_t *res
,
1081 uintmax_t low
, uintmax_t up
)
1086 char *dflt
= size_to_human_string(0, *res
);
1088 DBG(FRONTEND
, dbgprint("ui: get_size (default=%ju)", *res
));
1095 snprintf(buf
, sizeof(buf
), "%s", dflt
);
1096 rc
= ui_get_string(cf
, prompt
,
1097 _("The size may be followed by MiB, GiB or TiB suffix "
1098 "(the \"iB\" is optional)."),
1101 ui_warnx(_("Please, specify size."));
1102 continue; /* nothing specified */
1103 } else if (rc
== -CFDISK_ERR_ESC
)
1104 break; /* cancel dialog */
1106 rc
= parse_size(buf
, &user
, &pwr
); /* response, parse */
1108 DBG(FRONTEND
, dbgprint("ui: get_size user=%ju, power=%d", user
, pwr
));
1110 ui_warnx(_("Minimal size is %ju"), low
);
1113 if (user
> up
&& pwr
&& user
< up
+ (1ULL << pwr
* 10))
1114 /* ignore when the user specified size overflow
1115 * with in range specified by suffix (e.g. MiB) */
1119 ui_warnx(_("Maximal size is %ju bytes."), up
);
1129 DBG(FRONTEND
, dbgprint("ui: get_size (result=%ju, rc=%zd)", *res
, rc
));
1134 static int ui_run(struct cfdisk
*cf
)
1138 DBG(FRONTEND
, dbgprint("ui: start COLS=%d, LINES=%d", COLS
, LINES
));
1140 menu_push(cf
, CFDISK_MENU_MAIN
, NULL
);
1142 rc
= ui_refresh(cf
);
1147 int rc
= 0, key
= getch();
1151 case '\016': /* ^N */
1152 case 'j': /* Vi-like alternative */
1153 ui_table_goto(cf
, cf
->lines_idx
+ 1);
1156 case '\020': /* ^P */
1157 case 'k': /* Vi-like alternative */
1158 ui_table_goto(cf
, cf
->lines_idx
- 1);
1161 ui_table_goto(cf
, 0);
1164 ui_table_goto(cf
, cf
->nlines
- 1);
1166 ui_menu_action(cf
, 0);
1172 ui_menu_goto(cf
, cf
->menu_idx
- 1);
1176 ui_menu_goto(cf
, cf
->menu_idx
+ 1);
1181 rc
= ui_menu_action(cf
, 0);
1184 rc
= ui_menu_action(cf
, key
);
1196 DBG(FRONTEND
, dbgprint("ui: end"));
1201 int main(int argc
, char *argv
[])
1203 struct cfdisk _cf
= { .lines_idx
= 0 },
1206 setlocale(LC_ALL
, "");
1207 bindtextdomain(PACKAGE
, LOCALEDIR
);
1208 textdomain(PACKAGE
);
1209 atexit(close_stdout
);
1211 fdisk_init_debug(0);
1212 cf
->cxt
= fdisk_new_context();
1214 err(EXIT_FAILURE
, _("failed to allocate libfdisk context"));
1216 fdisk_context_set_ask(cf
->cxt
, ask_callback
, (void *) cf
);
1217 fdisk_context_enable_freespace(cf
->cxt
, 1);
1220 err(EXIT_FAILURE
, "usage: %s <device>", argv
[0]);
1222 if (fdisk_context_assign_device(cf
->cxt
, argv
[optind
], 0) != 0)
1223 err(EXIT_FAILURE
, _("cannot open %s"), argv
[optind
]);
1227 if (lines_refresh(cf
))
1228 errx(EXIT_FAILURE
, _("failed to read partitions"));
1230 /* Don't use err(), warn() from this point */
1237 fdisk_unref_table(cf
->table
);
1238 fdisk_free_context(cf
->cxt
);
1239 return EXIT_SUCCESS
;