buffer.c (16262B)
1 /* $Id$ */ 2 #include "fm.h" 3 4 #ifdef USE_MOUSE 5 #ifdef USE_GPM 6 #include <gpm.h> 7 #endif 8 #if defined(USE_GPM) || defined(USE_SYSMOUSE) 9 extern int do_getch(); 10 #define getch() do_getch() 11 #endif /* USE_GPM */ 12 #endif /* USE_MOUSE */ 13 14 #ifdef __EMX__ 15 #include <sys/kbdscan.h> 16 #include <strings.h> 17 #endif 18 char *NullLine = ""; 19 Lineprop NullProp[] = { 0 }; 20 21 /* 22 * Buffer creation 23 */ 24 Buffer * 25 newBuffer(int width) 26 { 27 Buffer *n; 28 29 n = New(Buffer); 30 if (n == NULL) 31 return NULL; 32 bzero((void *)n, sizeof(Buffer)); 33 n->width = width; 34 n->COLS = COLS; 35 n->LINES = LASTLINE; 36 n->currentURL.scheme = SCM_UNKNOWN; 37 n->baseURL = NULL; 38 n->baseTarget = NULL; 39 n->buffername = ""; 40 n->bufferprop = BP_NORMAL; 41 n->clone = New(int); 42 *n->clone = 1; 43 n->trbyte = 0; 44 #ifdef USE_SSL 45 n->ssl_certificate = NULL; 46 #endif 47 #ifdef USE_M17N 48 n->auto_detect = WcOption.auto_detect; 49 #endif 50 return n; 51 } 52 53 /* 54 * Create null buffer 55 */ 56 Buffer * 57 nullBuffer(void) 58 { 59 Buffer *b; 60 61 b = newBuffer(COLS); 62 b->buffername = "*Null*"; 63 return b; 64 } 65 66 /* 67 * clearBuffer: clear buffer content 68 */ 69 void 70 clearBuffer(Buffer *buf) 71 { 72 buf->firstLine = buf->topLine = buf->currentLine = buf->lastLine = NULL; 73 buf->allLine = 0; 74 } 75 76 /* 77 * discardBuffer: free buffer structure 78 */ 79 80 void 81 discardBuffer(Buffer *buf) 82 { 83 int i; 84 Buffer *b; 85 86 #ifdef USE_IMAGE 87 deleteImage(buf); 88 #endif 89 clearBuffer(buf); 90 for (i = 0; i < MAX_LB; i++) { 91 b = buf->linkBuffer[i]; 92 if (b == NULL) 93 continue; 94 b->linkBuffer[REV_LB[i]] = NULL; 95 } 96 if (buf->savecache) 97 unlink(buf->savecache); 98 if (--(*buf->clone)) 99 return; 100 if (buf->pagerSource) 101 ISclose(buf->pagerSource); 102 if (buf->sourcefile && 103 (!buf->real_type || strncasecmp(buf->real_type, "image/", 6))) { 104 if (buf->real_scheme != SCM_LOCAL || buf->bufferprop & BP_FRAME) 105 unlink(buf->sourcefile); 106 } 107 if (buf->header_source) 108 unlink(buf->header_source); 109 if (buf->mailcap_source) 110 unlink(buf->mailcap_source); 111 while (buf->frameset) { 112 deleteFrameSet(buf->frameset); 113 buf->frameset = popFrameTree(&(buf->frameQ)); 114 } 115 } 116 117 /* 118 * namedBuffer: Select buffer which have specified name 119 */ 120 Buffer * 121 namedBuffer(Buffer *first, char *name) 122 { 123 Buffer *buf; 124 125 if (!strcmp(first->buffername, name)) { 126 return first; 127 } 128 for (buf = first; buf->nextBuffer != NULL; buf = buf->nextBuffer) { 129 if (!strcmp(buf->nextBuffer->buffername, name)) { 130 return buf->nextBuffer; 131 } 132 } 133 return NULL; 134 } 135 136 /* 137 * deleteBuffer: delete buffer 138 */ 139 Buffer * 140 deleteBuffer(Buffer *first, Buffer *delbuf) 141 { 142 Buffer *buf, *b; 143 144 if (first == delbuf && first->nextBuffer != NULL) { 145 buf = first->nextBuffer; 146 discardBuffer(first); 147 return buf; 148 } 149 if ((buf = prevBuffer(first, delbuf)) != NULL) { 150 b = buf->nextBuffer; 151 buf->nextBuffer = b->nextBuffer; 152 discardBuffer(b); 153 } 154 return first; 155 } 156 157 /* 158 * replaceBuffer: replace buffer 159 */ 160 Buffer * 161 replaceBuffer(Buffer *first, Buffer *delbuf, Buffer *newbuf) 162 { 163 Buffer *buf; 164 165 if (delbuf == NULL) { 166 newbuf->nextBuffer = first; 167 return newbuf; 168 } 169 if (first == delbuf) { 170 newbuf->nextBuffer = delbuf->nextBuffer; 171 discardBuffer(delbuf); 172 return newbuf; 173 } 174 if (delbuf && (buf = prevBuffer(first, delbuf))) { 175 buf->nextBuffer = newbuf; 176 newbuf->nextBuffer = delbuf->nextBuffer; 177 discardBuffer(delbuf); 178 return first; 179 } 180 newbuf->nextBuffer = first; 181 return newbuf; 182 } 183 184 Buffer * 185 nthBuffer(Buffer *firstbuf, int n) 186 { 187 int i; 188 Buffer *buf = firstbuf; 189 190 if (n < 0) 191 return firstbuf; 192 for (i = 0; i < n; i++) { 193 if (buf == NULL) 194 return NULL; 195 buf = buf->nextBuffer; 196 } 197 return buf; 198 } 199 200 static void 201 writeBufferName(Buffer *buf, int n) 202 { 203 Str msg; 204 int all; 205 206 all = buf->allLine; 207 if (all == 0 && buf->lastLine != NULL) 208 all = buf->lastLine->linenumber; 209 move(n, 0); 210 /* FIXME: gettextize? */ 211 msg = Sprintf("<%s> [%d lines]", buf->buffername, all); 212 if (buf->filename != NULL) { 213 switch (buf->currentURL.scheme) { 214 case SCM_LOCAL: 215 case SCM_LOCAL_CGI: 216 if (strcmp(buf->currentURL.file, "-")) { 217 Strcat_char(msg, ' '); 218 Strcat_charp(msg, conv_from_system(buf->currentURL.real_file)); 219 } 220 break; 221 case SCM_UNKNOWN: 222 case SCM_MISSING: 223 break; 224 default: 225 Strcat_char(msg, ' '); 226 Strcat(msg, parsedURL2Str(&buf->currentURL)); 227 break; 228 } 229 } 230 addnstr_sup(msg->ptr, COLS - 1); 231 } 232 233 234 /* 235 * gotoLine: go to line number 236 */ 237 void 238 gotoLine(Buffer *buf, int n) 239 { 240 char msg[32]; 241 Line *l = buf->firstLine; 242 243 if (l == NULL) 244 return; 245 if (buf->pagerSource && !(buf->bufferprop & BP_CLOSE)) { 246 if (buf->lastLine->linenumber < n) 247 getNextPage(buf, n - buf->lastLine->linenumber); 248 while ((buf->lastLine->linenumber < n) && 249 (getNextPage(buf, 1) != NULL)) ; 250 } 251 if (l->linenumber > n) { 252 /* FIXME: gettextize? */ 253 sprintf(msg, "First line is #%ld", l->linenumber); 254 set_delayed_message(msg); 255 buf->topLine = buf->currentLine = l; 256 return; 257 } 258 if (buf->lastLine->linenumber < n) { 259 l = buf->lastLine; 260 /* FIXME: gettextize? */ 261 sprintf(msg, "Last line is #%ld", buf->lastLine->linenumber); 262 set_delayed_message(msg); 263 buf->currentLine = l; 264 buf->topLine = lineSkip(buf, buf->currentLine, -(buf->LINES - 1), 265 FALSE); 266 return; 267 } 268 for (; l != NULL; l = l->next) { 269 if (l->linenumber >= n) { 270 buf->currentLine = l; 271 if (n < buf->topLine->linenumber || 272 buf->topLine->linenumber + buf->LINES <= n) 273 buf->topLine = lineSkip(buf, l, -(buf->LINES + 1) / 2, FALSE); 274 break; 275 } 276 } 277 } 278 279 /* 280 * gotoRealLine: go to real line number 281 */ 282 void 283 gotoRealLine(Buffer *buf, int n) 284 { 285 char msg[32]; 286 Line *l = buf->firstLine; 287 288 if (l == NULL) 289 return; 290 if (buf->pagerSource && !(buf->bufferprop & BP_CLOSE)) { 291 if (buf->lastLine->real_linenumber < n) 292 getNextPage(buf, n - buf->lastLine->real_linenumber); 293 while ((buf->lastLine->real_linenumber < n) && 294 (getNextPage(buf, 1) != NULL)) ; 295 } 296 if (l->real_linenumber > n) { 297 /* FIXME: gettextize? */ 298 sprintf(msg, "First line is #%ld", l->real_linenumber); 299 set_delayed_message(msg); 300 buf->topLine = buf->currentLine = l; 301 return; 302 } 303 if (buf->lastLine->real_linenumber < n) { 304 l = buf->lastLine; 305 /* FIXME: gettextize? */ 306 sprintf(msg, "Last line is #%ld", buf->lastLine->real_linenumber); 307 set_delayed_message(msg); 308 buf->currentLine = l; 309 buf->topLine = lineSkip(buf, buf->currentLine, -(buf->LINES - 1), 310 FALSE); 311 return; 312 } 313 for (; l != NULL; l = l->next) { 314 if (l->real_linenumber >= n) { 315 buf->currentLine = l; 316 if (n < buf->topLine->real_linenumber || 317 buf->topLine->real_linenumber + buf->LINES <= n) 318 buf->topLine = lineSkip(buf, l, -(buf->LINES + 1) / 2, FALSE); 319 break; 320 } 321 } 322 } 323 324 325 static Buffer * 326 listBuffer(Buffer *top, Buffer *current) 327 { 328 int i, c = 0; 329 Buffer *buf = top; 330 331 move(0, 0); 332 #ifdef USE_COLOR 333 if (useColor) { 334 setfcolor(basic_color); 335 #ifdef USE_BG_COLOR 336 setbcolor(bg_color); 337 #endif /* USE_BG_COLOR */ 338 } 339 #endif /* USE_COLOR */ 340 clrtobotx(); 341 for (i = 0; i < LASTLINE; i++) { 342 if (buf == current) { 343 c = i; 344 standout(); 345 } 346 writeBufferName(buf, i); 347 if (buf == current) { 348 standend(); 349 clrtoeolx(); 350 move(i, 0); 351 toggle_stand(); 352 } 353 else 354 clrtoeolx(); 355 if (buf->nextBuffer == NULL) { 356 move(i + 1, 0); 357 clrtobotx(); 358 break; 359 } 360 buf = buf->nextBuffer; 361 } 362 standout(); 363 /* FIXME: gettextize? */ 364 message("Buffer selection mode: SPC for select / D for delete buffer", 0, 365 0); 366 standend(); 367 /* 368 * move(LASTLINE, COLS - 1); */ 369 move(c, 0); 370 refresh(); 371 return buf->nextBuffer; 372 } 373 374 375 /* 376 * Select buffer visually 377 */ 378 Buffer * 379 selectBuffer(Buffer *firstbuf, Buffer *currentbuf, char *selectchar) 380 { 381 int i, cpoint, /* Current Buffer Number */ 382 spoint, /* Current Line on Screen */ 383 maxbuf, sclimit = LASTLINE; /* Upper limit of line * number in 384 * the * screen */ 385 Buffer *buf, *topbuf; 386 char c; 387 388 i = cpoint = 0; 389 for (buf = firstbuf; buf != NULL; buf = buf->nextBuffer) { 390 if (buf == currentbuf) 391 cpoint = i; 392 i++; 393 } 394 maxbuf = i; 395 396 if (cpoint >= sclimit) { 397 spoint = sclimit / 2; 398 topbuf = nthBuffer(firstbuf, cpoint - spoint); 399 } 400 else { 401 topbuf = firstbuf; 402 spoint = cpoint; 403 } 404 listBuffer(topbuf, currentbuf); 405 406 for (;;) { 407 if ((c = getch()) == ESC_CODE) { 408 if ((c = getch()) == '[' || c == 'O') { 409 switch (c = getch()) { 410 case 'A': 411 c = 'k'; 412 break; 413 case 'B': 414 c = 'j'; 415 break; 416 case 'C': 417 c = ' '; 418 break; 419 case 'D': 420 c = 'B'; 421 break; 422 } 423 } 424 } 425 #ifdef __EMX__ 426 else if (!c) 427 switch (getch()) { 428 case K_UP: 429 c = 'k'; 430 break; 431 case K_DOWN: 432 c = 'j'; 433 break; 434 case K_RIGHT: 435 c = ' '; 436 break; 437 case K_LEFT: 438 c = 'B'; 439 } 440 #endif 441 switch (c) { 442 case CTRL_N: 443 case 'j': 444 if (spoint < sclimit - 1) { 445 if (currentbuf->nextBuffer == NULL) 446 continue; 447 writeBufferName(currentbuf, spoint); 448 currentbuf = currentbuf->nextBuffer; 449 cpoint++; 450 spoint++; 451 standout(); 452 writeBufferName(currentbuf, spoint); 453 standend(); 454 move(spoint, 0); 455 toggle_stand(); 456 } 457 else if (cpoint < maxbuf - 1) { 458 topbuf = currentbuf; 459 currentbuf = currentbuf->nextBuffer; 460 cpoint++; 461 spoint = 1; 462 listBuffer(topbuf, currentbuf); 463 } 464 break; 465 case CTRL_P: 466 case 'k': 467 if (spoint > 0) { 468 writeBufferName(currentbuf, spoint); 469 currentbuf = nthBuffer(topbuf, --spoint); 470 cpoint--; 471 standout(); 472 writeBufferName(currentbuf, spoint); 473 standend(); 474 move(spoint, 0); 475 toggle_stand(); 476 } 477 else if (cpoint > 0) { 478 i = cpoint - sclimit; 479 if (i < 0) 480 i = 0; 481 cpoint--; 482 spoint = cpoint - i; 483 currentbuf = nthBuffer(firstbuf, cpoint); 484 topbuf = nthBuffer(firstbuf, i); 485 listBuffer(topbuf, currentbuf); 486 } 487 break; 488 default: 489 *selectchar = c; 490 return currentbuf; 491 } 492 /* 493 * move(LASTLINE, COLS - 1); 494 */ 495 move(spoint, 0); 496 refresh(); 497 } 498 } 499 500 /* 501 * Reshape HTML buffer 502 */ 503 void 504 reshapeBuffer(Buffer *buf) 505 { 506 URLFile f; 507 Buffer sbuf; 508 #ifdef USE_M17N 509 wc_uint8 old_auto_detect = WcOption.auto_detect; 510 #endif 511 512 if (!buf->need_reshape) 513 return; 514 buf->need_reshape = FALSE; 515 buf->width = INIT_BUFFER_WIDTH; 516 if (buf->sourcefile == NULL) 517 return; 518 init_stream(&f, SCM_LOCAL, NULL); 519 examineFile(buf->mailcap_source ? buf->mailcap_source : buf->sourcefile, 520 &f); 521 if (f.stream == NULL) 522 return; 523 copyBuffer(&sbuf, buf); 524 clearBuffer(buf); 525 while (buf->frameset) { 526 deleteFrameSet(buf->frameset); 527 buf->frameset = popFrameTree(&(buf->frameQ)); 528 } 529 530 buf->href = NULL; 531 buf->name = NULL; 532 buf->img = NULL; 533 buf->formitem = NULL; 534 buf->formlist = NULL; 535 buf->linklist = NULL; 536 buf->maplist = NULL; 537 if (buf->hmarklist) 538 buf->hmarklist->nmark = 0; 539 if (buf->imarklist) 540 buf->imarklist->nmark = 0; 541 542 if (buf->header_source) { 543 if (buf->currentURL.scheme != SCM_LOCAL || 544 buf->mailcap_source || !strcmp(buf->currentURL.file, "-")) { 545 URLFile h; 546 init_stream(&h, SCM_LOCAL, NULL); 547 examineFile(buf->header_source, &h); 548 if (h.stream) { 549 readHeader(&h, buf, TRUE, NULL); 550 UFclose(&h); 551 } 552 } 553 else if (buf->search_header) /* -m option */ 554 readHeader(&f, buf, TRUE, NULL); 555 } 556 557 #ifdef USE_M17N 558 WcOption.auto_detect = WC_OPT_DETECT_OFF; 559 UseContentCharset = FALSE; 560 #endif 561 if (is_html_type(buf->type)) 562 loadHTMLBuffer(&f, buf); 563 else 564 loadBuffer(&f, buf); 565 UFclose(&f); 566 #ifdef USE_M17N 567 WcOption.auto_detect = old_auto_detect; 568 UseContentCharset = TRUE; 569 #endif 570 571 buf->height = LASTLINE + 1; 572 if (buf->firstLine && sbuf.firstLine) { 573 Line *cur = sbuf.currentLine; 574 int n; 575 576 buf->pos = sbuf.pos + cur->bpos; 577 while (cur->bpos && cur->prev) 578 cur = cur->prev; 579 if (cur->real_linenumber > 0) 580 gotoRealLine(buf, cur->real_linenumber); 581 else 582 gotoLine(buf, cur->linenumber); 583 n = (buf->currentLine->linenumber - buf->topLine->linenumber) 584 - (cur->linenumber - sbuf.topLine->linenumber); 585 if (n) { 586 buf->topLine = lineSkip(buf, buf->topLine, n, FALSE); 587 if (cur->real_linenumber > 0) 588 gotoRealLine(buf, cur->real_linenumber); 589 else 590 gotoLine(buf, cur->linenumber); 591 } 592 buf->pos -= buf->currentLine->bpos; 593 if (FoldLine && !is_html_type(buf->type)) 594 buf->currentColumn = 0; 595 else 596 buf->currentColumn = sbuf.currentColumn; 597 arrangeCursor(buf); 598 } 599 if (buf->check_url & CHK_URL) 600 chkURLBuffer(buf); 601 #ifdef USE_NNTP 602 if (buf->check_url & CHK_NMID) 603 chkNMIDBuffer(buf); 604 if (buf->real_scheme == SCM_NNTP || buf->real_scheme == SCM_NEWS) 605 reAnchorNewsheader(buf); 606 #endif 607 formResetBuffer(buf, sbuf.formitem); 608 } 609 610 /* shallow copy */ 611 void 612 copyBuffer(Buffer *a, Buffer *b) 613 { 614 readBufferCache(b); 615 bcopy((void *)b, (void *)a, sizeof(Buffer)); 616 } 617 618 Buffer * 619 prevBuffer(Buffer *first, Buffer *buf) 620 { 621 Buffer *b; 622 623 for (b = first; b != NULL && b->nextBuffer != buf; b = b->nextBuffer) ; 624 return b; 625 } 626 627 #define fwrite1(d, f) (fwrite(&d, sizeof(d), 1, f)==0) 628 #define fread1(d, f) (fread(&d, sizeof(d), 1, f)==0) 629 630 int 631 writeBufferCache(Buffer *buf) 632 { 633 Str tmp; 634 FILE *cache = NULL; 635 Line *l; 636 #ifdef USE_ANSI_COLOR 637 int colorflag; 638 #endif 639 640 if (buf->savecache) 641 return -1; 642 643 if (buf->firstLine == NULL) 644 goto _error1; 645 646 tmp = tmpfname(TMPF_CACHE, NULL); 647 buf->savecache = tmp->ptr; 648 cache = fopen(buf->savecache, "w"); 649 if (!cache) 650 goto _error1; 651 652 if (fwrite1(buf->currentLine->linenumber, cache) || 653 fwrite1(buf->topLine->linenumber, cache)) 654 goto _error; 655 656 for (l = buf->firstLine; l; l = l->next) { 657 if (fwrite1(l->real_linenumber, cache) || 658 fwrite1(l->usrflags, cache) || 659 fwrite1(l->width, cache) || 660 fwrite1(l->len, cache) || 661 fwrite1(l->size, cache) || 662 fwrite1(l->bpos, cache) || fwrite1(l->bwidth, cache)) 663 goto _error; 664 if (l->bpos == 0) { 665 if (fwrite(l->lineBuf, 1, l->size, cache) < l->size || 666 fwrite(l->propBuf, sizeof(Lineprop), l->size, cache) < l->size) 667 goto _error; 668 } 669 #ifdef USE_ANSI_COLOR 670 colorflag = l->colorBuf ? 1 : 0; 671 if (fwrite1(colorflag, cache)) 672 goto _error; 673 if (colorflag) { 674 if (l->bpos == 0) { 675 if (fwrite(l->colorBuf, sizeof(Linecolor), l->size, cache) < 676 l->size) 677 goto _error; 678 } 679 } 680 #endif 681 } 682 683 fclose(cache); 684 return 0; 685 _error: 686 fclose(cache); 687 unlink(buf->savecache); 688 _error1: 689 buf->savecache = NULL; 690 return -1; 691 } 692 693 int 694 readBufferCache(Buffer *buf) 695 { 696 FILE *cache; 697 Line *l = NULL, *prevl = NULL, *basel = NULL; 698 long lnum = 0, clnum, tlnum; 699 #ifdef USE_ANSI_COLOR 700 int colorflag; 701 #endif 702 703 if (buf->savecache == NULL) 704 return -1; 705 706 cache = fopen(buf->savecache, "r"); 707 if (cache == NULL || fread1(clnum, cache) || fread1(tlnum, cache)) { 708 buf->savecache = NULL; 709 return -1; 710 } 711 712 while (!feof(cache)) { 713 lnum++; 714 prevl = l; 715 l = New(Line); 716 l->prev = prevl; 717 if (prevl) 718 prevl->next = l; 719 else 720 buf->firstLine = l; 721 l->linenumber = lnum; 722 if (lnum == clnum) 723 buf->currentLine = l; 724 if (lnum == tlnum) 725 buf->topLine = l; 726 if (fread1(l->real_linenumber, cache) || 727 fread1(l->usrflags, cache) || 728 fread1(l->width, cache) || 729 fread1(l->len, cache) || 730 fread1(l->size, cache) || 731 fread1(l->bpos, cache) || fread1(l->bwidth, cache)) 732 break; 733 if (l->bpos == 0) { 734 basel = l; 735 l->lineBuf = NewAtom_N(char, l->size + 1); 736 fread(l->lineBuf, 1, l->size, cache); 737 l->lineBuf[l->size] = '\0'; 738 l->propBuf = NewAtom_N(Lineprop, l->size); 739 fread(l->propBuf, sizeof(Lineprop), l->size, cache); 740 } 741 else if (basel) { 742 l->lineBuf = basel->lineBuf + l->bpos; 743 l->propBuf = basel->propBuf + l->bpos; 744 } 745 else 746 break; 747 #ifdef USE_ANSI_COLOR 748 if (fread1(colorflag, cache)) 749 break; 750 if (colorflag) { 751 if (l->bpos == 0) { 752 l->colorBuf = NewAtom_N(Linecolor, l->size); 753 fread(l->colorBuf, sizeof(Linecolor), l->size, cache); 754 } 755 else 756 l->colorBuf = basel->colorBuf + l->bpos; 757 } 758 else { 759 l->colorBuf = NULL; 760 } 761 #endif 762 } 763 buf->lastLine = prevl; 764 buf->lastLine->next = NULL; 765 fclose(cache); 766 unlink(buf->savecache); 767 buf->savecache = NULL; 768 return 0; 769 }