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