17dd7cddfSDavid du Colombier #include <u.h> 27dd7cddfSDavid du Colombier #include <libc.h> 37dd7cddfSDavid du Colombier #include <draw.h> 47dd7cddfSDavid du Colombier #include <thread.h> 57dd7cddfSDavid du Colombier #include <mouse.h> 67dd7cddfSDavid du Colombier #include <keyboard.h> 77dd7cddfSDavid du Colombier #include <frame.h> 87dd7cddfSDavid du Colombier #include <auth.h> 97dd7cddfSDavid du Colombier #include <fcall.h> 107dd7cddfSDavid du Colombier #include <plumb.h> 117dd7cddfSDavid du Colombier #include "dat.h" 127dd7cddfSDavid du Colombier #include "fns.h" 137dd7cddfSDavid du Colombier 147dd7cddfSDavid du Colombier static Point prevmouse; 157dd7cddfSDavid du Colombier static Window *mousew; 167dd7cddfSDavid du Colombier 177dd7cddfSDavid du Colombier void 187dd7cddfSDavid du Colombier cvttorunes(char *p, int n, Rune *r, int *nb, int *nr, int *nulls) 197dd7cddfSDavid du Colombier { 207dd7cddfSDavid du Colombier uchar *q; 217dd7cddfSDavid du Colombier Rune *s; 227dd7cddfSDavid du Colombier int j, w; 237dd7cddfSDavid du Colombier 247dd7cddfSDavid du Colombier /* 257dd7cddfSDavid du Colombier * Always guaranteed that n bytes may be interpreted 267dd7cddfSDavid du Colombier * without worrying about partial runes. This may mean 277dd7cddfSDavid du Colombier * reading up to UTFmax-1 more bytes than n; the caller 287dd7cddfSDavid du Colombier * knows this. If n is a firm limit, the caller should 297dd7cddfSDavid du Colombier * set p[n] = 0. 307dd7cddfSDavid du Colombier */ 317dd7cddfSDavid du Colombier q = (uchar*)p; 327dd7cddfSDavid du Colombier s = r; 337dd7cddfSDavid du Colombier for(j=0; j<n; j+=w){ 347dd7cddfSDavid du Colombier if(*q < Runeself){ 357dd7cddfSDavid du Colombier w = 1; 367dd7cddfSDavid du Colombier *s = *q++; 377dd7cddfSDavid du Colombier }else{ 387dd7cddfSDavid du Colombier w = chartorune(s, (char*)q); 397dd7cddfSDavid du Colombier q += w; 407dd7cddfSDavid du Colombier } 417dd7cddfSDavid du Colombier if(*s) 427dd7cddfSDavid du Colombier s++; 437dd7cddfSDavid du Colombier else if(nulls) 447dd7cddfSDavid du Colombier *nulls = TRUE; 457dd7cddfSDavid du Colombier } 467dd7cddfSDavid du Colombier *nb = (char*)q-p; 477dd7cddfSDavid du Colombier *nr = s-r; 487dd7cddfSDavid du Colombier } 497dd7cddfSDavid du Colombier 507dd7cddfSDavid du Colombier void 517dd7cddfSDavid du Colombier error(char *s) 527dd7cddfSDavid du Colombier { 537dd7cddfSDavid du Colombier fprint(2, "acme: %s: %r\n", s); 547dd7cddfSDavid du Colombier remove(acmeerrorfile); 557dd7cddfSDavid du Colombier notify(nil); 567dd7cddfSDavid du Colombier abort(); 577dd7cddfSDavid du Colombier } 587dd7cddfSDavid du Colombier 597dd7cddfSDavid du Colombier Window* 607dd7cddfSDavid du Colombier errorwin(Rune *dir, int ndir, Rune **incl, int nincl) 617dd7cddfSDavid du Colombier { 627dd7cddfSDavid du Colombier Window *w; 637dd7cddfSDavid du Colombier Rune *r; 647dd7cddfSDavid du Colombier int i, n; 657dd7cddfSDavid du Colombier 667dd7cddfSDavid du Colombier r = runemalloc(ndir+7); 677dd7cddfSDavid du Colombier if(n = ndir) /* assign = */ 687dd7cddfSDavid du Colombier runemove(r, dir, ndir); 697dd7cddfSDavid du Colombier runemove(r+n, L"+Errors", 7); 707dd7cddfSDavid du Colombier n += 7; 717dd7cddfSDavid du Colombier w = lookfile(r, n); 727dd7cddfSDavid du Colombier if(w == nil){ 737dd7cddfSDavid du Colombier w = coladd(row.col[row.ncol-1], nil, nil, -1); 747dd7cddfSDavid du Colombier w->filemenu = FALSE; 757dd7cddfSDavid du Colombier winsetname(w, r, n); 767dd7cddfSDavid du Colombier } 777dd7cddfSDavid du Colombier free(r); 787dd7cddfSDavid du Colombier for(i=nincl; --i>=0; ){ 797dd7cddfSDavid du Colombier n = runestrlen(incl[i]); 807dd7cddfSDavid du Colombier r = runemalloc(n); 817dd7cddfSDavid du Colombier runemove(r, incl[i], n); 827dd7cddfSDavid du Colombier winaddincl(w, r, n); 837dd7cddfSDavid du Colombier } 847dd7cddfSDavid du Colombier return w; 857dd7cddfSDavid du Colombier } 867dd7cddfSDavid du Colombier 877dd7cddfSDavid du Colombier void 887dd7cddfSDavid du Colombier warning(Mntdir *md, char *s, ...) 897dd7cddfSDavid du Colombier { 907dd7cddfSDavid du Colombier char *buf; 917dd7cddfSDavid du Colombier Rune *r; 927dd7cddfSDavid du Colombier int n, nb, nr, q0, owner; 937dd7cddfSDavid du Colombier Window *w; 947dd7cddfSDavid du Colombier Text *t; 957dd7cddfSDavid du Colombier va_list arg; 967dd7cddfSDavid du Colombier 977dd7cddfSDavid du Colombier if(row.ncol == 0){ /* really early error */ 987dd7cddfSDavid du Colombier rowinit(&row, screen->clipr); 997dd7cddfSDavid du Colombier rowadd(&row, nil, -1); 1007dd7cddfSDavid du Colombier rowadd(&row, nil, -1); 1017dd7cddfSDavid du Colombier if(row.ncol == 0) 1027dd7cddfSDavid du Colombier error("initializing columns in warning()"); 1037dd7cddfSDavid du Colombier } 1047dd7cddfSDavid du Colombier buf = fbufalloc(); 1057dd7cddfSDavid du Colombier va_start(arg, s); 1067dd7cddfSDavid du Colombier n = doprint(buf, buf+BUFSIZE, s, arg)-buf; 1077dd7cddfSDavid du Colombier va_end(arg); 1087dd7cddfSDavid du Colombier r = runemalloc(n); 1097dd7cddfSDavid du Colombier cvttorunes(buf, n, r, &nb, &nr, nil); 1107dd7cddfSDavid du Colombier fbuffree(buf); 1117dd7cddfSDavid du Colombier if(md) 1127dd7cddfSDavid du Colombier for(;;){ 1137dd7cddfSDavid du Colombier w = errorwin(md->dir, md->ndir, md->incl, md->nincl); 1147dd7cddfSDavid du Colombier winlock(w, 'E'); 1157dd7cddfSDavid du Colombier if(w->col != nil) 1167dd7cddfSDavid du Colombier break; 1177dd7cddfSDavid du Colombier /* window was deleted too fast */ 1187dd7cddfSDavid du Colombier winunlock(w); 1197dd7cddfSDavid du Colombier } 1207dd7cddfSDavid du Colombier else 1217dd7cddfSDavid du Colombier w = errorwin(nil, 0, nil, 0); 1227dd7cddfSDavid du Colombier t = &w->body; 1237dd7cddfSDavid du Colombier owner = w->owner; 1247dd7cddfSDavid du Colombier if(owner == 0) 1257dd7cddfSDavid du Colombier w->owner = 'E'; 1267dd7cddfSDavid du Colombier wincommit(w, t); 1277dd7cddfSDavid du Colombier q0 = textbsinsert(t, t->file->nc, r, nr, TRUE, &nr); 1287dd7cddfSDavid du Colombier textshow(t, q0, q0+nr); 1297dd7cddfSDavid du Colombier winsettag(t->w); 1307dd7cddfSDavid du Colombier textscrdraw(t); 1317dd7cddfSDavid du Colombier w->owner = owner; 1327dd7cddfSDavid du Colombier w->dirty = FALSE; 1337dd7cddfSDavid du Colombier if(md) 1347dd7cddfSDavid du Colombier winunlock(w); 1357dd7cddfSDavid du Colombier free(r); 1367dd7cddfSDavid du Colombier } 1377dd7cddfSDavid du Colombier 1387dd7cddfSDavid du Colombier int 1397dd7cddfSDavid du Colombier runeeq(Rune *s1, uint n1, Rune *s2, uint n2) 1407dd7cddfSDavid du Colombier { 1417dd7cddfSDavid du Colombier if(n1 != n2) 1427dd7cddfSDavid du Colombier return FALSE; 1437dd7cddfSDavid du Colombier return memcmp(s1, s2, n1*sizeof(Rune)) == 0; 1447dd7cddfSDavid du Colombier } 1457dd7cddfSDavid du Colombier 1467dd7cddfSDavid du Colombier uint 1477dd7cddfSDavid du Colombier min(uint a, uint b) 1487dd7cddfSDavid du Colombier { 1497dd7cddfSDavid du Colombier if(a < b) 1507dd7cddfSDavid du Colombier return a; 1517dd7cddfSDavid du Colombier return b; 1527dd7cddfSDavid du Colombier } 1537dd7cddfSDavid du Colombier 1547dd7cddfSDavid du Colombier uint 1557dd7cddfSDavid du Colombier max(uint a, uint b) 1567dd7cddfSDavid du Colombier { 1577dd7cddfSDavid du Colombier if(a > b) 1587dd7cddfSDavid du Colombier return a; 1597dd7cddfSDavid du Colombier return b; 1607dd7cddfSDavid du Colombier } 1617dd7cddfSDavid du Colombier 1627dd7cddfSDavid du Colombier char* 1637dd7cddfSDavid du Colombier runetobyte(Rune *r, int n) 1647dd7cddfSDavid du Colombier { 1657dd7cddfSDavid du Colombier char *s; 1667dd7cddfSDavid du Colombier 1677dd7cddfSDavid du Colombier if(n == 0) 1687dd7cddfSDavid du Colombier return nil; 1697dd7cddfSDavid du Colombier s = emalloc(n*UTFmax+1); 170*59cc4ca5SDavid du Colombier setmalloctag(s, getcallerpc(&r)); 1717dd7cddfSDavid du Colombier snprint(s, n*UTFmax+1, "%.*S", n, r); 1727dd7cddfSDavid du Colombier return s; 1737dd7cddfSDavid du Colombier } 1747dd7cddfSDavid du Colombier 1757dd7cddfSDavid du Colombier Rune* 1767dd7cddfSDavid du Colombier bytetorune(char *s, int *ip) 1777dd7cddfSDavid du Colombier { 1787dd7cddfSDavid du Colombier Rune *r; 1797dd7cddfSDavid du Colombier int nb, nr; 1807dd7cddfSDavid du Colombier 1817dd7cddfSDavid du Colombier nb = strlen(s); 1827dd7cddfSDavid du Colombier r = runemalloc(nb+1); 1837dd7cddfSDavid du Colombier cvttorunes(s, nb, r, &nb, &nr, nil); 1847dd7cddfSDavid du Colombier r[nr] = '\0'; 1857dd7cddfSDavid du Colombier *ip = nr; 1867dd7cddfSDavid du Colombier return r; 1877dd7cddfSDavid du Colombier } 1887dd7cddfSDavid du Colombier 1897dd7cddfSDavid du Colombier int 1907dd7cddfSDavid du Colombier isalnum(Rune c) 1917dd7cddfSDavid du Colombier { 1927dd7cddfSDavid du Colombier /* 1937dd7cddfSDavid du Colombier * Hard to get absolutely right. Use what we know about ASCII 1947dd7cddfSDavid du Colombier * and assume anything above the Latin control characters is 1957dd7cddfSDavid du Colombier * potentially an alphanumeric. 1967dd7cddfSDavid du Colombier */ 1977dd7cddfSDavid du Colombier if(c <= ' ') 1987dd7cddfSDavid du Colombier return FALSE; 1997dd7cddfSDavid du Colombier if(0x7F<=c && c<=0xA0) 2007dd7cddfSDavid du Colombier return FALSE; 2017dd7cddfSDavid du Colombier if(utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", c)) 2027dd7cddfSDavid du Colombier return FALSE; 2037dd7cddfSDavid du Colombier return TRUE; 2047dd7cddfSDavid du Colombier } 2057dd7cddfSDavid du Colombier 2067dd7cddfSDavid du Colombier int 2077dd7cddfSDavid du Colombier rgetc(void *v, uint n) 2087dd7cddfSDavid du Colombier { 2097dd7cddfSDavid du Colombier return ((Rune*)v)[n]; 2107dd7cddfSDavid du Colombier } 2117dd7cddfSDavid du Colombier 2127dd7cddfSDavid du Colombier int 2137dd7cddfSDavid du Colombier tgetc(void *a, uint n) 2147dd7cddfSDavid du Colombier { 2157dd7cddfSDavid du Colombier Text *t; 2167dd7cddfSDavid du Colombier 2177dd7cddfSDavid du Colombier t = a; 2187dd7cddfSDavid du Colombier if(n >= t->file->nc) 2197dd7cddfSDavid du Colombier return 0; 2207dd7cddfSDavid du Colombier return textreadc(t, n); 2217dd7cddfSDavid du Colombier } 2227dd7cddfSDavid du Colombier 2237dd7cddfSDavid du Colombier Rune* 2247dd7cddfSDavid du Colombier skipbl(Rune *r, int n, int *np) 2257dd7cddfSDavid du Colombier { 2267dd7cddfSDavid du Colombier while(n>0 && *r==' ' || *r=='\t' || *r=='\n'){ 2277dd7cddfSDavid du Colombier --n; 2287dd7cddfSDavid du Colombier r++; 2297dd7cddfSDavid du Colombier } 2307dd7cddfSDavid du Colombier *np = n; 2317dd7cddfSDavid du Colombier return r; 2327dd7cddfSDavid du Colombier } 2337dd7cddfSDavid du Colombier 2347dd7cddfSDavid du Colombier Rune* 2357dd7cddfSDavid du Colombier findbl(Rune *r, int n, int *np) 2367dd7cddfSDavid du Colombier { 2377dd7cddfSDavid du Colombier while(n>0 && *r!=' ' && *r!='\t' && *r!='\n'){ 2387dd7cddfSDavid du Colombier --n; 2397dd7cddfSDavid du Colombier r++; 2407dd7cddfSDavid du Colombier } 2417dd7cddfSDavid du Colombier *np = n; 2427dd7cddfSDavid du Colombier return r; 2437dd7cddfSDavid du Colombier } 2447dd7cddfSDavid du Colombier 2457dd7cddfSDavid du Colombier void 2467dd7cddfSDavid du Colombier savemouse(Window *w) 2477dd7cddfSDavid du Colombier { 2487dd7cddfSDavid du Colombier prevmouse = mouse->xy; 2497dd7cddfSDavid du Colombier mousew = w; 2507dd7cddfSDavid du Colombier } 2517dd7cddfSDavid du Colombier 2527dd7cddfSDavid du Colombier void 2537dd7cddfSDavid du Colombier restoremouse(Window *w) 2547dd7cddfSDavid du Colombier { 2557dd7cddfSDavid du Colombier if(mousew!=nil && mousew==w) 2567dd7cddfSDavid du Colombier moveto(mousectl, prevmouse); 2577dd7cddfSDavid du Colombier mousew = nil; 2587dd7cddfSDavid du Colombier } 2597dd7cddfSDavid du Colombier 2607dd7cddfSDavid du Colombier void 2617dd7cddfSDavid du Colombier clearmouse() 2627dd7cddfSDavid du Colombier { 2637dd7cddfSDavid du Colombier mousew = nil; 2647dd7cddfSDavid du Colombier } 2657dd7cddfSDavid du Colombier 266*59cc4ca5SDavid du Colombier char* 267*59cc4ca5SDavid du Colombier estrdup(char *s) 268*59cc4ca5SDavid du Colombier { 269*59cc4ca5SDavid du Colombier char *t; 270*59cc4ca5SDavid du Colombier 271*59cc4ca5SDavid du Colombier t = strdup(s); 272*59cc4ca5SDavid du Colombier if(t == nil) 273*59cc4ca5SDavid du Colombier error("strdup failed"); 274*59cc4ca5SDavid du Colombier setmalloctag(t, getcallerpc(&s)); 275*59cc4ca5SDavid du Colombier return t; 276*59cc4ca5SDavid du Colombier } 277*59cc4ca5SDavid du Colombier 2787dd7cddfSDavid du Colombier void* 2797dd7cddfSDavid du Colombier emalloc(uint n) 2807dd7cddfSDavid du Colombier { 2817dd7cddfSDavid du Colombier void *p; 2827dd7cddfSDavid du Colombier 2837dd7cddfSDavid du Colombier p = malloc(n); 2847dd7cddfSDavid du Colombier if(p == nil) 2857dd7cddfSDavid du Colombier error("malloc failed"); 286*59cc4ca5SDavid du Colombier setmalloctag(p, getcallerpc(&n)); 2877dd7cddfSDavid du Colombier memset(p, 0, n); 2887dd7cddfSDavid du Colombier return p; 2897dd7cddfSDavid du Colombier } 2907dd7cddfSDavid du Colombier 291*59cc4ca5SDavid du Colombier void* 292*59cc4ca5SDavid du Colombier erealloc(void *p, uint n) 293*59cc4ca5SDavid du Colombier { 294*59cc4ca5SDavid du Colombier p = realloc(p, n); 295*59cc4ca5SDavid du Colombier if(p == nil) 296*59cc4ca5SDavid du Colombier error("realloc failed"); 297*59cc4ca5SDavid du Colombier setmalloctag(p, getcallerpc(&n)); 298*59cc4ca5SDavid du Colombier return p; 299*59cc4ca5SDavid du Colombier } 300*59cc4ca5SDavid du Colombier 3017dd7cddfSDavid du Colombier /* 3027dd7cddfSDavid du Colombier * Heuristic city. 3037dd7cddfSDavid du Colombier */ 3047dd7cddfSDavid du Colombier Window* 3057dd7cddfSDavid du Colombier newwindow(Text *t) 3067dd7cddfSDavid du Colombier { 3077dd7cddfSDavid du Colombier Column *c; 3087dd7cddfSDavid du Colombier Window *w, *bigw, *emptyw; 3097dd7cddfSDavid du Colombier Text *emptyb; 3107dd7cddfSDavid du Colombier int i, y, el; 3117dd7cddfSDavid du Colombier 3127dd7cddfSDavid du Colombier if(activecol) 3137dd7cddfSDavid du Colombier c = activecol; 3147dd7cddfSDavid du Colombier else if(seltext && seltext->col) 3157dd7cddfSDavid du Colombier c = seltext->col; 3167dd7cddfSDavid du Colombier else if(t && t->col) 3177dd7cddfSDavid du Colombier c = t->col; 3187dd7cddfSDavid du Colombier else{ 3197dd7cddfSDavid du Colombier if(row.ncol==0 && rowadd(&row, nil, -1)==nil) 3207dd7cddfSDavid du Colombier error("can't make column"); 3217dd7cddfSDavid du Colombier c = row.col[row.ncol-1]; 3227dd7cddfSDavid du Colombier } 3237dd7cddfSDavid du Colombier activecol = c; 3247dd7cddfSDavid du Colombier if(t==nil || t->w==nil || c->nw==0) 3257dd7cddfSDavid du Colombier return coladd(c, nil, nil, -1); 3267dd7cddfSDavid du Colombier 3277dd7cddfSDavid du Colombier /* find biggest window and biggest blank spot */ 3287dd7cddfSDavid du Colombier emptyw = c->w[0]; 3297dd7cddfSDavid du Colombier bigw = emptyw; 3307dd7cddfSDavid du Colombier for(i=1; i<c->nw; i++){ 3317dd7cddfSDavid du Colombier w = c->w[i]; 3327dd7cddfSDavid du Colombier /* use >= to choose one near bottom of screen */ 3337dd7cddfSDavid du Colombier if(w->body.maxlines >= bigw->body.maxlines) 3347dd7cddfSDavid du Colombier bigw = w; 3357dd7cddfSDavid du Colombier if(w->body.maxlines-w->body.nlines >= emptyw->body.maxlines-emptyw->body.nlines) 3367dd7cddfSDavid du Colombier emptyw = w; 3377dd7cddfSDavid du Colombier } 3387dd7cddfSDavid du Colombier emptyb = &emptyw->body; 3397dd7cddfSDavid du Colombier el = emptyb->maxlines-emptyb->nlines; 3407dd7cddfSDavid du Colombier /* if empty space is big, use it */ 3417dd7cddfSDavid du Colombier if(el>15 || (el>3 && el>(bigw->body.maxlines-1)/2)) 3427dd7cddfSDavid du Colombier y = emptyb->r.min.y+emptyb->nlines*font->height; 3437dd7cddfSDavid du Colombier else{ 3447dd7cddfSDavid du Colombier /* if this window is in column and isn't much smaller, split it */ 3457dd7cddfSDavid du Colombier if(t->col==c && Dy(t->w->r)>2*Dy(bigw->r)/3) 3467dd7cddfSDavid du Colombier bigw = t->w; 3477dd7cddfSDavid du Colombier y = (bigw->r.min.y + bigw->r.max.y)/2; 3487dd7cddfSDavid du Colombier } 3497dd7cddfSDavid du Colombier w = coladd(c, nil, nil, y); 3507dd7cddfSDavid du Colombier if(w->body.maxlines < 2) 3517dd7cddfSDavid du Colombier colgrow(w->col, w, 1); 3527dd7cddfSDavid du Colombier return w; 3537dd7cddfSDavid du Colombier } 354