Browse code

Color themes and black mode, using control-shift-'+'/'-'/'0'.

Dario Rodriguez authored on 28/06/2023 20:21:08
Showing 1 changed files
... ...
@@ -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
 
Browse code

Update author email

Dario Rodriguez authored on 07/01/2022 17:57:32
Showing 1 changed files
... ...
@@ -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
 
Browse code

fix plugins not being called on undo

Dario Rodriguez authored on 01/12/2020 21:24:22
Showing 1 changed files
... ...
@@ -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
 {
Browse code

unsaved plugin: encolse in "#ifdef 0" some debug messages

Dario Rodriguez authored on 01/12/2020 17:57:42
Showing 1 changed files
... ...
@@ -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
Browse code

plugin_unsaved: fix bug that caused unnecessary unsaved buffer reallocs

Dario Rodriguez authored on 08/10/2020 21:40:39
Showing 1 changed files
... ...
@@ -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
                 }
Browse code

plugin_unsaved: on error commiting the unsaved data to disk, disable plugin

Dario Rodriguez authored on 08/10/2020 21:34:27
Showing 1 changed files
... ...
@@ -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
         }
Browse code

fix memory leak in redata_unsaved_unregister

Dario Rodriguez authored on 08/10/2020 17:18:25
Showing 1 changed files
... ...
@@ -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
 
Browse code

Implement TAB: insert spaces until next tabstop. Implement DEL: erase to the right.

Dario Rodriguez authored on 07/10/2020 21:08:18
Showing 1 changed files
... ...
@@ -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) {
Browse code

Support the unsaved data recovery plugin from redata. Rework the question interface.

Dario Rodriguez authored on 05/10/2020 21:42:19
Showing 1 changed files
... ...
@@ -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
 
Dario Rodriguez authored on 04/08/2020 09:19:53
Showing 1 changed files
... ...
@@ -1,5 +1,5 @@
1 1
 /*
2
- * re_plugin_unsaved->c
2
+ * re_plugin_unsaved.c
3 3
  *
4 4
  * A programmers editor
5 5
  *
Browse code

Reworked plugin API

Dario Rodriguez authored on 09/04/2019 14:28:44
Showing 1 changed files
... ...
@@ -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
 {
Browse code

Refactor unsaved into a plugin of redata

Dario Rodriguez authored on 04/04/2019 21:53:07
Showing 1 changed files
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
+