... | ... |
@@ -78,6 +78,8 @@ redata_free(redata_t *redata) |
78 | 78 |
redata->sizechunks=0; |
79 | 79 |
if(redata->chunks!=NULL) |
80 | 80 |
free(redata->chunks),redata->chunks=NULL; |
81 |
+ if(redata->tmpchunk!=NULL) |
|
82 |
+ free(redata->tmpchunk),redata->tmpchunk=NULL; |
|
81 | 83 |
/* undo */ |
82 | 84 |
if(redata->undo!=NULL) |
83 | 85 |
free(redata->undo),redata->undo=NULL; |
... | ... |
@@ -95,6 +97,16 @@ redata_free(redata_t *redata) |
95 | 97 |
return; |
96 | 98 |
} |
97 | 99 |
|
100 |
+int |
|
101 |
+redata_config_chunkdatasize(redata_t *redata, int chunkdatasize) |
|
102 |
+{ |
|
103 |
+ /* NOTE: this can only be configured immediately after doing redata_init() */ |
|
104 |
+ if(redata==NULL || chunkdatasize<=0 || redata->sizechunks!=0) |
|
105 |
+ return(-1); /* sanity check failed */ |
|
106 |
+ redata->chunkdatasize=chunkdatasize; |
|
107 |
+ return(0); |
|
108 |
+} |
|
109 |
+ |
|
98 | 110 |
int |
99 | 111 |
redata_getsize(redata_t *redata) |
100 | 112 |
{ |
... | ... |
@@ -177,10 +189,17 @@ redata_preallocate(redata_t *redata, int newsize) |
177 | 189 |
int oldsizechunks; |
178 | 190 |
if(redata==NULL || redata->chunkdatasize==0 || newsize<0) |
179 | 191 |
return(-1); /* sanity check failed */ |
192 |
+ rechunksize=sizeof(rechunk_t)-1+redata->chunkdatasize; |
|
193 |
+ /* before doing any chunk alloc, we setup tmpchunk (used for moves) */ |
|
194 |
+ if(redata->tmpchunk==NULL) { |
|
195 |
+ if((redata->tmpchunk=malloc(rechunksize))==NULL) |
|
196 |
+ return(-1); /* insuf. mem. */ |
|
197 |
+ memset(redata->tmpchunk,0,rechunksize); |
|
198 |
+ } |
|
199 |
+ /* new chunk processing */ |
|
180 | 200 |
if((cursize=redata_getsize(redata))>=newsize) |
181 | 201 |
return(0); /* all done */ |
182 | 202 |
nchunks=(newsize-cursize+redata->chunkdatasize-1)/redata->chunkdatasize; |
183 |
- rechunksize=sizeof(rechunk_t)-1+redata->chunkdatasize; |
|
184 | 203 |
if((newchunks=realloc(redata->chunks,sizeof(rechunk_t *)*(redata->sizechunks+nchunks)))==NULL) |
185 | 204 |
return(-1); /* insuf. mem. */ |
186 | 205 |
redata->chunks=newchunks; |
... | ... |
@@ -198,6 +217,49 @@ redata_preallocate(redata_t *redata, int newsize) |
198 | 217 |
return(0); |
199 | 218 |
} |
200 | 219 |
|
220 |
+int |
|
221 |
+redata_chunk_movedata(redata_t *redata, int chunkfrom, int posfrom, int chunkto, int posto, int size) |
|
222 |
+{ |
|
223 |
+ if(redata==NULL || size<0 |
|
224 |
+ || chunkfrom<0 || chunkfrom>=redata->sizechunks |
|
225 |
+ || posfrom<0 || (posfrom+size)>redata->chunks[chunkfrom]->useddata |
|
226 |
+ || chunkto<0 || chunkto>=redata->sizechunks |
|
227 |
+ || posto<0 || (posto)>redata->chunks[chunkto]->useddata |
|
228 |
+ || (chunkfrom!=chunkto && (redata->chunkdatasize-redata->chunks[chunkto]->useddata)<size) |
|
229 |
+ || (chunkfrom==chunkto && posfrom<posto && posfrom+size>posto) |
|
230 |
+ ) |
|
231 |
+ return(-1); /* sanity check failed */ |
|
232 |
+ if(size==0 |
|
233 |
+ || (chunkfrom==chunkto && posfrom==posto) |
|
234 |
+ || (chunkfrom==chunkto && (posfrom+size)==posto) |
|
235 |
+ ) |
|
236 |
+ return(0); /* all done */ |
|
237 |
+ if(chunkfrom!=chunkto) { |
|
238 |
+ rechunk_t *from,*to; |
|
239 |
+ from=redata->chunks[chunkfrom]; |
|
240 |
+ to=redata->chunks[chunkto]; |
|
241 |
+ memmove(to->data+posto+size,to->data+posto,to->useddata-posto); |
|
242 |
+ memcpy(to->data+posto,from->data+posfrom,size); |
|
243 |
+ memmove(from->data+posfrom,from->data+posfrom+size,from->useddata-posfrom-size); |
|
244 |
+ from->useddata-=size; |
|
245 |
+ to->useddata+=size; |
|
246 |
+ } else { |
|
247 |
+ /* from==to */ |
|
248 |
+ rechunk_t *chunk=redata->chunks[chunkfrom]; |
|
249 |
+ memcpy(redata->tmpchunk->data,chunk->data+posfrom,size); |
|
250 |
+ if(posto>posfrom) { |
|
251 |
+ int inside=(posto-posfrom)-size; |
|
252 |
+ memmove(chunk->data+posfrom,chunk->data+posto-inside,inside); |
|
253 |
+ memcpy(chunk->data+posfrom+inside,redata->tmpchunk->data,size); |
|
254 |
+ } else { |
|
255 |
+ int inside=(posto-posfrom); |
|
256 |
+ memmove(chunk->data+posfrom+size-inside,chunk->data+posto,inside); |
|
257 |
+ memcpy(chunk->data+posto,redata->tmpchunk->data,size); |
|
258 |
+ } |
|
259 |
+ } |
|
260 |
+ return(0); |
|
261 |
+} |
|
262 |
+ |
|
201 | 263 |
int |
202 | 264 |
redata_fill_whatin(redata_t *redata, int chunkno) |
203 | 265 |
{ |
... | ... |
@@ -207,12 +269,80 @@ redata_fill_whatin(redata_t *redata, int chunkno) |
207 | 269 |
if(redata==NULL || chunkno<0 || chunkno>=redata->sizechunks || redata->chunks[chunkno]==NULL) |
208 | 270 |
return(-1); /* sanity check failed */ |
209 | 271 |
chunk=redata->chunks[chunkno]; |
272 |
+ if(chunk->whatin_fresh) |
|
273 |
+ return(0); |
|
210 | 274 |
memset(&(chunk->whatin),0,sizeof(whatin_t)); |
211 | 275 |
nlcount=0; |
212 | 276 |
for(i=0,lim=chunk->useddata;i<lim;i++) { |
213 | 277 |
nlcount+=(chunk->data[i]=='\n')?1:0; |
214 | 278 |
} |
215 | 279 |
chunk->whatin.nlcount=nlcount; |
280 |
+ chunk->whatin_fresh=1; |
|
281 |
+ return(0); |
|
282 |
+} |
|
283 |
+ |
|
284 |
+void * |
|
285 |
+mymemrchr(const void *s, int c, size_t n) |
|
286 |
+{ |
|
287 |
+ int i; |
|
288 |
+ void *res=NULL; |
|
289 |
+ unsigned char b; |
|
290 |
+ b=(*((unsigned int *)(&c)))&0xff; |
|
291 |
+ for(i=0;i<n;i++) { |
|
292 |
+ if(((unsigned char *)s)[i]==b) |
|
293 |
+ res=s+i; |
|
294 |
+ } |
|
295 |
+ return(res); |
|
296 |
+} |
|
297 |
+ |
|
298 |
+int |
|
299 |
+redata_fix_nl(redata_t *redata, int chunkno) |
|
300 |
+{ |
|
301 |
+ /* make sure a line of len<chunksize is entirely inside one chunk (to simplify the syntax highlighting code) */ |
|
302 |
+ if(redata==NULL || chunkno<0 || chunkno>=redata->sizechunks || redata->chunks[chunkno]==NULL) |
|
303 |
+ return(-1); /* sanity check failed */ |
|
304 |
+ if(chunkno==(redata->sizechunks-1) || redata->chunks[chunkno]->useddata==0 || redata->chunks[chunkno]->data[redata->chunks[chunkno]->useddata-1]=='\n') |
|
305 |
+ return(0); /* Nothing to do (last chunk, chunk empty or already fixed) */ |
|
306 |
+ rechunk_t *chunk,*nextchunk; |
|
307 |
+ int linesize, nextlinesize, avail, nextavail; |
|
308 |
+ unsigned char *ptr,*nextptr; |
|
309 |
+ chunk=redata->chunks[chunkno]; |
|
310 |
+ nextchunk=redata->chunks[chunkno+1]; |
|
311 |
+ ptr=mymemrchr(chunk->data,'\n',chunk->useddata); |
|
312 |
+ nextptr=memchr(nextchunk->data,'\n',nextchunk->useddata); |
|
313 |
+ linesize=(ptr==NULL)?chunk->useddata:(chunk->useddata-(ptr-chunk->data)-1); |
|
314 |
+ nextlinesize=(nextptr==NULL)?nextchunk->useddata:((nextptr-nextchunk->data)+1); |
|
315 |
+ avail=redata->chunkdatasize-chunk->useddata; |
|
316 |
+ nextavail=redata->chunkdatasize-nextchunk->useddata; |
|
317 |
+ if(avail>=nextlinesize) { |
|
318 |
+ /* move remaining bytes of line to current chunk */ |
|
319 |
+ redata_chunk_movedata(redata, chunkno+1, 0, chunkno, chunk->useddata, nextlinesize); |
|
320 |
+ } else if(nextavail>=linesize) { |
|
321 |
+ /* move incomplete line to next chunk */ |
|
322 |
+ redata_chunk_movedata(redata, chunkno, chunk->useddata-linesize, chunkno+1, 0, linesize); |
|
323 |
+ } else if(ptr!=NULL) { |
|
324 |
+ /* only if we have more data un chunkno before this long line */ |
|
325 |
+ int i,newavail; |
|
326 |
+ rechunk_t *newchunk; |
|
327 |
+ /* create a new empty chunk in-between and put the line there */ |
|
328 |
+ if(redata->chunks[redata->sizechunks-1]->useddata!=0) { |
|
329 |
+ if(redata_preallocate(redata,redata->available+redata->chunkdatasize)==-1 |
|
330 |
+ || redata->chunks[redata->sizechunks-1]->useddata!=0) |
|
331 |
+ return(-1); |
|
332 |
+ } |
|
333 |
+ newchunk=redata->chunks[redata->sizechunks-1]; |
|
334 |
+ /* move the emty chunk to after chunkno */ |
|
335 |
+ for(i=redata->sizechunks-1;i>(chunkno+1);i--) |
|
336 |
+ redata->chunks[i]=redata->chunks[i-1]; |
|
337 |
+ redata->chunks[chunkno+1]=newchunk; |
|
338 |
+ /* move the data; if it doesn't fit, move from the beginning until it is full */ |
|
339 |
+ redata_chunk_movedata(redata, chunkno, chunk->useddata-linesize, chunkno+1, 0, linesize); |
|
340 |
+ newavail=redata->sizechunks-linesize; |
|
341 |
+ redata_chunk_movedata(redata, chunkno+2, 0, chunkno+1, linesize, (newavail<nextlinesize)?newavail:nextlinesize); |
|
342 |
+ redata->chunks[chunkno+2]->whatin_fresh=0; |
|
343 |
+ } |
|
344 |
+ redata->chunks[chunkno]->whatin_fresh=0; |
|
345 |
+ redata->chunks[chunkno+1]->whatin_fresh=0; |
|
216 | 346 |
return(0); |
217 | 347 |
} |
218 | 348 |
|
... | ... |
@@ -329,7 +459,6 @@ redata_unsaved_unadd(redata_t *redata, undo_t *undo) |
329 | 459 |
int |
330 | 460 |
redata_load(redata_t *redata, char *filename, int use_unsaved) |
331 | 461 |
{ |
332 |
-#warning TODO: make sure a line of len<chunksize is entirely inside one chunk (to simplify the syntax highlighting code) |
|
333 | 462 |
int fd,nread,totalread; |
334 | 463 |
int chunkno, avail; |
335 | 464 |
struct stat statbuf; |
... | ... |
@@ -374,9 +503,12 @@ redata_load(redata_t *redata, char *filename, int use_unsaved) |
374 | 503 |
} |
375 | 504 |
chunk->useddata+=nread; |
376 | 505 |
redata->available-=nread; |
377 |
- redata_fill_whatin(redata,chunkno); |
|
378 | 506 |
} |
379 | 507 |
close(fd),fd=-1; |
508 |
+ for(chunkno=0;chunkno<redata->sizechunks;chunkno++) |
|
509 |
+ redata_fix_nl(redata,chunkno); |
|
510 |
+ for(chunkno=0;chunkno<redata->sizechunks;chunkno++) |
|
511 |
+ redata_fill_whatin(redata,chunkno); |
|
380 | 512 |
/* unsaved */ |
381 | 513 |
redata_hash(redata,redata->initialhash); |
382 | 514 |
if(use_unsaved) { |
... | ... |
@@ -19,6 +19,7 @@ typedef struct whatin_t { |
19 | 19 |
|
20 | 20 |
typedef struct rechunk_t { |
21 | 21 |
whatin_t whatin; |
22 |
+ int whatin_fresh; |
|
22 | 23 |
int useddata; |
23 | 24 |
unsigned char data[1]; |
24 | 25 |
} rechunk_t; |
... | ... |
@@ -35,6 +36,7 @@ typedef struct redata_t { |
35 | 36 |
int sizechunks; |
36 | 37 |
rechunk_t **chunks; |
37 | 38 |
int available; |
39 |
+ rechunk_t *tmpchunk; |
|
38 | 40 |
/* undo */ |
39 | 41 |
int sizeundo; |
40 | 42 |
int usedundo; |
... | ... |
@@ -55,17 +57,19 @@ typedef struct redata_t { |
55 | 57 |
redata_t *redata_init(void); |
56 | 58 |
void redata_free(redata_t *redata); |
57 | 59 |
|
60 |
+int redata_config_chunkdatasize(redata_t *redata, int chunkdatasize); |
|
61 |
+ |
|
58 | 62 |
int redata_getsize(redata_t *redata); |
59 | 63 |
int redata_getused(redata_t *redata); |
60 | 64 |
int redata_getavailable(redata_t *redata); |
61 | 65 |
int redata_getused(redata_t *redata); |
62 | 66 |
int redata_getposptr(redata_t *redata, int pos, int *numchunk, int *offset); |
63 | 67 |
|
64 |
- |
|
65 |
- |
|
66 | 68 |
int redata_wipe(redata_t *redata); |
67 | 69 |
int redata_preallocate(redata_t *redata, int size); |
70 |
+int redata_chunk_movedata(redata_t *redata, int chunkfrom, int posfrom, int chunkto, int posto, int size); |
|
68 | 71 |
int redata_fill_whatin(redata_t *redata, int chunkno); |
72 |
+int redata_fix_nl(redata_t *redata, int chunkno); |
|
69 | 73 |
|
70 | 74 |
int redata_unsaved_exists(redata_t *redata, char *filename); |
71 | 75 |
int redata_unsaved_check(redata_t *redata, char *filename); |
... | ... |
@@ -84,6 +88,8 @@ int redata_op_move(redata_t *redata, int posorig, int size, int posdest); |
84 | 88 |
int redata_op_undo(redata_t *redata); |
85 | 89 |
int redata_op_redo(redata_t *redata); |
86 | 90 |
|
91 |
+int redata_commit_unsaved(redata_t *redata); |
|
92 |
+ |
|
87 | 93 |
int redata_hash(redata_t *redata, char *resbuf129bytes); |
88 | 94 |
int redata_filehash(redata_t *redata, char *filename, char *resbuf129bytes); |
89 | 95 |
int redata_memhash(redata_t *redata, char *buf, int buflen, char *resbuf129bytes); |