Browse code

Implement add operation

Dario Rodriguez authored on 10/03/2019 23:50:38
Showing 3 changed files
... ...
@@ -52,7 +52,6 @@ redata_init(void)
52 52
         /* undo */
53 53
         redata->sizeundo=0;
54 54
         redata->usedundo=0;
55
-        redata->curundo=0;
56 55
         redata->undo=NULL;
57 56
         redata->undobuf=NULL;
58 57
         /* unsaved */
... ...
@@ -178,6 +177,27 @@ redata_wipe(redata_t *redata)
178 177
         return(0);
179 178
 }
180 179
 
180
+int
181
+redata_chunk_insertnew(redata_t *redata, int afterthischunk)
182
+{
183
+        rechunk_t *newchunk;
184
+        int i;
185
+        if(redata==NULL || afterthischunk<(-1) || afterthischunk>=redata->sizechunks)
186
+                return(-1);
187
+        if(redata->chunks[redata->sizechunks-1]->useddata!=0) {
188
+                if(redata_preallocate(redata,redata_getsize(redata)+redata->chunkdatasize)==-1
189
+                  || redata->chunks[redata->sizechunks-1]->useddata!=0)
190
+                        return(-1);
191
+        }
192
+        newchunk=redata->chunks[redata->sizechunks-1];
193
+        /* move the emtpy chunk to after chunkno */
194
+        for(i=redata->sizechunks-1;i>(afterthischunk+1);i--)
195
+                redata->chunks[i]=redata->chunks[i-1];
196
+        redata->chunks[afterthischunk+1]=newchunk;
197
+        return(0);
198
+}
199
+
200
+
181 201
 int
182 202
 redata_preallocate(redata_t *redata, int newsize)
183 203
 {
... ...
@@ -243,6 +263,8 @@ redata_chunk_movedata(redata_t *redata, int chunkfrom, int posfrom, int chunkto,
243 263
                 memmove(from->data+posfrom,from->data+posfrom+size,from->useddata-posfrom-size);
244 264
                 from->useddata-=size;
245 265
                 to->useddata+=size;
266
+                from->whatin_fresh=0;
267
+                to->whatin_fresh=0;
246 268
         } else {
247 269
                 /* from==to */
248 270
                 rechunk_t *chunk=redata->chunks[chunkfrom];
... ...
@@ -256,12 +278,48 @@ redata_chunk_movedata(redata_t *redata, int chunkfrom, int posfrom, int chunkto,
256 278
                         memmove(chunk->data+posfrom+size-inside,chunk->data+posto,inside);
257 279
                         memcpy(chunk->data+posto,redata->tmpchunk->data,size);
258 280
                 }
281
+                chunk->whatin_fresh=0;
259 282
         }
260 283
         return(0);
261 284
 }
262 285
 
263 286
 int
264
-redata_fill_whatin(redata_t *redata, int chunkno)
287
+redata_chunk_insertdata(redata_t *redata, int chunkto, int posto, char *buf, int buflen)
288
+{
289
+        rechunk_t *chunk;
290
+        if(redata==NULL || buflen<0 || buf==NULL
291
+          || chunkto<0 || chunkto>=redata->sizechunks
292
+          || posto<0 || posto>redata->chunks[chunkto]->useddata
293
+          || (redata->chunkdatasize-redata->chunks[chunkto]->useddata)<buflen)
294
+                return(-1); /* sanity check failed */
295
+        chunk=redata->chunks[chunkto];
296
+        memmove(chunk->data+posto+buflen,chunk->data+posto,chunk->useddata-posto);
297
+        memcpy(chunk->data+posto,buf,buflen);
298
+        chunk->useddata+=buflen;
299
+        chunk->whatin_fresh=0;
300
+        return(0);
301
+}
302
+
303
+int
304
+redata_chunk_deletedata(redata_t *redata, int chunkno, int pos, int n)
305
+{
306
+        rechunk_t *chunk;
307
+        if(redata==NULL || n<0
308
+          || chunk<0 || chunkno>=redata->sizechunks
309
+          || pos<0 || pos>redata->chunks[chunkno]->useddata
310
+          || (redata->chunks[chunkno]->useddata-pos)<n)
311
+                return(-1); /* sanity check failed */
312
+        if(n==0)
313
+                return(0); /* all done */
314
+        chunk=redata->chunks[chunkno];
315
+        memmove(chunk->data+pos,chunk->data+pos+n,chunk->useddata-pos-n);
316
+        chunk->useddata-=n;
317
+        chunk->whatin_fresh=0;
318
+        return(0);
319
+}
320
+
321
+int
322
+redata_whatin_refresh(redata_t *redata, int chunkno)
265 323
 {
266 324
         rechunk_t *chunk;
267 325
         int nlcount;
... ...
@@ -290,8 +348,7 @@ mymemrchr(const void *s, int c, size_t n)
290 348
         b=(*((unsigned int *)(&c)))&0xff;
291 349
         for(i=0;i<n;i++) {
292 350
                 if(((unsigned char *)s)[i]==b)
293
-                        res=s+i;
294
-        }
351
+                        res=(((unsigned char *)s)+i);        }
295 352
         return(res);
296 353
 }
297 354
 
... ...
@@ -321,28 +378,16 @@ redata_fix_nl(redata_t *redata, int chunkno)
321 378
                 /* move incomplete line to next chunk */
322 379
                 redata_chunk_movedata(redata, chunkno, chunk->useddata-linesize, chunkno+1, 0, linesize);
323 380
         } else if(ptr!=NULL) {
324
-                /* only if we have more data un chunkno before this long line */
325
-                int i,newavail;
326
-                rechunk_t *newchunk;
381
+                /* only if we have more data in chunkno before this long line */
382
+                int newavail;
327 383
                 /* create a new empty chunk in-between and put the line there */
328
-                if(redata->chunks[redata->sizechunks-1]->useddata!=0) {
329
-                        if(redata_preallocate(redata,redata->available+redata->chunkdatasize)==-1
330
-                          || redata->chunks[redata->sizechunks-1]->useddata!=0)
331
-                                return(-1);
332
-                }
333
-                newchunk=redata->chunks[redata->sizechunks-1];
334
-                /* move the emty chunk to after chunkno */
335
-                for(i=redata->sizechunks-1;i>(chunkno+1);i--)
336
-                        redata->chunks[i]=redata->chunks[i-1];
337
-                redata->chunks[chunkno+1]=newchunk;
384
+                if(redata_chunk_insertnew(redata,chunkno)==-1)
385
+                        return(-1);
338 386
                 /* move the data; if it doesn't fit, move from the beginning until it is full */
339 387
                 redata_chunk_movedata(redata, chunkno, chunk->useddata-linesize, chunkno+1, 0, linesize);
340 388
                 newavail=redata->sizechunks-linesize;
341 389
                 redata_chunk_movedata(redata, chunkno+2, 0, chunkno+1, linesize, (newavail<nextlinesize)?newavail:nextlinesize);
342
-                redata->chunks[chunkno+2]->whatin_fresh=0;
343 390
         }
344
-        redata->chunks[chunkno]->whatin_fresh=0;
345
-        redata->chunks[chunkno+1]->whatin_fresh=0;
346 391
         return(0);
347 392
 }
348 393
 
... ...
@@ -481,7 +526,7 @@ redata_load(redata_t *redata, char *filename, int use_unsaved)
481 526
         for(totalread=0,chunkno=0,nread=0;totalread<statbuf.st_size;totalread+=nread,nread=0) {
482 527
                 if(chunkno>=redata->sizechunks || redata->chunks[chunkno]==NULL) {
483 528
                         /* alloc another chunk */
484
-                        if(redata_preallocate(redata,(redata->sizechunks+1)*redata->chunkdatasize)==-1 ||
529
+                        if(redata_preallocate(redata,redata_getsize(redata)+redata->chunkdatasize)==-1 ||
485 530
                                 chunkno>=redata->sizechunks || redata->chunks[chunkno]==NULL) {
486 531
                                 close(fd),fd=-1;
487 532
                                 fprintf(stderr,"redata_load: INTERNAL ERROR\n");
... ...
@@ -508,7 +553,7 @@ redata_load(redata_t *redata, char *filename, int use_unsaved)
508 553
         for(chunkno=0;chunkno<redata->sizechunks;chunkno++)
509 554
                 redata_fix_nl(redata,chunkno);
510 555
         for(chunkno=0;chunkno<redata->sizechunks;chunkno++)
511
-                redata_fill_whatin(redata,chunkno);
556
+                redata_whatin_refresh(redata,chunkno);
512 557
         /* unsaved */
513 558
         redata_hash(redata,redata->initialhash);
514 559
         if(use_unsaved) {
... ...
@@ -642,7 +687,7 @@ redata_undo_newfromchunks(redata_t *redata,char *type, int pos1, int len)
642 687
 }
643 688
 
644 689
 undo_t *
645
-redata_undobuf_newfrombuf(redata_t *redata, char *type, char *buf, int buflen)
690
+redata_undo_newfrombuf(redata_t *redata, char *type, char *buf, int buflen)
646 691
 {
647 692
         undo_t *undo;
648 693
         if(redata==NULL || type==NULL || buflen<=0)
... ...
@@ -659,11 +704,73 @@ redata_undobuf_newfrombuf(redata_t *redata, char *type, char *buf, int buflen)
659 704
 }
660 705
 
661 706
 int
662
-redata_op_add(redata_t *redata, char *buf, int sizebuf, int pos)
707
+redata_op_add(redata_t *redata, char *buf, int buflen, int insertpos)
663 708
 {
709
+        int chunkno,pos;
710
+        char hashpost[129];
711
+        undo_t *undo;
712
+        rechunk_t *chunk,*nextchunk;
713
+        int avail,nextavail;
714
+        int i;
715
+        int needed;
716
+        char *ptr;
717
+        if(redata==NULL || buf==NULL || buflen<0 || insertpos<0  || insertpos>redata_getused(redata))
718
+                return(-1); /* sanity check failed */
719
+        if(redata_getposptr(redata,insertpos,&chunkno,&pos)==-1)
720
+                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);
724
+        chunk=redata->chunks[chunkno];
725
+        avail=redata->chunkdatasize-chunk->useddata;
726
+        nextchunk=((chunkno+1)<redata->sizechunks)?redata->chunks[chunkno+1]:NULL;
727
+        nextavail=(nextchunk==NULL)?0:redata->chunkdatasize-nextchunk->useddata;
728
+        if(avail>=buflen) {
729
+                /* fits in current chunk */
730
+                redata_chunk_insertdata(redata,chunkno,pos,buf,buflen);
731
+                redata_fix_nl(redata,chunkno);
732
+                nextchunk=chunk;
733
+        } else if((avail+nextavail)>=buflen) {
734
+                /* part fits in current chunk, part in next chunk */
735
+                int bothering;
736
+                bothering=chunk->useddata-pos;
737
+                bothering=(bothering>nextavail)?nextavail:bothering;
738
+                redata_chunk_movedata(redata,chunkno,chunk->useddata-bothering,chunkno+1,0,bothering);
739
+                redata_chunk_insertdata(redata,chunkno,pos,buf,buflen);
740
+        } else {
741
+                /* will need to add more chunks */
742
+                needed=(buflen+redata->chunkdatasize-1)/redata->chunkdatasize;
743
+                needed*=redata->chunkdatasize;
744
+                needed+=(chunk->useddata-pos);
745
+                if(redata_preallocate(redata,redata_getsize(redata)+needed)!=0) {
746
+                        redata->usedundobuf-=buflen;
747
+                        memset(undo,0,sizeof(undo_t));
748
+                        return(-1); /* insuf. mem. */
749
+                }
750
+                redata_chunk_insertnew(redata,chunkno);
751
+                redata_chunk_movedata(redata,chunkno,pos,chunkno+1,0,chunk->useddata-pos);
752
+                nextchunk=redata->chunks[chunkno+1];
753
+                avail=redata->chunkdatasize-chunk->useddata;
754
+                avail=(avail>buflen)?buflen:avail;
755
+                redata_chunk_insertdata(redata,chunkno,chunk->useddata,buf,avail);
756
+                for(ptr=buf+avail,i=chunkno;(ptr-buf)<buflen;i++,ptr+=avail) {
757
+                        redata_chunk_insertnew(redata,i);
758
+                        avail=redata->chunkdatasize-redata->chunks[i+1]->useddata;
759
+                        avail=(avail>(buflen-(ptr-buf)))?(buflen-(ptr-buf)):avail;
760
+                        redata_chunk_insertdata(redata,i+1,0,ptr,avail);
664 761
 
665
-#warning TODO
666
-        return(-1);
762
+                }
763
+        }
764
+        /* fix nl until nextchunk (...fix_nl can insert chunks) */
765
+        for(i=chunkno;i<redata->sizechunks;i++) {
766
+                redata_fix_nl(redata,i);
767
+                if(redata->chunks[i]==nextchunk)
768
+                        break;
769
+        }
770
+        /* activate undo */
771
+        redata_hash(redata,undo->posthash);
772
+        redata->usedundo++;
773
+        return(0);
667 774
 }
668 775
 
669 776
 int
... ...
@@ -25,9 +25,11 @@ typedef struct rechunk_t {
25 25
 } rechunk_t;
26 26
 
27 27
 typedef struct undo_t {
28
-        char type[5];
28
+        char type[4];
29 29
         int off;
30 30
         int len;
31
+        char prehash[129];
32
+        char posthash[129];
31 33
 } undo_t;
32 34
 
33 35
 typedef struct redata_t {
... ...
@@ -40,7 +42,6 @@ typedef struct redata_t {
40 42
         /* undo */
41 43
         int sizeundo;
42 44
         int usedundo;
43
-        int curundo;
44 45
         undo_t *undo;
45 46
         int sizeundobuf;
46 47
         int usedundobuf;
... ...
@@ -65,12 +66,20 @@ int redata_getavailable(redata_t *redata);
65 66
 int redata_getused(redata_t *redata);
66 67
 int redata_getposptr(redata_t *redata, int pos, int *numchunk, int *offset);
67 68
 
69
+/* low level stuff */
68 70
 int redata_wipe(redata_t *redata);
69 71
 int redata_preallocate(redata_t *redata, int size);
72
+int redata_chunk_insertnew(redata_t *redata, int afterthischunk);
70 73
 int redata_chunk_movedata(redata_t *redata, int chunkfrom, int posfrom, int chunkto, int posto, int size);
71
-int redata_fill_whatin(redata_t *redata, int chunkno);
74
+int redata_chunk_insertdata(redata_t *redata, int chunkto, int posto, char *buf, int buflen);
75
+int redata_chunk_deletedata(redata_t *redata, int chunk, int pos, int n);
76
+int redata_whatin_refresh(redata_t *redata, int chunkno);
72 77
 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);
73 81
 
82
+/* high level stuff */
74 83
 int redata_unsaved_exists(redata_t *redata, char *filename);
75 84
 int redata_unsaved_check(redata_t *redata, char *filename);
76 85
 int redata_unsaved_loadappend(redata_t *redata);
... ...
@@ -82,7 +91,7 @@ int redata_unsaved_unadd(redata_t *redata, undo_t *undo);
82 91
 int redata_load(redata_t *redata, char *filename, int use_unsaved);
83 92
 int redata_save(redata_t *redata, char *filename);
84 93
 
85
-int redata_op_add(redata_t *redata, char *buf, int sizebuf, int pos);
94
+int redata_op_add(redata_t *redata, char *buf, int buflen, int pos);
86 95
 int redata_op_del(redata_t *redata, int pos, int size);
87 96
 int redata_op_move(redata_t *redata, int posorig, int size, int posdest);
88 97
 int redata_op_undo(redata_t *redata);
... ...
@@ -190,7 +190,7 @@ fprintf(stderr,"\ntest_edit(%s%s%s,%s%s%s,%i,%i);\nResult: ",(filename!=NULL)?"\
190 190
                                 size=ptrend-ptr;
191 191
                                 if(k!=0) {
192 192
                                         /* editing */
193
-                                        memmove(mem+l+size,mem+l,size);
193
+                                        memmove(mem+l+size,mem+l,cursize-l);
194 194
                                         memcpy(mem+l,ptr,size);
195 195
                                         redata_op_add(redata,ptr,size,l);
196 196
                                 }