📄 cfdisk.c
字号:
/* GNU fdisk - a clone of Linux fdisk. Copyright (C) 2006 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA*/#include "../config.h"#include "common.h"#include "hacks.h"/*#include "command.h"*//*#include "ui.h"*/#define N_(String) String#if ENABLE_NLS# include <libintl.h># include <locale.h>/* TODO: Fix some localizing issues */# define _(String) dgettext (PACKAGE, String)/* FIXME: This doesn't seem to work */# define P_(String) dgettext ("parted", String)#else# define _(String) (String)# define P_(String) (String)#endif /* ENABLE_NLS */#include <parted/parted.h>#include <parted/debug.h>#if HAVE_NCURSES_H #include <ncurses.h>#else #include <curses.h>#endif/* FIXME: I'm not sure when these are available, and what portability issues they will raise Most likely this is not needed at all */#ifdef KEY_MIN#define USE_KEYPAD 1#else#define USE_KEYPAD 0/* Like Linux cfdisk */#define KEY_UP 1#define KEY_DOWN 2#define KEY_LEFT 3#define KEY_RIGHT 4#define KEY_BACKSPACE '\b'#define KEY_DC '\177'#endif#include <ctype.h>#include <stdarg.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#ifdef HAVE_GETOPT_H#include <getopt.h>#endifstatic const char* prog_name = "cfdisk (GNU fdisk) " VERSION "\n";static const char* license_msg = N_( "Copyright (C) 2006 Free Software Foundation, Inc.\n" "This is free software. You may redistribute copies of it under the terms of\n" "the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.\n" "There is NO WARRANTY, to the extent permitted by law.\n");static const char* usage_msg = N_( "Usage: cfdisk [OPTION]... [DEVICE]\n");/* TODO: Should we move to argp? */static struct { const char* lopt; const char opt; const char *arg; const char *help; } options_help[] = { {"help", 'h', NULL, N_("displays this help message")}, {"version", 'v', NULL, N_("displays the version")}, {"arrow-cursor", 'a', NULL, N_("use an arrow cursor instead of reverse video")}, {"new-table", 'z', NULL, N_("create a new partition table on the disk")}, {"units", 'u', N_("UNIT"),N_("sets the default display units to UNIT")}, {"list-partition-types", 't', NULL, N_("displays a list of supported partition types")}, {NULL, 0, NULL, NULL}};/* Help should go here */static const char *help = N_( "This is a curses-based disk partition manipulation program, which " "allows you create, destroy, resize, move and copy partitions on " "a hard drive.\n\n" "Copyright (C) 2006 Free Software Foundation, Inc.\n\n" "Key\tFunction\n" "---\t--------\n\n" " n\tCreate a new partition residing on the free space.\n" " d\tDelete the selected partition.\n" " c\tCheck the selected partition for consistency.\n" " r\tResize the selected partition or change the size of the " "entry in the partition table\n" " o\tMove the partition to another place on the drive.\n" " y\tCopies another partition over the selected one.\n" " s\tLook for deleted file systems in the selected free space.\n" " b\tDisplay or change partition flags, such as the bootable flag.\n" " t\tChange the system type on the partition in the partition " "in case it is currently wrong.\n" " m\tChange the partition name, if supported.\n" " x\tMaximize the extended partition.\n" " z\tMinimize the extended partition.\n" " u\tChange the display units.\n" " i\tDisplay partition info.\n" " w\tWrite the changes to the disk.\n" " q\tQuit the program.\n" " h\tDisplay this help.\n");#define MAX(X,Y) ((X) > (Y) ? (X) : (Y))#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))/* Keys */#define BELL '\007' /* ^G */#define TAB '\011' /* ^I */#define CR '\015' /* ^M */#define ESC '\033' /* ^[ */#define CTRL_L '\014' /* ^L */#define CTRL_P '\020' /* ^P */#define CTRL_N '\016' /* ^N */#define CTRL_R '\022' /* ^R */#define MENUSIZE 3#define INFOSIZE 5#define MENUDIV 1enum _MenuOptions { MENU_DEFAULT = 0, MENU_TITLE = 1, /* Leave one row for menu title */ MENU_LIST = 2, /* Unimplemented */ MENU_ANYKEY = 4, MENU_BUTTON = 8, MENU_LEAVE_WARNING = 16, /* Don't clear the warning line */ MENU_NOHIGHLIGHT = 32, /* Do not highlight the selected element in the menu */ MENU_ARROWS = 64 /* Accept arrow keys as valid */};typedef enum _MenuOptions MenuOptions;#define TINYBUF 16 /* NOTE: Changing this may lead to buffer overflows. Double-check. */#define FSBUF 19 /* Don't touch unless you know what you are doing!! */#define SMALLBUF 512#define MAXFLAGS 63/* struct for a menu item. I got the idea from Linux cfdisk. Every action is bound to a key. */struct _MenuItem { char key; const char *name; const char *desc; };typedef struct _MenuItem MenuItem;/* Struct for the opened device */struct _Context { PedDevice *dev; PedDisk *disk; int is_devicefile; char *devname; char *info_size; char *info_sectorsize; char *info_model; char *info_heads; char *info_cylinders; char *info_sectors; char *info_cylsize;};typedef struct _Context Context;Context *init_disk(int new_table, char *devname, PedDevice *dev, PedDiskType *type);int new_table = 0;int arrow_cursor = 0;static voiddo_quit(int status, const char *message) { endwin(); if (message) { printf("%s\n",message); } exit(status);}static intget_center(const char *string) { int x = strlen(string); x = MIN(x,COLS); x = (COLS-x)/2; return x;}static voidclear_lines(int start, int end) { int y = start; do { move (y,0); clrtoeol(); } while(y++ < end);}/* Define these as macros */#define clear_status(warn) clear_lines(LINES - 1 - ((warn) != 0),0)#define clear_menu() clear_lines(LINES - 2 - MENUSIZE, LINES - 1);static voidset_status(const char *status, int warn_line) { clear_status(warn_line); /*attron(A_REVERSE);*/ move(LINES-1-warn_line,0); mvaddstr(LINES-1-warn_line, get_center(status) ,status); /*attroff(A_REVERSE);*/}static voidprint_warning(const char *status, int status_line) { set_status(status,!status_line); putchar(BELL);}static voidmenu_title (const char *title) { move(LINES - 2 - MENUSIZE, 0); clrtoeol(); mvaddstr(LINES - 2 - MENUSIZE, MENUDIV, title); }enum _MsgOpts { DOUBLE_NEW_LINE = 1, /* Ignore space at the beginning of the line */ IGNORE_SPACE = 2, /* Use \t to indent the whole text, even after newline */ TAB_TO_INDENT = 4 };typedef enum _MsgOpts MsgOpts;/* This is an ancient magic that turns a char* into a StrList, so we can display it */static StrList*_message_display_strlist(const char *msg, int *lines, MsgOpts opts) { int x = 0, y = 0, lastword = 0, isnewline = 0, i, indent = 0; StrList *message = NULL; char buf[SMALLBUF]; /* We save the lines in a string list, counting them */ /* TODO: It doesn't deal with tabs correctly, this is currently only with tabs in the beginning of the text. */ /* NOTE: We calculate indent, even when we don't use it */ for (i = 0; msg[i]; i++) { /* If we reached the end of the line, move to the next line */ if (x >= SMALLBUF - 1 || x >= COLS-2) { if (isblank(msg[i]) || msg[i] == '\r' || msg[i] == '\n' || !lastword) { buf[x] = '\0'; message = str_list_append(message,buf); y++; /* Real new line is two lines. */ if (msg[i] == '\n') { if (opts & DOUBLE_NEW_LINE) message = str_list_append( message,""); y++; isnewline = 1; } } /* If this is not the end of the word, go back to the beginning of the word. */ else { buf[lastword-1] = '\0'; message = str_list_append(message,buf); y++; i = i-x+lastword; } lastword = 0; x = 0; /* If the text was indented, move it right */ if (msg[i] == '\n') indent = 0; else if ((opts & TAB_TO_INDENT) && indent > 0) { /* If the line is indented */ for (; x <= indent && x < SMALLBUF - 1 ; x++) { buf[x] = ' '; } } } /* We ignore carriage returns */ if (msg[i] == '\r') { continue; } /* We indent the text right, if we see a tab */ else if (msg[i] == '\t') { lastword = x+1; int n = ((x+9)/9)*9; n = MIN(COLS-2,n); for (; x <= n && x < SMALLBUF - 1; x++) { buf[x] = ' '; } indent += 9; continue; } /* If the line begins with a blank, skip it */ else if (isblank(msg[i])) { if ((opts & IGNORE_SPACE) && x == 0) continue; else lastword = x+1; } else if (msg[i] == '\n') { if (!isnewline) { buf[x] = '\0'; message = str_list_append(message,buf); if (opts & DOUBLE_NEW_LINE) message = str_list_append(message,""); y += 2; } x = 0; lastword = 0; indent = 0; continue; } isnewline = 0; buf[x] = msg[i]; x++; } buf[x] = '\0'; /* This doesn't produce an error, trust me */ if (strlen(buf)) { message = str_list_append(message,buf); y++; } if (lines) *lines = y; return message;}static voidstrlist_draw (const char *prompt, const StrList *strlist, int opts, const StrList* selected, int selnum, int *start);static const StrList*do_strlist (const char *prompt, const StrList *strlist, int opts);static void_display_strlist (const char* title, const StrList *message, int y) { int x, i; /* TODO: Write this, for now I will test it this way */ y=LINES-3-MENUSIZE-y; if (y < INFOSIZE+4) y = INFOSIZE+4; i=INFOSIZE+1; move(i++,0); clrtoeol(); mvaddch(i,0,' '); for (x = 1; x < COLS-1; x++) { mvaddch(i,x,'-'); } mvaddch(i,0,' '); for (i++; i < y; i++) { move(i,0); clrtoeol(); } mvaddstr(y-3,1,title); for (x = 1; title[x-1]; x++) { mvaddch(y-2,x,'='); } const StrList *current; for (current = message; current && y < LINES-MENUSIZE-3; current = current->next, y++) { char *temp = str_list_convert_node(current); move(y,0); clrtoeol(); mvaddstr(y,1,temp); free(temp); }}static void display_message (const char* title, const char *msg) { int lines; StrList *message; message = _message_display_strlist(msg,&lines,IGNORE_SPACE | DOUBLE_NEW_LINE); _display_strlist(title, message, lines); str_list_destroy(message); }/* Menu drawing function */static voidmenu_draw (const MenuItem *items, int item_len, MenuOptions opts, const char *keys, int selected) { int i, y = LINES - 2 - MENUSIZE + (opts & MENU_TITLE ? 1 : 0), x = MENUDIV; int item_size = item_len + (opts & MENU_BUTTON ? 2 : 0); const char *desc; move(y,0); clrtoeol(); for (i = 0; items[i].name; i++) { /* NOTE: Was tolower(items[i].key) */ if (strchr(keys, items[i].key)) { char buf[item_size+2]; int name_len; const char *name; /* Localize the text. Translate empty string to empty string. */ name = (items[i].name[0] ? _(items[i].name) : ""); name_len = strlen(name); /* Enclose the text if the type is a button. If it is too long, cut. */ if (name_len >= item_len) { snprintf(buf,item_size+1, (opts & MENU_BUTTON) ? "[%s]" : "%s" , name); if (opts & MENU_BUTTON) { buf[item_size-1] = ']'; buf[item_size] = '\0'; } } else { snprintf(buf,item_size+1, (opts & MENU_BUTTON) ? "[%*s%s%*s]" : "%*s%s%*s" , (item_len - name_len)/2, "", name, (item_len - name_len + 1)/2 , ""); } /* Write the button. Highlight if is selected. */ if (i == selected && !(opts & MENU_NOHIGHLIGHT)) attron(A_STANDOUT); //else if (strchr(keys,tolower(items[i].key))) attron(A_BOLD); mvaddstr(y,x,buf); if (i == selected && !(opts & MENU_NOHIGHLIGHT)) attroff(A_STANDOUT); //else if (strchr(keys,tolower(items[i].key))) attroff(A_BOLD); if (x + 2*item_size + 2*MENUDIV < COLS) { x += item_size + MENUDIV; } else if (y + 3 < LINES) { /* y + 1 < LINES - 2 */ y++; x = MENUDIV; move(y,0); clrtoeol(); } /* If we can't draw all the menu items, end. */ else break; } } while (++y < LINES-2) { move(y,0); clrtoeol(); } if (!(opts & MENU_LEAVE_WARNING)) { move(LINES-2,0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -