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