17dd7cddfSDavid du Colombier #include <u.h> 27dd7cddfSDavid du Colombier #include <libc.h> 37dd7cddfSDavid du Colombier #include <draw.h> 47dd7cddfSDavid du Colombier #include <thread.h> 59a747e4fSDavid du Colombier #include <cursor.h> 67dd7cddfSDavid du Colombier #include <mouse.h> 77dd7cddfSDavid du Colombier #include <keyboard.h> 87dd7cddfSDavid du Colombier #include <frame.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 abort(); 567dd7cddfSDavid du Colombier } 577dd7cddfSDavid du Colombier 587dd7cddfSDavid du Colombier Window* 59*3ff48bf5SDavid du Colombier errorwin1(Rune *dir, int ndir, Rune **incl, int nincl) 607dd7cddfSDavid du Colombier { 617dd7cddfSDavid du Colombier Window *w; 627dd7cddfSDavid du Colombier Rune *r; 637dd7cddfSDavid du Colombier int i, n; 647dd7cddfSDavid du Colombier 657dd7cddfSDavid du Colombier r = runemalloc(ndir+7); 667dd7cddfSDavid du Colombier if(n = ndir) /* assign = */ 677dd7cddfSDavid du Colombier runemove(r, dir, ndir); 687dd7cddfSDavid du Colombier runemove(r+n, L"+Errors", 7); 697dd7cddfSDavid du Colombier n += 7; 707dd7cddfSDavid du Colombier w = lookfile(r, n); 717dd7cddfSDavid du Colombier if(w == nil){ 727dd7cddfSDavid du Colombier w = coladd(row.col[row.ncol-1], nil, nil, -1); 737dd7cddfSDavid du Colombier w->filemenu = FALSE; 747dd7cddfSDavid du Colombier winsetname(w, r, n); 757dd7cddfSDavid du Colombier } 767dd7cddfSDavid du Colombier free(r); 777dd7cddfSDavid du Colombier for(i=nincl; --i>=0; ){ 787dd7cddfSDavid du Colombier n = runestrlen(incl[i]); 797dd7cddfSDavid du Colombier r = runemalloc(n); 807dd7cddfSDavid du Colombier runemove(r, incl[i], n); 817dd7cddfSDavid du Colombier winaddincl(w, r, n); 827dd7cddfSDavid du Colombier } 837dd7cddfSDavid du Colombier return w; 847dd7cddfSDavid du Colombier } 857dd7cddfSDavid du Colombier 86*3ff48bf5SDavid du Colombier /* make new window, if necessary; return with it locked */ 87*3ff48bf5SDavid du Colombier Window* 88*3ff48bf5SDavid du Colombier errorwin(Mntdir *md, int owner) 89*3ff48bf5SDavid du Colombier { 90*3ff48bf5SDavid du Colombier Window *w; 91*3ff48bf5SDavid du Colombier 92*3ff48bf5SDavid du Colombier for(;;){ 93*3ff48bf5SDavid du Colombier if(md == nil) 94*3ff48bf5SDavid du Colombier w = errorwin1(nil, 0, nil, 0); 95*3ff48bf5SDavid du Colombier else 96*3ff48bf5SDavid du Colombier w = errorwin1(md->dir, md->ndir, md->incl, md->nincl); 97*3ff48bf5SDavid du Colombier winlock(w, owner); 98*3ff48bf5SDavid du Colombier if(w->col != nil) 99*3ff48bf5SDavid du Colombier break; 100*3ff48bf5SDavid du Colombier /* window was deleted too fast */ 101*3ff48bf5SDavid du Colombier winunlock(w); 102*3ff48bf5SDavid du Colombier } 103*3ff48bf5SDavid du Colombier return w; 104*3ff48bf5SDavid du Colombier } 105*3ff48bf5SDavid du Colombier 1067dd7cddfSDavid du Colombier void 1077dd7cddfSDavid du Colombier warning(Mntdir *md, char *s, ...) 1087dd7cddfSDavid du Colombier { 1097dd7cddfSDavid du Colombier Rune *r; 1109a747e4fSDavid du Colombier int nr, q0, owner; 1117dd7cddfSDavid du Colombier Window *w; 1127dd7cddfSDavid du Colombier Text *t; 1137dd7cddfSDavid du Colombier va_list arg; 1147dd7cddfSDavid du Colombier 1159a747e4fSDavid du Colombier va_start(arg, s); 1169a747e4fSDavid du Colombier r = runevsmprint(s, arg); 1179a747e4fSDavid du Colombier va_end(arg); 1189a747e4fSDavid du Colombier if(r == nil) 1199a747e4fSDavid du Colombier error("runevsmprint failed"); 1209a747e4fSDavid du Colombier nr = runestrlen(r); 1219a747e4fSDavid du Colombier 1227dd7cddfSDavid du Colombier if(row.ncol == 0){ /* really early error */ 1237dd7cddfSDavid du Colombier rowinit(&row, screen->clipr); 1247dd7cddfSDavid du Colombier rowadd(&row, nil, -1); 1257dd7cddfSDavid du Colombier rowadd(&row, nil, -1); 1267dd7cddfSDavid du Colombier if(row.ncol == 0) 1277dd7cddfSDavid du Colombier error("initializing columns in warning()"); 1287dd7cddfSDavid du Colombier } 1299a747e4fSDavid du Colombier 130*3ff48bf5SDavid du Colombier w = errorwin(md, 'E'); 1317dd7cddfSDavid du Colombier t = &w->body; 1327dd7cddfSDavid du Colombier owner = w->owner; 1337dd7cddfSDavid du Colombier if(owner == 0) 1347dd7cddfSDavid du Colombier w->owner = 'E'; 1357dd7cddfSDavid du Colombier wincommit(w, t); 1367dd7cddfSDavid du Colombier q0 = textbsinsert(t, t->file->nc, r, nr, TRUE, &nr); 1379a747e4fSDavid du Colombier textshow(t, q0, q0+nr, 1); 1387dd7cddfSDavid du Colombier winsettag(t->w); 1397dd7cddfSDavid du Colombier textscrdraw(t); 1407dd7cddfSDavid du Colombier w->owner = owner; 1417dd7cddfSDavid du Colombier w->dirty = FALSE; 1427dd7cddfSDavid du Colombier winunlock(w); 1437dd7cddfSDavid du Colombier free(r); 1447dd7cddfSDavid du Colombier } 1457dd7cddfSDavid du Colombier 1467dd7cddfSDavid du Colombier int 1477dd7cddfSDavid du Colombier runeeq(Rune *s1, uint n1, Rune *s2, uint n2) 1487dd7cddfSDavid du Colombier { 1497dd7cddfSDavid du Colombier if(n1 != n2) 1507dd7cddfSDavid du Colombier return FALSE; 1517dd7cddfSDavid du Colombier return memcmp(s1, s2, n1*sizeof(Rune)) == 0; 1527dd7cddfSDavid du Colombier } 1537dd7cddfSDavid du Colombier 1547dd7cddfSDavid du Colombier uint 1557dd7cddfSDavid du Colombier min(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 uint 1637dd7cddfSDavid du Colombier max(uint a, uint b) 1647dd7cddfSDavid du Colombier { 1657dd7cddfSDavid du Colombier if(a > b) 1667dd7cddfSDavid du Colombier return a; 1677dd7cddfSDavid du Colombier return b; 1687dd7cddfSDavid du Colombier } 1697dd7cddfSDavid du Colombier 1707dd7cddfSDavid du Colombier char* 1717dd7cddfSDavid du Colombier runetobyte(Rune *r, int n) 1727dd7cddfSDavid du Colombier { 1737dd7cddfSDavid du Colombier char *s; 1747dd7cddfSDavid du Colombier 1757dd7cddfSDavid du Colombier if(n == 0) 1767dd7cddfSDavid du Colombier return nil; 1777dd7cddfSDavid du Colombier s = emalloc(n*UTFmax+1); 17859cc4ca5SDavid du Colombier setmalloctag(s, getcallerpc(&r)); 1797dd7cddfSDavid du Colombier snprint(s, n*UTFmax+1, "%.*S", n, r); 1807dd7cddfSDavid du Colombier return s; 1817dd7cddfSDavid du Colombier } 1827dd7cddfSDavid du Colombier 1837dd7cddfSDavid du Colombier Rune* 1847dd7cddfSDavid du Colombier bytetorune(char *s, int *ip) 1857dd7cddfSDavid du Colombier { 1867dd7cddfSDavid du Colombier Rune *r; 1877dd7cddfSDavid du Colombier int nb, nr; 1887dd7cddfSDavid du Colombier 1897dd7cddfSDavid du Colombier nb = strlen(s); 1907dd7cddfSDavid du Colombier r = runemalloc(nb+1); 1917dd7cddfSDavid du Colombier cvttorunes(s, nb, r, &nb, &nr, nil); 1927dd7cddfSDavid du Colombier r[nr] = '\0'; 1937dd7cddfSDavid du Colombier *ip = nr; 1947dd7cddfSDavid du Colombier return r; 1957dd7cddfSDavid du Colombier } 1967dd7cddfSDavid du Colombier 1977dd7cddfSDavid du Colombier int 1987dd7cddfSDavid du Colombier isalnum(Rune c) 1997dd7cddfSDavid du Colombier { 2007dd7cddfSDavid du Colombier /* 2017dd7cddfSDavid du Colombier * Hard to get absolutely right. Use what we know about ASCII 2027dd7cddfSDavid du Colombier * and assume anything above the Latin control characters is 2037dd7cddfSDavid du Colombier * potentially an alphanumeric. 2047dd7cddfSDavid du Colombier */ 2057dd7cddfSDavid du Colombier if(c <= ' ') 2067dd7cddfSDavid du Colombier return FALSE; 2077dd7cddfSDavid du Colombier if(0x7F<=c && c<=0xA0) 2087dd7cddfSDavid du Colombier return FALSE; 2097dd7cddfSDavid du Colombier if(utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", c)) 2107dd7cddfSDavid du Colombier return FALSE; 2117dd7cddfSDavid du Colombier return TRUE; 2127dd7cddfSDavid du Colombier } 2137dd7cddfSDavid du Colombier 2147dd7cddfSDavid du Colombier int 2157dd7cddfSDavid du Colombier rgetc(void *v, uint n) 2167dd7cddfSDavid du Colombier { 2177dd7cddfSDavid du Colombier return ((Rune*)v)[n]; 2187dd7cddfSDavid du Colombier } 2197dd7cddfSDavid du Colombier 2207dd7cddfSDavid du Colombier int 2217dd7cddfSDavid du Colombier tgetc(void *a, uint n) 2227dd7cddfSDavid du Colombier { 2237dd7cddfSDavid du Colombier Text *t; 2247dd7cddfSDavid du Colombier 2257dd7cddfSDavid du Colombier t = a; 2267dd7cddfSDavid du Colombier if(n >= t->file->nc) 2277dd7cddfSDavid du Colombier return 0; 2287dd7cddfSDavid du Colombier return textreadc(t, n); 2297dd7cddfSDavid du Colombier } 2307dd7cddfSDavid du Colombier 2317dd7cddfSDavid du Colombier Rune* 2327dd7cddfSDavid du Colombier skipbl(Rune *r, int n, int *np) 2337dd7cddfSDavid du Colombier { 2347dd7cddfSDavid du Colombier while(n>0 && *r==' ' || *r=='\t' || *r=='\n'){ 2357dd7cddfSDavid du Colombier --n; 2367dd7cddfSDavid du Colombier r++; 2377dd7cddfSDavid du Colombier } 2387dd7cddfSDavid du Colombier *np = n; 2397dd7cddfSDavid du Colombier return r; 2407dd7cddfSDavid du Colombier } 2417dd7cddfSDavid du Colombier 2427dd7cddfSDavid du Colombier Rune* 2437dd7cddfSDavid du Colombier findbl(Rune *r, int n, int *np) 2447dd7cddfSDavid du Colombier { 2457dd7cddfSDavid du Colombier while(n>0 && *r!=' ' && *r!='\t' && *r!='\n'){ 2467dd7cddfSDavid du Colombier --n; 2477dd7cddfSDavid du Colombier r++; 2487dd7cddfSDavid du Colombier } 2497dd7cddfSDavid du Colombier *np = n; 2507dd7cddfSDavid du Colombier return r; 2517dd7cddfSDavid du Colombier } 2527dd7cddfSDavid du Colombier 2537dd7cddfSDavid du Colombier void 2547dd7cddfSDavid du Colombier savemouse(Window *w) 2557dd7cddfSDavid du Colombier { 2567dd7cddfSDavid du Colombier prevmouse = mouse->xy; 2577dd7cddfSDavid du Colombier mousew = w; 2587dd7cddfSDavid du Colombier } 2597dd7cddfSDavid du Colombier 2607dd7cddfSDavid du Colombier void 2617dd7cddfSDavid du Colombier restoremouse(Window *w) 2627dd7cddfSDavid du Colombier { 2637dd7cddfSDavid du Colombier if(mousew!=nil && mousew==w) 2647dd7cddfSDavid du Colombier moveto(mousectl, prevmouse); 2657dd7cddfSDavid du Colombier mousew = nil; 2667dd7cddfSDavid du Colombier } 2677dd7cddfSDavid du Colombier 2687dd7cddfSDavid du Colombier void 2697dd7cddfSDavid du Colombier clearmouse() 2707dd7cddfSDavid du Colombier { 2717dd7cddfSDavid du Colombier mousew = nil; 2727dd7cddfSDavid du Colombier } 2737dd7cddfSDavid du Colombier 27459cc4ca5SDavid du Colombier char* 27559cc4ca5SDavid du Colombier estrdup(char *s) 27659cc4ca5SDavid du Colombier { 27759cc4ca5SDavid du Colombier char *t; 27859cc4ca5SDavid du Colombier 27959cc4ca5SDavid du Colombier t = strdup(s); 28059cc4ca5SDavid du Colombier if(t == nil) 28159cc4ca5SDavid du Colombier error("strdup failed"); 28259cc4ca5SDavid du Colombier setmalloctag(t, getcallerpc(&s)); 28359cc4ca5SDavid du Colombier return t; 28459cc4ca5SDavid du Colombier } 28559cc4ca5SDavid du Colombier 2867dd7cddfSDavid du Colombier void* 2877dd7cddfSDavid du Colombier emalloc(uint n) 2887dd7cddfSDavid du Colombier { 2897dd7cddfSDavid du Colombier void *p; 2907dd7cddfSDavid du Colombier 2917dd7cddfSDavid du Colombier p = malloc(n); 2927dd7cddfSDavid du Colombier if(p == nil) 2937dd7cddfSDavid du Colombier error("malloc failed"); 29459cc4ca5SDavid du Colombier setmalloctag(p, getcallerpc(&n)); 2957dd7cddfSDavid du Colombier memset(p, 0, n); 2967dd7cddfSDavid du Colombier return p; 2977dd7cddfSDavid du Colombier } 2987dd7cddfSDavid du Colombier 29959cc4ca5SDavid du Colombier void* 30059cc4ca5SDavid du Colombier erealloc(void *p, uint n) 30159cc4ca5SDavid du Colombier { 30259cc4ca5SDavid du Colombier p = realloc(p, n); 30359cc4ca5SDavid du Colombier if(p == nil) 30459cc4ca5SDavid du Colombier error("realloc failed"); 30559cc4ca5SDavid du Colombier setmalloctag(p, getcallerpc(&n)); 30659cc4ca5SDavid du Colombier return p; 30759cc4ca5SDavid du Colombier } 30859cc4ca5SDavid du Colombier 3097dd7cddfSDavid du Colombier /* 3107dd7cddfSDavid du Colombier * Heuristic city. 3117dd7cddfSDavid du Colombier */ 3127dd7cddfSDavid du Colombier Window* 3137dd7cddfSDavid du Colombier newwindow(Text *t) 3147dd7cddfSDavid du Colombier { 3157dd7cddfSDavid du Colombier Column *c; 3167dd7cddfSDavid du Colombier Window *w, *bigw, *emptyw; 3177dd7cddfSDavid du Colombier Text *emptyb; 3187dd7cddfSDavid du Colombier int i, y, el; 3197dd7cddfSDavid du Colombier 3207dd7cddfSDavid du Colombier if(activecol) 3217dd7cddfSDavid du Colombier c = activecol; 3227dd7cddfSDavid du Colombier else if(seltext && seltext->col) 3237dd7cddfSDavid du Colombier c = seltext->col; 3247dd7cddfSDavid du Colombier else if(t && t->col) 3257dd7cddfSDavid du Colombier c = t->col; 3267dd7cddfSDavid du Colombier else{ 3277dd7cddfSDavid du Colombier if(row.ncol==0 && rowadd(&row, nil, -1)==nil) 3287dd7cddfSDavid du Colombier error("can't make column"); 3297dd7cddfSDavid du Colombier c = row.col[row.ncol-1]; 3307dd7cddfSDavid du Colombier } 3317dd7cddfSDavid du Colombier activecol = c; 3327dd7cddfSDavid du Colombier if(t==nil || t->w==nil || c->nw==0) 3337dd7cddfSDavid du Colombier return coladd(c, nil, nil, -1); 3347dd7cddfSDavid du Colombier 3357dd7cddfSDavid du Colombier /* find biggest window and biggest blank spot */ 3367dd7cddfSDavid du Colombier emptyw = c->w[0]; 3377dd7cddfSDavid du Colombier bigw = emptyw; 3387dd7cddfSDavid du Colombier for(i=1; i<c->nw; i++){ 3397dd7cddfSDavid du Colombier w = c->w[i]; 3407dd7cddfSDavid du Colombier /* use >= to choose one near bottom of screen */ 3417dd7cddfSDavid du Colombier if(w->body.maxlines >= bigw->body.maxlines) 3427dd7cddfSDavid du Colombier bigw = w; 3437dd7cddfSDavid du Colombier if(w->body.maxlines-w->body.nlines >= emptyw->body.maxlines-emptyw->body.nlines) 3447dd7cddfSDavid du Colombier emptyw = w; 3457dd7cddfSDavid du Colombier } 3467dd7cddfSDavid du Colombier emptyb = &emptyw->body; 3477dd7cddfSDavid du Colombier el = emptyb->maxlines-emptyb->nlines; 3487dd7cddfSDavid du Colombier /* if empty space is big, use it */ 3497dd7cddfSDavid du Colombier if(el>15 || (el>3 && el>(bigw->body.maxlines-1)/2)) 3507dd7cddfSDavid du Colombier y = emptyb->r.min.y+emptyb->nlines*font->height; 3517dd7cddfSDavid du Colombier else{ 3527dd7cddfSDavid du Colombier /* if this window is in column and isn't much smaller, split it */ 3537dd7cddfSDavid du Colombier if(t->col==c && Dy(t->w->r)>2*Dy(bigw->r)/3) 3547dd7cddfSDavid du Colombier bigw = t->w; 3557dd7cddfSDavid du Colombier y = (bigw->r.min.y + bigw->r.max.y)/2; 3567dd7cddfSDavid du Colombier } 3577dd7cddfSDavid du Colombier w = coladd(c, nil, nil, y); 3587dd7cddfSDavid du Colombier if(w->body.maxlines < 2) 3597dd7cddfSDavid du Colombier colgrow(w->col, w, 1); 3607dd7cddfSDavid du Colombier return w; 3617dd7cddfSDavid du Colombier } 362