Browse code

Undo/redo enablement

Dario Rodriguez authored on 11/03/2019 23:24:17
Showing 3 changed files
... ...
@@ -50,10 +50,10 @@ redata_init(void)
50 50
         redata->chunkdatasize=CHUNKSIZE;
51 51
         redata->available=0;
52 52
         /* undo */
53
-        redata->sizeundo=0;
54
-        redata->usedundo=0;
55
-        redata->undo=NULL;
56
-        redata->undobuf=NULL;
53
+        redata->undostack.sizeundo=0;
54
+        redata->undostack.usedundo=0;
55
+        redata->undostack.undo=NULL;
56
+        redata->undostack.buf=NULL;
57 57
         /* unsaved */
58 58
         redata->filename[0]='\0';
59 59
         redata->unsavedfd=-1;
... ...
@@ -80,10 +80,10 @@ redata_free(redata_t *redata)
80 80
         if(redata->tmpchunk!=NULL)
81 81
                 free(redata->tmpchunk),redata->tmpchunk=NULL;
82 82
         /* undo */
83
-        if(redata->undo!=NULL)
84
-                free(redata->undo),redata->undo=NULL;
85
-        if(redata->undobuf!=NULL)
86
-                free(redata->undobuf),redata->undobuf=NULL;
83
+        if(redata->undostack.undo!=NULL)
84
+                free(redata->undostack.undo),redata->undostack.undo=NULL;
85
+        if(redata->undostack.buf!=NULL)
86
+                free(redata->undostack.buf),redata->undostack.buf=NULL;
87 87
         /* unsaved */
88 88
         if(redata->unsavedfd!=-1) {
89 89
                 close(redata->unsavedfd),redata->unsavedfd=-1;
... ...
@@ -600,69 +600,72 @@ redata_save(redata_t *redata, char *filename)
600 600
 }
601 601
 
602 602
 int
603
-redata_undobuf_reserve(redata_t *redata, int minavail)
603
+redata_undobuf_reserve(redata_t *redata, undostack_t *stack, int minavail)
604 604
 {
605 605
         int unused;
606 606
         int newsize;
607 607
         char *newptr;
608
-        if(redata==NULL || minavail<0)
608
+        if(redata==NULL || minavail<0
609
+          || (stack!=&(redata->undostack) && stack!=&(redata->redostack)))
609 610
                 return(-1); /* sanity check failed */
610
-        unused=redata->sizeundobuf-redata->usedundobuf;
611
+        unused=stack->sizebuf-stack->usedbuf;
611 612
         if(unused<minavail) {
612
-                newsize=(redata->sizeundobuf+minavail+UNDOGROWSIZE-1)/UNDOGROWSIZE;
613
+                newsize=(stack->sizebuf+minavail+UNDOGROWSIZE-1)/UNDOGROWSIZE;
613 614
                 newsize*=UNDOGROWSIZE;
614
-                if((newptr=realloc(redata->undobuf,newsize))==NULL)
615
+                if((newptr=realloc(stack->buf,newsize))==NULL)
615 616
                         return(-1); /* insuf. mem. */
616
-                redata->undobuf=newptr;
617
-                redata->sizeundobuf=newsize;
617
+                stack->buf=newptr;
618
+                stack->sizebuf=newsize;
618 619
         }
619 620
         return(0);
620 621
 }
621 622
 
622 623
 undo_t *
623
-redata_undo_new(redata_t *redata, char *type)
624
+redata_undo_new(redata_t *redata, undostack_t *stack, char *type)
624 625
 {
625 626
         int newsize;
626 627
         undo_t *newptr,*undo;
627
-        if(redata==NULL || type==NULL)
628
+        if(redata==NULL || type==NULL
629
+          || (stack!=&(redata->undostack) && stack!=&(redata->redostack)))
628 630
                 return(NULL); /* sanity check failed */
629
-        if(redata->sizeundo==redata->usedundo) {
630
-                newsize=(redata->sizeundo+1+UNDOBLOCK-1)/UNDOBLOCK;
631
+        if(stack->sizeundo==stack->usedundo) {
632
+                newsize=(stack->sizeundo+1+UNDOBLOCK-1)/UNDOBLOCK;
631 633
                 newsize*=UNDOBLOCK;
632
-                if((newptr=realloc(redata->undo,sizeof(undo_t)*newsize))==NULL)
634
+                if((newptr=realloc(stack->undo,sizeof(undo_t)*newsize))==NULL)
633 635
                         return(NULL);
634
-                redata->undo=newptr;
635
-                memset(redata->undo+redata->sizeundo,0,sizeof(undo_t)*(newsize-redata->sizeundo));
636
-                redata->sizeundo=newsize;
636
+                stack->undo=newptr;
637
+                memset(stack->undo+stack->sizeundo,0,sizeof(undo_t)*(newsize-stack->sizeundo));
638
+                stack->sizeundo=newsize;
637 639
         }
638
-        undo=redata->undo+redata->usedundo;
639
-        redata->usedundo++;
640
+        undo=stack->undo+stack->usedundo;
641
+        stack->usedundo++;
640 642
         strncpy(undo->type,type,sizeof(undo->type));
641 643
         undo->type[sizeof(undo->type)-1]='\0';
642
-        undo->off=redata->usedundobuf;
644
+        undo->off=stack->usedbuf;
643 645
         undo->len=0;
644 646
         return(undo);
645 647
 }
646 648
 
647 649
 undo_t *
648
-redata_undo_newfromchunks(redata_t *redata,char *type, int pos1, int len)
650
+redata_undo_newfromchunks(redata_t *redata, undostack_t *stack, char *type, int pos1, int len)
649 651
 {
650 652
         int startpos,startoff,endpos,endoff;
651 653
         undo_t *undo;
652 654
         int k;
653 655
         int used;
654 656
         int copyfrom,copysize;
655
-        if(redata==NULL || type==NULL || len<=0)
657
+        if(redata==NULL || type==NULL || len<=0
658
+          || (stack!=&(redata->undostack) && stack!=&(redata->redostack)))
656 659
                 return(NULL); /* sanity check failed */
657 660
         if(redata_getposptr(redata,pos1,&startpos,&startoff)==-1 ||
658 661
           redata_getposptr(redata,pos1+len,&endpos,&endoff)==-1) {
659 662
                 return(NULL); /* chunk data out of bounds */
660 663
         }
661
-        if(redata_undobuf_reserve(redata,len)!=0)
664
+        if(redata_undobuf_reserve(redata,stack,len)!=0)
662 665
                 return(NULL); /* insuf. mem. */
663
-        if((undo=redata_undo_new(redata,type))==NULL)
666
+        if((undo=redata_undo_new(redata,stack,type))==NULL)
664 667
                 return(NULL); /* insuf. mem. */
665
-        undo->off=redata->usedundobuf;
668
+        undo->off=stack->usedbuf;
666 669
         /* copy contents */
667 670
         for(k=startpos,used=0;k<=endpos;k++) {
668 671
                 if(k==startpos && k==endpos) {
... ...
@@ -678,8 +681,8 @@ redata_undo_newfromchunks(redata_t *redata,char *type, int pos1, int len)
678 681
                         copyfrom=0;
679 682
                         copysize=redata->chunks[k]->useddata;
680 683
                 }
681
-                memcpy(redata->undobuf+redata->usedundobuf,redata->chunks[k]->data+copyfrom,copysize);
682
-                redata->usedundobuf+=copysize;
684
+                memcpy(stack->buf+stack->usedbuf,redata->chunks[k]->data+copyfrom,copysize);
685
+                stack->usedbuf+=copysize;
683 686
                 used+=copysize;
684 687
         }
685 688
         undo->len=used;
... ...
@@ -687,40 +690,95 @@ redata_undo_newfromchunks(redata_t *redata,char *type, int pos1, int len)
687 690
 }
688 691
 
689 692
 undo_t *
690
-redata_undo_newfrombuf(redata_t *redata, char *type, char *buf, int buflen)
693
+redata_undo_newfrombuf(redata_t *redata, undostack_t *stack, char *type, char *buf, int buflen)
691 694
 {
692 695
         undo_t *undo;
693
-        if(redata==NULL || type==NULL || buflen<=0)
696
+        if(redata==NULL || type==NULL || buflen<=0
697
+          || (stack!=&(redata->undostack) && stack!=&(redata->redostack)))
694 698
                 return(NULL); /* sanity check failed */
695
-        if(redata_undobuf_reserve(redata,buflen)!=0)
699
+        if(redata_undobuf_reserve(redata,stack, buflen)!=0)
696 700
                 return(NULL); /* insuf. mem. */
697
-        if((undo=redata_undo_new(redata,type))==NULL)
701
+        if((undo=redata_undo_new(redata,stack,  type))==NULL)
698 702
                 return(NULL); /* insuf. mem. */
699
-        undo->off=redata->usedundobuf;
700
-        memcpy(redata->undobuf+redata->usedundobuf,buf,buflen);
701
-        redata->usedundobuf+=buflen;
703
+        undo->off=stack->usedbuf;
704
+        memcpy(stack->buf+stack->usedbuf,buf,buflen);
705
+        stack->usedbuf+=buflen;
702 706
         undo->len=buflen;
703 707
         return(undo);
704 708
 }
705 709
 
706 710
 int
707
-redata_op_add(redata_t *redata, char *buf, int buflen, int insertpos)
711
+redata_undo_movelast(redata_t *redata, undostack_t *from, undostack_t *to)
712
+{
713
+        undo_t *undofrom;
714
+        undo_t *undoto;
715
+        if(redata==NULL || from!=to
716
+          || (from!=&(redata->undostack) && from!=&(redata->redostack))
717
+          || (to!=&(redata->undostack) && to!=&(redata->redostack))
718
+          || from->usedundo<1)
719
+                return(-1); /* sanity check failed */
720
+        undofrom=from->undo+from->usedundo-1;
721
+        if((undoto=redata_undo_newfrombuf(redata,to,undofrom->type,from->buf+undofrom->off,undofrom->len))==NULL)
722
+                return(-1); /* insuf. mem. */
723
+        undoto->posorig=undofrom->posorig;
724
+        undoto->posdest=undofrom->posdest;
725
+        memcpy(undoto->prehash,undofrom->prehash,sizeof(undoto->prehash));
726
+        memcpy(undoto->posthash,undofrom->posthash,sizeof(undoto->posthash));
727
+        redata_undo_removelast(redata, from);
728
+        return(0);
729
+}
730
+
731
+int
732
+redata_undo_removelast(redata_t *redata, undostack_t *stack)
733
+{
734
+        undo_t *undo;
735
+        if(redata==NULL
736
+          || (stack!=&(redata->undostack) && stack!=&(redata->redostack))
737
+          || stack->usedundo<1)
738
+                return(-1); /* sanity check failed */
739
+        undo=stack->undo+stack->usedundo-1;
740
+        stack->usedbuf-=undo->len;
741
+        memset(undo,0,sizeof(undo_t));
742
+        stack->usedundo--;
743
+        return(0);
744
+}
745
+
746
+int
747
+redata_undo_wipe(redata_t *redata, undostack_t *stack)
748
+{
749
+        if(redata==NULL
750
+          || (stack!=&(redata->undostack) && stack!=&(redata->redostack)))
751
+                return(-1); /* sanity check failed */
752
+        memset(stack->undo,0,sizeof(undo_t)*stack->usedundo);
753
+        stack->usedundo=0;
754
+        memset(stack->buf,0,stack->usedbuf);
755
+        stack->usedbuf=0;
756
+        return(0);
757
+}
758
+
759
+int
760
+redata_op_add(redata_t *redata, int insertpos, char *buf, int buflen, undostack_t *fromhere)
708 761
 {
709 762
         int chunkno,pos;
710
-        char hashpost[129];
711 763
         undo_t *undo;
712 764
         rechunk_t *chunk,*nextchunk;
713 765
         int avail,nextavail;
714 766
         int i;
715 767
         int needed;
716 768
         char *ptr;
717
-        if(redata==NULL || buf==NULL || buflen<0 || insertpos<0  || insertpos>redata_getused(redata))
769
+        if(redata==NULL || buf==NULL || buflen<0 || insertpos<0
770
+          || insertpos>redata_getused(redata)
771
+          || (fromhere!=NULL && (fromhere!=&(redata->undostack) && fromhere!=&(redata->redostack))))
718 772
                 return(-1); /* sanity check failed */
719 773
         if(redata_getposptr(redata,insertpos,&chunkno,&pos)==-1)
720 774
                 return(-1); /* invalid pos */
721
-        if((undo=redata_undo_newfrombuf(redata,"ADD",buf,buflen))==NULL)
722
-                return(-1); /* couldn't create undo struct */
723
-        redata_hash(redata,undo->prehash);
775
+        if(fromhere!=&(redata->undostack)) {
776
+                if((undo=redata_undo_newfrombuf(redata,&(redata->undostack),"ADD",buf,buflen))==NULL)
777
+                        return(-1); /* couldn't create undo struct */
778
+                redata_hash(redata,undo->prehash);
779
+        } else {
780
+                undo=NULL;
781
+        }
724 782
         chunk=redata->chunks[chunkno];
725 783
         avail=redata->chunkdatasize-chunk->useddata;
726 784
         nextchunk=((chunkno+1)<redata->sizechunks)?redata->chunks[chunkno+1]:NULL;
... ...
@@ -743,8 +801,10 @@ redata_op_add(redata_t *redata, char *buf, int buflen, int insertpos)
743 801
                 needed*=redata->chunkdatasize;
744 802
                 needed+=(chunk->useddata-pos);
745 803
                 if(redata_preallocate(redata,redata_getsize(redata)+needed)!=0) {
746
-                        redata->usedundobuf-=buflen;
747
-                        memset(undo,0,sizeof(undo_t));
804
+                        if(undo!=NULL) {
805
+                                redata->undostack.usedbuf-=buflen;
806
+                                memset(undo,0,sizeof(undo_t));
807
+                        }
748 808
                         return(-1); /* insuf. mem. */
749 809
                 }
750 810
                 redata_chunk_insertnew(redata,chunkno);
... ...
@@ -768,20 +828,31 @@ redata_op_add(redata_t *redata, char *buf, int buflen, int insertpos)
768 828
                         break;
769 829
         }
770 830
         /* activate undo */
771
-        redata_hash(redata,undo->posthash);
772
-        redata->usedundo++;
831
+        if(undo!=NULL) {
832
+                /* new or from redo stack */
833
+                undo->posorig=undo->posdest=insertpos;
834
+                redata_hash(redata,undo->posthash);
835
+                redata->undostack.usedundo++;
836
+                if(fromhere==&(redata->redostack))
837
+                        redata_undo_removelast(redata,&(redata->redostack));
838
+                else
839
+                        redata_undo_wipe(redata,&(redata->redostack));
840
+        } else {
841
+                /* from undo stack */
842
+                redata_undo_movelast(redata,&(redata->undostack),&(redata->redostack));
843
+        }
773 844
         return(0);
774 845
 }
775 846
 
776 847
 int
777
-redata_op_del(redata_t *redata, int pos, int size)
848
+redata_op_del(redata_t *redata, int pos, int size, undostack_t *fromhere)
778 849
 {
779 850
 #warning TODO
780 851
         return(-1);
781 852
 }
782 853
 
783 854
 int
784
-redata_op_move(redata_t *redata, int posorig, int size, int posdest)
855
+redata_op_move(redata_t *redata, int posorig, int size, int posdest, undostack_t *fromhere)
785 856
 {
786 857
 #warning TODO
787 858
         return(-1);
... ...
@@ -790,13 +861,29 @@ redata_op_move(redata_t *redata, int posorig, int size, int posdest)
790 861
 int
791 862
 redata_op_undo(redata_t *redata)
792 863
 {
864
+        undo_t *undo;
865
+        if(redata==NULL
866
+          || redata->undostack.usedundo<1)
867
+                return(-1); /* sanity check failed */
868
+        undo=redata->undostack.undo+redata->undostack.usedundo-1;
869
+        if(strcmp(undo->type,"ADD")==0) {
870
+                redata_op_del(redata,undo->posorig,undo->len,&(redata->undostack));
871
+        } else if(strcmp(undo->type,"DEL")==0) {
872
+                redata_op_add(redata,undo->posorig,redata->undostack.buf+undo->off,undo->len,&(redata->undostack));
873
+        } else if(strcmp(undo->type,"MOV")==0) {
793 874
 #warning TODO
875
+        } else
876
+                return(-1); /* unknown operation */
877
+ #warning TODO
794 878
         return(-1);
795 879
 }
796 880
 
797 881
 int
798 882
 redata_op_redo(redata_t *redata)
799 883
 {
884
+        if(redata==NULL
885
+          || redata->redostack.usedundo<1)
886
+                return(-1); /* sanity check failed */
800 887
 #warning TODO
801 888
         return(-1);
802 889
 }
... ...
@@ -28,10 +28,21 @@ typedef struct undo_t {
28 28
         char type[4];
29 29
         int off;
30 30
         int len;
31
+        int posorig;
32
+        int posdest;
31 33
         char prehash[129];
32 34
         char posthash[129];
33 35
 } undo_t;
34 36
 
37
+typedef struct undostack_t {
38
+        int sizeundo;
39
+        int usedundo;
40
+        undo_t *undo;
41
+        int sizebuf;
42
+        int usedbuf;
43
+        char *buf;
44
+} undostack_t;
45
+
35 46
 typedef struct redata_t {
36 47
         /* data */
37 48
         int chunkdatasize;
... ...
@@ -40,12 +51,8 @@ typedef struct redata_t {
40 51
         int available;
41 52
         rechunk_t *tmpchunk;
42 53
         /* undo */
43
-        int sizeundo;
44
-        int usedundo;
45
-        undo_t *undo;
46
-        int sizeundobuf;
47
-        int usedundobuf;
48
-        char *undobuf;
54
+        undostack_t undostack;
55
+        undostack_t redostack;
49 56
         /* unsaved (for recovery when the program closes unexpectedly) */
50 57
         char filename[PATH_MAX];
51 58
         char initialhash[129];
... ...
@@ -75,9 +82,13 @@ int redata_chunk_insertdata(redata_t *redata, int chunkto, int posto, char *buf,
75 82
 int redata_chunk_deletedata(redata_t *redata, int chunk, int pos, int n);
76 83
 int redata_whatin_refresh(redata_t *redata, int chunkno);
77 84
 int redata_fix_nl(redata_t *redata, int chunkno);
78
-undo_t *redata_undo_new(redata_t *redata, char *type);
79
-undo_t *redata_undo_newfromchunks(redata_t *redata,char *type, int pos1, int len);
80
-undo_t *redata_undo_newfrombuf(redata_t *redata, char *type, char *buf, int buflen);
85
+int redata_undobuf_reserve(redata_t *redata, undostack_t *stack, int minavail);
86
+undo_t *redata_undo_new(redata_t *redata, undostack_t *stack, char *type);
87
+undo_t *redata_undo_newfromchunks(redata_t *redata, undostack_t *stack, char *type, int pos1, int len);
88
+undo_t *redata_undo_newfrombuf(redata_t *redata, undostack_t *stack, char *type, char *buf, int buflen);
89
+int redata_undo_movelast(redata_t *redata, undostack_t *from, undostack_t *to);
90
+int redata_undo_removelast(redata_t *redata, undostack_t *stack);
91
+int redata_undo_wipe(redata_t *redata, undostack_t *stack);
81 92
 
82 93
 /* high level stuff */
83 94
 int redata_unsaved_exists(redata_t *redata, char *filename);
... ...
@@ -91,9 +102,9 @@ int redata_unsaved_unadd(redata_t *redata, undo_t *undo);
91 102
 int redata_load(redata_t *redata, char *filename, int use_unsaved);
92 103
 int redata_save(redata_t *redata, char *filename);
93 104
 
94
-int redata_op_add(redata_t *redata, char *buf, int buflen, int pos);
95
-int redata_op_del(redata_t *redata, int pos, int size);
96
-int redata_op_move(redata_t *redata, int posorig, int size, int posdest);
105
+int redata_op_add(redata_t *redata, int pos, char *buf, int buflen, undostack_t *fromhere);
106
+int redata_op_del(redata_t *redata, int pos, int size, undostack_t *fromhere);
107
+int redata_op_move(redata_t *redata, int posorig, int size, int posdest, undostack_t *fromhere);
97 108
 int redata_op_undo(redata_t *redata);
98 109
 int redata_op_redo(redata_t *redata);
99 110
 
... ...
@@ -192,7 +192,7 @@ fprintf(stderr,"\ntest_edit(%s%s%s,%s%s%s,%i,%i);\nResult: ",(filename!=NULL)?"\
192 192
                                         /* editing */
193 193
                                         memmove(mem+l+size,mem+l,cursize-l);
194 194
                                         memcpy(mem+l,ptr,size);
195
-                                        redata_op_add(redata,ptr,size,l);
195
+                                        redata_op_add(redata,l,ptr,size,NULL);
196 196
                                 }
197 197
                                 cursize+=size;
198 198
                                 ptr+=size;