URI: 
       tfile.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tfile.c (5789B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 #include <draw.h>
            4 #include <thread.h>
            5 #include <cursor.h>
            6 #include <mouse.h>
            7 #include <keyboard.h>
            8 #include <frame.h>
            9 #include <fcall.h>
           10 #include <plumb.h>
           11 #include <libsec.h>
           12 #include "dat.h"
           13 #include "fns.h"
           14 
           15 /*
           16  * Structure of Undo list:
           17  *         The Undo structure follows any associated data, so the list
           18  *        can be read backwards: read the structure, then read whatever
           19  *        data is associated (insert string, file name) and precedes it.
           20  *        The structure includes the previous value of the modify bit
           21  *        and a sequence number; successive Undo structures with the
           22  *        same sequence number represent simultaneous changes.
           23  */
           24 
           25 typedef struct Undo Undo;
           26 struct Undo
           27 {
           28         short        type;                /* Delete, Insert, Filename */
           29         short        mod;        /* modify bit */
           30         uint                seq;                /* sequence number */
           31         uint                p0;                /* location of change (unused in f) */
           32         uint                n;                /* # runes in string or file name */
           33 };
           34 
           35 enum
           36 {
           37         Undosize = sizeof(Undo)/sizeof(Rune)
           38 };
           39 
           40 File*
           41 fileaddtext(File *f, Text *t)
           42 {
           43         if(f == nil){
           44                 f = emalloc(sizeof(File));
           45                 f->unread = TRUE;
           46         }
           47         f->text = realloc(f->text, (f->ntext+1)*sizeof(Text*));
           48         f->text[f->ntext++] = t;
           49         f->curtext = t;
           50         return f;
           51 }
           52 
           53 void
           54 filedeltext(File *f, Text *t)
           55 {
           56         int i;
           57 
           58         for(i=0; i<f->ntext; i++)
           59                 if(f->text[i] == t)
           60                         goto Found;
           61         error("can't find text in filedeltext");
           62 
           63     Found:
           64         f->ntext--;
           65         if(f->ntext == 0){
           66                 fileclose(f);
           67                 return;
           68         }
           69         memmove(f->text+i, f->text+i+1, (f->ntext-i)*sizeof(Text*));
           70         if(f->curtext == t)
           71                 f->curtext = f->text[0];
           72 }
           73 
           74 void
           75 fileinsert(File *f, uint p0, Rune *s, uint ns)
           76 {
           77         if(p0 > f->b.nc)
           78                 error("internal error: fileinsert");
           79         if(f->seq > 0)
           80                 fileuninsert(f, &f->delta, p0, ns);
           81         bufinsert(&f->b, p0, s, ns);
           82         if(ns)
           83                 f->mod = TRUE;
           84 }
           85 
           86 void
           87 fileuninsert(File *f, Buffer *delta, uint p0, uint ns)
           88 {
           89         Undo u;
           90 
           91         /* undo an insertion by deleting */
           92         u.type = Delete;
           93         u.mod = f->mod;
           94         u.seq = f->seq;
           95         u.p0 = p0;
           96         u.n = ns;
           97         bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
           98 }
           99 
          100 void
          101 filedelete(File *f, uint p0, uint p1)
          102 {
          103         if(!(p0<=p1 && p0<=f->b.nc && p1<=f->b.nc))
          104                 error("internal error: filedelete");
          105         if(f->seq > 0)
          106                 fileundelete(f, &f->delta, p0, p1);
          107         bufdelete(&f->b, p0, p1);
          108         if(p1 > p0)
          109                 f->mod = TRUE;
          110 }
          111 
          112 void
          113 fileundelete(File *f, Buffer *delta, uint p0, uint p1)
          114 {
          115         Undo u;
          116         Rune *buf;
          117         uint i, n;
          118 
          119         /* undo a deletion by inserting */
          120         u.type = Insert;
          121         u.mod = f->mod;
          122         u.seq = f->seq;
          123         u.p0 = p0;
          124         u.n = p1-p0;
          125         buf = fbufalloc();
          126         for(i=p0; i<p1; i+=n){
          127                 n = p1 - i;
          128                 if(n > RBUFSIZE)
          129                         n = RBUFSIZE;
          130                 bufread(&f->b, i, buf, n);
          131                 bufinsert(delta, delta->nc, buf, n);
          132         }
          133         fbuffree(buf);
          134         bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
          135 
          136 }
          137 
          138 void
          139 filesetname(File *f, Rune *name, int n)
          140 {
          141         if(f->seq > 0)
          142                 fileunsetname(f, &f->delta);
          143         free(f->name);
          144         f->name = runemalloc(n);
          145         runemove(f->name, name, n);
          146         f->nname = n;
          147         f->unread = TRUE;
          148 }
          149 
          150 void
          151 fileunsetname(File *f, Buffer *delta)
          152 {
          153         Undo u;
          154 
          155         /* undo a file name change by restoring old name */
          156         u.type = Filename;
          157         u.mod = f->mod;
          158         u.seq = f->seq;
          159         u.p0 = 0;        /* unused */
          160         u.n = f->nname;
          161         if(f->nname)
          162                 bufinsert(delta, delta->nc, f->name, f->nname);
          163         bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
          164 }
          165 
          166 uint
          167 fileload(File *f, uint p0, int fd, int *nulls, DigestState *h)
          168 {
          169         if(f->seq > 0)
          170                 error("undo in file.load unimplemented");
          171         return bufload(&f->b, p0, fd, nulls, h);
          172 }
          173 
          174 /* return sequence number of pending redo */
          175 uint
          176 fileredoseq(File *f)
          177 {
          178         Undo u;
          179         Buffer *delta;
          180 
          181         delta = &f->epsilon;
          182         if(delta->nc == 0)
          183                 return 0;
          184         bufread(delta, delta->nc-Undosize, (Rune*)&u, Undosize);
          185         return u.seq;
          186 }
          187 
          188 void
          189 fileundo(File *f, int isundo, uint *q0p, uint *q1p)
          190 {
          191         Undo u;
          192         Rune *buf;
          193         uint i, j, n, up;
          194         uint stop;
          195         Buffer *delta, *epsilon;
          196 
          197         if(isundo){
          198                 /* undo; reverse delta onto epsilon, seq decreases */
          199                 delta = &f->delta;
          200                 epsilon = &f->epsilon;
          201                 stop = f->seq;
          202         }else{
          203                 /* redo; reverse epsilon onto delta, seq increases */
          204                 delta = &f->epsilon;
          205                 epsilon = &f->delta;
          206                 stop = 0;        /* don't know yet */
          207         }
          208 
          209         buf = fbufalloc();
          210         while(delta->nc > 0){
          211                 up = delta->nc-Undosize;
          212                 bufread(delta, up, (Rune*)&u, Undosize);
          213                 if(isundo){
          214                         if(u.seq < stop){
          215                                 f->seq = u.seq;
          216                                 goto Return;
          217                         }
          218                 }else{
          219                         if(stop == 0)
          220                                 stop = u.seq;
          221                         if(u.seq > stop)
          222                                 goto Return;
          223                 }
          224                 switch(u.type){
          225                 default:
          226                         fprint(2, "undo: 0x%ux\n", u.type);
          227                         abort();
          228                         break;
          229 
          230                 case Delete:
          231                         f->seq = u.seq;
          232                         fileundelete(f, epsilon, u.p0, u.p0+u.n);
          233                         f->mod = u.mod;
          234                         bufdelete(&f->b, u.p0, u.p0+u.n);
          235                         for(j=0; j<f->ntext; j++)
          236                                 textdelete(f->text[j], u.p0, u.p0+u.n, FALSE);
          237                         *q0p = u.p0;
          238                         *q1p = u.p0;
          239                         break;
          240 
          241                 case Insert:
          242                         f->seq = u.seq;
          243                         fileuninsert(f, epsilon, u.p0, u.n);
          244                         f->mod = u.mod;
          245                         up -= u.n;
          246                         for(i=0; i<u.n; i+=n){
          247                                 n = u.n - i;
          248                                 if(n > RBUFSIZE)
          249                                         n = RBUFSIZE;
          250                                 bufread(delta, up+i, buf, n);
          251                                 bufinsert(&f->b, u.p0+i, buf, n);
          252                                 for(j=0; j<f->ntext; j++)
          253                                         textinsert(f->text[j], u.p0+i, buf, n, FALSE);
          254                         }
          255                         *q0p = u.p0;
          256                         *q1p = u.p0+u.n;
          257                         break;
          258 
          259                 case Filename:
          260                         f->seq = u.seq;
          261                         fileunsetname(f, epsilon);
          262                         f->mod = u.mod;
          263                         up -= u.n;
          264                         free(f->name);
          265                         if(u.n == 0)
          266                                 f->name = nil;
          267                         else
          268                                 f->name = runemalloc(u.n);
          269                         bufread(delta, up, f->name, u.n);
          270                         f->nname = u.n;
          271                         break;
          272                 }
          273                 bufdelete(delta, up, delta->nc);
          274         }
          275         if(isundo)
          276                 f->seq = 0;
          277     Return:
          278         fbuffree(buf);
          279 }
          280 
          281 void
          282 filereset(File *f)
          283 {
          284         bufreset(&f->delta);
          285         bufreset(&f->epsilon);
          286         f->seq = 0;
          287 }
          288 
          289 void
          290 fileclose(File *f)
          291 {
          292         free(f->name);
          293         f->nname = 0;
          294         f->name = nil;
          295         free(f->text);
          296         f->ntext = 0;
          297         f->text = nil;
          298         bufclose(&f->b);
          299         bufclose(&f->delta);
          300         bufclose(&f->epsilon);
          301         elogclose(f);
          302         free(f);
          303 }
          304 
          305 void
          306 filemark(File *f)
          307 {
          308         if(f->epsilon.nc)
          309                 bufdelete(&f->epsilon, 0, f->epsilon.nc);
          310         f->seq = seq;
          311 }