| ... | ... |
@@ -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 |
+ |