>From 4dc548fb943da9c67600c04792d84e2e88c7f496 Mon Sep 17 00:00:00 2001
From: Matt Davis <[EMAIL PROTECTED]>
Date: Thu, 28 Jun 2007 00:04:44 -0400
Subject: Added history with the capability to undo/redo before the disk changes
are actually written to disk.
Three commands were added
1) Save (commits changes to disk)
2) Undo Undoes the previous change
3) Redo Redoes the previous change
This is still in testing but I feel it is workable now to put in a patch.
Please give me feedback as to positives/negatives of this change.
Also, the idea of collecting all changes and applying them at the end was from
Vanni Brutto, who posted his concept 7 November 2006. The idea I use is
basically deep copying disk objects and command objects from the 'do_***'
commands in parted.c. When the 'Save' command is issued the collected disk
changes are applied via ped_disk_commit().
-Matt
---
include/parted/disk.h | 5 +-
libparted/disk.c | 11 +++
parted/Makefile.am | 2 +
parted/command.c | 2 +
parted/history.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++++
parted/history.h | 67 +++++++++++++++++
parted/parted.c | 101 +++++++++++++++++++++-----
7 files changed, 361 insertions(+), 20 deletions(-)
create mode 100644 parted/history.c
create mode 100644 parted/history.h
diff --git a/include/parted/disk.h b/include/parted/disk.h
index 4dd81d9..bdf8ba8 100644
--- a/include/parted/disk.h
+++ b/include/parted/disk.h
@@ -261,10 +261,13 @@ extern PedDisk* ped_disk_new_fresh (PedDevice* dev,
extern PedDisk* ped_disk_duplicate (const PedDisk* old_disk);
extern void ped_disk_destroy (PedDisk* disk);
extern int ped_disk_commit (PedDisk* disk);
-extern int ped_disk_commit_to_dev (PedDisk* disk);
extern int ped_disk_commit_to_os (PedDisk* disk);
extern int ped_disk_check (const PedDisk* disk);
extern void ped_disk_print (const PedDisk* disk);
+/* Located in parted/history.h
+ * extern void ped_disk_commit_to_history (const PedDisk* disk);
+ */
+extern int ped_disk_commit_to_dev (PedDisk* disk);
extern int ped_disk_get_primary_partition_count (const PedDisk* disk);
extern int ped_disk_get_last_partition_num (const PedDisk* disk);
diff --git a/libparted/disk.c b/libparted/disk.c
index 547d037..1593484 100644
--- a/libparted/disk.c
+++ b/libparted/disk.c
@@ -510,6 +510,17 @@ ped_disk_commit (PedDisk* disk)
}
/**
+ * Adds the changes to disk to the command history.
+ * This allows the commands to have an undo/redo effect
+ * without actually performing any (possibly unwanted)
+ * disk actions.
+ *
+ * This is actually defined in parted/history.c
+void
+ped_disk_commit_to_history(const PedDisk *disk)
+*/
+
+/**
* \addtogroup PedPartition
*
* @{
diff --git a/parted/Makefile.am b/parted/Makefile.am
index c699102..80023de 100644
--- a/parted/Makefile.am
+++ b/parted/Makefile.am
@@ -9,6 +9,8 @@ parted_SOURCES = command.c \
strlist.h \
ui.c \
ui.h \
+ history.c \
+ history.h \
table.c \
table.h
diff --git a/parted/command.c b/parted/command.c
index a5c4998..f6c155e 100644
--- a/parted/command.c
+++ b/parted/command.c
@@ -20,6 +20,7 @@
#include <config.h>
#include "command.h"
#include "ui.h"
+#include "history.h"
#include <parted/debug.h>
@@ -137,6 +138,7 @@ command_print_help (Command* cmd)
int
command_run (Command* cmd, PedDevice** dev)
{
+ history_add(cmd);
return cmd->method (dev);
}
diff --git a/parted/history.c b/parted/history.c
new file mode 100644
index 0000000..ff955d3
--- /dev/null
+++ b/parted/history.c
@@ -0,0 +1,193 @@
+#include <stdio.h>
+#include "history.h"
+#include "ui.h"
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+
+struct PedHistoryManager_t PedHistMgr = {0};
+
+
+void history_add(const Command *cmd)
+{
+ PedHistObj *addme;
+
+ /* Deep copy and add to end of list */
+ addme = history_alloc_obj();
+ addme->cmd = *cmd;
+ addme->cmd.help = str_list_duplicate(cmd->help);
+ addme->cmd.names = str_list_duplicate(cmd->names);
+ addme->cmd.summary = str_list_duplicate(cmd->summary);
+ addme->id = PedHistMgr.id++;
+
+ /* This becomes the new end, so remember who is before us */
+ addme->prev = PedHistMgr.end;
+
+ /* Add this to the end of the list */
+ if (PedHistMgr.end)
+ PedHistMgr.end->next = addme;
+ PedHistMgr.end = addme;
+
+ if (!PedHistMgr.begin)
+ PedHistMgr.begin = addme;
+
+ PedHistMgr.n_objs++;
+}
+
+
+void history_clear(void)
+{
+ PedHistObj *ii, *freeme;
+
+ ii = PedHistMgr.begin;
+ while (ii)
+ {
+ freeme = ii;
+ ii = ii->next;
+ history_dealloc_obj(freeme);
+ }
+
+ memset(&PedHistMgr, 0, sizeof(PedHistMgr));
+}
+
+
+void history_undo(void)
+{
+ PedHistObj *ii;
+
+ /* Mark the most recent change as ignored and that is an
+ * actual 'disk' modification
+ * Start with the last command issued before this 'undo' call
+ */
+ for (ii=PedHistMgr.end->prev; ii; ii=ii->prev)
+ if (!ii->ignore && ii->disk)
+ break;
+
+ if (!ii)
+ {
+ printf(PED_HISTORY_TAG "Cannot undo\n");
+ return;
+ }
+
+ ii->ignore = 1;
+ printf(PED_HISTORY_TAG "Undo: ");
+ str_list_print(ii->cmd.names);
+ fputs("\n", stdout);
+}
+
+
+void history_redo(void)
+{
+ PedHistObj *ii;
+
+ /* Find the most recent undone entry that is a 'disk' modification */
+ for (ii=PedHistMgr.begin; ii; ii=ii->next)
+ if (ii->ignore && ii->disk)
+ break;
+
+ if (!ii)
+ {
+ printf(PED_HISTORY_TAG "Cannot redo\n");
+ return;
+ }
+
+ ii->ignore = 0;
+ printf(PED_HISTORY_TAG "Redo: ");
+ str_list_print(ii->cmd.names);
+ fputs("\n", stdout);
+}
+
+
+void ped_disk_commit_to_history(const PedDisk *disk)
+{
+ PedHistMgr.end->disk = ped_disk_duplicate(disk);
+}
+
+
+PedHistObj *history_alloc_obj(void)
+{
+ int size = sizeof(PedHistObj) + sizeof(Command);
+ PedHistObj *obj = (PedHistObj *)malloc(size);
+ memset(obj, 0, size);
+ return obj;
+}
+
+
+void history_dealloc_obj(PedHistObj *obj)
+{
+ if (!obj)
+ return;
+
+ if (obj->disk)
+ ped_disk_destroy(obj->disk);
+ str_list_destroy(obj->cmd.help);
+ str_list_destroy(obj->cmd.names);
+ str_list_destroy(obj->cmd.summary);
+ free(obj);
+}
+
+
+void history_commit_to_disk(void)
+{
+ PedHistObj *ii;
+
+ for (ii=PedHistMgr.begin; ii; ii=ii->next)
+ if (ii->disk && !ii->ignore)
+ {
+ printf(PED_HISTORY_TAG "Apply ");
+ str_list_print_wrap(ii->cmd.names, screen_width(), 8, 8);
+ if (ped_disk_commit(ii->disk))
+ printf(" (Success)\n");
+ else
+ printf(" (Failure)\n");
+ }
+
+ /* Start fresh */
+ history_clear();
+}
+
+
+static void history_pr(PedHistObj *obj)
+{
+ /* Only print disk changes */
+ if (!obj->disk)
+ return;
+
+ printf("[History %d]\t", obj->id);
+ str_list_print_wrap(obj->cmd.names, screen_width(), 8, 8);
+ if (obj->ignore)
+ printf(" (UNDONE)");
+ fputs("\n", stdout);
+}
+
+
+/* Print range (or specific if start == end) */
+void history_print(int start, int end)
+{
+ int i;
+ PedHistObj *ii;
+
+ for (i=0, ii=PedHistMgr.begin;
+ ii && i>=start && i<end;
+ ii=ii->next, i++)
+ {
+ history_pr(ii);
+ }
+}
+
+
+void history_print_specific(int idx)
+{
+ history_print(idx, idx);
+}
+
+
+void history_print_all(void)
+{
+ history_print(0, PedHistMgr.n_objs);
+}
diff --git a/parted/history.h b/parted/history.h
new file mode 100644
index 0000000..ae81cc0
--- /dev/null
+++ b/parted/history.h
@@ -0,0 +1,67 @@
+#ifndef HISTORY_H_INCLUDED
+#define HISTORY_H_INCLUDED
+
+#include "command.h"
+
+
+#define PED_HISTORY_TAG "[History] "
+
+
+/*
+ * Structs
+ */
+
+typedef struct PedHistObj {
+ int id;
+ int ignore; /* Undo/Redo functionality */
+ Command cmd;
+ PedDisk *disk;
+
+ struct PedHistObj *prev;
+ struct PedHistObj *next;
+} PedHistObj;
+
+
+struct PedHistoryManager_t{
+ PedHistObj *begin;
+ PedHistObj *end;
+ int n_objs;
+ int id;
+};
+
+extern struct PedHistoryManager_t PedHistMgr;
+
+
+/*
+ * Funcs
+ */
+
+/* Add/Clear history */
+extern void history_add(const Command *cmd);
+extern void history_clear(void);
+
+/* Before changes are committed */
+extern void history_undo(void);
+extern void history_redo(void);
+
+/* Write changes to disk */
+extern void history_commit_to_disk(void);
+
+/* Print */
+extern void history_print(int start, int end);
+extern void history_print_specific(int i);
+extern void history_print_all(void);
+
+/* Alloc/dealloc */
+extern PedHistObj *history_alloc_obj(void);
+extern void history_dealloc_obj(PedHistObj *obj);
+
+/* Remember changes
+ * Note: This is not defined in disk.h
+ * This preserves encapsulation between
+ * PedCommands and libparted
+ */
+extern void ped_disk_commit_to_history(const PedDisk *disk);
+
+
+#endif /* HISTORY_H_INCLUDED */
diff --git a/parted/parted.c b/parted/parted.c
index 73be7a4..e01f401 100644
--- a/parted/parted.c
+++ b/parted/parted.c
@@ -26,6 +26,7 @@
#include "command.h"
#include "ui.h"
#include "table.h"
+#include "history.h"
#define AUTHORS \
"<http://parted.alioth.debian.org/cgi-bin/trac.cgi/browser/AUTHORS>"
@@ -535,8 +536,7 @@ do_cp (PedDevice** dev)
/* update the partition table, close disks */
if (!ped_partition_set_system (dst, dst_fs_type))
goto error_destroy_disk;
- if (!ped_disk_commit (dst_disk))
- goto error_destroy_disk;
+ ped_disk_commit_to_history (dst_disk);
if (src_disk != dst_disk)
ped_disk_destroy (src_disk);
ped_disk_destroy (dst_disk);
@@ -620,8 +620,7 @@ do_mklabel (PedDevice** dev)
if (!disk)
goto error;
- if (!ped_disk_commit (disk))
- goto error_destroy_disk;
+ ped_disk_commit_to_history (disk);
ped_disk_destroy (disk);
if ((*dev)->type != PED_DEVICE_FILE)
@@ -666,8 +665,7 @@ do_mkfs (PedDevice** dev)
goto error_destroy_disk;
if (ped_partition_is_flag_available (part, PED_PARTITION_LBA))
ped_partition_set_flag (part, PED_PARTITION_LBA, 1);
- if (!ped_disk_commit (disk))
- goto error_destroy_disk;
+ ped_disk_commit_to_history (disk);
ped_disk_destroy (disk);
if ((*dev)->type != PED_DEVICE_FILE)
@@ -798,8 +796,7 @@ do_mkpart (PedDevice** dev)
if (ped_partition_is_flag_available (part, PED_PARTITION_LBA))
ped_partition_set_flag (part, PED_PARTITION_LBA, 1);
- if (!ped_disk_commit (disk))
- goto error_destroy_disk;
+ ped_disk_commit_to_history (disk);
/* clean up */
ped_constraint_destroy (final_constraint);
@@ -973,8 +970,7 @@ do_mkpartfs (PedDevice** dev)
if (!ped_partition_set_system (part, fs_type))
goto error_destroy_disk;
- if (!ped_disk_commit (disk))
- goto error_destroy_disk;
+ ped_disk_commit_to_history (disk);
/* clean up */
ped_constraint_destroy (final_constraint);
@@ -1091,8 +1087,7 @@ do_move (PedDevice** dev)
goto error_close_fs;
ped_file_system_close (fs_copy);
ped_file_system_close (fs);
- if (!ped_disk_commit (disk))
- goto error_destroy_disk;
+ ped_disk_commit_to_history (disk);
ped_disk_destroy (disk);
if (range_start != NULL)
ped_geometry_destroy (range_start);
@@ -1140,7 +1135,7 @@ do_name (PedDevice** dev)
goto error_free_name;
free (name);
- if (!ped_disk_commit (disk))
+ ped_disk_commit_to_history (disk);
goto error_destroy_disk;
ped_disk_destroy (disk);
return 1;
@@ -1641,7 +1636,7 @@ _rescue_add_partition (PedPartition* part)
}
ped_partition_set_system (part, fs_type);
- ped_disk_commit (part->disk);
+ ped_disk_commit_to_history (part->disk);
return 1;
}
@@ -1817,7 +1812,7 @@ do_resize (PedDevice** dev)
ped_file_system_close (fs);
}
- ped_disk_commit (disk);
+ ped_disk_commit_to_history (disk);
ped_constraint_destroy (constraint);
ped_disk_destroy (disk);
if (range_start != NULL)
@@ -1860,7 +1855,7 @@ do_rm (PedDevice** dev)
goto error_destroy_disk;
ped_disk_delete_partition (disk, part);
- ped_disk_commit (disk);
+ ped_disk_commit_to_history (disk);
ped_disk_destroy (disk);
if ((*dev)->type != PED_DEVICE_FILE)
@@ -1915,8 +1910,7 @@ do_set (PedDevice** dev)
if (!ped_partition_set_flag (part, flag, state))
goto error_destroy_disk;
- if (!ped_disk_commit (disk))
- goto error_destroy_disk;
+ ped_disk_commit_to_history (disk);
ped_disk_destroy (disk);
if ((*dev)->type != PED_DEVICE_FILE)
@@ -1960,7 +1954,35 @@ do_version ()
_(copyright_msg));
return 1;
}
-
+
+static int
+do_undo ()
+{
+ history_undo();
+ return 1;
+}
+
+static int
+do_redo ()
+{
+ history_redo();
+ return 1;
+}
+
+static int
+do_history ()
+{
+ history_print_all();
+ return 1;
+}
+
+static int
+do_save ()
+{
+ history_commit_to_disk();
+ return 1;
+}
+
static void
_init_messages ()
{
@@ -2279,6 +2301,47 @@ _("'version' displays copyright and version information
corresponding to this "
"copy of GNU Parted\n"),
NULL), 1));
+command_register (commands, command_create (
+ str_list_create_unique ("undo", _("undo"), NULL),
+ do_undo,
+ str_list_create (
+_("undo Undo change to partition table"),
+ NULL),
+ str_list_create (
+_("'undo' undoes the previous partition table modifcation "), NULL), 1));
+
+command_register (commands, command_create (
+ str_list_create_unique ("redo", _("redo"), NULL),
+ do_redo,
+ str_list_create (
+_("redo Redo change to partition table"),
+ NULL),
+ str_list_create (
+_("'redo' redoes the previous change to the parititon table"),
+NULL), 1));
+
+
+
+command_register (commands, command_create (
+ str_list_create_unique ("history", _("history"), NULL),
+ do_history,
+ str_list_create (
+_("history display command history"), NULL),
+ str_list_create (
+_("'history' displays list of commands that have are to be executed\n"),
+NULL), 1));
+
+command_register (commands, command_create (
+ str_list_create_unique ("save", _("save"), NULL),
+ do_save,
+ str_list_create (
+_("save Write changes to partition
table"),
+ NULL),
+ str_list_create (
+_("'save' commits the changes that were created during the current parted "
+ "session. This writes the changes to disk."),
+NULL), 1));
+
}
static void
--
1.5.2
_______________________________________________
parted-devel mailing list
[email protected]
http://lists.alioth.debian.org/mailman/listinfo/parted-devel