fixed insert segfault, added nextrune 849f1dd7
Connor Lane Smith · 2010-08-12 15:35 1 file(s) · +35 −37
dmenu.c +35 −37
15 15
#define INRECT(x,y,rx,ry,rw,rh) ((x) >= (rx) && (x) < (rx)+(rw) && (y) >= (ry) && (y) < (ry)+(rh))
16 16
#define MIN(a,b)                ((a) < (b) ? (a) : (b))
17 17
#define MAX(a,b)                ((a) > (b) ? (a) : (b))
18 -
#define UTF8_CODEPOINT(c)       (((c) & 0xc0) != 0x80)
19 18
20 19
typedef struct Item Item;
21 20
struct Item {
32 31
static void insert(const char *s, ssize_t n);
33 32
static void keypress(XKeyEvent *ev);
34 33
static void match(void);
35 -
static void paste(Atom atom);
34 +
static size_t nextrune(int incr);
35 +
static void paste(void);
36 36
static void readstdin(void);
37 37
static void run(void);
38 38
static void setup(void);
52 52
static unsigned int promptw;
53 53
static unsigned long normcol[ColLast];
54 54
static unsigned long selcol[ColLast];
55 -
static Atom clip, utf8;
55 +
static Atom utf8;
56 56
static Bool topbar = True;
57 57
static DC *dc;
58 58
static Item *items = NULL;
159 159
160 160
void
161 161
insert(const char *s, ssize_t n) {
162 -
	memmove(text + cursor + n, text + cursor, sizeof text - cursor - n);
162 +
	if(strlen(text) + n > sizeof text - 1)
163 +
		return;
164 +
	memmove(text + cursor + n, text + cursor, sizeof text - cursor - MAX(n, 0));
163 165
	if(n > 0)
164 166
		memcpy(text + cursor, s, n);
165 167
	cursor += n;
169 171
void
170 172
keypress(XKeyEvent *ev) {
171 173
	char buf[32];
172 -
	int n;
173 174
	size_t len;
174 175
	KeySym ksym;
175 176
217 218
			ksym = XK_Up;
218 219
			break;
219 220
		case XK_u:  /* delete left */
220 -
			insert(NULL, -cursor);
221 +
			insert(NULL, 0 - cursor);
221 222
			break;
222 223
		case XK_w:  /* delete word */
223 -
			if(cursor == 0)
224 -
				return;
225 -
			n = 0;
226 -
			while(cursor - n++ > 0 && text[cursor - n] == ' ');
227 -
			while(cursor - n++ > 0 && text[cursor - n] != ' ');
228 -
			insert(NULL, 1-n);
224 +
			while(cursor > 0 && text[nextrune(-1)] == ' ')
225 +
				insert(NULL, nextrune(-1) - cursor);
226 +
			while(cursor > 0 && text[nextrune(-1)] != ' ')
227 +
				insert(NULL, nextrune(-1) - cursor);
229 228
			break;
230 229
		case XK_y:  /* paste selection */
231 -
			XConvertSelection(dc->dpy, XA_PRIMARY, utf8, clip, win, CurrentTime);
230 +
			XConvertSelection(dc->dpy, XA_PRIMARY, utf8, utf8, win, CurrentTime);
232 231
			return;
233 232
		}
234 233
	}
235 234
	switch(ksym) {
236 235
	default:
237 236
		if(isprint(*buf))
238 -
			insert(buf, MIN(strlen(buf), sizeof text - cursor));
239 -
		break;
240 -
	case XK_BackSpace:
241 -
		if(cursor == 0)
242 -
			return;
243 -
		for(n = 1; cursor - n > 0 && !UTF8_CODEPOINT(text[cursor - n]); n++);
244 -
		insert(NULL, -n);
237 +
			insert(buf, strlen(buf));
245 238
		break;
246 239
	case XK_Delete:
247 240
		if(cursor == len)
248 241
			return;
249 -
		for(n = 1; cursor + n < len && !UTF8_CODEPOINT(text[cursor + n]); n++);
250 -
		cursor += n;
251 -
		insert(NULL, -n);
242 +
		cursor = nextrune(+1);
243 +
	case XK_BackSpace:
244 +
		if(cursor > 0)
245 +
			insert(NULL, nextrune(-1) - cursor);
252 246
		break;
253 247
	case XK_End:
254 248
		if(cursor < len) {
274 268
		break;
275 269
	case XK_Left:
276 270
		if(cursor > 0 && (!sel || !sel->left || lines > 0)) {
277 -
			while(cursor-- > 0 && !UTF8_CODEPOINT(text[cursor]));
271 +
			cursor = nextrune(-1);
278 272
			break;
279 273
		}
280 274
		else if(lines > 0)
281 275
			return;
282 276
	case XK_Up:
283 -
		if(!sel || !sel->left)
284 -
			return;
285 -
		if((sel = sel->left)->right == curr) {
277 +
		if(sel && sel->left && (sel = sel->left)->right == curr) {
286 278
			curr = prev;
287 279
			calcoffsets();
288 280
		}
306 298
		exit(EXIT_SUCCESS);
307 299
	case XK_Right:
308 300
		if(cursor < len) {
309 -
			while(cursor++ < len && !UTF8_CODEPOINT(text[cursor]));
301 +
			cursor = nextrune(+1);
310 302
			break;
311 303
		}
312 304
		else if(lines > 0)
313 305
			return;
314 306
	case XK_Down:
315 -
		if(!sel || !sel->right)
316 -
			return;
317 -
		if((sel = sel->right) == next) {
307 +
		if(sel && sel->right && (sel = sel->right) == next) {
318 308
			curr = next;
319 309
			calcoffsets();
320 310
		}
370 360
	calcoffsets();
371 361
}
372 362
363 +
size_t
364 +
nextrune(int incr) {
365 +
	size_t n, len;
366 +
367 +
	len = strlen(text);
368 +
	for(n = cursor + incr; n >= 0 && n < len && (text[n] & 0xc0) == 0x80; n += incr);
369 +
	return n;
370 +
}
371 +
373 372
void
374 -
paste(Atom atom) {
373 +
paste(void) {
375 374
	char *p, *q;
376 375
	int di;
377 376
	unsigned long dl;
378 377
	Atom da;
379 378
380 -
	XGetWindowProperty(dc->dpy, win, atom, 0, sizeof text - cursor, False,
379 +
	XGetWindowProperty(dc->dpy, win, utf8, 0, (sizeof text / 4) + 1, False,
381 380
	                   utf8, &da, &di, &dl, &dl, (unsigned char **)&p);
382 381
	insert(p, (q = strchr(p, '\n')) ? q-p : strlen(p));
383 382
	XFree(p);
396 395
			eprintf("cannot malloc %u bytes\n", sizeof *item);
397 396
		if(!(item->text = strdup(buf)))
398 397
			eprintf("cannot strdup %u bytes\n", strlen(buf)+1);
398 +
		item->next = item->left = item->right = NULL;
399 399
		inputw = MAX(inputw, textw(dc, item->text));
400 -
		item->next = item->left = item->right = NULL;
401 400
	}
402 401
}
403 402
415 414
			keypress(&ev.xkey);
416 415
			break;
417 416
		case SelectionNotify:
418 -
			if(ev.xselection.property != None)
419 -
				paste(ev.xselection.property);
417 +
			if(ev.xselection.property == utf8)
418 +
				paste();
420 419
			break;
421 420
		case VisibilityNotify:
422 421
			if(ev.xvisibility.state != VisibilityUnobscured)
437 436
	screen = DefaultScreen(dc->dpy);
438 437
	root = RootWindow(dc->dpy, screen);
439 438
	utf8 = XInternAtom(dc->dpy, "UTF8_STRING", False);
440 -
	clip = XInternAtom(dc->dpy, "_DMENU_STRING", False);
441 439
442 440
	normcol[ColBG] = getcolor(dc, normbgcolor);
443 441
	normcol[ColFG] = getcolor(dc, normfgcolor);