1 #include <u.h> 2 #include <libc.h> 3 #include <draw.h> 4 #include <memdraw.h> 5 #include <thread.h> 6 #include <cursor.h> 7 #include <mouse.h> 8 #include <keyboard.h> 9 #include <frame.h> 10 #include <plumb.h> 11 #include <html.h> 12 #include "dat.h" 13 #include "fns.h" 14 15 void del(Text *, Text *, int, int, Rune *, int); 16 void delcol(Text *, Text *, int, int, Rune *, int); 17 void cut(Text *, Text *, int, int, Rune *, int); 18 void exit(Text *, Text *, int, int, Rune *, int); 19 void get(Text *, Text *, int, int, Rune *, int); 20 void go(Text *,Text *, int, int, Rune *, int); 21 void google(Text *,Text *, int, int, Rune *, int); 22 void new(Text*, Text *, int, int, Rune *, int); 23 void newcol(Text*, Text *, int, int, Rune *, int); 24 void paste(Text *, Text *, int, int, Rune *, int); 25 void sort(Text *, Text *, int, int, Rune *, int); 26 void stop(Text *, Text *, int, int, Rune *, int); 27 void debug(Text *, Text *, int, int, Rune *, int); 28 29 typedef struct Exectab Exectab; 30 struct Exectab 31 { 32 Rune *name; 33 void (*fn)(Text *, Text *, int, int, Rune *, int); 34 int flag1; 35 int flag2; 36 }; 37 38 Exectab exectab[] = { 39 { L"Back", go, FALSE, XXX }, 40 { L"Cut", cut, TRUE, TRUE }, 41 { L"Debug", debug, XXX, XXX }, 42 { L"Del", del, XXX, XXX }, 43 { L"Delcol", delcol, FALSE, TRUE }, 44 { L"Exit", exit, XXX, XXX }, 45 { L"Get", get, XXX, XXX }, 46 { L"Google", google, XXX, XXX }, 47 { L"New", new, XXX, XXX }, 48 { L"Newcol", newcol, XXX, XXX }, 49 { L"Next", go, TRUE, XXX }, 50 { L"Paste", paste, TRUE, XXX }, 51 { L"Snarf", cut, TRUE, FALSE }, 52 { L"Stop", stop, XXX, XXX }, 53 { L"Sort", sort, XXX, XXX }, 54 { nil, nil, 0, 0 }, 55 }; 56 57 static 58 Exectab* 59 lookup(Rune *r, int n) 60 { 61 Exectab *e; 62 int nr; 63 64 r = skipbl(r, n, &n); 65 if(n == 0) 66 return nil; 67 findbl(r, n, &nr); 68 nr = n-nr; 69 for(e=exectab; e->name; e++) 70 if(runeeq(r, nr, e->name, runestrlen(e->name)) == TRUE) 71 return e; 72 return nil; 73 } 74 75 int 76 isexecc(int c) 77 { 78 if(isalnum(c)) 79 return 1; 80 return c=='<' || c=='|' || c=='>'; 81 } 82 83 void 84 execute(Text *t, uint aq0, uint aq1, Text *) 85 { 86 uint q0, q1; 87 Rune *r, *s; 88 Exectab *e; 89 int c, n; 90 91 q0 = aq0; 92 q1 = aq1; 93 if(q1 == q0){ /* expand to find word (actually file name) */ 94 /* if in selection, choose selection */ 95 if(t->q1>t->q0 && t->q0<=q0 && q0<=t->q1){ 96 q0 = t->q0; 97 q1 = t->q1; 98 }else{ 99 while(q1<t->rs.nr && isexecc(c=t->rs.r[q1]) && c!=':') 100 q1++; 101 while(q0>0 && isexecc(c=t->rs.r[q0-1]) && c!=':') 102 q0--; 103 if(q1 == q0) 104 return; 105 } 106 } 107 r = runemalloc(q1-q0); 108 runemove(r, t->rs.r+q0, q1-q0); 109 e = lookup(r, q1-q0); 110 if(e){ 111 s = skipbl(r, q1-q0, &n); 112 s = findbl(s, n, &n); 113 s = skipbl(s, n, &n); 114 (*e->fn)(t, seltext, e->flag1, e->flag2, s, n); 115 } 116 free(r); 117 } 118 119 void 120 newcol(Text *et, Text *, int, int, Rune *, int) 121 { 122 Column *c; 123 124 c = rowadd(et->row, nil, -1); 125 if(c) 126 winsettag(coladd(c, nil, nil, -1)); 127 } 128 129 void 130 delcol(Text *t, Text *, int, int, Rune *, int) 131 { 132 Column *c; 133 134 c = t->col; 135 if(c==nil || colclean(c)==0) 136 return; 137 138 rowclose(c->row, c, TRUE); 139 } 140 141 void 142 del(Text *et, Text *, int flag1, int, Rune *, int) 143 { 144 if(et->w==nil) 145 return; 146 147 if(flag1 || winclean(et->w, FALSE)) 148 colclose(et->col, et->w, TRUE); 149 } 150 151 void 152 sort(Text *et, Text *, int, int, Rune *, int) 153 { 154 if(et->col) 155 colsort(et->col); 156 } 157 158 void 159 exit(Text *, Text *, int, int, Rune *, int) 160 { 161 sendul(cexit, 0); 162 threadexits(nil); 163 } 164 165 void 166 debug(Text *, Text *, int, int, Rune *, int) 167 { 168 Column *c; 169 int i, j; 170 171 for(j=0; j<row.ncol; j++){ 172 c = row.col[j]; 173 for(i=0; i<c->nw; i++){ 174 fprint(2, "Col: %d; Win: %d\n", j, i); 175 windebug(c->w[i]); 176 } 177 } 178 } 179 180 void 181 stop(Text *t, Text *, int, int, Rune *, int) 182 { 183 if(t==nil || t->w==nil) 184 return; 185 186 pageabort(&t->w->page); 187 } 188 189 void 190 get(Text *t, Text *, int, int, Rune *, int) 191 { 192 Window *w; 193 int dohist; 194 195 if(t==nil || t->w==nil) 196 return; 197 w = t->w; 198 if(w->url.rs.nr == 0) 199 return; 200 201 dohist = FALSE; 202 if(w->page.url==nil || runestreq(w->page.url->act, w->url.rs)==FALSE) 203 dohist = TRUE; 204 205 pageget(&w->page, &w->url.rs, nil, HGet, dohist); 206 } 207 208 void 209 go(Text *et, Text *t, int isnext, int, Rune *, int) 210 { 211 if(et!=nil && et->w!=nil) 212 t = et; 213 if(t==nil || t->w==nil) 214 return; 215 216 wingohist(t->w, isnext); 217 } 218 219 void 220 cut(Text *, Text *t, int dosnarf, int docut, Rune *, int) 221 { 222 Runestr rs; 223 uint u; 224 225 if(selpage){ 226 if(dosnarf && !docut && !eqpt(selpage->top, selpage->bot)) 227 pagesnarf(selpage); 228 return; 229 } 230 if(t==nil){ 231 /* can only happen if seltext == nil */ 232 return; 233 } 234 if(t->q0 > t->q1){ 235 u = t->q0; 236 t->q0 = t->q1; 237 t->q1 =u; 238 } 239 240 if(t->q0 == t->q1) 241 return; 242 243 if(dosnarf){ 244 rs.nr = t->q1-t->q0; 245 rs.r = runemalloc(rs.nr); 246 runemove(rs.r, t->rs.r+t->q0, rs.nr); 247 putsnarf(&rs); 248 closerunestr(&rs); 249 } 250 if(docut){ 251 textdelete(t, t->q0, t->q1); 252 textsetselect(t, t->q0, t->q0); 253 if(t->w) 254 textscrdraw(t); 255 }else if(dosnarf) /* Snarf command */ 256 argtext = t; 257 } 258 259 void 260 paste(Text *, Text *t, int selectall, int, Rune *, int) 261 { 262 Runestr rs; 263 uint q1; 264 265 if(t == nil) 266 return; 267 268 getsnarf(&rs); 269 if(rs.nr == 0) 270 return; 271 272 cut(t, t, FALSE, TRUE, nil, 0); 273 textinsert(t, t->q0, rs.r, rs.nr); 274 q1 = t->q0+rs.nr; 275 if(selectall) 276 textsetselect(t, t->q0, q1); 277 else 278 textsetselect(t, q1, q1); 279 if(t->w) 280 textscrdraw(t); 281 282 closerunestr(&rs); 283 } 284 285 typedef struct Expand Expand; 286 287 struct Expand 288 { 289 uint q0; 290 uint q1; 291 Rune *name; 292 int nname; 293 int jump; 294 union{ 295 Text *at; 296 Rune *ar; 297 }; 298 int (*agetc)(void*, uint); 299 int a0; 300 int a1; 301 }; 302 303 int 304 expand(Text *t, uint q0, uint q1, Expand *e) 305 { 306 memset(e, 0, sizeof *e); 307 308 /* if in selection, choose selection */ 309 e->jump = TRUE; 310 if(q1==q0 && t->q1>t->q0 && t->q0<=q0 && q0<=t->q1){ 311 q0 = t->q0; 312 q1 = t->q1; 313 if(t->what == Tag) 314 e->jump = FALSE; 315 } 316 if(q0 == q1){ 317 while(q1<t->rs.nr && isalnum(t->rs.r[q1])) 318 q1++; 319 while(q0>0 && isalnum(t->rs.r[q0-1])) 320 q0--; 321 } 322 e->q0 = q0; 323 e->q1 = q1; 324 return q1 > q0; 325 } 326 327 void 328 look3(Text *t, uint q0, uint q1) 329 { 330 Expand e; 331 Text *ct; 332 Runestr rs; 333 char buf[32]; 334 Rune *r, c; 335 uint p; 336 int n; 337 338 ct = seltext; 339 if(ct == nil) 340 ct = seltext = t; 341 if(expand(t, q0, q1, &e) == FALSE) 342 return; 343 if(plumbsendfd >= 0){ 344 /* send whitespace-delimited word to plumber */ 345 buf[0] = '\0'; 346 if(q1 == q0){ 347 if(t->q1>t->q0 && t->q0<=q0 && q0<=t->q1){ 348 q0 = t->q0; 349 q1 = t->q1; 350 }else{ 351 p = q0; 352 while(q0>0 && (c=t->rs.r[q0-1])!=L' ' && c!=L'\t' && c!=L'\n') 353 q0--; 354 while(q1<t->rs.nr && (c=t->rs.r[q1])!=L' ' && c!=L'\t' && c!=L'\n') 355 q1++; 356 if(q1 == q0) 357 return; 358 sprint(buf, "click=%d", p-q0); 359 } 360 } 361 rs.r = runemalloc(q1-q0); 362 runemove(rs.r, t->rs.r+q0, q1-q0); 363 rs.nr = q1-q0; 364 if(plumbrunestr(&rs, buf) >= 0){ 365 closerunestr(&rs); 366 return; 367 } 368 /* plumber failed to match; fall through */ 369 } 370 if(t == ct) 371 textsetselect(ct, e.q1, e.q1); 372 n = e.q1 - e.q0; 373 r = runemalloc(n); 374 runemove(r, t->rs.r+e.q0, n); 375 if(search(ct, r, n) && e.jump) 376 moveto(mousectl, addpt(frptofchar(ct, ct->p0), Pt(4, ct->font->height-4))); 377 378 free(r); 379 } 380 381 int 382 search(Text *ct, Rune *r, uint n) 383 { 384 uint q, nb, maxn; 385 int around; 386 Rune *s, *b, *c; 387 388 if(n==0 || n>ct->rs.nr || 2*n>RBUFSIZE) 389 return FALSE; 390 391 maxn = max(n*2, RBUFSIZE); 392 s = runemalloc(RBUFSIZE); 393 b = s; 394 nb = 0; 395 b[nb] = 0; 396 around = 0; 397 q = ct->q1; 398 for(;;){ 399 if(q >= ct->rs.nr){ 400 q = 0; 401 around = 1; 402 nb = 0; 403 b[nb] = 0; 404 } 405 if(nb > 0){ 406 c = runestrchr(b, r[0]); 407 if(c == nil){ 408 q += nb; 409 nb = 0; 410 b[nb] = 0; 411 if(around && q>=ct->q1) 412 break; 413 continue; 414 } 415 q += (c-b); 416 nb -= (c-b); 417 b = c; 418 } 419 /* reload if buffer covers neither string nor rest of file */ 420 if(nb<n && nb!=ct->rs.nr-q){ 421 nb = ct->rs.nr-q; 422 if(nb >= maxn) 423 nb = maxn-1; 424 runemove(s, ct->rs.r+q, nb); 425 b = s; 426 b[nb] = '\0'; 427 } 428 /* this runeeq is fishy but the null at b[nb] makes it safe */ 429 if(runeeq(b, n, r, n) == TRUE){ 430 if(ct->w) 431 textshow(ct, q, q+n, 1); 432 else{ 433 ct->q0 = q; 434 ct->q1 = q+n; 435 } 436 seltext = ct; 437 free(s); 438 return TRUE; 439 } 440 if(around && q>=ct->q1) 441 break; 442 --nb; 443 b++; 444 q++; 445 } 446 free(s); 447 return FALSE; 448 } 449 450 Window* 451 lookpage(Rune *s, int n) 452 { 453 int i, j; 454 Window *w; 455 Column *c; 456 Page *p; 457 458 /* avoid terminal slash on directories */ 459 if(n>1 && s[n-1] == '/') 460 --n; 461 for(j=0; j<row.ncol; j++){ 462 c = row.col[j]; 463 for(i=0; i<c->nw; i++){ 464 w = c->w[i]; 465 p = &w->page; 466 if(p->url && runeeq(p->url->src.r, p->url->src.nr, s, n)) 467 if(w->col != nil) 468 return w; 469 } 470 } 471 return nil; 472 } 473 474 Window * 475 openpage(Page *p, Runestr *rs) 476 { 477 Window *w; 478 479 if(!validurl(rs->r)) 480 return nil; 481 482 w = lookpage(rs->r, rs->nr); 483 if(w){ 484 p = &w->page; 485 if(!p->col->safe && Dy(p->r)==0) /* window is obscured by full-column window */ 486 colgrow(p->col, p->col->w[0], 1); 487 }else{ 488 w = makenewwindow(p); 489 winsettag(w); 490 pageget(&w->page, rs, nil, HGet, TRUE); 491 } 492 return w; 493 } 494 495 void 496 plumblook(Plumbmsg *m) 497 { 498 Runestr rs; 499 500 if(m->ndata >= BUFSIZE){ 501 fprint(2, "insanely long file name (%d bytes) in plumb message (%.32s...)\n", m->ndata, m->data); 502 return; 503 } 504 if(m->data[0] == '\0') 505 return; 506 507 bytetorunestr(m->data, &rs); 508 openpage(nil, &rs); 509 closerunestr(&rs); 510 } 511 512 void 513 new(Text *et, Text *, int, int, Rune *, int) 514 { 515 if(et->col != nil) 516 winsettag(coladd(et->col, nil, nil, -1)); 517 } 518 519 void 520 google(Text *, Text *, int, int, Rune *arg, int narg) 521 { 522 Runestr rs; 523 Rune *s; 524 525 s = ucvt(arg); 526 rs.r = runesmprint("http://www.google.com/search?hl=en&ie=UTF-8&q=%.*S", narg, s); 527 rs.nr = runestrlen(rs.r); 528 openpage(nil, &rs); 529 free(s); 530 closerunestr(&rs); 531 } 532