Browse code

bugfix: the hint system was not able to extract the first word of the file

Dario Rodriguez authored on 22/01/2024 18:37:11
Showing 1 changed files
... ...
@@ -1779,7 +1779,7 @@ redata_getsubstr(redata_t *redata, long posini, long posend, char *buf, int len,
1779 1779
         int offset;
1780 1780
         int ooff;
1781 1781
         long pos;
1782
-        if(redata==NULL || posini<=0 || posini>redata_getsize(redata) || posend<=0 || posend>redata_getsize(redata) || buf==NULL || len<1 || usedbuf==NULL)
1782
+        if(redata==NULL || posini<0 || posini>redata_getsize(redata) || posend<=0 || posend>redata_getsize(redata) || buf==NULL || len<1 || usedbuf==NULL)
1783 1783
                 return(-1); /* sanity check failed */
1784 1784
         if(redata_getposptr(redata,posini,&numchunk,&offset)!=0)
1785 1785
                 return(-1); /* couldn't get pos */
Browse code

Don't ask for exit confirmation on new files (was triggered because of the inserted \n at end-of-file)

Dario Rodriguez authored on 14/04/2023 18:45:47
Showing 1 changed files
... ...
@@ -817,13 +817,21 @@ redata_save(redata_t *redata, char *paramfilename, char **errordesc)
817 817
 }
818 818
 
819 819
 int
820
-redata_needs_saving(redata_t *redata)
820
+redata_needssaving(redata_t *redata)
821 821
 {
822 822
         if(redata==NULL)
823 823
                 return(0);
824 824
         return( (redata->needs_saving)?1:0 );
825 825
 }
826 826
 
827
+int
828
+redata_needssaving_reset(redata_t *redata)
829
+{
830
+        if(redata==NULL)
831
+                return(-1);
832
+        redata->needs_saving=0;
833
+        return(0);
834
+}
827 835
 
828 836
 int
829 837
 redata_undobuf_reserve(redata_t *redata, undostack_t *stack, int minavail)
Browse code

bugfix: sometimes the highlighting of the maching parens was wrong, because redata_searchbackwards() was not searchching correctly if position was the second byte of the chunk and the searched element was in the first byte (it skipped that occurrence)

Dario Rodriguez authored on 06/10/2022 10:29:52
Showing 1 changed files
... ...
@@ -1630,6 +1630,10 @@ redata_searchbackwards(redata_t *redata, long posini, char *str, int len)
1630 1630
                 return(posini); /* nothing to do, empty string is always equal */
1631 1631
         if(redata_getposptr(redata,posini,&numchunk,&offset)!=0)
1632 1632
                 return(-1); /* couldn't get pos */
1633
+        while((numchunk+1)<redata->sizechunks && offset==redata->chunks[numchunk]->useddata) {
1634
+                numchunk++;
1635
+                offset=0;
1636
+        }
1633 1637
         chunkstartpos=posini-offset;
1634 1638
         for(offset++;numchunk>=0
1635 1639
           ;numchunk--
Browse code

Add function to extract the previous utf8 character to a pos. Add function to extract a substring from a redata buffer.

Dario Rodriguez authored on 08/09/2022 21:57:42
Showing 1 changed files
... ...
@@ -1716,6 +1716,76 @@ redata_getutf8char(redata_t *redata, long pos, char *buf, int len, int *usedbuf)
1716 1716
         return(0);
1717 1717
 }
1718 1718
 
1719
+int
1720
+redata_getprevutf8char(redata_t *redata, long pos, char *buf, int len, int *usedbuf)
1721
+{
1722
+        int numchunk;
1723
+        int offset;
1724
+        int ooff;
1725
+        int c;
1726
+        int n;
1727
+        char tmpchar;
1728
+        if(redata==NULL || pos<=0 || pos>redata_getsize(redata) || buf==NULL || len<1 || usedbuf==NULL)
1729
+                return(-1); /* sanity check failed */
1730
+        if(redata_getposptr(redata,pos,&numchunk,&offset)!=0)
1731
+                return(-1); /* couldn't get pos */
1732
+        while(numchunk>0 && offset==0) {
1733
+                numchunk--;
1734
+                offset=redata->chunks[numchunk]->useddata;
1735
+        }
1736
+        if(offset==0)
1737
+                return(-1); /* at start, no data */
1738
+        ooff=0;
1739
+        c=redata->chunks[numchunk]->data[offset-1];
1740
+        offset--;
1741
+        ((unsigned char *)buf)[ooff++]=c;
1742
+        while(ooff<len && (!UTF8_IS_ASCII(c) || UTF8_IS_MULTIBYTECONT(c))) {
1743
+                while(numchunk>0 && offset==0) {
1744
+                        numchunk--;
1745
+                        offset=redata->chunks[numchunk]->useddata;
1746
+                }
1747
+                if(numchunk==0 && offset==0)
1748
+                        break;
1749
+                c=redata->chunks[numchunk]->data[offset-1];
1750
+                offset--;
1751
+                ((unsigned char *)buf)[ooff++]=c;
1752
+        }
1753
+        *usedbuf=ooff;
1754
+        /* invert the data in buf */
1755
+        for(n=0;(ooff-1-n)>n;n++) {
1756
+                tmpchar=buf[n];
1757
+                buf[n]=buf[ooff-1-n];
1758
+                buf[ooff-1-n]=tmpchar;
1759
+        }
1760
+        return(0);
1761
+}
1762
+
1763
+int
1764
+redata_getsubstr(redata_t *redata, long posini, long posend, char *buf, int len, int *usedbuf)
1765
+{
1766
+        int numchunk;
1767
+        int offset;
1768
+        int ooff;
1769
+        long pos;
1770
+        if(redata==NULL || posini<=0 || posini>redata_getsize(redata) || posend<=0 || posend>redata_getsize(redata) || buf==NULL || len<1 || usedbuf==NULL)
1771
+                return(-1); /* sanity check failed */
1772
+        if(redata_getposptr(redata,posini,&numchunk,&offset)!=0)
1773
+                return(-1); /* couldn't get pos */
1774
+        ooff=0;
1775
+        pos=posini;
1776
+        while(ooff<len && pos<posend) {
1777
+                while(numchunk<redata->sizechunks && redata->chunks[numchunk]!=NULL && offset>=redata->chunks[numchunk]->useddata) {
1778
+                        numchunk++;
1779
+                        offset=0;
1780
+                }
1781
+                if(numchunk>=redata->sizechunks)
1782
+                        return(-1); /* at end; no data */
1783
+                buf[ooff++]=redata->chunks[numchunk]->data[offset++];
1784
+                pos++;
1785
+        }
1786
+        *usedbuf=ooff;
1787
+        return(0);
1788
+}
1719 1789
 
1720 1790
 int
1721 1791
 redata_generic_utf8len(char *ptr, int size)
Browse code

Implement a primitive function navigator when clicking on the status line

Dario Rodriguez authored on 17/02/2022 22:52:05
Showing 1 changed files
... ...
@@ -258,6 +258,26 @@ redata_getchar(redata_t *redata, long pos)
258 258
         return(-1); /* not found */
259 259
 }
260 260
 
261
+int
262
+redata_getdata(redata_t *redata, long frompos, long size, char *dest)
263
+{
264
+        int nchunk,off,avail;
265
+        long n;
266
+        if(redata==NULL || frompos<0 || size<0 || dest==NULL || (frompos+size)>redata_getused(redata) || redata_getposptr(redata,frompos,&nchunk,&off)!=0)
267
+                return(-1); /* sanity check failed */
268
+        for(n=0;n<size && nchunk<redata->sizechunks;nchunk++,off=0) {
269
+                avail=redata->chunks[nchunk]->useddata-off;
270
+                if(avail<=0)
271
+                        continue;
272
+                if(avail>(size-n))
273
+                        avail=size-n;
274
+                memcpy(dest+n,redata->chunks[nchunk]->data+off,avail);
275
+                n+=avail;
276
+        }
277
+        return(0);
278
+}
279
+
280
+
261 281
 int
262 282
 redata_wipe(redata_t *redata)
263 283
 {
... ...
@@ -647,7 +667,6 @@ redata_load(redata_t *redata, char *filename, char **errordesc)
647 667
         struct stat statbuf;
648 668
         rechunk_t *chunk;
649 669
         int i;
650
-        int reply;
651 670
         if(redata==NULL || filename==NULL) {
652 671
                 if(errordesc!=NULL)
653 672
                         *errordesc="Internal error";
... ...
@@ -2157,6 +2176,107 @@ redata_linecol2pos(redata_t *redata, int line, int colrequest, long *pos, int *c
2157 2176
         return(0);
2158 2177
 }
2159 2178
 
2179
+int
2180
+redata_line_total(redata_t *redata)
2181
+{
2182
+        long chunkpos;
2183
+        int nchunk;
2184
+        int startline;
2185
+        rechunk_t *chunk,*lastchunkwithdata;
2186
+        if(redata==NULL)
2187
+                return(-1);
2188
+        /* find line */
2189
+        lastchunkwithdata=NULL;
2190
+        for(nchunk=0,chunkpos=0,startline=0
2191
+          ;nchunk<redata->sizechunks
2192
+          ;chunkpos+=(chunk!=NULL)?chunk->useddata:0
2193
+            ,startline+=(chunk!=NULL)?chunk->whatin.nlcount:0,nchunk++) {
2194
+                if((chunk=redata->chunks[nchunk])==NULL)
2195
+                        continue;
2196
+                if(!(chunk->whatin_fresh))
2197
+                        redata_whatin_refresh(redata,nchunk);
2198
+                if(chunk->useddata>0)
2199
+                        lastchunkwithdata=chunk;
2200
+        }
2201
+        if(lastchunkwithdata!=NULL && lastchunkwithdata->data[lastchunkwithdata->useddata-1]!='\n')
2202
+                startline++;
2203
+        return(startline);
2204
+}
2205
+
2206
+int
2207
+redata_line_getendstr(redata_t *redata, int line, char *buf, int sizebuf)
2208
+{
2209
+        return(redata_line_getendstrtrimmed(redata,line,buf,sizebuf,NULL));
2210
+}
2211
+
2212
+int
2213
+redata_line_getendstrtrimmed(redata_t *redata, int line, char *buf, int sizebuf, char *trimchars)
2214
+{
2215
+        long startpos,endpos;
2216
+        int coldone;
2217
+        if(redata==NULL || line<0 || buf==NULL || sizebuf<1)
2218
+                return(-1); /* sanity check error */
2219
+        if(redata_linecol2pos(redata,line,0,&startpos,&coldone)!=0
2220
+          || redata_line_realend(redata,startpos,&endpos)!=0) {
2221
+                return(-1); /* line not found */
2222
+        }
2223
+        if(endpos>startpos && redata_getchar(redata,endpos-1)=='\n')
2224
+                endpos--;
2225
+        if(trimchars!=NULL) {
2226
+                while(endpos>startpos && strchr(trimchars,redata_getchar(redata,endpos))!=NULL)
2227
+                        endpos--;
2228
+        }
2229
+        if((endpos-startpos)>(sizebuf-1))
2230
+                startpos=endpos-(sizebuf-1);
2231
+        redata_getdata(redata,startpos,endpos-startpos,buf);
2232
+        buf[endpos-startpos]='\0';
2233
+        return(0);
2234
+}
2235
+
2236
+int
2237
+redata_line_getsize(redata_t *redata, int line) /* includes the \n */
2238
+{
2239
+        long startpos,endpos;
2240
+        int coldone;
2241
+        if(redata==NULL || line<0)
2242
+                return(-1); /* sanity check error */
2243
+        if(redata_linecol2pos(redata,line,0,&startpos,&coldone)!=0
2244
+          || redata_line_realend(redata,startpos,&endpos)!=0) {
2245
+                return(-1); /* line not found */
2246
+        }
2247
+        return(endpos-startpos);
2248
+}
2249
+
2250
+int
2251
+redata_line_getstartstr(redata_t *redata, int line, char *buf, int sizebuf)
2252
+{
2253
+        return(redata_line_getstartstrtrimmed(redata,line,buf,sizebuf,NULL));
2254
+}
2255
+
2256
+int
2257
+redata_line_getstartstrtrimmed(redata_t *redata, int line, char *buf, int sizebuf, char *trimchars)
2258
+{
2259
+        long startpos,endpos;
2260
+        int coldone;
2261
+        if(redata==NULL || line<0 || buf==NULL || sizebuf<1)
2262
+                return(-1); /* sanity check error */
2263
+        if(redata_linecol2pos(redata,line,0,&startpos,&coldone)!=0
2264
+          || redata_line_realend(redata,startpos,&endpos)!=0) {
2265
+                return(-1); /* line not found */
2266
+        }
2267
+        if(endpos>startpos && redata_getchar(redata,endpos-1)=='\n')
2268
+                endpos--;
2269
+        if(trimchars!=NULL) {
2270
+                while(startpos<endpos && strchr(trimchars,redata_getchar(redata,startpos))!=NULL)
2271
+                        startpos++;
2272
+        }
2273
+        if((endpos-startpos)>(sizebuf-1))
2274
+                endpos=startpos+(sizebuf-1);
2275
+        redata_getdata(redata,startpos,endpos-startpos,buf);
2276
+        buf[endpos-startpos]='\0';
2277
+        return(0);
2278
+}
2279
+
2160 2280
 static char *
2161 2281
 securesave_genname(char *filename, char *buf, int bufsize)
2162 2282
 {
Browse code

bugfix: copying a block to the end of the line was inserting an additional space

Dario Rodriguez authored on 10/01/2022 14:56:25
Showing 1 changed files
... ...
@@ -2138,6 +2138,7 @@ redata_linecol2pos(redata_t *redata, int line, int colrequest, long *pos, int *c
2138 2138
                 done=0;
2139 2139
                 for(i=0;i<len && n<colrequest;i++,curpos++) {
2140 2140
                         if(ptr[i]=='\n') {
2141
+                                n++;
2141 2142
                                 done=1;
2142 2143
                                 break;
2143 2144
                         } else if(UTF8_IS_ASCII_OR_START(ptr[i])) {                    
Browse code

Update author email

Dario Rodriguez authored on 07/01/2022 17:57:32
Showing 1 changed files
... ...
@@ -5,7 +5,7 @@
5 5
  *
6 6
  * Structures to hold the current file contents.
7 7
  *
8
- * Author: Dario Rodriguez dario@softhome.net
8
+ * Author: Dario Rodriguez antartica@whereismybit.com
9 9
  * This program is licensed under the terms of GNU GPL v2.1+
10 10
  */
11 11
 
Browse code

bugfix: saving a file to a relative symlink now also works. This also fix the filename sent to plugins in files that are symlinks.

Dario Rodriguez authored on 11/07/2021 10:35:47
Showing 1 changed files
... ...
@@ -733,10 +733,26 @@ redata_save(redata_t *redata, char *paramfilename, char **errordesc)
733 733
                 return(-1); /* sanity check failed */
734 734
         }
735 735
         filename=paramfilename;
736
+        memset(tmpfile,0,sizeof(tmpfile));
736 737
         if(stat(paramfilename,&statbuf)==0
737 738
           && (statbuf.st_mode & S_IFLNK)!=0
738
-          && readlink(paramfilename,tmplinkfilename,sizeof(tmplinkfilename))>0) {
739
-                tmplinkfilename[sizeof(tmplinkfilename)-1]='\0';
739
+          && readlink(paramfilename,tmpfile,sizeof(tmpfile))>0) {
740
+                tmpfile[sizeof(tmpfile)-1]='\0';
741
+                if(tmpfile[0]=='/') {
742
+                        /* absolute symlink, just copy it */
743
+                        strncpy(tmplinkfilename,tmpfile,sizeof(tmplinkfilename));
744
+                        tmplinkfilename[sizeof(tmplinkfilename)-1]='\0';
745
+                } else {
746
+                        char *aux;
747
+                        int off;
748
+                        /* relative symlink, put it after the path of paramfilename */
749
+                        off=0;
750
+                        if((aux=mymemrchr(paramfilename,'/',strlen(paramfilename)))!=NULL)
751
+                                off=(aux-paramfilename+1);
752
+                        memcpy(tmplinkfilename,paramfilename,off);
753
+                        strncpy(tmplinkfilename+off,tmpfile,sizeof(tmplinkfilename)-off);
754
+                        tmplinkfilename[sizeof(tmplinkfilename)-1]='\0';
755
+                }
740 756
                 filename=tmplinkfilename;
741 757
         }
742 758
         if((securesave_genname(filename,tmpfile,sizeof(tmpfile)))==NULL) {
... ...
@@ -772,7 +788,7 @@ redata_save(redata_t *redata, char *paramfilename, char **errordesc)
772 788
         }
773 789
         for(i=0;i<redata->sizeplugins;i++) {
774 790
                 if(redata->plugins[i].postsave!=NULL)
775
-                        redata->plugins[i].postsave(redata,redata->plugins+i,redata->filename,filename);
791
+                        redata->plugins[i].postsave(redata,redata->plugins+i,redata->filename,paramfilename);
776 792
         }
777 793
         strncpy(redata->filename,paramfilename,sizeof(redata->filename));
778 794
         redata->filename[sizeof(redata->filename)-1]='\0';
... ...
@@ -2157,7 +2173,8 @@ mymemrchr(const void *s, int c, size_t n)
2157 2173
         b=(*((unsigned int *)(&c)))&0xff;
2158 2174
         for(i=0;i<n;i++) {
2159 2175
                 if(((unsigned char *)s)[i]==b)
2160
-                        res=(((unsigned char *)s)+i);        }
2176
+                        res=(((unsigned char *)s)+i);
2177
+        }
2161 2178
         return(res);
2162 2179
 }
2163 2180
 
Browse code

bugfix: Saving a file now follows symlinks

Dario Rodriguez authored on 11/07/2021 09:29:02
Showing 1 changed files
... ...
@@ -719,18 +719,27 @@ redata_load(redata_t *redata, char *filename, char **errordesc)
719 719
 }
720 720
 
721 721
 int
722
-redata_save(redata_t *redata, char *filename, char **errordesc)
722
+redata_save(redata_t *redata, char *paramfilename, char **errordesc)
723 723
 {
724 724
         int fd;
725 725
         int i,n;
726
+        char tmplinkfilename[PATH_MAX+1];
726 727
         char tmpfile[PATH_MAX+1];
727 728
         struct stat statbuf;
728
-        if(redata==NULL || filename==NULL) {
729
+        char *filename;
730
+        if(redata==NULL || paramfilename==NULL) {
729 731
                 if(errordesc!=NULL)
730 732
                         *errordesc="Internal error";
731 733
                 return(-1); /* sanity check failed */
732 734
         }
733
-        if((securesave_genname(redata->filename,tmpfile,sizeof(tmpfile)))==NULL) {
735
+        filename=paramfilename;
736
+        if(stat(paramfilename,&statbuf)==0
737
+          && (statbuf.st_mode & S_IFLNK)!=0
738
+          && readlink(paramfilename,tmplinkfilename,sizeof(tmplinkfilename))>0) {
739
+                tmplinkfilename[sizeof(tmplinkfilename)-1]='\0';
740
+                filename=tmplinkfilename;
741
+        }
742
+        if((securesave_genname(filename,tmpfile,sizeof(tmpfile)))==NULL) {
734 743
                 if(errordesc!=NULL)
735 744
                         *errordesc="Malformed filename";
736 745
                 return(-1); /* malformed filename */
... ...
@@ -765,7 +774,7 @@ redata_save(redata_t *redata, char *filename, char **errordesc)
765 774
                 if(redata->plugins[i].postsave!=NULL)
766 775
                         redata->plugins[i].postsave(redata,redata->plugins+i,redata->filename,filename);
767 776
         }
768
-        strncpy(redata->filename,filename,sizeof(redata->filename));
777
+        strncpy(redata->filename,paramfilename,sizeof(redata->filename));
769 778
         redata->filename[sizeof(redata->filename)-1]='\0';
770 779
         /* mark as not modified */
771 780
         redata->needs_saving=0;
Browse code

fix: correctly set the boundaries of data to move on Ctrl+K+C/Ctrl+K+V

Dario Rodriguez authored on 02/06/2021 05:31:03
Showing 1 changed files
... ...
@@ -2098,12 +2098,20 @@ redata_linecol2pos(redata_t *redata, int line, int colrequest, long *pos, int *c
2098 2098
         if(i>chunk->useddata)
2099 2099
                 return(-1); /* line not found */
2100 2100
         realstart=chunkpos+i;
2101
-        /* find col */
2101
+        /* trivial case: col 0 */
2102
+        if(colrequest==0) {
2103
+                if(coldone!=NULL)
2104
+                        *coldone=0;
2105
+                if(pos!=NULL)
2106
+                        *pos=realstart;
2107
+                return(0);
2108
+        }
2109
+        /* find col, stopping at the start of next char */
2102 2110
         for(n=-1,curpos=realstart;n<colrequest;) {
2103 2111
                 if(redata_line_rawinfo(redata,curpos,&startpos,&ptr,&len,NULL)==-1 || len==0)
2104 2112
                         return(-1); /* couldn't get current line data */
2105 2113
                 done=0;
2106
-                for(i=0;i<len && n<colrequest;i++) {
2114
+                for(i=0;i<len && n<colrequest;i++,curpos++) {
2107 2115
                         if(ptr[i]=='\n') {
2108 2116
                                 done=1;
2109 2117
                                 break;
... ...
@@ -2113,7 +2121,6 @@ redata_linecol2pos(redata_t *redata, int line, int colrequest, long *pos, int *c
2113 2121
                                         break;
2114 2122
                         }
2115 2123
                 }
2116
-                curpos=startpos+i;
2117 2124
                 if(done)
2118 2125
                         break;
2119 2126
         }
Browse code

fix: correctly handling of spaces at start and end of doing a Ctrl+C/Ctrl+V.

Dario Rodriguez authored on 30/05/2021 15:04:46
Showing 1 changed files
... ...
@@ -236,6 +236,28 @@ redata_getposptr(redata_t *redata, long pos, int *numchunk, int *offset)
236 236
         return(-1);
237 237
 }
238 238
 
239
+int
240
+redata_getchar(redata_t *redata, long pos)
241
+{
242
+        int numchunk;
243
+        int offset;
244
+        int avail;
245
+        rechunk_t *chunk;
246
+        if(redata==NULL || pos<0 || pos>=redata_getsize(redata))
247
+                return(-1); /* sanity check failed */
248
+        if(redata_getposptr(redata,pos,&numchunk,&offset)!=0)
249
+                return(-1); /* couldn't get pos */
250
+        /* search for data starting at that pos */
251
+        for(;numchunk<redata->sizechunks;numchunk++,offset=0) {
252
+                chunk=redata->chunks[numchunk];
253
+                avail=chunk->useddata-offset;
254
+                if(avail>0) {
255
+                        return((int) (((unsigned char *)chunk->data)[offset]));
256
+                }
257
+        }
258
+        return(-1); /* not found */
259
+}
260
+
239 261
 int
240 262
 redata_wipe(redata_t *redata)
241 263
 {
Browse code

Preserve file permissions on save

Dario Rodriguez authored on 31/03/2021 16:36:06
Showing 1 changed files
... ...
@@ -28,9 +28,9 @@
28 28
 //#define CHUNKSIZE 32768
29 29
 //#define CHUNKSIZE 4096
30 30
 //#define CHUNKSIZE 1024
31
-//#define CHUNKSIZE 160
31
+#define CHUNKSIZE 160
32 32
 //#define CHUNKSIZE 16
33
-#define CHUNKSIZE 3
33
+//#define CHUNKSIZE 3
34 34
 #warning XXX: TODO: CHANGE CHUNKSIZE TO A SANE VALUE (not 1!), THIS IS ONLY FOR TESTING UTF-8 multi-byte CHARS
35 35
 
36 36
 #define UNDOBLOCK 1024
... ...
@@ -702,6 +702,7 @@ redata_save(redata_t *redata, char *filename, char **errordesc)
702 702
         int fd;
703 703
         int i,n;
704 704
         char tmpfile[PATH_MAX+1];
705
+        struct stat statbuf;
705 706
         if(redata==NULL || filename==NULL) {
706 707
                 if(errordesc!=NULL)
707 708
                         *errordesc="Internal error";
... ...
@@ -712,7 +713,10 @@ redata_save(redata_t *redata, char *filename, char **errordesc)
712 713
                         *errordesc="Malformed filename";
713 714
                 return(-1); /* malformed filename */
714 715
         }
715
-        if((fd=open(tmpfile,O_WRONLY|O_TRUNC|O_CREAT,0644))==-1) {
716
+        memset(&statbuf,0,sizeof(statbuf));
717
+        if(stat(filename,&statbuf)!=0)
718
+                statbuf.st_mode=0644;
719
+        if((fd=open(tmpfile,O_WRONLY|O_TRUNC|O_CREAT,statbuf.st_mode))==-1) {
716 720
                 if(errordesc!=NULL)
717 721
                         *errordesc="Couldn't open file for writing";
718 722
                 return(-1); /* couldn't open file for writing */
Browse code

bugfix: was showing strange characters when a multibyte UTF-8 char crossed a chunk boundary; now behaves as expected (multibyte UTF-8 characters crossing a boundary display correctly)

Dario Rodriguez authored on 20/03/2021 01:53:12
Showing 1 changed files
... ...
@@ -29,13 +29,28 @@
29 29
 //#define CHUNKSIZE 4096
30 30
 //#define CHUNKSIZE 1024
31 31
 //#define CHUNKSIZE 160
32
-#define CHUNKSIZE 16
32
+//#define CHUNKSIZE 16
33
+#define CHUNKSIZE 3
34
+#warning XXX: TODO: CHANGE CHUNKSIZE TO A SANE VALUE (not 1!), THIS IS ONLY FOR TESTING UTF-8 multi-byte CHARS
35
+
33 36
 #define UNDOBLOCK 1024
34 37
 #define ADDNBLOCK 1024
35 38
 #define UNDOGROWSIZE (256*1024)
36 39
 #define SECURESAVEPREFIX "."
37 40
 #define SECURESAVEPOSTFIX ".saving"
38 41
 
42
+#define UTF8_IS_ASCII_OR_START(c) (((c)&0xc0)!=0x80)
43
+#define UTF8_IS_ASCII(c) (((c)&0x80)==0)
44
+#define UTF8_IS_MULTIBYTESTART(c) ((((c)&0x80)==0x80)&&(((c)&(0x80|0x40))!=0x80))
45
+#define UTF8_IS_MULTIBYTECONT(c) (((c)&(0x80|0x40))==0x80)
46
+
47
+#define UTF8_MULTIBYTESTART2LEN(c) ((((c)&0xe0)==0xc0)?2: \
48
+                                    (((c)&0xf0)==0xe0)?3: \
49
+                                    (((c)&0xf8)==0xf0)?4: \
50
+                                    (((c)&0xfc)==0xf8)?5: \
51
+                                    (((c)&0xfe)==0xfc)?6: \
52
+                                    1)
53
+
39 54
 static int redata_hash_gen(redata_t *redata, char *filename, char *buf, long buflen, char *resbuf129bytes);
40 55
 static char *securesave_genname(char *filename, char *buf, int bufsize);
41 56
 static void *mymemrchr(const void *s, int c, size_t n);
... ...
@@ -1587,6 +1602,50 @@ redata_memcmp(redata_t *redata, long pos, char *str, int len)
1587 1602
 
1588 1603
 }
1589 1604
 
1605
+int
1606
+redata_getutf8char(redata_t *redata, long pos, char *buf, int len, int *usedbuf)
1607
+{
1608
+        int numchunk;
1609
+        int offset;
1610
+        rechunk_t *chunk;
1611
+        int ooff;
1612
+        int req;
1613
+        int c;
1614
+        if(redata==NULL || pos<0 || pos>redata_getsize(redata) || buf==NULL || len<1 || usedbuf==NULL)
1615
+                return(-1); /* sanity check failed */
1616
+        ooff=0;
1617
+        if(redata_getposptr(redata,pos,&numchunk,&offset)!=0)
1618
+                return(-1); /* couldn't get pos */
1619
+        while(numchunk<redata->sizechunks && redata->chunks[numchunk]!=NULL && offset>=redata->chunks[numchunk]->useddata) {
1620
+                numchunk++;
1621
+                offset=0;
1622
+        }
1623
+        if(numchunk>=redata->sizechunks)
1624
+                return(-1); /* at end; no data */
1625
+        chunk=redata->chunks[numchunk];
1626
+        c=chunk->data[offset];
1627
+        ((unsigned char *)buf)[ooff++]=c;
1628
+        if(UTF8_IS_ASCII(c) || UTF8_IS_MULTIBYTECONT(c))
1629
+                req=1;
1630
+        else
1631
+                req=UTF8_MULTIBYTESTART2LEN(c);
1632
+        offset++;
1633
+        for(;ooff<len && ooff<req && numchunk<redata->sizechunks
1634
+            ;numchunk++,chunk=redata->chunks[numchunk],offset=0) {
1635
+                if(offset>=chunk->useddata)
1636
+                        continue;
1637
+                c=0x80|0x40; /* initialize c to whatever multibycont for the check after the while */
1638
+                while(ooff<len && ooff<req
1639
+                  && (c=chunk->data[offset])!=0 && UTF8_IS_MULTIBYTECONT(c)) {
1640
+                        ((unsigned char *)buf)[ooff++]=c;
1641
+                }
1642
+                if(!UTF8_IS_MULTIBYTECONT(c))
1643
+                        break;
1644
+        }
1645
+        *usedbuf=ooff;
1646
+        return(0);
1647
+}
1648
+
1590 1649
 
1591 1650
 int
1592 1651
 redata_generic_utf8len(char *ptr, int size)
... ...
@@ -1606,6 +1665,63 @@ redata_generic_utf8len(char *ptr, int size)
1606 1665
 /*#warning TODO: XXX Also consider tabs*/
1607 1666
 }
1608 1667
 
1668
+int
1669
+redata_generic_utf8lenincomplete(char *ptr, int size, int *nstartincomplete,int *nendincomplete, int *nendrequired)
1670
+{
1671
+        int len,i;
1672
+        int lastistart,lastclen;
1673
+/*#warning TODO: XXX support combining code points (at least U+0300 - U+036F ( https://en.wikipedia.org/wiki/Combining_character ) */
1674
+        if(size<0 || (ptr==NULL && size!=0) || nstartincomplete==NULL || nendincomplete==NULL)
1675
+                return(-1);
1676
+        /* from RFC2279/RFC3629, one character is up to 6 bytes:
1677
+           first    last     Byte1      Byte2      Byte3      Byte4
1678
+           U+0000   U+007F   0xxxxxxx
1679
+           U+0080   U+07FF   110xxxxx   10xxxxxx
1680
+           U+0800   U+FFFF   1110xxxx   10xxxxxx   10xxxxxx
1681
+          U+10000 U+10FFFF   11110xxx   10xxxxxx   10xxxxxx   10xxxxxx
1682
+            ...
1683
+         */   
1684
+        i=0;
1685
+        len=0;
1686
+        /* nstartincomplete */
1687
+        *nstartincomplete=0;
1688
+        while(i<size && (ptr[i]&(0x80|0x40))==0x80) {
1689
+                (*nstartincomplete)++;
1690
+                i++;
1691
+        }
1692
+        /* len */
1693
+        lastistart=-1;
1694
+        lastclen=0;
1695
+        for(;i<size;i++) { 
1696
+                len+=((ptr[i]&0xc0)!=0x80)?1:0;
1697
+                if((ptr[i]&0x80)==0x00) {
1698
+                        /* ASCII */
1699
+                        lastistart=i;
1700
+                        lastclen=1;
1701
+                } else if((ptr[i]&0xc0)!=0x80) {
1702
+                        /* multibytechar start (as ASCII case has already been processed) */
1703
+                        lastistart=i;
1704
+                        lastclen=((ptr[i]&0xe0)==0xc0)?2:
1705
+                                 ((ptr[i]&0xf0)==0xe0)?3:
1706
+                                 ((ptr[i]&0xf8)==0xf0)?4:
1707
+                                 ((ptr[i]&0xfc)==0xf8)?5:
1708
+                                 ((ptr[i]&0xfe)==0xfc)?6:
1709
+                                 1; /* unknown type of multibytechar */
1710
+                }
1711
+        }
1712
+        /* nendincomplete */
1713
+        *nendincomplete=0;
1714
+        *nendrequired=0;
1715
+        if(lastistart!=-1 && (lastistart+lastclen)>size) {
1716
+                *nendrequired=lastclen;
1717
+                *nendincomplete=(lastistart+lastclen-size);
1718
+                len--;
1719
+        }
1720
+        /* all done */
1721
+        return(len);
1722
+/*#warning TODO: XXX Also consider tabs*/
1723
+}
1724
+
1609 1725
 char *
1610 1726
 redata_generic_utf8col(char *ptr, int size, int col)
1611 1727
 {
... ...
@@ -1654,7 +1770,6 @@ redata_generic_utf8isstartbyte(int candidate)
1654 1770
         return(0);
1655 1771
 }
1656 1772
 
1657
-
1658 1773
 static int
1659 1774
 redata_hash_gen(redata_t *redata, char *filename, char *buf, long buflen, char *resbuf129bytes)
1660 1775
 {
... ...
@@ -1933,7 +2048,7 @@ redata_linecol2pos(redata_t *redata, int line, int colrequest, long *pos, int *c
1933 2048
         int i,n;
1934 2049
         char *ptr;
1935 2050
         int len;
1936
-        int done;
2051
+        int done;                       
1937 2052
         if(redata==NULL || line<0 || colrequest<0)
1938 2053
                 return(-1);
1939 2054
         /* find line */
... ...
@@ -1958,21 +2073,18 @@ redata_linecol2pos(redata_t *redata, int line, int colrequest, long *pos, int *c
1958 2073
                 return(-1); /* line not found */
1959 2074
         realstart=chunkpos+i;
1960 2075
         /* find col */
1961
-        for(n=0,curpos=realstart;n<colrequest;) {
2076
+        for(n=-1,curpos=realstart;n<colrequest;) {
1962 2077
                 if(redata_line_rawinfo(redata,curpos,&startpos,&ptr,&len,NULL)==-1 || len==0)
1963 2078
                         return(-1); /* couldn't get current line data */
1964 2079
                 done=0;
1965
-                for(i=0;colrequest>0 && i<len && n<=colrequest;i++) {
1966
-                        if(redata_generic_utf8isstartbyte(ptr[i])) {
1967
-                                if(n==colrequest) {
1968
-                                        done=1;
1969
-                                        break;
1970
-                                }
1971
-                                n++;
1972
-                        }
2080
+                for(i=0;i<len && n<colrequest;i++) {
1973 2081
                         if(ptr[i]=='\n') {
1974 2082
                                 done=1;
1975 2083
                                 break;
2084
+                        } else if(UTF8_IS_ASCII_OR_START(ptr[i])) {                    
2085
+                                n++;
2086
+                                if(n==colrequest)
2087
+                                        break;
1976 2088
                         }
1977 2089
                 }
1978 2090
                 curpos=startpos+i;
Browse code

fix plugins not being called on undo

Dario Rodriguez authored on 01/12/2020 21:24:22
Showing 1 changed files
... ...
@@ -1039,8 +1039,12 @@ redata_op_add(redata_t *redata, long insertpos, char *buf, long buflen, undostac
1039 1039
         }
1040 1040
         /* add to plugins (unsaved,...) */
1041 1041
         for(i=0;i<redata->sizeplugins;i++) {
1042
-                if(redata->plugins[i].add!=NULL)
1043
-                        redata->plugins[i].add(redata,redata->plugins+i,redata->undostack.undo+redata->undostack.usedundo-1);
1042
+                if(redata->plugins[i].add_or_unadd!=NULL) {
1043
+                        redata->plugins[i].add_or_unadd(redata,redata->plugins+i
1044
+                          ,(undo!=NULL)?redata->undostack.undo+redata->undostack.usedundo-1
1045
+                                       :redata->redostack.undo+redata->redostack.usedundo-1
1046
+                          ,(undo!=NULL)?0:1);
1047
+                }
1044 1048
         }
1045 1049
         /* compact if needed */
1046 1050
         if(redata_getsize(redata)>(redata->chunkdatasize) && redata_getavailable(redata)>(redata_getsize(redata)/2))
... ...
@@ -1131,8 +1135,12 @@ redata_op_del(redata_t *redata, long delpos, long size, undostack_t *fromhere)
1131 1135
         }
1132 1136
         /* add to plugins (unsaved,...) */
1133 1137
         for(i=0;i<redata->sizeplugins;i++) {
1134
-                if(redata->plugins[i].add!=NULL)
1135
-                        redata->plugins[i].add(redata,redata->plugins+i,redata->undostack.undo+redata->undostack.usedundo-1);
1138
+                if(redata->plugins[i].add_or_unadd!=NULL) {
1139
+                        redata->plugins[i].add_or_unadd(redata,redata->plugins+i
1140
+                          ,(undo!=NULL)?redata->undostack.undo+redata->undostack.usedundo-1
1141
+                                       :redata->redostack.undo+redata->redostack.usedundo-1
1142
+                          ,(undo!=NULL)?0:1);
1143
+                }
1136 1144
         }
1137 1145
         /* compact if needed */
1138 1146
         if(redata_getsize(redata)>(redata->chunkdatasize) && redata_getavailable(redata)>(redata_getsize(redata)/2))
... ...
@@ -1272,8 +1280,12 @@ redata_op_move(redata_t *redata, long posorig, long size, long posdest, undostac
1272 1280
         }
1273 1281
         /* add to plugins (unsaved,...) */
1274 1282
         for(i=0;i<redata->sizeplugins;i++) {
1275
-                if(redata->plugins[i].add!=NULL)
1276
-                        redata->plugins[i].add(redata,redata->plugins+i,redata->undostack.undo+redata->undostack.usedundo-1);
1283
+                if(redata->plugins[i].add_or_unadd!=NULL) {
1284
+                        redata->plugins[i].add_or_unadd(redata,redata->plugins+i
1285
+                          ,(undo!=NULL)?redata->undostack.undo+redata->undostack.usedundo-1
1286
+                                       :redata->redostack.undo+redata->redostack.usedundo-1
1287
+                          ,(undo!=NULL)?0:1);
1288
+                }
1277 1289
         }
1278 1290
         /* compact if needed */
1279 1291
         if(redata_getsize(redata)>(redata->chunkdatasize) && redata_getavailable(redata)>(redata_getsize(redata)/2))
Browse code

Added 'Exit without saving?' confirmation dialog

Dario Rodriguez authored on 30/11/2020 21:40:46
Showing 1 changed files
... ...
@@ -675,6 +675,8 @@ redata_load(redata_t *redata, char *filename, char **errordesc)
675 675
         }
676 676
         redata_loadquestions_wipe(redata);
677 677
 #warning TODO: IMPLEMENT POSTLOADQUESTIONS (call now loadquestion_postload).
678
+        /* mark as not modified */
679
+        redata->needs_saving=0;
678 680
         /* all done */
679 681
         return(0);
680 682
 }
... ...
@@ -724,9 +726,20 @@ redata_save(redata_t *redata, char *filename, char **errordesc)
724 726
         }
725 727
         strncpy(redata->filename,filename,sizeof(redata->filename));
726 728
         redata->filename[sizeof(redata->filename)-1]='\0';
729
+        /* mark as not modified */
730
+        redata->needs_saving=0;
727 731
         return(0);
728 732
 }
729 733
 
734
+int
735
+redata_needs_saving(redata_t *redata)
736
+{
737
+        if(redata==NULL)
738
+                return(0);
739
+        return( (redata->needs_saving)?1:0 );
740
+}
741
+
742
+
730 743
 int
731 744
 redata_undobuf_reserve(redata_t *redata, undostack_t *stack, int minavail)
732 745
 {
... ...
@@ -1032,6 +1045,8 @@ redata_op_add(redata_t *redata, long insertpos, char *buf, long buflen, undostac
1032 1045
         /* compact if needed */
1033 1046
         if(redata_getsize(redata)>(redata->chunkdatasize) && redata_getavailable(redata)>(redata_getsize(redata)/2))
1034 1047
                 redata_compact(redata);
1048
+        /* mark as modified */
1049
+        redata->needs_saving=1;
1035 1050
         return(0);
1036 1051
 }
1037 1052
 
... ...
@@ -1122,6 +1137,8 @@ redata_op_del(redata_t *redata, long delpos, long size, undostack_t *fromhere)
1122 1137
         /* compact if needed */
1123 1138
         if(redata_getsize(redata)>(redata->chunkdatasize) && redata_getavailable(redata)>(redata_getsize(redata)/2))
1124 1139
                 redata_compact(redata);
1140
+        /* mark as modified */
1141
+        redata->needs_saving=1;
1125 1142
         return(0);
1126 1143
 }
1127 1144
 
... ...
@@ -1261,6 +1278,8 @@ redata_op_move(redata_t *redata, long posorig, long size, long posdest, undostac
1261 1278
         /* compact if needed */
1262 1279
         if(redata_getsize(redata)>(redata->chunkdatasize) && redata_getavailable(redata)>(redata_getsize(redata)/2))
1263 1280
                 redata_compact(redata);
1281
+        /* mark as modified */
1282
+        redata->needs_saving=1;
1264 1283
         return(0);
1265 1284
 }
1266 1285
 
... ...
@@ -1289,7 +1308,8 @@ redata_op_undo(redata_t *redata, long *newcursorpos)
1289 1308
                 return(-1); /* unknown operation */
1290 1309
         if(newcursorpos!=NULL)
1291 1310
                 *newcursorpos=newpos;
1292
-#warning TODO: Is it neccessary to do an unadd to the plugins?
1311
+        /* mark as modified */
1312
+        redata->needs_saving=1;
1293 1313
         return(0);
1294 1314
 }
1295 1315
 
... ...
@@ -1316,6 +1336,8 @@ redata_op_redo(redata_t *redata, long *newcursorpos)
1316 1336
 #warning TODO: Is it neccessary to do an unadd to the plugins?
1317 1337
         if(newcursorpos!=NULL)
1318 1338
                 *newcursorpos=newpos;
1339
+        /* mark as modified */
1340
+        redata->needs_saving=1;
1319 1341
         return(0);
1320 1342
 }
1321 1343
 
Browse code

re_data: search/compare functions: search forward, search backwards, memcmp

Dario Rodriguez authored on 22/10/2020 21:34:45
Showing 1 changed files
... ...
@@ -1466,6 +1466,94 @@ redata_generic_genname(char *filename,char *prefix, char *postfix, char *buf, in
1466 1466
         return(name);
1467 1467
 }
1468 1468
 
1469
+long
1470
+redata_searchforward(redata_t *redata, long posini, char *str, int len)
1471
+{
1472
+        int numchunk;
1473
+        int offset;
1474
+        int avail;
1475
+        long chunkstartpos;
1476
+        rechunk_t *chunk;
1477
+        char *ptr;
1478
+        if(redata==NULL || posini<0 || (posini+len)>redata_getsize(redata) || len<0 || (str==NULL && len>0))
1479
+                return(-1); /* sanity check failed */
1480
+        if(len==0)
1481
+                return(posini); /* nothing to do, empty string is always equal */
1482
+        if(redata_getposptr(redata,posini,&numchunk,&offset)!=0)
1483
+                return(-1); /* couldn't get pos */
1484
+        chunkstartpos=posini-offset;
1485
+        for(;numchunk<redata->sizechunks
1486
+          ;chunkstartpos+=chunk->useddata,numchunk++,offset=0) {
1487
+                chunk=redata->chunks[numchunk];
1488
+                avail=chunk->useddata-offset;
1489
+                while(avail>0 && (ptr=memchr(chunk->data+offset,str[0],avail))!=NULL) {
1490
+                        offset=ptr-((char *)(chunk->data));
1491
+                        if(redata_memcmp(redata,chunkstartpos+offset,str,len)==0)
1492
+                                return(chunkstartpos+offset);
1493
+                        offset++;
1494
+                        avail=chunk->useddata-offset;
1495
+                }
1496
+        }
1497
+        return(-1); /* not found */
1498
+}
1499
+
1500
+long
1501
+redata_searchbackwards(redata_t *redata, long posini, char *str, int len)
1502
+{
1503
+        int numchunk;
1504
+        int offset;
1505
+        long chunkstartpos;
1506
+        rechunk_t *chunk;
1507
+        char *ptr;
1508
+        if(redata==NULL || posini<0 || (posini+len)>redata_getsize(redata) || len<0 || (str==NULL && len>0))
1509
+                return(-1); /* sanity check failed */
1510
+        if(len==0)
1511
+                return(posini); /* nothing to do, empty string is always equal */
1512
+        if(redata_getposptr(redata,posini,&numchunk,&offset)!=0)
1513
+                return(-1); /* couldn't get pos */
1514
+        chunkstartpos=posini-offset;
1515
+        for(offset++;numchunk>=0
1516
+          ;numchunk--
1517
+          ,offset=(numchunk>=0)?redata->chunks[numchunk]->useddata:0
1518
+          ,chunkstartpos-=(numchunk>=0)?redata->chunks[numchunk]->useddata:0) {
1519
+                chunk=redata->chunks[numchunk];
1520
+                while(offset>0 && (ptr=mymemrchr(chunk->data,str[0],offset))!=NULL) {
1521
+                        offset=ptr-((char *)(chunk->data));
1522
+                        if(redata_memcmp(redata,chunkstartpos+offset,str,len)==0)
1523
+                                return(chunkstartpos+offset);
1524
+                }
1525
+        }
1526
+        return(-1); /* not found */
1527
+}
1528
+
1529
+int
1530
+redata_memcmp(redata_t *redata, long pos, char *str, int len)
1531
+{
1532
+        int numchunk;
1533
+        int offset;
1534
+        int avail;
1535
+        int ncompared;
1536
+        rechunk_t *chunk;
1537
+        int res;
1538
+        if(redata==NULL || pos<0 || (pos+len)>redata_getsize(redata) || len<0 || (str==NULL && len>0))
1539
+                return(-1); /* sanity check failed, return "this is smaller" */
1540
+        if(len==0)
1541
+                return(0); /* nothing to do, empty string is always equal */
1542
+        if(redata_getposptr(redata,pos,&numchunk,&offset)!=0)
1543
+                return(-1); /* couldn't get pos */
1544
+        for(ncompared=0;numchunk<redata->sizechunks;numchunk++,offset=0) {
1545
+                chunk=redata->chunks[numchunk];
1546
+                avail=chunk->useddata-offset;
1547
+                avail=(avail>(len-ncompared))?(len-ncompared):avail;
1548
+                if((res=memcmp(chunk->data+offset,str+ncompared,avail))!=0 || (ncompared+avail)==len)
1549
+                        return(res); /* comparison finished */
1550
+                ncompared+=avail;
1551
+        }
1552
+        return(-1); /* not enough data in chunks */
1553
+
1554
+}
1555
+
1556
+
1469 1557
 int
1470 1558
 redata_generic_utf8len(char *ptr, int size)
1471 1559
 {
Browse code

Add a simple C-language highlighter as a plugin (and lots of temp. debug code; to be cleaned later)

Dario Rodriguez authored on 17/10/2020 22:30:36
Showing 1 changed files
... ...
@@ -23,11 +23,13 @@
23 23
 #include "re_data.h"
24 24
 #include "sha3/sha3.h"
25 25
 
26
+/* DEFAULT CHUNKSIZE: 1024 */
27
+//#define CHUNKSIZE 65536
26 28
 //#define CHUNKSIZE 32768
27 29
 //#define CHUNKSIZE 4096
28
-#define CHUNKSIZE 1024
30
+//#define CHUNKSIZE 1024
29 31
 //#define CHUNKSIZE 160
30
-//#define CHUNKSIZE 16
32
+#define CHUNKSIZE 16
31 33
 #define UNDOBLOCK 1024
32 34
 #define ADDNBLOCK 1024
33 35
 #define UNDOGROWSIZE (256*1024)
Browse code

Disable with a define the generation of a file hash in each undo element (it is too slow with large files)

Dario Rodriguez authored on 09/10/2020 21:43:36
Showing 1 changed files
... ...
@@ -24,8 +24,10 @@
24 24
 #include "sha3/sha3.h"
25 25
 
26 26
 //#define CHUNKSIZE 32768
27
+//#define CHUNKSIZE 4096
28
+#define CHUNKSIZE 1024
27 29
 //#define CHUNKSIZE 160
28
-#define CHUNKSIZE 16
30
+//#define CHUNKSIZE 16
29 31
 #define UNDOBLOCK 1024
30 32
 #define ADDNBLOCK 1024
31 33
 #define UNDOGROWSIZE (256*1024)
... ...
@@ -846,8 +848,10 @@ redata_undo_movelast(redata_t *redata, undostack_t *from, undostack_t *to)
846 848
                 return(-1); /* insuf. mem. */
847 849
         undoto->posorig=undofrom->posorig;
848 850
         undoto->posdest=undofrom->posdest;
851
+#ifdef REDATA_HASHUNDO
849 852
         memcpy(undoto->prehash,undofrom->prehash,sizeof(undoto->prehash));
850 853
         memcpy(undoto->posthash,undofrom->posthash,sizeof(undoto->posthash));
854
+#endif
851 855
         redata_undo_removelast(redata, from);
852 856
         return(0);
853 857
 }
... ...
@@ -945,7 +949,9 @@ redata_op_add(redata_t *redata, long insertpos, char *buf, long buflen, undostac
945 949
         if(fromhere!=&(redata->undostack)) {
946 950
                 if((undo=redata_undo_newfrombuf(redata,&(redata->undostack),'A',buf,buflen))==NULL)
947 951
                         return(-1); /* couldn't create undo struct */
952
+#ifdef REDATA_HASHUNDO
948 953
                 redata_hash(redata,undo->prehash);
954
+#endif
949 955
         } else {
950 956
                 undo=NULL;
951 957
         }
... ...
@@ -1005,7 +1011,9 @@ redata_op_add(redata_t *redata, long insertpos, char *buf, long buflen, undostac
1005 1011
         if(undo!=NULL) {
1006 1012
                 /* new or from redo stack */
1007 1013
                 undo->posorig=undo->posdest=insertpos;
1014
+#ifdef REDATA_HASHUNDO
1008 1015
                 redata_hash(redata,undo->posthash);
1016
+#endif
1009 1017
                 if(fromhere==&(redata->redostack))
1010 1018
                         redata_undo_removelast(redata,&(redata->redostack));
1011 1019
                 else
... ...
@@ -1067,7 +1075,9 @@ redata_op_del(redata_t *redata, long delpos, long size, undostack_t *fromhere)
1067 1075
         if(fromhere!=&(redata->undostack)) {
1068 1076
                 if((undo=redata_undo_newfromchunks(redata,&(redata->undostack),'D',delpos,size))==NULL)
1069 1077
                         return(-1); /* couldn't create undo struct */
1078
+#ifdef REDATA_HASHUNDO
1070 1079
                 redata_hash(redata,undo->prehash);
1080
+#endif
1071 1081
         } else {
1072 1082
                 undo=NULL;
1073 1083
         }
... ...
@@ -1091,7 +1101,9 @@ redata_op_del(redata_t *redata, long delpos, long size, undostack_t *fromhere)
1091 1101
         if(undo!=NULL) {
1092 1102
                 /* new or from redo stack */
1093 1103
                 undo->posorig=undo->posdest=delpos;
1104
+#ifdef REDATA_HASHUNDO
1094 1105
                 redata_hash(redata,undo->posthash);
1106
+#endif
1095 1107
                 if(fromhere==&(redata->redostack))
1096 1108
                         redata_undo_removelast(redata,&(redata->redostack));
1097 1109
                 else
... ...
@@ -1135,7 +1147,9 @@ redata_op_move(redata_t *redata, long posorig, long size, long posdest, undostac
1135 1147
                         return(-1); /* couldn't create undo struct */
1136 1148
                 /* inactivate the undo so we are able to use return(-1) without removing it */
1137 1149
                 redata_undo_inactivatelast(redata,&(redata->undostack));
1150
+#ifdef REDATA_HASHUNDO
1138 1151
                 redata_hash(redata,undo->prehash);
1152
+#endif
1139 1153
         } else {
1140 1154
                 undo=NULL;
1141 1155
         }
... ...
@@ -1226,7 +1240,9 @@ redata_op_move(redata_t *redata, long posorig, long size, long posdest, undostac
1226 1240
                 /* new or from redo stack */
1227 1241
                 undo->posorig=posorig;
1228 1242
                 undo->posdest=posdest;
1243
+#ifdef REDATA_HASHUNDO
1229 1244
                 redata_hash(redata,undo->posthash);
1245
+#endif
1230 1246
                 if(fromhere==&(redata->redostack))
1231 1247
                         redata_undo_removelast(redata,&(redata->redostack));
1232 1248
                 else
Browse code

fix redata_op_add() so that it can insert data when redata struct has no chunks yet (bug was: couldn't insert data on an empty file).

Dario Rodriguez authored on 08/10/2020 20:38:53
Showing 1 changed files
... ...
@@ -936,6 +936,10 @@ redata_op_add(redata_t *redata, long insertpos, char *buf, long buflen, undostac
936 936
           || insertpos>redata_getused(redata)
937 937
           || (fromhere!=NULL && (fromhere!=&(redata->undostack) && fromhere!=&(redata->redostack))))
938 938
                 return(-1); /* sanity check failed */
939
+        if(insertpos==0 && redata->sizechunks==0) {
940
+                /* add the first chunk */
941
+                redata_preallocate(redata,buflen);
942
+        }
939 943
         if(redata_getposptr(redata,insertpos,&chunkno,&offset)==-1)
940 944
                 return(-1); /* invalid pos */
941 945
         if(fromhere!=&(redata->undostack)) {
Browse code

Support the unsaved data recovery plugin from redata. Rework the question interface.

Dario Rodriguez authored on 05/10/2020 21:42:19
Showing 1 changed files
... ...
@@ -94,6 +94,7 @@ redata_init(int (*pluginregisterfn)(redata_t *redata, redata_plugin_t *slot), ..
94 94
         redata->undostack.undo=NULL;
95 95
         redata->undostack.buf=NULL;
96 96
         /* plugins */
97
+        va_start(args,pluginregisterfn);
97 98
         for(nargs=0,fn=pluginregisterfn;fn!=NULL;fn=va_arg(args,int (*)(redata_t *redata,redata_plugin_t *slot))) {
98 99
                 res=fn(redata,redata->plugins+nargs);
99 100
                 redata->plugins[nargs].active=(res==0)?1:0;
... ...
@@ -146,6 +147,20 @@ redata_free(redata_t *redata)
146 147
         return;
147 148
 }
148 149
 
150
+void
151
+redata_idleproc(redata_t *redata, char *filename)
152
+{
153
+        int i;
154
+        if(redata==NULL)
155
+                return;
156
+        for(i=0;i<redata->sizeplugins;i++) {
157
+                if(redata->plugins[i].commit!=NULL)
158
+                        redata->plugins[i].commit(redata,redata->plugins+i,filename);
159
+        }
160
+        return;
161
+}
162
+
163
+
149 164
 int
150 165
 redata_config_chunkdatasize(redata_t *redata, int chunkdatasize)
151 166
 {
... ...
@@ -524,27 +539,94 @@ redata_fix_nl(redata_t *redata, int chunkno)
524 539
 }
525 540
 
526 541
 int
527
-redata_load(redata_t *redata, char *filename, int (*callback_question)(/*char *title, char *body, int nopts, char *opts[],void *userptr*/), void *userptr)
542
+redata_loadquestions_setup(redata_t *redata, char *filename)
543
+{
544
+        int i;
545
+        if(redata==NULL || filename==NULL)
546
+                return(-1); /* sanity check failed */
547
+        redata_loadquestions_wipe(redata);
548
+        /* unsaved and other plugins: loadquestion (pre-to-load) */
549
+        for(i=0;i<redata->sizeplugins;i++) {
550
+                if(!redata->plugins[i].active)
551
+                        continue;
552
+                if(redata->plugins[i].loadquestion!=NULL)
553
+                        redata->plugins[i].loadquestion(redata,redata->plugins+i,filename);
554
+        }
555
+        return(0);
556
+
557
+}
558
+
559
+question_t *
560
+redata_loadquestions_getnext(redata_t *redata)
561
+{
562
+        int i;
563
+        if(redata==NULL)
564
+                return(NULL); /* sanity check failed */
565
+        for(i=0;i<redata->sizeplugins;i++) {
566
+                if(!redata->plugins[i].active || redata->plugins[i].question.active==0)
567
+                        continue;
568
+                if(redata->plugins[i].question.selectedoption==-1)
569
+                        return(&(redata->plugins[i].question));
570
+        }
571
+        return(NULL); /* no more questions */
572
+}
573
+
574
+int
575
+redata_loadquestions_reply(redata_t *redata, question_t *question, int selectedoption)
576
+{
577
+        if(redata==NULL || question==NULL || selectedoption<-1 || selectedoption>=question->nopts)
578
+                return(-1);
579
+        question->selectedoption=(selectedoption==-1)?question->defaultoption:selectedoption;
580
+        return(0);
581
+}
582
+
583
+int
584
+redata_loadquestions_wipe(redata_t *redata)
528 585
 {
586
+        int i;
587
+        if(redata==NULL)
588
+                return(-1);
589
+        for(i=0;i<redata->sizeplugins;i++) {
590
+                if(!redata->plugins[i].active)
591
+                        continue;
592
+                memset(redata->plugins[i].questionfilename,0,sizeof(redata->plugins[i].questionfilename));
593
+                memset(&(redata->plugins[i].question),0,sizeof(redata->plugins[i].question));
594
+                redata->plugins[i].question.active=0;
595
+                redata->plugins[i].question.selectedoption=-1;
596
+        }
597
+        return(0);
598
+}
599
+
600
+int
601
+redata_load(redata_t *redata, char *filename, char **errordesc)
602
+{
603
+#warning TODO: what to do when there plugins with questions AFTER loading instead of before loading...
529 604
         int fd,nread,totalread;
530 605
         int chunkno, avail;
531 606
         struct stat statbuf;
532 607
         rechunk_t *chunk;
533 608
         int i;
534 609
         int reply;
535
-        if(redata==NULL || filename==NULL)
610
+        if(redata==NULL || filename==NULL) {
611
+                if(errordesc!=NULL)
612
+                        *errordesc="Internal error";
536 613
                 return(-1); /* sanity check failed */
614
+        }
537 615
         redata_wipe(redata);
538 616
         strncpy(redata->filename,filename,sizeof(redata->filename));
539 617
         redata->filename[sizeof(redata->filename)-1]='\0';
540 618
         if((fd=open(filename,O_RDONLY))==-1 || fstat(fd,&statbuf)!=0 || !S_ISREG(statbuf.st_mode)) {
541 619
                 if(fd!=-1)
542 620
                         close(fd),fd=-1;
543
-                return(-1); /* file not found, couldn't query size or not regular file */
621
+                if(errordesc!=NULL)
622
+                        *errordesc="File not found, couldn't query size or not a regular file";
623
+                return(-1); /* file not found, couldn't query size or not a regular file */
544 624
         }
545 625
         /* preallocate 10% more than needed */
546 626
         if(redata_preallocate(redata,statbuf.st_size+(statbuf.st_size/10)+1 )) {
547 627
                 close(fd),fd=-1;
628
+                if(errordesc!=NULL)
629
+                        *errordesc="Insufficient memory";
548 630
                 return(-1); /* insuf. mem. */
549 631
         }
550 632
         for(totalread=0,chunkno=0,nread=0;totalread<statbuf.st_size;totalread+=nread,nread=0) {
... ...
@@ -568,6 +650,8 @@ redata_load(redata_t *redata, char *filename, int (*callback_question)(/*char *t
568 650
                 }
569 651
                 if((nread=read(fd,chunk->data+chunk->useddata,avail))<=0) {
570 652
                         close(fd),fd=-1;
653
+                        if(errordesc!=NULL)
654
+                                *errordesc="Short read loading file";
571 655
                         return(-1); /* short read */
572 656
                 }
573 657
                 chunk->useddata+=nread;
... ...
@@ -578,49 +662,56 @@ redata_load(redata_t *redata, char *filename, int (*callback_question)(/*char *t
578 662
                 redata_fix_nl(redata,chunkno);
579 663
         for(chunkno=0;chunkno<redata->sizechunks;chunkno++)
580 664
                 redata_whatin_refresh(redata,chunkno);
581
-        /* unsaved and other plugins */
665
+        /* unsaved and other plugins: postload */
582 666
         for(i=0;i<redata->sizeplugins;i++) {
583 667
                 if(!redata->plugins[i].active)
584 668
                         continue;
585
-                reply=-1;
586
-                if(redata->plugins[i].loadquestion!=NULL && callback_question!=NULL) {
587
-                        char *title, *body;
588
-                        int nopts;
589
-                        char **opts;
590
-                        if(redata->plugins[i].loadquestion(redata,redata->plugins+i,filename,&title,&body,&nopts,&opts)!=-1)
591
-                                reply=callback_question(title,body,nopts,opts,userptr);
592
-                }
593 669
                 if(redata->plugins[i].postload!=NULL)
594
-                        redata->plugins[i].postload(redata,redata->plugins+i,filename,reply);
670
+                        redata->plugins[i].postload(redata,redata->plugins+i,filename);
595 671
         }
672
+        redata_loadquestions_wipe(redata);
673
+#warning TODO: IMPLEMENT POSTLOADQUESTIONS (call now loadquestion_postload).
596 674
         /* all done */
597 675
         return(0);
598 676
 }
599 677
 
600 678
 int
601
-redata_save(redata_t *redata, char *filename)
679
+redata_save(redata_t *redata, char *filename, char **errordesc)
602 680
 {
603 681
         int fd;
604 682
         int i,n;
605 683
         char tmpfile[PATH_MAX+1];
606
-        if(redata==NULL || filename==NULL)
684
+        if(redata==NULL || filename==NULL) {
685
+                if(errordesc!=NULL)
686
+                        *errordesc="Internal error";
607 687
                 return(-1); /* sanity check failed */
608
-        if((securesave_genname(redata->filename,tmpfile,sizeof(tmpfile)))==NULL)
688
+        }
689
+        if((securesave_genname(redata->filename,tmpfile,sizeof(tmpfile)))==NULL) {
690
+                if(errordesc!=NULL)
691
+                        *errordesc="Malformed filename";
609 692
                 return(-1); /* malformed filename */
610
-        if((fd=open(tmpfile,O_WRONLY|O_TRUNC|O_CREAT,0644))==-1)
693
+        }
694
+        if((fd=open(tmpfile,O_WRONLY|O_TRUNC|O_CREAT,0644))==-1) {
695
+                if(errordesc!=NULL)
696
+                        *errordesc="Couldn't open file for writing";
611 697
                 return(-1); /* couldn't open file for writing */
698
+        }
612 699
         for(i=0;i<redata->sizechunks;i++) {
613 700
                 if(redata->chunks[i]->useddata==0)
614 701
                         continue;
615 702
                 if((n=write(fd,redata->chunks[i]->data,redata->chunks[i]->useddata))==-1 || n!=redata->chunks[i]->useddata) {
616 703
                         close(fd),fd=-1;
617 704
                         unlink(tmpfile);
705
+                        if(errordesc!=NULL)
706
+                                *errordesc="Short write saving file";
618 707
                         return(-1); /* short write */
619 708
                 }
620 709
         }
621 710
         close(fd),fd=-1;
622 711
         if(rename(tmpfile,filename)!=0) {
623 712
                 unlink(tmpfile);
713
+                if(errordesc!=NULL)
714
+                        *errordesc="Couldn't overwrite old file";
624 715
                 return(-1); /* couldn't overwrite old file */
625 716
         }
626 717
         for(i=0;i<redata->sizeplugins;i++) {
Browse code

Have the UI use the undo facilities of re_data.c when Ctrl-Z is pressed

Dario Rodriguez authored on 26/09/2020 21:23:03
Showing 1 changed files
... ...
@@ -1152,46 +1152,58 @@ redata_op_move(redata_t *redata, long posorig, long size, long posdest, undostac
1152 1152
 }
1153 1153
 
1154 1154
 int
1155
-redata_op_undo(redata_t *redata)
1155
+redata_op_undo(redata_t *redata, long *newcursorpos)
1156 1156
 {
1157 1157
         undo_t *undo;
1158
+        long newpos=0;
1158 1159
         if(redata==NULL
1159 1160
           || redata->undostack.usedundo<1)
1160 1161
                 return(-1); /* sanity check failed */
1161 1162
         undo=redata->undostack.undo+redata->undostack.usedundo-1;
1162 1163
         if(undo->type=='A') { /* ADD */
1164
+                newpos=undo->posorig;
1163 1165
                 redata_op_del(redata,undo->posorig,undo->len,&(redata->undostack));
1164 1166
         } else if(undo->type=='D') { /* DEL */
1167
+                newpos=undo->posorig+undo->len;
1165 1168
                 redata_op_add(redata,undo->posorig,redata->undostack.buf+undo->off,undo->len,&(redata->undostack));
1166 1169
         } else if(undo->type=='M') { /* MOVE */
1170
+                newpos=undo->posorig+undo->len;
1167 1171
                 if(undo->posorig<undo->posdest)
1168 1172
                         redata_op_move(redata,undo->posdest-undo->len, undo->len, undo->posorig,&(redata->undostack));
1169 1173
                 else
1170 1174
                         redata_op_move(redata,undo->posdest, undo->len, undo->posorig+undo->len,&(redata->undostack));
1171 1175
         } else
1172 1176
                 return(-1); /* unknown operation */
1177
+        if(newcursorpos!=NULL)
1178
+                *newcursorpos=newpos;
1173 1179
 #warning TODO: Is it neccessary to do an unadd to the plugins?
1174
-        return(-1);
1180
+        return(0);
1175 1181
 }
1176 1182
 
1177 1183
 int
1178
-redata_op_redo(redata_t *redata)
1184
+redata_op_redo(redata_t *redata, long *newcursorpos)
1179 1185
 {
1180 1186
         undo_t *undo;
1187
+        long newpos;
1181 1188
         if(redata==NULL
1182 1189
           || redata->redostack.usedundo<1)
1183 1190
                 return(-1); /* sanity check failed */
1184 1191
         undo=redata->redostack.undo+redata->redostack.usedundo-1;
1185 1192
         if(undo->type=='A') { /* ADD */
1193
+                newpos=undo->posorig+undo->len;
1186 1194
                 redata_op_add(redata,undo->posorig,redata->redostack.buf+undo->off,undo->len,&(redata->redostack));
1187 1195
         } else if(undo->type=='D') { /* DEL */
1196
+                newpos=undo->posorig;
1188 1197
                 redata_op_del(redata,undo->posorig,undo->len,&(redata->redostack));
1189 1198
         } else if(undo->type=='M') { /* MOVE */
1199
+                newpos=undo->posorig+undo->len;
1190 1200
                 redata_op_move(redata,undo->posorig, undo->len, undo->posdest,&(redata->redostack));
1191 1201
         } else
1192 1202
                 return(-1); /* unknown operation */
1193 1203
 #warning TODO: Is it neccessary to do an unadd to the plugins?
1194
-        return(-1);
1204
+        if(newcursorpos!=NULL)
1205
+                *newcursorpos=newpos;
1206
+        return(0);
1195 1207
 }
1196 1208
 
1197 1209
 int
... ...
@@ -1679,7 +1691,7 @@ redata_pos2linecol(redata_t *redata, long pos, int *resline, int *rescol)
1679 1691
 int
1680 1692
 redata_linecol2pos(redata_t *redata, int line, int colrequest, long *pos, int *coldone)
1681 1693
 {
1682
-        long chunkpos,realstart,newpos,curpos,startpos;
1694
+        long chunkpos,realstart,curpos,startpos;
1683 1695
         int startline;
1684 1696
         int nchunk;
1685 1697
         rechunk_t *chunk;
Browse code

Implement redata_linecol2pos() so that 'Go To Line' can do its thing

Dario Rodriguez authored on 25/09/2020 20:49:13
Showing 1 changed files
... ...
@@ -1679,10 +1679,64 @@ redata_pos2linecol(redata_t *redata, long pos, int *resline, int *rescol)
1679 1679
 int
1680 1680
 redata_linecol2pos(redata_t *redata, int line, int colrequest, long *pos, int *coldone)
1681 1681
 {
1682
-#warning TODO: XXX Implement this function
1683
-#warning TODO: XXX: Add a parameter so this is like reata_line_inccol (colrequest, coldone) --  maybe also linetrequest linedone? (zed doesn''t let you go to the last line doing a Ctrl+q+l to an arbitrarily large number...)
1684
-#warning TODO: XXX: The extra parameters are super-handy because the main user of this function is Control+Q+L "Go To Line" and we want to go to nearest pos
1685
-        return(-1);
1682
+        long chunkpos,realstart,newpos,curpos,startpos;
1683
+        int startline;
1684
+        int nchunk;
1685
+        rechunk_t *chunk;
1686
+        int i,n;
1687
+        char *ptr;
1688
+        int len;
1689
+        int done;
1690
+        if(redata==NULL || line<0 || colrequest<0)
1691
+                return(-1);
1692
+        /* find line */
1693
+        for(nchunk=0,chunkpos=0,startline=0
1694
+          ;nchunk<redata->sizechunks
1695
+          ;chunkpos+=(chunk!=NULL)?chunk->useddata:0
1696
+            ,startline+=(chunk!=NULL)?chunk->whatin.nlcount:0,nchunk++) {
1697
+                if((chunk=redata->chunks[nchunk])==NULL)
1698
+                        continue;
1699
+                if(!(chunk->whatin_fresh))
1700
+                        redata_whatin_refresh(redata,nchunk);
1701
+                if(line>=startline && line<=(startline+chunk->whatin.nlcount))
1702
+                        break;
1703
+        }
1704
+        if(nchunk>=redata->sizechunks)
1705
+                return(-1); /* line not found */
1706
+        for(i=0;line!=startline && i<chunk->useddata;i++) {
1707
+                if(chunk->data[i]=='\n')
1708
+                        startline++;
1709
+        }
1710
+        if(i>chunk->useddata)
1711
+                return(-1); /* line not found */
1712
+        realstart=chunkpos+i;
1713
+        /* find col */
1714
+        for(n=0,curpos=realstart;n<colrequest;) {
1715
+                if(redata_line_rawinfo(redata,curpos,&startpos,&ptr,&len,NULL)==-1 || len==0)
1716
+                        return(-1); /* couldn't get current line data */
1717
+                done=0;
1718
+                for(i=0;colrequest>0 && i<len && n<=colrequest;i++) {
1719
+                        if(redata_generic_utf8isstartbyte(ptr[i])) {
1720
+                                if(n==colrequest) {
1721
+                                        done=1;
1722
+                                        break;
1723
+                                }
1724
+                                n++;
1725
+                        }
1726
+                        if(ptr[i]=='\n') {
1727
+                                done=1;
1728
+                                break;
1729
+                        }
1730
+                }
1731
+                curpos=startpos+i;
1732
+                if(done)
1733
+                        break;
1734
+        }
1735
+        if(coldone!=NULL)
1736
+                *coldone=n;
1737
+        if(pos!=NULL)
1738
+                *pos=curpos;
1739
+        return(0);
1686 1740
 }
1687 1741
 
1688 1742
 static char *
Browse code

Improve implementation so it can edit lines longer than a chunk

Dario Rodriguez authored on 24/09/2020 21:40:49
Showing 1 changed files
... ...
@@ -24,7 +24,8 @@
24 24
 #include "sha3/sha3.h"
25 25
 
26 26
 //#define CHUNKSIZE 32768
27
-#define CHUNKSIZE 160
27
+//#define CHUNKSIZE 160
28
+#define CHUNKSIZE 16
28 29
 #define UNDOBLOCK 1024
29 30
 #define ADDNBLOCK 1024
30 31
 #define UNDOGROWSIZE (256*1024)
... ...
@@ -35,6 +36,7 @@ static int redata_hash_gen(redata_t *redata, char *filename, char *buf, long buf
35 36
 static char *securesave_genname(char *filename, char *buf, int bufsize);
36 37
 static void *mymemrchr(const void *s, int c, size_t n);
37 38
 static void meminvert(void *start, void *end);
39
+static size_t memrchroffset(char *ptr, int c, size_t n);
38 40
 
39 41
 #if 0
40 42
 static void
... ...
@@ -45,15 +47,22 @@ redata_debug_chunkdump(redata_t *redata, char *title)
45 47
         title=(title==NULL)?"":title;
46 48
         fprintf(stderr,"%s:CHUNKDUMP (sizechunks:%i)\n",title,redata->sizechunks);
47 49
         for(m=0;m<redata->sizechunks;m++) {
48
-                fprintf(stderr,"%s:chunk[%i]:\"",title,m);
50
+                fprintf(stderr,"%s:chunk[%i] len:%-5i data:\"",title,m,redata->chunks[m]->useddata);
49 51
                 for(k=0;k<redata->chunks[m]->useddata;k++) {
50 52
                         c=redata->chunks[m]->data[k];
51
-                        c=(c>=' ' && c<='~')?c:'.';
52
-                        fprintf(stderr,"%c",c);
53
+                        if(c=='\n' || c=='\0')
54
+                                fprintf(stderr,"\\%c",(c=='\n')?'n':'0');
55
+                        else if(c<' ' || c>'~' || c=='\\')
56
+                                fprintf(stderr,"\\x%02X",((unsigned char *)redata->chunks[m]->data)[k]);
57
+                        else
58
+                                fprintf(stderr,"%c",c);
53 59
                 }
54 60
                 fprintf(stderr,"\"\n");
55 61
         }
56 62
 }
63
+#define CHUNKDEBUG(a) redata_debug_chunkdump a
64
+#else
65
+#define CHUNKDEBUG(a)
57 66
 #endif
58 67
 
59 68
 redata_t *
... ...
@@ -247,6 +256,7 @@ redata_chunk_deletechunk(redata_t *redata, int chunkno)
247 256
                 redata->available+=chunk->useddata;
248 257
                 chunk->useddata=0;
249 258
                 chunk->whatin_fresh=0;
259
+                redata_chunk_unfreshnext(redata, chunkno);
250 260
         }
251 261
         for(i=chunkno;(i+1)<redata->sizechunks;i++)
252 262
                 redata->chunks[i]=redata->chunks[i+1];
... ...
@@ -320,8 +330,9 @@ redata_chunk_movedata(redata_t *redata, int chunkfrom, long posfrom, int chunkto
320 330
                 memmove(from->data+posfrom,from->data+posfrom+size,from->useddata-posfrom-size);
321 331
                 from->useddata-=size;
322 332
                 to->useddata+=size;
323
-                from->whatin_fresh=0;
324
-                to->whatin_fresh=0;
333
+                redata_chunk_unfreshrange(redata,chunkfrom,chunkto);
334
+                redata_chunk_unfreshnext(redata,chunkfrom);
335
+                redata_chunk_unfreshnext(redata,chunkto);
325 336
         } else {
326 337
                 /* from==to */
327 338
                 rechunk_t *chunk=redata->chunks[chunkfrom];
... ...
@@ -334,6 +345,7 @@ redata_chunk_movedata(redata_t *redata, int chunkfrom, long posfrom, int chunkto
334 345
                         memcpy(chunk->data+posto-size,redata->tmpchunk->data,size);
335 346
                 }
336 347
                 chunk->whatin_fresh=0;
348
+                redata_chunk_unfreshnext(redata,chunkfrom);
337 349
         }
338 350
         return(0);
339 351
 }
... ...
@@ -351,8 +363,9 @@ redata_chunk_insertdata(redata_t *redata, int chunkto, long posto, char *buf, lo
351 363
         memmove(chunk->data+posto+buflen,chunk->data+posto,chunk->useddata-posto);
352 364
         memcpy(chunk->data+posto,buf,buflen);
353 365
         chunk->useddata+=buflen;
354
-        chunk->whatin_fresh=0;
355 366
         redata->available-=buflen;
367
+        chunk->whatin_fresh=0;
368
+        redata_chunk_unfreshnext(redata,chunkto);
356 369
         return(0);
357 370
 }
358 371
 
... ...
@@ -370,8 +383,9 @@ redata_chunk_deletedata(redata_t *redata, int chunkno, long pos, long n)
370 383
         chunk=redata->chunks[chunkno];
371 384
         memmove(chunk->data+pos,chunk->data+pos+n,chunk->useddata-pos-n);
372 385
         chunk->useddata-=n;
373
-        chunk->whatin_fresh=0;
374 386
         redata->available+=n;
387
+        chunk->whatin_fresh=0;
388
+        redata_chunk_unfreshnext(redata,chunkno);
375 389
         return(0);
376 390
 }
377 391
 
... ...
@@ -409,6 +423,38 @@ redata_chunk_fillfromnext(redata_t *redata, int chunkno, int n)
409 423
         return(redata_chunk_movedata(redata,chunkno+1,0,chunkno,redata->chunks[chunkno]->useddata,n));
410 424
 }
411 425
 
426
+int
427
+redata_chunk_unfreshnext(redata_t *redata, int chunkno)
428
+{
429
+        int next;
430
+        if(redata==NULL || chunkno<0 || chunkno>=redata->sizechunks)
431
+                return(-1); /* sanity check failed */
432
+        /* invalidate whatin for next chunks until one not empty */
433
+        for(next=chunkno+1;next<redata->sizechunks;next++) {
434
+                redata->chunks[next]->whatin_fresh=0;
435
+                if(redata->chunks[next]->useddata!=0)
436
+                        break;
437
+        }
438
+        return(0);
439
+}
440
+
441
+int
442
+redata_chunk_unfreshrange(redata_t *redata, int fromchunkno, int tochunkno)
443
+{
444
+        int chunkno;
445
+        if(redata==NULL || fromchunkno<0 || fromchunkno>=redata->sizechunks || tochunkno<0 || tochunkno>=redata->sizechunks)
446
+                return(-1); /* sanity check failed */
447
+        if(fromchunkno>tochunkno) {
448
+                chunkno=fromchunkno;
449
+                fromchunkno=tochunkno;
450
+                tochunkno=chunkno;
451
+        }
452
+        /* invalidate whatin in range */
453
+        for(chunkno=fromchunkno;chunkno<=tochunkno;chunkno++)
454
+                redata->chunks[chunkno]->whatin_fresh=0;
455
+        return(0);
456
+}
457
+
412 458
 
413 459
 int
414 460
 redata_whatin_refresh(redata_t *redata, int chunkno)
... ...
@@ -423,10 +469,16 @@ redata_whatin_refresh(redata_t *redata, int chunkno)
423 469
                 return(0);
424 470
         memset(&(chunk->whatin),0,sizeof(whatin_t));
425 471
         nlcount=0;
426
-        for(i=0,lim=chunk->useddata;i<lim;i++) {
472
+        for(i=0,lim=chunk->useddata;i<lim;i++)
427 473
                 nlcount+=(chunk->data[i]=='\n')?1:0;
428
-        }
429 474
         chunk->whatin.nlcount=nlcount;
475
+        if(chunkno>0) {
476
+                int prev;
477
+                for(prev=chunkno-1;prev>0 && redata->chunks[prev]->useddata==0;prev--)
478
+                        ;
479
+                if(redata->chunks[prev]->useddata>0 && redata->chunks[prev]->data[redata->chunks[prev]->useddata-1]!='\n')
480
+                        chunk->whatin.iscontinuation=1;
481
+        }
430 482
         chunk->whatin_fresh=1;
431 483
         return(0);
432 484
 }
... ...
@@ -435,14 +487,14 @@ redata_whatin_refresh(redata_t *redata, int chunkno)
435 487
 int
436 488
 redata_fix_nl(redata_t *redata, int chunkno)
437 489
 {
490
+        rechunk_t *chunk,*nextchunk;
491
+        int linesize, nextlinesize, avail, nextavail;
492
+        unsigned char *ptr,*nextptr;
438 493
         /* make sure a line of len<chunksize is entirely inside one chunk (to simplify the syntax highlighting code) */
439 494
         if(redata==NULL || chunkno<0 || chunkno>=redata->sizechunks || redata->chunks[chunkno]==NULL)
440 495
                 return(-1); /* sanity check failed */
441 496
         if(chunkno==(redata->sizechunks-1) || redata->chunks[chunkno]->useddata==0 || redata->chunks[chunkno]->data[redata->chunks[chunkno]->useddata-1]=='\n')
442 497
                 return(0); /* Nothing to do (last chunk, chunk empty or already fixed) */
443
-        rechunk_t *chunk,*nextchunk;
444
-        int linesize, nextlinesize, avail, nextavail;
445
-        unsigned char *ptr,*nextptr;
446 498
         chunk=redata->chunks[chunkno];
447 499
         nextchunk=redata->chunks[chunkno+1];
448 500
         ptr=mymemrchr(chunk->data,'\n',chunk->useddata);
... ...
@@ -763,6 +815,20 @@ redata_undo_reactivatelast(redata_t *redata, undostack_t *stack)
763 815
         return(0);
764 816
 }
765 817
 
818
+int
819
+redata_undo_groupinit(redata_t *redata, undostack_t *stack)
820
+{
821
+        /* stores the current position in (undostack).groupinit */
822
+#warning TODO
823
+        return(-1);
824
+}
825
+
826
+int redata_undo_groupcommit(redata_t *redata, undostack_t *stack)
827
+{
828
+        /* marks as hint_groupedwithnext from stored groupinit position in undostack to last-1 position (if groupinit pos is the last pos, do nothing)*/
829
+#warning TODO
830
+        return(-1);
831
+}
766 832
 
767 833
 int
768 834
 redata_op_add(redata_t *redata, long insertpos, char *buf, long buflen, undostack_t *fromhere)
... ...
@@ -1333,6 +1399,14 @@ redata_generic_utf8charlen(char *ptr, int maxsize)
1333 1399
         return(i);
1334 1400
 }
1335 1401
 
1402
+inline int
1403
+redata_generic_utf8isstartbyte(int candidate)
1404
+{
1405
+        if((candidate&0xc0)!=0x80)
1406
+                return(1);
1407
+        return(0);
1408
+}
1409
+
1336 1410
 
1337 1411
 static int
1338 1412
 redata_hash_gen(redata_t *redata, char *filename, char *buf, long buflen, char *resbuf129bytes)
... ...
@@ -1389,94 +1463,225 @@ redata_hash_gen(redata_t *redata, char *filename, char *buf, long buflen, char *
1389 1463
         return(0);
1390 1464
 }
1391 1465
 
1392
-/*#define DEBUG_LINE_INFO*/
1393
-
1394
-#ifdef DEBUG_LINE_INFO
1395
-#define LINEINFODEBUG(a) fprintf a
1396
-#else
1397
-#define LINEINFODEBUG(a)
1398
-#endif
1399
-
1400 1466
 int
1401
-redata_line_info(redata_t *redata, long pos, long *startpos, char **startptr, int *len)
1467
+redata_line_rawinfo(redata_t *redata, long pos, long *startpos, char **startptr, int *len, int *is_continuation)
1402 1468
 {
1403
-        int chunkno;
1404
-        long start;
1405
-        unsigned char *ptr,*end;
1469
+        long chunkpos,newpos,endpos;
1470
+        int nchunk;
1406 1471
         rechunk_t *chunk;
1407
-        if(redata==NULL || pos<0)
1472
+        if(redata==NULL || pos<0 || pos>=redata_getused(redata))
1408 1473
                 return(-1);
1409
-        /* search chunk of pos */
1410
-        for(chunkno=0,start=0;chunkno<redata->sizechunks;start+=(redata->chunks[chunkno]==NULL)?0:redata->chunks[chunkno]->useddata,chunkno++) {
1411
-        LINEINFODEBUG((stderr,"redata_line_info: searchchunk: pos:%li chunkno:%i start:%li\n",pos,chunkno,start));
1412
-                if(redata->chunks[chunkno]==NULL)
1474
+        for(nchunk=0,chunkpos=0
1475
+          ;nchunk<redata->sizechunks
1476
+          ;chunkpos+=(chunk!=NULL)?chunk->useddata:0,nchunk++) {
1477
+                if((chunk=redata->chunks[nchunk])==NULL)
1413 1478
                         continue;
1414
-                if((start+redata->chunks[chunkno]->useddata)>pos)
1479
+                if(pos>=chunkpos && pos<(chunkpos+chunk->useddata))
1415 1480
                         break;
1416 1481
         }
1417
-        if(chunkno>=redata->sizechunks)
1418
-                return(-1);
1419
-        chunk=redata->chunks[chunkno];
1420
-        /* search line start */
1421
-        LINEINFODEBUG((stderr,"redata_line_info: searchstart: pos:%li start:%li offset:%li\n",pos,start,(pos-start)));
1422
-        for(ptr=chunk->data+(pos-start);ptr>chunk->data && ptr[-1]!='\n';ptr--)
1482
+        if(nchunk>=redata->sizechunks)
1483
+                return(-1); /* pos not found */
1484
+        for(newpos=pos;newpos>chunkpos && chunk->data[newpos-chunkpos-1]!='\n';newpos--)
1423 1485
                 ;
1424
-        /* search line end */
1425
-        LINEINFODEBUG((stderr,"redata_line_info: searchend: pos:%li start:%li offset:%li\n",pos,start,(pos-start)));
1426
-        for(end=chunk->data+(pos-start)+1;end<=(chunk->data+chunk->useddata) && end[-1]!='\n';end++)
1486
+        for(endpos=pos;endpos<(chunkpos+chunk->useddata) && chunk->data[endpos-chunkpos]!='\n';endpos++)
1427 1487
                 ;
1428
-        /* fill results */
1429
-        LINEINFODEBUG((stderr,"redata_line_info: filling results: len:%li\n",end-ptr));
1488
+        if(endpos==(chunkpos+chunk->useddata))
1489
+                endpos--;
1430 1490
         if(startpos!=NULL)
1431
-                *startpos=(pos-((chunk->data+(pos-start))-ptr));
1491
+                *startpos=newpos;
1432 1492
         if(startptr!=NULL)
1433
-                *startptr=(char *) ptr;
1493
+                *startptr=(char *) (chunk->data+(newpos-chunkpos));
1434 1494
         if(len!=NULL)
1435
-                *len=end-ptr;
1495
+                *len=endpos-newpos+1;
1496
+        if(is_continuation!=NULL) {
1497
+                if(!(chunk->whatin_fresh))
1498
+                        redata_whatin_refresh(redata,nchunk);
1499
+                *is_continuation=(newpos==chunkpos && chunk->whatin.iscontinuation)?1:0;
1500
+        }
1436 1501
         return(0);
1437 1502
 }
1438 1503
 
1439 1504
 int
1440
-redata_pos2linecol(redata_t *redata, long pos, int *resline, int *rescol)
1505
+redata_line_realstart(redata_t *redata, long pos, long *startpos)
1441 1506
 {
1442
-        int line,col;
1443
-        int nchunk;
1444
-        int chunkpos;
1445
-        rechunk_t *chunk;
1446
-        int i,o;
1447
-        if(redata==NULL)
1507
+        int is_continuation;
1508
+        long nextpos,newpos;
1509
+        if(redata==NULL || pos<0)
1510
+                return(-1); /* sanity check failed */
1511
+        nextpos=pos;
1512
+        do {
1513
+                if(redata_line_rawinfo(redata,nextpos,&newpos,NULL,NULL,&is_continuation)==-1)
1514
+                        return(-1);
1515
+                nextpos=newpos-1;
1516
+        } while(is_continuation && newpos>0);
1517
+        if(startpos!=NULL)
1518
+                *startpos=newpos;
1519
+        return(0);
1520
+}
1521
+
1522
+int
1523
+redata_line_realend(redata_t *redata, long pos, long *endpos)
1524
+{
1525
+        long nextpos,newpos;
1526
+        long datasize;
1527
+        char *ptr;
1528
+        int len;
1529
+        int has_nl;
1530
+        if(redata==NULL || pos<0)
1531
+                return(-1); /* sanity check failed */
1532
+        nextpos=pos;
1533
+        if((datasize=redata_getused(redata))<=0)
1534
+                return(-1); /* couldn't get last pos or there is no data */
1535
+        do {
1536
+                if(redata_line_rawinfo(redata,nextpos,&newpos,&ptr,&len,NULL)==-1 || len==0)
1537
+                        return(-1);
1538
+                nextpos=newpos+len;
1539
+                has_nl=(len>0 && ptr[len-1]=='\n')?1:0;
1540
+        } while(!has_nl && nextpos<datasize);
1541
+        if(endpos!=NULL)
1542
+                *endpos=newpos+len-1;
1543
+        return(0);
1544
+}
1545
+
1546
+int
1547
+redata_line_prevrealstart(redata_t *redata, long pos, long *startpos)
1548
+{
1549
+        long newpos,prevpos;
1550
+        if(redata==NULL || pos<0)
1448 1551
                 return(-1);
1449
-        /* search chunk of pos while calculating first lineno of chunk */
1450
-        for(nchunk=0,line=0,chunkpos=0
1451
-          ;nchunk<redata->sizechunks
1452
-          ;line+=chunk->whatin.nlcount,chunkpos+=chunk->useddata,nchunk++) {
1453
-                chunk=redata->chunks[nchunk];
1454
-                if(!(chunk->whatin_fresh))
1455
-                        redata_whatin_refresh(redata,nchunk);
1456
-                if(pos<(chunkpos+chunk->useddata))
1552
+        if(redata_line_realstart(redata,pos,&newpos)==-1)
1553
+                return(-1); /* couldn't get start of line */
1554
+        if(redata_line_realstart(redata,newpos-1,&prevpos)==-1)
1555
+                return(-1); /* couldn't get start of line */
1556
+        if(startpos!=NULL)
1557
+                *startpos=prevpos;
1558
+        return(0);
1559
+}
1560
+
1561
+int
1562
+redata_line_nextrealstart(redata_t *redata, long pos, long *startpos)
1563
+{
1564
+        long newpos,nextpos;
1565
+        if(redata==NULL || pos<0)
1566
+                return(-1);
1567
+        if(redata_line_realend(redata,pos,&newpos)==-1)
1568
+                return(-1); /* couldn't get end of line */
1569
+        if(redata_line_realstart(redata,newpos+1,&nextpos)==-1)
1570
+                return(-1); /* couldn't get start of line */
1571
+        if(startpos!=NULL)
1572
+                *startpos=nextpos;
1573
+        return(0);
1574
+}
1575
+
1576
+int
1577
+redata_line_inccol(redata_t *redata, long pos, int ncolrequest, long *newpos, int *ncoldone)
1578
+{
1579
+        long curpos,startpos;
1580
+        char *ptr;
1581
+        int len;
1582
+        int n,i;
1583
+        int done;
1584
+        if(redata==NULL || pos<0 || ncolrequest<0)
1585
+                return(-1); /* sanity check failed */
1586
+        if(ncolrequest==0) {
1587
+                if(newpos!=NULL)
1588
+                        *newpos=pos;
1589
+                if(ncoldone!=NULL)
1590
+                        *ncoldone=0;
1591
+                return(0); /* nothing to do */
1592
+        }
1593
+        for(n=0,curpos=pos;n<=ncolrequest;) {
1594
+                if(redata_line_rawinfo(redata,curpos,&startpos,&ptr,&len,NULL)==-1 || len==0)
1595
+                        return(-1); /* couldn't get current line data */
1596
+                done=0;
1597
+                /* advance until we are positioned on the next char to the requested one */
1598
+                for(i=startpos-curpos;i<len;i++) {
1599
+                        if(redata_generic_utf8isstartbyte(ptr[i]))
1600
+                                n++;
1601
+                        if(ptr[i]=='\n' || n>ncolrequest) {
1602
+                                done=1;
1603
+                                break;
1604
+                        }
1605
+                }
1606
+                curpos=startpos+i;
1607
+                if(done)
1457 1608
                         break;
1458 1609
         }
1459
-        if(nchunk>=redata->sizechunks)
1460
-                return(-1); /* pos not found */
1461
-        /* search chunk line/col */
1462
-        for(i=0,o=chunkpos,col=0;o<pos && i<chunk->useddata;i++,o++) {
1463
-                if(chunk->data[i]=='\n')
1464
-                        line++,col=0;
1465
-                else
1466
-                        col++;
1610
+        if(newpos!=NULL)
1611
+                *newpos=curpos;
1612
+        if(ncoldone!=NULL)
1613
+                *ncoldone=n-1;
1614
+        return(0);
1615
+}
1616
+
1617
+
1618
+int
1619
+redata_pos2linecol(redata_t *redata, long pos, int *resline, int *rescol)
1620
+{
1621
+        if(redata==NULL || pos<0 || pos>=redata_getused(redata))
1622
+                return(-1);
1623
+        /* calculate line */
1624
+        if(resline!=NULL) {
1625
+                long chunkpos,newpos;
1626
+                int startline;
1627
+                int nchunk;
1628
+                rechunk_t *chunk;
1629
+                int i;
1630
+                for(nchunk=0,chunkpos=0,startline=0
1631
+                  ;nchunk<redata->sizechunks
1632
+                  ;chunkpos+=(chunk!=NULL)?chunk->useddata:0
1633
+                    ,startline+=(chunk!=NULL)?chunk->whatin.nlcount:0,nchunk++) {
1634
+                        if((chunk=redata->chunks[nchunk])==NULL)
1635
+                                continue;
1636
+                        if(!(chunk->whatin_fresh))
1637
+                                redata_whatin_refresh(redata,nchunk);
1638
+                        if(pos>=chunkpos && pos<(chunkpos+chunk->useddata))
1639
+                                break;
1640
+                }
1641
+                if(nchunk>=redata->sizechunks)
1642
+                        return(-1); /* pos not found */
1643
+                for(newpos=chunkpos,i=0;newpos<pos && i<chunk->useddata;newpos++,i++) {
1644
+                        if(chunk->data[i]=='\n')
1645
+                                startline++;
1646
+                }
1647
+                *resline=startline;
1648
+        }
1649
+        /* calculate col */
1650
+        if(rescol!=NULL) {
1651
+                long realstart,curpos,startpos;
1652
+                char *ptr;
1653
+                int len;
1654
+                int n,i;
1655
+                int done;
1656
+                if(redata_line_realstart(redata,pos,&realstart)==-1)
1657
+                        return(-1); /* startpos for pos not found */
1658
+                for(n=0,curpos=realstart;curpos<pos;) {
1659
+                        if(redata_line_rawinfo(redata,curpos,&startpos,&ptr,&len,NULL)==-1 || len==0)
1660
+                                return(-1); /* couldn't get current line data */
1661
+                        done=0;
1662
+                        for(i=0;i<len && (startpos+i)<pos;i++) {
1663
+                                if(redata_generic_utf8isstartbyte(ptr[i]))
1664
+                                        n++;
1665
+                                if(ptr[i]=='\n') {
1666
+                                        done=1;
1667
+                                        break;
1668
+                                }
1669
+                        }
1670
+                        curpos=startpos+i;
1671
+                        if(done)
1672
+                                break;
1673
+                }
1674
+                *rescol=n;
1467 1675
         }
1468
-        if(resline!=NULL)
1469
-                *resline=line;
1470
-        if(rescol!=NULL)
1471
-                *rescol=col;
1472 1676
         return(0);
1473
-#warning DEBUG THIS
1474 1677
 }
1475 1678
 
1476 1679
 int
1477
-redata_linecol2pos(redata_t *redata, int line, int col, long *pos)
1680
+redata_linecol2pos(redata_t *redata, int line, int colrequest, long *pos, int *coldone)
1478 1681
 {
1479
-#warning TODO
1682
+#warning TODO: XXX Implement this function
1683
+#warning TODO: XXX: Add a parameter so this is like reata_line_inccol (colrequest, coldone) --  maybe also linetrequest linedone? (zed doesn''t let you go to the last line doing a Ctrl+q+l to an arbitrarily large number...)
1684
+#warning TODO: XXX: The extra parameters are super-handy because the main user of this function is Control+Q+L "Go To Line" and we want to go to nearest pos
1480 1685
         return(-1);
1481 1686
 }
1482 1687
 
... ...
@@ -1514,3 +1719,14 @@ meminvert(void *start, void *end)
1514 1719
         }
1515 1720
 }
1516 1721
 
1722
+static size_t
1723
+memrchroffset(char *ptr, int c, size_t n)
1724
+{
1725
+        size_t i;
1726
+        for(i=n-1;i>=0;i--) {
1727
+                if(((unsigned char *)ptr)[i]==c)
1728
+                        return(i);
1729
+        }
1730
+        return(-1);
1731
+}
1732
+
Browse code

Add pos2linecol and viceversa. Fix Cursor up/down.

Dario Rodriguez authored on 04/09/2020 17:56:20
Showing 1 changed files
... ...
@@ -1436,6 +1436,50 @@ redata_line_info(redata_t *redata, long pos, long *startpos, char **startptr, in
1436 1436
         return(0);
1437 1437
 }
1438 1438
 
1439
+int
1440
+redata_pos2linecol(redata_t *redata, long pos, int *resline, int *rescol)
1441
+{
1442
+        int line,col;
1443
+        int nchunk;
1444
+        int chunkpos;
1445
+        rechunk_t *chunk;
1446
+        int i,o;
1447
+        if(redata==NULL)
1448
+                return(-1);
1449
+        /* search chunk of pos while calculating first lineno of chunk */
1450
+        for(nchunk=0,line=0,chunkpos=0
1451
+          ;nchunk<redata->sizechunks
1452
+          ;line+=chunk->whatin.nlcount,chunkpos+=chunk->useddata,nchunk++) {
1453
+                chunk=redata->chunks[nchunk];
1454
+                if(!(chunk->whatin_fresh))
1455
+                        redata_whatin_refresh(redata,nchunk);
1456
+                if(pos<(chunkpos+chunk->useddata))
1457
+                        break;
1458
+        }
1459
+        if(nchunk>=redata->sizechunks)
1460
+                return(-1); /* pos not found */
1461
+        /* search chunk line/col */
1462
+        for(i=0,o=chunkpos,col=0;o<pos && i<chunk->useddata;i++,o++) {
1463
+                if(chunk->data[i]=='\n')
1464
+                        line++,col=0;
1465
+                else
1466
+                        col++;
1467
+        }
1468
+        if(resline!=NULL)
1469
+                *resline=line;
1470
+        if(rescol!=NULL)
1471
+                *rescol=col;
1472
+        return(0);
1473
+#warning DEBUG THIS
1474
+}
1475
+
1476
+int
1477
+redata_linecol2pos(redata_t *redata, int line, int col, long *pos)
1478
+{
1479
+#warning TODO
1480
+        return(-1);
1481
+}
1482
+
1439 1483
 static char *
1440 1484
 securesave_genname(char *filename, char *buf, int bufsize)
1441 1485
 {
Browse code

Free addnbuf in redata_free()

Dario Rodriguez authored on 03/09/2020 05:58:35
Showing 1 changed files
... ...
@@ -129,6 +129,9 @@ redata_free(redata_t *redata)
129 129
                 free(redata->redostack.undo),redata->redostack.undo=NULL;
130 130
         if(redata->redostack.buf!=NULL)
131 131
                 free(redata->redostack.buf),redata->redostack.buf=NULL;
132
+        /* addnbuf */
133
+        if(redata->addnbuf!=NULL)
134
+                free(redata->addnbuf),redata->addnbuf=NULL,redata->sizeaddnbuf=0;
132 135
         /* free main struct */
133 136
         free(redata),redata=NULL;
134 137
         return;
Browse code

Move utf8 helper functions to re_data. Add redata_op_addn().

Dario Rodriguez authored on 02/09/2020 22:07:13
Showing 1 changed files
... ...
@@ -26,6 +26,7 @@
26 26
 //#define CHUNKSIZE 32768
27 27
 #define CHUNKSIZE 160
28 28
 #define UNDOBLOCK 1024
29
+#define ADDNBLOCK 1024
29 30
 #define UNDOGROWSIZE (256*1024)
30 31
 #define SECURESAVEPREFIX "."
31 32
 #define SECURESAVEPOSTFIX ".saving"
... ...
@@ -860,6 +861,28 @@ redata_op_add(redata_t *redata, long insertpos, char *buf, long buflen, undostac
860 861
         return(0);
861 862
 }
862 863
 
864
+int
865
+redata_op_addn(redata_t *redata, long pos, char character, long n, undostack_t *fromhere)
866
+{
867
+        if(redata==NULL || n<0)
868
+                return(-1); /* sanity check failed */
869
+        if(n==0)
870
+                return(0); /* nothing to do */
871
+        if(redata->sizeaddnbuf<n) {
872
+                char *newptr;
873
+                long newsize;
874
+                newsize=(n+1+ADDNBLOCK)/ADDNBLOCK;
875
+                newsize*=ADDNBLOCK;
876
+                if((newptr=realloc(redata->addnbuf,newsize))==NULL)
877
+                        return(-1); /* insuf. mem. */
878
+                redata->addnbuf=newptr;
879
+                redata->sizeaddnbuf=newsize;
880
+        }
881
+        memset(redata->addnbuf,character,n);
882
+        redata->addnbuf[n]='\0';
883
+        return(redata_op_add(redata, pos, redata->addnbuf, n, fromhere));
884
+}
885
+
863 886
 int
864 887
 redata_op_del(redata_t *redata, long delpos, long size, undostack_t *fromhere)
865 888
 {
... ...
@@ -1249,6 +1272,64 @@ redata_generic_genname(char *filename,char *prefix, char *postfix, char *buf, in
1249 1272
         return(name);
1250 1273
 }
1251 1274
 
1275
+int
1276
+redata_generic_utf8len(char *ptr, int size)
1277
+{
1278
+        int len,i;
1279
+        /* calculate the number of utf8-charaters in buffer */
1280
+        if(size<0 || (ptr==NULL && size!=0))
1281
+                return(-1);
1282
+        /* for now we only count the number of code points */
1283
+        /* in UTF8: 0x00-0x7f single byte chars
1284
+         *          0xc0-0xff leading bytes
1285
+         *          0x80-0xbf continuation bytes (ignore these for len)*/
1286
+/*#warning TODO: XXX support combining code points (at least U+0300 - U+036F ( https://en.wikipedia.org/wiki/Combining_character ) */
1287
+        for(len=0,i=0;i<size;i++)
1288
+                len+=((ptr[i]&0xc0)!=0x80)?1:0;
1289
+        return(len);
1290
+/*#warning TODO: XXX Also consider tabs*/
1291
+}
1292
+
1293
+char *
1294
+redata_generic_utf8col(char *ptr, int size, int col)
1295
+{
1296
+        int len,i;
1297
+        /* return a pointer to the "n"th ("col"th) utf8-character in buffer */
1298
+        if(size<0 || (ptr==NULL && size!=0))
1299
+                return(NULL); /* sanity check failed */
1300
+        /* see reui_utf8len() for explanation of algorithm */
1301
+/*#warning TODO: support combining code points (at least U+0300 - U+036F ( https://en.wikipedia.org/wiki/Combining_character ) */
1302
+        if(col>=size)
1303
+                return(NULL);/* col greater than maximum possible char. count */
1304
+        /* skip "col" amount of single byte chars and leading bytes */
1305
+        for(len=0,i=0;len<col && i<size;i++)
1306
+                len+=((ptr[i]&0xc0)!=0x80)?1:0;
1307
+        /* if we landed in a continuation byte, advance until next single byte chars or leading byte */
1308
+        while(i<size && (ptr[i]&0xc0)==0x80)
1309
+                i++;
1310
+        if(i>=size)
1311
+                return(NULL); /* col is beyond end of string */
1312
+        return(ptr+i);
1313
+/*#warning TODO: XXX Also consider tabs*/
1314
+}
1315
+
1316
+int
1317
+redata_generic_utf8charlen(char *ptr, int maxsize)
1318
+{
1319
+        int i;
1320
+        /* returns the len in bytes of the character starting at ptr (zero on error)*/
1321
+        if(ptr==NULL || maxsize<1)
1322
+                return(0); /* sanity check failed */
1323
+/*#warning TODO: support combining code points (at least U+0300 - U+036F ( https://en.wikipedia.org/wiki/Combining_character ) */
1324
+        if(((unsigned char *)ptr)[0]<0x80)
1325
+                return(1); /* single byte char */
1326
+        if((ptr[0]&0xc0)==0x80)
1327
+                return(0); /* error: this is continuation, not leading byte */
1328
+        for(i=1;i<maxsize && (ptr[i]&0xc0)==0x80;i++)
1329
+                ;
1330
+        return(i);
1331
+}
1332
+
1252 1333
 
1253 1334
 static int
1254 1335
 redata_hash_gen(redata_t *redata, char *filename, char *buf, long buflen, char *resbuf129bytes)
Browse code

Implement up/down movement

Dario Rodriguez authored on 26/08/2020 21:50:45
Showing 1 changed files
... ...
@@ -23,7 +23,8 @@
23 23
 #include "re_data.h"
24 24
 #include "sha3/sha3.h"
25 25
 
26
-#define CHUNKSIZE 32768
26
+//#define CHUNKSIZE 32768
27
+#define CHUNKSIZE 160
27 28
 #define UNDOBLOCK 1024
28 29
 #define UNDOGROWSIZE (256*1024)
29 30
 #define SECURESAVEPREFIX "."
... ...
@@ -1304,6 +1305,53 @@ redata_hash_gen(redata_t *redata, char *filename, char *buf, long buflen, char *
1304 1305
         return(0);
1305 1306
 }
1306 1307
 
1308
+/*#define DEBUG_LINE_INFO*/
1309
+
1310
+#ifdef DEBUG_LINE_INFO
1311
+#define LINEINFODEBUG(a) fprintf a
1312
+#else
1313
+#define LINEINFODEBUG(a)
1314
+#endif
1315
+
1316
+int
1317
+redata_line_info(redata_t *redata, long pos, long *startpos, char **startptr, int *len)
1318
+{
1319
+        int chunkno;
1320
+        long start;
1321
+        unsigned char *ptr,*end;
1322
+        rechunk_t *chunk;
1323
+        if(redata==NULL || pos<0)
1324
+                return(-1);
1325
+        /* search chunk of pos */
1326
+        for(chunkno=0,start=0;chunkno<redata->sizechunks;start+=(redata->chunks[chunkno]==NULL)?0:redata->chunks[chunkno]->useddata,chunkno++) {
1327
+        LINEINFODEBUG((stderr,"redata_line_info: searchchunk: pos:%li chunkno:%i start:%li\n",pos,chunkno,start));
1328
+                if(redata->chunks[chunkno]==NULL)
1329
+                        continue;
1330
+                if((start+redata->chunks[chunkno]->useddata)>pos)
1331
+                        break;
1332
+        }
1333
+        if(chunkno>=redata->sizechunks)
1334
+                return(-1);
1335
+        chunk=redata->chunks[chunkno];
1336
+        /* search line start */
1337
+        LINEINFODEBUG((stderr,"redata_line_info: searchstart: pos:%li start:%li offset:%li\n",pos,start,(pos-start)));
1338
+        for(ptr=chunk->data+(pos-start);ptr>chunk->data && ptr[-1]!='\n';ptr--)
1339
+                ;
1340
+        /* search line end */
1341
+        LINEINFODEBUG((stderr,"redata_line_info: searchend: pos:%li start:%li offset:%li\n",pos,start,(pos-start)));
1342
+        for(end=chunk->data+(pos-start)+1;end<=(chunk->data+chunk->useddata) && end[-1]!='\n';end++)
1343
+                ;
1344
+        /* fill results */
1345
+        LINEINFODEBUG((stderr,"redata_line_info: filling results: len:%li\n",end-ptr));
1346
+        if(startpos!=NULL)
1347
+                *startpos=(pos-((chunk->data+(pos-start))-ptr));
1348
+        if(startptr!=NULL)
1349
+                *startptr=(char *) ptr;
1350
+        if(len!=NULL)
1351
+                *len=end-ptr;
1352
+        return(0);
1353
+}
1354
+
1307 1355
 static char *
1308 1356
 securesave_genname(char *filename, char *buf, int bufsize)
1309 1357
 {
Browse code

Fix pos and offset variable name mixups, fix offset data type (use int instead of long)

Dario Rodriguez authored on 19/08/2020 23:49:40
Showing 1 changed files
... ...
@@ -169,7 +169,7 @@ redata_getused(redata_t *redata)
169 169
 }
170 170
 
171 171
 int
172
-redata_getposptr(redata_t *redata, long pos, int *numchunk, long *offset)
172
+redata_getposptr(redata_t *redata, long pos, int *numchunk, int *offset)
173 173
 {
174 174
         long used;
175 175
         int i;
... ...
@@ -624,8 +624,8 @@ redata_undo_new(redata_t *redata, undostack_t *stack, char type)
624 624
 undo_t *
625 625
 redata_undo_newfromchunks(redata_t *redata, undostack_t *stack, char type, int pos1, int len)
626 626
 {
627
-        int startpos,endpos;
628
-        long startoff,endoff;
627
+        int startchunkno,endchunkno;
628
+        int startoff,endoff;
629 629
         undo_t *undo;
630 630
         int k;
631 631
         long used;
... ...
@@ -633,8 +633,8 @@ redata_undo_newfromchunks(redata_t *redata, undostack_t *stack, char type, int p
633 633
         if(redata==NULL || len<=0
634 634
           || (stack!=&(redata->undostack) && stack!=&(redata->redostack)))
635 635
                 return(NULL); /* sanity check failed */
636
-        if(redata_getposptr(redata,pos1,&startpos,&startoff)==-1 ||
637
-          redata_getposptr(redata,pos1+len,&endpos,&endoff)==-1) {
636
+        if(redata_getposptr(redata,pos1,&startchunkno,&startoff)==-1 ||
637
+          redata_getposptr(redata,pos1+len,&endchunkno,&endoff)==-1) {
638 638
                 return(NULL); /* chunk data out of bounds */
639 639
         }
640 640
         if(redata_undobuf_reserve(redata,stack,len)!=0)
... ...
@@ -643,14 +643,14 @@ redata_undo_newfromchunks(redata_t *redata, undostack_t *stack, char type, int p
643 643
                 return(NULL); /* insuf. mem. */
644 644
         undo->off=stack->usedbuf;
645 645
         /* copy contents */
646
-        for(k=startpos,used=0;k<=endpos;k++) {
647
-                if(k==startpos && k==endpos) {
646
+        for(k=startchunkno,used=0;k<=endchunkno;k++) {
647
+                if(k==startchunkno && k==endchunkno) {
648 648
                         copyfrom=startoff;
649 649
                         copysize=endoff-startoff;
650
-                } else if(k==startpos) {
650
+                } else if(k==startchunkno) {
651 651
                         copyfrom=startoff;
652 652
                         copysize=redata->chunks[k]->useddata-startoff;
653
-                } else if(k==endpos) {
653
+                } else if(k==endchunkno) {
654 654
                         copyfrom=0;
655 655
                         copysize=endoff;
656 656
                 } else {
... ...
@@ -763,7 +763,7 @@ int
763 763
 redata_op_add(redata_t *redata, long insertpos, char *buf, long buflen, undostack_t *fromhere)
764 764
 {
765 765
         int chunkno;
766
-        long pos;
766
+        int offset;
767 767
         undo_t *undo;
768 768
         rechunk_t *chunk,*nextchunk;
769 769
         long avail,nextavail;
... ...
@@ -774,7 +774,7 @@ redata_op_add(redata_t *redata, long insertpos, char *buf, long buflen, undostac
774 774
           || insertpos>redata_getused(redata)
775 775
           || (fromhere!=NULL && (fromhere!=&(redata->undostack) && fromhere!=&(redata->redostack))))
776 776
                 return(-1); /* sanity check failed */
777
-        if(redata_getposptr(redata,insertpos,&chunkno,&pos)==-1)
777
+        if(redata_getposptr(redata,insertpos,&chunkno,&offset)==-1)
778 778
                 return(-1); /* invalid pos */
779 779
         if(fromhere!=&(redata->undostack)) {
780 780
                 if((undo=redata_undo_newfrombuf(redata,&(redata->undostack),'A',buf,buflen))==NULL)
... ...
@@ -789,24 +789,24 @@ redata_op_add(redata_t *redata, long insertpos, char *buf, long buflen, undostac
789 789
         nextavail=(nextchunk==NULL)?0:redata->chunkdatasize-nextchunk->useddata;
790 790
         if(avail>=buflen) {
791 791
                 /* fits in current chunk */
792
-                redata_chunk_insertdata(redata,chunkno,pos,buf,buflen);
792
+                redata_chunk_insertdata(redata,chunkno,offset,buf,buflen);
793 793
                 redata_fix_nl(redata,chunkno);
794 794
                 nextchunk=chunk;
795 795
         } else if((avail+nextavail)>=buflen) {
796 796
                 /* part fits in current chunk, part in next chunk */
797 797
                 int bothering;
798
-                bothering=chunk->useddata-pos;
798
+                bothering=chunk->useddata-offset;
799 799
                 bothering=(bothering>nextavail)?nextavail:bothering;
800 800
                 redata_chunk_movedata(redata,chunkno,chunk->useddata-bothering,chunkno+1,0,bothering);
801 801
                 avail=redata->chunkdatasize-chunk->useddata;
802 802
                 avail=(avail>buflen)?buflen:avail;
803
-                redata_chunk_insertdata(redata,chunkno,pos,buf,avail);
803
+                redata_chunk_insertdata(redata,chunkno,offset,buf,avail);
804 804
                 redata_chunk_insertdata(redata,chunkno+1,0,buf+avail,buflen-avail);
805 805
         } else {
806 806
                 /* will need to add more chunks */
807 807
                 needed=(buflen+redata->chunkdatasize-1)/redata->chunkdatasize;
808 808
                 needed*=redata->chunkdatasize;
809
-                needed+=(chunk->useddata-pos);
809
+                needed+=(chunk->useddata-offset);
810 810
                 if(redata_preallocate(redata,redata_getsize(redata)+needed)!=0) {
811 811
                         if(undo!=NULL) {
812 812
                                 redata->undostack.usedundo--;
... ...
@@ -816,7 +816,7 @@ redata_op_add(redata_t *redata, long insertpos, char *buf, long buflen, undostac
816 816
                         return(-1); /* insuf. mem. */
817 817
                 }
818 818
                 redata_chunk_insertnew(redata,chunkno);
819
-                redata_chunk_movedata(redata,chunkno,pos,chunkno+1,0,chunk->useddata-pos);
819
+                redata_chunk_movedata(redata,chunkno,offset,chunkno+1,0,chunk->useddata-offset);
820 820
                 nextchunk=redata->chunks[chunkno+1];
821 821
                 avail=redata->chunkdatasize-chunk->useddata;
822 822
                 avail=(avail>buflen)?buflen:avail;
... ...
@@ -863,7 +863,7 @@ int
863 863
 redata_op_del(redata_t *redata, long delpos, long size, undostack_t *fromhere)
864 864
 {
865 865
         int chunkno,curchunk;
866
-        long pos;
866
+        int offset;
867 867
         undo_t *undo;
868 868
         rechunk_t *chunk;
869 869
         long ndel;
... ...
@@ -874,7 +874,7 @@ redata_op_del(redata_t *redata, long delpos, long size, undostack_t *fromhere)
874 874
           || (delpos+size)>redata_getused(redata)
875 875
           || (fromhere!=NULL && (fromhere!=&(redata->undostack) && fromhere!=&(redata->redostack))))
876 876
                 return(-1); /* sanity check failed */
877
-        if(redata_getposptr(redata,delpos,&chunkno,&pos)==-1)
877
+        if(redata_getposptr(redata,delpos,&chunkno,&offset)==-1)
878 878
                 return(-1); /* invalid pos */
879 879
         if(fromhere!=&(redata->undostack)) {
880 880
                 if((undo=redata_undo_newfromchunks(redata,&(redata->undostack),'D',delpos,size))==NULL)
... ...
@@ -884,7 +884,7 @@ redata_op_del(redata_t *redata, long delpos, long size, undostack_t *fromhere)
884 884
                 undo=NULL;
885 885
         }
886 886
         for(curchunk=chunkno,ndel=0;ndel<size;curchunk++) {
887
-                curpos=(curchunk==chunkno)?pos:0;
887
+                curpos=(curchunk==chunkno)?offset:0;
888 888
                 curdel=redata->chunks[curchunk]->useddata-curpos;
889 889
                 curdel=(curdel>(size-ndel))?(size-ndel):curdel;
890 890
                 redata_chunk_deletedata(redata,curchunk,curpos,curdel);
... ...
@@ -927,7 +927,7 @@ int
927 927
 redata_op_move(redata_t *redata, long posorig, long size, long posdest, undostack_t *fromhere)
928 928
 {
929 929
         int chunkno,dchunkno,curchunk;
930
-        long pos,dpos;
930
+        int offset,doffset;
931 931
         undo_t *undo;
932 932
         rechunk_t *chunk;
933 933
         int i;
... ...
@@ -938,9 +938,9 @@ redata_op_move(redata_t *redata, long posorig, long size, long posdest, undostac
938 938
           || (posdest>=posorig && posdest<(posorig+size))
939 939
           || (fromhere!=NULL && (fromhere!=&(redata->undostack) && fromhere!=&(redata->redostack))))
940 940
                 return(-1); /* sanity check failed */
941
-        if(redata_getposptr(redata,posorig,&chunkno,&pos)==-1)
941
+        if(redata_getposptr(redata,posorig,&chunkno,&offset)==-1)
942 942
                 return(-1); /* invalid pos */
943
-        if(redata_getposptr(redata,posdest,&dchunkno,&dpos)==-1)
943
+        if(redata_getposptr(redata,posdest,&dchunkno,&doffset)==-1)
944 944
                 return(-1); /* invalid pos */
945 945
         if(fromhere!=&(redata->undostack)) {
946 946
                 if((undo=redata_undo_newfromchunks(redata,&(redata->undostack),'M',posorig,size))==NULL)
... ...
@@ -951,48 +951,48 @@ redata_op_move(redata_t *redata, long posorig, long size, long posdest, undostac
951 951
         } else {
952 952
                 undo=NULL;
953 953
         }
954
-        if((pos+size)<=redata->chunks[chunkno]->useddata
954
+        if((offset+size)<=redata->chunks[chunkno]->useddata
955 955
           && (chunkno==dchunkno || (redata->chunkdatasize-redata->chunks[dchunkno]->useddata)>=size)) {
956 956
                 /* trivial case: (all the data is in the same chunk) AND (it is intra-chunk move or destination chunk has enough avail. space) */
957
-                redata_chunk_movedata(redata, chunkno, pos, dchunkno, dpos, size);
957
+                redata_chunk_movedata(redata, chunkno, offset, dchunkno, doffset, size);
958 958
         } else {
959 959
                 /* data spans several chunks, no space on dest, etc: do it the hard way */
960 960
                 /* separate the selected data into its own chunk(s) */
961 961
                 /* lower positions have to make the boundary first (or risk undoing it with next create boundary) */
962 962
                 if(posdest<posorig) {
963 963
                         /* make a chunk boundary in posdest */
964
-                        if(redata_getposptr(redata,posdest,&chunkno,&pos)==-1
965
-                          || redata_chunk_splithere(redata,chunkno,pos)!=0)
964
+                        if(redata_getposptr(redata,posdest,&chunkno,&offset)==-1
965
+                          || redata_chunk_splithere(redata,chunkno,offset)!=0)
966 966
                                 return(-1); /* invalid pos or insuf. mem */
967 967
                 }
968 968
                 /* make a chunk boundary in posorig and in posorig+size */
969
-                if(redata_getposptr(redata,posorig,&chunkno,&pos)==-1
970
-                  || redata_chunk_splithere(redata,chunkno,pos)!=0)
969
+                if(redata_getposptr(redata,posorig,&chunkno,&offset)==-1
970
+                  || redata_chunk_splithere(redata,chunkno,offset)!=0)
971 971
                         return(-1); /* invalid pos or insuf. mem */
972
-                if(redata_getposptr(redata,posorig+size,&chunkno,&pos)==-1
973
-                  || redata_chunk_splithere(redata,chunkno,pos)!=0)
972
+                if(redata_getposptr(redata,posorig+size,&chunkno,&offset)==-1
973
+                  || redata_chunk_splithere(redata,chunkno,offset)!=0)
974 974
                         return(-1); /* invalid pos or insuf. mem */
975 975
                 if(posdest>posorig) {
976 976
                         /* make a chunk boundary in posdest */
977
-                        if(redata_getposptr(redata,posdest,&chunkno,&pos)==-1
978
-                          || redata_chunk_splithere(redata,chunkno,pos)!=0)
977
+                        if(redata_getposptr(redata,posdest,&chunkno,&offset)==-1
978
+                          || redata_chunk_splithere(redata,chunkno,offset)!=0)
979 979
                                 return(-1); /* invalid pos or insuf. mem */
980 980
                 }
981 981
                 /* reorder the chunks */
982 982
                 {
983 983
                         int schunkno;
984
-                        long spos;
985
-                        if(redata_getposptr(redata,posorig,&chunkno,&pos)==-1)
984
+                        int soffset;
985
+                        if(redata_getposptr(redata,posorig,&chunkno,&offset)==-1)
986 986
                                 return(-1); /* invalid pos or insuf. mem */
987
-                        if(redata_getposptr(redata,posorig+size,&schunkno,&spos)==-1)
987
+                        if(redata_getposptr(redata,posorig+size,&schunkno,&soffset)==-1)
988 988
                                 return(-1); /* invalid pos or insuf. mem */
989
-                        if(redata_getposptr(redata,posdest,&dchunkno,&dpos)==-1)
989
+                        if(redata_getposptr(redata,posdest,&dchunkno,&doffset)==-1)
990 990
                                 return(-1); /* invalid pos or insuf. mem */
991
-                        if(pos!=0)
991
+                        if(offset!=0)
992 992
                                 chunkno++;
993
-                        if(spos!=0)
993
+                        if(soffset!=0)
994 994
                                 schunkno++;
995
-                        if(dpos!=0)
995
+                        if(doffset!=0)
996 996
                                 dchunkno++;
997 997
                         if(chunkno<0 || schunkno<0 || dchunkno<0
998 998
                           || chunkno>=redata->sizechunks || schunkno>=redata->sizechunks || dchunkno>=redata->sizechunks)
... ...
@@ -1011,14 +1011,14 @@ redata_op_move(redata_t *redata, long posorig, long size, long posdest, undostac
1011 1011
         }
1012 1012
         /* fix nl and delete unused chunks */
1013 1013
         if(posorig<posdest) {
1014
-              if(redata_getposptr(redata,posorig,&chunkno,&pos)==-1)
1014
+              if(redata_getposptr(redata,posorig,&chunkno,&offset)==-1)
1015 1015
                       return(-1); /* invalid pos */
1016
-              if(redata_getposptr(redata,posdest,&dchunkno,&dpos)==-1)
1016
+              if(redata_getposptr(redata,posdest,&dchunkno,&doffset)==-1)
1017 1017
                       return(-1); /* invalid pos */
1018 1018
         } else { /* posorig>posdest */
1019
-              if(redata_getposptr(redata,posdest,&chunkno,&pos)==-1)
1019
+              if(redata_getposptr(redata,posdest,&chunkno,&offset)==-1)
1020 1020
                       return(-1); /* invalid pos */
1021
-              if(redata_getposptr(redata,posorig+size,&dchunkno,&dpos)==-1)
1021
+              if(redata_getposptr(redata,posorig+size,&dchunkno,&doffset)==-1)
1022 1022
                       return(-1); /* invalid pos */
1023 1023
         }
1024 1024
         for(curchunk=dchunkno;curchunk>=chunkno;curchunk--) {
... ...
@@ -1105,7 +1105,7 @@ int
1105 1105
 redata_data_compare(redata_t *redata, long cmppos, char *buf, long buflen)
1106 1106
 {
1107 1107
         int chunkno;
1108
-        long pos;
1108
+        int offset;
1109 1109
         long compared;
1110 1110
         long n;
1111 1111
         int res;
... ...
@@ -1113,12 +1113,12 @@ redata_data_compare(redata_t *redata, long cmppos, char *buf, long buflen)
1113 1113
           || cmppos>redata_getused(redata)
1114 1114
           || (cmppos+buflen)>redata_getused(redata))
1115 1115
                 return(-1); /* sanity check failed */
1116
-        if(redata_getposptr(redata,cmppos,&chunkno,&pos)==-1)
1116
+        if(redata_getposptr(redata,cmppos,&chunkno,&offset)==-1)
1117 1117
                 return(-1); /* invalid pos */
1118
-        for(compared=0,n=0;compared<buflen && chunkno<redata->sizechunks;chunkno++,pos=0,compared+=n) {
1119
-                n=redata->chunks[chunkno]->useddata-pos;
1118
+        for(compared=0,n=0;compared<buflen && chunkno<redata->sizechunks;chunkno++,offset=0,compared+=n) {
1119
+                n=redata->chunks[chunkno]->useddata-offset;
1120 1120
                 n=(n<0)?0:((compared+n)>buflen)?(buflen-compared):n;
1121
-                if((res=memcmp(redata->chunks[chunkno]->data+pos,buf+compared,n))!=0)
1121
+                if((res=memcmp(redata->chunks[chunkno]->data+offset,buf+compared,n))!=0)
1122 1122
                         return(res);
1123 1123
         }
1124 1124
         if(compared<buflen)
Browse code

Reworked plugin API

Dario Rodriguez authored on 09/04/2019 14:28:44
Showing 1 changed files
... ...
@@ -467,13 +467,14 @@ redata_fix_nl(redata_t *redata, int chunkno)
467 467
 }
468 468
 
469 469
 int
470
-redata_load(redata_t *redata, char *filename, int use_unsaved)
470
+redata_load(redata_t *redata, char *filename, int (*callback_question)(/*char *title, char *body, int nopts, char *opts[],void *userptr*/), void *userptr)
471 471
 {
472 472
         int fd,nread,totalread;
473 473
         int chunkno, avail;
474 474
         struct stat statbuf;
475 475
         rechunk_t *chunk;
476 476
         int i;
477
+        int reply;
477 478
         if(redata==NULL || filename==NULL)
478 479
                 return(-1); /* sanity check failed */
479 480
         redata_wipe(redata);
... ...
@@ -520,18 +521,20 @@ redata_load(redata_t *redata, char *filename, int use_unsaved)
520 521
                 redata_fix_nl(redata,chunkno);
521 522
         for(chunkno=0;chunkno<redata->sizechunks;chunkno++)
522 523
                 redata_whatin_refresh(redata,chunkno);
523
-        /* unsaved */
524
+        /* unsaved and other plugins */
524 525
         for(i=0;i<redata->sizeplugins;i++) {
525
-                if(use_unsaved) {
526
-                        /* apply missing changes and append new changes to unsaved */
527
-                        if(redata->plugins[i].postload!=NULL)
528
-                                redata->plugins[i].postload(redata,redata->plugins+i,filename);
529
-                } else {
530
-                        /* nuke existing unsaved (if exists) and prepare new unsaved */
531
-                        /* _trunc() fills itself redata->initialhash */
532
-                        if(redata->plugins[i].truncload!=NULL)
533
-                                redata->plugins[i].truncload(redata,redata->plugins+i,filename);
526
+                if(!redata->plugins[i].active)
527
+                        continue;
528
+                reply=-1;
529
+                if(redata->plugins[i].loadquestion!=NULL && callback_question!=NULL) {
530
+                        char *title, *body;
531
+                        int nopts;
532
+                        char **opts;
533
+                        if(redata->plugins[i].loadquestion(redata,redata->plugins+i,filename,&title,&body,&nopts,&opts)!=-1)
534
+                                reply=callback_question(title,body,nopts,opts,userptr);
534 535
                 }
536
+                if(redata->plugins[i].postload!=NULL)
537
+                        redata->plugins[i].postload(redata,redata->plugins+i,filename,reply);
535 538
         }
536 539
         /* all done */
537 540
         return(0);
Browse code

Refactor unsaved into a plugin of redata

Dario Rodriguez authored on 04/04/2019 21:53:07
Showing 1 changed files
... ...
@@ -18,6 +18,7 @@
18 18
 #include <fcntl.h>
19 19
 #include <limits.h>
20 20
 #include <inttypes.h>
21
+#include <stdarg.h>
21 22
 
22 23
 #include "re_data.h"
23 24
 #include "sha3/sha3.h"
... ...
@@ -25,21 +26,11 @@
25 26
 #define CHUNKSIZE 32768
26 27
 #define UNDOBLOCK 1024
27 28
 #define UNDOGROWSIZE (256*1024)
28
-#define UNSAVEDPREFIX "."
29
-#define UNSAVEDPOSTFIX ".reu"
30 29
 #define SECURESAVEPREFIX "."
31 30
 #define SECURESAVEPOSTFIX ".saving"
32
-#define UNSAVEDHEADER "reunsaved00,"
33 31
 
34 32
 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 33
 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 34
 static void *mymemrchr(const void *s, int c, size_t n);
44 35
 static void meminvert(void *start, void *end);
45 36
 
... ...
@@ -64,12 +55,23 @@ redata_debug_chunkdump(redata_t *redata, char *title)
64 55
 #endif
65 56
 
66 57
 redata_t *
67
-redata_init(void)
58
+redata_init(int (*pluginregisterfn)(redata_t *redata, redata_plugin_t *slot), ...)
68 59
 {
69 60
         redata_t *redata;
70
-        if((redata=malloc(sizeof(redata_t)))==NULL)
61
+        va_list args;
62
+        int nargs;
63
+        int res;
64
+        int (*fn)(redata_t *redata, redata_plugin_t *slot);
65
+        /* count number of plugins */
66
+        va_start(args,pluginregisterfn);
67
+        for(nargs=0,fn=pluginregisterfn;fn!=NULL;fn=va_arg(args,int (*)(redata_t *redata, redata_plugin_t *slot)))
68
+                nargs++;
69
+        va_end(args);
70
+        /* get memory */
71
+        if((redata=malloc(sizeof(redata_t)+sizeof(redata_plugin_t)*(nargs-1)))==NULL)
71 72
                 return(NULL); /* sanity check failed */
72
-        memset(redata,0,sizeof(redata_t));
73
+        memset(redata,0,sizeof(redata_t)+sizeof(redata_plugin_t)*(nargs-1));
74
+        redata->sizeplugins=nargs;
73 75
         /* data */
74 76
         redata->sizechunks=0;
75 77
         redata->chunks=NULL;
... ...
@@ -80,10 +82,15 @@ redata_init(void)
80 82
         redata->undostack.usedundo=0;
81 83
         redata->undostack.undo=NULL;
82 84
         redata->undostack.buf=NULL;
83
-        /* unsaved */
85
+        /* plugins */
86
+        for(nargs=0,fn=pluginregisterfn;fn!=NULL;fn=va_arg(args,int (*)(redata_t *redata,redata_plugin_t *slot))) {
87
+                res=fn(redata,redata->plugins+nargs);
88
+                redata->plugins[nargs].active=(res==0)?1:0;
89
+                nargs++;
90
+        }
91
+        va_end(args);
92
+        /* filename */
84 93
         redata->filename[0]='\0';
85
-        redata->unsavedfd=-1;
86
-        redata->unsaved.sizebuf=redata->unsaved.usedbuf=0;
87 94
         /* all done */
88 95
         return(redata);
89 96
 }
... ...
@@ -92,9 +99,14 @@ void
92 99
 redata_free(redata_t *redata)
93 100
 {
94 101
         int i;
95
-        char unsname[PATH_MAX];
96 102
         if(redata==NULL)
97 103
                 return; /* nothing to do */
104
+        /* plugins */
105
+        for(i=0;i<redata->sizeplugins;i++) {
106
+                if(redata->plugins[i].unregister!=NULL)
107
+                        redata->plugins[i].unregister(redata,redata->plugins+i,redata->filename);
108
+                memset(redata->plugins+i,0,sizeof(redata_plugin_t));
109
+        }
98 110
         /* data */
99 111
         for(i=0;i<redata->sizechunks;i++) {
100 112
                 if(redata->chunks[i]!=NULL)
... ...
@@ -115,16 +127,6 @@ redata_free(redata_t *redata)
115 127
                 free(redata->redostack.undo),redata->redostack.undo=NULL;
116 128
         if(redata->redostack.buf!=NULL)
117 129
                 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 130
         /* free main struct */
129 131
         free(redata),redata=NULL;
130 132
         return;
... ...
@@ -190,7 +192,6 @@ int
190 192
 redata_wipe(redata_t *redata)
191 193
 {
192 194
         int i;
193
-        char unsname[PATH_MAX];
194 195
         if(redata==NULL)
195 196
                 return(-1); /* sanity check failed */
196 197
         /* data */
... ...
@@ -199,14 +200,12 @@ redata_wipe(redata_t *redata)
199 200
                 memset(&(redata->chunks[i]->whatin),0,sizeof(whatin_t));
200 201
         }
201 202
         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);
203
+        /* plugins */
204
+        for(i=0;i<redata->sizeplugins;i++) {
205
+                if(redata->plugins[i].wipe!=NULL)
206
+                        redata->plugins[i].wipe(redata,redata->plugins+i,redata->filename);
207 207
         }
208 208
         redata->filename[0]='\0';
209
-        redata->unsaved.usedbuf=0;
210 209
         /* all done */
211 210
         return(0);
212 211
 }
... ...
@@ -467,385 +466,6 @@ redata_fix_nl(redata_t *redata, int chunkno)
467 466
         return(0);
468 467
 }
469 468
 
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 469
 int
850 470
 redata_load(redata_t *redata, char *filename, int use_unsaved)
851 471
 {
... ...
@@ -853,6 +473,7 @@ redata_load(redata_t *redata, char *filename, int use_unsaved)
853 473
         int chunkno, avail;
854 474
         struct stat statbuf;
855 475
         rechunk_t *chunk;
476
+        int i;
856 477
         if(redata==NULL || filename==NULL)
857 478
                 return(-1); /* sanity check failed */
858 479
         redata_wipe(redata);
... ...
@@ -900,14 +521,17 @@ redata_load(redata_t *redata, char *filename, int use_unsaved)
900 521
         for(chunkno=0;chunkno<redata->sizechunks;chunkno++)
901 522
                 redata_whatin_refresh(redata,chunkno);
902 523
         /* 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);
524
+        for(i=0;i<redata->sizeplugins;i++) {
525
+                if(use_unsaved) {
526
+                        /* apply missing changes and append new changes to unsaved */
527
+                        if(redata->plugins[i].postload!=NULL)
528
+                                redata->plugins[i].postload(redata,redata->plugins+i,filename);
529
+                } else {
530
+                        /* nuke existing unsaved (if exists) and prepare new unsaved */
531
+                        /* _trunc() fills itself redata->initialhash */
532
+                        if(redata->plugins[i].truncload!=NULL)
533
+                                redata->plugins[i].truncload(redata,redata->plugins+i,filename);
534
+                }
911 535
         }
912 536
         /* all done */
913 537
         return(0);
... ...
@@ -939,10 +563,12 @@ redata_save(redata_t *redata, char *filename)
939 563
                 unlink(tmpfile);
940 564
                 return(-1); /* couldn't overwrite old file */
941 565
         }
942
-        redata_unsaved_unlink(redata);
566
+        for(i=0;i<redata->sizeplugins;i++) {
567
+                if(redata->plugins[i].postsave!=NULL)
568
+                        redata->plugins[i].postsave(redata,redata->plugins+i,redata->filename,filename);
569
+        }
943 570
         strncpy(redata->filename,filename,sizeof(redata->filename));
944 571
         redata->filename[sizeof(redata->filename)-1]='\0';
945
-        redata_unsaved_trunc(redata);
946 572
         return(0);
947 573
 }
948 574
 
... ...
@@ -1219,8 +845,11 @@ redata_op_add(redata_t *redata, long insertpos, char *buf, long buflen, undostac
1219 845
                 /* from undo stack */
1220 846
                 redata_undo_movelast(redata,&(redata->undostack),&(redata->redostack));
1221 847
         }
1222
-        /* add to unsaved */
1223
-        redata_unsaved_add(redata,&(redata->undostack),redata->undostack.usedundo-1);
848
+        /* add to plugins (unsaved,...) */
849
+        for(i=0;i<redata->sizeplugins;i++) {
850
+                if(redata->plugins[i].add!=NULL)
851
+                        redata->plugins[i].add(redata,redata->plugins+i,redata->undostack.undo+redata->undostack.usedundo-1);
852
+        }
1224 853
         /* compact if needed */
1225 854
         if(redata_getsize(redata)>(redata->chunkdatasize) && redata_getavailable(redata)>(redata_getsize(redata)/2))
1226 855
                 redata_compact(redata);
... ...
@@ -1236,6 +865,7 @@ redata_op_del(redata_t *redata, long delpos, long size, undostack_t *fromhere)
1236 865
         rechunk_t *chunk;
1237 866
         long ndel;
1238 867
         long curpos,curdel;
868
+        int i;
1239 869
         if(redata==NULL || size<0
1240 870
           || delpos<0
1241 871
           || (delpos+size)>redata_getused(redata)
... ...
@@ -1279,8 +909,11 @@ redata_op_del(redata_t *redata, long delpos, long size, undostack_t *fromhere)
1279 909
                 /* from undo stack */
1280 910
                 redata_undo_movelast(redata,&(redata->undostack),&(redata->redostack));
1281 911
         }
1282
-        /* add to unsaved */
1283
-        redata_unsaved_add(redata,&(redata->undostack),redata->undostack.usedundo-1);
912
+        /* add to plugins (unsaved,...) */
913
+        for(i=0;i<redata->sizeplugins;i++) {
914
+                if(redata->plugins[i].add!=NULL)
915
+                        redata->plugins[i].add(redata,redata->plugins+i,redata->undostack.undo+redata->undostack.usedundo-1);
916
+        }
1284 917
         /* compact if needed */
1285 918
         if(redata_getsize(redata)>(redata->chunkdatasize) && redata_getavailable(redata)>(redata_getsize(redata)/2))
1286 919
                 redata_compact(redata);
... ...
@@ -1294,6 +927,7 @@ redata_op_move(redata_t *redata, long posorig, long size, long posdest, undostac
1294 927
         long pos,dpos;
1295 928
         undo_t *undo;
1296 929
         rechunk_t *chunk;
930
+        int i;
1297 931
         if(redata==NULL || size<0
1298 932
           || posorig<0
1299 933
           || (posorig+size)>redata_getused(redata)
... ...
@@ -1410,8 +1044,11 @@ redata_op_move(redata_t *redata, long posorig, long size, long posdest, undostac
1410 1044
                 /* from undo stack */
1411 1045
                 redata_undo_movelast(redata,&(redata->undostack),&(redata->redostack));
1412 1046
         }
1413
-        /* add to unsaved */
1414
-        redata_unsaved_add(redata,&(redata->undostack),redata->undostack.usedundo-1);
1047
+        /* add to plugins (unsaved,...) */
1048
+        for(i=0;i<redata->sizeplugins;i++) {
1049
+                if(redata->plugins[i].add!=NULL)
1050
+                        redata->plugins[i].add(redata,redata->plugins+i,redata->undostack.undo+redata->undostack.usedundo-1);
1051
+        }
1415 1052
         /* compact if needed */
1416 1053
         if(redata_getsize(redata)>(redata->chunkdatasize) && redata_getavailable(redata)>(redata_getsize(redata)/2))
1417 1054
                 redata_compact(redata);
... ...
@@ -1437,6 +1074,7 @@ redata_op_undo(redata_t *redata)
1437 1074
                         redata_op_move(redata,undo->posdest, undo->len, undo->posorig+undo->len,&(redata->undostack));
1438 1075
         } else
1439 1076
                 return(-1); /* unknown operation */
1077
+#warning TODO: Is it neccessary to do an unadd to the plugins?
1440 1078
         return(-1);
1441 1079
 }
1442 1080
 
... ...
@@ -1456,6 +1094,7 @@ redata_op_redo(redata_t *redata)
1456 1094
                 redata_op_move(redata,undo->posorig, undo->len, undo->posdest,&(redata->redostack));
1457 1095
         } else
1458 1096
                 return(-1); /* unknown operation */
1097
+#warning TODO: Is it neccessary to do an unadd to the plugins?
1459 1098
         return(-1);
1460 1099
 }
1461 1100
 
... ...
@@ -1559,6 +1198,54 @@ redata_memhash(redata_t *redata, char *buf, long buflen, char *resbuf129bytes)
1559 1198
         return(redata_hash_gen(NULL,NULL,buf,buflen,resbuf129bytes));
1560 1199
 }
1561 1200
 
1201
+undostack_t *
1202
+redata_getstack(redata_t *redata, undo_t *undo)
1203
+{
1204
+        if(redata==NULL || undo==NULL)
1205
+                return(NULL); /* sanity check failed */
1206
+        if(undo>=redata->undostack.undo && undo<(redata->undostack.undo+redata->undostack.sizeundo))
1207
+                return(&(redata->undostack));
1208
+        if(undo>=redata->redostack.undo && undo<(redata->redostack.undo+redata->redostack.sizeundo))
1209
+                return(&(redata->redostack));
1210
+        return(NULL); /* unknown stack */
1211
+}
1212
+
1213
+char *
1214
+redata_generic_genname(char *filename,char *prefix, char *postfix, char *buf, int bufsize)
1215
+{
1216
+        char *name,*ptr;
1217
+        int filenamelen;
1218
+        int prelen,postlen,finallen,off;
1219
+        if(filename==NULL || prefix==NULL || postfix==NULL)
1220
+                return(NULL);
1221
+        filenamelen=strlen(filename);
1222
+        prelen=strlen(prefix);
1223
+        postlen=strlen(postfix);
1224
+        finallen=filenamelen+prelen+postlen+1;
1225
+        if(buf==NULL) {
1226
+                if((name=malloc(finallen))==NULL)
1227
+                        return(NULL);
1228
+        } else {
1229
+                if(bufsize<filenamelen)
1230
+                        return(NULL);
1231
+                name=buf;
1232
+        }
1233
+        for(ptr=filename+strlen(filename);ptr>filename && ptr[-1]!='/';ptr--)
1234
+                ;
1235
+        off=0;
1236
+        memcpy(name+off,filename,ptr-filename);
1237
+        off+=ptr-filename;
1238
+        memcpy(name+off,prefix,prelen);
1239
+        off+=prelen;
1240
+        memcpy(name+off,ptr,filenamelen-(ptr-filename));
1241
+        off+=filenamelen-(ptr-filename);
1242
+        memcpy(name+off,postfix,postlen);
1243
+        off+=postlen;
1244
+        name[off]='\0';
1245
+        return(name);
1246
+}
1247
+
1248
+
1562 1249
 static int
1563 1250
 redata_hash_gen(redata_t *redata, char *filename, char *buf, long buflen, char *resbuf129bytes)
1564 1251
 {
... ...
@@ -1614,128 +1301,12 @@ redata_hash_gen(redata_t *redata, char *filename, char *buf, long buflen, char *
1614 1301
         return(0);
1615 1302
 }
1616 1303
 
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 1304
 static char *
1627 1305
 securesave_genname(char *filename, char *buf, int bufsize)
1628 1306
 {
1629 1307
         static char pre[]={SECURESAVEPREFIX};
1630 1308
         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]);
1309
+        return(redata_generic_genname(filename,pre,post,buf,bufsize));
1739 1310
 }
1740 1311
 
1741 1312
 static void *
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
new file mode 100644
... ...
@@ -0,0 +1,1766 @@
1
+/*
2
+ * re_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 "re_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
+