linein.c (21804B)
1 /* $Id$ */ 2 #include "fm.h" 3 #include "local.h" 4 #include "myctype.h" 5 6 #ifdef USE_MOUSE 7 #ifdef USE_GPM 8 #include <gpm.h> 9 #endif 10 #if defined(USE_GPM) || defined(USE_SYSMOUSE) 11 extern int do_getch(); 12 #define getch() do_getch() 13 #endif /* USE_GPM */ 14 #endif /* USE_MOUSE */ 15 16 #ifdef __EMX__ 17 #include <sys/kbdscan.h> 18 #endif 19 20 #define STR_LEN 1024 21 #define CLEN (COLS - 2) 22 23 static Str strBuf; 24 static Lineprop strProp[STR_LEN]; 25 26 static Str CompleteBuf; 27 static Str CFileName; 28 static Str CBeforeBuf; 29 static Str CAfterBuf; 30 static Str CDirBuf; 31 static char **CFileBuf = NULL; 32 static int NCFileBuf; 33 static int NCFileOffset; 34 35 static void insertself(char c), 36 _mvR(void), _mvL(void), _mvRw(void), _mvLw(void), delC(void), insC(void), 37 _mvB(void), _mvE(void), _enter(void), _quo(void), _bs(void), _bsw(void), 38 killn(void), killb(void), _inbrk(void), _esc(void), _editor(void), 39 _prev(void), _next(void), _compl(void), _tcompl(void), 40 _dcompl(void), _rdcompl(void), _rcompl(void); 41 #ifdef __EMX__ 42 static int getcntrl(void); 43 #endif 44 45 static int terminated(unsigned char c); 46 #define iself ((void(*)())insertself) 47 48 static void next_compl(int next); 49 static void next_dcompl(int next); 50 static Str doComplete(Str ifn, int *status, int next); 51 52 /* *INDENT-OFF* */ 53 void (*InputKeymap[32]) () = { 54 /* C-@ C-a C-b C-c C-d C-e C-f C-g */ 55 _compl, _mvB, _mvL, _inbrk, delC, _mvE, _mvR, _inbrk, 56 /* C-h C-i C-j C-k C-l C-m C-n C-o */ 57 _bs, iself, _enter, killn, iself, _enter, _next, _editor, 58 /* C-p C-q C-r C-s C-t C-u C-v C-w */ 59 _prev, _quo, _bsw, iself, _mvLw, killb, _quo, _bsw, 60 /* C-x C-y C-z C-[ C-\ C-] C-^ C-_ */ 61 _tcompl,_mvRw, iself, _esc, iself, iself, iself, iself, 62 }; 63 /* *INDENT-ON* */ 64 65 static int setStrType(Str str, Lineprop *prop); 66 static void addPasswd(char *p, Lineprop *pr, int len, int pos, int limit); 67 static void addStr(char *p, Lineprop *pr, int len, int pos, int limit); 68 69 static int CPos, CLen, offset; 70 static int i_cont, i_broken, i_quote; 71 static int cm_mode, cm_next, cm_clear, cm_disp_next, cm_disp_clear; 72 static int need_redraw, is_passwd; 73 static int move_word; 74 75 static Hist *CurrentHist; 76 static Str strCurrentBuf; 77 static int use_hist; 78 #ifdef USE_M17N 79 static void ins_char(Str str); 80 #else 81 static void ins_char(char c); 82 #endif 83 84 char * 85 inputLineHistSearch(char *prompt, char *def_str, int flag, Hist *hist, 86 int (*incrfunc) (int ch, Str str, Lineprop *prop)) 87 { 88 int opos, x, y, lpos, rpos, epos; 89 unsigned char c; 90 char *p; 91 #ifdef USE_M17N 92 Str tmp; 93 #endif 94 95 is_passwd = FALSE; 96 move_word = TRUE; 97 98 CurrentHist = hist; 99 if (hist != NULL) { 100 use_hist = TRUE; 101 strCurrentBuf = NULL; 102 } 103 else { 104 use_hist = FALSE; 105 } 106 if (flag & IN_URL) { 107 cm_mode = CPL_ALWAYS | CPL_URL; 108 } 109 else if (flag & IN_FILENAME) { 110 cm_mode = CPL_ALWAYS; 111 } 112 else if (flag & IN_PASSWORD) { 113 cm_mode = CPL_NEVER; 114 is_passwd = TRUE; 115 move_word = FALSE; 116 } 117 else if (flag & IN_COMMAND) 118 cm_mode = CPL_ON; 119 else 120 cm_mode = CPL_OFF; 121 opos = get_strwidth(prompt); 122 epos = CLEN - opos; 123 if (epos < 0) 124 epos = 0; 125 lpos = epos / 3; 126 rpos = epos * 2 / 3; 127 offset = 0; 128 129 if (def_str) { 130 strBuf = Strnew_charp(def_str); 131 CLen = CPos = setStrType(strBuf, strProp); 132 } 133 else { 134 strBuf = Strnew(); 135 CLen = CPos = 0; 136 } 137 138 #ifdef SUPPORT_WIN9X_CONSOLE_MBCS 139 enable_win9x_console_input(); 140 #endif 141 i_cont = TRUE; 142 i_broken = FALSE; 143 i_quote = FALSE; 144 cm_next = FALSE; 145 cm_disp_next = -1; 146 need_redraw = FALSE; 147 148 #ifdef USE_M17N 149 wc_char_conv_init(wc_guess_8bit_charset(DisplayCharset), InnerCharset); 150 #endif 151 do { 152 x = calcPosition(strBuf->ptr, strProp, CLen, CPos, 0, CP_FORCE); 153 if (x - rpos > offset) { 154 y = calcPosition(strBuf->ptr, strProp, CLen, CLen, 0, CP_AUTO); 155 if (y - epos > x - rpos) 156 offset = x - rpos; 157 else if (y - epos > 0) 158 offset = y - epos; 159 } 160 else if (x - lpos < offset) { 161 if (x - lpos > 0) 162 offset = x - lpos; 163 else 164 offset = 0; 165 } 166 move(LASTLINE, 0); 167 addstr(prompt); 168 if (is_passwd) 169 addPasswd(strBuf->ptr, strProp, CLen, offset, COLS - opos); 170 else 171 addStr(strBuf->ptr, strProp, CLen, offset, COLS - opos); 172 clrtoeolx(); 173 move(LASTLINE, opos + x - offset); 174 refresh(); 175 176 next_char: 177 c = getch(); 178 #ifdef __EMX__ 179 if (c == 0) { 180 if (!(c = getcntrl())) 181 goto next_char; 182 } 183 #endif 184 cm_clear = TRUE; 185 cm_disp_clear = TRUE; 186 if (!i_quote && 187 (((cm_mode & CPL_ALWAYS) && (c == CTRL_I || c == ' ')) || 188 ((cm_mode & CPL_ON) && (c == CTRL_I)))) { 189 if (emacs_like_lineedit && cm_next) { 190 _dcompl(); 191 need_redraw = TRUE; 192 } 193 else { 194 _compl(); 195 cm_disp_next = -1; 196 } 197 } 198 else if (!i_quote && CLen == CPos && 199 (cm_mode & CPL_ALWAYS || cm_mode & CPL_ON) && c == CTRL_D) { 200 if (!emacs_like_lineedit) { 201 _dcompl(); 202 need_redraw = TRUE; 203 } 204 } 205 else if (!i_quote && c == DEL_CODE) { 206 _bs(); 207 cm_next = FALSE; 208 cm_disp_next = -1; 209 } 210 else if (!i_quote && c < 0x20) { /* Control code */ 211 if (incrfunc == NULL 212 || (c = incrfunc((int)c, strBuf, strProp)) < 0x20) 213 (*InputKeymap[(int)c]) (c); 214 if (incrfunc && c != (unsigned char)-1 && c != CTRL_J) 215 incrfunc(-1, strBuf, strProp); 216 if (cm_clear) 217 cm_next = FALSE; 218 if (cm_disp_clear) 219 cm_disp_next = -1; 220 } 221 #ifdef USE_M17N 222 else { 223 tmp = wc_char_conv(c); 224 if (tmp == NULL) { 225 i_quote = TRUE; 226 goto next_char; 227 } 228 i_quote = FALSE; 229 cm_next = FALSE; 230 cm_disp_next = -1; 231 if (CLen + tmp->length > STR_LEN || !tmp->length) 232 goto next_char; 233 ins_char(tmp); 234 if (incrfunc) 235 incrfunc(-1, strBuf, strProp); 236 } 237 #else 238 else { 239 i_quote = FALSE; 240 cm_next = FALSE; 241 cm_disp_next = -1; 242 if (CLen >= STR_LEN) 243 goto next_char; 244 insC(); 245 strBuf->ptr[CPos] = c; 246 if (!is_passwd && get_mctype(&c) == PC_CTRL) 247 strProp[CPos] = PC_CTRL; 248 else 249 strProp[CPos] = PC_ASCII; 250 CPos++; 251 if (incrfunc) 252 incrfunc(-1, strBuf, strProp); 253 } 254 #endif 255 if (CLen && (flag & IN_CHAR)) 256 break; 257 } while (i_cont); 258 259 if (CurrentTab) { 260 if (need_redraw) 261 displayBuffer(Currentbuf, B_FORCE_REDRAW); 262 } 263 264 #ifdef SUPPORT_WIN9X_CONSOLE_MBCS 265 disable_win9x_console_input(); 266 #endif 267 268 if (i_broken) 269 return NULL; 270 271 move(LASTLINE, 0); 272 refresh(); 273 p = strBuf->ptr; 274 if (flag & (IN_FILENAME | IN_COMMAND)) { 275 SKIP_BLANKS(p); 276 } 277 if (use_hist && !(flag & IN_URL) && *p != '\0') { 278 char *q = lastHist(hist); 279 if (!q || strcmp(q, p)) 280 pushHist(hist, p); 281 } 282 if (flag & IN_FILENAME) 283 return expandPath(p); 284 else 285 return allocStr(p, -1); 286 } 287 288 #ifdef __EMX__ 289 static int 290 getcntrl(void) 291 { 292 switch (getch()) { 293 case K_DEL: 294 return CTRL_D; 295 case K_LEFT: 296 return CTRL_B; 297 case K_RIGHT: 298 return CTRL_F; 299 case K_UP: 300 return CTRL_P; 301 case K_DOWN: 302 return CTRL_N; 303 case K_HOME: 304 case K_CTRL_LEFT: 305 return CTRL_A; 306 case K_END: 307 case K_CTRL_RIGHT: 308 return CTRL_E; 309 case K_CTRL_HOME: 310 return CTRL_U; 311 case K_CTRL_END: 312 return CTRL_K; 313 } 314 return 0; 315 } 316 #endif 317 318 static void 319 addPasswd(char *p, Lineprop *pr, int len, int offset, int limit) 320 { 321 int rcol = 0, ncol; 322 323 ncol = calcPosition(p, pr, len, len, 0, CP_AUTO); 324 if (ncol > offset + limit) 325 ncol = offset + limit; 326 if (offset) { 327 addChar('{', 0); 328 rcol = offset + 1; 329 } 330 for (; rcol < ncol; rcol++) 331 addChar('*', 0); 332 } 333 334 static void 335 addStr(char *p, Lineprop *pr, int len, int offset, int limit) 336 { 337 int i = 0, rcol = 0, ncol, delta = 1; 338 339 if (offset) { 340 for (i = 0; i < len; i++) { 341 if (calcPosition(p, pr, len, i, 0, CP_AUTO) > offset) 342 break; 343 } 344 if (i >= len) 345 return; 346 #ifdef USE_M17N 347 while (pr[i] & PC_WCHAR2) 348 i++; 349 #endif 350 addChar('{', 0); 351 rcol = offset + 1; 352 ncol = calcPosition(p, pr, len, i, 0, CP_AUTO); 353 for (; rcol < ncol; rcol++) 354 addChar(' ', 0); 355 } 356 for (; i < len; i += delta) { 357 #ifdef USE_M17N 358 delta = wtf_len((wc_uchar *) & p[i]); 359 #endif 360 ncol = calcPosition(p, pr, len, i + delta, 0, CP_AUTO); 361 if (ncol - offset > limit) 362 break; 363 if (p[i] == '\t') { 364 for (; rcol < ncol; rcol++) 365 addChar(' ', 0); 366 continue; 367 } 368 else { 369 #ifdef USE_M17N 370 addMChar(&p[i], pr[i], delta); 371 #else 372 addChar(p[i], pr[i]); 373 #endif 374 } 375 rcol = ncol; 376 } 377 } 378 379 #ifdef USE_M17N 380 static void 381 ins_char(Str str) 382 { 383 char *p = str->ptr, *ep = p + str->length; 384 Lineprop ctype; 385 int len; 386 387 if (CLen + str->length >= STR_LEN) 388 return; 389 while (p < ep) { 390 len = get_mclen(p); 391 ctype = get_mctype(p); 392 if (is_passwd) { 393 if (ctype & PC_CTRL) 394 ctype = PC_ASCII; 395 if (ctype & PC_UNKNOWN) 396 ctype = PC_WCHAR1; 397 } 398 insC(); 399 strBuf->ptr[CPos] = *(p++); 400 strProp[CPos] = ctype; 401 CPos++; 402 if (--len) { 403 ctype = (ctype & ~PC_WCHAR1) | PC_WCHAR2; 404 while (len--) { 405 insC(); 406 strBuf->ptr[CPos] = *(p++); 407 strProp[CPos] = ctype; 408 CPos++; 409 } 410 } 411 } 412 } 413 #endif 414 415 static void 416 _esc(void) 417 { 418 char c; 419 420 switch (c = getch()) { 421 case '[': 422 case 'O': 423 switch (c = getch()) { 424 case 'A': 425 _prev(); 426 break; 427 case 'B': 428 _next(); 429 break; 430 case 'C': 431 _mvR(); 432 break; 433 case 'D': 434 _mvL(); 435 break; 436 } 437 break; 438 case CTRL_I: 439 case ' ': 440 if (emacs_like_lineedit) { 441 _rdcompl(); 442 cm_clear = FALSE; 443 need_redraw = TRUE; 444 } 445 else 446 _rcompl(); 447 break; 448 case CTRL_D: 449 if (!emacs_like_lineedit) 450 _rdcompl(); 451 need_redraw = TRUE; 452 break; 453 case 'f': 454 if (emacs_like_lineedit) 455 _mvRw(); 456 break; 457 case 'b': 458 if (emacs_like_lineedit) 459 _mvLw(); 460 break; 461 case CTRL_H: 462 if (emacs_like_lineedit) 463 _bsw(); 464 break; 465 #ifdef USE_M17N 466 default: 467 if (wc_char_conv(ESC_CODE) == NULL && wc_char_conv(c) == NULL) 468 i_quote = TRUE; 469 #endif 470 } 471 } 472 473 static void 474 insC(void) 475 { 476 int i; 477 478 Strinsert_char(strBuf, CPos, ' '); 479 CLen = strBuf->length; 480 for (i = CLen; i > CPos; i--) { 481 strProp[i] = strProp[i - 1]; 482 } 483 } 484 485 static void 486 delC(void) 487 { 488 int i = CPos; 489 int delta = 1; 490 491 if (CLen == CPos) 492 return; 493 #ifdef USE_M17N 494 while (i + delta < CLen && strProp[i + delta] & PC_WCHAR2) 495 delta++; 496 #endif 497 for (i = CPos; i < CLen; i++) { 498 strProp[i] = strProp[i + delta]; 499 } 500 Strdelete(strBuf, CPos, delta); 501 CLen -= delta; 502 } 503 504 static void 505 _mvL(void) 506 { 507 if (CPos > 0) 508 CPos--; 509 #ifdef USE_M17N 510 while (CPos > 0 && strProp[CPos] & PC_WCHAR2) 511 CPos--; 512 #endif 513 } 514 515 static void 516 _mvLw(void) 517 { 518 int first = 1; 519 while (CPos > 0 && (first || !terminated(strBuf->ptr[CPos - 1]))) { 520 CPos--; 521 first = 0; 522 #ifdef USE_M17N 523 if (CPos > 0 && strProp[CPos] & PC_WCHAR2) 524 CPos--; 525 #endif 526 if (!move_word) 527 break; 528 } 529 } 530 531 static void 532 _mvRw(void) 533 { 534 int first = 1; 535 while (CPos < CLen && (first || !terminated(strBuf->ptr[CPos - 1]))) { 536 CPos++; 537 first = 0; 538 #ifdef USE_M17N 539 if (CPos < CLen && strProp[CPos] & PC_WCHAR2) 540 CPos++; 541 #endif 542 if (!move_word) 543 break; 544 } 545 } 546 547 static void 548 _mvR(void) 549 { 550 if (CPos < CLen) 551 CPos++; 552 #ifdef USE_M17N 553 while (CPos < CLen && strProp[CPos] & PC_WCHAR2) 554 CPos++; 555 #endif 556 } 557 558 static void 559 _bs(void) 560 { 561 if (CPos > 0) { 562 _mvL(); 563 delC(); 564 } 565 } 566 567 static void 568 _bsw(void) 569 { 570 int t = 0; 571 while (CPos > 0 && !t) { 572 _mvL(); 573 t = (move_word && terminated(strBuf->ptr[CPos - 1])); 574 delC(); 575 } 576 } 577 578 static void 579 _enter(void) 580 { 581 i_cont = FALSE; 582 } 583 584 static void 585 insertself(char c) 586 { 587 if (CLen >= STR_LEN) 588 return; 589 insC(); 590 strBuf->ptr[CPos] = c; 591 strProp[CPos] = (is_passwd) ? PC_ASCII : PC_CTRL; 592 CPos++; 593 } 594 595 static void 596 _quo(void) 597 { 598 i_quote = TRUE; 599 } 600 601 static void 602 _mvB(void) 603 { 604 CPos = 0; 605 } 606 607 static void 608 _mvE(void) 609 { 610 CPos = CLen; 611 } 612 613 static void 614 killn(void) 615 { 616 CLen = CPos; 617 Strtruncate(strBuf, CLen); 618 } 619 620 static void 621 killb(void) 622 { 623 while (CPos > 0) 624 _bs(); 625 } 626 627 static void 628 _inbrk(void) 629 { 630 i_cont = FALSE; 631 i_broken = TRUE; 632 } 633 634 static void 635 _compl(void) 636 { 637 next_compl(1); 638 } 639 640 static void 641 _rcompl(void) 642 { 643 next_compl(-1); 644 } 645 646 static void 647 _tcompl(void) 648 { 649 if (cm_mode & CPL_OFF) 650 cm_mode = CPL_ON; 651 else if (cm_mode & CPL_ON) 652 cm_mode = CPL_OFF; 653 } 654 655 static void 656 next_compl(int next) 657 { 658 int status; 659 int b, a; 660 Str buf; 661 Str s; 662 663 if (cm_mode == CPL_NEVER || cm_mode & CPL_OFF) 664 return; 665 cm_clear = FALSE; 666 if (!cm_next) { 667 if (cm_mode & CPL_ALWAYS) { 668 b = 0; 669 } 670 else { 671 for (b = CPos - 1; b >= 0; b--) { 672 if ((strBuf->ptr[b] == ' ' || strBuf->ptr[b] == CTRL_I) && 673 !((b > 0) && strBuf->ptr[b - 1] == '\\')) 674 break; 675 } 676 b++; 677 } 678 a = CPos; 679 CBeforeBuf = Strsubstr(strBuf, 0, b); 680 buf = Strsubstr(strBuf, b, a - b); 681 CAfterBuf = Strsubstr(strBuf, a, strBuf->length - a); 682 s = doComplete(buf, &status, next); 683 } 684 else { 685 s = doComplete(strBuf, &status, next); 686 } 687 if (next == 0) 688 return; 689 690 if (status != CPL_OK && status != CPL_MENU) 691 bell(); 692 if (status == CPL_FAIL) 693 return; 694 695 strBuf = Strnew_m_charp(CBeforeBuf->ptr, s->ptr, CAfterBuf->ptr, NULL); 696 CLen = setStrType(strBuf, strProp); 697 CPos = CBeforeBuf->length + s->length; 698 if (CPos > CLen) 699 CPos = CLen; 700 } 701 702 static void 703 _dcompl(void) 704 { 705 next_dcompl(1); 706 } 707 708 static void 709 _rdcompl(void) 710 { 711 next_dcompl(-1); 712 } 713 714 static void 715 next_dcompl(int next) 716 { 717 static int col, row, len; 718 static Str d; 719 int i, j, n, y; 720 Str f; 721 char *p; 722 struct stat st; 723 int comment, nline; 724 725 if (cm_mode == CPL_NEVER || cm_mode & CPL_OFF) 726 return; 727 cm_disp_clear = FALSE; 728 if (CurrentTab) 729 displayBuffer(Currentbuf, B_FORCE_REDRAW); 730 if (LASTLINE >= 3) { 731 comment = TRUE; 732 nline = LASTLINE - 2; 733 } 734 else if (LASTLINE) { 735 comment = FALSE; 736 nline = LASTLINE; 737 } 738 else { 739 return; 740 } 741 742 if (cm_disp_next >= 0) { 743 if (next == 1) { 744 cm_disp_next += col * nline; 745 if (cm_disp_next >= NCFileBuf) 746 cm_disp_next = 0; 747 } 748 else if (next == -1) { 749 cm_disp_next -= col * nline; 750 if (cm_disp_next < 0) 751 cm_disp_next = 0; 752 } 753 row = (NCFileBuf - cm_disp_next + col - 1) / col; 754 goto disp_next; 755 } 756 757 cm_next = FALSE; 758 next_compl(0); 759 if (NCFileBuf == 0) 760 return; 761 cm_disp_next = 0; 762 763 d = Str_conv_to_system(Strdup(CDirBuf)); 764 if (d->length > 0 && Strlastchar(d) != '/') 765 Strcat_char(d, '/'); 766 if (cm_mode & CPL_URL && d->ptr[0] == 'f') { 767 p = d->ptr; 768 if (strncmp(p, "file://localhost/", 17) == 0) 769 p = &p[16]; 770 else if (strncmp(p, "file:///", 8) == 0) 771 p = &p[7]; 772 else if (strncmp(p, "file:/", 6) == 0 && p[6] != '/') 773 p = &p[5]; 774 d = Strnew_charp(p); 775 } 776 777 len = 0; 778 for (i = 0; i < NCFileBuf; i++) { 779 n = strlen(CFileBuf[i]) + 3; 780 if (len < n) 781 len = n; 782 } 783 col = COLS / len; 784 if (col == 0) 785 col = 1; 786 row = (NCFileBuf + col - 1) / col; 787 788 disp_next: 789 if (comment) { 790 if (row > nline) { 791 row = nline; 792 y = 0; 793 } 794 else 795 y = nline - row + 1; 796 } 797 else { 798 if (row >= nline) { 799 row = nline; 800 y = 0; 801 } 802 else 803 y = nline - row - 1; 804 } 805 if (y) { 806 move(y - 1, 0); 807 clrtoeolx(); 808 } 809 if (comment) { 810 move(y, 0); 811 clrtoeolx(); 812 bold(); 813 /* FIXME: gettextize? */ 814 addstr("----- Completion list -----"); 815 boldend(); 816 y++; 817 } 818 for (i = 0; i < row; i++) { 819 for (j = 0; j < col; j++) { 820 n = cm_disp_next + j * row + i; 821 if (n >= NCFileBuf) 822 break; 823 move(y, j * len); 824 clrtoeolx(); 825 f = Strdup(d); 826 Strcat_charp(f, CFileBuf[n]); 827 addstr(conv_from_system(CFileBuf[n])); 828 if (stat(expandPath(f->ptr), &st) != -1 && S_ISDIR(st.st_mode)) 829 addstr("/"); 830 } 831 y++; 832 } 833 if (comment && y == LASTLINE - 1) { 834 move(y, 0); 835 clrtoeolx(); 836 bold(); 837 if (emacs_like_lineedit) 838 /* FIXME: gettextize? */ 839 addstr("----- Press TAB to continue -----"); 840 else 841 /* FIXME: gettextize? */ 842 addstr("----- Press CTRL-D to continue -----"); 843 boldend(); 844 } 845 } 846 847 848 Str 849 escape_spaces(Str s) 850 { 851 Str tmp = NULL; 852 char *p; 853 854 if (s == NULL) 855 return s; 856 for (p = s->ptr; *p; p++) { 857 if (*p == ' ' || *p == CTRL_I) { 858 if (tmp == NULL) 859 tmp = Strnew_charp_n(s->ptr, (int)(p - s->ptr)); 860 Strcat_char(tmp, '\\'); 861 } 862 if (tmp) 863 Strcat_char(tmp, *p); 864 } 865 if (tmp) 866 return tmp; 867 return s; 868 } 869 870 871 Str 872 unescape_spaces(Str s) 873 { 874 Str tmp = NULL; 875 char *p; 876 877 if (s == NULL) 878 return s; 879 for (p = s->ptr; *p; p++) { 880 if (*p == '\\' && (*(p + 1) == ' ' || *(p + 1) == CTRL_I)) { 881 if (tmp == NULL) 882 tmp = Strnew_charp_n(s->ptr, (int)(p - s->ptr)); 883 } 884 else { 885 if (tmp) 886 Strcat_char(tmp, *p); 887 } 888 } 889 if (tmp) 890 return tmp; 891 return s; 892 } 893 894 static Str 895 doComplete(Str ifn, int *status, int next) 896 { 897 int fl, i; 898 char *fn, *p; 899 DIR *d; 900 Directory *dir; 901 struct stat st; 902 903 if (!cm_next) { 904 NCFileBuf = 0; 905 ifn = Str_conv_to_system(ifn); 906 if (cm_mode & CPL_ON) 907 ifn = unescape_spaces(ifn); 908 CompleteBuf = Strdup(ifn); 909 while (Strlastchar(CompleteBuf) != '/' && CompleteBuf->length > 0) 910 Strshrink(CompleteBuf, 1); 911 CDirBuf = Strdup(CompleteBuf); 912 if (cm_mode & CPL_URL) { 913 if (strncmp(CompleteBuf->ptr, "file://localhost/", 17) == 0) 914 Strdelete(CompleteBuf, 0, 16); 915 else if (strncmp(CompleteBuf->ptr, "file:///", 8) == 0) 916 Strdelete(CompleteBuf, 0, 7); 917 else if (strncmp(CompleteBuf->ptr, "file:/", 6) == 0 && 918 CompleteBuf->ptr[6] != '/') 919 Strdelete(CompleteBuf, 0, 5); 920 else { 921 CompleteBuf = Strdup(ifn); 922 *status = CPL_FAIL; 923 return Str_conv_to_system(CompleteBuf); 924 } 925 } 926 if (CompleteBuf->length == 0) { 927 Strcat_char(CompleteBuf, '.'); 928 } 929 if (Strlastchar(CompleteBuf) == '/' && CompleteBuf->length > 1) { 930 Strshrink(CompleteBuf, 1); 931 } 932 if ((d = opendir(expandPath(CompleteBuf->ptr))) == NULL) { 933 CompleteBuf = Strdup(ifn); 934 *status = CPL_FAIL; 935 if (cm_mode & CPL_ON) 936 CompleteBuf = escape_spaces(CompleteBuf); 937 return CompleteBuf; 938 } 939 fn = lastFileName(ifn->ptr); 940 fl = strlen(fn); 941 CFileName = Strnew(); 942 for (;;) { 943 dir = readdir(d); 944 if (dir == NULL) 945 break; 946 if (fl == 0 947 && (!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, ".."))) 948 continue; 949 if (!strncmp(dir->d_name, fn, fl)) { /* match */ 950 NCFileBuf++; 951 CFileBuf = New_Reuse(char *, CFileBuf, NCFileBuf); 952 CFileBuf[NCFileBuf - 1] = 953 NewAtom_N(char, strlen(dir->d_name) + 1); 954 strcpy(CFileBuf[NCFileBuf - 1], dir->d_name); 955 if (NCFileBuf == 1) { 956 CFileName = Strnew_charp(dir->d_name); 957 } 958 else { 959 for (i = 0; CFileName->ptr[i] == dir->d_name[i]; i++) ; 960 Strtruncate(CFileName, i); 961 } 962 } 963 } 964 closedir(d); 965 if (NCFileBuf == 0) { 966 CompleteBuf = Strdup(ifn); 967 *status = CPL_FAIL; 968 if (cm_mode & CPL_ON) 969 CompleteBuf = escape_spaces(CompleteBuf); 970 return CompleteBuf; 971 } 972 qsort(CFileBuf, NCFileBuf, sizeof(CFileBuf[0]), strCmp); 973 NCFileOffset = 0; 974 if (NCFileBuf >= 2) { 975 cm_next = TRUE; 976 *status = CPL_AMBIG; 977 } 978 else { 979 *status = CPL_OK; 980 } 981 } 982 else { 983 CFileName = Strnew_charp(CFileBuf[NCFileOffset]); 984 NCFileOffset = (NCFileOffset + next + NCFileBuf) % NCFileBuf; 985 *status = CPL_MENU; 986 } 987 CompleteBuf = Strdup(CDirBuf); 988 if (CompleteBuf->length && Strlastchar(CompleteBuf) != '/') 989 Strcat_char(CompleteBuf, '/'); 990 Strcat(CompleteBuf, CFileName); 991 if (*status != CPL_AMBIG) { 992 p = CompleteBuf->ptr; 993 if (cm_mode & CPL_URL) { 994 if (strncmp(p, "file://localhost/", 17) == 0) 995 p = &p[16]; 996 else if (strncmp(p, "file:///", 8) == 0) 997 p = &p[7]; 998 else if (strncmp(p, "file:/", 6) == 0 && p[6] != '/') 999 p = &p[5]; 1000 } 1001 if (stat(expandPath(p), &st) != -1 && S_ISDIR(st.st_mode)) 1002 Strcat_char(CompleteBuf, '/'); 1003 } 1004 if (cm_mode & CPL_ON) 1005 CompleteBuf = escape_spaces(CompleteBuf); 1006 return Str_conv_from_system(CompleteBuf); 1007 } 1008 1009 static void 1010 _prev(void) 1011 { 1012 Hist *hist = CurrentHist; 1013 char *p; 1014 1015 if (!use_hist) 1016 return; 1017 if (strCurrentBuf) { 1018 p = prevHist(hist); 1019 if (p == NULL) 1020 return; 1021 } 1022 else { 1023 p = lastHist(hist); 1024 if (p == NULL) 1025 return; 1026 strCurrentBuf = strBuf; 1027 } 1028 if (DecodeURL && (cm_mode & CPL_URL) ) 1029 p = url_unquote_conv(p, 0); 1030 strBuf = Strnew_charp(p); 1031 CLen = CPos = setStrType(strBuf, strProp); 1032 offset = 0; 1033 } 1034 1035 static void 1036 _next(void) 1037 { 1038 Hist *hist = CurrentHist; 1039 char *p; 1040 1041 if (!use_hist) 1042 return; 1043 if (strCurrentBuf == NULL) 1044 return; 1045 p = nextHist(hist); 1046 if (p) { 1047 if (DecodeURL && (cm_mode & CPL_URL) ) 1048 p = url_unquote_conv(p, 0); 1049 strBuf = Strnew_charp(p); 1050 } 1051 else { 1052 strBuf = strCurrentBuf; 1053 strCurrentBuf = NULL; 1054 } 1055 CLen = CPos = setStrType(strBuf, strProp); 1056 offset = 0; 1057 } 1058 1059 static int 1060 setStrType(Str str, Lineprop *prop) 1061 { 1062 Lineprop ctype; 1063 char *p = str->ptr, *ep = p + str->length; 1064 int i, len = 1; 1065 1066 for (i = 0; p < ep;) { 1067 #ifdef USE_M17N 1068 len = get_mclen(p); 1069 #endif 1070 if (i + len > STR_LEN) 1071 break; 1072 ctype = get_mctype(p); 1073 if (is_passwd) { 1074 if (ctype & PC_CTRL) 1075 ctype = PC_ASCII; 1076 #ifdef USE_M17N 1077 if (ctype & PC_UNKNOWN) 1078 ctype = PC_WCHAR1; 1079 #endif 1080 } 1081 prop[i++] = ctype; 1082 #ifdef USE_M17N 1083 p += len; 1084 if (--len) { 1085 ctype = (ctype & ~PC_WCHAR1) | PC_WCHAR2; 1086 while (len--) 1087 prop[i++] = ctype; 1088 } 1089 #else 1090 p++; 1091 #endif 1092 } 1093 return i; 1094 } 1095 1096 static int 1097 terminated(unsigned char c) 1098 { 1099 int termchar[] = { '/', '&', '?', ' ', -1 }; 1100 int *tp; 1101 1102 for (tp = termchar; *tp > 0; tp++) { 1103 if (c == *tp) { 1104 return 1; 1105 } 1106 } 1107 1108 return 0; 1109 } 1110 1111 static void 1112 _editor(void) 1113 { 1114 FormItemList fi; 1115 char *p; 1116 1117 if (is_passwd) 1118 return; 1119 1120 fi.readonly = FALSE; 1121 fi.value = Strdup(strBuf); 1122 Strcat_char(fi.value, '\n'); 1123 1124 input_textarea(&fi); 1125 1126 strBuf = Strnew(); 1127 for (p = fi.value->ptr; *p; p++) { 1128 if (*p == '\r' || *p == '\n') 1129 continue; 1130 Strcat_char(strBuf, *p); 1131 } 1132 CLen = CPos = setStrType(strBuf, strProp); 1133 if (CurrentTab) 1134 displayBuffer(Currentbuf, B_FORCE_REDRAW); 1135 }