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