1 /* $Id: linein.c,v 1.35 2007/05/23 12:14:24 inu Exp $ */
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 *
inputLineHistSearch(char * prompt,char * def_str,int flag,Hist * hist,int (* incrfunc)(int ch,Str str,Lineprop * prop))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 || (space_autocomplete && 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
getcntrl(void)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
addPasswd(char * p,Lineprop * pr,int len,int offset,int limit)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
addStr(char * p,Lineprop * pr,int len,int offset,int limit)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
ins_char(Str str)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
_esc(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
insC(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
delC(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
_mvL(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
_mvLw(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
_mvRw(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
_mvR(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
_bs(void)559 _bs(void)
560 {
561 if (CPos > 0) {
562 _mvL();
563 delC();
564 }
565 }
566
567 static void
_bsw(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
_enter(void)579 _enter(void)
580 {
581 i_cont = FALSE;
582 }
583
584 static void
insertself(char c)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
_quo(void)596 _quo(void)
597 {
598 i_quote = TRUE;
599 }
600
601 static void
_mvB(void)602 _mvB(void)
603 {
604 CPos = 0;
605 }
606
607 static void
_mvE(void)608 _mvE(void)
609 {
610 CPos = CLen;
611 }
612
613 static void
killn(void)614 killn(void)
615 {
616 CLen = CPos;
617 Strtruncate(strBuf, CLen);
618 }
619
620 static void
killb(void)621 killb(void)
622 {
623 while (CPos > 0)
624 _bs();
625 }
626
627 static void
_inbrk(void)628 _inbrk(void)
629 {
630 i_cont = FALSE;
631 i_broken = TRUE;
632 }
633
634 static void
_compl(void)635 _compl(void)
636 {
637 next_compl(1);
638 }
639
640 static void
_rcompl(void)641 _rcompl(void)
642 {
643 next_compl(-1);
644 }
645
646 static void
_tcompl(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
next_compl(int next)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
_dcompl(void)703 _dcompl(void)
704 {
705 next_dcompl(1);
706 }
707
708 static void
_rdcompl(void)709 _rdcompl(void)
710 {
711 next_dcompl(-1);
712 }
713
714 static void
next_dcompl(int next)715 next_dcompl(int next)
716 {
717 static int col, row;
718 static unsigned int len;
719 static Str d;
720 int i, j, n, y;
721 Str f;
722 char *p;
723 struct stat st;
724 int comment, nline;
725
726 if (cm_mode == CPL_NEVER || cm_mode & CPL_OFF)
727 return;
728 cm_disp_clear = FALSE;
729 if (CurrentTab)
730 displayBuffer(Currentbuf, B_FORCE_REDRAW);
731 if (LASTLINE >= 3) {
732 comment = TRUE;
733 nline = LASTLINE - 2;
734 }
735 else if (LASTLINE) {
736 comment = FALSE;
737 nline = LASTLINE;
738 }
739 else {
740 return;
741 }
742
743 if (cm_disp_next >= 0) {
744 if (next == 1) {
745 cm_disp_next += col * nline;
746 if (cm_disp_next >= NCFileBuf)
747 cm_disp_next = 0;
748 }
749 else if (next == -1) {
750 cm_disp_next -= col * nline;
751 if (cm_disp_next < 0)
752 cm_disp_next = 0;
753 }
754 row = (NCFileBuf - cm_disp_next + col - 1) / col;
755 goto disp_next;
756 }
757
758 cm_next = FALSE;
759 next_compl(0);
760 if (NCFileBuf == 0)
761 return;
762 cm_disp_next = 0;
763
764 d = Str_conv_to_system(Strdup(CDirBuf));
765 if (d->length > 0 && Strlastchar(d) != '/')
766 Strcat_char(d, '/');
767 if (cm_mode & CPL_URL && d->ptr[0] == 'f') {
768 p = d->ptr;
769 if (strncmp(p, "file://localhost/", 17) == 0)
770 p = &p[16];
771 else if (strncmp(p, "file:///", 8) == 0)
772 p = &p[7];
773 else if (strncmp(p, "file:/", 6) == 0 && p[6] != '/')
774 p = &p[5];
775 d = Strnew_charp(p);
776 }
777
778 len = 0;
779 for (i = 0; i < NCFileBuf; i++) {
780 n = strlen(CFileBuf[i]) + 3;
781 if (len < n)
782 len = n;
783 }
784 if (len > 0 && COLS > len)
785 col = COLS / len;
786 else
787 col = 1;
788 row = (NCFileBuf + col - 1) / col;
789
790 disp_next:
791 if (comment) {
792 if (row > nline) {
793 row = nline;
794 y = 0;
795 }
796 else
797 y = nline - row + 1;
798 }
799 else {
800 if (row >= nline) {
801 row = nline;
802 y = 0;
803 }
804 else
805 y = nline - row - 1;
806 }
807 if (y) {
808 move(y - 1, 0);
809 clrtoeolx();
810 }
811 if (comment) {
812 move(y, 0);
813 clrtoeolx();
814 bold();
815 /* FIXME: gettextize? */
816 addstr("----- Completion list -----");
817 boldend();
818 y++;
819 }
820 for (i = 0; i < row; i++) {
821 for (j = 0; j < col; j++) {
822 n = cm_disp_next + j * row + i;
823 if (n >= NCFileBuf)
824 break;
825 move(y, j * len);
826 clrtoeolx();
827 f = Strdup(d);
828 Strcat_charp(f, CFileBuf[n]);
829 addstr(conv_from_system(CFileBuf[n]));
830 if (stat(expandPath(f->ptr), &st) != -1 && S_ISDIR(st.st_mode))
831 addstr("/");
832 }
833 y++;
834 }
835 if (comment && y == LASTLINE - 1) {
836 move(y, 0);
837 clrtoeolx();
838 bold();
839 if (emacs_like_lineedit)
840 /* FIXME: gettextize? */
841 addstr("----- Press TAB to continue -----");
842 else
843 /* FIXME: gettextize? */
844 addstr("----- Press CTRL-D to continue -----");
845 boldend();
846 }
847 }
848
849
850 Str
escape_spaces(Str s)851 escape_spaces(Str s)
852 {
853 Str tmp = NULL;
854 char *p;
855
856 if (s == NULL)
857 return s;
858 for (p = s->ptr; *p; p++) {
859 if (*p == ' ' || *p == CTRL_I) {
860 if (tmp == NULL)
861 tmp = Strnew_charp_n(s->ptr, (int)(p - s->ptr));
862 Strcat_char(tmp, '\\');
863 }
864 if (tmp)
865 Strcat_char(tmp, *p);
866 }
867 if (tmp)
868 return tmp;
869 return s;
870 }
871
872
873 Str
unescape_spaces(Str s)874 unescape_spaces(Str s)
875 {
876 Str tmp = NULL;
877 char *p;
878
879 if (s == NULL)
880 return s;
881 for (p = s->ptr; *p; p++) {
882 if (*p == '\\' && (*(p + 1) == ' ' || *(p + 1) == CTRL_I)) {
883 if (tmp == NULL)
884 tmp = Strnew_charp_n(s->ptr, (int)(p - s->ptr));
885 }
886 else {
887 if (tmp)
888 Strcat_char(tmp, *p);
889 }
890 }
891 if (tmp)
892 return tmp;
893 return s;
894 }
895
896 static Str
doComplete(Str ifn,int * status,int next)897 doComplete(Str ifn, int *status, int next)
898 {
899 int fl, i;
900 char *fn, *p;
901 DIR *d;
902 Directory *dir;
903 struct stat st;
904
905 if (!cm_next) {
906 NCFileBuf = 0;
907 ifn = Str_conv_to_system(ifn);
908 if (cm_mode & CPL_ON)
909 ifn = unescape_spaces(ifn);
910 CompleteBuf = Strdup(ifn);
911 while (Strlastchar(CompleteBuf) != '/' && CompleteBuf->length > 0)
912 Strshrink(CompleteBuf, 1);
913 CDirBuf = Strdup(CompleteBuf);
914 if (cm_mode & CPL_URL) {
915 if (strncmp(CompleteBuf->ptr, "file://localhost/", 17) == 0)
916 Strdelete(CompleteBuf, 0, 16);
917 else if (strncmp(CompleteBuf->ptr, "file:///", 8) == 0)
918 Strdelete(CompleteBuf, 0, 7);
919 else if (strncmp(CompleteBuf->ptr, "file:/", 6) == 0 &&
920 CompleteBuf->ptr[6] != '/')
921 Strdelete(CompleteBuf, 0, 5);
922 else {
923 CompleteBuf = Strdup(ifn);
924 *status = CPL_FAIL;
925 return Str_conv_to_system(CompleteBuf);
926 }
927 }
928 if (CompleteBuf->length == 0) {
929 Strcat_char(CompleteBuf, '.');
930 }
931 if (Strlastchar(CompleteBuf) == '/' && CompleteBuf->length > 1) {
932 Strshrink(CompleteBuf, 1);
933 }
934 if ((d = opendir(expandPath(CompleteBuf->ptr))) == NULL) {
935 CompleteBuf = Strdup(ifn);
936 *status = CPL_FAIL;
937 if (cm_mode & CPL_ON)
938 CompleteBuf = escape_spaces(CompleteBuf);
939 return CompleteBuf;
940 }
941 fn = lastFileName(ifn->ptr);
942 fl = strlen(fn);
943 CFileName = Strnew();
944 for (;;) {
945 dir = readdir(d);
946 if (dir == NULL)
947 break;
948 if (fl == 0
949 && (!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, "..")))
950 continue;
951 if (!strncmp(dir->d_name, fn, fl)) { /* match */
952 NCFileBuf++;
953 CFileBuf = New_Reuse(char *, CFileBuf, NCFileBuf);
954 CFileBuf[NCFileBuf - 1] =
955 NewAtom_N(char, strlen(dir->d_name) + 1);
956 strcpy(CFileBuf[NCFileBuf - 1], dir->d_name);
957 if (NCFileBuf == 1) {
958 CFileName = Strnew_charp(dir->d_name);
959 }
960 else {
961 for (i = 0; CFileName->ptr[i] == dir->d_name[i]; i++) ;
962 Strtruncate(CFileName, i);
963 }
964 }
965 }
966 closedir(d);
967 if (NCFileBuf == 0) {
968 CompleteBuf = Strdup(ifn);
969 *status = CPL_FAIL;
970 if (cm_mode & CPL_ON)
971 CompleteBuf = escape_spaces(CompleteBuf);
972 return CompleteBuf;
973 }
974 qsort(CFileBuf, NCFileBuf, sizeof(CFileBuf[0]), strCmp);
975 NCFileOffset = 0;
976 if (NCFileBuf >= 2) {
977 cm_next = TRUE;
978 *status = CPL_AMBIG;
979 }
980 else {
981 *status = CPL_OK;
982 }
983 }
984 else {
985 CFileName = Strnew_charp(CFileBuf[NCFileOffset]);
986 NCFileOffset = (NCFileOffset + next + NCFileBuf) % NCFileBuf;
987 *status = CPL_MENU;
988 }
989 CompleteBuf = Strdup(CDirBuf);
990 if (CompleteBuf->length && Strlastchar(CompleteBuf) != '/')
991 Strcat_char(CompleteBuf, '/');
992 Strcat(CompleteBuf, CFileName);
993 if (*status != CPL_AMBIG) {
994 p = CompleteBuf->ptr;
995 if (cm_mode & CPL_URL) {
996 if (strncmp(p, "file://localhost/", 17) == 0)
997 p = &p[16];
998 else if (strncmp(p, "file:///", 8) == 0)
999 p = &p[7];
1000 else if (strncmp(p, "file:/", 6) == 0 && p[6] != '/')
1001 p = &p[5];
1002 }
1003 if (stat(expandPath(p), &st) != -1 && S_ISDIR(st.st_mode))
1004 Strcat_char(CompleteBuf, '/');
1005 }
1006 if (cm_mode & CPL_ON)
1007 CompleteBuf = escape_spaces(CompleteBuf);
1008 return Str_conv_from_system(CompleteBuf);
1009 }
1010
1011 static void
_prev(void)1012 _prev(void)
1013 {
1014 Hist *hist = CurrentHist;
1015 char *p;
1016
1017 if (!use_hist)
1018 return;
1019 if (strCurrentBuf) {
1020 p = prevHist(hist);
1021 if (p == NULL)
1022 return;
1023 }
1024 else {
1025 p = lastHist(hist);
1026 if (p == NULL)
1027 return;
1028 strCurrentBuf = strBuf;
1029 }
1030 if (DecodeURL && (cm_mode & CPL_URL) )
1031 p = url_decode2(p, NULL);
1032 strBuf = Strnew_charp(p);
1033 CLen = CPos = setStrType(strBuf, strProp);
1034 offset = 0;
1035 }
1036
1037 static void
_next(void)1038 _next(void)
1039 {
1040 Hist *hist = CurrentHist;
1041 char *p;
1042
1043 if (!use_hist)
1044 return;
1045 if (strCurrentBuf == NULL)
1046 return;
1047 p = nextHist(hist);
1048 if (p) {
1049 if (DecodeURL && (cm_mode & CPL_URL) )
1050 p = url_decode2(p, NULL);
1051 strBuf = Strnew_charp(p);
1052 }
1053 else {
1054 strBuf = strCurrentBuf;
1055 strCurrentBuf = NULL;
1056 }
1057 CLen = CPos = setStrType(strBuf, strProp);
1058 offset = 0;
1059 }
1060
1061 static int
setStrType(Str str,Lineprop * prop)1062 setStrType(Str str, Lineprop *prop)
1063 {
1064 Lineprop ctype;
1065 char *p = str->ptr, *ep = p + str->length;
1066 int i, len = 1;
1067
1068 for (i = 0; p < ep;) {
1069 #ifdef USE_M17N
1070 len = get_mclen(p);
1071 #endif
1072 if (i + len > STR_LEN)
1073 break;
1074 ctype = get_mctype(p);
1075 if (is_passwd) {
1076 if (ctype & PC_CTRL)
1077 ctype = PC_ASCII;
1078 #ifdef USE_M17N
1079 if (ctype & PC_UNKNOWN)
1080 ctype = PC_WCHAR1;
1081 #endif
1082 }
1083 prop[i++] = ctype;
1084 #ifdef USE_M17N
1085 p += len;
1086 if (--len) {
1087 ctype = (ctype & ~PC_WCHAR1) | PC_WCHAR2;
1088 while (len--)
1089 prop[i++] = ctype;
1090 }
1091 #else
1092 p++;
1093 #endif
1094 }
1095 return i;
1096 }
1097
1098 static int
terminated(unsigned char c)1099 terminated(unsigned char c)
1100 {
1101 int termchar[] = { '/', '&', '?', ' ', -1 };
1102 int *tp;
1103
1104 for (tp = termchar; *tp > 0; tp++) {
1105 if (c == *tp) {
1106 return 1;
1107 }
1108 }
1109
1110 return 0;
1111 }
1112
1113 static void
_editor(void)1114 _editor(void)
1115 {
1116 FormItemList fi;
1117 char *p;
1118
1119 if (is_passwd)
1120 return;
1121
1122 fi.readonly = FALSE;
1123 fi.value = Strdup(strBuf);
1124 Strcat_char(fi.value, '\n');
1125
1126 input_textarea(&fi);
1127
1128 strBuf = Strnew();
1129 for (p = fi.value->ptr; *p; p++) {
1130 if (*p == '\r' || *p == '\n')
1131 continue;
1132 Strcat_char(strBuf, *p);
1133 }
1134 CLen = CPos = setStrType(strBuf, strProp);
1135 if (CurrentTab)
1136 displayBuffer(Currentbuf, B_FORCE_REDRAW);
1137 }
1138