Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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+8);
66
	if(n = ndir){	/* assign = */
67
		runemove(r, dir, ndir);
68
		r[n++] = L'/';
69
	}
70
	runemove(r+n, L"+Errors", 7);
71
	n += 7;
72
	w = lookfile(r, n);
73
	if(w == nil){
74
		if(row.ncol == 0)
75
			if(rowadd(&row, nil, -1) == nil)
76
				error("can't create column to make error window");
77
		w = coladd(row.col[row.ncol-1], nil, nil, -1);
78
		w->filemenu = FALSE;
79
		winsetname(w, r, n);
80
	}
81
	free(r);
82
	for(i=nincl; --i>=0; ){
83
		n = runestrlen(incl[i]);
84
		r = runemalloc(n);
85
		runemove(r, incl[i], n);
86
		winaddincl(w, r, n);
87
	}
88
	w->autoindent = globalautoindent;
89
	return w;
90
}
91
 
92
/* make new window, if necessary; return with it locked */
93
Window*
94
errorwin(Mntdir *md, int owner)
95
{
96
	Window *w;
97
 
98
	for(;;){
99
		if(md == nil)
100
			w = errorwin1(nil, 0, nil, 0);
101
		else
102
			w = errorwin1(md->dir, md->ndir, md->incl, md->nincl);
103
		winlock(w, owner);
104
		if(w->col != nil)
105
			break;
106
		/* window was deleted too fast */
107
		winunlock(w);
108
	}
109
	return w;
110
}
111
 
112
/*
113
 * Incoming window should be locked. 
114
 * It will be unlocked and returned window
115
 * will be locked in its place.
116
 */
117
Window*
118
errorwinforwin(Window *w)
119
{
120
	int i, n, nincl, owner;
121
	Rune **incl;
122
	Runestr dir;
123
	Text *t;
124
 
125
	t = &w->body;
126
	dir = dirname(t, nil, 0);
127
	if(dir.nr==1 && dir.r[0]=='.'){	/* sigh */
128
		free(dir.r);
129
		dir.r = nil;
130
		dir.nr = 0;
131
	}
132
	incl = nil;
133
	nincl = w->nincl;
134
	if(nincl > 0){
135
		incl = emalloc(nincl*sizeof(Rune*));
136
		for(i=0; i<nincl; i++){
137
			n = runestrlen(w->incl[i]);
138
			incl[i] = runemalloc(n+1);
139
			runemove(incl[i], w->incl[i], n);
140
		}
141
	}
142
	owner = w->owner;
143
	winunlock(w);
144
	for(;;){
145
		w = errorwin1(dir.r, dir.nr, incl, nincl);
146
		winlock(w, owner);
147
		if(w->col != nil)
148
			break;
149
		/* window deleted too fast */
150
		winunlock(w);
151
	}
152
	return w;
153
}
154
 
155
typedef struct Warning Warning;
156
 
157
struct Warning{
158
	Mntdir *md;
159
	Buffer buf;
160
	Warning *next;
161
};
162
 
163
static Warning *warnings;
164
 
165
static
166
void
167
addwarningtext(Mntdir *md, Rune *r, int nr)
168
{
169
	Warning *warn;
170
 
171
	for(warn = warnings; warn; warn=warn->next){
172
		if(warn->md == md){
173
			bufinsert(&warn->buf, warn->buf.nc, r, nr);
174
			return;
175
		}
176
	}
177
	warn = emalloc(sizeof(Warning));
178
	warn->next = warnings;
179
	warn->md = md;
180
	if(md)
181
		fsysincid(md);
182
	warnings = warn;
183
	bufinsert(&warn->buf, 0, r, nr);
184
	nbsendp(cwarn, 0);
185
}
186
 
187
/* called while row is locked */
188
void
189
flushwarnings(void)
190
{
191
	Warning *warn, *next;
192
	Window *w;
193
	Text *t;
194
	int owner, nr, q0, n;
195
	Rune *r;
196
 
197
	for(warn=warnings; warn; warn=next) {
198
		w = errorwin(warn->md, 'E');
199
		t = &w->body;
200
		owner = w->owner;
201
		if(owner == 0)
202
			w->owner = 'E';
203
		wincommit(w, t);
204
		/*
205
		 * Most commands don't generate much output. For instance,
206
		 * Edit ,>cat goes through /dev/cons and is already in blocks
207
		 * because of the i/o system, but a few can.  Edit ,p will
208
		 * put the entire result into a single hunk.  So it's worth doing
209
		 * this in blocks (and putting the text in a buffer in the first
210
		 * place), to avoid a big memory footprint.
211
		 */
212
		r = fbufalloc();
213
		q0 = t->file->nc;
214
		for(n = 0; n < warn->buf.nc; n += nr){
215
			nr = warn->buf.nc - n;
216
			if(nr > RBUFSIZE)
217
				nr = RBUFSIZE;
218
			bufread(&warn->buf, n, r, nr);
219
			textbsinsert(t, t->file->nc, r, nr, TRUE, &nr);
220
		}
221
		textshow(t, q0, t->file->nc, 1);
222
		free(r);
223
		winsettag(t->w);
224
		textscrdraw(t);
225
		w->owner = owner;
226
		w->dirty = FALSE;
227
		winunlock(w);
228
		bufclose(&warn->buf);
229
		next = warn->next;
230
		if(warn->md)
231
			fsysdelid(warn->md);
232
		free(warn);
233
	}
234
	warnings = nil;
235
}
236
 
237
void
238
warning(Mntdir *md, char *s, ...)
239
{
240
	Rune *r;
241
	va_list arg;
242
 
243
	va_start(arg, s);
244
	r = runevsmprint(s, arg);
245
	va_end(arg);
246
	if(r == nil)
247
		error("runevsmprint failed");
248
	addwarningtext(md, r, runestrlen(r));
249
	free(r);
250
}
251
 
252
int
253
runeeq(Rune *s1, uint n1, Rune *s2, uint n2)
254
{
255
	if(n1 != n2)
256
		return FALSE;
257
	return memcmp(s1, s2, n1*sizeof(Rune)) == 0;
258
}
259
 
260
uint
261
min(uint a, uint b)
262
{
263
	if(a < b)
264
		return a;
265
	return b;
266
}
267
 
268
uint
269
max(uint a, uint b)
270
{
271
	if(a > b)
272
		return a;
273
	return b;
274
}
275
 
276
char*
277
runetobyte(Rune *r, int n)
278
{
279
	char *s;
280
 
281
	if(r == nil)
282
		return nil;
283
	s = emalloc(n*UTFmax+1);
284
	setmalloctag(s, getcallerpc(&r));
285
	snprint(s, n*UTFmax+1, "%.*S", n, r);
286
	return s;
287
}
288
 
289
Rune*
290
bytetorune(char *s, int *ip)
291
{
292
	Rune *r;
293
	int nb, nr;
294
 
295
	nb = strlen(s);
296
	r = runemalloc(nb+1);
297
	cvttorunes(s, nb, r, &nb, &nr, nil);
298
	r[nr] = '\0';
299
	*ip = nr;
300
	return r;
301
}
302
 
303
int
304
isalnum(Rune c)
305
{
306
	/*
307
	 * Hard to get absolutely right.  Use what we know about ASCII
308
	 * and assume anything above the Latin control characters is
309
	 * potentially an alphanumeric.
310
	 *
311
	 * Treat 0xA0 (non-breaking space) as a special alphanumeric
312
	 * character [sape]
313
	 */
314
	if(c <= ' ')
315
		return FALSE;
316
	if(0x7F<=c && c<0xA0)
317
		return FALSE;
318
	if(utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", c))
319
		return FALSE;
320
	return TRUE;
321
}
322
 
323
int
324
rgetc(void *v, uint n)
325
{
326
	return ((Rune*)v)[n];
327
}
328
 
329
int
330
tgetc(void *a, uint n)
331
{
332
	Text *t;
333
 
334
	t = a;
335
	if(n >= t->file->nc)
336
		return 0;
337
	return textreadc(t, n);
338
}
339
 
340
Rune*
341
skipbl(Rune *r, int n, int *np)
342
{
343
	while(n>0 && (*r==' ' || *r=='\t' || *r=='\n')){
344
		--n;
345
		r++;
346
	}
347
	*np = n;
348
	return r;
349
}
350
 
351
Rune*
352
findbl(Rune *r, int n, int *np)
353
{
354
	while(n>0 && *r!=' ' && *r!='\t' && *r!='\n'){
355
		--n;
356
		r++;
357
	}
358
	*np = n;
359
	return r;
360
}
361
 
362
void
363
savemouse(Window *w)
364
{
365
	prevmouse = mouse->xy;
366
	mousew = w;
367
}
368
 
369
int
370
restoremouse(Window *w)
371
{
372
	int did;
373
 
374
	did = 0;
375
	if(mousew!=nil && mousew==w){
376
		moveto(mousectl, prevmouse);
377
		did = 1;
378
	}
379
	mousew = nil;
380
	return did;
381
}
382
 
383
void
384
clearmouse()
385
{
386
	mousew = nil;
387
}
388
 
389
char*
390
estrdup(char *s)
391
{
392
	char *t;
393
 
394
	t = strdup(s);
395
	if(t == nil)
396
		error("strdup failed");
397
	setmalloctag(t, getcallerpc(&s));
398
	return t;
399
}
400
 
401
void*
402
emalloc(uint n)
403
{
404
	void *p;
405
 
406
	p = malloc(n);
407
	if(p == nil)
408
		error("malloc failed");
409
	setmalloctag(p, getcallerpc(&n));
410
	memset(p, 0, n);
411
	return p;
412
}
413
 
414
void*
415
erealloc(void *p, uint n)
416
{
417
	p = realloc(p, n);
418
	if(p == nil)
419
		error("realloc failed");
420
	setmalloctag(p, getcallerpc(&n));
421
	return p;
422
}
423
 
424
/*
425
 * Heuristic city.
426
 */
427
Window*
428
makenewwindow(Text *t)
429
{
430
	Column *c;
431
	Window *w, *bigw, *emptyw;
432
	Text *emptyb;
433
	int i, y, el;
434
 
435
	if(activecol)
436
		c = activecol;
437
	else if(seltext && seltext->col)
438
		c = seltext->col;
439
	else if(t && t->col)
440
		c = t->col;
441
	else{
442
		if(row.ncol==0 && rowadd(&row, nil, -1)==nil)
443
			error("can't make column");
444
		c = row.col[row.ncol-1];
445
	}
446
	activecol = c;
447
	if(t==nil || t->w==nil || c->nw==0)
448
		return coladd(c, nil, nil, -1);
449
 
450
	/* find biggest window and biggest blank spot */
451
	emptyw = c->w[0];
452
	bigw = emptyw;
453
	for(i=1; i<c->nw; i++){
454
		w = c->w[i];
455
		/* use >= to choose one near bottom of screen */
456
		if(w->body.maxlines >= bigw->body.maxlines)
457
			bigw = w;
458
		if(w->body.maxlines-w->body.nlines >= emptyw->body.maxlines-emptyw->body.nlines)
459
			emptyw = w;
460
	}
461
	emptyb = &emptyw->body;
462
	el = emptyb->maxlines-emptyb->nlines;
463
	/* if empty space is big, use it */
464
	if(el>15 || (el>3 && el>(bigw->body.maxlines-1)/2))
465
		y = emptyb->r.min.y+emptyb->nlines*font->height;
466
	else{
467
		/* if this window is in column and isn't much smaller, split it */
468
		if(t->col==c && Dy(t->w->r)>2*Dy(bigw->r)/3)
469
			bigw = t->w;
470
		y = (bigw->r.min.y + bigw->r.max.y)/2;
471
	}
472
	w = coladd(c, nil, nil, y);
473
	if(w->body.maxlines < 2)
474
		colgrow(w->col, w, 1);
475
	return w;
476
}