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