URI:
       trows.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
       ---
       trows.c (16842B)
       ---
            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 <bio.h>
           11 #include <plumb.h>
           12 #include <libsec.h>
           13 #include "dat.h"
           14 #include "fns.h"
           15 
           16 static Rune Lcolhdr[] = {
           17         'N', 'e', 'w', 'c', 'o', 'l', ' ',
           18         'K', 'i', 'l', 'l', ' ',
           19         'P', 'u', 't', 'a', 'l', 'l', ' ',
           20         'D', 'u', 'm', 'p', ' ',
           21         'E', 'x', 'i', 't', ' ',
           22         0
           23 };
           24 
           25 void
           26 rowinit(Row *row, Rectangle r)
           27 {
           28         Rectangle r1;
           29         Text *t;
           30 
           31         draw(screen, r, display->white, nil, ZP);
           32         row->r = r;
           33         row->col = nil;
           34         row->ncol = 0;
           35         r1 = r;
           36         r1.max.y = r1.min.y + font->height;
           37         t = &row->tag;
           38         textinit(t, fileaddtext(nil, t), r1, rfget(FALSE, FALSE, FALSE, nil), tagcols);
           39         t->what = Rowtag;
           40         t->row = row;
           41         t->w = nil;
           42         t->col = nil;
           43         r1.min.y = r1.max.y;
           44         r1.max.y += Border;
           45         draw(screen, r1, display->black, nil, ZP);
           46         textinsert(t, 0, Lcolhdr, 29, TRUE);
           47         textsetselect(t, t->file->b.nc, t->file->b.nc);
           48 }
           49 
           50 Column*
           51 rowadd(Row *row, Column *c, int x)
           52 {
           53         Rectangle r, r1;
           54         Column *d;
           55         int i;
           56 
           57         d = nil;
           58         r = row->r;
           59         r.min.y = row->tag.fr.r.max.y+Border;
           60         if(x<r.min.x && row->ncol>0){        /*steal 40% of last column by default */
           61                 d = row->col[row->ncol-1];
           62                 x = d->r.min.x + 3*Dx(d->r)/5;
           63         }
           64         /* look for column we'll land on */
           65         for(i=0; i<row->ncol; i++){
           66                 d = row->col[i];
           67                 if(x < d->r.max.x)
           68                         break;
           69         }
           70         if(row->ncol > 0){
           71                 if(i < row->ncol)
           72                         i++;        /* new column will go after d */
           73                 r = d->r;
           74                 if(Dx(r) < 100)
           75                         return nil;
           76                 draw(screen, r, display->white, nil, ZP);
           77                 r1 = r;
           78                 r1.max.x = min(x-Border, r.max.x-50);
           79                 if(Dx(r1) < 50)
           80                         r1.max.x = r1.min.x+50;
           81                 colresize(d, r1);
           82                 r1.min.x = r1.max.x;
           83                 r1.max.x = r1.min.x+Border;
           84                 draw(screen, r1, display->black, nil, ZP);
           85                 r.min.x = r1.max.x;
           86         }
           87         if(c == nil){
           88                 c = emalloc(sizeof(Column));
           89                 colinit(c, r);
           90                 incref(&reffont.ref);
           91         }else
           92                 colresize(c, r);
           93         c->row = row;
           94         c->tag.row = row;
           95         row->col = realloc(row->col, (row->ncol+1)*sizeof(Column*));
           96         memmove(row->col+i+1, row->col+i, (row->ncol-i)*sizeof(Column*));
           97         row->col[i] = c;
           98         row->ncol++;
           99         clearmouse();
          100         return c;
          101 }
          102 
          103 void
          104 rowresize(Row *row, Rectangle r)
          105 {
          106         int i, deltax;
          107         Rectangle or, r1, r2;
          108         Column *c;
          109 
          110         or = row->r;
          111         deltax = r.min.x - or.min.x;
          112         row->r = r;
          113         r1 = r;
          114         r1.max.y = r1.min.y + font->height;
          115         textresize(&row->tag, r1, TRUE);
          116         r1.min.y = r1.max.y;
          117         r1.max.y += Border;
          118         draw(screen, r1, display->black, nil, ZP);
          119         r.min.y = r1.max.y;
          120         r1 = r;
          121         r1.max.x = r1.min.x;
          122         for(i=0; i<row->ncol; i++){
          123                 c = row->col[i];
          124                 r1.min.x = r1.max.x;
          125                 /* the test should not be necessary, but guarantee we don't lose a pixel */
          126                 if(i == row->ncol-1)
          127                         r1.max.x = r.max.x;
          128                 else
          129                         r1.max.x = (c->r.max.x-or.min.x)*Dx(r)/Dx(or) + deltax;
          130                 if(i > 0){
          131                         r2 = r1;
          132                         r2.max.x = r2.min.x+Border;
          133                         draw(screen, r2, display->black, nil, ZP);
          134                         r1.min.x = r2.max.x;
          135                 }
          136                 colresize(c, r1);
          137         }
          138 }
          139 
          140 void
          141 rowdragcol(Row *row, Column *c, int _0)
          142 {
          143         Rectangle r;
          144         int i, b, x;
          145         Point p, op;
          146         Column *d;
          147 
          148         USED(_0);
          149 
          150         clearmouse();
          151         setcursor2(mousectl, &boxcursor, &boxcursor2);
          152         b = mouse->buttons;
          153         op = mouse->xy;
          154         while(mouse->buttons == b)
          155                 readmouse(mousectl);
          156         setcursor(mousectl, nil);
          157         if(mouse->buttons){
          158                 while(mouse->buttons)
          159                         readmouse(mousectl);
          160                 return;
          161         }
          162 
          163         for(i=0; i<row->ncol; i++)
          164                 if(row->col[i] == c)
          165                         goto Found;
          166         error("can't find column");
          167 
          168   Found:
          169         p = mouse->xy;
          170         if((abs(p.x-op.x)<5 && abs(p.y-op.y)<5))
          171                 return;
          172         if((i>0 && p.x<row->col[i-1]->r.min.x) || (i<row->ncol-1 && p.x>c->r.max.x)){
          173                 /* shuffle */
          174                 x = c->r.min.x;
          175                 rowclose(row, c, FALSE);
          176                 if(rowadd(row, c, p.x) == nil)        /* whoops! */
          177                 if(rowadd(row, c, x) == nil)                /* WHOOPS! */
          178                 if(rowadd(row, c, -1)==nil){                /* shit! */
          179                         rowclose(row, c, TRUE);
          180                         return;
          181                 }
          182                 colmousebut(c);
          183                 return;
          184         }
          185         if(i == 0)
          186                 return;
          187         d = row->col[i-1];
          188         if(p.x < d->r.min.x+80+Scrollwid)
          189                 p.x = d->r.min.x+80+Scrollwid;
          190         if(p.x > c->r.max.x-80-Scrollwid)
          191                 p.x = c->r.max.x-80-Scrollwid;
          192         r = d->r;
          193         r.max.x = c->r.max.x;
          194         draw(screen, r, display->white, nil, ZP);
          195         r.max.x = p.x;
          196         colresize(d, r);
          197         r = c->r;
          198         r.min.x = p.x;
          199         r.max.x = r.min.x;
          200         r.max.x += Border;
          201         draw(screen, r, display->black, nil, ZP);
          202         r.min.x = r.max.x;
          203         r.max.x = c->r.max.x;
          204         colresize(c, r);
          205         colmousebut(c);
          206 }
          207 
          208 void
          209 rowclose(Row *row, Column *c, int dofree)
          210 {
          211         Rectangle r;
          212         int i;
          213 
          214         for(i=0; i<row->ncol; i++)
          215                 if(row->col[i] == c)
          216                         goto Found;
          217         error("can't find column");
          218   Found:
          219         r = c->r;
          220         if(dofree)
          221                 colcloseall(c);
          222         row->ncol--;
          223         memmove(row->col+i, row->col+i+1, (row->ncol-i)*sizeof(Column*));
          224         row->col = realloc(row->col, row->ncol*sizeof(Column*));
          225         if(row->ncol == 0){
          226                 draw(screen, r, display->white, nil, ZP);
          227                 return;
          228         }
          229         if(i == row->ncol){                /* extend last column right */
          230                 c = row->col[i-1];
          231                 r.min.x = c->r.min.x;
          232                 r.max.x = row->r.max.x;
          233         }else{                        /* extend next window left */
          234                 c = row->col[i];
          235                 r.max.x = c->r.max.x;
          236         }
          237         draw(screen, r, display->white, nil, ZP);
          238         colresize(c, r);
          239 }
          240 
          241 Column*
          242 rowwhichcol(Row *row, Point p)
          243 {
          244         int i;
          245         Column *c;
          246 
          247         for(i=0; i<row->ncol; i++){
          248                 c = row->col[i];
          249                 if(ptinrect(p, c->r))
          250                         return c;
          251         }
          252         return nil;
          253 }
          254 
          255 Text*
          256 rowwhich(Row *row, Point p)
          257 {
          258         Column *c;
          259 
          260         if(ptinrect(p, row->tag.all))
          261                 return &row->tag;
          262         c = rowwhichcol(row, p);
          263         if(c)
          264                 return colwhich(c, p);
          265         return nil;
          266 }
          267 
          268 Text*
          269 rowtype(Row *row, Rune r, Point p)
          270 {
          271         Window *w;
          272         Text *t;
          273 
          274         if(r == 0)
          275                 r = Runeerror;
          276 
          277         clearmouse();
          278         qlock(&row->lk);
          279         if(bartflag)
          280                 t = barttext;
          281         else
          282                 t = rowwhich(row, p);
          283         if(t!=nil && !(t->what==Tag && ptinrect(p, t->scrollr))){
          284                 w = t->w;
          285                 if(w == nil)
          286                         texttype(t, r);
          287                 else{
          288                         winlock(w, 'K');
          289                         wintype(w, t, r);
          290                         /* Expand tag if necessary */
          291                         if(t->what == Tag){
          292                                 t->w->tagsafe = FALSE;
          293                                 if(r == '\n')
          294                                         t->w->tagexpand = TRUE;
          295                                 winresize(w, w->r, TRUE, TRUE);
          296                         }
          297                         winunlock(w);
          298                 }
          299         }
          300         qunlock(&row->lk);
          301         return t;
          302 }
          303 
          304 int
          305 rowclean(Row *row)
          306 {
          307         int clean;
          308         int i;
          309 
          310         clean = TRUE;
          311         for(i=0; i<row->ncol; i++)
          312                 clean &= colclean(row->col[i]);
          313         return clean;
          314 }
          315 
          316 void
          317 rowdump(Row *row, char *file)
          318 {
          319         int i, j, fd, m, n, start, dumped;
          320         uint q0, q1;
          321         Biobuf *b;
          322         char *buf, *a, *fontname;
          323         Rune *r;
          324         Column *c;
          325         Window *w, *w1;
          326         Text *t;
          327 
          328         if(row->ncol == 0)
          329                 return;
          330         buf = fbufalloc();
          331         if(file == nil){
          332                 if(home == nil){
          333                         warning(nil, "can't find file for dump: $home not defined\n");
          334                         goto Rescue;
          335                 }
          336                 sprint(buf, "%s/acme.dump", home);
          337                 file = buf;
          338         }
          339         fd = create(file, OWRITE, 0600);
          340         if(fd < 0){
          341                 warning(nil, "can't open %s: %r\n", file);
          342                 goto Rescue;
          343         }
          344         b = emalloc(sizeof(Biobuf));
          345         Binit(b, fd, OWRITE);
          346         r = fbufalloc();
          347         Bprint(b, "%s\n", wdir);
          348         Bprint(b, "%s\n", fontnames[0]);
          349         Bprint(b, "%s\n", fontnames[1]);
          350         for(i=0; i<row->ncol; i++){
          351                 c = row->col[i];
          352                 Bprint(b, "%11.7f", 100.0*(c->r.min.x-row->r.min.x)/Dx(row->r));
          353                 if(i == row->ncol-1)
          354                         Bputc(b, '\n');
          355                 else
          356                         Bputc(b, ' ');
          357         }
          358         for(i=0; i<row->ncol; i++){
          359                 c = row->col[i];
          360                 for(j=0; j<c->nw; j++)
          361                         c->w[j]->body.file->dumpid = 0;
          362         }
          363         m = min(RBUFSIZE, row->tag.file->b.nc);
          364         bufread(&row->tag.file->b, 0, r, m);
          365         n = 0;
          366         while(n<m && r[n]!='\n')
          367                 n++;
          368         Bprint(b, "w %.*S\n", n, r);
          369         for(i=0; i<row->ncol; i++){
          370                 c = row->col[i];
          371                 m = min(RBUFSIZE, c->tag.file->b.nc);
          372                 bufread(&c->tag.file->b, 0, r, m);
          373                 n = 0;
          374                 while(n<m && r[n]!='\n')
          375                         n++;
          376                 Bprint(b, "c%11d %.*S\n", i, n, r);
          377         }
          378         for(i=0; i<row->ncol; i++){
          379                 c = row->col[i];
          380                 for(j=0; j<c->nw; j++){
          381                         w = c->w[j];
          382                         wincommit(w, &w->tag);
          383                         t = &w->body;
          384                         /* windows owned by others get special treatment */
          385                         if(w->nopen[QWevent] > 0)
          386                                 if(w->dumpstr == nil)
          387                                         continue;
          388                         /* zeroxes of external windows are tossed */
          389                         if(t->file->ntext > 1)
          390                                 for(n=0; n<t->file->ntext; n++){
          391                                         w1 = t->file->text[n]->w;
          392                                         if(w == w1)
          393                                                 continue;
          394                                         if(w1->nopen[QWevent])
          395                                                 goto Continue2;
          396                                 }
          397                         fontname = "";
          398                         if(t->reffont->f != font)
          399                                 fontname = t->reffont->f->name;
          400                         if(t->file->nname)
          401                                 a = runetobyte(t->file->name, t->file->nname);
          402                         else
          403                                 a = emalloc(1);
          404                         if(t->file->dumpid){
          405                                 dumped = FALSE;
          406                                 Bprint(b, "x%11d %11d %11d %11d %11.7f %s\n", i, t->file->dumpid,
          407                                         w->body.q0, w->body.q1,
          408                                         100.0*(w->r.min.y-c->r.min.y)/Dy(c->r),
          409                                         fontname);
          410                         }else if(w->dumpstr){
          411                                 dumped = FALSE;
          412                                 Bprint(b, "e%11d %11d %11d %11d %11.7f %s\n", i, t->file->dumpid,
          413                                         0, 0,
          414                                         100.0*(w->r.min.y-c->r.min.y)/Dy(c->r),
          415                                         fontname);
          416                         }else if((w->dirty==FALSE && access(a, 0)==0) || w->isdir){
          417                                 dumped = FALSE;
          418                                 t->file->dumpid = w->id;
          419                                 Bprint(b, "f%11d %11d %11d %11d %11.7f %s\n", i, w->id,
          420                                         w->body.q0, w->body.q1,
          421                                         100.0*(w->r.min.y-c->r.min.y)/Dy(c->r),
          422                                         fontname);
          423                         }else{
          424                                 dumped = TRUE;
          425                                 t->file->dumpid = w->id;
          426                                 Bprint(b, "F%11d %11d %11d %11d %11.7f %11d %s\n", i, j,
          427                                         w->body.q0, w->body.q1,
          428                                         100.0*(w->r.min.y-c->r.min.y)/Dy(c->r),
          429                                         w->body.file->b.nc, fontname);
          430                         }
          431                         free(a);
          432                         winctlprint(w, buf, 0);
          433                         Bwrite(b, buf, strlen(buf));
          434                         m = min(RBUFSIZE, w->tag.file->b.nc);
          435                         bufread(&w->tag.file->b, 0, r, m);
          436                         n = 0;
          437                         while(n<m) {
          438                                 start = n;
          439                                 while(n<m && r[n]!='\n')
          440                                         n++;
          441                                 Bprint(b, "%.*S", n-start, r+start);
          442                                 if(n<m) {
          443                                         Bputc(b, 0xff); // \n in tag becomes 0xff byte (invalid UTF)
          444                                         n++;
          445                                 }
          446                         }
          447                         Bprint(b, "\n");
          448                         if(dumped){
          449                                 q0 = 0;
          450                                 q1 = t->file->b.nc;
          451                                 while(q0 < q1){
          452                                         n = q1 - q0;
          453                                         if(n > BUFSIZE/UTFmax)
          454                                                 n = BUFSIZE/UTFmax;
          455                                         bufread(&t->file->b, q0, r, n);
          456                                         Bprint(b, "%.*S", n, r);
          457                                         q0 += n;
          458                                 }
          459                         }
          460                         if(w->dumpstr){
          461                                 if(w->dumpdir)
          462                                         Bprint(b, "%s\n%s\n", w->dumpdir, w->dumpstr);
          463                                 else
          464                                         Bprint(b, "\n%s\n", w->dumpstr);
          465                         }
          466     Continue2:;
          467                 }
          468         }
          469         Bterm(b);
          470         close(fd);
          471         free(b);
          472         fbuffree(r);
          473 
          474    Rescue:
          475         fbuffree(buf);
          476 }
          477 
          478 static
          479 char*
          480 rdline(Biobuf *b, int *linep)
          481 {
          482         char *l;
          483 
          484         l = Brdline(b, '\n');
          485         if(l)
          486                 (*linep)++;
          487         return l;
          488 }
          489 
          490 /*
          491  * Get font names from load file so we don't load fonts we won't use
          492  */
          493 void
          494 rowloadfonts(char *file)
          495 {
          496         int i;
          497         Biobuf *b;
          498         char *l;
          499 
          500         b = Bopen(file, OREAD);
          501         if(b == nil)
          502                 return;
          503         /* current directory */
          504         l = Brdline(b, '\n');
          505         if(l == nil)
          506                 goto Return;
          507         /* global fonts */
          508         for(i=0; i<2; i++){
          509                 l = Brdline(b, '\n');
          510                 if(l == nil)
          511                         goto Return;
          512                 l[Blinelen(b)-1] = 0;
          513                 if(*l && strcmp(l, fontnames[i])!=0){
          514                         free(fontnames[i]);
          515                         fontnames[i] = estrdup(l);
          516                 }
          517         }
          518     Return:
          519         Bterm(b);
          520 }
          521 
          522 int
          523 rowload(Row *row, char *file, int initing)
          524 {
          525         int i, j, line, y, nr, nfontr, n, ns, ndumped, dumpid, x, fd, done;
          526         double percent;
          527         Biobuf *b, *bout;
          528         char *buf, *l, *t, *fontname;
          529         Rune *r, *fontr;
          530         int rune;
          531         Column *c, *c1, *c2;
          532         uint q0, q1;
          533         Rectangle r1, r2;
          534         Window *w;
          535 
          536         buf = fbufalloc();
          537         if(file == nil){
          538                 if(home == nil){
          539                         warning(nil, "can't find file for load: $home not defined\n");
          540                         goto Rescue1;
          541                 }
          542                 sprint(buf, "%s/acme.dump", home);
          543                 file = buf;
          544         }
          545         b = Bopen(file, OREAD);
          546         if(b == nil){
          547                 warning(nil, "can't open load file %s: %r\n", file);
          548                 goto Rescue1;
          549         }
          550         /* current directory */
          551         line = 0;
          552         l = rdline(b, &line);
          553         if(l == nil)
          554                 goto Rescue2;
          555         l[Blinelen(b)-1] = 0;
          556         if(chdir(l) < 0){
          557                 warning(nil, "can't chdir %s\n", l);
          558                 goto Rescue2;
          559         }
          560         /* global fonts */
          561         for(i=0; i<2; i++){
          562                 l = rdline(b, &line);
          563                 if(l == nil)
          564                         goto Rescue2;
          565                 l[Blinelen(b)-1] = 0;
          566                 if(*l && strcmp(l, fontnames[i])!=0)
          567                         rfget(i, TRUE, i==0 && initing, l);
          568         }
          569         if(initing && row->ncol==0)
          570                 rowinit(row, screen->clipr);
          571         l = rdline(b, &line);
          572         if(l == nil)
          573                 goto Rescue2;
          574         j = Blinelen(b)/12;
          575         if(j<=0 || j>10)
          576                 goto Rescue2;
          577         for(i=0; i<j; i++){
          578                 percent = atof(l+i*12);
          579                 if(percent<0 || percent>=100)
          580                         goto Rescue2;
          581                 x = row->r.min.x+percent*Dx(row->r)/100+0.5;
          582                 if(i < row->ncol){
          583                         if(i == 0)
          584                                 continue;
          585                         c1 = row->col[i-1];
          586                         c2 = row->col[i];
          587                         r1 = c1->r;
          588                         r2 = c2->r;
          589                         if(x<Border)
          590                                 x = Border;
          591                         r1.max.x = x-Border;
          592                         r2.min.x = x;
          593                         if(Dx(r1) < 50 || Dx(r2) < 50)
          594                                 continue;
          595                         draw(screen, Rpt(r1.min, r2.max), display->white, nil, ZP);
          596                         colresize(c1, r1);
          597                         colresize(c2, r2);
          598                         r2.min.x = x-Border;
          599                         r2.max.x = x;
          600                         draw(screen, r2, display->black, nil, ZP);
          601                 }
          602                 if(i >= row->ncol)
          603                         rowadd(row, nil, x);
          604         }
          605         done = 0;
          606         while(!done){
          607                 l = rdline(b, &line);
          608                 if(l == nil)
          609                         break;
          610                 switch(l[0]){
          611                 case 'c':
          612                         l[Blinelen(b)-1] = 0;
          613                         i = atoi(l+1+0*12);
          614                         r = bytetorune(l+1*12, &nr);
          615                         ns = -1;
          616                         for(n=0; n<nr; n++){
          617                                 if(r[n] == '/')
          618                                         ns = n;
          619                                 if(r[n] == ' ')
          620                                         break;
          621                         }
          622                         textdelete(&row->col[i]->tag, 0, row->col[i]->tag.file->b.nc, TRUE);
          623                         textinsert(&row->col[i]->tag, 0, r+n+1, nr-(n+1), TRUE);
          624                         free(r);
          625                         break;
          626                 case 'w':
          627                         l[Blinelen(b)-1] = 0;
          628                         r = bytetorune(l+2, &nr);
          629                         ns = -1;
          630                         for(n=0; n<nr; n++){
          631                                 if(r[n] == '/')
          632                                         ns = n;
          633                                 if(r[n] == ' ')
          634                                         break;
          635                         }
          636                         textdelete(&row->tag, 0, row->tag.file->b.nc, TRUE);
          637                         textinsert(&row->tag, 0, r, nr, TRUE);
          638                         free(r);
          639                         break;
          640                 default:
          641                         done = 1;
          642                         break;
          643                 }
          644         }
          645         for(;;){
          646                 if(l == nil)
          647                         break;
          648                 dumpid = 0;
          649                 switch(l[0]){
          650                 case 'e':
          651                         if(Blinelen(b) < 1+5*12+1)
          652                                 goto Rescue2;
          653                         l = rdline(b, &line);        /* ctl line; ignored */
          654                         if(l == nil)
          655                                 goto Rescue2;
          656                         l = rdline(b, &line);        /* directory */
          657                         if(l == nil)
          658                                 goto Rescue2;
          659                         l[Blinelen(b)-1] = 0;
          660                         if(*l == '\0'){
          661                                 if(home == nil)
          662                                         r = bytetorune("./", &nr);
          663                                 else{
          664                                         t = emalloc(strlen(home)+1+1);
          665                                         sprint(t, "%s/", home);
          666                                         r = bytetorune(t, &nr);
          667                                         free(t);
          668                                 }
          669                         }else
          670                                 r = bytetorune(l, &nr);
          671                         l = rdline(b, &line);        /* command */
          672                         if(l == nil)
          673                                 goto Rescue2;
          674                         t = emalloc(Blinelen(b)+1);
          675                         memmove(t, l, Blinelen(b));
          676                         run(nil, t, r, nr, TRUE, nil, nil, FALSE);
          677                         /* r is freed in run() */
          678                         goto Nextline;
          679                 case 'f':
          680                         if(Blinelen(b) < 1+5*12+1)
          681                                 goto Rescue2;
          682                         fontname = l+1+5*12;
          683                         ndumped = -1;
          684                         break;
          685                 case 'F':
          686                         if(Blinelen(b) < 1+6*12+1)
          687                                 goto Rescue2;
          688                         fontname = l+1+6*12;
          689                         ndumped = atoi(l+1+5*12+1);
          690                         break;
          691                 case 'x':
          692                         if(Blinelen(b) < 1+5*12+1)
          693                                 goto Rescue2;
          694                         fontname = l+1+5*12;
          695                         ndumped = -1;
          696                         dumpid = atoi(l+1+1*12);
          697                         break;
          698                 default:
          699                         goto Rescue2;
          700                 }
          701                 l[Blinelen(b)-1] = 0;
          702                 fontr = nil;
          703                 nfontr = 0;
          704                 if(*fontname)
          705                         fontr = bytetorune(fontname, &nfontr);
          706                 i = atoi(l+1+0*12);
          707                 j = atoi(l+1+1*12);
          708                 q0 = atoi(l+1+2*12);
          709                 q1 = atoi(l+1+3*12);
          710                 percent = atof(l+1+4*12);
          711                 if(i<0 || i>10)
          712                         goto Rescue2;
          713                 if(i > row->ncol)
          714                         i = row->ncol;
          715                 c = row->col[i];
          716                 y = c->r.min.y+(percent*Dy(c->r))/100+0.5;
          717                 if(y<c->r.min.y || y>=c->r.max.y)
          718                         y = -1;
          719                 if(dumpid == 0)
          720                         w = coladd(c, nil, nil, y);
          721                 else
          722                         w = coladd(c, nil, lookid(dumpid, TRUE), y);
          723                 if(w == nil)
          724                         goto Nextline;
          725                 w->dumpid = j;
          726                 l = rdline(b, &line);
          727                 if(l == nil)
          728                         goto Rescue2;
          729                 l[Blinelen(b)-1] = 0;
          730                 /* convert 0xff in multiline tag back to \n */
          731                 for(i = 0; l[i] != 0; i++)
          732                         if((uchar)l[i] == 0xff)
          733                                 l[i] = '\n';
          734                 r = bytetorune(l+5*12, &nr);
          735                 ns = -1;
          736                 for(n=0; n<nr; n++){
          737                         if(r[n] == '/')
          738                                 ns = n;
          739                         if(r[n] == ' ')
          740                                 break;
          741                 }
          742                 if(dumpid == 0)
          743                         winsetname(w, r, n);
          744                 for(; n<nr; n++)
          745                         if(r[n] == '|')
          746                                 break;
          747                 wincleartag(w);
          748                 textinsert(&w->tag, w->tag.file->b.nc, r+n+1, nr-(n+1), TRUE);
          749                 if(ndumped >= 0){
          750                         /* simplest thing is to put it in a file and load that */
          751                         sprint(buf, "/tmp/d%d.%.4sacme", getpid(), getuser());
          752                         fd = create(buf, OWRITE, 0600);
          753                         if(fd < 0){
          754                                 free(r);
          755                                 warning(nil, "can't create temp file: %r\n");
          756                                 goto Rescue2;
          757                         }
          758                         bout = emalloc(sizeof(Biobuf));
          759                         Binit(bout, fd, OWRITE);
          760                         for(n=0; n<ndumped; n++){
          761                                 rune = Bgetrune(b);
          762                                 if(rune == '\n')
          763                                         line++;
          764                                 if(rune == Beof){
          765                                         free(r);
          766                                         Bterm(bout);
          767                                         free(bout);
          768                                         close(fd);
          769                                         remove(buf);
          770                                         goto Rescue2;
          771                                 }
          772                                 Bputrune(bout, rune);
          773                         }
          774                         Bterm(bout);
          775                         free(bout);
          776                         textload(&w->body, 0, buf, 1);
          777                         remove(buf);
          778                         close(fd);
          779                         w->body.file->mod = TRUE;
          780                         for(n=0; n<w->body.file->ntext; n++)
          781                                 w->body.file->text[n]->w->dirty = TRUE;
          782                         winsettag(w);
          783                 }else if(dumpid==0 && r[ns+1]!='+' && r[ns+1]!='-')
          784                         get(&w->body, nil, nil, FALSE, XXX, nil, 0);
          785                 if(fontr){
          786                         fontx(&w->body, nil, nil, 0, 0, fontr, nfontr);
          787                         free(fontr);
          788                 }
          789                 free(r);
          790                 if(q0>w->body.file->b.nc || q1>w->body.file->b.nc || q0>q1)
          791                         q0 = q1 = 0;
          792                 textshow(&w->body, q0, q1, 1);
          793                 w->maxlines = min(w->body.fr.nlines, max(w->maxlines, w->body.fr.maxlines));
          794                 xfidlog(w, "new");
          795 Nextline:
          796                 l = rdline(b, &line);
          797         }
          798         Bterm(b);
          799         fbuffree(buf);
          800         return TRUE;
          801 
          802 Rescue2:
          803         warning(nil, "bad load file %s:%d\n", file, line);
          804         Bterm(b);
          805 Rescue1:
          806         fbuffree(buf);
          807         return FALSE;
          808 }
          809 
          810 void
          811 allwindows(void (*f)(Window*, void*), void *arg)
          812 {
          813         int i, j;
          814         Column *c;
          815 
          816         for(i=0; i<row.ncol; i++){
          817                 c = row.col[i];
          818                 for(j=0; j<c->nw; j++)
          819                         (*f)(c->w[j], arg);
          820         }
          821 }