... | ... |
@@ -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 */ |
... | ... |
@@ -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) |
... | ... |
@@ -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-- |
... | ... |
@@ -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) |
... | ... |
@@ -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 |
{ |
... | ... |
@@ -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])) { |
... | ... |
@@ -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 |
|
... | ... |
@@ -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; |
... | ... |
@@ -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 |
} |
... | ... |
@@ -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 |
{ |
... | ... |
@@ -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 */ |
... | ... |
@@ -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; |
... | ... |
@@ -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)) |
... | ... |
@@ -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 |
|
... | ... |
@@ -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 |
{ |
... | ... |
@@ -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) |
... | ... |
@@ -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 |
... | ... |
@@ -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)) { |
... | ... |
@@ -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++) { |
... | ... |
@@ -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; |
... | ... |
@@ -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 * |
... | ... |
@@ -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 |
+ |
... | ... |
@@ -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 |
{ |
... | ... |
@@ -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; |
... | ... |
@@ -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) |
... | ... |
@@ -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 |
{ |
... | ... |
@@ -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) |
... | ... |
@@ -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); |
... | ... |
@@ -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 * |
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 |
+ |