Browse code

renamed recenteditor_data to re_data, recenteditor_tests to re_tests

Dario Rodriguez authored on 01/04/2019 21:26:29
Showing 1 changed files
1 1
deleted file mode 100644
... ...
@@ -1,1766 +0,0 @@
1
-/*
2
- * recenteditor_data.c
3
- *
4
- * A programmers editor
5
- *
6
- * Structures to hold the current file contents.
7
- *
8
- * Author: Dario Rodriguez dario@softhome.net
9
- * This program is licensed under the terms of GNU GPL v2.1+
10
- */
11
-
12
-#include <stdio.h>
13
-#include <stdlib.h>
14
-#include <unistd.h>
15
-#include <string.h>
16
-#include <sys/types.h>
17
-#include <sys/stat.h>
18
-#include <fcntl.h>
19
-#include <limits.h>
20
-#include <inttypes.h>
21
-
22
-#include "recenteditor_data.h"
23
-#include "sha3/sha3.h"
24
-
25
-#define CHUNKSIZE 32768
26
-#define UNDOBLOCK 1024
27
-#define UNDOGROWSIZE (256*1024)
28
-#define UNSAVEDPREFIX "."
29
-#define UNSAVEDPOSTFIX ".reu"
30
-#define SECURESAVEPREFIX "."
31
-#define SECURESAVEPOSTFIX ".saving"
32
-#define UNSAVEDHEADER "reunsaved00,"
33
-
34
-static int redata_hash_gen(redata_t *redata, char *filename, char *buf, long buflen, char *resbuf129bytes);
35
-static int redata_unsaved_check_gen(redata_t *redata, char *filename);
36
-static char *unsaved_genname(char *filename, char *buf, int bufsize);
37
-static char *securesave_genname(char *filename, char *buf, int bufsize);
38
-static char *genname(char *filename,char *prefix, char *postfix, char *buf, int bufsize);
39
-static char *ptr_getlong(char *ptr,char *endptr,long *data);
40
-static char *ptr_getchar(char *ptr,char *endptr,char *data);
41
-static char *ptr_searchendchar(char *ptr, char *endptr, char endchar, char **endcharpos);
42
-static char sep_select(char *buf, int bufsize, char **pos);
43
-static void *mymemrchr(const void *s, int c, size_t n);
44
-static void meminvert(void *start, void *end);
45
-
46
-#if 0
47
-static void
48
-redata_debug_chunkdump(redata_t *redata, char *title)
49
-{
50
-        int m,k;
51
-        char c;
52
-        title=(title==NULL)?"":title;
53
-        fprintf(stderr,"%s:CHUNKDUMP (sizechunks:%i)\n",title,redata->sizechunks);
54
-        for(m=0;m<redata->sizechunks;m++) {
55
-                fprintf(stderr,"%s:chunk[%i]:\"",title,m);
56
-                for(k=0;k<redata->chunks[m]->useddata;k++) {
57
-                        c=redata->chunks[m]->data[k];
58
-                        c=(c>=' ' && c<='~')?c:'.';
59
-                        fprintf(stderr,"%c",c);
60
-                }
61
-                fprintf(stderr,"\"\n");
62
-        }
63
-}
64
-#endif
65
-
66
-redata_t *
67
-redata_init(void)
68
-{
69
-        redata_t *redata;
70
-        if((redata=malloc(sizeof(redata_t)))==NULL)
71
-                return(NULL); /* sanity check failed */
72
-        memset(redata,0,sizeof(redata_t));
73
-        /* data */
74
-        redata->sizechunks=0;
75
-        redata->chunks=NULL;
76
-        redata->chunkdatasize=CHUNKSIZE;
77
-        redata->available=0;
78
-        /* undo */
79
-        redata->undostack.sizeundo=0;
80
-        redata->undostack.usedundo=0;
81
-        redata->undostack.undo=NULL;
82
-        redata->undostack.buf=NULL;
83
-        /* unsaved */
84
-        redata->filename[0]='\0';
85
-        redata->unsavedfd=-1;
86
-        redata->unsaved.sizebuf=redata->unsaved.usedbuf=0;
87
-        /* all done */
88
-        return(redata);
89
-}
90
-
91
-void
92
-redata_free(redata_t *redata)
93
-{
94
-        int i;
95
-        char unsname[PATH_MAX];
96
-        if(redata==NULL)
97
-                return; /* nothing to do */
98
-        /* data */
99
-        for(i=0;i<redata->sizechunks;i++) {
100
-                if(redata->chunks[i]!=NULL)
101
-                        free(redata->chunks[i]),redata->chunks[i]=NULL;
102
-        }
103
-        redata->sizechunks=0;
104
-        if(redata->chunks!=NULL)
105
-                free(redata->chunks),redata->chunks=NULL;
106
-        if(redata->tmpchunk!=NULL)
107
-                free(redata->tmpchunk),redata->tmpchunk=NULL;
108
-        /* undo */
109
-        if(redata->undostack.undo!=NULL)
110
-                free(redata->undostack.undo),redata->undostack.undo=NULL;
111
-        if(redata->undostack.buf!=NULL)
112
-                free(redata->undostack.buf),redata->undostack.buf=NULL;
113
-        /* redo */
114
-        if(redata->redostack.undo!=NULL)
115
-                free(redata->redostack.undo),redata->redostack.undo=NULL;
116
-        if(redata->redostack.buf!=NULL)
117
-                free(redata->redostack.buf),redata->redostack.buf=NULL;
118
-        /* unsaved */
119
-        if(redata->unsavedfd!=-1) {
120
-                close(redata->unsavedfd),redata->unsavedfd=-1;
121
-                if(unsaved_genname(redata->filename,unsname,sizeof(unsname))!=NULL)
122
-                        unlink(unsname);
123
-        }
124
-        if(redata->unsaved.buf!=NULL) {
125
-                free(redata->unsaved.buf),redata->unsaved.buf=NULL;
126
-                redata->unsaved.sizebuf=redata->unsaved.usedbuf=0;
127
-        }
128
-        /* free main struct */
129
-        free(redata),redata=NULL;
130
-        return;
131
-}
132
-
133
-int
134
-redata_config_chunkdatasize(redata_t *redata, int chunkdatasize)
135
-{
136
-        /* NOTE: this can only be configured immediately after doing redata_init() */
137
-        if(redata==NULL || chunkdatasize<=0 || redata->sizechunks!=0)
138
-                return(-1); /* sanity check failed */
139
-        redata->chunkdatasize=chunkdatasize;
140
-        return(0);
141
-}
142
-
143
-long
144
-redata_getsize(redata_t *redata)
145
-{
146
-        if(redata==NULL)
147
-                return(0); /* sanity check failed */
148
-        return(redata->chunkdatasize*redata->sizechunks);
149
-}
150
-
151
-long
152
-redata_getavailable(redata_t *redata)
153
-{
154
-        if(redata==NULL)
155
-                return(0); /* sanity check failed */
156
-        return(redata->available);
157
-}
158
-
159
-long
160
-redata_getused(redata_t *redata)
161
-{
162
-        long used;
163
-        if(redata==NULL)
164
-                return(0); /* sanity check failed */
165
-        used=redata->chunkdatasize*redata->sizechunks-redata->available;
166
-        return(used);
167
-}
168
-
169
-int
170
-redata_getposptr(redata_t *redata, long pos, int *numchunk, long *offset)
171
-{
172
-        long used;
173
-        int i;
174
-        long ipos;
175
-        used=redata_getused(redata);
176
-        if(redata==NULL || pos<0 || pos>used || numchunk==NULL || offset==NULL)
177
-                return(-1); /* sanity check failed */
178
-        for(ipos=0,i=0;i<redata->sizechunks;ipos+=redata->chunks[i]->useddata,i++) {
179
-                if(pos>(ipos+redata->chunks[i]->useddata))
180
-                        continue;
181
-                /* found */
182
-                *numchunk=i;
183
-                *offset=pos-ipos;
184
-                return(0);
185
-        }
186
-        return(-1);
187
-}
188
-
189
-int
190
-redata_wipe(redata_t *redata)
191
-{
192
-        int i;
193
-        char unsname[PATH_MAX];
194
-        if(redata==NULL)
195
-                return(-1); /* sanity check failed */
196
-        /* data */
197
-        for(i=0;i<redata->sizechunks;i++) {
198
-                redata->chunks[i]->useddata=0;
199
-                memset(&(redata->chunks[i]->whatin),0,sizeof(whatin_t));
200
-        }
201
-        redata->available=redata_getsize(redata);
202
-        /* unsaved */
203
-        if(redata->unsavedfd!=-1) {
204
-                close(redata->unsavedfd),redata->unsavedfd=-1;
205
-                if(unsaved_genname(redata->filename,unsname,sizeof(unsname))!=NULL)
206
-                        unlink(unsname);
207
-        }
208
-        redata->filename[0]='\0';
209
-        redata->unsaved.usedbuf=0;
210
-        /* all done */
211
-        return(0);
212
-}
213
-
214
-int
215
-redata_chunk_insertnew(redata_t *redata, int afterthischunk)
216
-{
217
-        rechunk_t *newchunk;
218
-        int i;
219
-        if(redata==NULL || afterthischunk<(-1) || afterthischunk>=redata->sizechunks)
220
-                return(-1);
221
-        if(redata->chunks[redata->sizechunks-1]->useddata!=0) {
222
-                if(redata_preallocate(redata,redata_getsize(redata)+redata->chunkdatasize)==-1
223
-                  || redata->chunks[redata->sizechunks-1]->useddata!=0)
224
-                        return(-1);
225
-        }
226
-        newchunk=redata->chunks[redata->sizechunks-1];
227
-        /* move the emtpy chunk to after chunkno */
228
-        for(i=redata->sizechunks-1;i>(afterthischunk+1);i--)
229
-                redata->chunks[i]=redata->chunks[i-1];
230
-        redata->chunks[afterthischunk+1]=newchunk;
231
-        return(0);
232
-}
233
-
234
-int
235
-redata_chunk_deletechunk(redata_t *redata, int chunkno)
236
-{
237
-        rechunk_t *chunk;
238
-        int i;
239
-        if(redata==NULL || chunkno<0 || chunkno>=redata->sizechunks)
240
-                return(-1);
241
-        chunk=redata->chunks[chunkno];
242
-        if(chunk->useddata>0) {
243
-                redata->available+=chunk->useddata;
244
-                chunk->useddata=0;
245
-                chunk->whatin_fresh=0;
246
-        }
247
-        for(i=chunkno;(i+1)<redata->sizechunks;i++)
248
-                redata->chunks[i]=redata->chunks[i+1];
249
-        redata->chunks[redata->sizechunks-1]=chunk;
250
-        return(0);
251
-}
252
-
253
-
254
-int
255
-redata_preallocate(redata_t *redata, long newsize)
256
-{
257
-        long cursize;
258
-        int nchunks;
259
-        int i;
260
-        long rechunksize;
261
-        rechunk_t **newchunks,*chunk;
262
-        int oldsizechunks;
263
-        if(redata==NULL || redata->chunkdatasize==0 || newsize<0)
264
-                return(-1); /* sanity check failed */
265
-        rechunksize=sizeof(rechunk_t)-1+redata->chunkdatasize;
266
-        /* before doing any chunk alloc, we setup tmpchunk (used for moves) */
267
-        if(redata->tmpchunk==NULL) {
268
-                if((redata->tmpchunk=malloc(rechunksize))==NULL)
269
-                        return(-1);  /* insuf. mem. */
270
-                memset(redata->tmpchunk,0,rechunksize);
271
-        }
272
-        /* new chunk processing */
273
-        if((cursize=redata_getsize(redata))>=newsize)
274
-                return(0); /* all done */
275
-        nchunks=(newsize-cursize+redata->chunkdatasize-1)/redata->chunkdatasize;
276
-        if((newchunks=realloc(redata->chunks,sizeof(rechunk_t *)*(redata->sizechunks+nchunks)))==NULL)
277
-                return(-1); /* insuf. mem. */
278
-        redata->chunks=newchunks;
279
-        memset(redata->chunks+redata->sizechunks,0,sizeof(rechunk_t *)*nchunks);
280
-        oldsizechunks=redata->sizechunks;
281
-        for(i=0;i<nchunks;i++) {
282
-                if((chunk=malloc(rechunksize))==NULL)
283
-                        return(-1);  /* insuf. mem. */
284
-                memset(chunk,0,rechunksize);
285
-                chunk->useddata=0;
286
-                redata->chunks[oldsizechunks+i]=chunk;
287
-                redata->sizechunks++;
288
-                redata->available+=redata->chunkdatasize;
289
-        }
290
-        return(0);
291
-}
292
-
293
-int
294
-redata_chunk_movedata(redata_t *redata, int chunkfrom, long posfrom, int chunkto, long posto, long size)
295
-{
296
-        if(redata==NULL || size<0
297
-          || chunkfrom<0 || chunkfrom>=redata->sizechunks
298
-          || posfrom<0 || (posfrom+size)>redata->chunks[chunkfrom]->useddata
299
-          || chunkto<0 || chunkto>=redata->sizechunks
300
-          || posto<0 || (posto)>redata->chunks[chunkto]->useddata
301
-          || (chunkfrom!=chunkto && (redata->chunkdatasize-redata->chunks[chunkto]->useddata)<size)
302
-          || (chunkfrom==chunkto && posfrom<posto && posfrom+size>posto)
303
-          )
304
-                return(-1); /* sanity check failed */
305
-        if(size==0
306
-          || (chunkfrom==chunkto && posfrom==posto)
307
-          || (chunkfrom==chunkto && (posfrom+size)==posto)
308
-          )
309
-                return(0); /* all done */
310
-        if(chunkfrom!=chunkto) {
311
-                rechunk_t *from,*to;
312
-                from=redata->chunks[chunkfrom];
313
-                to=redata->chunks[chunkto];
314
-                memmove(to->data+posto+size,to->data+posto,to->useddata-posto);
315
-                memcpy(to->data+posto,from->data+posfrom,size);
316
-                memmove(from->data+posfrom,from->data+posfrom+size,from->useddata-posfrom-size);
317
-                from->useddata-=size;
318
-                to->useddata+=size;
319
-                from->whatin_fresh=0;
320
-                to->whatin_fresh=0;
321
-        } else {
322
-                /* from==to */
323
-                rechunk_t *chunk=redata->chunks[chunkfrom];
324
-                memcpy(redata->tmpchunk->data,chunk->data+posfrom,size);
325
-                if(posfrom>posto) {
326
-                        memmove(chunk->data+posto+size,chunk->data+posto,posfrom-posto);
327
-                        memcpy(chunk->data+posto,redata->tmpchunk->data,size);
328
-                } else {
329
-                        memmove(chunk->data+posfrom,chunk->data+posfrom+size,posto-posfrom-size);
330
-                        memcpy(chunk->data+posto-size,redata->tmpchunk->data,size);
331
-                }
332
-                chunk->whatin_fresh=0;
333
-        }
334
-        return(0);
335
-}
336
-
337
-int
338
-redata_chunk_insertdata(redata_t *redata, int chunkto, long posto, char *buf, long buflen)
339
-{
340
-        rechunk_t *chunk;
341
-        if(redata==NULL || buflen<0 || buf==NULL
342
-          || chunkto<0 || chunkto>=redata->sizechunks
343
-          || posto<0 || posto>redata->chunks[chunkto]->useddata
344
-          || (redata->chunkdatasize-redata->chunks[chunkto]->useddata)<buflen)
345
-                return(-1); /* sanity check failed */
346
-        chunk=redata->chunks[chunkto];
347
-        memmove(chunk->data+posto+buflen,chunk->data+posto,chunk->useddata-posto);
348
-        memcpy(chunk->data+posto,buf,buflen);
349
-        chunk->useddata+=buflen;
350
-        chunk->whatin_fresh=0;
351
-        redata->available-=buflen;
352
-        return(0);
353
-}
354
-
355
-int
356
-redata_chunk_deletedata(redata_t *redata, int chunkno, long pos, long n)
357
-{
358
-        rechunk_t *chunk;
359
-        if(redata==NULL || n<0
360
-          || chunkno<0 || chunkno>=redata->sizechunks
361
-          || pos<0 || pos>redata->chunks[chunkno]->useddata
362
-          || (redata->chunks[chunkno]->useddata-pos)<n)
363
-                return(-1); /* sanity check failed */
364
-        if(n==0)
365
-                return(0); /* all done */
366
-        chunk=redata->chunks[chunkno];
367
-        memmove(chunk->data+pos,chunk->data+pos+n,chunk->useddata-pos-n);
368
-        chunk->useddata-=n;
369
-        chunk->whatin_fresh=0;
370
-        redata->available+=n;
371
-        return(0);
372
-}
373
-
374
-int
375
-redata_chunk_splithere(redata_t *redata, int chunkno, int pos)
376
-{
377
-        rechunk_t *chunk;
378
-        int size;
379
-        if(redata==NULL
380
-          || chunkno<0 || chunkno>=redata->sizechunks
381
-          || pos<0 || pos>redata->chunks[chunkno]->useddata)
382
-                return(-1); /* sanity check failed */
383
-        chunk=redata->chunks[chunkno];
384
-        if(chunk->useddata==pos)
385
-                return(0); /* all done: already splitted */
386
-        size=redata->chunks[chunkno]->useddata-pos;
387
-        if((chunkno+1)<redata->sizechunks
388
-          && (redata->chunkdatasize-redata->chunks[chunkno+1]->useddata)>=size) {
389
-                redata_chunk_movedata(redata,chunkno,pos,chunkno+1,0,size);
390
-                return(0); /* all done: moved data cleanly to next chunk */
391
-        }
392
-        if(redata_chunk_insertnew(redata,chunkno)!=0)
393
-                return(-1); /* insuf. mem. */
394
-        redata_chunk_movedata(redata,chunkno,pos,chunkno+1,0,size);
395
-        return(0);
396
-}
397
-
398
-int
399
-redata_chunk_fillfromnext(redata_t *redata, int chunkno, int n)
400
-{
401
-        if(redata==NULL || chunkno<0 || (chunkno+1)>=redata->sizechunks
402
-          || (redata->chunkdatasize-redata->chunks[chunkno]->useddata)<n
403
-          || (redata->chunks[chunkno+1]->useddata)<n)
404
-                return(-1); /* sanity check failed */
405
-        return(redata_chunk_movedata(redata,chunkno+1,0,chunkno,redata->chunks[chunkno]->useddata,n));
406
-}
407
-
408
-
409
-int
410
-redata_whatin_refresh(redata_t *redata, int chunkno)
411
-{
412
-        rechunk_t *chunk;
413
-        int nlcount;
414
-        int i,lim;
415
-        if(redata==NULL || chunkno<0 || chunkno>=redata->sizechunks || redata->chunks[chunkno]==NULL)
416
-                return(-1); /* sanity check failed */
417
-        chunk=redata->chunks[chunkno];
418
-        if(chunk->whatin_fresh)
419
-                return(0);
420
-        memset(&(chunk->whatin),0,sizeof(whatin_t));
421
-        nlcount=0;
422
-        for(i=0,lim=chunk->useddata;i<lim;i++) {
423
-                nlcount+=(chunk->data[i]=='\n')?1:0;
424
-        }
425
-        chunk->whatin.nlcount=nlcount;
426
-        chunk->whatin_fresh=1;
427
-        return(0);
428
-}
429
-
430
-
431
-int
432
-redata_fix_nl(redata_t *redata, int chunkno)
433
-{
434
-        /* make sure a line of len<chunksize is entirely inside one chunk (to simplify the syntax highlighting code) */
435
-        if(redata==NULL || chunkno<0 || chunkno>=redata->sizechunks || redata->chunks[chunkno]==NULL)
436
-                return(-1); /* sanity check failed */
437
-        if(chunkno==(redata->sizechunks-1) || redata->chunks[chunkno]->useddata==0 || redata->chunks[chunkno]->data[redata->chunks[chunkno]->useddata-1]=='\n')
438
-                return(0); /* Nothing to do (last chunk, chunk empty or already fixed) */
439
-        rechunk_t *chunk,*nextchunk;
440
-        int linesize, nextlinesize, avail, nextavail;
441
-        unsigned char *ptr,*nextptr;
442
-        chunk=redata->chunks[chunkno];
443
-        nextchunk=redata->chunks[chunkno+1];
444
-        ptr=mymemrchr(chunk->data,'\n',chunk->useddata);
445
-        nextptr=memchr(nextchunk->data,'\n',nextchunk->useddata);
446
-        linesize=(ptr==NULL)?chunk->useddata:(chunk->useddata-(ptr-chunk->data)-1);
447
-        nextlinesize=(nextptr==NULL)?nextchunk->useddata:((nextptr-nextchunk->data)+1);
448
-        avail=redata->chunkdatasize-chunk->useddata;
449
-        nextavail=redata->chunkdatasize-nextchunk->useddata;
450
-        if(avail>=nextlinesize) {
451
-                /* move remaining bytes of line to current chunk */
452
-                redata_chunk_movedata(redata, chunkno+1, 0, chunkno, chunk->useddata, nextlinesize);
453
-        } else if(nextavail>=linesize) {
454
-                /* move incomplete line to next chunk */
455
-                redata_chunk_movedata(redata, chunkno, chunk->useddata-linesize, chunkno+1, 0, linesize);
456
-        } else if(ptr!=NULL) {
457
-                /* only if we have more data in chunkno before this long line */
458
-                int newavail;
459
-                /* create a new empty chunk in-between and put the line there */
460
-                if(redata_chunk_insertnew(redata,chunkno)==-1)
461
-                        return(-1);
462
-                /* move the data; if it doesn't fit, move from the beginning until it is full */
463
-                redata_chunk_movedata(redata, chunkno, chunk->useddata-linesize, chunkno+1, 0, linesize);
464
-                newavail=redata->sizechunks-linesize;
465
-                redata_chunk_movedata(redata, chunkno+2, 0, chunkno+1, linesize, (newavail<nextlinesize)?newavail:nextlinesize);
466
-        }
467
-        return(0);
468
-}
469
-
470
-int
471
-redata_unsaved_exists(redata_t *redata, char *filename)
472
-{
473
-        char unsname[PATH_MAX+1];
474
-        int fd;
475
-        if(redata==NULL || filename==NULL)
476
-                return(-1); /* sanity check failed */
477
-        if((unsaved_genname(filename,unsname,sizeof(unsname)))==NULL)
478
-                return(-1); /* malformed filename */
479
-        if((fd=open(unsname,O_RDONLY))==-1)
480
-                return(-1);
481
-        close(fd),fd=-1;
482
-        return(0);
483
-}
484
-
485
-static int
486
-redata_unsaved_check_gen(redata_t *redata, char *filename)
487
-{
488
-        char unsname[PATH_MAX+1];
489
-        int fd,nread;
490
-        static char header[]={UNSAVEDHEADER};
491
-        char filehash[129],undohash[129],buf[16];
492
-        char fileheader[]={UNSAVEDHEADER};
493
-        if(redata==NULL || filename==NULL)
494
-                return(-1); /* sanity check failed */
495
-        if((unsaved_genname(filename,unsname,sizeof(unsname)))==NULL)
496
-                return(-1); /* malformed filename */
497
-        if(redata_filehash(redata,filename,filehash)!=0)
498
-                return(-1);
499
-        if((fd=open(unsname,O_RDONLY))==-1)
500
-                return(-1);
501
-        memset(fileheader,0,sizeof(fileheader));
502
-        if((nread=read(fd,fileheader,sizeof(fileheader)-1))==-1
503
-          || nread!=(sizeof(fileheader)-1) || memcmp(fileheader,header,sizeof(fileheader))!=0) {
504
-                close(fd),fd=-1;
505
-                return(-1); /* corrupted header */
506
-        }
507
-        if((nread=read(fd,undohash,128))==-1 || nread!=128 || memcmp(undohash,filehash,128)!=0) {
508
-                close(fd),fd=-1;
509
-                return(-1); /* wrong hash */
510
-        }
511
-        if((nread=read(fd,buf,1))==-1 || nread!=1 || *buf!=',') {
512
-                close(fd),fd=-1;
513
-                return(-1); /* wrong hash separator */
514
-        }
515
-        return(fd);
516
-}
517
-
518
-int
519
-redata_unsaved_check(redata_t *redata, char *filename)
520
-{
521
-        int fd;
522
-        if((fd=redata_unsaved_check_gen(redata,filename))==-1)
523
-                return(-1); /* check failed */
524
-        close(fd),fd=-1;
525
-        return(0);
526
-}
527
-
528
-
529
-int
530
-redata_unsaved_unlink(redata_t *redata)
531
-{
532
-        char unsname[PATH_MAX+1];
533
-        if(redata==NULL || redata->filename[0]=='\0')
534
-                return(-1); /* sanity check failed */
535
-        if(redata_unsaved_exists(redata,redata->filename)==-1)
536
-                return(0); /* file not found, nothing to unlink */
537
-        if((unsaved_genname(redata->filename,unsname,sizeof(unsname)))==NULL)
538
-                return(-1); /* malformed filename */
539
-        unlink(unsname);
540
-        return(0);
541
-}
542
-
543
-int
544
-redata_unsaved_trunc(redata_t *redata)
545
-{
546
-        char unsname[PATH_MAX+1];
547
-        static char header[]={UNSAVEDHEADER};
548
-        int n;
549
-        if(redata==NULL || redata->filename[0]=='\0')
550
-                return(-1); /* sanity check failed */
551
-        redata_unsaved_unlink(redata);
552
-        if((unsaved_genname(redata->filename,unsname,sizeof(unsname)))==NULL)
553
-                return(-1); /* malformed filename */
554
-        if(redata->unsavedfd!=-1)
555
-                close(redata->unsavedfd),redata->unsavedfd=-1;
556
-        redata_hash(redata,redata->initialhash);
557
-        redata->unsaved.usedbuf=0;
558
-        if((redata->unsavedfd=open(unsname,O_WRONLY|O_TRUNC|O_CREAT,0644))==-1)
559
-                return(-1); /* couldn't open file for writing */
560
-        if((n=write(redata->unsavedfd,header,sizeof(header)-1))==-1
561
-          || n!=(sizeof(header)-1)
562
-          || (n=write(redata->unsavedfd,redata->initialhash,128))==-1 || n!=128
563
-          || (n=write(redata->unsavedfd,",",1))==-1 || n!=1) {
564
-                close(redata->unsavedfd),redata->unsavedfd=-1;
565
-                unlink(unsname);
566
-                return(-1); /* couldn't write header/hash */
567
-        }
568
-        return(0);
569
-}
570
-
571
-
572
-int
573
-redata_unsaved_loadappend(redata_t *redata)
574
-{
575
-        int fd;
576
-        struct stat statbuf;
577
-        static char header[]={UNSAVEDHEADER};
578
-        long headerhashsize;
579
-        char *newptr;
580
-        long nread,lim;
581
-        char *ptr,*endptr,*aux,*bufptr;
582
-        char actioncode;
583
-        long pos,pos2;
584
-        char endcode;
585
-        int flag_multipart;
586
-        if((fd=redata_unsaved_check_gen(redata,redata->filename))==-1)
587
-                return(-1); /* check failed */
588
-        if(fstat(fd,&statbuf)!=0 || !S_ISREG(statbuf.st_mode)) {
589
-                close(fd),fd=-1;
590
-                return(-1); /* couldn't query size or not regular file */
591
-        }
592
-        headerhashsize=(sizeof(header)-1)+1+128+1;
593
-        /* load unsaved to memory */
594
-        if(redata->unsaved.sizebuf<(statbuf.st_size-headerhashsize)) {
595
-                if((newptr=realloc(redata->unsaved.buf,(statbuf.st_size-headerhashsize)))==NULL) {
596
-                        close(fd),fd=-1;
597
-                        return(-1); /* insuf. mem. */
598
-                }
599
-                redata->unsaved.buf=newptr;
600
-                redata->unsaved.sizebuf=(statbuf.st_size-headerhashsize);
601
-        }
602
-        redata->unsaved.usedbuf=0;
603
-        lim=(statbuf.st_size-headerhashsize);
604
-        for(nread=0;redata->unsaved.usedbuf<lim;redata->unsaved.usedbuf+=nread,nread=0) {
605
-                if((nread=read(fd,redata->unsaved.buf+redata->unsaved.usedbuf,lim-redata->unsaved.usedbuf))<=0) {
606
-                        redata->unsaved.usedbuf=0;
607
-                        close(fd),fd=-1;
608
-                        return(-1); /* short read */
609
-                }
610
-        }
611
-        close(fd),fd=-1;
612
-        /* process unsaved data */
613
-        endptr=redata->unsaved.buf+redata->unsaved.usedbuf;
614
-        for(ptr=redata->unsaved.buf;ptr<endptr;) {
615
-                if((ptr=ptr_getchar(ptr,endptr,&actioncode))==NULL)
616
-                        return(-1); /* no space for action char */
617
-                /* multipart example: A10+$aj$%$% >> insert "aj$" into pos 10 */
618
-                if(actioncode=='A') {
619
-                        ptr=ptr_getlong(ptr,endptr,&pos);
620
-                        do {
621
-                                flag_multipart=0;
622
-                                ptr=ptr_getchar(ptr,endptr,&endcode);
623
-                                if(ptr!=NULL && endcode=='+') {
624
-                                        flag_multipart=1;
625
-                                        ptr=ptr_getchar(ptr,endptr,&endcode);
626
-                                }
627
-                                bufptr=ptr;
628
-                                ptr=ptr_searchendchar(ptr,endptr,endcode,&aux);
629
-                                if(ptr==NULL || pos<0 || pos>redata_getused(redata))
630
-                                        return(-1); /* malformed register */
631
-                                redata_op_add(redata,pos,bufptr,aux-bufptr,NULL);
632
-                                pos+=aux-bufptr;
633
-                        } while(flag_multipart);
634
-                } else if(actioncode=='D') {
635
-                        ptr=ptr_getlong(ptr,endptr,&pos);
636
-                        do {
637
-                                flag_multipart=0;
638
-                                ptr=ptr_getchar(ptr,endptr,&endcode);
639
-                                if(ptr!=NULL && endcode=='+') {
640
-                                        flag_multipart=1;
641
-                                        ptr=ptr_getchar(ptr,endptr,&endcode);
642
-                                }
643
-                                bufptr=ptr;
644
-                                ptr=ptr_searchendchar(ptr,endptr,endcode,&aux);
645
-                                if(ptr==NULL || pos<0 || (pos+(aux-bufptr))>redata_getused(redata))
646
-                                        return(-1); /* malformed register */
647
-                                if(redata_data_compare(redata,pos,bufptr,aux-bufptr)!=0)
648
-                                        return(-1); /* corrupted data */
649
-                                redata_op_del(redata,pos,aux-bufptr,NULL);
650
-                        } while(flag_multipart);
651
-                } else if(actioncode=='M') {
652
-                        ptr=ptr_getlong(ptr,endptr,&pos);
653
-                        ptr+=(ptr!=NULL && ptr<endptr)?1:0;
654
-                        ptr=ptr_getlong(ptr,endptr,&pos2);
655
-                        do {
656
-                                flag_multipart=0;
657
-                                ptr=ptr_getchar(ptr,endptr,&endcode);
658
-                                if(ptr!=NULL && endcode=='+') {
659
-                                        flag_multipart=1;
660
-                                        ptr=ptr_getchar(ptr,endptr,&endcode);
661
-                                }
662
-                                bufptr=ptr;
663
-                                ptr=ptr_searchendchar(ptr,endptr,endcode,&aux);
664
-                                if(ptr==NULL
665
-                                  || pos<0 || (pos+(aux-bufptr))>redata_getused(redata)
666
-                                  || pos2<0 || pos2>redata_getused(redata)
667
-                                  || ((aux-bufptr)>0 && pos2>=pos && pos2<(pos+(aux-bufptr)))
668
-                                  ) {
669
-                                        return(-1); /* malformed register */
670
-                                }
671
-                                if(redata_data_compare(redata,pos,bufptr,aux-bufptr)!=0)
672
-                                        return(-1); /* corrupted data */
673
-                                redata_op_move(redata,pos,(aux-bufptr),pos2,NULL);
674
-                                pos=(pos<pos2)?pos:(pos+(aux-bufptr));
675
-                                pos2=pos2+(aux-bufptr);
676
-                        } while(flag_multipart);
677
-                } else {
678
-                        return(-1); /* corrupted undobuf */
679
-                }
680
-        }
681
-        return(-1);
682
-}
683
-
684
-
685
-int
686
-redata_unsaved_add(redata_t *redata, undostack_t *stack, int undono)
687
-{
688
-        char sep;
689
-        undo_t *undo;
690
-        char *sepend,*ptr,*endptr;
691
-        char *buf;
692
-        int k;
693
-        int maxsize,newsize;
694
-        char posbuf[128];
695
-        if(redata==NULL
696
-          || (stack!=&(redata->undostack) && stack!=&(redata->redostack))
697
-          || undono<0 || undono>=stack->usedundo)
698
-                return(-1); /* sanity check failed */
699
-        /* syntax (see loadappend): A<pos><+?><sep><text><sep>[<+?><sep><text><sep>[...]] */
700
-        undo=stack->undo+undono;
701
-        if(undo->type!='A' && undo->type!='D' && undo->type!='M')
702
-                return(-1); /* unrecognized undo type */
703
-        for(k=0,maxsize=0,buf=NULL;k<2;k++,maxsize=0) {
704
-                ptr=stack->buf+undo->off;
705
-                endptr=ptr+undo->len;
706
-                if(k!=0)
707
-                        buf[maxsize]=undo->type;
708
-                maxsize++;
709
-                snprintf(posbuf,sizeof(posbuf),"%li",undo->posorig);
710
-                posbuf[sizeof(posbuf)-1]='\0';
711
-                if(k!=0)
712
-                        strcpy(buf+maxsize,posbuf);
713
-                maxsize+=strlen(posbuf);
714
-                if(undo->type=='M') {
715
-                        snprintf(posbuf,sizeof(posbuf),",%li",undo->posdest);
716
-                        posbuf[sizeof(posbuf)-1]='\0';
717
-                        if(k!=0)
718
-                                strcpy(buf+maxsize,posbuf);
719
-                        maxsize+=strlen(posbuf);
720
-                }
721
-                while(ptr<endptr) {
722
-                        sep=sep_select(ptr,endptr-ptr,&sepend);
723
-                        if(sepend!=endptr) {
724
-                                if(k!=0)
725
-                                        buf[maxsize]='+';
726
-                                maxsize++;
727
-                        }
728
-                        if(k!=0)
729
-                                buf[maxsize]=sep;
730
-                        maxsize++;
731
-                        if(k!=0)
732
-                                memcpy(buf+maxsize,ptr,sepend-ptr);
733
-                        maxsize+=sepend-ptr;
734
-                        if(k!=0)
735
-                                buf[maxsize]=sep;
736
-                        maxsize++;
737
-                        ptr=sepend;
738
-                }
739
-                if(k==0) {
740
-                        /* get mem */
741
-                        if((redata->unsaved.sizebuf-redata->unsaved.sizebuf)<maxsize) {
742
-                                newsize=(redata->unsaved.sizebuf+maxsize+UNDOGROWSIZE-1)/UNDOGROWSIZE;
743
-                                newsize*=UNDOGROWSIZE;
744
-                                if((buf=realloc(redata->unsaved.buf,newsize))==NULL)
745
-                                        return(-1); /* insuf. mem. */
746
-                                redata->unsaved.buf=buf;
747
-                                redata->unsaved.sizebuf=newsize;
748
-                        }
749
-                        buf=redata->unsaved.buf+redata->unsaved.usedbuf;
750
-                }
751
-        }
752
-        return(0);
753
-}
754
-
755
-int
756
-redata_unsaved_unadd(redata_t *redata, undostack_t *stack, int undono)
757
-{
758
-        /* adds to unsaved the inverse operation to the one specified in the undo */
759
-        char sep;
760
-        undo_t *undo;
761
-        char *sepend,*ptr,*endptr;
762
-        char *buf;
763
-        int k;
764
-        int maxsize,newsize;
765
-        char posbuf[128];
766
-        if(redata==NULL
767
-          || (stack!=&(redata->undostack) && stack!=&(redata->redostack))
768
-          || undono<0 || undono>=stack->usedundo)
769
-                return(-1); /* sanity check failed */
770
-        /* syntax (see loadappend): A<pos><+?><sep><text><sep>[<+?><sep><text><sep>[...]] */
771
-        undo=stack->undo+undono;
772
-        if(undo->type!='A' && undo->type!='D' && undo->type!='M')
773
-                return(-1); /* unrecognized undo type */
774
-        for(k=0,maxsize=0,buf=NULL;k<2;k++,maxsize=0) {
775
-                ptr=stack->buf+undo->off;
776
-                endptr=ptr+undo->len;
777
-                if(k!=0)
778
-                        buf[maxsize]=(undo->type=='A')?'D':(undo->type=='D')?'A':undo->type;
779
-                maxsize++;
780
-                if(undo->type=='A' || undo->type=='D')
781
-                        snprintf(posbuf,sizeof(posbuf),"%li",undo->posorig);
782
-                else
783
-                        snprintf(posbuf,sizeof(posbuf),"%li",(undo->posorig<undo->posdest)?undo->posdest-undo->len:undo->posdest);
784
-                posbuf[sizeof(posbuf)-1]='\0';
785
-                if(k!=0)
786
-                        strcpy(buf+maxsize,posbuf);
787
-                maxsize+=strlen(posbuf);
788
-                if(undo->type=='M') {
789
-                        snprintf(posbuf,sizeof(posbuf),",%li",(undo->posorig<undo->posdest)?undo->posorig:undo->posorig+undo->len);
790
-                        posbuf[sizeof(posbuf)-1]='\0';
791
-                        if(k!=0)
792
-                                strcpy(buf+maxsize,posbuf);
793
-                        maxsize+=strlen(posbuf);
794
-                }
795
-                while(ptr<endptr) {
796
-                        sep=sep_select(ptr,endptr-ptr,&sepend);
797
-                        if(sepend!=endptr) {
798
-                                if(k!=0)
799
-                                        buf[maxsize]='+';
800
-                                maxsize++;
801
-                        }
802
-                        if(k!=0)
803
-                                buf[maxsize]=sep;
804
-                        maxsize++;
805
-                        if(k!=0)
806
-                                memcpy(buf+maxsize,ptr,sepend-ptr);
807
-                        maxsize+=sepend-ptr;
808
-                        if(k!=0)
809
-                                buf[maxsize]=sep;
810
-                        maxsize++;
811
-                        ptr=sepend;
812
-                }
813
-                if(k==0) {
814
-                        /* get mem */
815
-                        if((redata->unsaved.sizebuf-redata->unsaved.sizebuf)<maxsize) {
816
-                                newsize=(redata->unsaved.sizebuf+maxsize+UNDOGROWSIZE-1)/UNDOGROWSIZE;
817
-                                newsize*=UNDOGROWSIZE;
818
-                                if((buf=realloc(redata->unsaved.buf,newsize))==NULL)
819
-                                        return(-1); /* insuf. mem. */
820
-                                redata->unsaved.buf=buf;
821
-                                redata->unsaved.sizebuf=newsize;
822
-                        }
823
-                        buf=redata->unsaved.buf+redata->unsaved.usedbuf;
824
-                }
825
-        }
826
-        return(0);
827
-}
828
-
829
-int
830
-redata_unsaved_commit(redata_t *redata)
831
-{
832
-        int n,nwritten;
833
-        char unsname[PATH_MAX+1];
834
-        if(redata==NULL || redata->unsavedfd==-1)
835
-                return(-1);
836
-        for(nwritten=0;nwritten<redata->unsaved.usedbuf;nwritten+=n) {
837
-                if((n=write(redata->unsavedfd,redata->unsaved.buf+nwritten,redata->unsaved.usedbuf-nwritten))<0) {
838
-                        close(redata->unsavedfd),redata->unsavedfd=-1;
839
-                        if((unsaved_genname(redata->filename,unsname,sizeof(unsname)))!=NULL)
840
-                                unlink(unsname); /* a corrupted unsaved is of no use, delete it */
841
-                        return(-1); /* error writing */
842
-                }
843
-        }
844
-        redata->unsaved.usedbuf=0;
845
-        return(0);
846
-}
847
-
848
-
849
-int
850
-redata_load(redata_t *redata, char *filename, int use_unsaved)
851
-{
852
-        int fd,nread,totalread;
853
-        int chunkno, avail;
854
-        struct stat statbuf;
855
-        rechunk_t *chunk;
856
-        if(redata==NULL || filename==NULL)
857
-                return(-1); /* sanity check failed */
858
-        redata_wipe(redata);
859
-        strncpy(redata->filename,filename,sizeof(redata->filename));
860
-        redata->filename[sizeof(redata->filename)-1]='\0';
861
-        if((fd=open(filename,O_RDONLY))==-1 || fstat(fd,&statbuf)!=0 || !S_ISREG(statbuf.st_mode)) {
862
-                if(fd!=-1)
863
-                        close(fd),fd=-1;
864
-                return(-1); /* file not found, couldn't query size or not regular file */
865
-        }
866
-        /* preallocate 10% more than needed */
867
-        if(redata_preallocate(redata,statbuf.st_size+(statbuf.st_size/10)+1 )) {
868
-                close(fd),fd=-1;
869
-                return(-1); /* insuf. mem. */
870
-        }
871
-        for(totalread=0,chunkno=0,nread=0;totalread<statbuf.st_size;totalread+=nread,nread=0) {
872
-                if(chunkno>=redata->sizechunks || redata->chunks[chunkno]==NULL) {
873
-                        /* alloc another chunk */
874
-                        if(redata_preallocate(redata,redata_getsize(redata)+redata->chunkdatasize)==-1 ||
875
-                                chunkno>=redata->sizechunks || redata->chunks[chunkno]==NULL) {
876
-                                close(fd),fd=-1;
877
-                                fprintf(stderr,"redata_load: INTERNAL ERROR\n");
878
-                                return(-2); /* internal error */
879
-                        }
880
-                }
881
-                chunk=redata->chunks[chunkno];
882
-                /* leave 10% free on each chunk */
883
-                avail=(redata->chunkdatasize-redata->chunkdatasize/10)-chunk->useddata;
884
-                avail=(avail<0)?0:avail;
885
-                avail=((totalread+avail)>statbuf.st_size)?statbuf.st_size-totalread:avail;
886
-                if(avail==0) {
887
-                        chunkno++; /* full, try next */
888
-                        continue;
889
-                }
890
-                if((nread=read(fd,chunk->data+chunk->useddata,avail))<=0) {
891
-                        close(fd),fd=-1;
892
-                        return(-1); /* short read */
893
-                }
894
-                chunk->useddata+=nread;
895
-                redata->available-=nread;
896
-        }
897
-        close(fd),fd=-1;
898
-        for(chunkno=0;chunkno<redata->sizechunks;chunkno++)
899
-                redata_fix_nl(redata,chunkno);
900
-        for(chunkno=0;chunkno<redata->sizechunks;chunkno++)
901
-                redata_whatin_refresh(redata,chunkno);
902
-        /* unsaved */
903
-        if(use_unsaved) {
904
-                /* apply missing changes and append new changes to unsaved */
905
-                redata_hash(redata,redata->initialhash);
906
-                redata_unsaved_loadappend(redata);
907
-        } else {
908
-                /* nuke existing unsaved (if exists) and prepare new unsaved */
909
-                /* _trunc() fills itself redata->initialhash */
910
-                redata_unsaved_trunc(redata);
911
-        }
912
-        /* all done */
913
-        return(0);
914
-}
915
-
916
-int
917
-redata_save(redata_t *redata, char *filename)
918
-{
919
-        int fd;
920
-        int i,n;
921
-        char tmpfile[PATH_MAX+1];
922
-        if(redata==NULL || filename==NULL)
923
-                return(-1); /* sanity check failed */
924
-        if((securesave_genname(redata->filename,tmpfile,sizeof(tmpfile)))==NULL)
925
-                return(-1); /* malformed filename */
926
-        if((fd=open(tmpfile,O_WRONLY|O_TRUNC|O_CREAT,0644))==-1)
927
-                return(-1); /* couldn't open file for writing */
928
-        for(i=0;i<redata->sizechunks;i++) {
929
-                if(redata->chunks[i]->useddata==0)
930
-                        continue;
931
-                if((n=write(fd,redata->chunks[i]->data,redata->chunks[i]->useddata))==-1 || n!=redata->chunks[i]->useddata) {
932
-                        close(fd),fd=-1;
933
-                        unlink(tmpfile);
934
-                        return(-1); /* short write */
935
-                }
936
-        }
937
-        close(fd),fd=-1;
938
-        if(rename(tmpfile,filename)!=0) {
939
-                unlink(tmpfile);
940
-                return(-1); /* couldn't overwrite old file */
941
-        }
942
-        redata_unsaved_unlink(redata);
943
-        strncpy(redata->filename,filename,sizeof(redata->filename));
944
-        redata->filename[sizeof(redata->filename)-1]='\0';
945
-        redata_unsaved_trunc(redata);
946
-        return(0);
947
-}
948
-
949
-int
950
-redata_undobuf_reserve(redata_t *redata, undostack_t *stack, int minavail)
951
-{
952
-        int unused;
953
-        int newsize;
954
-        char *newptr;
955
-        if(redata==NULL || minavail<0
956
-          || (stack!=&(redata->undostack) && stack!=&(redata->redostack)))
957
-                return(-1); /* sanity check failed */
958
-        unused=stack->sizebuf-stack->usedbuf;
959
-        if(unused<minavail) {
960
-                newsize=(stack->sizebuf+minavail+UNDOGROWSIZE-1)/UNDOGROWSIZE;
961
-                newsize*=UNDOGROWSIZE;
962
-                if((newptr=realloc(stack->buf,newsize))==NULL)
963
-                        return(-1); /* insuf. mem. */
964
-                stack->buf=newptr;
965
-                stack->sizebuf=newsize;
966
-        }
967
-        return(0);
968
-}
969
-
970
-undo_t *
971
-redata_undo_new(redata_t *redata, undostack_t *stack, char type)
972
-{
973
-        int newsize;
974
-        undo_t *newptr,*undo;
975
-        if(redata==NULL
976
-          || (stack!=&(redata->undostack) && stack!=&(redata->redostack)))
977
-                return(NULL); /* sanity check failed */
978
-        if(stack->sizeundo==stack->usedundo) {
979
-                newsize=(stack->sizeundo+1+UNDOBLOCK-1)/UNDOBLOCK;
980
-                newsize*=UNDOBLOCK;
981
-                if((newptr=realloc(stack->undo,sizeof(undo_t)*newsize))==NULL)
982
-                        return(NULL);
983
-                stack->undo=newptr;
984
-                memset(stack->undo+stack->sizeundo,0,sizeof(undo_t)*(newsize-stack->sizeundo));
985
-                stack->sizeundo=newsize;
986
-        }
987
-        undo=stack->undo+stack->usedundo;
988
-        stack->usedundo++;
989
-        undo->type=type;
990
-        undo->off=stack->usedbuf;
991
-        undo->len=0;
992
-        return(undo);
993
-}
994
-
995
-undo_t *
996
-redata_undo_newfromchunks(redata_t *redata, undostack_t *stack, char type, int pos1, int len)
997
-{
998
-        int startpos,endpos;
999
-        long startoff,endoff;
1000
-        undo_t *undo;
1001
-        int k;
1002
-        long used;
1003
-        long copyfrom,copysize;
1004
-        if(redata==NULL || len<=0
1005
-          || (stack!=&(redata->undostack) && stack!=&(redata->redostack)))
1006
-                return(NULL); /* sanity check failed */
1007
-        if(redata_getposptr(redata,pos1,&startpos,&startoff)==-1 ||
1008
-          redata_getposptr(redata,pos1+len,&endpos,&endoff)==-1) {
1009
-                return(NULL); /* chunk data out of bounds */
1010
-        }
1011
-        if(redata_undobuf_reserve(redata,stack,len)!=0)
1012
-                return(NULL); /* insuf. mem. */
1013
-        if((undo=redata_undo_new(redata,stack,type))==NULL)
1014
-                return(NULL); /* insuf. mem. */
1015
-        undo->off=stack->usedbuf;
1016
-        /* copy contents */
1017
-        for(k=startpos,used=0;k<=endpos;k++) {
1018
-                if(k==startpos && k==endpos) {
1019
-                        copyfrom=startoff;
1020
-                        copysize=endoff-startoff;
1021
-                } else if(k==startpos) {
1022
-                        copyfrom=startoff;
1023
-                        copysize=redata->chunks[k]->useddata-startoff;
1024
-                } else if(k==endpos) {
1025
-                        copyfrom=0;
1026
-                        copysize=endoff;
1027
-                } else {
1028
-                        copyfrom=0;
1029
-                        copysize=redata->chunks[k]->useddata;
1030
-                }
1031
-                memcpy(stack->buf+stack->usedbuf,redata->chunks[k]->data+copyfrom,copysize);
1032
-                stack->usedbuf+=copysize;
1033
-                used+=copysize;
1034
-        }
1035
-        undo->len=used;
1036
-        return(undo);
1037
-}
1038
-
1039
-undo_t *
1040
-redata_undo_newfrombuf(redata_t *redata, undostack_t *stack, char type, char *buf, int buflen)
1041
-{
1042
-        undo_t *undo;
1043
-        if(redata==NULL || buflen<=0
1044
-          || (stack!=&(redata->undostack) && stack!=&(redata->redostack)))
1045
-                return(NULL); /* sanity check failed */
1046
-        if(redata_undobuf_reserve(redata,stack, buflen)!=0)
1047
-                return(NULL); /* insuf. mem. */
1048
-        if((undo=redata_undo_new(redata,stack,  type))==NULL)
1049
-                return(NULL); /* insuf. mem. */
1050
-        undo->off=stack->usedbuf;
1051
-        memcpy(stack->buf+stack->usedbuf,buf,buflen);
1052
-        stack->usedbuf+=buflen;
1053
-        undo->len=buflen;
1054
-        return(undo);
1055
-}
1056
-
1057
-int
1058
-redata_undo_movelast(redata_t *redata, undostack_t *from, undostack_t *to)
1059
-{
1060
-        undo_t *undofrom;
1061
-        undo_t *undoto;
1062
-        if(redata==NULL || from==to
1063
-          || (from!=&(redata->undostack) && from!=&(redata->redostack))
1064
-          || (to!=&(redata->undostack) && to!=&(redata->redostack))
1065
-          || from->usedundo<1)
1066
-                return(-1); /* sanity check failed */
1067
-        undofrom=from->undo+from->usedundo-1;
1068
-        if((undoto=redata_undo_newfrombuf(redata,to,undofrom->type,from->buf+undofrom->off,undofrom->len))==NULL)
1069
-                return(-1); /* insuf. mem. */
1070
-        undoto->posorig=undofrom->posorig;
1071
-        undoto->posdest=undofrom->posdest;
1072
-        memcpy(undoto->prehash,undofrom->prehash,sizeof(undoto->prehash));
1073
-        memcpy(undoto->posthash,undofrom->posthash,sizeof(undoto->posthash));
1074
-        redata_undo_removelast(redata, from);
1075
-        return(0);
1076
-}
1077
-
1078
-int
1079
-redata_undo_removelast(redata_t *redata, undostack_t *stack)
1080
-{
1081
-        undo_t *undo;
1082
-        if(redata==NULL
1083
-          || (stack!=&(redata->undostack) && stack!=&(redata->redostack))
1084
-          || stack->usedundo<1)
1085
-                return(-1); /* sanity check failed */
1086
-        undo=stack->undo+stack->usedundo-1;
1087
-        stack->usedbuf-=undo->len;
1088
-        memset(undo,0,sizeof(undo_t));
1089
-        stack->usedundo--;
1090
-        return(0);
1091
-}
1092
-
1093
-int
1094
-redata_undo_wipe(redata_t *redata, undostack_t *stack)
1095
-{
1096
-        if(redata==NULL
1097
-          || (stack!=&(redata->undostack) && stack!=&(redata->redostack)))
1098
-                return(-1); /* sanity check failed */
1099
-        memset(stack->undo,0,sizeof(undo_t)*stack->usedundo);
1100
-        stack->usedundo=0;
1101
-        memset(stack->buf,0,stack->usedbuf);
1102
-        stack->usedbuf=0;
1103
-        return(0);
1104
-}
1105
-
1106
-int
1107
-redata_undo_inactivatelast(redata_t *redata, undostack_t *stack)
1108
-{
1109
-        if(redata==NULL
1110
-          || (stack!=&(redata->undostack) && stack!=&(redata->redostack)))
1111
-                return(-1); /* sanity check failed */
1112
-        if(stack->usedundo==0)
1113
-                return(-1);
1114
-        stack->usedundo--;
1115
-        stack->usedbuf-=stack->undo[stack->usedundo].len;
1116
-        return(0);
1117
-}
1118
-
1119
-int
1120
-redata_undo_reactivatelast(redata_t *redata, undostack_t *stack)
1121
-{
1122
-        if(redata==NULL
1123
-          || (stack!=&(redata->undostack) && stack!=&(redata->redostack)))
1124
-                return(-1); /* sanity check failed */
1125
-        if(stack->usedundo==stack->sizeundo)
1126
-                return(-1);
1127
-        stack->usedbuf+=stack->undo[stack->usedundo].len;
1128
-        stack->usedundo++;
1129
-        return(0);
1130
-}
1131
-
1132
-
1133
-int
1134
-redata_op_add(redata_t *redata, long insertpos, char *buf, long buflen, undostack_t *fromhere)
1135
-{
1136
-        int chunkno;
1137
-        long pos;
1138
-        undo_t *undo;
1139
-        rechunk_t *chunk,*nextchunk;
1140
-        long avail,nextavail;
1141
-        int i;
1142
-        int needed;
1143
-        char *ptr;
1144
-        if(redata==NULL || buf==NULL || buflen<0 || insertpos<0
1145
-          || insertpos>redata_getused(redata)
1146
-          || (fromhere!=NULL && (fromhere!=&(redata->undostack) && fromhere!=&(redata->redostack))))
1147
-                return(-1); /* sanity check failed */
1148
-        if(redata_getposptr(redata,insertpos,&chunkno,&pos)==-1)
1149
-                return(-1); /* invalid pos */
1150
-        if(fromhere!=&(redata->undostack)) {
1151
-                if((undo=redata_undo_newfrombuf(redata,&(redata->undostack),'A',buf,buflen))==NULL)
1152
-                        return(-1); /* couldn't create undo struct */
1153
-                redata_hash(redata,undo->prehash);
1154
-        } else {
1155
-                undo=NULL;
1156
-        }
1157
-        chunk=redata->chunks[chunkno];
1158
-        avail=redata->chunkdatasize-chunk->useddata;
1159
-        nextchunk=((chunkno+1)<redata->sizechunks)?redata->chunks[chunkno+1]:NULL;
1160
-        nextavail=(nextchunk==NULL)?0:redata->chunkdatasize-nextchunk->useddata;
1161
-        if(avail>=buflen) {
1162
-                /* fits in current chunk */
1163
-                redata_chunk_insertdata(redata,chunkno,pos,buf,buflen);
1164
-                redata_fix_nl(redata,chunkno);
1165
-                nextchunk=chunk;
1166
-        } else if((avail+nextavail)>=buflen) {
1167
-                /* part fits in current chunk, part in next chunk */
1168
-                int bothering;
1169
-                bothering=chunk->useddata-pos;
1170
-                bothering=(bothering>nextavail)?nextavail:bothering;
1171
-                redata_chunk_movedata(redata,chunkno,chunk->useddata-bothering,chunkno+1,0,bothering);
1172
-                avail=redata->chunkdatasize-chunk->useddata;
1173
-                avail=(avail>buflen)?buflen:avail;
1174
-                redata_chunk_insertdata(redata,chunkno,pos,buf,avail);
1175
-                redata_chunk_insertdata(redata,chunkno+1,0,buf+avail,buflen-avail);
1176
-        } else {
1177
-                /* will need to add more chunks */
1178
-                needed=(buflen+redata->chunkdatasize-1)/redata->chunkdatasize;
1179
-                needed*=redata->chunkdatasize;
1180
-                needed+=(chunk->useddata-pos);
1181
-                if(redata_preallocate(redata,redata_getsize(redata)+needed)!=0) {
1182
-                        if(undo!=NULL) {
1183
-                                redata->undostack.usedundo--;
1184
-                                redata->undostack.usedbuf-=buflen;
1185
-                                memset(undo,0,sizeof(undo_t));
1186
-                        }
1187
-                        return(-1); /* insuf. mem. */
1188
-                }
1189
-                redata_chunk_insertnew(redata,chunkno);
1190
-                redata_chunk_movedata(redata,chunkno,pos,chunkno+1,0,chunk->useddata-pos);
1191
-                nextchunk=redata->chunks[chunkno+1];
1192
-                avail=redata->chunkdatasize-chunk->useddata;
1193
-                avail=(avail>buflen)?buflen:avail;
1194
-                redata_chunk_insertdata(redata,chunkno,chunk->useddata,buf,avail);
1195
-                for(ptr=buf+avail,i=chunkno;(ptr-buf)<buflen;i++,ptr+=avail) {
1196
-                        redata_chunk_insertnew(redata,i);
1197
-                        avail=redata->chunkdatasize-redata->chunks[i+1]->useddata;
1198
-                        avail=(avail>(buflen-(ptr-buf)))?(buflen-(ptr-buf)):avail;
1199
-                        redata_chunk_insertdata(redata,i+1,0,ptr,avail);
1200
-
1201
-                }
1202
-        }
1203
-        /* fix nl until nextchunk (...fix_nl can insert chunks) */
1204
-        for(i=chunkno;i<redata->sizechunks;i++) {
1205
-                redata_fix_nl(redata,i);
1206
-                if(redata->chunks[i]==nextchunk)
1207
-                        break;
1208
-        }
1209
-        /* activate undo */
1210
-        if(undo!=NULL) {
1211
-                /* new or from redo stack */
1212
-                undo->posorig=undo->posdest=insertpos;
1213
-                redata_hash(redata,undo->posthash);
1214
-                if(fromhere==&(redata->redostack))
1215
-                        redata_undo_removelast(redata,&(redata->redostack));
1216
-                else
1217
-                        redata_undo_wipe(redata,&(redata->redostack));
1218
-        } else {
1219
-                /* from undo stack */
1220
-                redata_undo_movelast(redata,&(redata->undostack),&(redata->redostack));
1221
-        }
1222
-        /* add to unsaved */
1223
-        redata_unsaved_add(redata,&(redata->undostack),redata->undostack.usedundo-1);
1224
-        /* compact if needed */
1225
-        if(redata_getsize(redata)>(redata->chunkdatasize) && redata_getavailable(redata)>(redata_getsize(redata)/2))
1226
-                redata_compact(redata);
1227
-        return(0);
1228
-}
1229
-
1230
-int
1231
-redata_op_del(redata_t *redata, long delpos, long size, undostack_t *fromhere)
1232
-{
1233
-        int chunkno,curchunk;
1234
-        long pos;
1235
-        undo_t *undo;
1236
-        rechunk_t *chunk;
1237
-        long ndel;
1238
-        long curpos,curdel;
1239
-        if(redata==NULL || size<0
1240
-          || delpos<0
1241
-          || (delpos+size)>redata_getused(redata)
1242
-          || (fromhere!=NULL && (fromhere!=&(redata->undostack) && fromhere!=&(redata->redostack))))
1243
-                return(-1); /* sanity check failed */
1244
-        if(redata_getposptr(redata,delpos,&chunkno,&pos)==-1)
1245
-                return(-1); /* invalid pos */
1246
-        if(fromhere!=&(redata->undostack)) {
1247
-                if((undo=redata_undo_newfromchunks(redata,&(redata->undostack),'D',delpos,size))==NULL)
1248
-                        return(-1); /* couldn't create undo struct */
1249
-                redata_hash(redata,undo->prehash);
1250
-        } else {
1251
-                undo=NULL;
1252
-        }
1253
-        for(curchunk=chunkno,ndel=0;ndel<size;curchunk++) {
1254
-                curpos=(curchunk==chunkno)?pos:0;
1255
-                curdel=redata->chunks[curchunk]->useddata-curpos;
1256
-                curdel=(curdel>(size-ndel))?(size-ndel):curdel;
1257
-                redata_chunk_deletedata(redata,curchunk,curpos,curdel);
1258
-                ndel+=curdel;
1259
-        }
1260
-        /* fix nl and delete unused chunks */
1261
-        for(curchunk--;curchunk>=chunkno;curchunk--) {
1262
-                chunk=redata->chunks[curchunk];
1263
-                if(chunk->useddata==0) {
1264
-                        /* move this chunk to the end */
1265
-                        redata_chunk_deletechunk(redata,curchunk);
1266
-                } else
1267
-                        redata_fix_nl(redata,curchunk);
1268
-        }
1269
-        /* activate undo */
1270
-        if(undo!=NULL) {
1271
-                /* new or from redo stack */
1272
-                undo->posorig=undo->posdest=delpos;
1273
-                redata_hash(redata,undo->posthash);
1274
-                if(fromhere==&(redata->redostack))
1275
-                        redata_undo_removelast(redata,&(redata->redostack));
1276
-                else
1277
-                        redata_undo_wipe(redata,&(redata->redostack));
1278
-        } else {
1279
-                /* from undo stack */
1280
-                redata_undo_movelast(redata,&(redata->undostack),&(redata->redostack));
1281
-        }
1282
-        /* add to unsaved */
1283
-        redata_unsaved_add(redata,&(redata->undostack),redata->undostack.usedundo-1);
1284
-        /* compact if needed */
1285
-        if(redata_getsize(redata)>(redata->chunkdatasize) && redata_getavailable(redata)>(redata_getsize(redata)/2))
1286
-                redata_compact(redata);
1287
-        return(0);
1288
-}
1289
-
1290
-int
1291
-redata_op_move(redata_t *redata, long posorig, long size, long posdest, undostack_t *fromhere)
1292
-{
1293
-        int chunkno,dchunkno,curchunk;
1294
-        long pos,dpos;
1295
-        undo_t *undo;
1296
-        rechunk_t *chunk;
1297
-        if(redata==NULL || size<0
1298
-          || posorig<0
1299
-          || (posorig+size)>redata_getused(redata)
1300
-          || posdest<0
1301
-          || (posdest>=posorig && posdest<(posorig+size))
1302
-          || (fromhere!=NULL && (fromhere!=&(redata->undostack) && fromhere!=&(redata->redostack))))
1303
-                return(-1); /* sanity check failed */
1304
-        if(redata_getposptr(redata,posorig,&chunkno,&pos)==-1)
1305
-                return(-1); /* invalid pos */
1306
-        if(redata_getposptr(redata,posdest,&dchunkno,&dpos)==-1)
1307
-                return(-1); /* invalid pos */
1308
-        if(fromhere!=&(redata->undostack)) {
1309
-                if((undo=redata_undo_newfromchunks(redata,&(redata->undostack),'M',posorig,size))==NULL)
1310
-                        return(-1); /* couldn't create undo struct */
1311
-                /* inactivate the undo so we are able to use return(-1) without removing it */
1312
-                redata_undo_inactivatelast(redata,&(redata->undostack));
1313
-                redata_hash(redata,undo->prehash);
1314
-        } else {
1315
-                undo=NULL;
1316
-        }
1317
-        if((pos+size)<=redata->chunks[chunkno]->useddata
1318
-          && (chunkno==dchunkno || (redata->chunkdatasize-redata->chunks[dchunkno]->useddata)>=size)) {
1319
-                /* trivial case: (all the data is in the same chunk) AND (it is intra-chunk move or destination chunk has enough avail. space) */
1320
-                redata_chunk_movedata(redata, chunkno, pos, dchunkno, dpos, size);
1321
-        } else {
1322
-                /* data spans several chunks, no space on dest, etc: do it the hard way */
1323
-                /* separate the selected data into its own chunk(s) */
1324
-                /* lower positions have to make the boundary first (or risk undoing it with next create boundary) */
1325
-                if(posdest<posorig) {
1326
-                        /* make a chunk boundary in posdest */
1327
-                        if(redata_getposptr(redata,posdest,&chunkno,&pos)==-1
1328
-                          || redata_chunk_splithere(redata,chunkno,pos)!=0)
1329
-                                return(-1); /* invalid pos or insuf. mem */
1330
-                }
1331
-                /* make a chunk boundary in posorig and in posorig+size */
1332
-                if(redata_getposptr(redata,posorig,&chunkno,&pos)==-1
1333
-                  || redata_chunk_splithere(redata,chunkno,pos)!=0)
1334
-                        return(-1); /* invalid pos or insuf. mem */
1335
-                if(redata_getposptr(redata,posorig+size,&chunkno,&pos)==-1
1336
-                  || redata_chunk_splithere(redata,chunkno,pos)!=0)
1337
-                        return(-1); /* invalid pos or insuf. mem */
1338
-                if(posdest>posorig) {
1339
-                        /* make a chunk boundary in posdest */
1340
-                        if(redata_getposptr(redata,posdest,&chunkno,&pos)==-1
1341
-                          || redata_chunk_splithere(redata,chunkno,pos)!=0)
1342
-                                return(-1); /* invalid pos or insuf. mem */
1343
-                }
1344
-                /* reorder the chunks */
1345
-                {
1346
-                        int schunkno;
1347
-                        long spos;
1348
-                        if(redata_getposptr(redata,posorig,&chunkno,&pos)==-1)
1349
-                                return(-1); /* invalid pos or insuf. mem */
1350
-                        if(redata_getposptr(redata,posorig+size,&schunkno,&spos)==-1)
1351
-                                return(-1); /* invalid pos or insuf. mem */
1352
-                        if(redata_getposptr(redata,posdest,&dchunkno,&dpos)==-1)
1353
-                                return(-1); /* invalid pos or insuf. mem */
1354
-                        if(pos!=0)
1355
-                                chunkno++;
1356
-                        if(spos!=0)
1357
-                                schunkno++;
1358
-                        if(dpos!=0)
1359
-                                dchunkno++;
1360
-                        if(chunkno<0 || schunkno<0 || dchunkno<0
1361
-                          || chunkno>=redata->sizechunks || schunkno>=redata->sizechunks || dchunkno>=redata->sizechunks)
1362
-                                return(-1); /* ERROR: INTERNAL ERROR */
1363
-                        /* reorder inplace inverting the bytes (as in flipping a image) */
1364
-                        if(chunkno<dchunkno) {
1365
-                                meminvert(redata->chunks+chunkno,redata->chunks+dchunkno);
1366
-                                meminvert(redata->chunks+dchunkno-(schunkno-chunkno),redata->chunks+dchunkno);
1367
-                                meminvert(redata->chunks+chunkno,redata->chunks+dchunkno-(schunkno-chunkno));
1368
-                        } else {
1369
-                                meminvert(redata->chunks+dchunkno,redata->chunks+schunkno);
1370
-                                meminvert(redata->chunks+dchunkno,redata->chunks+dchunkno+(schunkno-chunkno));
1371
-                                meminvert(redata->chunks+dchunkno+(schunkno-chunkno),redata->chunks+schunkno);
1372
-                        }
1373
-                }
1374
-        }
1375
-        /* fix nl and delete unused chunks */
1376
-        if(posorig<posdest) {
1377
-              if(redata_getposptr(redata,posorig,&chunkno,&pos)==-1)
1378
-                      return(-1); /* invalid pos */
1379
-              if(redata_getposptr(redata,posdest,&dchunkno,&dpos)==-1)
1380
-                      return(-1); /* invalid pos */
1381
-        } else { /* posorig>posdest */
1382
-              if(redata_getposptr(redata,posdest,&chunkno,&pos)==-1)
1383
-                      return(-1); /* invalid pos */
1384
-              if(redata_getposptr(redata,posorig+size,&dchunkno,&dpos)==-1)
1385
-                      return(-1); /* invalid pos */
1386
-        }
1387
-        for(curchunk=dchunkno;curchunk>=chunkno;curchunk--) {
1388
-                chunk=redata->chunks[curchunk];
1389
-                if(chunk->useddata==0) {
1390
-                        /* move this chunk to the end */
1391
-                        redata_chunk_deletechunk(redata,curchunk);
1392
-                } else
1393
-                        redata_fix_nl(redata,curchunk);
1394
-        }
1395
-        /* activate undo */
1396
-        if(fromhere!=&(redata->undostack)) {
1397
-                /* reactivate the undo, now it is fine */
1398
-                redata_undo_reactivatelast(redata,&(redata->undostack));
1399
-        }
1400
-        if(undo!=NULL) {
1401
-                /* new or from redo stack */
1402
-                undo->posorig=posorig;
1403
-                undo->posdest=posdest;
1404
-                redata_hash(redata,undo->posthash);
1405
-                if(fromhere==&(redata->redostack))
1406
-                        redata_undo_removelast(redata,&(redata->redostack));
1407
-                else
1408
-                        redata_undo_wipe(redata,&(redata->redostack));
1409
-        } else {
1410
-                /* from undo stack */
1411
-                redata_undo_movelast(redata,&(redata->undostack),&(redata->redostack));
1412
-        }
1413
-        /* add to unsaved */
1414
-        redata_unsaved_add(redata,&(redata->undostack),redata->undostack.usedundo-1);
1415
-        /* compact if needed */
1416
-        if(redata_getsize(redata)>(redata->chunkdatasize) && redata_getavailable(redata)>(redata_getsize(redata)/2))
1417
-                redata_compact(redata);
1418
-        return(0);
1419
-}
1420
-
1421
-int
1422
-redata_op_undo(redata_t *redata)
1423
-{
1424
-        undo_t *undo;
1425
-        if(redata==NULL
1426
-          || redata->undostack.usedundo<1)
1427
-                return(-1); /* sanity check failed */
1428
-        undo=redata->undostack.undo+redata->undostack.usedundo-1;
1429
-        if(undo->type=='A') { /* ADD */
1430
-                redata_op_del(redata,undo->posorig,undo->len,&(redata->undostack));
1431
-        } else if(undo->type=='D') { /* DEL */
1432
-                redata_op_add(redata,undo->posorig,redata->undostack.buf+undo->off,undo->len,&(redata->undostack));
1433
-        } else if(undo->type=='M') { /* MOVE */
1434
-                if(undo->posorig<undo->posdest)
1435
-                        redata_op_move(redata,undo->posdest-undo->len, undo->len, undo->posorig,&(redata->undostack));
1436
-                else
1437
-                        redata_op_move(redata,undo->posdest, undo->len, undo->posorig+undo->len,&(redata->undostack));
1438
-        } else
1439
-                return(-1); /* unknown operation */
1440
-        return(-1);
1441
-}
1442
-
1443
-int
1444
-redata_op_redo(redata_t *redata)
1445
-{
1446
-        undo_t *undo;
1447
-        if(redata==NULL
1448
-          || redata->redostack.usedundo<1)
1449
-                return(-1); /* sanity check failed */
1450
-        undo=redata->redostack.undo+redata->redostack.usedundo-1;
1451
-        if(undo->type=='A') { /* ADD */
1452
-                redata_op_add(redata,undo->posorig,redata->redostack.buf+undo->off,undo->len,&(redata->redostack));
1453
-        } else if(undo->type=='D') { /* DEL */
1454
-                redata_op_del(redata,undo->posorig,undo->len,&(redata->redostack));
1455
-        } else if(undo->type=='M') { /* MOVE */
1456
-                redata_op_move(redata,undo->posorig, undo->len, undo->posdest,&(redata->redostack));
1457
-        } else
1458
-                return(-1); /* unknown operation */
1459
-        return(-1);
1460
-}
1461
-
1462
-int
1463
-redata_data_compare(redata_t *redata, long cmppos, char *buf, long buflen)
1464
-{
1465
-        int chunkno;
1466
-        long pos;
1467
-        long compared;
1468
-        long n;
1469
-        int res;
1470
-        if(redata==NULL || cmppos<0 || buf==NULL || buflen<0
1471
-          || cmppos>redata_getused(redata)
1472
-          || (cmppos+buflen)>redata_getused(redata))
1473
-                return(-1); /* sanity check failed */
1474
-        if(redata_getposptr(redata,cmppos,&chunkno,&pos)==-1)
1475
-                return(-1); /* invalid pos */
1476
-        for(compared=0,n=0;compared<buflen && chunkno<redata->sizechunks;chunkno++,pos=0,compared+=n) {
1477
-                n=redata->chunks[chunkno]->useddata-pos;
1478
-                n=(n<0)?0:((compared+n)>buflen)?(buflen-compared):n;
1479
-                if((res=memcmp(redata->chunks[chunkno]->data+pos,buf+compared,n))!=0)
1480
-                        return(res);
1481
-        }
1482
-        if(compared<buflen)
1483
-                return(1);
1484
-        return(0);
1485
-}
1486
-
1487
-
1488
-
1489
-int
1490
-redata_compact(redata_t *redata)
1491
-{
1492
-        /* compact and free surplus chunks */
1493
-        /* criterion: */
1494
-        /* 1. if two neighbouring chunks could join with 10% free in result chunk, do it */
1495
-        /* 2. if there are more than 2 unused chunks free at the end, free all unused chunks except two */
1496
-        int i,l;
1497
-        rechunk_t *chunk,**newchunks;
1498
-        if(redata==NULL)
1499
-                return(-1); /* sanity check failed */
1500
-        /* skip free chunks at end */
1501
-        for(i=redata->sizechunks-1;i>=0;i--) {
1502
-                if(redata->chunks[i]->useddata!=0)
1503
-                        break;
1504
-        }
1505
-        /* join neighbouring chunks where appropiate */
1506
-        l=redata->chunkdatasize-(redata->chunkdatasize)/10;
1507
-        for(;i>0;i--) {
1508
-                if((redata->chunks[i]->useddata+redata->chunks[i-1]->useddata)>=l)
1509
-                        continue;
1510
-                /* move data to prev. chunk, move chunk to end */
1511
-                redata_chunk_fillfromnext(redata,i-1,redata->chunks[i]->useddata);
1512
-                if(redata->chunks[i]->useddata>0)
1513
-                        continue; /* couldn't move data */
1514
-                chunk=redata->chunks[i];
1515
-                memmove(redata->chunks+i,redata->chunks+i+1,sizeof(rechunk_t *)*(redata->sizechunks-i-1));
1516
-                redata->chunks[redata->sizechunks-1]=chunk;
1517
-        }
1518
-        /* free unused chunks at end (leave two empty chunks, free the rest) */
1519
-        for(i=redata->sizechunks-1;i>=0;i--) {
1520
-                if(redata->chunks[i]->useddata!=0)
1521
-                        break;
1522
-        }
1523
-        l=i+3;
1524
-        if(l<redata->sizechunks) {
1525
-                for(i=l;i<redata->sizechunks;i++) {
1526
-                        free(redata->chunks[i]),redata->chunks[i]=NULL;
1527
-                        redata->available-=redata->chunkdatasize;
1528
-                }
1529
-                if((newchunks=realloc(redata->chunks,l*sizeof(rechunk_t *)))!=NULL)
1530
-                        redata->chunks=newchunks;
1531
-                redata->sizechunks=l;
1532
-        }
1533
-        return(0);
1534
-}
1535
-
1536
-int
1537
-redata_hash(redata_t *redata, char *resbuf129bytes)
1538
-{
1539
-        return(redata_hash_gen(redata,NULL,NULL,0,resbuf129bytes));
1540
-}
1541
-
1542
-int
1543
-redata_filehash(redata_t *redata, char *filename, char *resbuf129bytes)
1544
-{
1545
-        if(resbuf129bytes!=NULL)
1546
-                *resbuf129bytes='\0';
1547
-        if(filename==NULL)
1548
-                return(-1);
1549
-        return(redata_hash_gen(NULL,filename,NULL,0,resbuf129bytes));
1550
-}
1551
-
1552
-int
1553
-redata_memhash(redata_t *redata, char *buf, long buflen, char *resbuf129bytes)
1554
-{
1555
-        if(resbuf129bytes!=NULL)
1556
-                *resbuf129bytes='\0';
1557
-        if(buf==NULL || buflen<0)
1558
-                return(-1);
1559
-        return(redata_hash_gen(NULL,NULL,buf,buflen,resbuf129bytes));
1560
-}
1561
-
1562
-static int
1563
-redata_hash_gen(redata_t *redata, char *filename, char *buf, long buflen, char *resbuf129bytes)
1564
-{
1565
-        static char conv[]={"0123456789ABCDEF"};
1566
-        sha3_context sha3;
1567
-        unsigned char *hash;
1568
-        int i,c;
1569
-        int fd=-1;
1570
-        struct stat statbuf;
1571
-        if(resbuf129bytes==NULL)
1572
-                return(-1);  /* sanity check failed */
1573
-        if(resbuf129bytes!=NULL)
1574
-                *resbuf129bytes='\0';
1575
-        if((redata==NULL && filename==NULL && buf==NULL)
1576
-           || (redata!=NULL && (filename!=NULL || buf!=NULL))
1577
-           || (filename!=NULL && (redata!=NULL || buf!=NULL))
1578
-           || (buf!=NULL && (redata!=NULL || filename!=NULL))) {
1579
-                return(-1); /* sanity check failed */
1580
-        }
1581
-        if(filename!=NULL) {
1582
-                if((fd=open(filename,O_RDONLY))==-1 || fstat(fd,&statbuf)!=0 || !S_ISREG(statbuf.st_mode)) {
1583
-                       if(fd!=-1)
1584
-                               close(fd),fd=-1;
1585
-                       return(-1); /* file not found, couldn't query size or not regular file */
1586
-                }
1587
-        }
1588
-        sha3_Init512(&sha3);
1589
-        if(redata!=NULL) {
1590
-                for(i=0;i<redata->sizechunks;i++)
1591
-                        sha3_Update(&sha3,(void *) redata->chunks[i]->data,redata->chunks[i]->useddata);
1592
-        } else if(filename!=NULL) {
1593
-                char buf[16384];
1594
-                long totalread,nread;
1595
-                for(totalread=0,nread=0;totalread<statbuf.st_size;totalread+=nread,nread=0) {
1596
-                        if((nread=read(fd,buf,sizeof(buf)))<=0) {
1597
-                                close(fd),fd=-1;
1598
-                                return(-1); /* short read */
1599
-                        }
1600
-                        sha3_Update(&sha3,(void *) buf,nread);
1601
-                }
1602
-                close(fd),fd=-1;
1603
-        } else if(buf!=NULL) {
1604
-                sha3_Update(&sha3,(void *) buf,buflen);
1605
-        }
1606
-        hash=(unsigned char *)sha3_Finalize(&sha3);
1607
-        for(i=0;i<64;i++) {
1608
-                c=hash[i];
1609
-                resbuf129bytes[i<<1]=conv[((c>>4)&0xf)];
1610
-                resbuf129bytes[(i<<1)+1]=conv[(c&0xf)];
1611
-        }
1612
-        resbuf129bytes[128]='\0';
1613
-        /* NOTE this is SHA3-512, not keccak (empty result is a69f..cd26) */
1614
-        return(0);
1615
-}
1616
-
1617
-
1618
-static char *
1619
-unsaved_genname(char *filename, char *buf, int bufsize)
1620
-{
1621
-        static char pre[]={UNSAVEDPREFIX};
1622
-        static char post[]={UNSAVEDPOSTFIX};
1623
-        return(genname(filename,pre,post,buf,bufsize));
1624
-}
1625
-
1626
-static char *
1627
-securesave_genname(char *filename, char *buf, int bufsize)
1628
-{
1629
-        static char pre[]={SECURESAVEPREFIX};
1630
-        static char post[]={SECURESAVEPOSTFIX};
1631
-        return(genname(filename,pre,post,buf,bufsize));
1632
-}
1633
-
1634
-
1635
-static char *
1636
-genname(char *filename,char *prefix, char *postfix, char *buf, int bufsize)
1637
-{
1638
-        char *name,*ptr;
1639
-        int filenamelen;
1640
-        int prelen,postlen,finallen,off;
1641
-        if(filename==NULL || prefix==NULL || postfix==NULL)
1642
-                return(NULL);
1643
-        filenamelen=strlen(filename);
1644
-        prelen=strlen(prefix);
1645
-        postlen=strlen(postfix);
1646
-        finallen=filenamelen+prelen+postlen+1;
1647
-        if(buf==NULL) {
1648
-                if((name=malloc(finallen))==NULL)
1649
-                        return(NULL);
1650
-        } else {
1651
-                if(bufsize<filenamelen)
1652
-                        return(NULL);
1653
-                name=buf;
1654
-        }
1655
-        for(ptr=filename+strlen(filename);ptr>filename && ptr[-1]!='/';ptr--)
1656
-                ;
1657
-        off=0;
1658
-        memcpy(name+off,filename,ptr-filename);
1659
-        off+=ptr-filename;
1660
-        memcpy(name+off,prefix,prelen);
1661
-        off+=prelen;
1662
-        memcpy(name+off,ptr,filenamelen-(ptr-filename));
1663
-        off+=filenamelen-(ptr-filename);
1664
-        memcpy(name+off,postfix,postlen);
1665
-        off+=postlen;
1666
-        name[off]='\0';
1667
-        return(name);
1668
-}
1669
-
1670
-static char *
1671
-ptr_getlong(char *ptr,char *endptr,long *data)
1672
-{
1673
-        long l,s;
1674
-        if(ptr==NULL || endptr==NULL || ptr>endptr)
1675
-                return(NULL);
1676
-        s=1;
1677
-        if(ptr<endptr && *ptr=='-') {
1678
-                s=-1;
1679
-                ptr++;
1680
-        }
1681
-        for(l=0;ptr<endptr && *ptr>='0' && *ptr<='9';ptr++) {
1682
-                l*=10;
1683
-                l+=(*ptr-'0');
1684
-        }
1685
-        l*=s;
1686
-        if(data!=NULL)
1687
-                *data=l;
1688
-        return(ptr);
1689
-}
1690
-
1691
-
1692
-static char *
1693
-ptr_getchar(char *ptr,char *endptr,char *data)
1694
-{
1695
-        if(ptr==NULL || endptr==NULL || ptr>endptr)
1696
-                return(NULL);
1697
-        if(data!=NULL)
1698
-                *data=*ptr;
1699
-        ptr++;
1700
-        return(ptr);
1701
-}
1702
-
1703
-static char *
1704
-ptr_searchendchar(char *ptr, char *endptr, char endchar, char **endcharpos)
1705
-{
1706
-        char *aux;
1707
-        if(ptr==NULL || endptr==NULL || ptr>endptr)
1708
-                return(NULL);
1709
-        if((aux=memchr(ptr,endchar,endptr-ptr))==NULL)
1710
-                return(NULL);
1711
-        if(endcharpos!=NULL)
1712
-                *endcharpos=aux;
1713
-        return(aux+1);
1714
-}
1715
-
1716
-static char
1717
-sep_select(char *buf, int bufsize, char **pos)
1718
-{
1719
-        static char seps[]={"$%@!|&/='\"^*;:,-_"};
1720
-        char *ptr,*bestptr;
1721
-        int i,besti;
1722
-        bestptr=buf;
1723
-        if(pos!=NULL)
1724
-                *pos=NULL;
1725
-        for(i=0,besti=0;i<sizeof(seps);i++) {
1726
-                if((ptr=memchr(buf,seps[i],bufsize))==NULL) {
1727
-                        if(pos!=NULL)
1728
-                                *pos=buf+bufsize;
1729
-                        return(seps[i]);
1730
-                }
1731
-                if(ptr>bestptr) {
1732
-                        besti=0;
1733
-                        bestptr=ptr;
1734
-                }
1735
-        }
1736
-        if(pos!=NULL)
1737
-                *pos=bestptr;
1738
-        return(seps[besti]);
1739
-}
1740
-
1741
-static void *
1742
-mymemrchr(const void *s, int c, size_t n)
1743
-{
1744
-        long i;
1745
-        void *res=NULL;
1746
-        unsigned char b;
1747
-        b=(*((unsigned int *)(&c)))&0xff;
1748
-        for(i=0;i<n;i++) {
1749
-                if(((unsigned char *)s)[i]==b)
1750
-                        res=(((unsigned char *)s)+i);        }
1751
-        return(res);
1752
-}
1753
-
1754
-static void
1755
-meminvert(void *start, void *end)
1756
-{
1757
-        unsigned char *a=(unsigned char *)start;
1758
-        unsigned char *b=(unsigned char *)end;
1759
-        unsigned char t;
1760
-        for(b=b-1;a<b;a++,b--) {
1761
-                t=*a;
1762
-                *a=*b;
1763
-                *b=t;
1764
-        }
1765
-}
1766
-
Browse code

implement redata_compact

Dario Rodriguez authored on 21/03/2019 22:55:07
Showing 1 changed files
... ...
@@ -43,6 +43,25 @@ static char sep_select(char *buf, int bufsize, char **pos);
43 43
 static void *mymemrchr(const void *s, int c, size_t n);
44 44
 static void meminvert(void *start, void *end);
45 45
 
46
+#if 0
47
+static void
48
+redata_debug_chunkdump(redata_t *redata, char *title)
49
+{
50
+        int m,k;
51
+        char c;
52
+        title=(title==NULL)?"":title;
53
+        fprintf(stderr,"%s:CHUNKDUMP (sizechunks:%i)\n",title,redata->sizechunks);
54
+        for(m=0;m<redata->sizechunks;m++) {
55
+                fprintf(stderr,"%s:chunk[%i]:\"",title,m);
56
+                for(k=0;k<redata->chunks[m]->useddata;k++) {
57
+                        c=redata->chunks[m]->data[k];
58
+                        c=(c>=' ' && c<='~')?c:'.';
59
+                        fprintf(stderr,"%c",c);
60
+                }
61
+                fprintf(stderr,"\"\n");
62
+        }
63
+}
64
+#endif
46 65
 
47 66
 redata_t *
48 67
 redata_init(void)
... ...
@@ -534,6 +553,8 @@ redata_unsaved_trunc(redata_t *redata)
534 553
                 return(-1); /* malformed filename */
535 554
         if(redata->unsavedfd!=-1)
536 555
                 close(redata->unsavedfd),redata->unsavedfd=-1;
556
+        redata_hash(redata,redata->initialhash);
557
+        redata->unsaved.usedbuf=0;
537 558
         if((redata->unsavedfd=open(unsname,O_WRONLY|O_TRUNC|O_CREAT,0644))==-1)
538 559
                 return(-1); /* couldn't open file for writing */
539 560
         if((n=write(redata->unsavedfd,header,sizeof(header)-1))==-1
... ...
@@ -879,12 +900,13 @@ redata_load(redata_t *redata, char *filename, int use_unsaved)
879 900
         for(chunkno=0;chunkno<redata->sizechunks;chunkno++)
880 901
                 redata_whatin_refresh(redata,chunkno);
881 902
         /* unsaved */
882
-        redata_hash(redata,redata->initialhash);
883 903
         if(use_unsaved) {
884 904
                 /* apply missing changes and append new changes to unsaved */
905
+                redata_hash(redata,redata->initialhash);
885 906
                 redata_unsaved_loadappend(redata);
886 907
         } else {
887 908
                 /* nuke existing unsaved (if exists) and prepare new unsaved */
909
+                /* _trunc() fills itself redata->initialhash */
888 910
                 redata_unsaved_trunc(redata);
889 911
         }
890 912
         /* all done */
... ...
@@ -918,8 +940,9 @@ redata_save(redata_t *redata, char *filename)
918 940
                 return(-1); /* couldn't overwrite old file */
919 941
         }
920 942
         redata_unsaved_unlink(redata);
921
-        redata_hash(redata,redata->initialhash);
922
-        redata->unsaved.usedbuf=0;
943
+        strncpy(redata->filename,filename,sizeof(redata->filename));
944
+        redata->filename[sizeof(redata->filename)-1]='\0';
945
+        redata_unsaved_trunc(redata);
923 946
         return(0);
924 947
 }
925 948
 
... ...
@@ -1461,6 +1484,8 @@ redata_data_compare(redata_t *redata, long cmppos, char *buf, long buflen)
1461 1484
         return(0);
1462 1485
 }
1463 1486
 
1487
+
1488
+
1464 1489
 int
1465 1490
 redata_compact(redata_t *redata)
1466 1491
 {
... ...
@@ -1468,8 +1493,44 @@ redata_compact(redata_t *redata)
1468 1493
         /* criterion: */
1469 1494
         /* 1. if two neighbouring chunks could join with 10% free in result chunk, do it */
1470 1495
         /* 2. if there are more than 2 unused chunks free at the end, free all unused chunks except two */
1471
-#warning TODO
1472
-        return(-1);
1496
+        int i,l;
1497
+        rechunk_t *chunk,**newchunks;
1498
+        if(redata==NULL)
1499
+                return(-1); /* sanity check failed */
1500
+        /* skip free chunks at end */
1501
+        for(i=redata->sizechunks-1;i>=0;i--) {
1502
+                if(redata->chunks[i]->useddata!=0)
1503
+                        break;
1504
+        }
1505
+        /* join neighbouring chunks where appropiate */
1506
+        l=redata->chunkdatasize-(redata->chunkdatasize)/10;
1507
+        for(;i>0;i--) {
1508
+                if((redata->chunks[i]->useddata+redata->chunks[i-1]->useddata)>=l)
1509
+                        continue;
1510
+                /* move data to prev. chunk, move chunk to end */
1511
+                redata_chunk_fillfromnext(redata,i-1,redata->chunks[i]->useddata);
1512
+                if(redata->chunks[i]->useddata>0)
1513
+                        continue; /* couldn't move data */
1514
+                chunk=redata->chunks[i];
1515
+                memmove(redata->chunks+i,redata->chunks+i+1,sizeof(rechunk_t *)*(redata->sizechunks-i-1));
1516
+                redata->chunks[redata->sizechunks-1]=chunk;
1517
+        }
1518
+        /* free unused chunks at end (leave two empty chunks, free the rest) */
1519
+        for(i=redata->sizechunks-1;i>=0;i--) {
1520
+                if(redata->chunks[i]->useddata!=0)
1521
+                        break;
1522
+        }
1523
+        l=i+3;
1524
+        if(l<redata->sizechunks) {
1525
+                for(i=l;i<redata->sizechunks;i++) {
1526
+                        free(redata->chunks[i]),redata->chunks[i]=NULL;
1527
+                        redata->available-=redata->chunkdatasize;
1528
+                }
1529
+                if((newchunks=realloc(redata->chunks,l*sizeof(rechunk_t *)))!=NULL)
1530
+                        redata->chunks=newchunks;
1531
+                redata->sizechunks=l;
1532
+        }
1533
+        return(0);
1473 1534
 }
1474 1535
 
1475 1536
 int
Browse code

fix missing assignment in sep_select

Dario Rodriguez authored on 21/03/2019 21:36:42
Showing 1 changed files
... ...
@@ -1662,8 +1662,11 @@ sep_select(char *buf, int bufsize, char **pos)
1662 1662
         if(pos!=NULL)
1663 1663
                 *pos=NULL;
1664 1664
         for(i=0,besti=0;i<sizeof(seps);i++) {
1665
-                if((ptr=memchr(buf,seps[i],bufsize))==NULL)
1665
+                if((ptr=memchr(buf,seps[i],bufsize))==NULL) {
1666
+                        if(pos!=NULL)
1667
+                                *pos=buf+bufsize;
1666 1668
                         return(seps[i]);
1669
+                }
1667 1670
                 if(ptr>bestptr) {
1668 1671
                         besti=0;
1669 1672
                         bestptr=ptr;
Browse code

unsaved_unadd and unsaved_commit

Dario Rodriguez authored on 20/03/2019 22:56:11
Showing 1 changed files
... ...
@@ -65,7 +65,6 @@ redata_init(void)
65 65
         redata->filename[0]='\0';
66 66
         redata->unsavedfd=-1;
67 67
         redata->unsaved.sizebuf=redata->unsaved.usedbuf=0;
68
-        redata->unsaved.lastsize=0;
69 68
         /* all done */
70 69
         return(redata);
71 70
 }
... ...
@@ -106,7 +105,6 @@ redata_free(redata_t *redata)
106 105
         if(redata->unsaved.buf!=NULL) {
107 106
                 free(redata->unsaved.buf),redata->unsaved.buf=NULL;
108 107
                 redata->unsaved.sizebuf=redata->unsaved.usedbuf=0;
109
-                redata->unsaved.lastsize=0;
110 108
         }
111 109
         /* free main struct */
112 110
         free(redata),redata=NULL;
... ...
@@ -580,7 +578,6 @@ redata_unsaved_loadappend(redata_t *redata)
580 578
                 redata->unsaved.buf=newptr;
581 579
                 redata->unsaved.sizebuf=(statbuf.st_size-headerhashsize);
582 580
         }
583
-        redata->unsaved.lastsize=0;
584 581
         redata->unsaved.usedbuf=0;
585 582
         lim=(statbuf.st_size-headerhashsize);
586 583
         for(nread=0;redata->unsaved.usedbuf<lim;redata->unsaved.usedbuf+=nread,nread=0) {
... ...
@@ -731,21 +728,100 @@ redata_unsaved_add(redata_t *redata, undostack_t *stack, int undono)
731 728
                         buf=redata->unsaved.buf+redata->unsaved.usedbuf;
732 729
                 }
733 730
         }
734
-        return(-1);
731
+        return(0);
735 732
 }
736 733
 
737 734
 int
738 735
 redata_unsaved_unadd(redata_t *redata, undostack_t *stack, int undono)
739 736
 {
740
-#warning TODO
741
-        return(-1);
737
+        /* adds to unsaved the inverse operation to the one specified in the undo */
738
+        char sep;
739
+        undo_t *undo;
740
+        char *sepend,*ptr,*endptr;
741
+        char *buf;
742
+        int k;
743
+        int maxsize,newsize;
744
+        char posbuf[128];
745
+        if(redata==NULL
746
+          || (stack!=&(redata->undostack) && stack!=&(redata->redostack))
747
+          || undono<0 || undono>=stack->usedundo)
748
+                return(-1); /* sanity check failed */
749
+        /* syntax (see loadappend): A<pos><+?><sep><text><sep>[<+?><sep><text><sep>[...]] */
750
+        undo=stack->undo+undono;
751
+        if(undo->type!='A' && undo->type!='D' && undo->type!='M')
752
+                return(-1); /* unrecognized undo type */
753
+        for(k=0,maxsize=0,buf=NULL;k<2;k++,maxsize=0) {
754
+                ptr=stack->buf+undo->off;
755
+                endptr=ptr+undo->len;
756
+                if(k!=0)
757
+                        buf[maxsize]=(undo->type=='A')?'D':(undo->type=='D')?'A':undo->type;
758
+                maxsize++;
759
+                if(undo->type=='A' || undo->type=='D')
760
+                        snprintf(posbuf,sizeof(posbuf),"%li",undo->posorig);
761
+                else
762
+                        snprintf(posbuf,sizeof(posbuf),"%li",(undo->posorig<undo->posdest)?undo->posdest-undo->len:undo->posdest);
763
+                posbuf[sizeof(posbuf)-1]='\0';
764
+                if(k!=0)
765
+                        strcpy(buf+maxsize,posbuf);
766
+                maxsize+=strlen(posbuf);
767
+                if(undo->type=='M') {
768
+                        snprintf(posbuf,sizeof(posbuf),",%li",(undo->posorig<undo->posdest)?undo->posorig:undo->posorig+undo->len);
769
+                        posbuf[sizeof(posbuf)-1]='\0';
770
+                        if(k!=0)
771
+                                strcpy(buf+maxsize,posbuf);
772
+                        maxsize+=strlen(posbuf);
773
+                }
774
+                while(ptr<endptr) {
775
+                        sep=sep_select(ptr,endptr-ptr,&sepend);
776
+                        if(sepend!=endptr) {
777
+                                if(k!=0)
778
+                                        buf[maxsize]='+';
779
+                                maxsize++;
780
+                        }
781
+                        if(k!=0)
782
+                                buf[maxsize]=sep;
783
+                        maxsize++;
784
+                        if(k!=0)
785
+                                memcpy(buf+maxsize,ptr,sepend-ptr);
786
+                        maxsize+=sepend-ptr;
787
+                        if(k!=0)
788
+                                buf[maxsize]=sep;
789
+                        maxsize++;
790
+                        ptr=sepend;
791
+                }
792
+                if(k==0) {
793
+                        /* get mem */
794
+                        if((redata->unsaved.sizebuf-redata->unsaved.sizebuf)<maxsize) {
795
+                                newsize=(redata->unsaved.sizebuf+maxsize+UNDOGROWSIZE-1)/UNDOGROWSIZE;
796
+                                newsize*=UNDOGROWSIZE;
797
+                                if((buf=realloc(redata->unsaved.buf,newsize))==NULL)
798
+                                        return(-1); /* insuf. mem. */
799
+                                redata->unsaved.buf=buf;
800
+                                redata->unsaved.sizebuf=newsize;
801
+                        }
802
+                        buf=redata->unsaved.buf+redata->unsaved.usedbuf;
803
+                }
804
+        }
805
+        return(0);
742 806
 }
743 807
 
744 808
 int
745 809
 redata_unsaved_commit(redata_t *redata)
746 810
 {
747
-#warning TODO
748
-        return(-1);
811
+        int n,nwritten;
812
+        char unsname[PATH_MAX+1];
813
+        if(redata==NULL || redata->unsavedfd==-1)
814
+                return(-1);
815
+        for(nwritten=0;nwritten<redata->unsaved.usedbuf;nwritten+=n) {
816
+                if((n=write(redata->unsavedfd,redata->unsaved.buf+nwritten,redata->unsaved.usedbuf-nwritten))<0) {
817
+                        close(redata->unsavedfd),redata->unsavedfd=-1;
818
+                        if((unsaved_genname(redata->filename,unsname,sizeof(unsname)))!=NULL)
819
+                                unlink(unsname); /* a corrupted unsaved is of no use, delete it */
820
+                        return(-1); /* error writing */
821
+                }
822
+        }
823
+        redata->unsaved.usedbuf=0;
824
+        return(0);
749 825
 }
750 826
 
751 827
 
... ...
@@ -1120,6 +1196,8 @@ redata_op_add(redata_t *redata, long insertpos, char *buf, long buflen, undostac
1120 1196
                 /* from undo stack */
1121 1197
                 redata_undo_movelast(redata,&(redata->undostack),&(redata->redostack));
1122 1198
         }
1199
+        /* add to unsaved */
1200
+        redata_unsaved_add(redata,&(redata->undostack),redata->undostack.usedundo-1);
1123 1201
         /* compact if needed */
1124 1202
         if(redata_getsize(redata)>(redata->chunkdatasize) && redata_getavailable(redata)>(redata_getsize(redata)/2))
1125 1203
                 redata_compact(redata);
... ...
@@ -1178,6 +1256,8 @@ redata_op_del(redata_t *redata, long delpos, long size, undostack_t *fromhere)
1178 1256
                 /* from undo stack */
1179 1257
                 redata_undo_movelast(redata,&(redata->undostack),&(redata->redostack));
1180 1258
         }
1259
+        /* add to unsaved */
1260
+        redata_unsaved_add(redata,&(redata->undostack),redata->undostack.usedundo-1);
1181 1261
         /* compact if needed */
1182 1262
         if(redata_getsize(redata)>(redata->chunkdatasize) && redata_getavailable(redata)>(redata_getsize(redata)/2))
1183 1263
                 redata_compact(redata);
... ...
@@ -1307,6 +1387,8 @@ redata_op_move(redata_t *redata, long posorig, long size, long posdest, undostac
1307 1387
                 /* from undo stack */
1308 1388
                 redata_undo_movelast(redata,&(redata->undostack),&(redata->redostack));
1309 1389
         }
1390
+        /* add to unsaved */
1391
+        redata_unsaved_add(redata,&(redata->undostack),redata->undostack.usedundo-1);
1310 1392
         /* compact if needed */
1311 1393
         if(redata_getsize(redata)>(redata->chunkdatasize) && redata_getavailable(redata)>(redata_getsize(redata)/2))
1312 1394
                 redata_compact(redata);
Browse code

implement unsaved_loadappend 'M' and unsaved_add

Dario Rodriguez authored on 19/03/2019 22:07:56
Showing 1 changed files
... ...
@@ -561,7 +561,7 @@ redata_unsaved_loadappend(redata_t *redata)
561 561
         long nread,lim;
562 562
         char *ptr,*endptr,*aux,*bufptr;
563 563
         char actioncode;
564
-        long pos;
564
+        long pos,pos2;
565 565
         char endcode;
566 566
         int flag_multipart;
567 567
         if((fd=redata_unsaved_check_gen(redata,redata->filename))==-1)
... ...
@@ -631,7 +631,31 @@ redata_unsaved_loadappend(redata_t *redata)
631 631
                                 redata_op_del(redata,pos,aux-bufptr,NULL);
632 632
                         } while(flag_multipart);
633 633
                 } else if(actioncode=='M') {
634
-#warning TODO
634
+                        ptr=ptr_getlong(ptr,endptr,&pos);
635
+                        ptr+=(ptr!=NULL && ptr<endptr)?1:0;
636
+                        ptr=ptr_getlong(ptr,endptr,&pos2);
637
+                        do {
638
+                                flag_multipart=0;
639
+                                ptr=ptr_getchar(ptr,endptr,&endcode);
640
+                                if(ptr!=NULL && endcode=='+') {
641
+                                        flag_multipart=1;
642
+                                        ptr=ptr_getchar(ptr,endptr,&endcode);
643
+                                }
644
+                                bufptr=ptr;
645
+                                ptr=ptr_searchendchar(ptr,endptr,endcode,&aux);
646
+                                if(ptr==NULL
647
+                                  || pos<0 || (pos+(aux-bufptr))>redata_getused(redata)
648
+                                  || pos2<0 || pos2>redata_getused(redata)
649
+                                  || ((aux-bufptr)>0 && pos2>=pos && pos2<(pos+(aux-bufptr)))
650
+                                  ) {
651
+                                        return(-1); /* malformed register */
652
+                                }
653
+                                if(redata_data_compare(redata,pos,bufptr,aux-bufptr)!=0)
654
+                                        return(-1); /* corrupted data */
655
+                                redata_op_move(redata,pos,(aux-bufptr),pos2,NULL);
656
+                                pos=(pos<pos2)?pos:(pos+(aux-bufptr));
657
+                                pos2=pos2+(aux-bufptr);
658
+                        } while(flag_multipart);
635 659
                 } else {
636 660
                         return(-1); /* corrupted undobuf */
637 661
                 }
... ...
@@ -641,17 +665,77 @@ redata_unsaved_loadappend(redata_t *redata)
641 665
 
642 666
 
643 667
 int
644
-redata_unsaved_add(redata_t *redata, undo_t *undo)
668
+redata_unsaved_add(redata_t *redata, undostack_t *stack, int undono)
645 669
 {
646
-
647
-        /* separator is '$' , '@'  or '%' (whatever makes the longest string) */
648
-        /* if len is omitted, then it goes inmediatly after the last op (probably there separator character was used in the string) */
649
-#warning TODO
670
+        char sep;
671
+        undo_t *undo;
672
+        char *sepend,*ptr,*endptr;
673
+        char *buf;
674
+        int k;
675
+        int maxsize,newsize;
676
+        char posbuf[128];
677
+        if(redata==NULL
678
+          || (stack!=&(redata->undostack) && stack!=&(redata->redostack))
679
+          || undono<0 || undono>=stack->usedundo)
680
+                return(-1); /* sanity check failed */
681
+        /* syntax (see loadappend): A<pos><+?><sep><text><sep>[<+?><sep><text><sep>[...]] */
682
+        undo=stack->undo+undono;
683
+        if(undo->type!='A' && undo->type!='D' && undo->type!='M')
684
+                return(-1); /* unrecognized undo type */
685
+        for(k=0,maxsize=0,buf=NULL;k<2;k++,maxsize=0) {
686
+                ptr=stack->buf+undo->off;
687
+                endptr=ptr+undo->len;
688
+                if(k!=0)
689
+                        buf[maxsize]=undo->type;
690
+                maxsize++;
691
+                snprintf(posbuf,sizeof(posbuf),"%li",undo->posorig);
692
+                posbuf[sizeof(posbuf)-1]='\0';
693
+                if(k!=0)
694
+                        strcpy(buf+maxsize,posbuf);
695
+                maxsize+=strlen(posbuf);
696
+                if(undo->type=='M') {
697
+                        snprintf(posbuf,sizeof(posbuf),",%li",undo->posdest);
698
+                        posbuf[sizeof(posbuf)-1]='\0';
699
+                        if(k!=0)
700
+                                strcpy(buf+maxsize,posbuf);
701
+                        maxsize+=strlen(posbuf);
702
+                }
703
+                while(ptr<endptr) {
704
+                        sep=sep_select(ptr,endptr-ptr,&sepend);
705
+                        if(sepend!=endptr) {
706
+                                if(k!=0)
707
+                                        buf[maxsize]='+';
708
+                                maxsize++;
709
+                        }
710
+                        if(k!=0)
711
+                                buf[maxsize]=sep;
712
+                        maxsize++;
713
+                        if(k!=0)
714
+                                memcpy(buf+maxsize,ptr,sepend-ptr);
715
+                        maxsize+=sepend-ptr;
716
+                        if(k!=0)
717
+                                buf[maxsize]=sep;
718
+                        maxsize++;
719
+                        ptr=sepend;
720
+                }
721
+                if(k==0) {
722
+                        /* get mem */
723
+                        if((redata->unsaved.sizebuf-redata->unsaved.sizebuf)<maxsize) {
724
+                                newsize=(redata->unsaved.sizebuf+maxsize+UNDOGROWSIZE-1)/UNDOGROWSIZE;
725
+                                newsize*=UNDOGROWSIZE;
726
+                                if((buf=realloc(redata->unsaved.buf,newsize))==NULL)
727
+                                        return(-1); /* insuf. mem. */
728
+                                redata->unsaved.buf=buf;
729
+                                redata->unsaved.sizebuf=newsize;
730
+                        }
731
+                        buf=redata->unsaved.buf+redata->unsaved.usedbuf;
732
+                }
733
+        }
650 734
         return(-1);
651 735
 }
652 736
 
653 737
 int
654
-redata_unsaved_unadd(redata_t *redata, undo_t *undo)
738
+redata_unsaved_unadd(redata_t *redata, undostack_t *stack, int undono)
655 739
 {
656 740
 #warning TODO
657 741
         return(-1);
Browse code

Add move test. Fix op_move code.

Dario Rodriguez authored on 18/03/2019 21:56:38
Showing 1 changed files
... ...
@@ -305,14 +305,12 @@ redata_chunk_movedata(redata_t *redata, int chunkfrom, long posfrom, int chunkto
305 305
                 /* from==to */
306 306
                 rechunk_t *chunk=redata->chunks[chunkfrom];
307 307
                 memcpy(redata->tmpchunk->data,chunk->data+posfrom,size);
308
-                if(posto>posfrom) {
309
-                        int inside=(posto-posfrom)-size;
310
-                        memmove(chunk->data+posfrom,chunk->data+posto-inside,inside);
311
-                        memcpy(chunk->data+posfrom+inside,redata->tmpchunk->data,size);
312
-                } else {
313
-                        int inside=(posto-posfrom);
314
-                        memmove(chunk->data+posfrom+size-inside,chunk->data+posto,inside);
308
+                if(posfrom>posto) {
309
+                        memmove(chunk->data+posto+size,chunk->data+posto,posfrom-posto);
315 310
                         memcpy(chunk->data+posto,redata->tmpchunk->data,size);
311
+                } else {
312
+                        memmove(chunk->data+posfrom,chunk->data+posfrom+size,posto-posfrom-size);
313
+                        memcpy(chunk->data+posto-size,redata->tmpchunk->data,size);
316 314
                 }
317 315
                 chunk->whatin_fresh=0;
318 316
         }
... ...
@@ -1168,8 +1166,8 @@ redata_op_move(redata_t *redata, long posorig, long size, long posdest, undostac
1168 1166
                                 return(-1); /* invalid pos or insuf. mem */
1169 1167
                         if(pos!=0)
1170 1168
                                 chunkno++;
1171
-                        if(spos==0)
1172
-                                schunkno--;
1169
+                        if(spos!=0)
1170
+                                schunkno++;
1173 1171
                         if(dpos!=0)
1174 1172
                                 dchunkno++;
1175 1173
                         if(chunkno<0 || schunkno<0 || dchunkno<0
... ...
@@ -1178,12 +1176,12 @@ redata_op_move(redata_t *redata, long posorig, long size, long posdest, undostac
1178 1176
                         /* reorder inplace inverting the bytes (as in flipping a image) */
1179 1177
                         if(chunkno<dchunkno) {
1180 1178
                                 meminvert(redata->chunks+chunkno,redata->chunks+dchunkno);
1181
-                                meminvert(redata->chunks+chunkno,redata->chunks+dchunkno-(schunkno-chunkno));
1182 1179
                                 meminvert(redata->chunks+dchunkno-(schunkno-chunkno),redata->chunks+dchunkno);
1180
+                                meminvert(redata->chunks+chunkno,redata->chunks+dchunkno-(schunkno-chunkno));
1183 1181
                         } else {
1184
-                                meminvert(redata->chunks+dchunkno,redata->chunks+chunkno);
1182
+                                meminvert(redata->chunks+dchunkno,redata->chunks+schunkno);
1185 1183
                                 meminvert(redata->chunks+dchunkno,redata->chunks+dchunkno+(schunkno-chunkno));
1186
-                                meminvert(redata->chunks+dchunkno+(schunkno-chunkno),redata->chunks+chunkno);
1184
+                                meminvert(redata->chunks+dchunkno+(schunkno-chunkno),redata->chunks+schunkno);
1187 1185
                         }
1188 1186
                 }
1189 1187
         }
Browse code

Fix some corner cases of op_add, op_del

Dario Rodriguez authored on 16/03/2019 11:04:02
Showing 1 changed files
... ...
@@ -988,7 +988,10 @@ redata_op_add(redata_t *redata, long insertpos, char *buf, long buflen, undostac
988 988
                 bothering=chunk->useddata-pos;
989 989
                 bothering=(bothering>nextavail)?nextavail:bothering;
990 990
                 redata_chunk_movedata(redata,chunkno,chunk->useddata-bothering,chunkno+1,0,bothering);
991
-                redata_chunk_insertdata(redata,chunkno,pos,buf,buflen);
991
+                avail=redata->chunkdatasize-chunk->useddata;
992
+                avail=(avail>buflen)?buflen:avail;
993
+                redata_chunk_insertdata(redata,chunkno,pos,buf,avail);
994
+                redata_chunk_insertdata(redata,chunkno+1,0,buf+avail,buflen-avail);
992 995
         } else {
993 996
                 /* will need to add more chunks */
994 997
                 needed=(buflen+redata->chunkdatasize-1)/redata->chunkdatasize;
... ...
@@ -1068,7 +1071,7 @@ redata_op_del(redata_t *redata, long delpos, long size, undostack_t *fromhere)
1068 1071
                 curpos=(curchunk==chunkno)?pos:0;
1069 1072
                 curdel=redata->chunks[curchunk]->useddata-curpos;
1070 1073
                 curdel=(curdel>(size-ndel))?(size-ndel):curdel;
1071
-                redata_chunk_deletedata(redata,chunkno,curpos,curdel);
1074
+                redata_chunk_deletedata(redata,curchunk,curpos,curdel);
1072 1075
                 ndel+=curdel;
1073 1076
         }
1074 1077
         /* fix nl and delete unused chunks */
Browse code

Implement op_move. Make the tests more thorough by having them check several different chunkdatasizes.

Dario Rodriguez authored on 15/03/2019 21:43:40
Showing 1 changed files
... ...
@@ -40,6 +40,9 @@ static char *ptr_getlong(char *ptr,char *endptr,long *data);
40 40
 static char *ptr_getchar(char *ptr,char *endptr,char *data);
41 41
 static char *ptr_searchendchar(char *ptr, char *endptr, char endchar, char **endcharpos);
42 42
 static char sep_select(char *buf, int bufsize, char **pos);
43
+static void *mymemrchr(const void *s, int c, size_t n);
44
+static void meminvert(void *start, void *end);
45
+
43 46
 
44 47
 redata_t *
45 48
 redata_init(void)
... ...
@@ -339,7 +342,7 @@ redata_chunk_deletedata(redata_t *redata, int chunkno, long pos, long n)
339 342
 {
340 343
         rechunk_t *chunk;
341 344
         if(redata==NULL || n<0
342
-          || chunk<0 || chunkno>=redata->sizechunks
345
+          || chunkno<0 || chunkno>=redata->sizechunks
343 346
           || pos<0 || pos>redata->chunks[chunkno]->useddata
344 347
           || (redata->chunks[chunkno]->useddata-pos)<n)
345 348
                 return(-1); /* sanity check failed */
... ...
@@ -353,6 +356,41 @@ redata_chunk_deletedata(redata_t *redata, int chunkno, long pos, long n)
353 356
         return(0);
354 357
 }
355 358
 
359
+int
360
+redata_chunk_splithere(redata_t *redata, int chunkno, int pos)
361
+{
362
+        rechunk_t *chunk;
363
+        int size;
364
+        if(redata==NULL
365
+          || chunkno<0 || chunkno>=redata->sizechunks
366
+          || pos<0 || pos>redata->chunks[chunkno]->useddata)
367
+                return(-1); /* sanity check failed */
368
+        chunk=redata->chunks[chunkno];
369
+        if(chunk->useddata==pos)
370
+                return(0); /* all done: already splitted */
371
+        size=redata->chunks[chunkno]->useddata-pos;
372
+        if((chunkno+1)<redata->sizechunks
373
+          && (redata->chunkdatasize-redata->chunks[chunkno+1]->useddata)>=size) {
374
+                redata_chunk_movedata(redata,chunkno,pos,chunkno+1,0,size);
375
+                return(0); /* all done: moved data cleanly to next chunk */
376
+        }
377
+        if(redata_chunk_insertnew(redata,chunkno)!=0)
378
+                return(-1); /* insuf. mem. */
379
+        redata_chunk_movedata(redata,chunkno,pos,chunkno+1,0,size);
380
+        return(0);
381
+}
382
+
383
+int
384
+redata_chunk_fillfromnext(redata_t *redata, int chunkno, int n)
385
+{
386
+        if(redata==NULL || chunkno<0 || (chunkno+1)>=redata->sizechunks
387
+          || (redata->chunkdatasize-redata->chunks[chunkno]->useddata)<n
388
+          || (redata->chunks[chunkno+1]->useddata)<n)
389
+                return(-1); /* sanity check failed */
390
+        return(redata_chunk_movedata(redata,chunkno+1,0,chunkno,redata->chunks[chunkno]->useddata,n));
391
+}
392
+
393
+
356 394
 int
357 395
 redata_whatin_refresh(redata_t *redata, int chunkno)
358 396
 {
... ...
@@ -374,18 +412,6 @@ redata_whatin_refresh(redata_t *redata, int chunkno)
374 412
         return(0);
375 413
 }
376 414
 
377
-void *
378
-mymemrchr(const void *s, int c, size_t n)
379
-{
380
-        long i;
381
-        void *res=NULL;
382
-        unsigned char b;
383
-        b=(*((unsigned int *)(&c)))&0xff;
384
-        for(i=0;i<n;i++) {
385
-                if(((unsigned char *)s)[i]==b)
386
-                        res=(((unsigned char *)s)+i);        }
387
-        return(res);
388
-}
389 415
 
390 416
 int
391 417
 redata_fix_nl(redata_t *redata, int chunkno)
... ...
@@ -896,6 +922,33 @@ redata_undo_wipe(redata_t *redata, undostack_t *stack)
896 922
         return(0);
897 923
 }
898 924
 
925
+int
926
+redata_undo_inactivatelast(redata_t *redata, undostack_t *stack)
927
+{
928
+        if(redata==NULL
929
+          || (stack!=&(redata->undostack) && stack!=&(redata->redostack)))
930
+                return(-1); /* sanity check failed */
931
+        if(stack->usedundo==0)
932
+                return(-1);
933
+        stack->usedundo--;
934
+        stack->usedbuf-=stack->undo[stack->usedundo].len;
935
+        return(0);
936
+}
937
+
938
+int
939
+redata_undo_reactivatelast(redata_t *redata, undostack_t *stack)
940
+{
941
+        if(redata==NULL
942
+          || (stack!=&(redata->undostack) && stack!=&(redata->redostack)))
943
+                return(-1); /* sanity check failed */
944
+        if(stack->usedundo==stack->sizeundo)
945
+                return(-1);
946
+        stack->usedbuf+=stack->undo[stack->usedundo].len;
947
+        stack->usedundo++;
948
+        return(0);
949
+}
950
+
951
+
899 952
 int
900 953
 redata_op_add(redata_t *redata, long insertpos, char *buf, long buflen, undostack_t *fromhere)
901 954
 {
... ...
@@ -982,6 +1035,9 @@ redata_op_add(redata_t *redata, long insertpos, char *buf, long buflen, undostac
982 1035
                 /* from undo stack */
983 1036
                 redata_undo_movelast(redata,&(redata->undostack),&(redata->redostack));
984 1037
         }
1038
+        /* compact if needed */
1039
+        if(redata_getsize(redata)>(redata->chunkdatasize) && redata_getavailable(redata)>(redata_getsize(redata)/2))
1040
+                redata_compact(redata);
985 1041
         return(0);
986 1042
 }
987 1043
 
... ...
@@ -995,7 +1051,7 @@ redata_op_del(redata_t *redata, long delpos, long size, undostack_t *fromhere)
995 1051
         long ndel;
996 1052
         long curpos,curdel;
997 1053
         if(redata==NULL || size<0
998
-          || delpos>redata_getused(redata)
1054
+          || delpos<0
999 1055
           || (delpos+size)>redata_getused(redata)
1000 1056
           || (fromhere!=NULL && (fromhere!=&(redata->undostack) && fromhere!=&(redata->redostack))))
1001 1057
                 return(-1); /* sanity check failed */
... ...
@@ -1037,14 +1093,139 @@ redata_op_del(redata_t *redata, long delpos, long size, undostack_t *fromhere)
1037 1093
                 /* from undo stack */
1038 1094
                 redata_undo_movelast(redata,&(redata->undostack),&(redata->redostack));
1039 1095
         }
1096
+        /* compact if needed */
1097
+        if(redata_getsize(redata)>(redata->chunkdatasize) && redata_getavailable(redata)>(redata_getsize(redata)/2))
1098
+                redata_compact(redata);
1040 1099
         return(0);
1041 1100
 }
1042 1101
 
1043 1102
 int
1044 1103
 redata_op_move(redata_t *redata, long posorig, long size, long posdest, undostack_t *fromhere)
1045 1104
 {
1046
-#warning TODO
1047
-        return(-1);
1105
+        int chunkno,dchunkno,curchunk;
1106
+        long pos,dpos;
1107
+        undo_t *undo;
1108
+        rechunk_t *chunk;
1109
+        if(redata==NULL || size<0
1110
+          || posorig<0
1111
+          || (posorig+size)>redata_getused(redata)
1112
+          || posdest<0
1113
+          || (posdest>=posorig && posdest<(posorig+size))
1114
+          || (fromhere!=NULL && (fromhere!=&(redata->undostack) && fromhere!=&(redata->redostack))))
1115
+                return(-1); /* sanity check failed */
1116
+        if(redata_getposptr(redata,posorig,&chunkno,&pos)==-1)
1117
+                return(-1); /* invalid pos */
1118
+        if(redata_getposptr(redata,posdest,&dchunkno,&dpos)==-1)
1119
+                return(-1); /* invalid pos */
1120
+        if(fromhere!=&(redata->undostack)) {
1121
+                if((undo=redata_undo_newfromchunks(redata,&(redata->undostack),'M',posorig,size))==NULL)
1122
+                        return(-1); /* couldn't create undo struct */
1123
+                /* inactivate the undo so we are able to use return(-1) without removing it */
1124
+                redata_undo_inactivatelast(redata,&(redata->undostack));
1125
+                redata_hash(redata,undo->prehash);
1126
+        } else {
1127
+                undo=NULL;
1128
+        }
1129
+        if((pos+size)<=redata->chunks[chunkno]->useddata
1130
+          && (chunkno==dchunkno || (redata->chunkdatasize-redata->chunks[dchunkno]->useddata)>=size)) {
1131
+                /* trivial case: (all the data is in the same chunk) AND (it is intra-chunk move or destination chunk has enough avail. space) */
1132
+                redata_chunk_movedata(redata, chunkno, pos, dchunkno, dpos, size);
1133
+        } else {
1134
+                /* data spans several chunks, no space on dest, etc: do it the hard way */
1135
+                /* separate the selected data into its own chunk(s) */
1136
+                /* lower positions have to make the boundary first (or risk undoing it with next create boundary) */
1137
+                if(posdest<posorig) {
1138
+                        /* make a chunk boundary in posdest */
1139
+                        if(redata_getposptr(redata,posdest,&chunkno,&pos)==-1
1140
+                          || redata_chunk_splithere(redata,chunkno,pos)!=0)
1141
+                                return(-1); /* invalid pos or insuf. mem */
1142
+                }
1143
+                /* make a chunk boundary in posorig and in posorig+size */
1144
+                if(redata_getposptr(redata,posorig,&chunkno,&pos)==-1
1145
+                  || redata_chunk_splithere(redata,chunkno,pos)!=0)
1146
+                        return(-1); /* invalid pos or insuf. mem */
1147
+                if(redata_getposptr(redata,posorig+size,&chunkno,&pos)==-1
1148
+                  || redata_chunk_splithere(redata,chunkno,pos)!=0)
1149
+                        return(-1); /* invalid pos or insuf. mem */
1150
+                if(posdest>posorig) {
1151
+                        /* make a chunk boundary in posdest */
1152
+                        if(redata_getposptr(redata,posdest,&chunkno,&pos)==-1
1153
+                          || redata_chunk_splithere(redata,chunkno,pos)!=0)
1154
+                                return(-1); /* invalid pos or insuf. mem */
1155
+                }
1156
+                /* reorder the chunks */
1157
+                {
1158
+                        int schunkno;
1159
+                        long spos;
1160
+                        if(redata_getposptr(redata,posorig,&chunkno,&pos)==-1)
1161
+                                return(-1); /* invalid pos or insuf. mem */
1162
+                        if(redata_getposptr(redata,posorig+size,&schunkno,&spos)==-1)
1163
+                                return(-1); /* invalid pos or insuf. mem */
1164
+                        if(redata_getposptr(redata,posdest,&dchunkno,&dpos)==-1)
1165
+                                return(-1); /* invalid pos or insuf. mem */
1166
+                        if(pos!=0)
1167
+                                chunkno++;
1168
+                        if(spos==0)
1169
+                                schunkno--;
1170
+                        if(dpos!=0)
1171
+                                dchunkno++;
1172
+                        if(chunkno<0 || schunkno<0 || dchunkno<0
1173
+                          || chunkno>=redata->sizechunks || schunkno>=redata->sizechunks || dchunkno>=redata->sizechunks)
1174
+                                return(-1); /* ERROR: INTERNAL ERROR */
1175
+                        /* reorder inplace inverting the bytes (as in flipping a image) */
1176
+                        if(chunkno<dchunkno) {
1177
+                                meminvert(redata->chunks+chunkno,redata->chunks+dchunkno);
1178
+                                meminvert(redata->chunks+chunkno,redata->chunks+dchunkno-(schunkno-chunkno));
1179
+                                meminvert(redata->chunks+dchunkno-(schunkno-chunkno),redata->chunks+dchunkno);
1180
+                        } else {
1181
+                                meminvert(redata->chunks+dchunkno,redata->chunks+chunkno);
1182
+                                meminvert(redata->chunks+dchunkno,redata->chunks+dchunkno+(schunkno-chunkno));
1183
+                                meminvert(redata->chunks+dchunkno+(schunkno-chunkno),redata->chunks+chunkno);
1184
+                        }
1185
+                }
1186
+        }
1187
+        /* fix nl and delete unused chunks */
1188
+        if(posorig<posdest) {
1189
+              if(redata_getposptr(redata,posorig,&chunkno,&pos)==-1)
1190
+                      return(-1); /* invalid pos */
1191
+              if(redata_getposptr(redata,posdest,&dchunkno,&dpos)==-1)
1192
+                      return(-1); /* invalid pos */
1193
+        } else { /* posorig>posdest */
1194
+              if(redata_getposptr(redata,posdest,&chunkno,&pos)==-1)
1195
+                      return(-1); /* invalid pos */
1196
+              if(redata_getposptr(redata,posorig+size,&dchunkno,&dpos)==-1)
1197
+                      return(-1); /* invalid pos */
1198
+        }
1199
+        for(curchunk=dchunkno;curchunk>=chunkno;curchunk--) {
1200
+                chunk=redata->chunks[curchunk];
1201
+                if(chunk->useddata==0) {
1202
+                        /* move this chunk to the end */
1203
+                        redata_chunk_deletechunk(redata,curchunk);
1204
+                } else
1205
+                        redata_fix_nl(redata,curchunk);
1206
+        }
1207
+        /* activate undo */
1208
+        if(fromhere!=&(redata->undostack)) {
1209
+                /* reactivate the undo, now it is fine */
1210
+                redata_undo_reactivatelast(redata,&(redata->undostack));
1211
+        }
1212
+        if(undo!=NULL) {
1213
+                /* new or from redo stack */
1214
+                undo->posorig=posorig;
1215
+                undo->posdest=posdest;
1216
+                redata_hash(redata,undo->posthash);
1217
+                if(fromhere==&(redata->redostack))
1218
+                        redata_undo_removelast(redata,&(redata->redostack));
1219
+                else
1220
+                        redata_undo_wipe(redata,&(redata->redostack));
1221
+        } else {
1222
+                /* from undo stack */
1223
+                redata_undo_movelast(redata,&(redata->undostack),&(redata->redostack));
1224
+        }
1225
+        /* compact if needed */
1226
+        if(redata_getsize(redata)>(redata->chunkdatasize) && redata_getavailable(redata)>(redata_getsize(redata)/2))
1227
+                redata_compact(redata);
1228
+        return(0);
1048 1229
 }
1049 1230
 
1050 1231
 int
... ...
@@ -1113,6 +1294,17 @@ redata_data_compare(redata_t *redata, long cmppos, char *buf, long buflen)
1113 1294
         return(0);
1114 1295
 }
1115 1296
 
1297
+int
1298
+redata_compact(redata_t *redata)
1299
+{
1300
+        /* compact and free surplus chunks */
1301
+        /* criterion: */
1302
+        /* 1. if two neighbouring chunks could join with 10% free in result chunk, do it */
1303
+        /* 2. if there are more than 2 unused chunks free at the end, free all unused chunks except two */
1304
+#warning TODO
1305
+        return(-1);
1306
+}
1307
+
1116 1308
 int
1117 1309
 redata_hash(redata_t *redata, char *resbuf129bytes)
1118 1310
 {
... ...
@@ -1315,3 +1507,29 @@ sep_select(char *buf, int bufsize, char **pos)
1315 1507
         return(seps[besti]);
1316 1508
 }
1317 1509
 
1510
+static void *
1511
+mymemrchr(const void *s, int c, size_t n)
1512
+{
1513
+        long i;
1514
+        void *res=NULL;
1515
+        unsigned char b;
1516
+        b=(*((unsigned int *)(&c)))&0xff;
1517
+        for(i=0;i<n;i++) {
1518
+                if(((unsigned char *)s)[i]==b)
1519
+                        res=(((unsigned char *)s)+i);        }
1520
+        return(res);
1521
+}
1522
+
1523
+static void
1524
+meminvert(void *start, void *end)
1525
+{
1526
+        unsigned char *a=(unsigned char *)start;
1527
+        unsigned char *b=(unsigned char *)end;
1528
+        unsigned char t;
1529
+        for(b=b-1;a<b;a++,b--) {
1530
+                t=*a;
1531
+                *a=*b;
1532
+                *b=t;
1533
+        }
1534
+}
1535
+
Browse code

Add del test

Dario Rodriguez authored on 15/03/2019 13:38:18
Showing 1 changed files
... ...
@@ -1096,7 +1096,7 @@ redata_data_compare(redata_t *redata, long cmppos, char *buf, long buflen)
1096 1096
         long compared;
1097 1097
         long n;
1098 1098
         int res;
1099
-        if(redata==NULL || pos<0 || buf==NULL || buflen<0
1099
+        if(redata==NULL || cmppos<0 || buf==NULL || buflen<0
1100 1100
           || cmppos>redata_getused(redata)
1101 1101
           || (cmppos+buflen)>redata_getused(redata))
1102 1102
                 return(-1); /* sanity check failed */
Browse code

recenteditor_data: change undo type from string to char (as it is in the unsaved buf)

Dario Rodriguez authored on 15/03/2019 13:21:58
Showing 1 changed files
... ...
@@ -39,6 +39,7 @@ static char *genname(char *filename,char *prefix, char *postfix, char *buf, int
39 39
 static char *ptr_getlong(char *ptr,char *endptr,long *data);
40 40
 static char *ptr_getchar(char *ptr,char *endptr,char *data);
41 41
 static char *ptr_searchendchar(char *ptr, char *endptr, char endchar, char **endcharpos);
42
+static char sep_select(char *buf, int bufsize, char **pos);
42 43
 
43 44
 redata_t *
44 45
 redata_init(void)
... ...
@@ -618,6 +619,7 @@ redata_unsaved_loadappend(redata_t *redata)
618 619
 int
619 620
 redata_unsaved_add(redata_t *redata, undo_t *undo)
620 621
 {
622
+
621 623
         /* separator is '$' , '@'  or '%' (whatever makes the longest string) */
622 624
         /* if len is omitted, then it goes inmediatly after the last op (probably there separator character was used in the string) */
623 625
 #warning TODO
... ...
@@ -631,6 +633,14 @@ redata_unsaved_unadd(redata_t *redata, undo_t *undo)
631 633
         return(-1);
632 634
 }
633 635
 
636
+int
637
+redata_unsaved_commit(redata_t *redata)
638
+{
639
+#warning TODO
640
+        return(-1);
641
+}
642
+
643
+
634 644
 int
635 645
 redata_load(redata_t *redata, char *filename, int use_unsaved)
636 646
 {
... ...
@@ -751,11 +761,11 @@ redata_undobuf_reserve(redata_t *redata, undostack_t *stack, int minavail)
751 761
 }
752 762
 
753 763
 undo_t *
754
-redata_undo_new(redata_t *redata, undostack_t *stack, char *type)
764
+redata_undo_new(redata_t *redata, undostack_t *stack, char type)
755 765
 {
756 766
         int newsize;
757 767
         undo_t *newptr,*undo;
758
-        if(redata==NULL || type==NULL
768
+        if(redata==NULL
759 769
           || (stack!=&(redata->undostack) && stack!=&(redata->redostack)))
760 770
                 return(NULL); /* sanity check failed */
761 771
         if(stack->sizeundo==stack->usedundo) {
... ...
@@ -769,15 +779,14 @@ redata_undo_new(redata_t *redata, undostack_t *stack, char *type)
769 779
         }
770 780
         undo=stack->undo+stack->usedundo;
771 781
         stack->usedundo++;
772
-        strncpy(undo->type,type,sizeof(undo->type));
773
-        undo->type[sizeof(undo->type)-1]='\0';
782
+        undo->type=type;
774 783
         undo->off=stack->usedbuf;
775 784
         undo->len=0;
776 785
         return(undo);
777 786
 }
778 787
 
779 788
 undo_t *
780
-redata_undo_newfromchunks(redata_t *redata, undostack_t *stack, char *type, int pos1, int len)
789
+redata_undo_newfromchunks(redata_t *redata, undostack_t *stack, char type, int pos1, int len)
781 790
 {
782 791
         int startpos,endpos;
783 792
         long startoff,endoff;
... ...
@@ -785,7 +794,7 @@ redata_undo_newfromchunks(redata_t *redata, undostack_t *stack, char *type, int
785 794
         int k;
786 795
         long used;
787 796
         long copyfrom,copysize;
788
-        if(redata==NULL || type==NULL || len<=0
797
+        if(redata==NULL || len<=0
789 798
           || (stack!=&(redata->undostack) && stack!=&(redata->redostack)))
790 799
                 return(NULL); /* sanity check failed */
791 800
         if(redata_getposptr(redata,pos1,&startpos,&startoff)==-1 ||
... ...
@@ -821,10 +830,10 @@ redata_undo_newfromchunks(redata_t *redata, undostack_t *stack, char *type, int
821 830
 }
822 831
 
823 832
 undo_t *
824
-redata_undo_newfrombuf(redata_t *redata, undostack_t *stack, char *type, char *buf, int buflen)
833
+redata_undo_newfrombuf(redata_t *redata, undostack_t *stack, char type, char *buf, int buflen)
825 834
 {
826 835
         undo_t *undo;
827
-        if(redata==NULL || type==NULL || buflen<=0
836
+        if(redata==NULL || buflen<=0
828 837
           || (stack!=&(redata->undostack) && stack!=&(redata->redostack)))
829 838
                 return(NULL); /* sanity check failed */
830 839
         if(redata_undobuf_reserve(redata,stack, buflen)!=0)
... ...
@@ -905,7 +914,7 @@ redata_op_add(redata_t *redata, long insertpos, char *buf, long buflen, undostac
905 914
         if(redata_getposptr(redata,insertpos,&chunkno,&pos)==-1)
906 915
                 return(-1); /* invalid pos */
907 916
         if(fromhere!=&(redata->undostack)) {
908
-                if((undo=redata_undo_newfrombuf(redata,&(redata->undostack),"ADD",buf,buflen))==NULL)
917
+                if((undo=redata_undo_newfrombuf(redata,&(redata->undostack),'A',buf,buflen))==NULL)
909 918
                         return(-1); /* couldn't create undo struct */
910 919
                 redata_hash(redata,undo->prehash);
911 920
         } else {
... ...
@@ -993,7 +1002,7 @@ redata_op_del(redata_t *redata, long delpos, long size, undostack_t *fromhere)
993 1002
         if(redata_getposptr(redata,delpos,&chunkno,&pos)==-1)
994 1003
                 return(-1); /* invalid pos */
995 1004
         if(fromhere!=&(redata->undostack)) {
996
-                if((undo=redata_undo_newfromchunks(redata,&(redata->undostack),"DEL",delpos,size))==NULL)
1005
+                if((undo=redata_undo_newfromchunks(redata,&(redata->undostack),'D',delpos,size))==NULL)
997 1006
                         return(-1); /* couldn't create undo struct */
998 1007
                 redata_hash(redata,undo->prehash);
999 1008
         } else {
... ...
@@ -1046,11 +1055,11 @@ redata_op_undo(redata_t *redata)
1046 1055
           || redata->undostack.usedundo<1)
1047 1056
                 return(-1); /* sanity check failed */
1048 1057
         undo=redata->undostack.undo+redata->undostack.usedundo-1;
1049
-        if(strcmp(undo->type,"ADD")==0) {
1058
+        if(undo->type=='A') { /* ADD */
1050 1059
                 redata_op_del(redata,undo->posorig,undo->len,&(redata->undostack));
1051
-        } else if(strcmp(undo->type,"DEL")==0) {
1060
+        } else if(undo->type=='D') { /* DEL */
1052 1061
                 redata_op_add(redata,undo->posorig,redata->undostack.buf+undo->off,undo->len,&(redata->undostack));
1053
-        } else if(strcmp(undo->type,"MOV")==0) {
1062
+        } else if(undo->type=='M') { /* MOVE */
1054 1063
                 if(undo->posorig<undo->posdest)
1055 1064
                         redata_op_move(redata,undo->posdest-undo->len, undo->len, undo->posorig,&(redata->undostack));
1056 1065
                 else
... ...
@@ -1068,11 +1077,11 @@ redata_op_redo(redata_t *redata)
1068 1077
           || redata->redostack.usedundo<1)
1069 1078
                 return(-1); /* sanity check failed */
1070 1079
         undo=redata->redostack.undo+redata->redostack.usedundo-1;
1071
-        if(strcmp(undo->type,"ADD")==0) {
1080
+        if(undo->type=='A') { /* ADD */
1072 1081
                 redata_op_add(redata,undo->posorig,redata->redostack.buf+undo->off,undo->len,&(redata->redostack));
1073
-        } else if(strcmp(undo->type,"DEL")==0) {
1082
+        } else if(undo->type=='D') { /* DEL */
1074 1083
                 redata_op_del(redata,undo->posorig,undo->len,&(redata->redostack));
1075
-        } else if(strcmp(undo->type,"MOV")==0) {
1084
+        } else if(undo->type=='M') { /* MOVE */
1076 1085
                 redata_op_move(redata,undo->posorig, undo->len, undo->posdest,&(redata->redostack));
1077 1086
         } else
1078 1087
                 return(-1); /* unknown operation */
... ...
@@ -1284,3 +1293,25 @@ ptr_searchendchar(char *ptr, char *endptr, char endchar, char **endcharpos)
1284 1293
         return(aux+1);
1285 1294
 }
1286 1295
 
1296
+static char
1297
+sep_select(char *buf, int bufsize, char **pos)
1298
+{
1299
+        static char seps[]={"$%@!|&/='\"^*;:,-_"};
1300
+        char *ptr,*bestptr;
1301
+        int i,besti;
1302
+        bestptr=buf;
1303
+        if(pos!=NULL)
1304
+                *pos=NULL;
1305
+        for(i=0,besti=0;i<sizeof(seps);i++) {
1306
+                if((ptr=memchr(buf,seps[i],bufsize))==NULL)
1307
+                        return(seps[i]);
1308
+                if(ptr>bestptr) {
1309
+                        besti=0;
1310
+                        bestptr=ptr;
1311
+                }
1312
+        }
1313
+        if(pos!=NULL)
1314
+                *pos=bestptr;
1315
+        return(seps[besti]);
1316
+}
1317
+
Browse code

unsaved_loadappend: implement loading of A(dd) and D(el) registers

Dario Rodriguez authored on 14/03/2019 22:37:34
Showing 1 changed files
... ...
@@ -36,6 +36,9 @@ static int redata_unsaved_check_gen(redata_t *redata, char *filename);
36 36
 static char *unsaved_genname(char *filename, char *buf, int bufsize);
37 37
 static char *securesave_genname(char *filename, char *buf, int bufsize);
38 38
 static char *genname(char *filename,char *prefix, char *postfix, char *buf, int bufsize);
39
+static char *ptr_getlong(char *ptr,char *endptr,long *data);
40
+static char *ptr_getchar(char *ptr,char *endptr,char *data);
41
+static char *ptr_searchendchar(char *ptr, char *endptr, char endchar, char **endcharpos);
39 42
 
40 43
 redata_t *
41 44
 redata_init(void)
... ...
@@ -57,6 +60,8 @@ redata_init(void)
57 60
         /* unsaved */
58 61
         redata->filename[0]='\0';
59 62
         redata->unsavedfd=-1;
63
+        redata->unsaved.sizebuf=redata->unsaved.usedbuf=0;
64
+        redata->unsaved.lastsize=0;
60 65
         /* all done */
61 66
         return(redata);
62 67
 }
... ...
@@ -472,7 +477,7 @@ int
472 477
 redata_unsaved_check(redata_t *redata, char *filename)
473 478
 {
474 479
         int fd;
475
-        if((fd=redata_unsaved_check(redata,filename))==-1)
480
+        if((fd=redata_unsaved_check_gen(redata,filename))==-1)
476 481
                 return(-1); /* check failed */
477 482
         close(fd),fd=-1;
478 483
         return(0);
... ...
@@ -519,6 +524,7 @@ redata_unsaved_trunc(redata_t *redata)
519 524
         return(0);
520 525
 }
521 526
 
527
+
522 528
 int
523 529
 redata_unsaved_loadappend(redata_t *redata)
524 530
 {
... ...
@@ -528,7 +534,12 @@ redata_unsaved_loadappend(redata_t *redata)
528 534
         long headerhashsize;
529 535
         char *newptr;
530 536
         long nread,lim;
531
-        if((fd=redata_unsaved_check(redata,redata->filename))==-1)
537
+        char *ptr,*endptr,*aux,*bufptr;
538
+        char actioncode;
539
+        long pos;
540
+        char endcode;
541
+        int flag_multipart;
542
+        if((fd=redata_unsaved_check_gen(redata,redata->filename))==-1)
532 543
                 return(-1); /* check failed */
533 544
         if(fstat(fd,&statbuf)!=0 || !S_ISREG(statbuf.st_mode)) {
534 545
                 close(fd),fd=-1;
... ...
@@ -556,7 +567,50 @@ redata_unsaved_loadappend(redata_t *redata)
556 567
         }
557 568
         close(fd),fd=-1;
558 569
         /* process unsaved data */
570
+        endptr=redata->unsaved.buf+redata->unsaved.usedbuf;
571
+        for(ptr=redata->unsaved.buf;ptr<endptr;) {
572
+                if((ptr=ptr_getchar(ptr,endptr,&actioncode))==NULL)
573
+                        return(-1); /* no space for action char */
574
+                /* multipart example: A10+$aj$%$% >> insert "aj$" into pos 10 */
575
+                if(actioncode=='A') {
576
+                        ptr=ptr_getlong(ptr,endptr,&pos);
577
+                        do {
578
+                                flag_multipart=0;
579
+                                ptr=ptr_getchar(ptr,endptr,&endcode);
580
+                                if(ptr!=NULL && endcode=='+') {
581
+                                        flag_multipart=1;
582
+                                        ptr=ptr_getchar(ptr,endptr,&endcode);
583
+                                }
584
+                                bufptr=ptr;
585
+                                ptr=ptr_searchendchar(ptr,endptr,endcode,&aux);
586
+                                if(ptr==NULL || pos<0 || pos>redata_getused(redata))
587
+                                        return(-1); /* malformed register */
588
+                                redata_op_add(redata,pos,bufptr,aux-bufptr,NULL);
589
+                                pos+=aux-bufptr;
590
+                        } while(flag_multipart);
591
+                } else if(actioncode=='D') {
592
+                        ptr=ptr_getlong(ptr,endptr,&pos);
593
+                        do {
594
+                                flag_multipart=0;
595
+                                ptr=ptr_getchar(ptr,endptr,&endcode);
596
+                                if(ptr!=NULL && endcode=='+') {
597
+                                        flag_multipart=1;
598
+                                        ptr=ptr_getchar(ptr,endptr,&endcode);
599
+                                }
600
+                                bufptr=ptr;
601
+                                ptr=ptr_searchendchar(ptr,endptr,endcode,&aux);
602
+                                if(ptr==NULL || pos<0 || (pos+(aux-bufptr))>redata_getused(redata))
603
+                                        return(-1); /* malformed register */
604
+                                if(redata_data_compare(redata,pos,bufptr,aux-bufptr)!=0)
605
+                                        return(-1); /* corrupted data */
606
+                                redata_op_del(redata,pos,aux-bufptr,NULL);
607
+                        } while(flag_multipart);
608
+                } else if(actioncode=='M') {
559 609
 #warning TODO
610
+                } else {
611
+                        return(-1); /* corrupted undobuf */
612
+                }
613
+        }
560 614
         return(-1);
561 615
 }
562 616
 
... ...
@@ -1025,6 +1079,31 @@ redata_op_redo(redata_t *redata)
1025 1079
         return(-1);
1026 1080
 }
1027 1081
 
1082
+int
1083
+redata_data_compare(redata_t *redata, long cmppos, char *buf, long buflen)
1084
+{
1085
+        int chunkno;
1086
+        long pos;
1087
+        long compared;
1088
+        long n;
1089
+        int res;
1090
+        if(redata==NULL || pos<0 || buf==NULL || buflen<0
1091
+          || cmppos>redata_getused(redata)
1092
+          || (cmppos+buflen)>redata_getused(redata))
1093
+                return(-1); /* sanity check failed */
1094
+        if(redata_getposptr(redata,cmppos,&chunkno,&pos)==-1)
1095
+                return(-1); /* invalid pos */
1096
+        for(compared=0,n=0;compared<buflen && chunkno<redata->sizechunks;chunkno++,pos=0,compared+=n) {
1097
+                n=redata->chunks[chunkno]->useddata-pos;
1098
+                n=(n<0)?0:((compared+n)>buflen)?(buflen-compared):n;
1099
+                if((res=memcmp(redata->chunks[chunkno]->data+pos,buf+compared,n))!=0)
1100
+                        return(res);
1101
+        }
1102
+        if(compared<buflen)
1103
+                return(1);
1104
+        return(0);
1105
+}
1106
+
1028 1107
 int
1029 1108
 redata_hash(redata_t *redata, char *resbuf129bytes)
1030 1109
 {
... ...
@@ -1159,4 +1238,49 @@ genname(char *filename,char *prefix, char *postfix, char *buf, int bufsize)
1159 1238
         return(name);
1160 1239
 }
1161 1240
 
1241
+static char *
1242
+ptr_getlong(char *ptr,char *endptr,long *data)
1243
+{
1244
+        long l,s;
1245
+        if(ptr==NULL || endptr==NULL || ptr>endptr)
1246
+                return(NULL);
1247
+        s=1;
1248
+        if(ptr<endptr && *ptr=='-') {
1249
+                s=-1;
1250
+                ptr++;
1251
+        }
1252
+        for(l=0;ptr<endptr && *ptr>='0' && *ptr<='9';ptr++) {
1253
+                l*=10;
1254
+                l+=(*ptr-'0');
1255
+        }
1256
+        l*=s;
1257
+        if(data!=NULL)
1258
+                *data=l;
1259
+        return(ptr);
1260
+}
1261
+
1262
+
1263
+static char *
1264
+ptr_getchar(char *ptr,char *endptr,char *data)
1265
+{
1266
+        if(ptr==NULL || endptr==NULL || ptr>endptr)
1267
+                return(NULL);
1268
+        if(data!=NULL)
1269
+                *data=*ptr;
1270
+        ptr++;
1271
+        return(ptr);
1272
+}
1273
+
1274
+static char *
1275
+ptr_searchendchar(char *ptr, char *endptr, char endchar, char **endcharpos)
1276
+{
1277
+        char *aux;
1278
+        if(ptr==NULL || endptr==NULL || ptr>endptr)
1279
+                return(NULL);
1280
+        if((aux=memchr(ptr,endchar,endptr-ptr))==NULL)
1281
+                return(NULL);
1282
+        if(endcharpos!=NULL)
1283
+                *endcharpos=aux;
1284
+        return(aux+1);
1285
+}
1162 1286
 
Browse code

partial unsaved implementation

Dario Rodriguez authored on 13/03/2019 23:31:53
Showing 1 changed files
... ...
@@ -29,10 +29,10 @@
29 29
 #define UNSAVEDPOSTFIX ".reu"
30 30
 #define SECURESAVEPREFIX "."
31 31
 #define SECURESAVEPOSTFIX ".saving"
32
-#define UNSAVEDHEADER "REUNSAV\n"
33
-#define UNSAVEDVERSION "\n000001\0"
32
+#define UNSAVEDHEADER "reunsaved00,"
34 33
 
35 34
 static int redata_hash_gen(redata_t *redata, char *filename, char *buf, long buflen, char *resbuf129bytes);
35
+static int redata_unsaved_check_gen(redata_t *redata, char *filename);
36 36
 static char *unsaved_genname(char *filename, char *buf, int bufsize);
37 37
 static char *securesave_genname(char *filename, char *buf, int bufsize);
38 38
 static char *genname(char *filename,char *prefix, char *postfix, char *buf, int bufsize);
... ...
@@ -57,7 +57,6 @@ redata_init(void)
57 57
         /* unsaved */
58 58
         redata->filename[0]='\0';
59 59
         redata->unsavedfd=-1;
60
-        redata->flag_unsaveddata=0;
61 60
         /* all done */
62 61
         return(redata);
63 62
 }
... ...
@@ -84,13 +83,22 @@ redata_free(redata_t *redata)
84 83
                 free(redata->undostack.undo),redata->undostack.undo=NULL;
85 84
         if(redata->undostack.buf!=NULL)
86 85
                 free(redata->undostack.buf),redata->undostack.buf=NULL;
86
+        /* redo */
87
+        if(redata->redostack.undo!=NULL)
88
+                free(redata->redostack.undo),redata->redostack.undo=NULL;
89
+        if(redata->redostack.buf!=NULL)
90
+                free(redata->redostack.buf),redata->redostack.buf=NULL;
87 91
         /* unsaved */
88 92
         if(redata->unsavedfd!=-1) {
89 93
                 close(redata->unsavedfd),redata->unsavedfd=-1;
90 94
                 if(unsaved_genname(redata->filename,unsname,sizeof(unsname))!=NULL)
91 95
                         unlink(unsname);
92 96
         }
93
-        redata->flag_unsaveddata=0;
97
+        if(redata->unsaved.buf!=NULL) {
98
+                free(redata->unsaved.buf),redata->unsaved.buf=NULL;
99
+                redata->unsaved.sizebuf=redata->unsaved.usedbuf=0;
100
+                redata->unsaved.lastsize=0;
101
+        }
94 102
         /* free main struct */
95 103
         free(redata),redata=NULL;
96 104
         return;
... ...
@@ -171,8 +179,8 @@ redata_wipe(redata_t *redata)
171 179
                 if(unsaved_genname(redata->filename,unsname,sizeof(unsname))!=NULL)
172 180
                         unlink(unsname);
173 181
         }
174
-        redata->flag_unsaveddata=0;
175 182
         redata->filename[0]='\0';
183
+        redata->unsaved.usedbuf=0;
176 184
         /* all done */
177 185
         return(0);
178 186
 }
... ...
@@ -427,14 +435,14 @@ redata_unsaved_exists(redata_t *redata, char *filename)
427 435
         return(0);
428 436
 }
429 437
 
430
-int
431
-redata_unsaved_check(redata_t *redata, char *filename)
438
+static int
439
+redata_unsaved_check_gen(redata_t *redata, char *filename)
432 440
 {
433 441
         char unsname[PATH_MAX+1];
434 442
         int fd,nread;
435
-        static char header[9]={UNSAVEDHEADER};
436
-        static char version[9]={UNSAVEDVERSION};
437
-        char filehash[129],undohash[129],buf[64];
443
+        static char header[]={UNSAVEDHEADER};
444
+        char filehash[129],undohash[129],buf[16];
445
+        char fileheader[]={UNSAVEDHEADER};
438 446
         if(redata==NULL || filename==NULL)
439 447
                 return(-1); /* sanity check failed */
440 448
         if((unsaved_genname(filename,unsname,sizeof(unsname)))==NULL)
... ...
@@ -443,7 +451,9 @@ redata_unsaved_check(redata_t *redata, char *filename)
443 451
                 return(-1);
444 452
         if((fd=open(unsname,O_RDONLY))==-1)
445 453
                 return(-1);
446
-        if((nread=read(fd,buf,8))==-1 || nread!=8 || memcmp(buf,header,8)!=0) {
454
+        memset(fileheader,0,sizeof(fileheader));
455
+        if((nread=read(fd,fileheader,sizeof(fileheader)-1))==-1
456
+          || nread!=(sizeof(fileheader)-1) || memcmp(fileheader,header,sizeof(fileheader))!=0) {
447 457
                 close(fd),fd=-1;
448 458
                 return(-1); /* corrupted header */
449 459
         }
... ...
@@ -451,10 +461,19 @@ redata_unsaved_check(redata_t *redata, char *filename)
451 461
                 close(fd),fd=-1;
452 462
                 return(-1); /* wrong hash */
453 463
         }
454
-        if((nread=read(fd,buf,8))==-1 || nread!=8 || memcmp(buf,version,8)!=0) {
464
+        if((nread=read(fd,buf,1))==-1 || nread!=1 || *buf!=',') {
455 465
                 close(fd),fd=-1;
456
-                return(-1); /* wrong version */
466
+                return(-1); /* wrong hash separator */
457 467
         }
468
+        return(fd);
469
+}
470
+
471
+int
472
+redata_unsaved_check(redata_t *redata, char *filename)
473
+{
474
+        int fd;
475
+        if((fd=redata_unsaved_check(redata,filename))==-1)
476
+                return(-1); /* check failed */
458 477
         close(fd),fd=-1;
459 478
         return(0);
460 479
 }
... ...
@@ -474,28 +493,28 @@ redata_unsaved_unlink(redata_t *redata)
474 493
         return(0);
475 494
 }
476 495
 
477
-
478
-
479 496
 int
480 497
 redata_unsaved_trunc(redata_t *redata)
481 498
 {
482 499
         char unsname[PATH_MAX+1];
483
-        static char header[9]={UNSAVEDHEADER};
484
-        static char version[9]={UNSAVEDVERSION};
500
+        static char header[]={UNSAVEDHEADER};
485 501
         int n;
486 502
         if(redata==NULL || redata->filename[0]=='\0')
487 503
                 return(-1); /* sanity check failed */
488 504
         redata_unsaved_unlink(redata);
489 505
         if((unsaved_genname(redata->filename,unsname,sizeof(unsname)))==NULL)
490 506
                 return(-1); /* malformed filename */
507
+        if(redata->unsavedfd!=-1)
508
+                close(redata->unsavedfd),redata->unsavedfd=-1;
491 509
         if((redata->unsavedfd=open(unsname,O_WRONLY|O_TRUNC|O_CREAT,0644))==-1)
492 510
                 return(-1); /* couldn't open file for writing */
493
-        if((n=write(redata->unsavedfd,header,8))==-1 || n!=8 ||
494
-          (n=write(redata->unsavedfd,redata->initialhash,128))==-1 || n!=128 ||
495
-          (n=write(redata->unsavedfd,version,8))==-1 || n!=8) {
511
+        if((n=write(redata->unsavedfd,header,sizeof(header)-1))==-1
512
+          || n!=(sizeof(header)-1)
513
+          || (n=write(redata->unsavedfd,redata->initialhash,128))==-1 || n!=128
514
+          || (n=write(redata->unsavedfd,",",1))==-1 || n!=1) {
496 515
                 close(redata->unsavedfd),redata->unsavedfd=-1;
497 516
                 unlink(unsname);
498
-                return(-1); /* couldn't write header/hash/version */
517
+                return(-1); /* couldn't write header/hash */
499 518
         }
500 519
         return(0);
501 520
 }
... ...
@@ -503,6 +522,40 @@ redata_unsaved_trunc(redata_t *redata)
503 522
 int
504 523
 redata_unsaved_loadappend(redata_t *redata)
505 524
 {
525
+        int fd;
526
+        struct stat statbuf;
527
+        static char header[]={UNSAVEDHEADER};
528
+        long headerhashsize;
529
+        char *newptr;
530
+        long nread,lim;
531
+        if((fd=redata_unsaved_check(redata,redata->filename))==-1)
532
+                return(-1); /* check failed */
533
+        if(fstat(fd,&statbuf)!=0 || !S_ISREG(statbuf.st_mode)) {
534
+                close(fd),fd=-1;
535
+                return(-1); /* couldn't query size or not regular file */
536
+        }
537
+        headerhashsize=(sizeof(header)-1)+1+128+1;
538
+        /* load unsaved to memory */
539
+        if(redata->unsaved.sizebuf<(statbuf.st_size-headerhashsize)) {
540
+                if((newptr=realloc(redata->unsaved.buf,(statbuf.st_size-headerhashsize)))==NULL) {
541
+                        close(fd),fd=-1;
542
+                        return(-1); /* insuf. mem. */
543
+                }
544
+                redata->unsaved.buf=newptr;
545
+                redata->unsaved.sizebuf=(statbuf.st_size-headerhashsize);
546
+        }
547
+        redata->unsaved.lastsize=0;
548
+        redata->unsaved.usedbuf=0;
549
+        lim=(statbuf.st_size-headerhashsize);
550
+        for(nread=0;redata->unsaved.usedbuf<lim;redata->unsaved.usedbuf+=nread,nread=0) {
551
+                if((nread=read(fd,redata->unsaved.buf+redata->unsaved.usedbuf,lim-redata->unsaved.usedbuf))<=0) {
552
+                        redata->unsaved.usedbuf=0;
553
+                        close(fd),fd=-1;
554
+                        return(-1); /* short read */
555
+                }
556
+        }
557
+        close(fd),fd=-1;
558
+        /* process unsaved data */
506 559
 #warning TODO
507 560
         return(-1);
508 561
 }
... ...
@@ -511,6 +564,8 @@ redata_unsaved_loadappend(redata_t *redata)
511 564
 int
512 565
 redata_unsaved_add(redata_t *redata, undo_t *undo)
513 566
 {
567
+        /* separator is '$' , '@'  or '%' (whatever makes the longest string) */
568
+        /* if len is omitted, then it goes inmediatly after the last op (probably there separator character was used in the string) */
514 569
 #warning TODO
515 570
         return(-1);
516 571
 }
... ...
@@ -615,8 +670,8 @@ redata_save(redata_t *redata, char *filename)
615 670
                 return(-1); /* couldn't overwrite old file */
616 671
         }
617 672
         redata_unsaved_unlink(redata);
618
-        redata->flag_unsaveddata=0;
619 673
         redata_hash(redata,redata->initialhash);
674
+        redata->unsaved.usedbuf=0;
620 675
         return(0);
621 676
 }
622 677
 
Browse code

implementation of op_del, op_undo, op_redo

Dario Rodriguez authored on 13/03/2019 17:07:30
Showing 1 changed files
... ...
@@ -197,6 +197,25 @@ redata_chunk_insertnew(redata_t *redata, int afterthischunk)
197 197
         return(0);
198 198
 }
199 199
 
200
+int
201
+redata_chunk_deletechunk(redata_t *redata, int chunkno)
202
+{
203
+        rechunk_t *chunk;
204
+        int i;
205
+        if(redata==NULL || chunkno<0 || chunkno>=redata->sizechunks)
206
+                return(-1);
207
+        chunk=redata->chunks[chunkno];
208
+        if(chunk->useddata>0) {
209
+                redata->available+=chunk->useddata;
210
+                chunk->useddata=0;
211
+                chunk->whatin_fresh=0;
212
+        }
213
+        for(i=chunkno;(i+1)<redata->sizechunks;i++)
214
+                redata->chunks[i]=redata->chunks[i+1];
215
+        redata->chunks[redata->sizechunks-1]=chunk;
216
+        return(0);
217
+}
218
+
200 219
 
201 220
 int
202 221
 redata_preallocate(redata_t *redata, long newsize)
... ...
@@ -297,6 +316,7 @@ redata_chunk_insertdata(redata_t *redata, int chunkto, long posto, char *buf, lo
297 316
         memcpy(chunk->data+posto,buf,buflen);
298 317
         chunk->useddata+=buflen;
299 318
         chunk->whatin_fresh=0;
319
+        redata->available-=buflen;
300 320
         return(0);
301 321
 }
302 322
 
... ...
@@ -315,6 +335,7 @@ redata_chunk_deletedata(redata_t *redata, int chunkno, long pos, long n)
315 335
         memmove(chunk->data+pos,chunk->data+pos+n,chunk->useddata-pos-n);
316 336
         chunk->useddata-=n;
317 337
         chunk->whatin_fresh=0;
338
+        redata->available+=n;
318 339
         return(0);
319 340
 }
320 341
 
... ...
@@ -713,7 +734,7 @@ redata_undo_movelast(redata_t *redata, undostack_t *from, undostack_t *to)
713 734
 {
714 735
         undo_t *undofrom;
715 736
         undo_t *undoto;
716
-        if(redata==NULL || from!=to
737
+        if(redata==NULL || from==to
717 738
           || (from!=&(redata->undostack) && from!=&(redata->redostack))
718 739
           || (to!=&(redata->undostack) && to!=&(redata->redostack))
719 740
           || from->usedundo<1)
... ...
@@ -758,7 +779,7 @@ redata_undo_wipe(redata_t *redata, undostack_t *stack)
758 779
 }
759 780
 
760 781
 int
761
-redata_op_add(redata_t *redata, int insertpos, char *buf, int buflen, undostack_t *fromhere)
782
+redata_op_add(redata_t *redata, long insertpos, char *buf, long buflen, undostack_t *fromhere)
762 783
 {
763 784
         int chunkno;
764 785
         long pos;
... ...
@@ -804,6 +825,7 @@ redata_op_add(redata_t *redata, int insertpos, char *buf, int buflen, undostack_
804 825
                 needed+=(chunk->useddata-pos);
805 826
                 if(redata_preallocate(redata,redata_getsize(redata)+needed)!=0) {
806 827
                         if(undo!=NULL) {
828
+                                redata->undostack.usedundo--;
807 829
                                 redata->undostack.usedbuf-=buflen;
808 830
                                 memset(undo,0,sizeof(undo_t));
809 831
                         }
... ...
@@ -834,7 +856,6 @@ redata_op_add(redata_t *redata, int insertpos, char *buf, int buflen, undostack_
834 856
                 /* new or from redo stack */
835 857
                 undo->posorig=undo->posdest=insertpos;
836 858
                 redata_hash(redata,undo->posthash);
837
-                redata->undostack.usedundo++;
838 859
                 if(fromhere==&(redata->redostack))
839 860
                         redata_undo_removelast(redata,&(redata->redostack));
840 861
                 else
... ...
@@ -847,14 +868,62 @@ redata_op_add(redata_t *redata, int insertpos, char *buf, int buflen, undostack_
847 868
 }
848 869
 
849 870
 int
850
-redata_op_del(redata_t *redata, int pos, int size, undostack_t *fromhere)
871
+redata_op_del(redata_t *redata, long delpos, long size, undostack_t *fromhere)
851 872
 {
852
-#warning TODO
853
-        return(-1);
873
+        int chunkno,curchunk;
874
+        long pos;
875
+        undo_t *undo;
876
+        rechunk_t *chunk;
877
+        long ndel;
878
+        long curpos,curdel;
879
+        if(redata==NULL || size<0
880
+          || delpos>redata_getused(redata)
881
+          || (delpos+size)>redata_getused(redata)
882
+          || (fromhere!=NULL && (fromhere!=&(redata->undostack) && fromhere!=&(redata->redostack))))
883
+                return(-1); /* sanity check failed */
884
+        if(redata_getposptr(redata,delpos,&chunkno,&pos)==-1)
885
+                return(-1); /* invalid pos */
886
+        if(fromhere!=&(redata->undostack)) {
887
+                if((undo=redata_undo_newfromchunks(redata,&(redata->undostack),"DEL",delpos,size))==NULL)
888
+                        return(-1); /* couldn't create undo struct */
889
+                redata_hash(redata,undo->prehash);
890
+        } else {
891
+                undo=NULL;
892
+        }
893
+        for(curchunk=chunkno,ndel=0;ndel<size;curchunk++) {
894
+                curpos=(curchunk==chunkno)?pos:0;
895
+                curdel=redata->chunks[curchunk]->useddata-curpos;
896
+                curdel=(curdel>(size-ndel))?(size-ndel):curdel;
897
+                redata_chunk_deletedata(redata,chunkno,curpos,curdel);
898
+                ndel+=curdel;
899
+        }
900
+        /* fix nl and delete unused chunks */
901
+        for(curchunk--;curchunk>=chunkno;curchunk--) {
902
+                chunk=redata->chunks[curchunk];
903
+                if(chunk->useddata==0) {
904
+                        /* move this chunk to the end */
905
+                        redata_chunk_deletechunk(redata,curchunk);
906
+                } else
907
+                        redata_fix_nl(redata,curchunk);
908
+        }
909
+        /* activate undo */
910
+        if(undo!=NULL) {
911
+                /* new or from redo stack */
912
+                undo->posorig=undo->posdest=delpos;
913
+                redata_hash(redata,undo->posthash);
914
+                if(fromhere==&(redata->redostack))
915
+                        redata_undo_removelast(redata,&(redata->redostack));
916
+                else
917
+                        redata_undo_wipe(redata,&(redata->redostack));
918
+        } else {
919
+                /* from undo stack */
920
+                redata_undo_movelast(redata,&(redata->undostack),&(redata->redostack));
921
+        }
922
+        return(0);
854 923
 }
855 924
 
856 925
 int
857
-redata_op_move(redata_t *redata, int posorig, int size, int posdest, undostack_t *fromhere)
926
+redata_op_move(redata_t *redata, long posorig, long size, long posdest, undostack_t *fromhere)
858 927
 {
859 928
 #warning TODO
860 929
         return(-1);
Browse code

op_undo and op_redo

Dario Rodriguez authored on 12/03/2019 15:35:30
Showing 1 changed files
... ...
@@ -873,20 +873,31 @@ redata_op_undo(redata_t *redata)
873 873
         } else if(strcmp(undo->type,"DEL")==0) {
874 874
                 redata_op_add(redata,undo->posorig,redata->undostack.buf+undo->off,undo->len,&(redata->undostack));
875 875
         } else if(strcmp(undo->type,"MOV")==0) {
876
-#warning TODO
876
+                if(undo->posorig<undo->posdest)
877
+                        redata_op_move(redata,undo->posdest-undo->len, undo->len, undo->posorig,&(redata->undostack));
878
+                else
879
+                        redata_op_move(redata,undo->posdest, undo->len, undo->posorig+undo->len,&(redata->undostack));
877 880
         } else
878 881
                 return(-1); /* unknown operation */
879
- #warning TODO
880 882
         return(-1);
881 883
 }
882 884
 
883 885
 int
884 886
 redata_op_redo(redata_t *redata)
885 887
 {
888
+        undo_t *undo;
886 889
         if(redata==NULL
887 890
           || redata->redostack.usedundo<1)
888 891
                 return(-1); /* sanity check failed */
889
-#warning TODO
892
+        undo=redata->redostack.undo+redata->redostack.usedundo-1;
893
+        if(strcmp(undo->type,"ADD")==0) {
894
+                redata_op_add(redata,undo->posorig,redata->redostack.buf+undo->off,undo->len,&(redata->redostack));
895
+        } else if(strcmp(undo->type,"DEL")==0) {
896
+                redata_op_del(redata,undo->posorig,undo->len,&(redata->redostack));
897
+        } else if(strcmp(undo->type,"MOV")==0) {
898
+                redata_op_move(redata,undo->posorig, undo->len, undo->posdest,&(redata->redostack));
899
+        } else
900
+                return(-1); /* unknown operation */
890 901
         return(-1);
891 902
 }
892 903
 
Browse code

Changes to support files larger than 2GB

Dario Rodriguez authored on 12/03/2019 15:17:21
Showing 1 changed files
... ...
@@ -32,7 +32,7 @@
32 32
 #define UNSAVEDHEADER "REUNSAV\n"
33 33
 #define UNSAVEDVERSION "\n000001\0"
34 34
 
35
-static int redata_hash_gen(redata_t *redata, char *filename, char *buf, int buflen, char *resbuf129bytes);
35
+static int redata_hash_gen(redata_t *redata, char *filename, char *buf, long buflen, char *resbuf129bytes);
36 36
 static char *unsaved_genname(char *filename, char *buf, int bufsize);
37 37
 static char *securesave_genname(char *filename, char *buf, int bufsize);
38 38
 static char *genname(char *filename,char *prefix, char *postfix, char *buf, int bufsize);
... ...
@@ -106,7 +106,7 @@ redata_config_chunkdatasize(redata_t *redata, int chunkdatasize)
106 106
         return(0);
107 107
 }
108 108
 
109
-int
109
+long
110 110
 redata_getsize(redata_t *redata)
111 111
 {
112 112
         if(redata==NULL)
... ...
@@ -114,7 +114,7 @@ redata_getsize(redata_t *redata)
114 114
         return(redata->chunkdatasize*redata->sizechunks);
115 115
 }
116 116
 
117
-int
117
+long
118 118
 redata_getavailable(redata_t *redata)
119 119
 {
120 120
         if(redata==NULL)
... ...
@@ -122,10 +122,10 @@ redata_getavailable(redata_t *redata)
122 122
         return(redata->available);
123 123
 }
124 124
 
125
-int
125
+long
126 126
 redata_getused(redata_t *redata)
127 127
 {
128
-        int used;
128
+        long used;
129 129
         if(redata==NULL)
130 130
                 return(0); /* sanity check failed */
131 131
         used=redata->chunkdatasize*redata->sizechunks-redata->available;
... ...
@@ -133,11 +133,11 @@ redata_getused(redata_t *redata)
133 133
 }
134 134
 
135 135
 int
136
-redata_getposptr(redata_t *redata, int pos, int *numchunk, int *offset)
136
+redata_getposptr(redata_t *redata, long pos, int *numchunk, long *offset)
137 137
 {
138
-        int used;
138
+        long used;
139 139
         int i;
140
-        int ipos;
140
+        long ipos;
141 141
         used=redata_getused(redata);
142 142
         if(redata==NULL || pos<0 || pos>used || numchunk==NULL || offset==NULL)
143 143
                 return(-1); /* sanity check failed */
... ...
@@ -199,12 +199,12 @@ redata_chunk_insertnew(redata_t *redata, int afterthischunk)
199 199
 
200 200
 
201 201
 int
202
-redata_preallocate(redata_t *redata, int newsize)
202
+redata_preallocate(redata_t *redata, long newsize)
203 203
 {
204
-        int cursize;
204
+        long cursize;
205 205
         int nchunks;
206 206
         int i;
207
-        int rechunksize;
207
+        long rechunksize;
208 208
         rechunk_t **newchunks,*chunk;
209 209
         int oldsizechunks;
210 210
         if(redata==NULL || redata->chunkdatasize==0 || newsize<0)
... ...
@@ -238,7 +238,7 @@ redata_preallocate(redata_t *redata, int newsize)
238 238
 }
239 239
 
240 240
 int
241
-redata_chunk_movedata(redata_t *redata, int chunkfrom, int posfrom, int chunkto, int posto, int size)
241
+redata_chunk_movedata(redata_t *redata, int chunkfrom, long posfrom, int chunkto, long posto, long size)
242 242
 {
243 243
         if(redata==NULL || size<0
244 244
           || chunkfrom<0 || chunkfrom>=redata->sizechunks
... ...
@@ -284,7 +284,7 @@ redata_chunk_movedata(redata_t *redata, int chunkfrom, int posfrom, int chunkto,
284 284
 }
285 285
 
286 286
 int
287
-redata_chunk_insertdata(redata_t *redata, int chunkto, int posto, char *buf, int buflen)
287
+redata_chunk_insertdata(redata_t *redata, int chunkto, long posto, char *buf, long buflen)
288 288
 {
289 289
         rechunk_t *chunk;
290 290
         if(redata==NULL || buflen<0 || buf==NULL
... ...
@@ -301,7 +301,7 @@ redata_chunk_insertdata(redata_t *redata, int chunkto, int posto, char *buf, int
301 301
 }
302 302
 
303 303
 int
304
-redata_chunk_deletedata(redata_t *redata, int chunkno, int pos, int n)
304
+redata_chunk_deletedata(redata_t *redata, int chunkno, long pos, long n)
305 305
 {
306 306
         rechunk_t *chunk;
307 307
         if(redata==NULL || n<0
... ...
@@ -342,7 +342,7 @@ redata_whatin_refresh(redata_t *redata, int chunkno)
342 342
 void *
343 343
 mymemrchr(const void *s, int c, size_t n)
344 344
 {
345
-        int i;
345
+        long i;
346 346
         void *res=NULL;
347 347
         unsigned char b;
348 348
         b=(*((unsigned int *)(&c)))&0xff;
... ...
@@ -649,11 +649,12 @@ redata_undo_new(redata_t *redata, undostack_t *stack, char *type)
649 649
 undo_t *
650 650
 redata_undo_newfromchunks(redata_t *redata, undostack_t *stack, char *type, int pos1, int len)
651 651
 {
652
-        int startpos,startoff,endpos,endoff;
652
+        int startpos,endpos;
653
+        long startoff,endoff;
653 654
         undo_t *undo;
654 655
         int k;
655
-        int used;
656
-        int copyfrom,copysize;
656
+        long used;
657
+        long copyfrom,copysize;
657 658
         if(redata==NULL || type==NULL || len<=0
658 659
           || (stack!=&(redata->undostack) && stack!=&(redata->redostack)))
659 660
                 return(NULL); /* sanity check failed */
... ...
@@ -759,10 +760,11 @@ redata_undo_wipe(redata_t *redata, undostack_t *stack)
759 760
 int
760 761
 redata_op_add(redata_t *redata, int insertpos, char *buf, int buflen, undostack_t *fromhere)
761 762
 {
762
-        int chunkno,pos;
763
+        int chunkno;
764
+        long pos;
763 765
         undo_t *undo;
764 766
         rechunk_t *chunk,*nextchunk;
765
-        int avail,nextavail;
767
+        long avail,nextavail;
766 768
         int i;
767 769
         int needed;
768 770
         char *ptr;
... ...
@@ -905,7 +907,7 @@ redata_filehash(redata_t *redata, char *filename, char *resbuf129bytes)
905 907
 }
906 908
 
907 909
 int
908
-redata_memhash(redata_t *redata, char *buf, int buflen, char *resbuf129bytes)
910
+redata_memhash(redata_t *redata, char *buf, long buflen, char *resbuf129bytes)
909 911
 {
910 912
         if(resbuf129bytes!=NULL)
911 913
                 *resbuf129bytes='\0';
... ...
@@ -915,7 +917,7 @@ redata_memhash(redata_t *redata, char *buf, int buflen, char *resbuf129bytes)
915 917
 }
916 918
 
917 919
 static int
918
-redata_hash_gen(redata_t *redata, char *filename, char *buf, int buflen, char *resbuf129bytes)
920
+redata_hash_gen(redata_t *redata, char *filename, char *buf, long buflen, char *resbuf129bytes)
919 921
 {
920 922
         static char conv[]={"0123456789ABCDEF"};
921 923
         sha3_context sha3;
... ...
@@ -946,7 +948,7 @@ redata_hash_gen(redata_t *redata, char *filename, char *buf, int buflen, char *r
946 948
                         sha3_Update(&sha3,(void *) redata->chunks[i]->data,redata->chunks[i]->useddata);
947 949
         } else if(filename!=NULL) {
948 950
                 char buf[16384];
949
-                int totalread,nread;
951
+                long totalread,nread;
950 952
                 for(totalread=0,nread=0;totalread<statbuf.st_size;totalread+=nread,nread=0) {
951 953
                         if((nread=read(fd,buf,sizeof(buf)))<=0) {
952 954
                                 close(fd),fd=-1;
Browse code

Undo/redo enablement

Dario Rodriguez authored on 11/03/2019 23:24:17
Showing 1 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
 }
Browse code

Implement add operation

Dario Rodriguez authored on 10/03/2019 23:50:38
Showing 1 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
Browse code

Change chunk data management so that lines are entirely inside one chunk (this is to simplify the implementation of syntax highlighting)

Dario Rodriguez authored on 10/03/2019 00:03:02
Showing 1 changed files
... ...
@@ -78,6 +78,8 @@ redata_free(redata_t *redata)
78 78
         redata->sizechunks=0;
79 79
         if(redata->chunks!=NULL)
80 80
                 free(redata->chunks),redata->chunks=NULL;
81
+        if(redata->tmpchunk!=NULL)
82
+                free(redata->tmpchunk),redata->tmpchunk=NULL;
81 83
         /* undo */
82 84
         if(redata->undo!=NULL)
83 85
                 free(redata->undo),redata->undo=NULL;
... ...
@@ -95,6 +97,16 @@ redata_free(redata_t *redata)
95 97
         return;
96 98
 }
97 99
 
100
+int
101
+redata_config_chunkdatasize(redata_t *redata, int chunkdatasize)
102
+{
103
+        /* NOTE: this can only be configured immediately after doing redata_init() */
104
+        if(redata==NULL || chunkdatasize<=0 || redata->sizechunks!=0)
105
+                return(-1); /* sanity check failed */
106
+        redata->chunkdatasize=chunkdatasize;
107
+        return(0);
108
+}
109
+
98 110
 int
99 111
 redata_getsize(redata_t *redata)
100 112
 {
... ...
@@ -177,10 +189,17 @@ redata_preallocate(redata_t *redata, int newsize)
177 189
         int oldsizechunks;
178 190
         if(redata==NULL || redata->chunkdatasize==0 || newsize<0)
179 191
                 return(-1); /* sanity check failed */
192
+        rechunksize=sizeof(rechunk_t)-1+redata->chunkdatasize;
193
+        /* before doing any chunk alloc, we setup tmpchunk (used for moves) */
194
+        if(redata->tmpchunk==NULL) {
195
+                if((redata->tmpchunk=malloc(rechunksize))==NULL)
196
+                        return(-1);  /* insuf. mem. */
197
+                memset(redata->tmpchunk,0,rechunksize);
198
+        }
199
+        /* new chunk processing */
180 200
         if((cursize=redata_getsize(redata))>=newsize)
181 201
                 return(0); /* all done */
182 202
         nchunks=(newsize-cursize+redata->chunkdatasize-1)/redata->chunkdatasize;
183
-        rechunksize=sizeof(rechunk_t)-1+redata->chunkdatasize;
184 203
         if((newchunks=realloc(redata->chunks,sizeof(rechunk_t *)*(redata->sizechunks+nchunks)))==NULL)
185 204
                 return(-1); /* insuf. mem. */
186 205
         redata->chunks=newchunks;
... ...
@@ -198,6 +217,49 @@ redata_preallocate(redata_t *redata, int newsize)
198 217
         return(0);
199 218
 }
200 219
 
220
+int
221
+redata_chunk_movedata(redata_t *redata, int chunkfrom, int posfrom, int chunkto, int posto, int size)
222
+{
223
+        if(redata==NULL || size<0
224
+          || chunkfrom<0 || chunkfrom>=redata->sizechunks
225
+          || posfrom<0 || (posfrom+size)>redata->chunks[chunkfrom]->useddata
226
+          || chunkto<0 || chunkto>=redata->sizechunks
227
+          || posto<0 || (posto)>redata->chunks[chunkto]->useddata
228
+          || (chunkfrom!=chunkto && (redata->chunkdatasize-redata->chunks[chunkto]->useddata)<size)
229
+          || (chunkfrom==chunkto && posfrom<posto && posfrom+size>posto)
230
+          )
231
+                return(-1); /* sanity check failed */
232
+        if(size==0
233
+          || (chunkfrom==chunkto && posfrom==posto)
234
+          || (chunkfrom==chunkto && (posfrom+size)==posto)
235
+          )
236
+                return(0); /* all done */
237
+        if(chunkfrom!=chunkto) {
238
+                rechunk_t *from,*to;
239
+                from=redata->chunks[chunkfrom];
240
+                to=redata->chunks[chunkto];
241
+                memmove(to->data+posto+size,to->data+posto,to->useddata-posto);
242
+                memcpy(to->data+posto,from->data+posfrom,size);
243
+                memmove(from->data+posfrom,from->data+posfrom+size,from->useddata-posfrom-size);
244
+                from->useddata-=size;
245
+                to->useddata+=size;
246
+        } else {
247
+                /* from==to */
248
+                rechunk_t *chunk=redata->chunks[chunkfrom];
249
+                memcpy(redata->tmpchunk->data,chunk->data+posfrom,size);
250
+                if(posto>posfrom) {
251
+                        int inside=(posto-posfrom)-size;
252
+                        memmove(chunk->data+posfrom,chunk->data+posto-inside,inside);
253
+                        memcpy(chunk->data+posfrom+inside,redata->tmpchunk->data,size);
254
+                } else {
255
+                        int inside=(posto-posfrom);
256
+                        memmove(chunk->data+posfrom+size-inside,chunk->data+posto,inside);
257
+                        memcpy(chunk->data+posto,redata->tmpchunk->data,size);
258
+                }
259
+        }
260
+        return(0);
261
+}
262
+
201 263
 int
202 264
 redata_fill_whatin(redata_t *redata, int chunkno)
203 265
 {
... ...
@@ -207,12 +269,80 @@ redata_fill_whatin(redata_t *redata, int chunkno)
207 269
         if(redata==NULL || chunkno<0 || chunkno>=redata->sizechunks || redata->chunks[chunkno]==NULL)
208 270
                 return(-1); /* sanity check failed */
209 271
         chunk=redata->chunks[chunkno];
272
+        if(chunk->whatin_fresh)
273
+                return(0);
210 274
         memset(&(chunk->whatin),0,sizeof(whatin_t));
211 275
         nlcount=0;
212 276
         for(i=0,lim=chunk->useddata;i<lim;i++) {
213 277
                 nlcount+=(chunk->data[i]=='\n')?1:0;
214 278
         }
215 279
         chunk->whatin.nlcount=nlcount;
280
+        chunk->whatin_fresh=1;
281
+        return(0);
282
+}
283
+
284
+void *
285
+mymemrchr(const void *s, int c, size_t n)
286
+{
287
+        int i;
288
+        void *res=NULL;
289
+        unsigned char b;
290
+        b=(*((unsigned int *)(&c)))&0xff;
291
+        for(i=0;i<n;i++) {
292
+                if(((unsigned char *)s)[i]==b)
293
+                        res=s+i;
294
+        }
295
+        return(res);
296
+}
297
+
298
+int
299
+redata_fix_nl(redata_t *redata, int chunkno)
300
+{
301
+        /* make sure a line of len<chunksize is entirely inside one chunk (to simplify the syntax highlighting code) */
302
+        if(redata==NULL || chunkno<0 || chunkno>=redata->sizechunks || redata->chunks[chunkno]==NULL)
303
+                return(-1); /* sanity check failed */
304
+        if(chunkno==(redata->sizechunks-1) || redata->chunks[chunkno]->useddata==0 || redata->chunks[chunkno]->data[redata->chunks[chunkno]->useddata-1]=='\n')
305
+                return(0); /* Nothing to do (last chunk, chunk empty or already fixed) */
306
+        rechunk_t *chunk,*nextchunk;
307
+        int linesize, nextlinesize, avail, nextavail;
308
+        unsigned char *ptr,*nextptr;
309
+        chunk=redata->chunks[chunkno];
310
+        nextchunk=redata->chunks[chunkno+1];
311
+        ptr=mymemrchr(chunk->data,'\n',chunk->useddata);
312
+        nextptr=memchr(nextchunk->data,'\n',nextchunk->useddata);
313
+        linesize=(ptr==NULL)?chunk->useddata:(chunk->useddata-(ptr-chunk->data)-1);
314
+        nextlinesize=(nextptr==NULL)?nextchunk->useddata:((nextptr-nextchunk->data)+1);
315
+        avail=redata->chunkdatasize-chunk->useddata;
316
+        nextavail=redata->chunkdatasize-nextchunk->useddata;
317
+        if(avail>=nextlinesize) {
318
+                /* move remaining bytes of line to current chunk */
319
+                redata_chunk_movedata(redata, chunkno+1, 0, chunkno, chunk->useddata, nextlinesize);
320
+        } else if(nextavail>=linesize) {
321
+                /* move incomplete line to next chunk */
322
+                redata_chunk_movedata(redata, chunkno, chunk->useddata-linesize, chunkno+1, 0, linesize);
323
+        } 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;
327
+                /* 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;
338
+                /* move the data; if it doesn't fit, move from the beginning until it is full */
339
+                redata_chunk_movedata(redata, chunkno, chunk->useddata-linesize, chunkno+1, 0, linesize);
340
+                newavail=redata->sizechunks-linesize;
341
+                redata_chunk_movedata(redata, chunkno+2, 0, chunkno+1, linesize, (newavail<nextlinesize)?newavail:nextlinesize);
342
+                redata->chunks[chunkno+2]->whatin_fresh=0;
343
+        }
344
+        redata->chunks[chunkno]->whatin_fresh=0;
345
+        redata->chunks[chunkno+1]->whatin_fresh=0;
216 346
         return(0);
217 347
 }
218 348
 
... ...
@@ -329,7 +459,6 @@ redata_unsaved_unadd(redata_t *redata, undo_t *undo)
329 459
 int
330 460
 redata_load(redata_t *redata, char *filename, int use_unsaved)
331 461
 {
332
-#warning TODO: make sure a line of len<chunksize is entirely inside one chunk (to simplify the syntax highlighting code)
333 462
         int fd,nread,totalread;
334 463
         int chunkno, avail;
335 464
         struct stat statbuf;
... ...
@@ -374,9 +503,12 @@ redata_load(redata_t *redata, char *filename, int use_unsaved)
374 503
                 }
375 504
                 chunk->useddata+=nread;
376 505
                 redata->available-=nread;
377
-                redata_fill_whatin(redata,chunkno);
378 506
         }
379 507
         close(fd),fd=-1;
508
+        for(chunkno=0;chunkno<redata->sizechunks;chunkno++)
509
+                redata_fix_nl(redata,chunkno);
510
+        for(chunkno=0;chunkno<redata->sizechunks;chunkno++)
511
+                redata_fill_whatin(redata,chunkno);
380 512
         /* unsaved */
381 513
         redata_hash(redata,redata->initialhash);
382 514
         if(use_unsaved) {
Browse code

Add insertion test as preparation for implementing insertion

Dario Rodriguez authored on 08/03/2019 18:49:22
Showing 1 changed files
... ...
@@ -32,7 +32,7 @@
32 32
 #define UNSAVEDHEADER "REUNSAV\n"
33 33
 #define UNSAVEDVERSION "\n000001\0"
34 34
 
35
-static int redata_hash_gen(redata_t *redata, char *filename, char *resbuf129bytes);
35
+static int redata_hash_gen(redata_t *redata, char *filename, char *buf, int buflen, char *resbuf129bytes);
36 36
 static char *unsaved_genname(char *filename, char *buf, int bufsize);
37 37
 static char *securesave_genname(char *filename, char *buf, int bufsize);
38 38
 static char *genname(char *filename,char *prefix, char *postfix, char *buf, int bufsize);
... ...
@@ -565,7 +565,7 @@ redata_op_redo(redata_t *redata)
565 565
 int
566 566
 redata_hash(redata_t *redata, char *resbuf129bytes)
567 567
 {
568
-        return(redata_hash_gen(redata,NULL,resbuf129bytes));
568
+        return(redata_hash_gen(redata,NULL,NULL,0,resbuf129bytes));
569 569
 }
570 570
 
571 571
 int
... ...
@@ -575,12 +575,21 @@ redata_filehash(redata_t *redata, char *filename, char *resbuf129bytes)
575 575
                 *resbuf129bytes='\0';
576 576
         if(filename==NULL)
577 577
                 return(-1);
578
-        return(redata_hash_gen(redata,filename,resbuf129bytes));
578
+        return(redata_hash_gen(NULL,filename,NULL,0,resbuf129bytes));
579 579
 }
580 580
 
581
+int
582
+redata_memhash(redata_t *redata, char *buf, int buflen, char *resbuf129bytes)
583
+{
584
+        if(resbuf129bytes!=NULL)
585
+                *resbuf129bytes='\0';
586
+        if(buf==NULL || buflen<0)
587
+                return(-1);
588
+        return(redata_hash_gen(NULL,NULL,buf,buflen,resbuf129bytes));
589
+}
581 590
 
582 591
 static int
583
-redata_hash_gen(redata_t *redata, char *filename, char *resbuf129bytes)
592
+redata_hash_gen(redata_t *redata, char *filename, char *buf, int buflen, char *resbuf129bytes)
584 593
 {
585 594
         static char conv[]={"0123456789ABCDEF"};
586 595
         sha3_context sha3;
... ...
@@ -588,9 +597,14 @@ redata_hash_gen(redata_t *redata, char *filename, char *resbuf129bytes)
588 597
         int i,c;
589 598
         int fd=-1;
590 599
         struct stat statbuf;
600
+        if(resbuf129bytes==NULL)
601
+                return(-1);  /* sanity check failed */
591 602
         if(resbuf129bytes!=NULL)
592 603
                 *resbuf129bytes='\0';
593
-        if(redata==NULL || resbuf129bytes==NULL) {
604
+        if((redata==NULL && filename==NULL && buf==NULL)
605
+           || (redata!=NULL && (filename!=NULL || buf!=NULL))
606
+           || (filename!=NULL && (redata!=NULL || buf!=NULL))
607
+           || (buf!=NULL && (redata!=NULL || filename!=NULL))) {
594 608
                 return(-1); /* sanity check failed */
595 609
         }
596 610
         if(filename!=NULL) {
... ...
@@ -601,10 +615,10 @@ redata_hash_gen(redata_t *redata, char *filename, char *resbuf129bytes)
601 615
                 }
602 616
         }
603 617
         sha3_Init512(&sha3);
604
-        if(filename==NULL) {
618
+        if(redata!=NULL) {
605 619
                 for(i=0;i<redata->sizechunks;i++)
606 620
                         sha3_Update(&sha3,(void *) redata->chunks[i]->data,redata->chunks[i]->useddata);
607
-        } else {
621
+        } else if(filename!=NULL) {
608 622
                 char buf[16384];
609 623
                 int totalread,nread;
610 624
                 for(totalread=0,nread=0;totalread<statbuf.st_size;totalread+=nread,nread=0) {
... ...
@@ -615,6 +629,8 @@ redata_hash_gen(redata_t *redata, char *filename, char *resbuf129bytes)
615 629
                         sha3_Update(&sha3,(void *) buf,nread);
616 630
                 }
617 631
                 close(fd),fd=-1;
632
+        } else if(buf!=NULL) {
633
+                sha3_Update(&sha3,(void *) buf,buflen);
618 634
         }
619 635
         hash=(unsigned char *)sha3_Finalize(&sha3);
620 636
         for(i=0;i<64;i++) {
Browse code

Fix bug in genname triggered when there were no '/' in filename. Add load/save unit test (test_newfile).

Dario Rodriguez authored on 07/03/2019 18:02:06
Showing 1 changed files
... ...
@@ -665,7 +665,7 @@ genname(char *filename,char *prefix, char *postfix, char *buf, int bufsize)
665 665
                         return(NULL);
666 666
                 name=buf;
667 667
         }
668
-        for(ptr=filename+strlen(filename);ptr>0 && ptr[-1]!='/';ptr--)
668
+        for(ptr=filename+strlen(filename);ptr>filename && ptr[-1]!='/';ptr--)
669 669
                 ;
670 670
         off=0;
671 671
         memcpy(name+off,filename,ptr-filename);
Browse code

Add undobuf structire and corresponding functions

Dario Rodriguez authored on 05/03/2019 21:40:51
Showing 1 changed files
... ...
@@ -23,12 +23,19 @@
23 23
 #include "sha3/sha3.h"
24 24
 
25 25
 #define CHUNKSIZE 32768
26
+#define UNDOBLOCK 1024
27
+#define UNDOGROWSIZE (256*1024)
26 28
 #define UNSAVEDPREFIX "."
27 29
 #define UNSAVEDPOSTFIX ".reu"
28
-
30
+#define SECURESAVEPREFIX "."
31
+#define SECURESAVEPOSTFIX ".saving"
32
+#define UNSAVEDHEADER "REUNSAV\n"
33
+#define UNSAVEDVERSION "\n000001\0"
29 34
 
30 35
 static int redata_hash_gen(redata_t *redata, char *filename, char *resbuf129bytes);
31 36
 static char *unsaved_genname(char *filename, char *buf, int bufsize);
37
+static char *securesave_genname(char *filename, char *buf, int bufsize);
38
+static char *genname(char *filename,char *prefix, char *postfix, char *buf, int bufsize);
32 39
 
33 40
 redata_t *
34 41
 redata_init(void)
... ...
@@ -49,6 +56,7 @@ redata_init(void)
49 56
         redata->undo=NULL;
50 57
         redata->undobuf=NULL;
51 58
         /* unsaved */
59
+        redata->filename[0]='\0';
52 60
         redata->unsavedfd=-1;
53 61
         redata->flag_unsaveddata=0;
54 62
         /* all done */
... ...
@@ -59,6 +67,7 @@ void
59 67
 redata_free(redata_t *redata)
60 68
 {
61 69
         int i;
70
+        char unsname[PATH_MAX];
62 71
         if(redata==NULL)
63 72
                 return; /* nothing to do */
64 73
         /* data */
... ...
@@ -75,15 +84,12 @@ redata_free(redata_t *redata)
75 84
         if(redata->undobuf!=NULL)
76 85
                 free(redata->undobuf),redata->undobuf=NULL;
77 86
         /* unsaved */
78
-        if(redata->unsavedfd!=-1)
87
+        if(redata->unsavedfd!=-1) {
79 88
                 close(redata->unsavedfd),redata->unsavedfd=-1;
80
-        if(redata->unsavedfilename!=NULL) {
81
-                if(redata->unsavedfilename[0]!='\0') {
82
-                        /* remove the file, if here, the user has validated exiting without saving */
83
-                        unlink(redata->unsavedfilename);
84
-                }
85
-                free(redata->unsavedfilename),redata->unsavedfilename=NULL;
89
+                if(unsaved_genname(redata->filename,unsname,sizeof(unsname))!=NULL)
90
+                        unlink(unsname);
86 91
         }
92
+        redata->flag_unsaveddata=0;
87 93
         /* free main struct */
88 94
         free(redata),redata=NULL;
89 95
         return;
... ...
@@ -98,25 +104,48 @@ redata_getsize(redata_t *redata)
98 104
 }
99 105
 
100 106
 int
101
-redata_getused(redata_t *redata)
107
+redata_getavailable(redata_t *redata)
102 108
 {
103 109
         if(redata==NULL)
104 110
                 return(0); /* sanity check failed */
105
-        return(redata_getsize(redata)-redata_getavailable(redata));
111
+        return(redata->available);
106 112
 }
107 113
 
108 114
 int
109
-redata_getavailable(redata_t *redata)
115
+redata_getused(redata_t *redata)
110 116
 {
117
+        int used;
111 118
         if(redata==NULL)
112 119
                 return(0); /* sanity check failed */
113
-        return(redata->available);
120
+        used=redata->chunkdatasize*redata->sizechunks-redata->available;
121
+        return(used);
122
+}
123
+
124
+int
125
+redata_getposptr(redata_t *redata, int pos, int *numchunk, int *offset)
126
+{
127
+        int used;
128
+        int i;
129
+        int ipos;
130
+        used=redata_getused(redata);
131
+        if(redata==NULL || pos<0 || pos>used || numchunk==NULL || offset==NULL)
132
+                return(-1); /* sanity check failed */
133
+        for(ipos=0,i=0;i<redata->sizechunks;ipos+=redata->chunks[i]->useddata,i++) {
134
+                if(pos>(ipos+redata->chunks[i]->useddata))
135
+                        continue;
136
+                /* found */
137
+                *numchunk=i;
138
+                *offset=pos-ipos;
139
+                return(0);
140
+        }
141
+        return(-1);
114 142
 }
115 143
 
116 144
 int
117 145
 redata_wipe(redata_t *redata)
118 146
 {
119 147
         int i;
148
+        char unsname[PATH_MAX];
120 149
         if(redata==NULL)
121 150
                 return(-1); /* sanity check failed */
122 151
         /* data */
... ...
@@ -126,16 +155,13 @@ redata_wipe(redata_t *redata)
126 155
         }
127 156
         redata->available=redata_getsize(redata);
128 157
         /* unsaved */
129
-        if(redata->unsavedfd!=-1)
158
+        if(redata->unsavedfd!=-1) {
130 159
                 close(redata->unsavedfd),redata->unsavedfd=-1;
131
-        if(redata->unsavedfilename!=NULL) {
132
-                if(redata->unsavedfilename[0]!='\0') {
133
-                        /* remove the file, if here, the user has validated exiting without saving */
134
-                        unlink(redata->unsavedfilename);
135
-                }
136
-                free(redata->unsavedfilename),redata->unsavedfilename=NULL;
160
+                if(unsaved_genname(redata->filename,unsname,sizeof(unsname))!=NULL)
161
+                        unlink(unsname);
137 162
         }
138 163
         redata->flag_unsaveddata=0;
164
+        redata->filename[0]='\0';
139 165
         /* all done */
140 166
         return(0);
141 167
 }
... ...
@@ -195,8 +221,10 @@ redata_unsaved_exists(redata_t *redata, char *filename)
195 221
 {
196 222
         char unsname[PATH_MAX+1];
197 223
         int fd;
224
+        if(redata==NULL || filename==NULL)
225
+                return(-1); /* sanity check failed */
198 226
         if((unsaved_genname(filename,unsname,sizeof(unsname)))==NULL)
199
-                return(-1);
227
+                return(-1); /* malformed filename */
200 228
         if((fd=open(unsname,O_RDONLY))==-1)
201 229
                 return(-1);
202 230
         close(fd),fd=-1;
... ...
@@ -206,25 +234,84 @@ redata_unsaved_exists(redata_t *redata, char *filename)
206 234
 int
207 235
 redata_unsaved_check(redata_t *redata, char *filename)
208 236
 {
237
+        char unsname[PATH_MAX+1];
238
+        int fd,nread;
239
+        static char header[9]={UNSAVEDHEADER};
240
+        static char version[9]={UNSAVEDVERSION};
241
+        char filehash[129],undohash[129],buf[64];
242
+        if(redata==NULL || filename==NULL)
243
+                return(-1); /* sanity check failed */
244
+        if((unsaved_genname(filename,unsname,sizeof(unsname)))==NULL)
245
+                return(-1); /* malformed filename */
246
+        if(redata_filehash(redata,filename,filehash)!=0)
247
+                return(-1);
248
+        if((fd=open(unsname,O_RDONLY))==-1)
249
+                return(-1);
250
+        if((nread=read(fd,buf,8))==-1 || nread!=8 || memcmp(buf,header,8)!=0) {
251
+                close(fd),fd=-1;
252
+                return(-1); /* corrupted header */
253
+        }
254
+        if((nread=read(fd,undohash,128))==-1 || nread!=128 || memcmp(undohash,filehash,128)!=0) {
255
+                close(fd),fd=-1;
256
+                return(-1); /* wrong hash */
257
+        }
258
+        if((nread=read(fd,buf,8))==-1 || nread!=8 || memcmp(buf,version,8)!=0) {
259
+                close(fd),fd=-1;
260
+                return(-1); /* wrong version */
261
+        }
262
+        close(fd),fd=-1;
263
+        return(0);
264
+}
209 265
 
210
-#warning TODO
211
-        return(-1);
266
+
267
+int
268
+redata_unsaved_unlink(redata_t *redata)
269
+{
270
+        char unsname[PATH_MAX+1];
271
+        if(redata==NULL || redata->filename[0]=='\0')
272
+                return(-1); /* sanity check failed */
273
+        if(redata_unsaved_exists(redata,redata->filename)==-1)
274
+                return(0); /* file not found, nothing to unlink */
275
+        if((unsaved_genname(redata->filename,unsname,sizeof(unsname)))==NULL)
276
+                return(-1); /* malformed filename */
277
+        unlink(unsname);
278
+        return(0);
212 279
 }
213 280
 
281
+
282
+
214 283
 int
215
-redata_unsaved_loadappend(redata_t *redata, char *filename)
284
+redata_unsaved_trunc(redata_t *redata)
216 285
 {
217
-#warning TODO
218
-        return(-1);
286
+        char unsname[PATH_MAX+1];
287
+        static char header[9]={UNSAVEDHEADER};
288
+        static char version[9]={UNSAVEDVERSION};
289
+        int n;
290
+        if(redata==NULL || redata->filename[0]=='\0')
291
+                return(-1); /* sanity check failed */
292
+        redata_unsaved_unlink(redata);
293
+        if((unsaved_genname(redata->filename,unsname,sizeof(unsname)))==NULL)
294
+                return(-1); /* malformed filename */
295
+        if((redata->unsavedfd=open(unsname,O_WRONLY|O_TRUNC|O_CREAT,0644))==-1)
296
+                return(-1); /* couldn't open file for writing */
297
+        if((n=write(redata->unsavedfd,header,8))==-1 || n!=8 ||
298
+          (n=write(redata->unsavedfd,redata->initialhash,128))==-1 || n!=128 ||
299
+          (n=write(redata->unsavedfd,version,8))==-1 || n!=8) {
300
+                close(redata->unsavedfd),redata->unsavedfd=-1;
301
+                unlink(unsname);
302
+                return(-1); /* couldn't write header/hash/version */
303
+        }
304
+        return(0);
219 305
 }
220 306
 
221 307
 int
222
-redata_unsaved_trunc(redata_t *redata, char *filename)
308
+redata_unsaved_loadappend(redata_t *redata)
223 309
 {
224 310
 #warning TODO
225 311
         return(-1);
226 312
 }
227 313
 
314
+
228 315
 int
229 316
 redata_unsaved_add(redata_t *redata, undo_t *undo)
230 317
 {
... ...
@@ -242,12 +329,16 @@ redata_unsaved_unadd(redata_t *redata, undo_t *undo)
242 329
 int
243 330
 redata_load(redata_t *redata, char *filename, int use_unsaved)
244 331
 {
245
-#warning TODO: use_unsaved (apply unsaved changes after load)
332
+#warning TODO: make sure a line of len<chunksize is entirely inside one chunk (to simplify the syntax highlighting code)
246 333
         int fd,nread,totalread;
247 334
         int chunkno, avail;
248 335
         struct stat statbuf;
249 336
         rechunk_t *chunk;
337
+        if(redata==NULL || filename==NULL)
338
+                return(-1); /* sanity check failed */
250 339
         redata_wipe(redata);
340
+        strncpy(redata->filename,filename,sizeof(redata->filename));
341
+        redata->filename[sizeof(redata->filename)-1]='\0';
251 342
         if((fd=open(filename,O_RDONLY))==-1 || fstat(fd,&statbuf)!=0 || !S_ISREG(statbuf.st_mode)) {
252 343
                 if(fd!=-1)
253 344
                         close(fd),fd=-1;
... ...
@@ -287,12 +378,13 @@ redata_load(redata_t *redata, char *filename, int use_unsaved)
287 378
         }
288 379
         close(fd),fd=-1;
289 380
         /* unsaved */
381
+        redata_hash(redata,redata->initialhash);
290 382
         if(use_unsaved) {
291 383
                 /* apply missing changes and append new changes to unsaved */
292
-                redata_unsaved_loadappend(redata,filename);
384
+                redata_unsaved_loadappend(redata);
293 385
         } else {
294 386
                 /* nuke existing unsaved (if exists) and prepare new unsaved */
295
-                redata_unsaved_trunc(redata,filename);
387
+                redata_unsaved_trunc(redata);
296 388
         }
297 389
         /* all done */
298 390
         return(0);
... ...
@@ -301,13 +393,143 @@ redata_load(redata_t *redata, char *filename, int use_unsaved)
301 393
 int
302 394
 redata_save(redata_t *redata, char *filename)
303 395
 {
304
-#warning TODO
305
-        return(-1);
396
+        int fd;
397
+        int i,n;
398
+        char tmpfile[PATH_MAX+1];
399
+        if(redata==NULL || filename==NULL)
400
+                return(-1); /* sanity check failed */
401
+        if((securesave_genname(redata->filename,tmpfile,sizeof(tmpfile)))==NULL)
402
+                return(-1); /* malformed filename */
403
+        if((fd=open(tmpfile,O_WRONLY|O_TRUNC|O_CREAT,0644))==-1)
404
+                return(-1); /* couldn't open file for writing */
405
+        for(i=0;i<redata->sizechunks;i++) {
406
+                if(redata->chunks[i]->useddata==0)
407
+                        continue;
408
+                if((n=write(fd,redata->chunks[i]->data,redata->chunks[i]->useddata))==-1 || n!=redata->chunks[i]->useddata) {
409
+                        close(fd),fd=-1;
410
+                        unlink(tmpfile);
411
+                        return(-1); /* short write */
412
+                }
413
+        }
414
+        close(fd),fd=-1;
415
+        if(rename(tmpfile,filename)!=0) {
416
+                unlink(tmpfile);
417
+                return(-1); /* couldn't overwrite old file */
418
+        }
419
+        redata_unsaved_unlink(redata);
420
+        redata->flag_unsaveddata=0;
421
+        redata_hash(redata,redata->initialhash);
422
+        return(0);
423
+}
424
+
425
+int
426
+redata_undobuf_reserve(redata_t *redata, int minavail)
427
+{
428
+        int unused;
429
+        int newsize;
430
+        char *newptr;
431
+        if(redata==NULL || minavail<0)
432
+                return(-1); /* sanity check failed */
433
+        unused=redata->sizeundobuf-redata->usedundobuf;
434
+        if(unused<minavail) {
435
+                newsize=(redata->sizeundobuf+minavail+UNDOGROWSIZE-1)/UNDOGROWSIZE;
436
+                newsize*=UNDOGROWSIZE;
437
+                if((newptr=realloc(redata->undobuf,newsize))==NULL)
438
+                        return(-1); /* insuf. mem. */
439
+                redata->undobuf=newptr;
440
+                redata->sizeundobuf=newsize;
441
+        }
442
+        return(0);
443
+}
444
+
445
+undo_t *
446
+redata_undo_new(redata_t *redata, char *type)
447
+{
448
+        int newsize;
449
+        undo_t *newptr,*undo;
450
+        if(redata==NULL || type==NULL)
451
+                return(NULL); /* sanity check failed */
452
+        if(redata->sizeundo==redata->usedundo) {
453
+                newsize=(redata->sizeundo+1+UNDOBLOCK-1)/UNDOBLOCK;
454
+                newsize*=UNDOBLOCK;
455
+                if((newptr=realloc(redata->undo,sizeof(undo_t)*newsize))==NULL)
456
+                        return(NULL);
457
+                redata->undo=newptr;
458
+                memset(redata->undo+redata->sizeundo,0,sizeof(undo_t)*(newsize-redata->sizeundo));
459
+                redata->sizeundo=newsize;
460
+        }
461
+        undo=redata->undo+redata->usedundo;
462
+        redata->usedundo++;
463
+        strncpy(undo->type,type,sizeof(undo->type));
464
+        undo->type[sizeof(undo->type)-1]='\0';
465
+        undo->off=redata->usedundobuf;
466
+        undo->len=0;
467
+        return(undo);
468
+}
469
+
470
+undo_t *
471
+redata_undo_newfromchunks(redata_t *redata,char *type, int pos1, int len)
472
+{
473
+        int startpos,startoff,endpos,endoff;
474
+        undo_t *undo;
475
+        int k;
476
+        int used;
477
+        int copyfrom,copysize;
478
+        if(redata==NULL || type==NULL || len<=0)
479
+                return(NULL); /* sanity check failed */
480
+        if(redata_getposptr(redata,pos1,&startpos,&startoff)==-1 ||
481
+          redata_getposptr(redata,pos1+len,&endpos,&endoff)==-1) {
482
+                return(NULL); /* chunk data out of bounds */
483
+        }
484
+        if(redata_undobuf_reserve(redata,len)!=0)
485
+                return(NULL); /* insuf. mem. */
486
+        if((undo=redata_undo_new(redata,type))==NULL)
487
+                return(NULL); /* insuf. mem. */
488
+        undo->off=redata->usedundobuf;
489
+        /* copy contents */
490
+        for(k=startpos,used=0;k<=endpos;k++) {
491
+                if(k==startpos && k==endpos) {
492
+                        copyfrom=startoff;
493
+                        copysize=endoff-startoff;
494
+                } else if(k==startpos) {
495
+                        copyfrom=startoff;
496
+                        copysize=redata->chunks[k]->useddata-startoff;
497
+                } else if(k==endpos) {
498
+                        copyfrom=0;
499
+                        copysize=endoff;
500
+                } else {
501
+                        copyfrom=0;
502
+                        copysize=redata->chunks[k]->useddata;
503
+                }
504
+                memcpy(redata->undobuf+redata->usedundobuf,redata->chunks[k]->data+copyfrom,copysize);
505
+                redata->usedundobuf+=copysize;
506
+                used+=copysize;
507
+        }
508
+        undo->len=used;
509
+        return(undo);
510
+}
511
+
512
+undo_t *
513
+redata_undobuf_newfrombuf(redata_t *redata, char *type, char *buf, int buflen)
514
+{
515
+        undo_t *undo;
516
+        if(redata==NULL || type==NULL || buflen<=0)
517
+                return(NULL); /* sanity check failed */
518
+        if(redata_undobuf_reserve(redata,buflen)!=0)
519
+                return(NULL); /* insuf. mem. */
520
+        if((undo=redata_undo_new(redata,type))==NULL)
521
+                return(NULL); /* insuf. mem. */
522
+        undo->off=redata->usedundobuf;
523
+        memcpy(redata->undobuf+redata->usedundobuf,buf,buflen);
524
+        redata->usedundobuf+=buflen;
525
+        undo->len=buflen;
526
+        return(undo);
306 527
 }
307 528
 
308 529
 int
309 530
 redata_op_add(redata_t *redata, char *buf, int sizebuf, int pos)
310 531
 {
532
+
311 533
 #warning TODO
312 534
         return(-1);
313 535
 }
... ...
@@ -326,6 +548,20 @@ redata_op_move(redata_t *redata, int posorig, int size, int posdest)
326 548
         return(-1);
327 549
 }
328 550
 
551
+int
552
+redata_op_undo(redata_t *redata)
553
+{
554
+#warning TODO
555
+        return(-1);
556
+}
557
+
558
+int
559
+redata_op_redo(redata_t *redata)
560
+{
561
+#warning TODO
562
+        return(-1);
563
+}
564
+
329 565
 int
330 566
 redata_hash(redata_t *redata, char *resbuf129bytes)
331 567
 {
... ...
@@ -395,17 +631,34 @@ redata_hash_gen(redata_t *redata, char *filename, char *resbuf129bytes)
395 631
 static char *
396 632
 unsaved_genname(char *filename, char *buf, int bufsize)
397 633
 {
398
-        char *name,*ptr;
399
-        int filenamelen;
400
-        int len,off;
401 634
         static char pre[]={UNSAVEDPREFIX};
402 635
         static char post[]={UNSAVEDPOSTFIX};
403
-        if(filename==NULL)
636
+        return(genname(filename,pre,post,buf,bufsize));
637
+}
638
+
639
+static char *
640
+securesave_genname(char *filename, char *buf, int bufsize)
641
+{
642
+        static char pre[]={SECURESAVEPREFIX};
643
+        static char post[]={SECURESAVEPOSTFIX};
644
+        return(genname(filename,pre,post,buf,bufsize));
645
+}
646
+
647
+
648
+static char *
649
+genname(char *filename,char *prefix, char *postfix, char *buf, int bufsize)
650
+{
651
+        char *name,*ptr;
652
+        int filenamelen;
653
+        int prelen,postlen,finallen,off;
654
+        if(filename==NULL || prefix==NULL || postfix==NULL)
404 655
                 return(NULL);
405 656
         filenamelen=strlen(filename);
406
-        len=filenamelen+sizeof(pre)-1+sizeof(post)-1+1;
657
+        prelen=strlen(prefix);
658
+        postlen=strlen(postfix);
659
+        finallen=filenamelen+prelen+postlen+1;
407 660
         if(buf==NULL) {
408
-                if((name=malloc(len))==NULL)
661
+                if((name=malloc(finallen))==NULL)
409 662
                         return(NULL);
410 663
         } else {
411 664
                 if(bufsize<filenamelen)
... ...
@@ -417,13 +670,14 @@ unsaved_genname(char *filename, char *buf, int bufsize)
417 670
         off=0;
418 671
         memcpy(name+off,filename,ptr-filename);
419 672
         off+=ptr-filename;
420
-        memcpy(name+off,pre,sizeof(pre)-1);
421
-        off+=sizeof(pre)-1;
673
+        memcpy(name+off,prefix,prelen);
674
+        off+=prelen;
422 675
         memcpy(name+off,ptr,filenamelen-(ptr-filename));
423 676
         off+=filenamelen-(ptr-filename);
424
-        memcpy(name+off,post,sizeof(post)-1);
425
-        off+=sizeof(post)-1;
677
+        memcpy(name+off,postfix,postlen);
678
+        off+=postlen;
426 679
         name[off]='\0';
427 680
         return(name);
428 681
 }
429 682
 
683
+
Browse code

Change sha3 implementation used. Initial unsaved data API.

Dario Rodriguez authored on 02/03/2019 16:12:12
Showing 1 changed files
... ...
@@ -16,15 +16,20 @@
16 16
 #include <sys/types.h>
17 17
 #include <sys/stat.h>
18 18
 #include <fcntl.h>
19
+#include <limits.h>
20
+#include <inttypes.h>
19 21
 
20 22
 #include "recenteditor_data.h"
21
-#include "keccak/KeccakHash.h"
23
+#include "sha3/sha3.h"
22 24
 
23 25
 #define CHUNKSIZE 32768
24 26
 #define UNSAVEDPREFIX "."
25 27
 #define UNSAVEDPOSTFIX ".reu"
26 28
 
27 29
 
30
+static int redata_hash_gen(redata_t *redata, char *filename, char *resbuf129bytes);
31
+static char *unsaved_genname(char *filename, char *buf, int bufsize);
32
+
28 33
 redata_t *
29 34
 redata_init(void)
30 35
 {
... ...
@@ -185,11 +190,59 @@ redata_fill_whatin(redata_t *redata, int chunkno)
185 190
         return(0);
186 191
 }
187 192
 
193
+int
194
+redata_unsaved_exists(redata_t *redata, char *filename)
195
+{
196
+        char unsname[PATH_MAX+1];
197
+        int fd;
198
+        if((unsaved_genname(filename,unsname,sizeof(unsname)))==NULL)
199
+                return(-1);
200
+        if((fd=open(unsname,O_RDONLY))==-1)
201
+                return(-1);
202
+        close(fd),fd=-1;
203
+        return(0);
204
+}
205
+
206
+int
207
+redata_unsaved_check(redata_t *redata, char *filename)
208
+{
209
+
210
+#warning TODO
211
+        return(-1);
212
+}
213
+
214
+int
215
+redata_unsaved_loadappend(redata_t *redata, char *filename)
216
+{
217
+#warning TODO
218
+        return(-1);
219
+}
220
+
221
+int
222
+redata_unsaved_trunc(redata_t *redata, char *filename)
223
+{
224
+#warning TODO
225
+        return(-1);
226
+}
227
+
228
+int
229
+redata_unsaved_add(redata_t *redata, undo_t *undo)
230
+{
231
+#warning TODO
232
+        return(-1);
233
+}
234
+
235
+int
236
+redata_unsaved_unadd(redata_t *redata, undo_t *undo)
237
+{
238
+#warning TODO
239
+        return(-1);
240
+}
188 241
 
189 242
 int
190 243
 redata_load(redata_t *redata, char *filename, int use_unsaved)
191 244
 {
192
-#warning TODO: use_unsaved
245
+#warning TODO: use_unsaved (apply unsaved changes after load)
193 246
         int fd,nread,totalread;
194 247
         int chunkno, avail;
195 248
         struct stat statbuf;
... ...
@@ -202,8 +255,7 @@ redata_load(redata_t *redata, char *filename, int use_unsaved)
202 255
         }
203 256
         /* preallocate 10% more than needed */
204 257
         if(redata_preallocate(redata,statbuf.st_size+(statbuf.st_size/10)+1 )) {
205
-                if(fd!=-1)
206
-                        close(fd),fd=-1;
258
+                close(fd),fd=-1;
207 259
                 return(-1); /* insuf. mem. */
208 260
         }
209 261
         for(totalread=0,chunkno=0,nread=0;totalread<statbuf.st_size;totalread+=nread,nread=0) {
... ...
@@ -211,8 +263,7 @@ redata_load(redata_t *redata, char *filename, int use_unsaved)
211 263
                         /* alloc another chunk */
212 264
                         if(redata_preallocate(redata,(redata->sizechunks+1)*redata->chunkdatasize)==-1 ||
213 265
                                 chunkno>=redata->sizechunks || redata->chunks[chunkno]==NULL) {
214
-                                if(fd!=-1)
215
-                                        close(fd),fd=-1;
266
+                                close(fd),fd=-1;
216 267
                                 fprintf(stderr,"redata_load: INTERNAL ERROR\n");
217 268
                                 return(-2); /* internal error */
218 269
                         }
... ...
@@ -227,16 +278,22 @@ redata_load(redata_t *redata, char *filename, int use_unsaved)
227 278
                         continue;
228 279
                 }
229 280
                 if((nread=read(fd,chunk->data+chunk->useddata,avail))<=0) {
230
-                        if(fd!=-1)
231
-                                close(fd),fd=-1;
281
+                        close(fd),fd=-1;
232 282
                         return(-1); /* short read */
233 283
                 }
234 284
                 chunk->useddata+=nread;
235 285
                 redata->available-=nread;
236 286
                 redata_fill_whatin(redata,chunkno);
237 287
         }
238
-        /* prepare unsaved */
239
-
288
+        close(fd),fd=-1;
289
+        /* unsaved */
290
+        if(use_unsaved) {
291
+                /* apply missing changes and append new changes to unsaved */
292
+                redata_unsaved_loadappend(redata,filename);
293
+        } else {
294
+                /* nuke existing unsaved (if exists) and prepare new unsaved */
295
+                redata_unsaved_trunc(redata,filename);
296
+        }
240 297
         /* all done */
241 298
         return(0);
242 299
 }
... ...
@@ -251,47 +308,122 @@ redata_save(redata_t *redata, char *filename)
251 308
 int
252 309
 redata_op_add(redata_t *redata, char *buf, int sizebuf, int pos)
253 310
 {
311
+#warning TODO
312
+        return(-1);
254 313
 }
255 314
 
256 315
 int
257 316
 redata_op_del(redata_t *redata, int pos, int size)
258 317
 {
318
+#warning TODO
319
+        return(-1);
259 320
 }
260 321
 
261 322
 int
262 323
 redata_op_move(redata_t *redata, int posorig, int size, int posdest)
263 324
 {
325
+#warning TODO
326
+        return(-1);
264 327
 }
265 328
 
266 329
 int
267 330
 redata_hash(redata_t *redata, char *resbuf129bytes)
331
+{
332
+        return(redata_hash_gen(redata,NULL,resbuf129bytes));
333
+}
334
+
335
+int
336
+redata_filehash(redata_t *redata, char *filename, char *resbuf129bytes)
337
+{
338
+        if(resbuf129bytes!=NULL)
339
+                *resbuf129bytes='\0';
340
+        if(filename==NULL)
341
+                return(-1);
342
+        return(redata_hash_gen(redata,filename,resbuf129bytes));
343
+}
344
+
345
+
346
+static int
347
+redata_hash_gen(redata_t *redata, char *filename, char *resbuf129bytes)
268 348
 {
269 349
         static char conv[]={"0123456789ABCDEF"};
270
-        Keccak_HashInstance hash;
350
+        sha3_context sha3;
351
+        unsigned char *hash;
271 352
         int i,c;
353
+        int fd=-1;
354
+        struct stat statbuf;
272 355
         if(resbuf129bytes!=NULL)
273 356
                 *resbuf129bytes='\0';
274 357
         if(redata==NULL || resbuf129bytes==NULL) {
275 358
                 return(-1); /* sanity check failed */
276 359
         }
277
-        if(Keccak_HashInitialize_SHA3_512(&hash)!=SUCCESS)
278
-                return(-1); /* init failed */
279
-        for(i=0;i<redata->sizechunks;i++) {
280
-                if(Keccak_HashUpdate(&hash, (void *) redata->chunks[i]->data,redata->chunks[i]->useddata)!=SUCCESS)
281
-                        return(-1); /* hash calc. error */
360
+        if(filename!=NULL) {
361
+                if((fd=open(filename,O_RDONLY))==-1 || fstat(fd,&statbuf)!=0 || !S_ISREG(statbuf.st_mode)) {
362
+                       if(fd!=-1)
363
+                               close(fd),fd=-1;
364
+                       return(-1); /* file not found, couldn't query size or not regular file */
365
+                }
282 366
         }
283
-        if(Keccak_HashFinal(&hash, (void *) resbuf129bytes)!=SUCCESS) {
284
-                *resbuf129bytes='\0';
285
-                return(-1); /* hash final calc. error */
367
+        sha3_Init512(&sha3);
368
+        if(filename==NULL) {
369
+                for(i=0;i<redata->sizechunks;i++)
370
+                        sha3_Update(&sha3,(void *) redata->chunks[i]->data,redata->chunks[i]->useddata);
371
+        } else {
372
+                char buf[16384];
373
+                int totalread,nread;
374
+                for(totalread=0,nread=0;totalread<statbuf.st_size;totalread+=nread,nread=0) {
375
+                        if((nread=read(fd,buf,sizeof(buf)))<=0) {
376
+                                close(fd),fd=-1;
377
+                                return(-1); /* short read */
378
+                        }
379
+                        sha3_Update(&sha3,(void *) buf,nread);
380
+                }
381
+                close(fd),fd=-1;
286 382
         }
287
-        resbuf129bytes[128]='\0';
288
-        for(i=63;i>=0;i--) {
289
-                c=((unsigned char *)resbuf129bytes)[i];
383
+        hash=(unsigned char *)sha3_Finalize(&sha3);
384
+        for(i=0;i<64;i++) {
385
+                c=hash[i];
290 386
                 resbuf129bytes[i<<1]=conv[((c>>4)&0xf)];
291 387
                 resbuf129bytes[(i<<1)+1]=conv[(c&0xf)];
292 388
         }
293
-#warning TODO: result is not as expected
389
+        resbuf129bytes[128]='\0';
390
+        /* NOTE this is SHA3-512, not keccak (empty result is a69f..cd26) */
294 391
         return(0);
295 392
 }
296 393
 
297 394
 
395
+static char *
396
+unsaved_genname(char *filename, char *buf, int bufsize)
397
+{
398
+        char *name,*ptr;
399
+        int filenamelen;
400
+        int len,off;
401
+        static char pre[]={UNSAVEDPREFIX};
402
+        static char post[]={UNSAVEDPOSTFIX};
403
+        if(filename==NULL)
404
+                return(NULL);
405
+        filenamelen=strlen(filename);
406
+        len=filenamelen+sizeof(pre)-1+sizeof(post)-1+1;
407
+        if(buf==NULL) {
408
+                if((name=malloc(len))==NULL)
409
+                        return(NULL);
410
+        } else {
411
+                if(bufsize<filenamelen)
412
+                        return(NULL);
413
+                name=buf;
414
+        }
415
+        for(ptr=filename+strlen(filename);ptr>0 && ptr[-1]!='/';ptr--)
416
+                ;
417
+        off=0;
418
+        memcpy(name+off,filename,ptr-filename);
419
+        off+=ptr-filename;
420
+        memcpy(name+off,pre,sizeof(pre)-1);
421
+        off+=sizeof(pre)-1;
422
+        memcpy(name+off,ptr,filenamelen-(ptr-filename));
423
+        off+=filenamelen-(ptr-filename);
424
+        memcpy(name+off,post,sizeof(post)-1);
425
+        off+=sizeof(post)-1;
426
+        name[off]='\0';
427
+        return(name);
428
+}
429
+
Browse code

start implementation of undo and unsaved in redata. tentative sha3-512 support for unsaved integrity check

Dario Rodriguez authored on 26/02/2019 21:26:05
Showing 1 changed files
... ...
@@ -18,8 +18,11 @@
18 18
 #include <fcntl.h>
19 19
 
20 20
 #include "recenteditor_data.h"
21
+#include "keccak/KeccakHash.h"
21 22
 
22 23
 #define CHUNKSIZE 32768
24
+#define UNSAVEDPREFIX "."
25
+#define UNSAVEDPOSTFIX ".reu"
23 26
 
24 27
 
25 28
 redata_t *
... ...
@@ -29,10 +32,21 @@ redata_init(void)
29 32
         if((redata=malloc(sizeof(redata_t)))==NULL)
30 33
                 return(NULL); /* sanity check failed */
31 34
         memset(redata,0,sizeof(redata_t));
35
+        /* data */
32 36
         redata->sizechunks=0;
33 37
         redata->chunks=NULL;
34 38
         redata->chunkdatasize=CHUNKSIZE;
35 39
         redata->available=0;
40
+        /* undo */
41
+        redata->sizeundo=0;
42
+        redata->usedundo=0;
43
+        redata->curundo=0;
44
+        redata->undo=NULL;
45
+        redata->undobuf=NULL;
46
+        /* unsaved */
47
+        redata->unsavedfd=-1;
48
+        redata->flag_unsaveddata=0;
49
+        /* all done */
36 50
         return(redata);
37 51
 }
38 52
 
... ...
@@ -42,6 +56,7 @@ redata_free(redata_t *redata)
42 56
         int i;
43 57
         if(redata==NULL)
44 58
                 return; /* nothing to do */
59
+        /* data */
45 60
         for(i=0;i<redata->sizechunks;i++) {
46 61
                 if(redata->chunks[i]!=NULL)
47 62
                         free(redata->chunks[i]),redata->chunks[i]=NULL;
... ...
@@ -49,6 +64,22 @@ redata_free(redata_t *redata)
49 64
         redata->sizechunks=0;
50 65
         if(redata->chunks!=NULL)
51 66
                 free(redata->chunks),redata->chunks=NULL;
67
+        /* undo */
68
+        if(redata->undo!=NULL)
69
+                free(redata->undo),redata->undo=NULL;
70
+        if(redata->undobuf!=NULL)
71
+                free(redata->undobuf),redata->undobuf=NULL;
72
+        /* unsaved */
73
+        if(redata->unsavedfd!=-1)
74
+                close(redata->unsavedfd),redata->unsavedfd=-1;
75
+        if(redata->unsavedfilename!=NULL) {
76
+                if(redata->unsavedfilename[0]!='\0') {
77
+                        /* remove the file, if here, the user has validated exiting without saving */
78
+                        unlink(redata->unsavedfilename);
79
+                }
80
+                free(redata->unsavedfilename),redata->unsavedfilename=NULL;
81
+        }
82
+        /* free main struct */
52 83
         free(redata),redata=NULL;
53 84
         return;
54 85
 }
... ...
@@ -83,11 +114,24 @@ redata_wipe(redata_t *redata)
83 114
         int i;
84 115
         if(redata==NULL)
85 116
                 return(-1); /* sanity check failed */
117
+        /* data */
86 118
         for(i=0;i<redata->sizechunks;i++) {
87 119
                 redata->chunks[i]->useddata=0;
88 120
                 memset(&(redata->chunks[i]->whatin),0,sizeof(whatin_t));
89 121
         }
90 122
         redata->available=redata_getsize(redata);
123
+        /* unsaved */
124
+        if(redata->unsavedfd!=-1)
125
+                close(redata->unsavedfd),redata->unsavedfd=-1;
126
+        if(redata->unsavedfilename!=NULL) {
127
+                if(redata->unsavedfilename[0]!='\0') {
128
+                        /* remove the file, if here, the user has validated exiting without saving */
129
+                        unlink(redata->unsavedfilename);
130
+                }
131
+                free(redata->unsavedfilename),redata->unsavedfilename=NULL;
132
+        }
133
+        redata->flag_unsaveddata=0;
134
+        /* all done */
91 135
         return(0);
92 136
 }
93 137
 
... ...
@@ -98,7 +142,7 @@ redata_preallocate(redata_t *redata, int newsize)
98 142
         int nchunks;
99 143
         int i;
100 144
         int rechunksize;
101
-        rechunk_t *newchunks,*chunk;
145
+        rechunk_t **newchunks,*chunk;
102 146
         int oldsizechunks;
103 147
         if(redata==NULL || redata->chunkdatasize==0 || newsize<0)
104 148
                 return(-1); /* sanity check failed */
... ...
@@ -143,8 +187,9 @@ redata_fill_whatin(redata_t *redata, int chunkno)
143 187
 
144 188
 
145 189
 int
146
-redata_load(redata_t *redata, char *filename)
190
+redata_load(redata_t *redata, char *filename, int use_unsaved)
147 191
 {
192
+#warning TODO: use_unsaved
148 193
         int fd,nread,totalread;
149 194
         int chunkno, avail;
150 195
         struct stat statbuf;
... ...
@@ -155,20 +200,27 @@ redata_load(redata_t *redata, char *filename)
155 200
                         close(fd),fd=-1;
156 201
                 return(-1); /* file not found, couldn't query size or not regular file */
157 202
         }
158
-        if(redata_preallocate(redata,statbuf.st_size)) {
203
+        /* preallocate 10% more than needed */
204
+        if(redata_preallocate(redata,statbuf.st_size+(statbuf.st_size/10)+1 )) {
159 205
                 if(fd!=-1)
160 206
                         close(fd),fd=-1;
161 207
                 return(-1); /* insuf. mem. */
162 208
         }
163 209
         for(totalread=0,chunkno=0,nread=0;totalread<statbuf.st_size;totalread+=nread,nread=0) {
164 210
                 if(chunkno>=redata->sizechunks || redata->chunks[chunkno]==NULL) {
165
-                        if(fd!=-1)
166
-                                close(fd),fd=-1;
167
-                        fprintf(stderr,"redata_load: INTERNAL ERROR\n");
168
-                        return(-2); /* internal error */
211
+                        /* alloc another chunk */
212
+                        if(redata_preallocate(redata,(redata->sizechunks+1)*redata->chunkdatasize)==-1 ||
213
+                                chunkno>=redata->sizechunks || redata->chunks[chunkno]==NULL) {
214
+                                if(fd!=-1)
215
+                                        close(fd),fd=-1;
216
+                                fprintf(stderr,"redata_load: INTERNAL ERROR\n");
217
+                                return(-2); /* internal error */
218
+                        }
169 219
                 }
170 220
                 chunk=redata->chunks[chunkno];
171
-                avail=redata->chunkdatasize-chunk->useddata;
221
+                /* leave 10% free on each chunk */
222
+                avail=(redata->chunkdatasize-redata->chunkdatasize/10)-chunk->useddata;
223
+                avail=(avail<0)?0:avail;
172 224
                 avail=((totalread+avail)>statbuf.st_size)?statbuf.st_size-totalread:avail;
173 225
                 if(avail==0) {
174 226
                         chunkno++; /* full, try next */
... ...
@@ -183,6 +235,9 @@ redata_load(redata_t *redata, char *filename)
183 235
                 redata->available-=nread;
184 236
                 redata_fill_whatin(redata,chunkno);
185 237
         }
238
+        /* prepare unsaved */
239
+
240
+        /* all done */
186 241
         return(0);
187 242
 }
188 243
 
... ...
@@ -192,3 +247,51 @@ redata_save(redata_t *redata, char *filename)
192 247
 #warning TODO
193 248
         return(-1);
194 249
 }
250
+
251
+int
252
+redata_op_add(redata_t *redata, char *buf, int sizebuf, int pos)
253
+{
254
+}
255
+
256
+int
257
+redata_op_del(redata_t *redata, int pos, int size)
258
+{
259
+}
260
+
261
+int
262
+redata_op_move(redata_t *redata, int posorig, int size, int posdest)
263
+{
264
+}
265
+
266
+int
267
+redata_hash(redata_t *redata, char *resbuf129bytes)
268
+{
269
+        static char conv[]={"0123456789ABCDEF"};
270
+        Keccak_HashInstance hash;
271
+        int i,c;
272
+        if(resbuf129bytes!=NULL)
273
+                *resbuf129bytes='\0';
274
+        if(redata==NULL || resbuf129bytes==NULL) {
275
+                return(-1); /* sanity check failed */
276
+        }
277
+        if(Keccak_HashInitialize_SHA3_512(&hash)!=SUCCESS)
278
+                return(-1); /* init failed */
279
+        for(i=0;i<redata->sizechunks;i++) {
280
+                if(Keccak_HashUpdate(&hash, (void *) redata->chunks[i]->data,redata->chunks[i]->useddata)!=SUCCESS)
281
+                        return(-1); /* hash calc. error */
282
+        }
283
+        if(Keccak_HashFinal(&hash, (void *) resbuf129bytes)!=SUCCESS) {
284
+                *resbuf129bytes='\0';
285
+                return(-1); /* hash final calc. error */
286
+        }
287
+        resbuf129bytes[128]='\0';
288
+        for(i=63;i>=0;i--) {
289
+                c=((unsigned char *)resbuf129bytes)[i];
290
+                resbuf129bytes[i<<1]=conv[((c>>4)&0xf)];
291
+                resbuf129bytes[(i<<1)+1]=conv[(c&0xf)];
292
+        }
293
+#warning TODO: result is not as expected
294
+        return(0);
295
+}
296
+
297
+
Browse code

data structures skeleton

Dario Rodriguez authored on 25/02/2019 22:04:09
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,194 @@
1
+/*
2
+ * recenteditor_data.c
3
+ *
4
+ * A programmers editor
5
+ *
6
+ * Structures to hold the current file contents.
7
+ *
8
+ * Author: Dario Rodriguez dario@softhome.net
9
+ * This program is licensed under the terms of GNU GPL v2.1+
10
+ */
11
+
12
+#include <stdio.h>
13
+#include <stdlib.h>
14
+#include <unistd.h>
15
+#include <string.h>
16
+#include <sys/types.h>
17
+#include <sys/stat.h>
18
+#include <fcntl.h>
19
+
20
+#include "recenteditor_data.h"
21
+
22
+#define CHUNKSIZE 32768
23
+
24
+
25
+redata_t *
26
+redata_init(void)
27
+{
28
+        redata_t *redata;
29
+        if((redata=malloc(sizeof(redata_t)))==NULL)
30
+                return(NULL); /* sanity check failed */
31
+        memset(redata,0,sizeof(redata_t));
32
+        redata->sizechunks=0;
33
+        redata->chunks=NULL;
34
+        redata->chunkdatasize=CHUNKSIZE;
35
+        redata->available=0;
36
+        return(redata);
37
+}
38
+
39
+void
40
+redata_free(redata_t *redata)
41
+{
42
+        int i;
43
+        if(redata==NULL)
44
+                return; /* nothing to do */
45
+        for(i=0;i<redata->sizechunks;i++) {
46
+                if(redata->chunks[i]!=NULL)
47
+                        free(redata->chunks[i]),redata->chunks[i]=NULL;
48
+        }
49
+        redata->sizechunks=0;
50
+        if(redata->chunks!=NULL)
51
+                free(redata->chunks),redata->chunks=NULL;
52
+        free(redata),redata=NULL;
53
+        return;
54
+}
55
+
56
+int
57
+redata_getsize(redata_t *redata)
58
+{
59
+        if(redata==NULL)
60
+                return(0); /* sanity check failed */
61
+        return(redata->chunkdatasize*redata->sizechunks);
62
+}
63
+
64
+int
65
+redata_getused(redata_t *redata)
66
+{
67
+        if(redata==NULL)
68
+                return(0); /* sanity check failed */
69
+        return(redata_getsize(redata)-redata_getavailable(redata));
70
+}
71
+
72
+int
73
+redata_getavailable(redata_t *redata)
74
+{
75
+        if(redata==NULL)
76
+                return(0); /* sanity check failed */
77
+        return(redata->available);
78
+}
79
+
80
+int
81
+redata_wipe(redata_t *redata)
82
+{
83
+        int i;
84
+        if(redata==NULL)
85
+                return(-1); /* sanity check failed */
86
+        for(i=0;i<redata->sizechunks;i++) {
87
+                redata->chunks[i]->useddata=0;
88
+                memset(&(redata->chunks[i]->whatin),0,sizeof(whatin_t));
89
+        }
90
+        redata->available=redata_getsize(redata);
91
+        return(0);
92
+}
93
+
94
+int
95
+redata_preallocate(redata_t *redata, int newsize)
96
+{
97
+        int cursize;
98
+        int nchunks;
99
+        int i;
100
+        int rechunksize;
101
+        rechunk_t *newchunks,*chunk;
102
+        int oldsizechunks;
103
+        if(redata==NULL || redata->chunkdatasize==0 || newsize<0)
104
+                return(-1); /* sanity check failed */
105
+        if((cursize=redata_getsize(redata))>=newsize)
106
+                return(0); /* all done */
107
+        nchunks=(newsize-cursize+redata->chunkdatasize-1)/redata->chunkdatasize;
108
+        rechunksize=sizeof(rechunk_t)-1+redata->chunkdatasize;
109
+        if((newchunks=realloc(redata->chunks,sizeof(rechunk_t *)*(redata->sizechunks+nchunks)))==NULL)
110
+                return(-1); /* insuf. mem. */
111
+        redata->chunks=newchunks;
112
+        memset(redata->chunks+redata->sizechunks,0,sizeof(rechunk_t *)*nchunks);
113
+        oldsizechunks=redata->sizechunks;
114
+        for(i=0;i<nchunks;i++) {
115
+                if((chunk=malloc(rechunksize))==NULL)
116
+                        return(-1);  /* insuf. mem. */
117
+                memset(chunk,0,rechunksize);
118
+                chunk->useddata=0;
119
+                redata->chunks[oldsizechunks+i]=chunk;
120
+                redata->sizechunks++;
121
+                redata->available+=redata->chunkdatasize;
122
+        }
123
+        return(0);
124
+}
125
+
126
+int
127
+redata_fill_whatin(redata_t *redata, int chunkno)
128
+{
129
+        rechunk_t *chunk;
130
+        int nlcount;
131
+        int i,lim;
132
+        if(redata==NULL || chunkno<0 || chunkno>=redata->sizechunks || redata->chunks[chunkno]==NULL)
133
+                return(-1); /* sanity check failed */
134
+        chunk=redata->chunks[chunkno];
135
+        memset(&(chunk->whatin),0,sizeof(whatin_t));
136
+        nlcount=0;
137
+        for(i=0,lim=chunk->useddata;i<lim;i++) {
138
+                nlcount+=(chunk->data[i]=='\n')?1:0;
139
+        }
140
+        chunk->whatin.nlcount=nlcount;
141
+        return(0);
142
+}
143
+
144
+
145
+int
146
+redata_load(redata_t *redata, char *filename)
147
+{
148
+        int fd,nread,totalread;
149
+        int chunkno, avail;
150
+        struct stat statbuf;
151
+        rechunk_t *chunk;
152
+        redata_wipe(redata);
153
+        if((fd=open(filename,O_RDONLY))==-1 || fstat(fd,&statbuf)!=0 || !S_ISREG(statbuf.st_mode)) {
154
+                if(fd!=-1)
155
+                        close(fd),fd=-1;
156
+                return(-1); /* file not found, couldn't query size or not regular file */
157
+        }
158
+        if(redata_preallocate(redata,statbuf.st_size)) {
159
+                if(fd!=-1)
160
+                        close(fd),fd=-1;
161
+                return(-1); /* insuf. mem. */
162
+        }
163
+        for(totalread=0,chunkno=0,nread=0;totalread<statbuf.st_size;totalread+=nread,nread=0) {
164
+                if(chunkno>=redata->sizechunks || redata->chunks[chunkno]==NULL) {
165
+                        if(fd!=-1)
166
+                                close(fd),fd=-1;
167
+                        fprintf(stderr,"redata_load: INTERNAL ERROR\n");
168
+                        return(-2); /* internal error */
169
+                }
170
+                chunk=redata->chunks[chunkno];
171
+                avail=redata->chunkdatasize-chunk->useddata;
172
+                avail=((totalread+avail)>statbuf.st_size)?statbuf.st_size-totalread:avail;
173
+                if(avail==0) {
174
+                        chunkno++; /* full, try next */
175
+                        continue;
176
+                }
177
+                if((nread=read(fd,chunk->data+chunk->useddata,avail))<=0) {
178
+                        if(fd!=-1)
179
+                                close(fd),fd=-1;
180
+                        return(-1); /* short read */
181
+                }
182
+                chunk->useddata+=nread;
183
+                redata->available-=nread;
184
+                redata_fill_whatin(redata,chunkno);
185
+        }
186
+        return(0);
187
+}
188
+
189
+int
190
+redata_save(redata_t *redata, char *filename)
191
+{
192
+#warning TODO
193
+        return(-1);
194
+}