1 #include <u.h> 2 #include <libc.h> 3 #include <draw.h> 4 #include <thread.h> 5 #include <mouse.h> 6 #include <keyboard.h> 7 #include <frame.h> 8 #include <auth.h> 9 #include <fcall.h> 10 #include <plumb.h> 11 #include "dat.h" 12 #include "fns.h" 13 14 static Point prevmouse; 15 static Window *mousew; 16 17 void 18 cvttorunes(char *p, int n, Rune *r, int *nb, int *nr, int *nulls) 19 { 20 uchar *q; 21 Rune *s; 22 int j, w; 23 24 /* 25 * Always guaranteed that n bytes may be interpreted 26 * without worrying about partial runes. This may mean 27 * reading up to UTFmax-1 more bytes than n; the caller 28 * knows this. If n is a firm limit, the caller should 29 * set p[n] = 0. 30 */ 31 q = (uchar*)p; 32 s = r; 33 for(j=0; j<n; j+=w){ 34 if(*q < Runeself){ 35 w = 1; 36 *s = *q++; 37 }else{ 38 w = chartorune(s, (char*)q); 39 q += w; 40 } 41 if(*s) 42 s++; 43 else if(nulls) 44 *nulls = TRUE; 45 } 46 *nb = (char*)q-p; 47 *nr = s-r; 48 } 49 50 void 51 error(char *s) 52 { 53 fprint(2, "acme: %s: %r\n", s); 54 remove(acmeerrorfile); 55 notify(nil); 56 abort(); 57 } 58 59 Window* 60 errorwin(Rune *dir, int ndir, Rune **incl, int nincl) 61 { 62 Window *w; 63 Rune *r; 64 int i, n; 65 66 r = runemalloc(ndir+7); 67 if(n = ndir) /* assign = */ 68 runemove(r, dir, ndir); 69 runemove(r+n, L"+Errors", 7); 70 n += 7; 71 w = lookfile(r, n); 72 if(w == nil){ 73 w = coladd(row.col[row.ncol-1], nil, nil, -1); 74 w->filemenu = FALSE; 75 winsetname(w, r, n); 76 } 77 free(r); 78 for(i=nincl; --i>=0; ){ 79 n = runestrlen(incl[i]); 80 r = runemalloc(n); 81 runemove(r, incl[i], n); 82 winaddincl(w, r, n); 83 } 84 return w; 85 } 86 87 void 88 warning(Mntdir *md, char *s, ...) 89 { 90 char *buf; 91 Rune *r; 92 int n, nb, nr, q0, owner; 93 Window *w; 94 Text *t; 95 va_list arg; 96 97 if(row.ncol == 0){ /* really early error */ 98 rowinit(&row, screen->clipr); 99 rowadd(&row, nil, -1); 100 rowadd(&row, nil, -1); 101 if(row.ncol == 0) 102 error("initializing columns in warning()"); 103 } 104 buf = fbufalloc(); 105 va_start(arg, s); 106 n = doprint(buf, buf+BUFSIZE, s, arg)-buf; 107 va_end(arg); 108 r = runemalloc(n); 109 cvttorunes(buf, n, r, &nb, &nr, nil); 110 fbuffree(buf); 111 if(md) 112 for(;;){ 113 w = errorwin(md->dir, md->ndir, md->incl, md->nincl); 114 winlock(w, 'E'); 115 if(w->col != nil) 116 break; 117 /* window was deleted too fast */ 118 winunlock(w); 119 } 120 else 121 w = errorwin(nil, 0, nil, 0); 122 t = &w->body; 123 owner = w->owner; 124 if(owner == 0) 125 w->owner = 'E'; 126 wincommit(w, t); 127 q0 = textbsinsert(t, t->file->nc, r, nr, TRUE, &nr); 128 textshow(t, q0, q0+nr); 129 winsettag(t->w); 130 textscrdraw(t); 131 w->owner = owner; 132 w->dirty = FALSE; 133 if(md) 134 winunlock(w); 135 free(r); 136 } 137 138 int 139 runeeq(Rune *s1, uint n1, Rune *s2, uint n2) 140 { 141 if(n1 != n2) 142 return FALSE; 143 return memcmp(s1, s2, n1*sizeof(Rune)) == 0; 144 } 145 146 uint 147 min(uint a, uint b) 148 { 149 if(a < b) 150 return a; 151 return b; 152 } 153 154 uint 155 max(uint a, uint b) 156 { 157 if(a > b) 158 return a; 159 return b; 160 } 161 162 char* 163 runetobyte(Rune *r, int n) 164 { 165 char *s; 166 167 if(n == 0) 168 return nil; 169 s = emalloc(n*UTFmax+1); 170 setmalloctag(s, getcallerpc(&r)); 171 snprint(s, n*UTFmax+1, "%.*S", n, r); 172 return s; 173 } 174 175 Rune* 176 bytetorune(char *s, int *ip) 177 { 178 Rune *r; 179 int nb, nr; 180 181 nb = strlen(s); 182 r = runemalloc(nb+1); 183 cvttorunes(s, nb, r, &nb, &nr, nil); 184 r[nr] = '\0'; 185 *ip = nr; 186 return r; 187 } 188 189 int 190 isalnum(Rune c) 191 { 192 /* 193 * Hard to get absolutely right. Use what we know about ASCII 194 * and assume anything above the Latin control characters is 195 * potentially an alphanumeric. 196 */ 197 if(c <= ' ') 198 return FALSE; 199 if(0x7F<=c && c<=0xA0) 200 return FALSE; 201 if(utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", c)) 202 return FALSE; 203 return TRUE; 204 } 205 206 int 207 rgetc(void *v, uint n) 208 { 209 return ((Rune*)v)[n]; 210 } 211 212 int 213 tgetc(void *a, uint n) 214 { 215 Text *t; 216 217 t = a; 218 if(n >= t->file->nc) 219 return 0; 220 return textreadc(t, n); 221 } 222 223 Rune* 224 skipbl(Rune *r, int n, int *np) 225 { 226 while(n>0 && *r==' ' || *r=='\t' || *r=='\n'){ 227 --n; 228 r++; 229 } 230 *np = n; 231 return r; 232 } 233 234 Rune* 235 findbl(Rune *r, int n, int *np) 236 { 237 while(n>0 && *r!=' ' && *r!='\t' && *r!='\n'){ 238 --n; 239 r++; 240 } 241 *np = n; 242 return r; 243 } 244 245 void 246 savemouse(Window *w) 247 { 248 prevmouse = mouse->xy; 249 mousew = w; 250 } 251 252 void 253 restoremouse(Window *w) 254 { 255 if(mousew!=nil && mousew==w) 256 moveto(mousectl, prevmouse); 257 mousew = nil; 258 } 259 260 void 261 clearmouse() 262 { 263 mousew = nil; 264 } 265 266 char* 267 estrdup(char *s) 268 { 269 char *t; 270 271 t = strdup(s); 272 if(t == nil) 273 error("strdup failed"); 274 setmalloctag(t, getcallerpc(&s)); 275 return t; 276 } 277 278 void* 279 emalloc(uint n) 280 { 281 void *p; 282 283 p = malloc(n); 284 if(p == nil) 285 error("malloc failed"); 286 setmalloctag(p, getcallerpc(&n)); 287 memset(p, 0, n); 288 return p; 289 } 290 291 void* 292 erealloc(void *p, uint n) 293 { 294 p = realloc(p, n); 295 if(p == nil) 296 error("realloc failed"); 297 setmalloctag(p, getcallerpc(&n)); 298 return p; 299 } 300 301 /* 302 * Heuristic city. 303 */ 304 Window* 305 newwindow(Text *t) 306 { 307 Column *c; 308 Window *w, *bigw, *emptyw; 309 Text *emptyb; 310 int i, y, el; 311 312 if(activecol) 313 c = activecol; 314 else if(seltext && seltext->col) 315 c = seltext->col; 316 else if(t && t->col) 317 c = t->col; 318 else{ 319 if(row.ncol==0 && rowadd(&row, nil, -1)==nil) 320 error("can't make column"); 321 c = row.col[row.ncol-1]; 322 } 323 activecol = c; 324 if(t==nil || t->w==nil || c->nw==0) 325 return coladd(c, nil, nil, -1); 326 327 /* find biggest window and biggest blank spot */ 328 emptyw = c->w[0]; 329 bigw = emptyw; 330 for(i=1; i<c->nw; i++){ 331 w = c->w[i]; 332 /* use >= to choose one near bottom of screen */ 333 if(w->body.maxlines >= bigw->body.maxlines) 334 bigw = w; 335 if(w->body.maxlines-w->body.nlines >= emptyw->body.maxlines-emptyw->body.nlines) 336 emptyw = w; 337 } 338 emptyb = &emptyw->body; 339 el = emptyb->maxlines-emptyb->nlines; 340 /* if empty space is big, use it */ 341 if(el>15 || (el>3 && el>(bigw->body.maxlines-1)/2)) 342 y = emptyb->r.min.y+emptyb->nlines*font->height; 343 else{ 344 /* if this window is in column and isn't much smaller, split it */ 345 if(t->col==c && Dy(t->w->r)>2*Dy(bigw->r)/3) 346 bigw = t->w; 347 y = (bigw->r.min.y + bigw->r.max.y)/2; 348 } 349 w = coladd(c, nil, nil, y); 350 if(w->body.maxlines < 2) 351 colgrow(w->col, w, 1); 352 return w; 353 } 354