fixed insert segfault, added nextrune
849f1dd7
1 file(s) · +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); |
|