| ... | ... |
@@ -547,8 +547,8 @@ redata_unsaved_loadquestion(redata_t *redata, redata_plugin_t *slot,char *filena |
| 547 | 547 |
static char mybody[]={"The file you're trying to load has some unsaved data from a previous session. I can recover the data. What do you want to do?"};
|
| 548 | 548 |
static char *myopts[]={"Recover unsaved data (safest option)","Don't use old unsaved data, delete old unsaved data (if you're sure what you're doing)"};
|
| 549 | 549 |
static char mytitleshort[]={"Unsaved data found"};
|
| 550 |
- static char mybodyshort[]={"Should try to recover the data?"};
|
|
| 551 |
- static char *myoptsshort[]={"Recover","Ignore it"};
|
|
| 550 |
+ static char mybodyshort[]={"Try to recover the data?"};
|
|
| 551 |
+ static char *myoptsshort[]={"Recover data","Ignore data","Quit"};
|
|
| 552 | 552 |
question_t *q; |
| 553 | 553 |
if(redata==NULL || slot==NULL || filename==NULL) |
| 554 | 554 |
return(-1); /* sanity check failed */ |
| ... | ... |
@@ -563,7 +563,7 @@ redata_unsaved_loadquestion(redata_t *redata, redata_plugin_t *slot,char *filena |
| 563 | 563 |
q->bodyshort=mybodyshort; |
| 564 | 564 |
q->opts=myopts; |
| 565 | 565 |
q->optsshort=myoptsshort; |
| 566 |
- q->nopts=2; |
|
| 566 |
+ q->nopts=3; |
|
| 567 | 567 |
q->defaultoption=1; |
| 568 | 568 |
q->selectedoption=-1; |
| 569 | 569 |
return(0); |
| ... | ... |
@@ -582,6 +582,11 @@ redata_unsaved_postload(redata_t *redata, redata_plugin_t *slot,char *filename) |
| 582 | 582 |
return(redata_unsaved_truncload(redata, slot, filename)); |
| 583 | 583 |
else if(selectedoption==0) /* recover */ |
| 584 | 584 |
return(redata_unsaved_loadappend(redata, slot, filename)); |
| 585 |
+#if 0 |
|
| 586 |
+#error TODO: implement be able to force-quit from plugin */ |
|
| 587 |
+ else if(selectedoption==2) /* quit */ |
|
| 588 |
+ return(-1); |
|
| 589 |
+#endif |
|
| 585 | 590 |
return(-1); |
| 586 | 591 |
} |
| 587 | 592 |
|
| ... | ... |
@@ -6,7 +6,7 @@ |
| 6 | 6 |
* re_data plugin to support the unsaved changes file. |
| 7 | 7 |
* (for recovery when the program closes unexpectedly) |
| 8 | 8 |
* |
| 9 |
- * Author: Dario Rodriguez dario@softhome.net |
|
| 9 |
+ * Author: Dario Rodriguez antartica@whereismybit.com |
|
| 10 | 10 |
* This program is licensed under the terms of GNU GPL v2.1+ |
| 11 | 11 |
*/ |
| 12 | 12 |
|
| ... | ... |
@@ -27,7 +27,8 @@ |
| 27 | 27 |
#define UNSAVEDGROWSIZE (256*1024) |
| 28 | 28 |
|
| 29 | 29 |
|
| 30 |
- |
|
| 30 |
+int redata_unsaved_add(redata_t *redata, redata_plugin_t *slot, undo_t *undo); |
|
| 31 |
+int redata_unsaved_unadd(redata_t *redata, redata_plugin_t *slot, undo_t *undo); |
|
| 31 | 32 |
static int redata_unsaved_loadquestion(redata_t *redata, redata_plugin_t *slot,char *filename); |
| 32 | 33 |
static int redata_unsaved_postload(redata_t *redata, redata_plugin_t *slot,char *filename); |
| 33 | 34 |
static int redata_unsaved_check_gen(redata_t *redata, redata_plugin_t *slot, char *filename); |
| ... | ... |
@@ -55,8 +56,7 @@ redata_unsaved_register(redata_t *redata, redata_plugin_t *slot) |
| 55 | 56 |
slot->wipe=redata_unsaved_wipe; |
| 56 | 57 |
slot->postload=redata_unsaved_postload; |
| 57 | 58 |
slot->postsave=redata_unsaved_trunc; |
| 58 |
- slot->add=redata_unsaved_add; |
|
| 59 |
- slot->unadd=redata_unsaved_unadd; |
|
| 59 |
+ slot->add_or_unadd=redata_unsaved_add_or_unadd; |
|
| 60 | 60 |
slot->commit=redata_unsaved_commit; |
| 61 | 61 |
slot->userptr=unsaved; |
| 62 | 62 |
return(0); |
| ... | ... |
@@ -357,6 +357,15 @@ fprintf(stderr,"\n"); |
| 357 | 357 |
return(0); |
| 358 | 358 |
} |
| 359 | 359 |
|
| 360 |
+int |
|
| 361 |
+redata_unsaved_add_or_unadd(redata_t *redata, redata_plugin_t *slot, undo_t *undo, int is_unadd) |
|
| 362 |
+{
|
|
| 363 |
+ return((is_unadd==0)? |
|
| 364 |
+ redata_unsaved_add(redata, slot, undo): |
|
| 365 |
+ redata_unsaved_unadd(redata, slot, undo)); |
|
| 366 |
+} |
|
| 367 |
+ |
|
| 368 |
+ |
|
| 360 | 369 |
int |
| 361 | 370 |
redata_unsaved_add(redata_t *redata, redata_plugin_t *slot, undo_t *undo) |
| 362 | 371 |
{
|
| ... | ... |
@@ -208,7 +208,7 @@ redata_unsaved_trunc(redata_t *redata, redata_plugin_t *slot, char *oldfilename, |
| 208 | 208 |
int |
| 209 | 209 |
redata_unsaved_truncload(redata_t *redata, redata_plugin_t *slot, char *filename) |
| 210 | 210 |
{
|
| 211 |
-#if 1 |
|
| 211 |
+#if 0 |
|
| 212 | 212 |
fprintf(stderr,"UNSAVED: TRUNCLOAD (ignore)\n"); |
| 213 | 213 |
#endif |
| 214 | 214 |
return(redata_unsaved_trunc(redata, slot, NULL, filename)); |
| ... | ... |
@@ -230,17 +230,17 @@ redata_unsaved_loadappend(redata_t *redata, redata_plugin_t *slot, char *filenam |
| 230 | 230 |
char endcode; |
| 231 | 231 |
int flag_multipart; |
| 232 | 232 |
unsaved_t *unsaved=(unsaved_t *) ((slot!=NULL)?(slot->userptr):NULL); |
| 233 |
-#if 1 |
|
| 233 |
+#if 0 |
|
| 234 | 234 |
fprintf(stderr,"UNSAVED: LOADAPPEND (recover)\n"); |
| 235 | 235 |
#endif |
| 236 | 236 |
if(redata==NULL || slot==NULL || unsaved==NULL || filename==NULL) |
| 237 | 237 |
return(-1); |
| 238 |
-#if 1 |
|
| 238 |
+#if 0 |
|
| 239 | 239 |
fprintf(stderr,"UNSAVED: LOADAPPEND pre-check\n"); |
| 240 | 240 |
#endif |
| 241 | 241 |
if((fd=redata_unsaved_check_gen(redata,slot,filename))==-1) |
| 242 | 242 |
return(-1); /* check failed */ |
| 243 |
-#if 1 |
|
| 243 |
+#if 0 |
|
| 244 | 244 |
fprintf(stderr,"UNSAVED: LOADAPPEND post-check\n"); |
| 245 | 245 |
#endif |
| 246 | 246 |
if(fstat(fd,&statbuf)!=0 || !S_ISREG(statbuf.st_mode)) {
|
| ... | ... |
@@ -249,7 +249,7 @@ fprintf(stderr,"UNSAVED: LOADAPPEND post-check\n"); |
| 249 | 249 |
} |
| 250 | 250 |
redata_hash(redata,unsaved->initialhash); |
| 251 | 251 |
headerhashsize=(sizeof(header)-1)+128+1; |
| 252 |
-#if 1 |
|
| 252 |
+#if 0 |
|
| 253 | 253 |
fprintf(stderr,"UNSAVED: LOADAPPEND headerhashsize: %li\n",headerhashsize); |
| 254 | 254 |
#endif |
| 255 | 255 |
/* load unsaved to memory */ |
| ... | ... |
@@ -419,7 +419,7 @@ redata_unsaved_add(redata_t *redata, redata_plugin_t *slot, undo_t *undo) |
| 419 | 419 |
return(-1); /* insuf. mem. */ |
| 420 | 420 |
unsaved->buf=buf; |
| 421 | 421 |
unsaved->sizebuf=newsize; |
| 422 |
-#if 1 |
|
| 422 |
+#if 0 |
|
| 423 | 423 |
fprintf(stderr,"UNSAVED: ADD realloc: %li\n",(long)newsize); |
| 424 | 424 |
#endif |
| 425 | 425 |
} |
| ... | ... |
@@ -496,7 +496,7 @@ redata_unsaved_unadd(redata_t *redata, redata_plugin_t *slot, undo_t *undo) |
| 496 | 496 |
return(-1); /* insuf. mem. */ |
| 497 | 497 |
unsaved->buf=buf; |
| 498 | 498 |
unsaved->sizebuf=newsize; |
| 499 |
-#if 1 |
|
| 499 |
+#if 0 |
|
| 500 | 500 |
fprintf(stderr,"UNSAVED: UNADD realloc: %li\n",(long)newsize); |
| 501 | 501 |
#endif |
| 502 | 502 |
} |
| ... | ... |
@@ -514,7 +514,7 @@ redata_unsaved_commit(redata_t *redata, redata_plugin_t *slot,char *filename) |
| 514 | 514 |
unsaved_t *unsaved=(unsaved_t *) ((slot!=NULL)?(slot->userptr):NULL); |
| 515 | 515 |
if(redata==NULL || slot==NULL || unsaved==NULL || unsaved->unsavedfd==-1) |
| 516 | 516 |
return(-1); |
| 517 |
-#if 1 |
|
| 517 |
+#if 0 |
|
| 518 | 518 |
if(unsaved->usedbuf>0) |
| 519 | 519 |
fprintf(stderr,"UNSAVED_COMMITTED\n"); |
| 520 | 520 |
#endif |
| ... | ... |
@@ -412,13 +412,16 @@ redata_unsaved_add(redata_t *redata, redata_plugin_t *slot, undo_t *undo) |
| 412 | 412 |
} |
| 413 | 413 |
if(k==0) {
|
| 414 | 414 |
/* get mem */ |
| 415 |
- if((unsaved->sizebuf-unsaved->sizebuf)<maxsize) {
|
|
| 415 |
+ if((unsaved->sizebuf-unsaved->usedbuf)<maxsize) {
|
|
| 416 | 416 |
newsize=(unsaved->sizebuf+maxsize+UNSAVEDGROWSIZE-1)/UNSAVEDGROWSIZE; |
| 417 | 417 |
newsize*=UNSAVEDGROWSIZE; |
| 418 | 418 |
if((buf=realloc(unsaved->buf,newsize))==NULL) |
| 419 | 419 |
return(-1); /* insuf. mem. */ |
| 420 | 420 |
unsaved->buf=buf; |
| 421 | 421 |
unsaved->sizebuf=newsize; |
| 422 |
+#if 1 |
|
| 423 |
+fprintf(stderr,"UNSAVED: ADD realloc: %li\n",(long)newsize); |
|
| 424 |
+#endif |
|
| 422 | 425 |
} |
| 423 | 426 |
buf=unsaved->buf+unsaved->usedbuf; |
| 424 | 427 |
} else |
| ... | ... |
@@ -486,13 +489,16 @@ redata_unsaved_unadd(redata_t *redata, redata_plugin_t *slot, undo_t *undo) |
| 486 | 489 |
} |
| 487 | 490 |
if(k==0) {
|
| 488 | 491 |
/* get mem */ |
| 489 |
- if((unsaved->sizebuf-unsaved->sizebuf)<maxsize) {
|
|
| 492 |
+ if((unsaved->sizebuf-unsaved->usedbuf)<maxsize) {
|
|
| 490 | 493 |
newsize=(unsaved->sizebuf+maxsize+UNSAVEDGROWSIZE-1)/UNSAVEDGROWSIZE; |
| 491 | 494 |
newsize*=UNSAVEDGROWSIZE; |
| 492 | 495 |
if((buf=realloc(unsaved->buf,newsize))==NULL) |
| 493 | 496 |
return(-1); /* insuf. mem. */ |
| 494 | 497 |
unsaved->buf=buf; |
| 495 | 498 |
unsaved->sizebuf=newsize; |
| 499 |
+#if 1 |
|
| 500 |
+fprintf(stderr,"UNSAVED: UNADD realloc: %li\n",(long)newsize); |
|
| 501 |
+#endif |
|
| 496 | 502 |
} |
| 497 | 503 |
buf=unsaved->buf+unsaved->usedbuf; |
| 498 | 504 |
} |
| ... | ... |
@@ -517,6 +517,7 @@ if(unsaved->usedbuf>0) |
| 517 | 517 |
close(unsaved->unsavedfd),unsaved->unsavedfd=-1; |
| 518 | 518 |
if((unsaved_genname(filename,unsname,sizeof(unsname)))!=NULL) |
| 519 | 519 |
unlink(unsname); /* a corrupted unsaved is of no use, delete it */ |
| 520 |
+ slot->active=0; |
|
| 520 | 521 |
return(-1); /* error writing */ |
| 521 | 522 |
} |
| 522 | 523 |
} |
| ... | ... |
@@ -77,6 +77,8 @@ redata_unsaved_unregister(redata_t *redata, redata_plugin_t *slot, char *filenam |
| 77 | 77 |
if(filename!=NULL && unsaved_genname(filename,unsname,sizeof(unsname))!=NULL) |
| 78 | 78 |
unlink(unsname); |
| 79 | 79 |
} |
| 80 |
+ if(slot->userptr!=NULL) |
|
| 81 |
+ free(slot->userptr),slot->userptr=NULL; |
|
| 80 | 82 |
return(0); |
| 81 | 83 |
} |
| 82 | 84 |
|
| ... | ... |
@@ -507,7 +507,8 @@ redata_unsaved_commit(redata_t *redata, redata_plugin_t *slot,char *filename) |
| 507 | 507 |
if(redata==NULL || slot==NULL || unsaved==NULL || unsaved->unsavedfd==-1) |
| 508 | 508 |
return(-1); |
| 509 | 509 |
#if 1 |
| 510 |
-fprintf(stderr,"UNSAVED_COMMITTED\n"); |
|
| 510 |
+if(unsaved->usedbuf>0) |
|
| 511 |
+ fprintf(stderr,"UNSAVED_COMMITTED\n"); |
|
| 511 | 512 |
#endif |
| 512 | 513 |
for(nwritten=0;nwritten<unsaved->usedbuf;nwritten+=n) {
|
| 513 | 514 |
if((n=write(unsaved->unsavedfd,unsaved->buf+nwritten,unsaved->usedbuf-nwritten))<0) {
|
| ... | ... |
@@ -28,8 +28,8 @@ |
| 28 | 28 |
|
| 29 | 29 |
|
| 30 | 30 |
|
| 31 |
-static int redata_unsaved_loadquestion(redata_t *redata, redata_plugin_t *slot,char *filename, char **title, char **body, int *nopts, char **opts[]); |
|
| 32 |
-static int redata_unsaved_postload(redata_t *redata, redata_plugin_t *slot,char *filename,int questionreply); |
|
| 31 |
+static int redata_unsaved_loadquestion(redata_t *redata, redata_plugin_t *slot,char *filename); |
|
| 32 |
+static int redata_unsaved_postload(redata_t *redata, redata_plugin_t *slot,char *filename); |
|
| 33 | 33 |
static int redata_unsaved_check_gen(redata_t *redata, redata_plugin_t *slot, char *filename); |
| 34 | 34 |
static char *unsaved_genname(char *filename, char *buf, int bufsize); |
| 35 | 35 |
static char *ptr_getlong(char *ptr,char *endptr,long *data); |
| ... | ... |
@@ -58,6 +58,7 @@ redata_unsaved_register(redata_t *redata, redata_plugin_t *slot) |
| 58 | 58 |
slot->add=redata_unsaved_add; |
| 59 | 59 |
slot->unadd=redata_unsaved_unadd; |
| 60 | 60 |
slot->commit=redata_unsaved_commit; |
| 61 |
+ slot->userptr=unsaved; |
|
| 61 | 62 |
return(0); |
| 62 | 63 |
} |
| 63 | 64 |
|
| ... | ... |
@@ -205,6 +206,9 @@ redata_unsaved_trunc(redata_t *redata, redata_plugin_t *slot, char *oldfilename, |
| 205 | 206 |
int |
| 206 | 207 |
redata_unsaved_truncload(redata_t *redata, redata_plugin_t *slot, char *filename) |
| 207 | 208 |
{
|
| 209 |
+#if 1 |
|
| 210 |
+fprintf(stderr,"UNSAVED: TRUNCLOAD (ignore)\n"); |
|
| 211 |
+#endif |
|
| 208 | 212 |
return(redata_unsaved_trunc(redata, slot, NULL, filename)); |
| 209 | 213 |
} |
| 210 | 214 |
|
| ... | ... |
@@ -224,16 +228,28 @@ redata_unsaved_loadappend(redata_t *redata, redata_plugin_t *slot, char *filenam |
| 224 | 228 |
char endcode; |
| 225 | 229 |
int flag_multipart; |
| 226 | 230 |
unsaved_t *unsaved=(unsaved_t *) ((slot!=NULL)?(slot->userptr):NULL); |
| 231 |
+#if 1 |
|
| 232 |
+fprintf(stderr,"UNSAVED: LOADAPPEND (recover)\n"); |
|
| 233 |
+#endif |
|
| 227 | 234 |
if(redata==NULL || slot==NULL || unsaved==NULL || filename==NULL) |
| 228 | 235 |
return(-1); |
| 236 |
+#if 1 |
|
| 237 |
+fprintf(stderr,"UNSAVED: LOADAPPEND pre-check\n"); |
|
| 238 |
+#endif |
|
| 229 | 239 |
if((fd=redata_unsaved_check_gen(redata,slot,filename))==-1) |
| 230 | 240 |
return(-1); /* check failed */ |
| 241 |
+#if 1 |
|
| 242 |
+fprintf(stderr,"UNSAVED: LOADAPPEND post-check\n"); |
|
| 243 |
+#endif |
|
| 231 | 244 |
if(fstat(fd,&statbuf)!=0 || !S_ISREG(statbuf.st_mode)) {
|
| 232 | 245 |
close(fd),fd=-1; |
| 233 | 246 |
return(-1); /* couldn't query size or not regular file */ |
| 234 | 247 |
} |
| 235 | 248 |
redata_hash(redata,unsaved->initialhash); |
| 236 |
- headerhashsize=(sizeof(header)-1)+1+128+1; |
|
| 249 |
+ headerhashsize=(sizeof(header)-1)+128+1; |
|
| 250 |
+#if 1 |
|
| 251 |
+fprintf(stderr,"UNSAVED: LOADAPPEND headerhashsize: %li\n",headerhashsize); |
|
| 252 |
+#endif |
|
| 237 | 253 |
/* load unsaved to memory */ |
| 238 | 254 |
if(unsaved->sizebuf<(statbuf.st_size-headerhashsize)) {
|
| 239 | 255 |
if((newptr=realloc(unsaved->buf,(statbuf.st_size-headerhashsize)))==NULL) {
|
| ... | ... |
@@ -254,8 +270,21 @@ redata_unsaved_loadappend(redata_t *redata, redata_plugin_t *slot, char *filenam |
| 254 | 270 |
} |
| 255 | 271 |
close(fd),fd=-1; |
| 256 | 272 |
/* process unsaved data */ |
| 273 |
+ slot->active=0; |
|
| 257 | 274 |
endptr=unsaved->buf+unsaved->usedbuf; |
| 258 | 275 |
for(ptr=unsaved->buf;ptr<endptr;) {
|
| 276 |
+#ifdef DEBUG_PLUGIN_UNSAVED |
|
| 277 |
+{
|
|
| 278 |
+int m; |
|
| 279 |
+fprintf(stderr,"%05X: ",ptr-unsaved->buf); |
|
| 280 |
+for(m=0;m<16 && (ptr+m)<endptr;m++) |
|
| 281 |
+ fprintf(stderr,"%02X%s ",((unsigned char *)ptr)[m],(m==7)?" ":""); |
|
| 282 |
+fprintf(stderr," | "); |
|
| 283 |
+for(m=0;m<16 && (ptr+m)<endptr;m++) |
|
| 284 |
+ fprintf(stderr,"%c%s",((((unsigned char *)ptr)[m])<20)?'.':((((unsigned char *)ptr)[m])>126)?'.':((unsigned char *)ptr)[m],(m==7)?" ":""); |
|
| 285 |
+fprintf(stderr,"\n"); |
|
| 286 |
+} |
|
| 287 |
+#endif |
|
| 259 | 288 |
if((ptr=ptr_getchar(ptr,endptr,&actioncode))==NULL) |
| 260 | 289 |
return(-1); /* no space for action char */ |
| 261 | 290 |
/* multipart example: A10+$aj$%$% >> insert "aj$" into pos 10 */ |
| ... | ... |
@@ -322,7 +351,8 @@ redata_unsaved_loadappend(redata_t *redata, redata_plugin_t *slot, char *filenam |
| 322 | 351 |
return(-1); /* corrupted undobuf */ |
| 323 | 352 |
} |
| 324 | 353 |
} |
| 325 |
- return(-1); |
|
| 354 |
+ slot->active=1; |
|
| 355 |
+ return(0); |
|
| 326 | 356 |
} |
| 327 | 357 |
|
| 328 | 358 |
int |
| ... | ... |
@@ -337,7 +367,7 @@ redata_unsaved_add(redata_t *redata, redata_plugin_t *slot, undo_t *undo) |
| 337 | 367 |
undostack_t *stack; |
| 338 | 368 |
unsaved_t *unsaved=(unsaved_t *) ((slot!=NULL)?(slot->userptr):NULL); |
| 339 | 369 |
stack=redata_getstack(redata,undo); |
| 340 |
- if(redata==NULL || slot==NULL || unsaved==NULL || undo==NULL || stack==NULL) |
|
| 370 |
+ if(redata==NULL || slot==NULL || unsaved==NULL || undo==NULL || stack==NULL || slot->active==0) |
|
| 341 | 371 |
return(-1); /* sanity check failed */ |
| 342 | 372 |
/* syntax (see loadappend): A<pos><+?><sep><text><sep>[<+?><sep><text><sep>[...]] */ |
| 343 | 373 |
if(undo->type!='A' && undo->type!='D' && undo->type!='M') |
| ... | ... |
@@ -389,7 +419,8 @@ redata_unsaved_add(redata_t *redata, redata_plugin_t *slot, undo_t *undo) |
| 389 | 419 |
unsaved->sizebuf=newsize; |
| 390 | 420 |
} |
| 391 | 421 |
buf=unsaved->buf+unsaved->usedbuf; |
| 392 |
- } |
|
| 422 |
+ } else |
|
| 423 |
+ unsaved->usedbuf+=maxsize; |
|
| 393 | 424 |
} |
| 394 | 425 |
return(0); |
| 395 | 426 |
} |
| ... | ... |
@@ -407,7 +438,7 @@ redata_unsaved_unadd(redata_t *redata, redata_plugin_t *slot, undo_t *undo) |
| 407 | 438 |
undostack_t *stack; |
| 408 | 439 |
unsaved_t *unsaved=(unsaved_t *) ((slot!=NULL)?(slot->userptr):NULL); |
| 409 | 440 |
stack=redata_getstack(redata,undo); |
| 410 |
- if(redata==NULL || slot==NULL || unsaved==NULL || undo==NULL || stack==NULL) |
|
| 441 |
+ if(redata==NULL || slot==NULL || unsaved==NULL || undo==NULL || stack==NULL || slot->active==0) |
|
| 411 | 442 |
return(-1); /* sanity check failed */ |
| 412 | 443 |
/* syntax (see loadappend): A<pos><+?><sep><text><sep>[<+?><sep><text><sep>[...]] */ |
| 413 | 444 |
if(undo->type!='A' && undo->type!='D' && undo->type!='M') |
| ... | ... |
@@ -475,6 +506,9 @@ redata_unsaved_commit(redata_t *redata, redata_plugin_t *slot,char *filename) |
| 475 | 506 |
unsaved_t *unsaved=(unsaved_t *) ((slot!=NULL)?(slot->userptr):NULL); |
| 476 | 507 |
if(redata==NULL || slot==NULL || unsaved==NULL || unsaved->unsavedfd==-1) |
| 477 | 508 |
return(-1); |
| 509 |
+#if 1 |
|
| 510 |
+fprintf(stderr,"UNSAVED_COMMITTED\n"); |
|
| 511 |
+#endif |
|
| 478 | 512 |
for(nwritten=0;nwritten<unsaved->usedbuf;nwritten+=n) {
|
| 479 | 513 |
if((n=write(unsaved->unsavedfd,unsaved->buf+nwritten,unsaved->usedbuf-nwritten))<0) {
|
| 480 | 514 |
close(unsaved->unsavedfd),unsaved->unsavedfd=-1; |
| ... | ... |
@@ -488,30 +522,47 @@ redata_unsaved_commit(redata_t *redata, redata_plugin_t *slot,char *filename) |
| 488 | 522 |
} |
| 489 | 523 |
|
| 490 | 524 |
static int |
| 491 |
-redata_unsaved_loadquestion(redata_t *redata, redata_plugin_t *slot,char *filename, char **title, char **body, int *nopts, char **opts[]) |
|
| 525 |
+redata_unsaved_loadquestion(redata_t *redata, redata_plugin_t *slot,char *filename) |
|
| 492 | 526 |
{
|
| 493 | 527 |
static char mytitle[]={"Unsaved data from a previous session detected"};
|
| 494 | 528 |
static char mybody[]={"The file you're trying to load has some unsaved data from a previous session. I can recover the data. What do you want to do?"};
|
| 495 | 529 |
static char *myopts[]={"Recover unsaved data (safest option)","Don't use old unsaved data, delete old unsaved data (if you're sure what you're doing)"};
|
| 496 |
- if(redata==NULL || slot==NULL || filename==NULL || title==NULL || body==NULL || nopts==NULL || opts==NULL) |
|
| 530 |
+ static char mytitleshort[]={"Unsaved data found"};
|
|
| 531 |
+ static char mybodyshort[]={"Should try to recover the data?"};
|
|
| 532 |
+ static char *myoptsshort[]={"Recover","Ignore it"};
|
|
| 533 |
+ question_t *q; |
|
| 534 |
+ if(redata==NULL || slot==NULL || filename==NULL) |
|
| 497 | 535 |
return(-1); /* sanity check failed */ |
| 536 |
+ q=&(slot->question); |
|
| 537 |
+ q->active=0; |
|
| 498 | 538 |
if(redata_unsaved_check(redata,slot,filename)==-1) |
| 499 |
- return(-1); /* no unsaved data on disk */ |
|
| 500 |
- *title=mytitle; |
|
| 501 |
- *body=mybody; |
|
| 502 |
- *opts=myopts; |
|
| 503 |
- *nopts=2; |
|
| 539 |
+ return(0); /* no unsaved data on disk */ |
|
| 540 |
+ q->active=1; |
|
| 541 |
+ q->title=mytitle; |
|
| 542 |
+ q->titleshort=mytitleshort; |
|
| 543 |
+ q->body=mybody; |
|
| 544 |
+ q->bodyshort=mybodyshort; |
|
| 545 |
+ q->opts=myopts; |
|
| 546 |
+ q->optsshort=myoptsshort; |
|
| 547 |
+ q->nopts=2; |
|
| 548 |
+ q->defaultoption=1; |
|
| 549 |
+ q->selectedoption=-1; |
|
| 504 | 550 |
return(0); |
| 505 | 551 |
} |
| 506 | 552 |
|
| 507 | 553 |
static int |
| 508 |
-redata_unsaved_postload(redata_t *redata, redata_plugin_t *slot,char *filename,int questionreply) |
|
| 554 |
+redata_unsaved_postload(redata_t *redata, redata_plugin_t *slot,char *filename) |
|
| 509 | 555 |
{
|
| 556 |
+#warning XXX TODO: add errordesc parameter, so that the user can see what happened. |
|
| 557 |
+ int selectedoption; |
|
| 558 |
+ if(redata==NULL || slot==NULL || filename==NULL) |
|
| 559 |
+ return(-1); /* sanity check failed */ |
|
| 510 | 560 |
/* questionreply is from loadquestion, specifically the selected element in the array "opts" */ |
| 511 |
- if(questionreply==0) /* recover */ |
|
| 512 |
- return(redata_unsaved_loadappend(redata, slot, filename)); |
|
| 513 |
- else if(questionreply==1 || questionreply==-1) /* delete unsaved data */ |
|
| 561 |
+ selectedoption=slot->question.selectedoption; |
|
| 562 |
+ if(slot->question.active==0 || selectedoption==1 || selectedoption==-1) /* delete unsaved data */ |
|
| 514 | 563 |
return(redata_unsaved_truncload(redata, slot, filename)); |
| 564 |
+ else if(selectedoption==0) /* recover */ |
|
| 565 |
+ return(redata_unsaved_loadappend(redata, slot, filename)); |
|
| 515 | 566 |
return(-1); |
| 516 | 567 |
} |
| 517 | 568 |
|
| ... | ... |
@@ -28,6 +28,8 @@ |
| 28 | 28 |
|
| 29 | 29 |
|
| 30 | 30 |
|
| 31 |
+static int redata_unsaved_loadquestion(redata_t *redata, redata_plugin_t *slot,char *filename, char **title, char **body, int *nopts, char **opts[]); |
|
| 32 |
+static int redata_unsaved_postload(redata_t *redata, redata_plugin_t *slot,char *filename,int questionreply); |
|
| 31 | 33 |
static int redata_unsaved_check_gen(redata_t *redata, redata_plugin_t *slot, char *filename); |
| 32 | 34 |
static char *unsaved_genname(char *filename, char *buf, int bufsize); |
| 33 | 35 |
static char *ptr_getlong(char *ptr,char *endptr,long *data); |
| ... | ... |
@@ -46,15 +48,16 @@ redata_unsaved_register(redata_t *redata, redata_plugin_t *slot) |
| 46 | 48 |
memset(unsaved,0,sizeof(unsaved_t)); |
| 47 | 49 |
unsaved->unsavedfd=-1; |
| 48 | 50 |
unsaved->sizebuf=unsaved->usedbuf=0; |
| 51 |
+ strncpy(slot->name,"unsaved",sizeof(slot->name)); |
|
| 52 |
+ slot->name[sizeof(slot->name)-1]='\0'; |
|
| 49 | 53 |
slot->unregister=redata_unsaved_unregister; |
| 50 |
- slot->checkload=redata_unsaved_check; |
|
| 54 |
+ slot->loadquestion=redata_unsaved_loadquestion; |
|
| 51 | 55 |
slot->wipe=redata_unsaved_wipe; |
| 52 |
- slot->postload=redata_unsaved_loadappend; |
|
| 53 |
- slot->truncload=redata_unsaved_truncload; |
|
| 56 |
+ slot->postload=redata_unsaved_postload; |
|
| 54 | 57 |
slot->postsave=redata_unsaved_trunc; |
| 55 | 58 |
slot->add=redata_unsaved_add; |
| 56 | 59 |
slot->unadd=redata_unsaved_unadd; |
| 57 |
- slot->flags=PLUGIN_CHECKUSERCONFIRM; |
|
| 60 |
+ slot->commit=redata_unsaved_commit; |
|
| 58 | 61 |
return(0); |
| 59 | 62 |
} |
| 60 | 63 |
|
| ... | ... |
@@ -484,6 +487,35 @@ redata_unsaved_commit(redata_t *redata, redata_plugin_t *slot,char *filename) |
| 484 | 487 |
return(0); |
| 485 | 488 |
} |
| 486 | 489 |
|
| 490 |
+static int |
|
| 491 |
+redata_unsaved_loadquestion(redata_t *redata, redata_plugin_t *slot,char *filename, char **title, char **body, int *nopts, char **opts[]) |
|
| 492 |
+{
|
|
| 493 |
+ static char mytitle[]={"Unsaved data from a previous session detected"};
|
|
| 494 |
+ static char mybody[]={"The file you're trying to load has some unsaved data from a previous session. I can recover the data. What do you want to do?"};
|
|
| 495 |
+ static char *myopts[]={"Recover unsaved data (safest option)","Don't use old unsaved data, delete old unsaved data (if you're sure what you're doing)"};
|
|
| 496 |
+ if(redata==NULL || slot==NULL || filename==NULL || title==NULL || body==NULL || nopts==NULL || opts==NULL) |
|
| 497 |
+ return(-1); /* sanity check failed */ |
|
| 498 |
+ if(redata_unsaved_check(redata,slot,filename)==-1) |
|
| 499 |
+ return(-1); /* no unsaved data on disk */ |
|
| 500 |
+ *title=mytitle; |
|
| 501 |
+ *body=mybody; |
|
| 502 |
+ *opts=myopts; |
|
| 503 |
+ *nopts=2; |
|
| 504 |
+ return(0); |
|
| 505 |
+} |
|
| 506 |
+ |
|
| 507 |
+static int |
|
| 508 |
+redata_unsaved_postload(redata_t *redata, redata_plugin_t *slot,char *filename,int questionreply) |
|
| 509 |
+{
|
|
| 510 |
+ /* questionreply is from loadquestion, specifically the selected element in the array "opts" */ |
|
| 511 |
+ if(questionreply==0) /* recover */ |
|
| 512 |
+ return(redata_unsaved_loadappend(redata, slot, filename)); |
|
| 513 |
+ else if(questionreply==1 || questionreply==-1) /* delete unsaved data */ |
|
| 514 |
+ return(redata_unsaved_truncload(redata, slot, filename)); |
|
| 515 |
+ return(-1); |
|
| 516 |
+} |
|
| 517 |
+ |
|
| 518 |
+ |
|
| 487 | 519 |
static char * |
| 488 | 520 |
unsaved_genname(char *filename, char *buf, int bufsize) |
| 489 | 521 |
{
|
| 1 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,565 @@ |
| 1 |
+/* |
|
| 2 |
+ * re_plugin_unsaved->c |
|
| 3 |
+ * |
|
| 4 |
+ * A programmers editor |
|
| 5 |
+ * |
|
| 6 |
+ * re_data plugin to support the unsaved changes file. |
|
| 7 |
+ * (for recovery when the program closes unexpectedly) |
|
| 8 |
+ * |
|
| 9 |
+ * Author: Dario Rodriguez dario@softhome.net |
|
| 10 |
+ * This program is licensed under the terms of GNU GPL v2.1+ |
|
| 11 |
+ */ |
|
| 12 |
+ |
|
| 13 |
+#include <stdio.h> |
|
| 14 |
+#include <stdlib.h> |
|
| 15 |
+#include <unistd.h> |
|
| 16 |
+#include <string.h> |
|
| 17 |
+#include <fcntl.h> |
|
| 18 |
+#include <sys/types.h> |
|
| 19 |
+#include <sys/stat.h> |
|
| 20 |
+ |
|
| 21 |
+ |
|
| 22 |
+#include "re_plugin_unsaved.h" |
|
| 23 |
+ |
|
| 24 |
+#define UNSAVEDPREFIX "." |
|
| 25 |
+#define UNSAVEDPOSTFIX ".reu" |
|
| 26 |
+#define UNSAVEDHEADER "reunsaved00," |
|
| 27 |
+#define UNSAVEDGROWSIZE (256*1024) |
|
| 28 |
+ |
|
| 29 |
+ |
|
| 30 |
+ |
|
| 31 |
+static int redata_unsaved_check_gen(redata_t *redata, redata_plugin_t *slot, char *filename); |
|
| 32 |
+static char *unsaved_genname(char *filename, char *buf, int bufsize); |
|
| 33 |
+static char *ptr_getlong(char *ptr,char *endptr,long *data); |
|
| 34 |
+static char *ptr_getchar(char *ptr,char *endptr,char *data); |
|
| 35 |
+static char *ptr_searchendchar(char *ptr, char *endptr, char endchar, char **endcharpos); |
|
| 36 |
+static char sep_select(char *buf, int bufsize, char **pos); |
|
| 37 |
+ |
|
| 38 |
+int |
|
| 39 |
+redata_unsaved_register(redata_t *redata, redata_plugin_t *slot) |
|
| 40 |
+{
|
|
| 41 |
+ unsaved_t *unsaved; |
|
| 42 |
+ if(redata==NULL || slot==NULL) |
|
| 43 |
+ return(-1); |
|
| 44 |
+ if((unsaved=malloc(sizeof(unsaved_t)))==NULL) |
|
| 45 |
+ return(-1); |
|
| 46 |
+ memset(unsaved,0,sizeof(unsaved_t)); |
|
| 47 |
+ unsaved->unsavedfd=-1; |
|
| 48 |
+ unsaved->sizebuf=unsaved->usedbuf=0; |
|
| 49 |
+ slot->unregister=redata_unsaved_unregister; |
|
| 50 |
+ slot->checkload=redata_unsaved_check; |
|
| 51 |
+ slot->wipe=redata_unsaved_wipe; |
|
| 52 |
+ slot->postload=redata_unsaved_loadappend; |
|
| 53 |
+ slot->truncload=redata_unsaved_truncload; |
|
| 54 |
+ slot->postsave=redata_unsaved_trunc; |
|
| 55 |
+ slot->add=redata_unsaved_add; |
|
| 56 |
+ slot->unadd=redata_unsaved_unadd; |
|
| 57 |
+ slot->flags=PLUGIN_CHECKUSERCONFIRM; |
|
| 58 |
+ return(0); |
|
| 59 |
+} |
|
| 60 |
+ |
|
| 61 |
+int |
|
| 62 |
+redata_unsaved_unregister(redata_t *redata, redata_plugin_t *slot, char *filename) |
|
| 63 |
+{
|
|
| 64 |
+ char unsname[PATH_MAX]; |
|
| 65 |
+ unsaved_t *unsaved=(unsaved_t *) ((slot!=NULL)?(slot->userptr):NULL); |
|
| 66 |
+ if(redata==NULL || slot==NULL || unsaved==NULL) |
|
| 67 |
+ return(-1); |
|
| 68 |
+ if(unsaved->buf!=NULL) |
|
| 69 |
+ free(unsaved->buf),unsaved->buf=NULL; |
|
| 70 |
+ unsaved->sizebuf=unsaved->usedbuf=0; |
|
| 71 |
+ if(unsaved->unsavedfd!=-1) {
|
|
| 72 |
+ close(unsaved->unsavedfd),unsaved->unsavedfd=-1; |
|
| 73 |
+ if(filename!=NULL && unsaved_genname(filename,unsname,sizeof(unsname))!=NULL) |
|
| 74 |
+ unlink(unsname); |
|
| 75 |
+ } |
|
| 76 |
+ return(0); |
|
| 77 |
+} |
|
| 78 |
+ |
|
| 79 |
+ |
|
| 80 |
+int |
|
| 81 |
+redata_unsaved_exists(redata_t *redata, redata_plugin_t *slot, char *filename) |
|
| 82 |
+{
|
|
| 83 |
+ char unsname[PATH_MAX+1]; |
|
| 84 |
+ int fd; |
|
| 85 |
+ unsaved_t *unsaved=(unsaved_t *) ((slot!=NULL)?(slot->userptr):NULL); |
|
| 86 |
+ if(redata==NULL || slot==NULL || unsaved==NULL || filename==NULL || filename[0]=='\0') |
|
| 87 |
+ return(-1); /* sanity check failed */ |
|
| 88 |
+ if((unsaved_genname(filename,unsname,sizeof(unsname)))==NULL) |
|
| 89 |
+ return(-1); /* malformed filename */ |
|
| 90 |
+ if((fd=open(unsname,O_RDONLY))==-1) |
|
| 91 |
+ return(-1); |
|
| 92 |
+ close(fd),fd=-1; |
|
| 93 |
+ return(0); |
|
| 94 |
+} |
|
| 95 |
+ |
|
| 96 |
+int |
|
| 97 |
+redata_unsaved_wipe(redata_t *redata, redata_plugin_t *slot, char *filename) |
|
| 98 |
+{
|
|
| 99 |
+ char unsname[PATH_MAX]; |
|
| 100 |
+ unsaved_t *unsaved=(unsaved_t *) ((slot!=NULL)?(slot->userptr):NULL); |
|
| 101 |
+ if(redata==NULL || slot==NULL || unsaved==NULL || filename==NULL || filename[0]=='\0') |
|
| 102 |
+ return(-1); |
|
| 103 |
+ if(unsaved->unsavedfd!=-1) {
|
|
| 104 |
+ close(unsaved->unsavedfd),unsaved->unsavedfd=-1; |
|
| 105 |
+ if(unsaved_genname(filename,unsname,sizeof(unsname))!=NULL) |
|
| 106 |
+ unlink(unsname); |
|
| 107 |
+ } |
|
| 108 |
+ unsaved->usedbuf=0; |
|
| 109 |
+ return(0); |
|
| 110 |
+} |
|
| 111 |
+ |
|
| 112 |
+static int |
|
| 113 |
+redata_unsaved_check_gen(redata_t *redata, redata_plugin_t *slot, char *filename) |
|
| 114 |
+{
|
|
| 115 |
+ char unsname[PATH_MAX+1]; |
|
| 116 |
+ int fd,nread; |
|
| 117 |
+ static char header[]={UNSAVEDHEADER};
|
|
| 118 |
+ char filehash[129],undohash[129],buf[16]; |
|
| 119 |
+ char fileheader[]={UNSAVEDHEADER};
|
|
| 120 |
+ unsaved_t *unsaved=(unsaved_t *) ((slot!=NULL)?(slot->userptr):NULL); |
|
| 121 |
+ if(redata==NULL || slot==NULL || unsaved==NULL || filename==NULL || filename[0]=='\0') |
|
| 122 |
+ return(-1); /* sanity check failed */ |
|
| 123 |
+ if((unsaved_genname(filename,unsname,sizeof(unsname)))==NULL) |
|
| 124 |
+ return(-1); /* malformed filename */ |
|
| 125 |
+ if(redata_filehash(redata,filename,filehash)!=0) |
|
| 126 |
+ return(-1); |
|
| 127 |
+ if((fd=open(unsname,O_RDONLY))==-1) |
|
| 128 |
+ return(-1); |
|
| 129 |
+ memset(fileheader,0,sizeof(fileheader)); |
|
| 130 |
+ if((nread=read(fd,fileheader,sizeof(fileheader)-1))==-1 |
|
| 131 |
+ || nread!=(sizeof(fileheader)-1) || memcmp(fileheader,header,sizeof(fileheader))!=0) {
|
|
| 132 |
+ close(fd),fd=-1; |
|
| 133 |
+ return(-1); /* corrupted header */ |
|
| 134 |
+ } |
|
| 135 |
+ if((nread=read(fd,undohash,128))==-1 || nread!=128 || memcmp(undohash,filehash,128)!=0) {
|
|
| 136 |
+ close(fd),fd=-1; |
|
| 137 |
+ return(-1); /* wrong hash */ |
|
| 138 |
+ } |
|
| 139 |
+ if((nread=read(fd,buf,1))==-1 || nread!=1 || *buf!=',') {
|
|
| 140 |
+ close(fd),fd=-1; |
|
| 141 |
+ return(-1); /* wrong hash separator */ |
|
| 142 |
+ } |
|
| 143 |
+ return(fd); |
|
| 144 |
+} |
|
| 145 |
+ |
|
| 146 |
+int |
|
| 147 |
+redata_unsaved_check(redata_t *redata, redata_plugin_t *slot, char *filename) |
|
| 148 |
+{
|
|
| 149 |
+ int fd; |
|
| 150 |
+ if((fd=redata_unsaved_check_gen(redata,slot,filename))==-1) |
|
| 151 |
+ return(-1); /* check failed */ |
|
| 152 |
+ close(fd),fd=-1; |
|
| 153 |
+ return(0); |
|
| 154 |
+} |
|
| 155 |
+ |
|
| 156 |
+ |
|
| 157 |
+int |
|
| 158 |
+redata_unsaved_unlink(redata_t *redata, redata_plugin_t *slot, char *filename) |
|
| 159 |
+{
|
|
| 160 |
+ char unsname[PATH_MAX+1]; |
|
| 161 |
+ unsaved_t *unsaved=(unsaved_t *) ((slot!=NULL)?(slot->userptr):NULL); |
|
| 162 |
+ if(redata==NULL || slot==NULL || unsaved==NULL || filename==NULL || filename[0]=='\0') |
|
| 163 |
+ return(-1); /* sanity check failed */ |
|
| 164 |
+ if(redata_unsaved_exists(redata,slot,filename)==-1) |
|
| 165 |
+ return(0); /* file not found, nothing to unlink */ |
|
| 166 |
+ if((unsaved_genname(filename,unsname,sizeof(unsname)))==NULL) |
|
| 167 |
+ return(-1); /* malformed filename */ |
|
| 168 |
+ unlink(unsname); |
|
| 169 |
+ return(0); |
|
| 170 |
+} |
|
| 171 |
+ |
|
| 172 |
+int |
|
| 173 |
+redata_unsaved_trunc(redata_t *redata, redata_plugin_t *slot, char *oldfilename, char *newfilename) |
|
| 174 |
+{
|
|
| 175 |
+ char unsname[PATH_MAX+1]; |
|
| 176 |
+ static char header[]={UNSAVEDHEADER};
|
|
| 177 |
+ int n; |
|
| 178 |
+ unsaved_t *unsaved=(unsaved_t *) ((slot!=NULL)?(slot->userptr):NULL); |
|
| 179 |
+ if(redata==NULL || slot==NULL || unsaved==NULL || newfilename==NULL || newfilename[0]=='\0') |
|
| 180 |
+ return(-1); /* sanity check failed */ |
|
| 181 |
+ if(oldfilename!=NULL) |
|
| 182 |
+ redata_unsaved_unlink(redata,slot,oldfilename); |
|
| 183 |
+ if((unsaved_genname(newfilename,unsname,sizeof(unsname)))==NULL) |
|
| 184 |
+ return(-1); /* malformed filename */ |
|
| 185 |
+ if(unsaved->unsavedfd!=-1) |
|
| 186 |
+ close(unsaved->unsavedfd),unsaved->unsavedfd=-1; |
|
| 187 |
+ redata_hash(redata,unsaved->initialhash); |
|
| 188 |
+ unsaved->usedbuf=0; |
|
| 189 |
+ if((unsaved->unsavedfd=open(unsname,O_WRONLY|O_TRUNC|O_CREAT,0644))==-1) |
|
| 190 |
+ return(-1); /* couldn't open file for writing */ |
|
| 191 |
+ if((n=write(unsaved->unsavedfd,header,sizeof(header)-1))==-1 |
|
| 192 |
+ || n!=(sizeof(header)-1) |
|
| 193 |
+ || (n=write(unsaved->unsavedfd,unsaved->initialhash,128))==-1 || n!=128 |
|
| 194 |
+ || (n=write(unsaved->unsavedfd,",",1))==-1 || n!=1) {
|
|
| 195 |
+ close(unsaved->unsavedfd),unsaved->unsavedfd=-1; |
|
| 196 |
+ unlink(unsname); |
|
| 197 |
+ return(-1); /* couldn't write header/hash */ |
|
| 198 |
+ } |
|
| 199 |
+ return(0); |
|
| 200 |
+} |
|
| 201 |
+ |
|
| 202 |
+int |
|
| 203 |
+redata_unsaved_truncload(redata_t *redata, redata_plugin_t *slot, char *filename) |
|
| 204 |
+{
|
|
| 205 |
+ return(redata_unsaved_trunc(redata, slot, NULL, filename)); |
|
| 206 |
+} |
|
| 207 |
+ |
|
| 208 |
+ |
|
| 209 |
+int |
|
| 210 |
+redata_unsaved_loadappend(redata_t *redata, redata_plugin_t *slot, char *filename) |
|
| 211 |
+{
|
|
| 212 |
+ int fd; |
|
| 213 |
+ struct stat statbuf; |
|
| 214 |
+ static char header[]={UNSAVEDHEADER};
|
|
| 215 |
+ long headerhashsize; |
|
| 216 |
+ char *newptr; |
|
| 217 |
+ long nread,lim; |
|
| 218 |
+ char *ptr,*endptr,*aux,*bufptr; |
|
| 219 |
+ char actioncode; |
|
| 220 |
+ long pos,pos2; |
|
| 221 |
+ char endcode; |
|
| 222 |
+ int flag_multipart; |
|
| 223 |
+ unsaved_t *unsaved=(unsaved_t *) ((slot!=NULL)?(slot->userptr):NULL); |
|
| 224 |
+ if(redata==NULL || slot==NULL || unsaved==NULL || filename==NULL) |
|
| 225 |
+ return(-1); |
|
| 226 |
+ if((fd=redata_unsaved_check_gen(redata,slot,filename))==-1) |
|
| 227 |
+ return(-1); /* check failed */ |
|
| 228 |
+ if(fstat(fd,&statbuf)!=0 || !S_ISREG(statbuf.st_mode)) {
|
|
| 229 |
+ close(fd),fd=-1; |
|
| 230 |
+ return(-1); /* couldn't query size or not regular file */ |
|
| 231 |
+ } |
|
| 232 |
+ redata_hash(redata,unsaved->initialhash); |
|
| 233 |
+ headerhashsize=(sizeof(header)-1)+1+128+1; |
|
| 234 |
+ /* load unsaved to memory */ |
|
| 235 |
+ if(unsaved->sizebuf<(statbuf.st_size-headerhashsize)) {
|
|
| 236 |
+ if((newptr=realloc(unsaved->buf,(statbuf.st_size-headerhashsize)))==NULL) {
|
|
| 237 |
+ close(fd),fd=-1; |
|
| 238 |
+ return(-1); /* insuf. mem. */ |
|
| 239 |
+ } |
|
| 240 |
+ unsaved->buf=newptr; |
|
| 241 |
+ unsaved->sizebuf=(statbuf.st_size-headerhashsize); |
|
| 242 |
+ } |
|
| 243 |
+ unsaved->usedbuf=0; |
|
| 244 |
+ lim=(statbuf.st_size-headerhashsize); |
|
| 245 |
+ for(nread=0;unsaved->usedbuf<lim;unsaved->usedbuf+=nread,nread=0) {
|
|
| 246 |
+ if((nread=read(fd,unsaved->buf+unsaved->usedbuf,lim-unsaved->usedbuf))<=0) {
|
|
| 247 |
+ unsaved->usedbuf=0; |
|
| 248 |
+ close(fd),fd=-1; |
|
| 249 |
+ return(-1); /* short read */ |
|
| 250 |
+ } |
|
| 251 |
+ } |
|
| 252 |
+ close(fd),fd=-1; |
|
| 253 |
+ /* process unsaved data */ |
|
| 254 |
+ endptr=unsaved->buf+unsaved->usedbuf; |
|
| 255 |
+ for(ptr=unsaved->buf;ptr<endptr;) {
|
|
| 256 |
+ if((ptr=ptr_getchar(ptr,endptr,&actioncode))==NULL) |
|
| 257 |
+ return(-1); /* no space for action char */ |
|
| 258 |
+ /* multipart example: A10+$aj$%$% >> insert "aj$" into pos 10 */ |
|
| 259 |
+ if(actioncode=='A') {
|
|
| 260 |
+ ptr=ptr_getlong(ptr,endptr,&pos); |
|
| 261 |
+ do {
|
|
| 262 |
+ flag_multipart=0; |
|
| 263 |
+ ptr=ptr_getchar(ptr,endptr,&endcode); |
|
| 264 |
+ if(ptr!=NULL && endcode=='+') {
|
|
| 265 |
+ flag_multipart=1; |
|
| 266 |
+ ptr=ptr_getchar(ptr,endptr,&endcode); |
|
| 267 |
+ } |
|
| 268 |
+ bufptr=ptr; |
|
| 269 |
+ ptr=ptr_searchendchar(ptr,endptr,endcode,&aux); |
|
| 270 |
+ if(ptr==NULL || pos<0 || pos>redata_getused(redata)) |
|
| 271 |
+ return(-1); /* malformed register */ |
|
| 272 |
+ redata_op_add(redata,pos,bufptr,aux-bufptr,NULL); |
|
| 273 |
+ pos+=aux-bufptr; |
|
| 274 |
+ } while(flag_multipart); |
|
| 275 |
+ } else if(actioncode=='D') {
|
|
| 276 |
+ ptr=ptr_getlong(ptr,endptr,&pos); |
|
| 277 |
+ do {
|
|
| 278 |
+ flag_multipart=0; |
|
| 279 |
+ ptr=ptr_getchar(ptr,endptr,&endcode); |
|
| 280 |
+ if(ptr!=NULL && endcode=='+') {
|
|
| 281 |
+ flag_multipart=1; |
|
| 282 |
+ ptr=ptr_getchar(ptr,endptr,&endcode); |
|
| 283 |
+ } |
|
| 284 |
+ bufptr=ptr; |
|
| 285 |
+ ptr=ptr_searchendchar(ptr,endptr,endcode,&aux); |
|
| 286 |
+ if(ptr==NULL || pos<0 || (pos+(aux-bufptr))>redata_getused(redata)) |
|
| 287 |
+ return(-1); /* malformed register */ |
|
| 288 |
+ if(redata_data_compare(redata,pos,bufptr,aux-bufptr)!=0) |
|
| 289 |
+ return(-1); /* corrupted data */ |
|
| 290 |
+ redata_op_del(redata,pos,aux-bufptr,NULL); |
|
| 291 |
+ } while(flag_multipart); |
|
| 292 |
+ } else if(actioncode=='M') {
|
|
| 293 |
+ ptr=ptr_getlong(ptr,endptr,&pos); |
|
| 294 |
+ ptr+=(ptr!=NULL && ptr<endptr)?1:0; |
|
| 295 |
+ ptr=ptr_getlong(ptr,endptr,&pos2); |
|
| 296 |
+ do {
|
|
| 297 |
+ flag_multipart=0; |
|
| 298 |
+ ptr=ptr_getchar(ptr,endptr,&endcode); |
|
| 299 |
+ if(ptr!=NULL && endcode=='+') {
|
|
| 300 |
+ flag_multipart=1; |
|
| 301 |
+ ptr=ptr_getchar(ptr,endptr,&endcode); |
|
| 302 |
+ } |
|
| 303 |
+ bufptr=ptr; |
|
| 304 |
+ ptr=ptr_searchendchar(ptr,endptr,endcode,&aux); |
|
| 305 |
+ if(ptr==NULL |
|
| 306 |
+ || pos<0 || (pos+(aux-bufptr))>redata_getused(redata) |
|
| 307 |
+ || pos2<0 || pos2>redata_getused(redata) |
|
| 308 |
+ || ((aux-bufptr)>0 && pos2>=pos && pos2<(pos+(aux-bufptr))) |
|
| 309 |
+ ) {
|
|
| 310 |
+ return(-1); /* malformed register */ |
|
| 311 |
+ } |
|
| 312 |
+ if(redata_data_compare(redata,pos,bufptr,aux-bufptr)!=0) |
|
| 313 |
+ return(-1); /* corrupted data */ |
|
| 314 |
+ redata_op_move(redata,pos,(aux-bufptr),pos2,NULL); |
|
| 315 |
+ pos=(pos<pos2)?pos:(pos+(aux-bufptr)); |
|
| 316 |
+ pos2=pos2+(aux-bufptr); |
|
| 317 |
+ } while(flag_multipart); |
|
| 318 |
+ } else {
|
|
| 319 |
+ return(-1); /* corrupted undobuf */ |
|
| 320 |
+ } |
|
| 321 |
+ } |
|
| 322 |
+ return(-1); |
|
| 323 |
+} |
|
| 324 |
+ |
|
| 325 |
+int |
|
| 326 |
+redata_unsaved_add(redata_t *redata, redata_plugin_t *slot, undo_t *undo) |
|
| 327 |
+{
|
|
| 328 |
+ char sep; |
|
| 329 |
+ char *sepend,*ptr,*endptr; |
|
| 330 |
+ char *buf; |
|
| 331 |
+ int k; |
|
| 332 |
+ int maxsize,newsize; |
|
| 333 |
+ char posbuf[128]; |
|
| 334 |
+ undostack_t *stack; |
|
| 335 |
+ unsaved_t *unsaved=(unsaved_t *) ((slot!=NULL)?(slot->userptr):NULL); |
|
| 336 |
+ stack=redata_getstack(redata,undo); |
|
| 337 |
+ if(redata==NULL || slot==NULL || unsaved==NULL || undo==NULL || stack==NULL) |
|
| 338 |
+ return(-1); /* sanity check failed */ |
|
| 339 |
+ /* syntax (see loadappend): A<pos><+?><sep><text><sep>[<+?><sep><text><sep>[...]] */ |
|
| 340 |
+ if(undo->type!='A' && undo->type!='D' && undo->type!='M') |
|
| 341 |
+ return(-1); /* unrecognized undo type */ |
|
| 342 |
+ for(k=0,maxsize=0,buf=NULL;k<2;k++,maxsize=0) {
|
|
| 343 |
+ ptr=stack->buf+undo->off; |
|
| 344 |
+ endptr=ptr+undo->len; |
|
| 345 |
+ if(k!=0) |
|
| 346 |
+ buf[maxsize]=undo->type; |
|
| 347 |
+ maxsize++; |
|
| 348 |
+ snprintf(posbuf,sizeof(posbuf),"%li",undo->posorig); |
|
| 349 |
+ posbuf[sizeof(posbuf)-1]='\0'; |
|
| 350 |
+ if(k!=0) |
|
| 351 |
+ strcpy(buf+maxsize,posbuf); |
|
| 352 |
+ maxsize+=strlen(posbuf); |
|
| 353 |
+ if(undo->type=='M') {
|
|
| 354 |
+ snprintf(posbuf,sizeof(posbuf),",%li",undo->posdest); |
|
| 355 |
+ posbuf[sizeof(posbuf)-1]='\0'; |
|
| 356 |
+ if(k!=0) |
|
| 357 |
+ strcpy(buf+maxsize,posbuf); |
|
| 358 |
+ maxsize+=strlen(posbuf); |
|
| 359 |
+ } |
|
| 360 |
+ while(ptr<endptr) {
|
|
| 361 |
+ sep=sep_select(ptr,endptr-ptr,&sepend); |
|
| 362 |
+ if(sepend!=endptr) {
|
|
| 363 |
+ if(k!=0) |
|
| 364 |
+ buf[maxsize]='+'; |
|
| 365 |
+ maxsize++; |
|
| 366 |
+ } |
|
| 367 |
+ if(k!=0) |
|
| 368 |
+ buf[maxsize]=sep; |
|
| 369 |
+ maxsize++; |
|
| 370 |
+ if(k!=0) |
|
| 371 |
+ memcpy(buf+maxsize,ptr,sepend-ptr); |
|
| 372 |
+ maxsize+=sepend-ptr; |
|
| 373 |
+ if(k!=0) |
|
| 374 |
+ buf[maxsize]=sep; |
|
| 375 |
+ maxsize++; |
|
| 376 |
+ ptr=sepend; |
|
| 377 |
+ } |
|
| 378 |
+ if(k==0) {
|
|
| 379 |
+ /* get mem */ |
|
| 380 |
+ if((unsaved->sizebuf-unsaved->sizebuf)<maxsize) {
|
|
| 381 |
+ newsize=(unsaved->sizebuf+maxsize+UNSAVEDGROWSIZE-1)/UNSAVEDGROWSIZE; |
|
| 382 |
+ newsize*=UNSAVEDGROWSIZE; |
|
| 383 |
+ if((buf=realloc(unsaved->buf,newsize))==NULL) |
|
| 384 |
+ return(-1); /* insuf. mem. */ |
|
| 385 |
+ unsaved->buf=buf; |
|
| 386 |
+ unsaved->sizebuf=newsize; |
|
| 387 |
+ } |
|
| 388 |
+ buf=unsaved->buf+unsaved->usedbuf; |
|
| 389 |
+ } |
|
| 390 |
+ } |
|
| 391 |
+ return(0); |
|
| 392 |
+} |
|
| 393 |
+ |
|
| 394 |
+int |
|
| 395 |
+redata_unsaved_unadd(redata_t *redata, redata_plugin_t *slot, undo_t *undo) |
|
| 396 |
+{
|
|
| 397 |
+ /* adds to unsaved the inverse operation to the one specified in the undo */ |
|
| 398 |
+ char sep; |
|
| 399 |
+ char *sepend,*ptr,*endptr; |
|
| 400 |
+ char *buf; |
|
| 401 |
+ int k; |
|
| 402 |
+ int maxsize,newsize; |
|
| 403 |
+ char posbuf[128]; |
|
| 404 |
+ undostack_t *stack; |
|
| 405 |
+ unsaved_t *unsaved=(unsaved_t *) ((slot!=NULL)?(slot->userptr):NULL); |
|
| 406 |
+ stack=redata_getstack(redata,undo); |
|
| 407 |
+ if(redata==NULL || slot==NULL || unsaved==NULL || undo==NULL || stack==NULL) |
|
| 408 |
+ return(-1); /* sanity check failed */ |
|
| 409 |
+ /* syntax (see loadappend): A<pos><+?><sep><text><sep>[<+?><sep><text><sep>[...]] */ |
|
| 410 |
+ if(undo->type!='A' && undo->type!='D' && undo->type!='M') |
|
| 411 |
+ return(-1); /* unrecognized undo type */ |
|
| 412 |
+ for(k=0,maxsize=0,buf=NULL;k<2;k++,maxsize=0) {
|
|
| 413 |
+ ptr=stack->buf+undo->off; |
|
| 414 |
+ endptr=ptr+undo->len; |
|
| 415 |
+ if(k!=0) |
|
| 416 |
+ buf[maxsize]=(undo->type=='A')?'D':(undo->type=='D')?'A':undo->type; |
|
| 417 |
+ maxsize++; |
|
| 418 |
+ if(undo->type=='A' || undo->type=='D') |
|
| 419 |
+ snprintf(posbuf,sizeof(posbuf),"%li",undo->posorig); |
|
| 420 |
+ else |
|
| 421 |
+ snprintf(posbuf,sizeof(posbuf),"%li",(undo->posorig<undo->posdest)?undo->posdest-undo->len:undo->posdest); |
|
| 422 |
+ posbuf[sizeof(posbuf)-1]='\0'; |
|
| 423 |
+ if(k!=0) |
|
| 424 |
+ strcpy(buf+maxsize,posbuf); |
|
| 425 |
+ maxsize+=strlen(posbuf); |
|
| 426 |
+ if(undo->type=='M') {
|
|
| 427 |
+ snprintf(posbuf,sizeof(posbuf),",%li",(undo->posorig<undo->posdest)?undo->posorig:undo->posorig+undo->len); |
|
| 428 |
+ posbuf[sizeof(posbuf)-1]='\0'; |
|
| 429 |
+ if(k!=0) |
|
| 430 |
+ strcpy(buf+maxsize,posbuf); |
|
| 431 |
+ maxsize+=strlen(posbuf); |
|
| 432 |
+ } |
|
| 433 |
+ while(ptr<endptr) {
|
|
| 434 |
+ sep=sep_select(ptr,endptr-ptr,&sepend); |
|
| 435 |
+ if(sepend!=endptr) {
|
|
| 436 |
+ if(k!=0) |
|
| 437 |
+ buf[maxsize]='+'; |
|
| 438 |
+ maxsize++; |
|
| 439 |
+ } |
|
| 440 |
+ if(k!=0) |
|
| 441 |
+ buf[maxsize]=sep; |
|
| 442 |
+ maxsize++; |
|
| 443 |
+ if(k!=0) |
|
| 444 |
+ memcpy(buf+maxsize,ptr,sepend-ptr); |
|
| 445 |
+ maxsize+=sepend-ptr; |
|
| 446 |
+ if(k!=0) |
|
| 447 |
+ buf[maxsize]=sep; |
|
| 448 |
+ maxsize++; |
|
| 449 |
+ ptr=sepend; |
|
| 450 |
+ } |
|
| 451 |
+ if(k==0) {
|
|
| 452 |
+ /* get mem */ |
|
| 453 |
+ if((unsaved->sizebuf-unsaved->sizebuf)<maxsize) {
|
|
| 454 |
+ newsize=(unsaved->sizebuf+maxsize+UNSAVEDGROWSIZE-1)/UNSAVEDGROWSIZE; |
|
| 455 |
+ newsize*=UNSAVEDGROWSIZE; |
|
| 456 |
+ if((buf=realloc(unsaved->buf,newsize))==NULL) |
|
| 457 |
+ return(-1); /* insuf. mem. */ |
|
| 458 |
+ unsaved->buf=buf; |
|
| 459 |
+ unsaved->sizebuf=newsize; |
|
| 460 |
+ } |
|
| 461 |
+ buf=unsaved->buf+unsaved->usedbuf; |
|
| 462 |
+ } |
|
| 463 |
+ } |
|
| 464 |
+ return(0); |
|
| 465 |
+} |
|
| 466 |
+ |
|
| 467 |
+int |
|
| 468 |
+redata_unsaved_commit(redata_t *redata, redata_plugin_t *slot,char *filename) |
|
| 469 |
+{
|
|
| 470 |
+ int n,nwritten; |
|
| 471 |
+ char unsname[PATH_MAX+1]; |
|
| 472 |
+ unsaved_t *unsaved=(unsaved_t *) ((slot!=NULL)?(slot->userptr):NULL); |
|
| 473 |
+ if(redata==NULL || slot==NULL || unsaved==NULL || unsaved->unsavedfd==-1) |
|
| 474 |
+ return(-1); |
|
| 475 |
+ for(nwritten=0;nwritten<unsaved->usedbuf;nwritten+=n) {
|
|
| 476 |
+ if((n=write(unsaved->unsavedfd,unsaved->buf+nwritten,unsaved->usedbuf-nwritten))<0) {
|
|
| 477 |
+ close(unsaved->unsavedfd),unsaved->unsavedfd=-1; |
|
| 478 |
+ if((unsaved_genname(filename,unsname,sizeof(unsname)))!=NULL) |
|
| 479 |
+ unlink(unsname); /* a corrupted unsaved is of no use, delete it */ |
|
| 480 |
+ return(-1); /* error writing */ |
|
| 481 |
+ } |
|
| 482 |
+ } |
|
| 483 |
+ unsaved->usedbuf=0; |
|
| 484 |
+ return(0); |
|
| 485 |
+} |
|
| 486 |
+ |
|
| 487 |
+static char * |
|
| 488 |
+unsaved_genname(char *filename, char *buf, int bufsize) |
|
| 489 |
+{
|
|
| 490 |
+ static char pre[]={UNSAVEDPREFIX};
|
|
| 491 |
+ static char post[]={UNSAVEDPOSTFIX};
|
|
| 492 |
+ return(redata_generic_genname(filename,pre,post,buf,bufsize)); |
|
| 493 |
+} |
|
| 494 |
+ |
|
| 495 |
+static char * |
|
| 496 |
+ptr_getlong(char *ptr,char *endptr,long *data) |
|
| 497 |
+{
|
|
| 498 |
+ long l,s; |
|
| 499 |
+ if(ptr==NULL || endptr==NULL || ptr>endptr) |
|
| 500 |
+ return(NULL); |
|
| 501 |
+ s=1; |
|
| 502 |
+ if(ptr<endptr && *ptr=='-') {
|
|
| 503 |
+ s=-1; |
|
| 504 |
+ ptr++; |
|
| 505 |
+ } |
|
| 506 |
+ for(l=0;ptr<endptr && *ptr>='0' && *ptr<='9';ptr++) {
|
|
| 507 |
+ l*=10; |
|
| 508 |
+ l+=(*ptr-'0'); |
|
| 509 |
+ } |
|
| 510 |
+ l*=s; |
|
| 511 |
+ if(data!=NULL) |
|
| 512 |
+ *data=l; |
|
| 513 |
+ return(ptr); |
|
| 514 |
+} |
|
| 515 |
+ |
|
| 516 |
+ |
|
| 517 |
+static char * |
|
| 518 |
+ptr_getchar(char *ptr,char *endptr,char *data) |
|
| 519 |
+{
|
|
| 520 |
+ if(ptr==NULL || endptr==NULL || ptr>endptr) |
|
| 521 |
+ return(NULL); |
|
| 522 |
+ if(data!=NULL) |
|
| 523 |
+ *data=*ptr; |
|
| 524 |
+ ptr++; |
|
| 525 |
+ return(ptr); |
|
| 526 |
+} |
|
| 527 |
+ |
|
| 528 |
+static char * |
|
| 529 |
+ptr_searchendchar(char *ptr, char *endptr, char endchar, char **endcharpos) |
|
| 530 |
+{
|
|
| 531 |
+ char *aux; |
|
| 532 |
+ if(ptr==NULL || endptr==NULL || ptr>endptr) |
|
| 533 |
+ return(NULL); |
|
| 534 |
+ if((aux=memchr(ptr,endchar,endptr-ptr))==NULL) |
|
| 535 |
+ return(NULL); |
|
| 536 |
+ if(endcharpos!=NULL) |
|
| 537 |
+ *endcharpos=aux; |
|
| 538 |
+ return(aux+1); |
|
| 539 |
+} |
|
| 540 |
+ |
|
| 541 |
+static char |
|
| 542 |
+sep_select(char *buf, int bufsize, char **pos) |
|
| 543 |
+{
|
|
| 544 |
+ static char seps[]={"$%@!|&/='\"^*;:,-_"};
|
|
| 545 |
+ char *ptr,*bestptr; |
|
| 546 |
+ int i,besti; |
|
| 547 |
+ bestptr=buf; |
|
| 548 |
+ if(pos!=NULL) |
|
| 549 |
+ *pos=NULL; |
|
| 550 |
+ for(i=0,besti=0;i<sizeof(seps);i++) {
|
|
| 551 |
+ if((ptr=memchr(buf,seps[i],bufsize))==NULL) {
|
|
| 552 |
+ if(pos!=NULL) |
|
| 553 |
+ *pos=buf+bufsize; |
|
| 554 |
+ return(seps[i]); |
|
| 555 |
+ } |
|
| 556 |
+ if(ptr>bestptr) {
|
|
| 557 |
+ besti=0; |
|
| 558 |
+ bestptr=ptr; |
|
| 559 |
+ } |
|
| 560 |
+ } |
|
| 561 |
+ if(pos!=NULL) |
|
| 562 |
+ *pos=bestptr; |
|
| 563 |
+ return(seps[besti]); |
|
| 564 |
+} |
|
| 565 |
+ |