The following 3 patches implement history/undo/redo behavior for parted.

This change captures potential disk modifications based on what commands a user
issues.  The list of disk modifications can be displayed/queried, undone, or
redone.  Eventually the changes can be commited to disk.  This prevents the user
from performing unwanted modifications to disk before they are ready.  Also, the
user can view the disk as if the modifications were taking place, even before
the "save" their changes.

These patches were based against the master this evening.

-Matt
>From 16bf982c9c5f29705a8e99ce2752f70ab27801d7 Mon Sep 17 00:00:00 2001
From: Matt Davis <[EMAIL PROTECTED]>
Date: Thu, 7 Feb 2008 00:16:58 -0500
Subject: [PATCH] History patch 1 of 3

The following changes modify to parted's core to enable history.

    parted/command.c:
    Captures user entered commands and stores them as nodes in a link-list
    These commands, when the "save" command is issued, are applied to disk.
    This allows the user to undo/redo their choices before the disk actually
    becomes modified.

    parted/parted.c:
    The commands that would normally make disk changes immediately, now are
    stored as nodes in a link list.  This allows disk modifications to be
    undone before they actually take affect.

    The changes here also implement the following commands:
    * undo: Undoes the most recent disk modification per session
    * redo: Redoes the most recent disk modification per session
    * save: Actually applies the disk modification list (history) to disk
    * history: Shows the list of commands executed
---
 parted/command.c |    2 +
 parted/parted.c  |  221 +++++++++++++++++++++++++++++++++++++++++-------------
 2 files changed, 172 insertions(+), 51 deletions(-)

diff --git a/parted/command.c b/parted/command.c
index a3ae7c0..3d34d06 100644
--- a/parted/command.c
+++ b/parted/command.c
@@ -21,6 +21,7 @@
 #include "ui.h"
 
 #include <parted/debug.h>
+#include <parted/history.h>
 
 #include <stdlib.h>
 #include <string.h>
@@ -136,6 +137,7 @@ command_print_help (Command* cmd)
 int
 command_run (Command* cmd, PedDevice** dev)
 {
+       ped_history_add(str_list_convert(cmd->names));
        return cmd->method (dev);
 }
 
diff --git a/parted/parted.c b/parted/parted.c
index 46999f5..1b97b56 100644
--- a/parted/parted.c
+++ b/parted/parted.c
@@ -42,6 +42,7 @@
 
 #include <parted/parted.h>
 #include <parted/debug.h>
+#include <parted/history.h>
 
 #include <ctype.h>
 #include <stdarg.h>
@@ -492,9 +493,10 @@ do_cp (PedDevice** dev)
         PedFileSystem*          dst_fs;
         PedFileSystemType*      dst_fs_type;
 
-        dst_disk = ped_disk_new (*dev);
-        if (!dst_disk)
-                goto error;
+        /* Use the most recent disk from history if available */
+        if (!(dst_disk = ped_history_disk ()))
+                if (!(dst_disk = ped_disk_new (*dev)))
+                        goto error;
 
         src_disk = dst_disk;
         if (!command_line_is_integer ()) {
@@ -533,8 +535,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);
@@ -598,8 +599,12 @@ do_mklabel (PedDevice** dev)
         const PedDiskType*      type = ped_disk_probe (*dev);
 
         ped_exception_fetch_all ();
-        disk = ped_disk_new (*dev);
-        if (!disk) ped_exception_catch ();
+
+        /* Use the most recent disk from history if available */
+        if (!(disk = ped_history_disk ()))
+                if (!(disk = ped_disk_new (*dev)))
+                        ped_exception_catch ();
+
         ped_exception_leave_all ();
 
         if (disk) {
@@ -618,8 +623,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)
@@ -641,9 +645,10 @@ do_mkfs (PedDevice** dev)
         const PedFileSystemType* type = ped_file_system_type_get ("ext2");
         PedFileSystem*          fs;
 
-        disk = ped_disk_new (*dev);
-        if (!disk)
-                goto error;
+        /* Use the most recent disk from history if available */
+        if (!(disk = ped_history_disk ()))
+                if (!(disk = ped_disk_new (*dev)))
+                        goto error;
 
         if  (!opt_script_mode && !_partition_warn_loss())
                 goto error_destroy_disk;
@@ -664,8 +669,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)
@@ -695,10 +699,11 @@ do_mkpart (PedDevice** dev)
         char*                    part_name = NULL;
         char                     *start_usr = NULL, *end_usr = NULL;
         char                     *start_sol = NULL, *end_sol = NULL;
-        
-        disk = ped_disk_new (*dev);
-        if (!disk)
-                goto error;
+ 
+        /* Use the most recent disk from history if available */
+        if (!(disk = ped_history_disk ()))
+                if (!(disk = ped_disk_new (*dev)))
+                        goto error;
 
         if (!ped_disk_type_check_feature (disk->type, PED_DISK_TYPE_EXTENDED)) 
{
                 part_type = PED_PARTITION_NORMAL;
@@ -807,8 +812,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);
@@ -880,9 +884,10 @@ do_mkpartfs (PedDevice** dev)
         char                *start_usr = NULL, *end_usr = NULL;
         char                *start_sol = NULL, *end_sol = NULL;
 
-        disk = ped_disk_new (*dev);
-        if (!disk)
-                goto error;
+        /* Use the most recent disk from history if available */
+        if (!(disk = ped_history_disk ()))
+                if (!(disk = ped_disk_new (*dev)))
+                        goto error;
 
         if (!ped_disk_type_check_feature (disk->type, PED_DISK_TYPE_EXTENDED)) 
{
                 part_type = PED_PARTITION_NORMAL;
@@ -982,8 +987,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);
@@ -1050,9 +1054,10 @@ do_move (PedDevice** dev)
         PedGeometry     *range_start = NULL, *range_end = NULL;
         PedGeometry     old_geom, new_geom;
 
-        disk = ped_disk_new (*dev);
-        if (!disk)
-                goto error;
+        /* Use the most recent disk from history if available */
+        if (!(disk = ped_history_disk ()))
+                if (!(disk = ped_disk_new (*dev)))
+                        goto error;
 
         if (!command_line_get_partition (_("Partition number?"), disk, &part))
                 goto error_destroy_disk;
@@ -1100,8 +1105,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);
@@ -1134,9 +1138,10 @@ do_name (PedDevice** dev)
         PedPartition*   part = NULL;
         char*           name;
 
-        disk = ped_disk_new (*dev);
-        if (!disk)
-                goto error;
+        /* Use the most recent disk from history if available */
+        if (!(disk = ped_history_disk ()))
+                if (!(disk = ped_disk_new (*dev)))
+                        goto error;
 
         if (!command_line_get_partition (_("Partition number?"), disk, &part))
                 goto error_destroy_disk;
@@ -1149,7 +1154,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;
@@ -1286,9 +1291,10 @@ do_print (PedDevice** dev)
         char*           tmp;
         wchar_t*        table_rendered;
 
-        disk = ped_disk_new (*dev);
-        if (!disk)
-                goto error;
+        /* Use the most recent disk from history if available */
+        if (!(disk = ped_history_disk ()))
+                if (!(disk = ped_disk_new (*dev)))
+                        goto error;
 
         peek_word = command_line_peek_word ();
         if (peek_word) {
@@ -1651,7 +1657,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;
 }
 
@@ -1779,9 +1785,10 @@ do_resize (PedDevice** dev)
         PedGeometry             *range_start = NULL, *range_end = NULL;
         PedGeometry             new_geom;
 
-        disk = ped_disk_new (*dev);
-        if (!disk)
-                goto error;
+        /* Use the most recent disk from history if available */
+        if (!(disk = ped_history_disk ()))
+                if (!(disk = ped_disk_new (*dev)))
+                        goto error;
 
         if (!command_line_get_partition (_("Partition number?"), disk, &part))
                 goto error_destroy_disk;
@@ -1827,7 +1834,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,9 +1867,10 @@ do_rm (PedDevice** dev)
         PedDisk*                disk;
         PedPartition*           part = NULL;
 
-        disk = ped_disk_new (*dev);
-        if (!disk)
-                goto error;
+        /* Use the most recent disk from history if available */
+        if (!(disk = ped_history_disk ()))
+                if (!(disk = ped_disk_new (*dev)))
+                        goto error;
 
         if (!command_line_get_partition (_("Partition number?"), disk, &part))
                 goto error_destroy_disk;
@@ -1870,7 +1878,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)
@@ -1908,9 +1916,10 @@ do_set (PedDevice** dev)
         PedPartitionFlag        flag;
         int                     state;
         
-        disk = ped_disk_new (*dev);
-        if (!disk)
-                goto error;
+        /* Use the most recent disk from history if available */
+        if (!(disk = ped_history_disk ()))
+                if (!(disk = ped_disk_new (*dev)))
+                        goto error;
         
         if (!command_line_get_partition (_("Partition number?"), disk, &part))
                 goto error_destroy_disk;
@@ -1925,8 +1934,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)
@@ -1971,6 +1979,76 @@ do_version ()
     return 1;
 }
 
+static int
+do_undo ()
+{
+    PedHistRet err;
+
+    if ((err = ped_history_undo ()))
+            printf(PED_HISTORY_TAG "%s\n", ped_history_print_ret (err));
+
+    return 1;
+}
+    
+static int
+do_redo ()
+{
+    PedHistRet err;
+
+    if ((err = ped_history_redo ()))
+            printf(PED_HISTORY_TAG "%s\n", ped_history_print_ret (err));
+
+    return 1;
+}
+
+/* Called back each time a disk modification is 
+ * made from history.
+ */
+static void
+print_handler (PedHistRet val, PedHistObj *obj)
+{
+    switch (val)
+    {
+        case PED_HISTORY_RET_SUCCESS:
+            printf("Applying change %s (Success)\n", obj->name);
+            break;
+
+        case PED_HISTORY_RET_ERROR:
+            printf(PED_HISTORY_TAG "Applying change %s (Failed)\n", obj->name);
+            break;
+
+        default: break;
+    }
+}
+
+static int
+do_history ()
+{
+    const PedHistObj *ii;
+        
+    /* Only print changes that are undone or modify the disk */
+    for (ii = ped_history_begin (); ii; ii = ii->next)
+           if (PED_HISTORY_IS_UNDONE (ii))
+                   printf(PED_HISTORY_TAG "%s (Undone)\n", ii->name);
+            else if (ii->disk)
+                    printf(PED_HISTORY_TAG "%s\n", ii->name);
+
+    return 1;
+}
+    
+static int
+do_save ()
+{
+    PedHistRet err;
+
+    if ((err = ped_history_commit_to_disk (print_handler)))
+            printf(PED_HISTORY_TAG "%s\n", ped_history_print_ret (err));
+    else
+            printf(PED_HISTORY_TAG "Successfully modified the disk\n");
+
+    return 1;
+}
+ 
 static void
 _init_messages ()
 {
@@ -2289,6 +2367,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.1.5

>From c3278c2c8dfda35a63453e07940df46152e760f7 Mon Sep 17 00:00:00 2001
From: Matt Davis <[EMAIL PROTECTED]>
Date: Thu, 7 Feb 2008 00:30:17 -0500
Subject: [PATCH] History patch 2 of 3

The following changes modify parted's library set to enable history.

    include/parted/Makefile.am:
    Adds history.h library header

    include/parted/disk.h
    Adds the function: ped_disk_commit_to_history
    This routine stores disk commits to the history list, Where they can later
    be used to make the actual disk modifications all at once.

    include/parted/history.h
    Structures and routines to manage history.

    include/parted/parted.h
    Adds history.h library header

    libparted/Makefile.am
    Adds history.c

    libparted/disk.c
    Implements ped_disk_commit_to_history()

    libparted/history.c
    Implements routines useful in managing parted disk history.
    These calls are called by parted's core
---
 include/parted/Makefile.am |    1 +
 include/parted/disk.h      |    1 +
 include/parted/history.h   |  111 ++++++++++++++++++
 include/parted/parted.h    |    1 +
 libparted/Makefile.am      |    1 +
 libparted/disk.c           |   11 ++
 libparted/history.c        |  265 ++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 391 insertions(+), 0 deletions(-)
 create mode 100644 include/parted/history.h
 create mode 100644 libparted/history.c

diff --git a/include/parted/Makefile.am b/include/parted/Makefile.am
index dd0e1d4..88a426b 100644
--- a/include/parted/Makefile.am
+++ b/include/parted/Makefile.am
@@ -18,6 +18,7 @@ partedinclude_HEADERS = gnu.h         \
                        natmath.h       \
                        timer.h         \
                        unit.h          \
+                       history.h       \
                        parted.h        \
                        $(S390_HDRS)
 
diff --git a/include/parted/disk.h b/include/parted/disk.h
index b82ea0f..69542c1 100644
--- a/include/parted/disk.h
+++ b/include/parted/disk.h
@@ -260,6 +260,7 @@ 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 void ped_disk_commit_to_history (const 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);
diff --git a/include/parted/history.h b/include/parted/history.h
new file mode 100644
index 0000000..b2b2cf5
--- /dev/null
+++ b/include/parted/history.h
@@ -0,0 +1,111 @@
+/*
+    libparted - a library for manipulating disk partitions
+    Copyright (C) 1999, 2000, 2001, 2007 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PED_HISTORY_H_INCLUDED
+#define PED_HISTORY_H_INCLUDED
+
+
+/*
+ * Macros
+ */
+
+#define PED_HISTORY_TAG      "[History] "
+#define PED_HISTORY_MAX_NAME 64
+#define PED_HISTORY_IS_UNDONE(_o) (_o->ignore && _o->disk)
+        
+
+typedef struct _PedHistObj PedHistObj;
+typedef struct _PedHistManager PedHistManager;
+typedef enum _PedHistRet PedHistRet;
+
+#include <parted/disk.h>
+
+/*
+ * Enums
+ */
+
+enum _PedHistRet {
+    PED_HISTORY_RET_SUCCESS,
+    PED_HISTORY_RET_ERROR,
+    PED_HISTORY_RET_NO_UNDO,
+    PED_HISTORY_RET_NO_REDO,
+    PED_HISTORY_RET_NO_SAVE,
+};
+
+
+/*
+ * Structs
+ */
+
+struct _PedHistObj {
+    int         id;
+    int         ignore; /* Undo/Redo functionality */
+    char       *name;   /* Command name */
+    PedDisk    *disk;
+    PedHistObj *prev;
+    PedHistObj *next;
+};
+
+
+struct _PedHistManager {
+    PedHistObj  *begin;
+    PedHistObj  *end;
+    int          n_objs;
+    int          id;
+};
+
+
+/*
+ * Funcs
+ */
+
+/* Add/Clear history */
+extern void ped_history_add (const char *cmd);
+extern void ped_history_clear (void);
+
+/* Iterating */
+extern const PedHistObj *ped_history_begin (void);
+
+/* Duplicate of the most recent disk mod, this can safely be destroyed */
+extern PedDisk *ped_history_disk (void);
+
+/* Before changes are committed */
+extern PedHistRet ped_history_undo (void);
+extern PedHistRet ped_history_redo (void);
+
+/* Write changes to disk
+ * Each change's success/failure value is passed 
+ * to the optional callback so that the end application
+ * can display such values appropriately.
+ */
+typedef void (*PedHistPrintCB) (PedHistRet val, PedHistObj *obj);
+extern PedHistRet ped_history_commit_to_disk (PedHistPrintCB cb);
+
+/* Copy the most recent disk change */
+extern void ped_history_add_disk (const PedDisk *disk);
+
+/* Print */
+extern const char *ped_history_print_ret (PedHistRet val);
+extern void ped_history_print_debug (void);
+
+/* Alloc/dealloc */
+extern PedHistObj *ped_history_alloc_obj (void);
+extern void ped_history_dealloc_obj (PedHistObj *obj);
+
+
+#endif /* PED_HISTORY_H_INCLUDED */
diff --git a/include/parted/parted.h b/include/parted/parted.h
index 31ed6ec..32130d5 100644
--- a/include/parted/parted.h
+++ b/include/parted/parted.h
@@ -28,6 +28,7 @@ extern "C" {
 #include <parted/disk.h>
 #include <parted/exception.h>
 #include <parted/filesys.h>
+#include <parted/history.h>
 #include <parted/natmath.h>
 #include <parted/unit.h>
 
diff --git a/libparted/Makefile.am b/libparted/Makefile.am
index 6f52193..6200166 100644
--- a/libparted/Makefile.am
+++ b/libparted/Makefile.am
@@ -26,6 +26,7 @@ libparted_la_SOURCES  = debug.c                       \
                        timer.c                 \
                        unit.c                  \
                        disk.c                  \
+                       history.c               \
                        cs/geom.c               \
                        cs/constraint.c         \
                        cs/natmath.c            \
diff --git a/libparted/disk.c b/libparted/disk.c
index ec09996..c554e6a 100644
--- a/libparted/disk.c
+++ b/libparted/disk.c
@@ -511,6 +511,17 @@ ped_disk_commit (PedDisk* disk)
        return ped_disk_commit_to_os (disk);
 }
 
+/** 
+ * This adds the disk changes to history.  
+ * These changes can further be undone or redone
+ * until the choses to save them to the partition table.
+ */
+void
+ped_disk_commit_to_history (const PedDisk *disk)
+{
+    ped_history_add_disk (disk);
+}
+
 /**
  * \addtogroup PedPartition
  *
diff --git a/libparted/history.c b/libparted/history.c
new file mode 100644
index 0000000..175199e
--- /dev/null
+++ b/libparted/history.c
@@ -0,0 +1,265 @@
+/*
+    libparted - a library for manipulating disk partitions
+    Copyright (C) 1999, 2000, 2001, 2002, 2003, 2005, 2007
+                  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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <parted/parted.h>
+
+
+/*
+ * Macros for handling error printing
+ */
+
+#if ENABLE_NLS
+#  include <libintl.h>
+#  include <locale.h>
+#  define _(String) dgettext (PACKAGE, String)
+#else
+#  define _(String) (String)
+#endif /* ENABLE_NLS */
+
+char PedHistStr[32];
+
+#define PED_HISTORY_CLR_STR() memset (PedHistStr, 0, sizeof (PedHistStr));
+
+#define PED_HISTORY_SET_STR(_s)                    \
+{                                                  \
+    strncpy (PedHistStr, _s, sizeof (PedHistStr)); \
+}
+
+
+PedHistManager PedHistMgr = {0};
+
+
+void 
+ped_history_add (const char *name)
+{
+    PedHistObj *addme;
+    size_t      name_length;
+
+    /* Deep copy and add to end of list */
+    addme = ped_history_alloc_obj ();
+    addme->id = PedHistMgr.id++;
+
+    /* Add the name using ped allocation */
+    name_length = strlen (name);
+    name_length = (name_length > PED_HISTORY_MAX_NAME) ?
+        PED_HISTORY_MAX_NAME : name_length;
+    addme->name = ped_malloc (name_length);
+    strncpy (addme->name, name, name_length);
+            
+    /* 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 
+ped_history_clear (void)
+{
+    PedHistObj *ii, *freeme;
+ 
+    ii = PedHistMgr.begin;
+    while (ii) {
+        freeme = ii;
+        ii = ii->next;
+        ped_history_dealloc_obj (freeme);
+    }
+
+    memset (&PedHistMgr, 0, sizeof (PedHistMgr));
+}
+
+
+const PedHistObj *
+ped_history_begin (void)
+{
+    return PedHistMgr.begin;
+}
+
+
+/* Return most recent (non-undone) disk modification */
+PedDisk *
+ped_history_disk (void)
+{
+    PedHistObj *ii;
+
+    for (ii = PedHistMgr.end; ii; ii = ii->prev)
+        if (!ii->ignore && ii->disk)
+            return ped_disk_duplicate (ii->disk);
+
+    return NULL;
+}
+
+
+PedHistRet 
+ped_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)
+        return PED_HISTORY_RET_NO_UNDO;
+
+     ii->ignore = 1;
+     return PED_HISTORY_RET_SUCCESS;
+}
+
+    
+PedHistRet 
+ped_history_redo (void)
+{
+    PedHistObj *ii;
+
+    /* Find the most recent undone entry that is a 'disk' mod */
+    for (ii = PedHistMgr.begin; ii; ii = ii->next)
+        if (ii->ignore && ii->disk)
+            break;
+
+    if (!ii)
+        return PED_HISTORY_RET_NO_REDO;
+
+    ii->ignore = 0;
+    return PED_HISTORY_RET_SUCCESS;
+}
+
+
+PedHistObj *
+ped_history_alloc_obj (void)
+{
+    PedHistObj *obj = (PedHistObj *)ped_calloc (sizeof (PedHistObj));
+    return obj;
+}
+
+
+void 
+ped_history_dealloc_obj (PedHistObj *obj)
+{
+    if (!obj)
+        return;
+
+    if (obj->disk)
+        ped_disk_destroy (obj->disk);
+  
+    ped_free (obj->name);
+    ped_free (obj);
+}
+
+
+PedHistRet 
+ped_history_commit_to_disk (PedHistPrintCB cb)
+{
+    int         has_commit;
+    PedHistObj *ii;
+
+    has_commit = 0;
+    for (ii = PedHistMgr.begin; ii; ii = ii->next) {
+        if (ii->disk && !ii->ignore) {
+            has_commit = 1;
+            if (ped_disk_commit (ii->disk) && cb)
+                cb (PED_HISTORY_RET_SUCCESS, ii);
+            else if (cb)
+                cb (PED_HISTORY_RET_ERROR, ii);
+        }
+    }
+  
+    /* Restart fresh */
+    ped_history_clear ();
+
+    if (!has_commit)
+        return PED_HISTORY_RET_NO_SAVE;
+
+    return PED_HISTORY_RET_SUCCESS;
+} 
+
+
+void
+ped_history_add_disk (const PedDisk *disk)
+{
+    PedHistMgr.end->disk = ped_disk_duplicate (disk); 
+}
+
+
+/* Print all history objects */
+void 
+ped_history_print_debug (void)
+{
+    int         has_history;
+    PedHistObj *ii;
+
+    has_history = 0; 
+    for (ii = PedHistMgr.begin; ii; ii = ii->next) {
+
+        /* Only print disk changes */
+        if (!ii->disk)
+            continue;
+        
+        has_history = 1; 
+        printf (_("[History]\t"));
+    
+        if (ii->ignore)
+            printf (_(" (UNDONE)"));
+    }
+
+    if (!has_history)
+        printf (_(PED_HISTORY_TAG "No history available\n"));
+}
+
+
+const char *
+ped_history_print_ret (PedHistRet val)
+{
+    switch (val)
+    {
+        case PED_HISTORY_RET_ERROR: 
+            PED_HISTORY_SET_STR ("unknown error");
+            break;
+
+        case PED_HISTORY_RET_NO_UNDO:
+            PED_HISTORY_SET_STR ("could not undo");
+            break;
+        
+        case PED_HISTORY_RET_NO_REDO:
+            PED_HISTORY_SET_STR ("could not redo");
+            break;
+        
+        case PED_HISTORY_RET_NO_SAVE:
+            PED_HISTORY_SET_STR ("nothing to save");
+            break;
+
+        default: PED_HISTORY_CLR_STR ();
+            break;
+    }
+
+    return PedHistStr;
+}
-- 
1.5.1.5

>From 9a73862a190741bc7ed476893aeaa398581c6f0c Mon Sep 17 00:00:00 2001
From: Matt Davis <[EMAIL PROTECTED]>
Date: Thu, 7 Feb 2008 00:33:00 -0500
Subject: [PATCH] History patch 3 of 3

The following changes apply to testing the history system.

    tests/t4000-history.sh
    Performs 15 tests against the history modifications

    tests/Makefile.am
    Adds the t4000-history.sh test set
---
 tests/t4000-history.sh |  112 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 112 insertions(+), 0 deletions(-)
 create mode 100755 tests/t4000-history.sh

diff --git a/tests/t4000-history.sh b/tests/t4000-history.sh
new file mode 100755
index 0000000..5caecc1
--- /dev/null
+++ b/tests/t4000-history.sh
@@ -0,0 +1,112 @@
+#!/bin/sh
+# Tests for history functionality
+
+# Copyright (C) 2007 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, see <http://www.gnu.org/licenses/>.
+
+test_description='Test history functionality'
+
+. ./init.sh
+
+dev=loop-file
+N=128M
+
+test_expect_success \
+    'create the test file' \
+    'dd if=/dev/null of=$dev bs=1 seek=$N 2> /dev/null'
+
+# Make sure an empty history does not cause any failures.
+test_expect_success \
+    'run parted -s FILE history' \
+    'parted -s $dev history> out 2>&1'
+test_expect_success 'check for empty output' '$compare out /dev/null'
+
+# Make sure an empty history does not cause any failures.
+test_expect_success \
+    'run parted -s FILE undo' \
+    'parted -s $dev undo > out 2>&1'
+test_expect_success 'check for "could not undo"' \
+                    'grep -e "could not undo" out'
+
+# Make sure an empty history does not cause any failures.
+test_expect_success \
+    'run parted -s FILE redo' \
+    'parted -s $dev redo > out 2>&1'
+test_expect_success 'check for "could not redo"' \
+                    'grep -e "could not redo" out'
+
+# Make sure an empty history does not cause any failures.
+test_expect_success \
+    'run parted -s FILE save' \
+    'parted -s $dev save> out 2>&1'
+test_expect_success 'check for "nothing to save"' \
+                    'grep -e "nothing to save" out'
+
+# Add two items and undo the most recent and apply
+test_expect_success \
+    'label the test disk' \
+    'parted -s $dev \
+        mklabel msdos \
+        mkpartfs primary ext2 1 100 \
+        undo \
+        save > out 2>&1'
+test_expect_success 'check for mklabel success'\
+                    'if [ `cat out | wc -l` -eq 2 ]; \
+                     then let success=1; \
+                     fi; \
+                     if grep -q "mklabelmktable" out; \
+                     then let success=$success+1; \
+                     fi; \
+                     test $success -eq 2'
+
+# Add two items, undo the most recent, redo the most recent, and apply
+test_expect_success \
+    'label and partition the test disk' \
+    'parted -s $dev \
+        mklabel msdos \
+        mkpartfs primary ext2 1 100 \
+        undo \
+        redo \
+        save > out 2>&1'
+test_expect_success 'check for mkpartfs success'\
+                    'if [ `cat out | grep "Success" | wc -l` -eq 3 ]; \
+                     then let success=1; \
+                     fi; \
+                     if grep -n "Success" out | \
+                        grep -q -e "2:.*mkpartfs"; \
+                     then let success=$success+1; \
+                     fi; \
+                     test $success -eq 2'
+
+# Test that history output is functioning
+test_expect_success \
+    'label, partition disk twice, and output history log' \
+    'parted -s $dev \
+        mklabel msdos \
+        mkpartfs primary ext2 1 100 \
+        undo \
+        mkpartfs primary ext2 1 64 \
+        history > out 2>&1'
+test_expect_success 'check history output' \
+                    'if [ `cat out | wc -l` -eq 3 ]; \
+                     then let success=1; \
+                     fi; \
+                     if grep -n "Undone" out | \
+                        grep -n -e "2:.*Undone"; \
+                     then let success=$success+1; \
+                     fi; \
+                     test $success -eq 2'
+                        
+test_done
-- 
1.5.1.5

_______________________________________________
parted-devel mailing list
[email protected]
http://lists.alioth.debian.org/mailman/listinfo/parted-devel

Reply via email to