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