aboutsummaryrefslogtreecommitdiffstats
path: root/linein.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--linein.c1135
1 files changed, 1135 insertions, 0 deletions
diff --git a/linein.c b/linein.c
new file mode 100644
index 0000000..03c14d1
--- /dev/null
+++ b/linein.c
@@ -0,0 +1,1135 @@
+/* $Id: linein.c,v 1.34 2003/09/26 17:59:51 ukai Exp $ */
+#include "fm.h"
+#include "local.h"
+#include "myctype.h"
+
+#ifdef USE_MOUSE
+#ifdef USE_GPM
+#include <gpm.h>
+#endif
+#if defined(USE_GPM) || defined(USE_SYSMOUSE)
+extern int do_getch();
+#define getch() do_getch()
+#endif /* USE_GPM */
+#endif /* USE_MOUSE */
+
+#ifdef __EMX__
+#include <sys/kbdscan.h>
+#endif
+
+#define STR_LEN 1024
+#define CLEN (COLS - 2)
+
+static Str strBuf;
+static Lineprop strProp[STR_LEN];
+
+static Str CompleteBuf;
+static Str CFileName;
+static Str CBeforeBuf;
+static Str CAfterBuf;
+static Str CDirBuf;
+static char **CFileBuf = NULL;
+static int NCFileBuf;
+static int NCFileOffset;
+
+static void insertself(char c),
+_mvR(void), _mvL(void), _mvRw(void), _mvLw(void), delC(void), insC(void),
+_mvB(void), _mvE(void), _enter(void), _quo(void), _bs(void), _bsw(void),
+killn(void), killb(void), _inbrk(void), _esc(void), _editor(void),
+_prev(void), _next(void), _compl(void), _tcompl(void),
+_dcompl(void), _rdcompl(void), _rcompl(void);
+#ifdef __EMX__
+static int getcntrl(void);
+#endif
+
+static int terminated(unsigned char c);
+#define iself ((void(*)())insertself)
+
+static void next_compl(int next);
+static void next_dcompl(int next);
+static Str doComplete(Str ifn, int *status, int next);
+
+/* *INDENT-OFF* */
+void (*InputKeymap[32]) () = {
+/* C-@ C-a C-b C-c C-d C-e C-f C-g */
+ _compl, _mvB, _mvL, _inbrk, delC, _mvE, _mvR, _inbrk,
+/* C-h C-i C-j C-k C-l C-m C-n C-o */
+ _bs, iself, _enter, killn, iself, _enter, _next, _editor,
+/* C-p C-q C-r C-s C-t C-u C-v C-w */
+ _prev, _quo, _bsw, iself, _mvLw, killb, _quo, _bsw,
+/* C-x C-y C-z C-[ C-\ C-] C-^ C-_ */
+ _tcompl,_mvRw, iself, _esc, iself, iself, iself, iself,
+};
+/* *INDENT-ON* */
+
+static int setStrType(Str str, Lineprop *prop);
+static void addPasswd(char *p, Lineprop *pr, int len, int pos, int limit);
+static void addStr(char *p, Lineprop *pr, int len, int pos, int limit);
+
+static int CPos, CLen, offset;
+static int i_cont, i_broken, i_quote;
+static int cm_mode, cm_next, cm_clear, cm_disp_next, cm_disp_clear;
+static int need_redraw, is_passwd;
+static int move_word;
+
+static Hist *CurrentHist;
+static Str strCurrentBuf;
+static int use_hist;
+#ifdef USE_M17N
+static void ins_char(Str str);
+#else
+static void ins_char(char c);
+#endif
+
+char *
+inputLineHistSearch(char *prompt, char *def_str, int flag, Hist *hist,
+ int (*incrfunc) (int ch, Str str, Lineprop *prop))
+{
+ int opos, x, y, lpos, rpos, epos;
+ unsigned char c;
+ char *p;
+#ifdef USE_M17N
+ Str tmp;
+#endif
+
+ is_passwd = FALSE;
+ move_word = TRUE;
+
+ CurrentHist = hist;
+ if (hist != NULL) {
+ use_hist = TRUE;
+ strCurrentBuf = NULL;
+ }
+ else {
+ use_hist = FALSE;
+ }
+ if (flag & IN_URL) {
+ cm_mode = CPL_ALWAYS | CPL_URL;
+ }
+ else if (flag & IN_FILENAME) {
+ cm_mode = CPL_ALWAYS;
+ }
+ else if (flag & IN_PASSWORD) {
+ cm_mode = CPL_NEVER;
+ is_passwd = TRUE;
+ move_word = FALSE;
+ }
+ else if (flag & IN_COMMAND)
+ cm_mode = CPL_ON;
+ else
+ cm_mode = CPL_OFF;
+ opos = get_strwidth(prompt);
+ epos = CLEN - opos;
+ if (epos < 0)
+ epos = 0;
+ lpos = epos / 3;
+ rpos = epos * 2 / 3;
+ offset = 0;
+
+ if (def_str) {
+ strBuf = Strnew_charp(def_str);
+ CLen = CPos = setStrType(strBuf, strProp);
+ }
+ else {
+ strBuf = Strnew();
+ CLen = CPos = 0;
+ }
+
+#ifdef SUPPORT_WIN9X_CONSOLE_MBCS
+ enable_win9x_console_input();
+#endif
+ i_cont = TRUE;
+ i_broken = FALSE;
+ i_quote = FALSE;
+ cm_next = FALSE;
+ cm_disp_next = -1;
+ need_redraw = FALSE;
+
+#ifdef USE_M17N
+ wc_char_conv_init(wc_guess_8bit_charset(DisplayCharset), InnerCharset);
+#endif
+ do {
+ x = calcPosition(strBuf->ptr, strProp, CLen, CPos, 0, CP_FORCE);
+ if (x - rpos > offset) {
+ y = calcPosition(strBuf->ptr, strProp, CLen, CLen, 0, CP_AUTO);
+ if (y - epos > x - rpos)
+ offset = x - rpos;
+ else if (y - epos > 0)
+ offset = y - epos;
+ }
+ else if (x - lpos < offset) {
+ if (x - lpos > 0)
+ offset = x - lpos;
+ else
+ offset = 0;
+ }
+ move(LASTLINE, 0);
+ addstr(prompt);
+ if (is_passwd)
+ addPasswd(strBuf->ptr, strProp, CLen, offset, COLS - opos);
+ else
+ addStr(strBuf->ptr, strProp, CLen, offset, COLS - opos);
+ clrtoeolx();
+ move(LASTLINE, opos + x - offset);
+ refresh();
+
+ next_char:
+ c = getch();
+#ifdef __EMX__
+ if (c == 0) {
+ if (!(c = getcntrl()))
+ goto next_char;
+ }
+#endif
+ cm_clear = TRUE;
+ cm_disp_clear = TRUE;
+ if (!i_quote &&
+ (((cm_mode & CPL_ALWAYS) && (c == CTRL_I || c == ' ')) ||
+ ((cm_mode & CPL_ON) && (c == CTRL_I)))) {
+ if (emacs_like_lineedit && cm_next) {
+ _dcompl();
+ need_redraw = TRUE;
+ }
+ else {
+ _compl();
+ cm_disp_next = -1;
+ }
+ }
+ else if (!i_quote && CLen == CPos &&
+ (cm_mode & CPL_ALWAYS || cm_mode & CPL_ON) && c == CTRL_D) {
+ if (!emacs_like_lineedit) {
+ _dcompl();
+ need_redraw = TRUE;
+ }
+ }
+ else if (!i_quote && c == DEL_CODE) {
+ _bs();
+ cm_next = FALSE;
+ cm_disp_next = -1;
+ }
+ else if (!i_quote && c < 0x20) { /* Control code */
+ if (incrfunc == NULL
+ || (c = incrfunc((int)c, strBuf, strProp)) < 0x20)
+ (*InputKeymap[(int)c]) (c);
+ if (incrfunc && c != (unsigned char)-1 && c != CTRL_J)
+ incrfunc(-1, strBuf, strProp);
+ if (cm_clear)
+ cm_next = FALSE;
+ if (cm_disp_clear)
+ cm_disp_next = -1;
+ }
+#ifdef USE_M17N
+ else {
+ tmp = wc_char_conv(c);
+ if (tmp == NULL) {
+ i_quote = TRUE;
+ goto next_char;
+ }
+ i_quote = FALSE;
+ cm_next = FALSE;
+ cm_disp_next = -1;
+ if (CLen + tmp->length > STR_LEN || !tmp->length)
+ goto next_char;
+ ins_char(tmp);
+ if (incrfunc)
+ incrfunc(-1, strBuf, strProp);
+ }
+#else
+ else {
+ i_quote = FALSE;
+ cm_next = FALSE;
+ cm_disp_next = -1;
+ if (CLen >= STR_LEN)
+ goto next_char;
+ insC();
+ strBuf->ptr[CPos] = c;
+ if (!is_passwd && get_mctype(&c) == PC_CTRL)
+ strProp[CPos] = PC_CTRL;
+ else
+ strProp[CPos] = PC_ASCII;
+ CPos++;
+ if (incrfunc)
+ incrfunc(-1, strBuf, strProp);
+ }
+#endif
+ if (CLen && (flag & IN_CHAR))
+ break;
+ } while (i_cont);
+
+ if (CurrentTab) {
+ if (need_redraw)
+ displayBuffer(Currentbuf, B_FORCE_REDRAW);
+ }
+
+#ifdef SUPPORT_WIN9X_CONSOLE_MBCS
+ disable_win9x_console_input();
+#endif
+
+ if (i_broken)
+ return NULL;
+
+ move(LASTLINE, 0);
+ refresh();
+ p = strBuf->ptr;
+ if (flag & (IN_FILENAME | IN_COMMAND)) {
+ SKIP_BLANKS(p);
+ }
+ if (use_hist && !(flag & IN_URL) && *p != '\0') {
+ char *q = lastHist(hist);
+ if (!q || strcmp(q, p))
+ pushHist(hist, p);
+ }
+ if (flag & IN_FILENAME)
+ return expandPath(p);
+ else
+ return allocStr(p, -1);
+}
+
+#ifdef __EMX__
+static int
+getcntrl(void)
+{
+ switch (getch()) {
+ case K_DEL:
+ return CTRL_D;
+ case K_LEFT:
+ return CTRL_B;
+ case K_RIGHT:
+ return CTRL_F;
+ case K_UP:
+ return CTRL_P;
+ case K_DOWN:
+ return CTRL_N;
+ case K_HOME:
+ case K_CTRL_LEFT:
+ return CTRL_A;
+ case K_END:
+ case K_CTRL_RIGHT:
+ return CTRL_E;
+ case K_CTRL_HOME:
+ return CTRL_U;
+ case K_CTRL_END:
+ return CTRL_K;
+ }
+ return 0;
+}
+#endif
+
+static void
+addPasswd(char *p, Lineprop *pr, int len, int offset, int limit)
+{
+ int rcol = 0, ncol;
+
+ ncol = calcPosition(p, pr, len, len, 0, CP_AUTO);
+ if (ncol > offset + limit)
+ ncol = offset + limit;
+ if (offset) {
+ addChar('{', 0);
+ rcol = offset + 1;
+ }
+ for (; rcol < ncol; rcol++)
+ addChar('*', 0);
+}
+
+static void
+addStr(char *p, Lineprop *pr, int len, int offset, int limit)
+{
+ int i = 0, rcol = 0, ncol, delta = 1;
+
+ if (offset) {
+ for (i = 0; i < len; i++) {
+ if (calcPosition(p, pr, len, i, 0, CP_AUTO) > offset)
+ break;
+ }
+ if (i >= len)
+ return;
+#ifdef USE_M17N
+ while (pr[i] & PC_WCHAR2)
+ i++;
+#endif
+ addChar('{', 0);
+ rcol = offset + 1;
+ ncol = calcPosition(p, pr, len, i, 0, CP_AUTO);
+ for (; rcol < ncol; rcol++)
+ addChar(' ', 0);
+ }
+ for (; i < len; i += delta) {
+#ifdef USE_M17N
+ delta = wtf_len((wc_uchar *) & p[i]);
+#endif
+ ncol = calcPosition(p, pr, len, i + delta, 0, CP_AUTO);
+ if (ncol - offset > limit)
+ break;
+ if (p[i] == '\t') {
+ for (; rcol < ncol; rcol++)
+ addChar(' ', 0);
+ continue;
+ }
+ else {
+#ifdef USE_M17N
+ addMChar(&p[i], pr[i], delta);
+#else
+ addChar(p[i], pr[i]);
+#endif
+ }
+ rcol = ncol;
+ }
+}
+
+#ifdef USE_M17N
+static void
+ins_char(Str str)
+{
+ char *p = str->ptr, *ep = p + str->length;
+ Lineprop ctype;
+ int len;
+
+ if (CLen + str->length >= STR_LEN)
+ return;
+ while (p < ep) {
+ len = get_mclen(p);
+ ctype = get_mctype(p);
+ if (is_passwd) {
+ if (ctype & PC_CTRL)
+ ctype = PC_ASCII;
+ if (ctype & PC_UNKNOWN)
+ ctype = PC_WCHAR1;
+ }
+ insC();
+ strBuf->ptr[CPos] = *(p++);
+ strProp[CPos] = ctype;
+ CPos++;
+ if (--len) {
+ ctype = (ctype & ~PC_WCHAR1) | PC_WCHAR2;
+ while (len--) {
+ insC();
+ strBuf->ptr[CPos] = *(p++);
+ strProp[CPos] = ctype;
+ CPos++;
+ }
+ }
+ }
+}
+#endif
+
+static void
+_esc(void)
+{
+ char c;
+
+ switch (c = getch()) {
+ case '[':
+ case 'O':
+ switch (c = getch()) {
+ case 'A':
+ _prev();
+ break;
+ case 'B':
+ _next();
+ break;
+ case 'C':
+ _mvR();
+ break;
+ case 'D':
+ _mvL();
+ break;
+ }
+ break;
+ case CTRL_I:
+ case ' ':
+ if (emacs_like_lineedit) {
+ _rdcompl();
+ cm_clear = FALSE;
+ need_redraw = TRUE;
+ }
+ else
+ _rcompl();
+ break;
+ case CTRL_D:
+ if (!emacs_like_lineedit)
+ _rdcompl();
+ need_redraw = TRUE;
+ break;
+ case 'f':
+ if (emacs_like_lineedit)
+ _mvRw();
+ break;
+ case 'b':
+ if (emacs_like_lineedit)
+ _mvLw();
+ break;
+ case CTRL_H:
+ if (emacs_like_lineedit)
+ _bsw();
+ break;
+#ifdef USE_M17N
+ default:
+ if (wc_char_conv(ESC_CODE) == NULL && wc_char_conv(c) == NULL)
+ i_quote = TRUE;
+#endif
+ }
+}
+
+static void
+insC(void)
+{
+ int i;
+
+ Strinsert_char(strBuf, CPos, ' ');
+ CLen = strBuf->length;
+ for (i = CLen; i > CPos; i--) {
+ strProp[i] = strProp[i - 1];
+ }
+}
+
+static void
+delC(void)
+{
+ int i = CPos;
+ int delta = 1;
+
+ if (CLen == CPos)
+ return;
+#ifdef USE_M17N
+ while (i + delta < CLen && strProp[i + delta] & PC_WCHAR2)
+ delta++;
+#endif
+ for (i = CPos; i < CLen; i++) {
+ strProp[i] = strProp[i + delta];
+ }
+ Strdelete(strBuf, CPos, delta);
+ CLen -= delta;
+}
+
+static void
+_mvL(void)
+{
+ if (CPos > 0)
+ CPos--;
+#ifdef USE_M17N
+ while (CPos > 0 && strProp[CPos] & PC_WCHAR2)
+ CPos--;
+#endif
+}
+
+static void
+_mvLw(void)
+{
+ int first = 1;
+ while (CPos > 0 && (first || !terminated(strBuf->ptr[CPos - 1]))) {
+ CPos--;
+ first = 0;
+#ifdef USE_M17N
+ if (CPos > 0 && strProp[CPos] & PC_WCHAR2)
+ CPos--;
+#endif
+ if (!move_word)
+ break;
+ }
+}
+
+static void
+_mvRw(void)
+{
+ int first = 1;
+ while (CPos < CLen && (first || !terminated(strBuf->ptr[CPos - 1]))) {
+ CPos++;
+ first = 0;
+#ifdef USE_M17N
+ if (CPos < CLen && strProp[CPos] & PC_WCHAR2)
+ CPos++;
+#endif
+ if (!move_word)
+ break;
+ }
+}
+
+static void
+_mvR(void)
+{
+ if (CPos < CLen)
+ CPos++;
+#ifdef USE_M17N
+ while (CPos < CLen && strProp[CPos] & PC_WCHAR2)
+ CPos++;
+#endif
+}
+
+static void
+_bs(void)
+{
+ if (CPos > 0) {
+ _mvL();
+ delC();
+ }
+}
+
+static void
+_bsw(void)
+{
+ int t = 0;
+ while (CPos > 0 && !t) {
+ _mvL();
+ t = (move_word && terminated(strBuf->ptr[CPos - 1]));
+ delC();
+ }
+}
+
+static void
+_enter(void)
+{
+ i_cont = FALSE;
+}
+
+static void
+insertself(char c)
+{
+ if (CLen >= STR_LEN)
+ return;
+ insC();
+ strBuf->ptr[CPos] = c;
+ strProp[CPos] = (is_passwd) ? PC_ASCII : PC_CTRL;
+ CPos++;
+}
+
+static void
+_quo(void)
+{
+ i_quote = TRUE;
+}
+
+static void
+_mvB(void)
+{
+ CPos = 0;
+}
+
+static void
+_mvE(void)
+{
+ CPos = CLen;
+}
+
+static void
+killn(void)
+{
+ CLen = CPos;
+ Strtruncate(strBuf, CLen);
+}
+
+static void
+killb(void)
+{
+ while (CPos > 0)
+ _bs();
+}
+
+static void
+_inbrk(void)
+{
+ i_cont = FALSE;
+ i_broken = TRUE;
+}
+
+static void
+_compl(void)
+{
+ next_compl(1);
+}
+
+static void
+_rcompl(void)
+{
+ next_compl(-1);
+}
+
+static void
+_tcompl(void)
+{
+ if (cm_mode & CPL_OFF)
+ cm_mode = CPL_ON;
+ else if (cm_mode & CPL_ON)
+ cm_mode = CPL_OFF;
+}
+
+static void
+next_compl(int next)
+{
+ int status;
+ int b, a;
+ Str buf;
+ Str s;
+
+ if (cm_mode == CPL_NEVER || cm_mode & CPL_OFF)
+ return;
+ cm_clear = FALSE;
+ if (!cm_next) {
+ if (cm_mode & CPL_ALWAYS) {
+ b = 0;
+ }
+ else {
+ for (b = CPos - 1; b >= 0; b--) {
+ if ((strBuf->ptr[b] == ' ' || strBuf->ptr[b] == CTRL_I) &&
+ !((b > 0) && strBuf->ptr[b - 1] == '\\'))
+ break;
+ }
+ b++;
+ }
+ a = CPos;
+ CBeforeBuf = Strsubstr(strBuf, 0, b);
+ buf = Strsubstr(strBuf, b, a - b);
+ CAfterBuf = Strsubstr(strBuf, a, strBuf->length - a);
+ s = doComplete(buf, &status, next);
+ }
+ else {
+ s = doComplete(strBuf, &status, next);
+ }
+ if (next == 0)
+ return;
+
+ if (status != CPL_OK && status != CPL_MENU)
+ bell();
+ if (status == CPL_FAIL)
+ return;
+
+ strBuf = Strnew_m_charp(CBeforeBuf->ptr, s->ptr, CAfterBuf->ptr, NULL);
+ CLen = setStrType(strBuf, strProp);
+ CPos = CBeforeBuf->length + s->length;
+ if (CPos > CLen)
+ CPos = CLen;
+}
+
+static void
+_dcompl(void)
+{
+ next_dcompl(1);
+}
+
+static void
+_rdcompl(void)
+{
+ next_dcompl(-1);
+}
+
+static void
+next_dcompl(int next)
+{
+ static int col, row, len;
+ static Str d;
+ int i, j, n, y;
+ Str f;
+ char *p;
+ struct stat st;
+ int comment, nline;
+
+ if (cm_mode == CPL_NEVER || cm_mode & CPL_OFF)
+ return;
+ cm_disp_clear = FALSE;
+ if (CurrentTab)
+ displayBuffer(Currentbuf, B_FORCE_REDRAW);
+ if (LASTLINE >= 3) {
+ comment = TRUE;
+ nline = LASTLINE - 2;
+ }
+ else if (LASTLINE) {
+ comment = FALSE;
+ nline = LASTLINE;
+ }
+ else {
+ return;
+ }
+
+ if (cm_disp_next >= 0) {
+ if (next == 1) {
+ cm_disp_next += col * nline;
+ if (cm_disp_next >= NCFileBuf)
+ cm_disp_next = 0;
+ }
+ else if (next == -1) {
+ cm_disp_next -= col * nline;
+ if (cm_disp_next < 0)
+ cm_disp_next = 0;
+ }
+ row = (NCFileBuf - cm_disp_next + col - 1) / col;
+ goto disp_next;
+ }
+
+ cm_next = FALSE;
+ next_compl(0);
+ if (NCFileBuf == 0)
+ return;
+ cm_disp_next = 0;
+
+ d = Str_conv_to_system(Strdup(CDirBuf));
+ if (d->length > 0 && Strlastchar(d) != '/')
+ Strcat_char(d, '/');
+ if (cm_mode & CPL_URL && d->ptr[0] == 'f') {
+ p = d->ptr;
+ if (strncmp(p, "file://localhost/", 17) == 0)
+ p = &p[16];
+ else if (strncmp(p, "file:///", 8) == 0)
+ p = &p[7];
+ else if (strncmp(p, "file:/", 6) == 0 && p[6] != '/')
+ p = &p[5];
+ d = Strnew_charp(p);
+ }
+
+ len = 0;
+ for (i = 0; i < NCFileBuf; i++) {
+ n = strlen(CFileBuf[i]) + 3;
+ if (len < n)
+ len = n;
+ }
+ col = COLS / len;
+ if (col == 0)
+ col = 1;
+ row = (NCFileBuf + col - 1) / col;
+
+ disp_next:
+ if (comment) {
+ if (row > nline) {
+ row = nline;
+ y = 0;
+ }
+ else
+ y = nline - row + 1;
+ }
+ else {
+ if (row >= nline) {
+ row = nline;
+ y = 0;
+ }
+ else
+ y = nline - row - 1;
+ }
+ if (y) {
+ move(y - 1, 0);
+ clrtoeolx();
+ }
+ if (comment) {
+ move(y, 0);
+ clrtoeolx();
+ bold();
+ /* FIXME: gettextize? */
+ addstr("----- Completion list -----");
+ boldend();
+ y++;
+ }
+ for (i = 0; i < row; i++) {
+ for (j = 0; j < col; j++) {
+ n = cm_disp_next + j * row + i;
+ if (n >= NCFileBuf)
+ break;
+ move(y, j * len);
+ clrtoeolx();
+ f = Strdup(d);
+ Strcat_charp(f, CFileBuf[n]);
+ addstr(conv_from_system(CFileBuf[n]));
+ if (stat(expandPath(f->ptr), &st) != -1 && S_ISDIR(st.st_mode))
+ addstr("/");
+ }
+ y++;
+ }
+ if (comment && y == LASTLINE - 1) {
+ move(y, 0);
+ clrtoeolx();
+ bold();
+ if (emacs_like_lineedit)
+ /* FIXME: gettextize? */
+ addstr("----- Press TAB to continue -----");
+ else
+ /* FIXME: gettextize? */
+ addstr("----- Press CTRL-D to continue -----");
+ boldend();
+ }
+}
+
+
+Str
+escape_spaces(Str s)
+{
+ Str tmp = NULL;
+ char *p;
+
+ if (s == NULL)
+ return s;
+ for (p = s->ptr; *p; p++) {
+ if (*p == ' ' || *p == CTRL_I) {
+ if (tmp == NULL)
+ tmp = Strnew_charp_n(s->ptr, (int)(p - s->ptr));
+ Strcat_char(tmp, '\\');
+ }
+ if (tmp)
+ Strcat_char(tmp, *p);
+ }
+ if (tmp)
+ return tmp;
+ return s;
+}
+
+
+Str
+unescape_spaces(Str s)
+{
+ Str tmp = NULL;
+ char *p;
+
+ if (s == NULL)
+ return s;
+ for (p = s->ptr; *p; p++) {
+ if (*p == '\\' && (*(p + 1) == ' ' || *(p + 1) == CTRL_I)) {
+ if (tmp == NULL)
+ tmp = Strnew_charp_n(s->ptr, (int)(p - s->ptr));
+ }
+ else {
+ if (tmp)
+ Strcat_char(tmp, *p);
+ }
+ }
+ if (tmp)
+ return tmp;
+ return s;
+}
+
+static Str
+doComplete(Str ifn, int *status, int next)
+{
+ int fl, i;
+ char *fn, *p;
+ DIR *d;
+ Directory *dir;
+ struct stat st;
+
+ if (!cm_next) {
+ NCFileBuf = 0;
+ ifn = Str_conv_to_system(ifn);
+ if (cm_mode & CPL_ON)
+ ifn = unescape_spaces(ifn);
+ CompleteBuf = Strdup(ifn);
+ while (Strlastchar(CompleteBuf) != '/' && CompleteBuf->length > 0)
+ Strshrink(CompleteBuf, 1);
+ CDirBuf = Strdup(CompleteBuf);
+ if (cm_mode & CPL_URL) {
+ if (strncmp(CompleteBuf->ptr, "file://localhost/", 17) == 0)
+ Strdelete(CompleteBuf, 0, 16);
+ else if (strncmp(CompleteBuf->ptr, "file:///", 8) == 0)
+ Strdelete(CompleteBuf, 0, 7);
+ else if (strncmp(CompleteBuf->ptr, "file:/", 6) == 0 &&
+ CompleteBuf->ptr[6] != '/')
+ Strdelete(CompleteBuf, 0, 5);
+ else {
+ CompleteBuf = Strdup(ifn);
+ *status = CPL_FAIL;
+ return Str_conv_to_system(CompleteBuf);
+ }
+ }
+ if (CompleteBuf->length == 0) {
+ Strcat_char(CompleteBuf, '.');
+ }
+ if (Strlastchar(CompleteBuf) == '/' && CompleteBuf->length > 1) {
+ Strshrink(CompleteBuf, 1);
+ }
+ if ((d = opendir(expandPath(CompleteBuf->ptr))) == NULL) {
+ CompleteBuf = Strdup(ifn);
+ *status = CPL_FAIL;
+ if (cm_mode & CPL_ON)
+ CompleteBuf = escape_spaces(CompleteBuf);
+ return CompleteBuf;
+ }
+ fn = lastFileName(ifn->ptr);
+ fl = strlen(fn);
+ CFileName = Strnew();
+ for (;;) {
+ dir = readdir(d);
+ if (dir == NULL)
+ break;
+ if (fl == 0
+ && (!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, "..")))
+ continue;
+ if (!strncmp(dir->d_name, fn, fl)) { /* match */
+ NCFileBuf++;
+ CFileBuf = New_Reuse(char *, CFileBuf, NCFileBuf);
+ CFileBuf[NCFileBuf - 1] =
+ NewAtom_N(char, strlen(dir->d_name) + 1);
+ strcpy(CFileBuf[NCFileBuf - 1], dir->d_name);
+ if (NCFileBuf == 1) {
+ CFileName = Strnew_charp(dir->d_name);
+ }
+ else {
+ for (i = 0; CFileName->ptr[i] == dir->d_name[i]; i++) ;
+ Strtruncate(CFileName, i);
+ }
+ }
+ }
+ closedir(d);
+ if (NCFileBuf == 0) {
+ CompleteBuf = Strdup(ifn);
+ *status = CPL_FAIL;
+ if (cm_mode & CPL_ON)
+ CompleteBuf = escape_spaces(CompleteBuf);
+ return CompleteBuf;
+ }
+ qsort(CFileBuf, NCFileBuf, sizeof(CFileBuf[0]), strCmp);
+ NCFileOffset = 0;
+ if (NCFileBuf >= 2) {
+ cm_next = TRUE;
+ *status = CPL_AMBIG;
+ }
+ else {
+ *status = CPL_OK;
+ }
+ }
+ else {
+ CFileName = Strnew_charp(CFileBuf[NCFileOffset]);
+ NCFileOffset = (NCFileOffset + next + NCFileBuf) % NCFileBuf;
+ *status = CPL_MENU;
+ }
+ CompleteBuf = Strdup(CDirBuf);
+ if (CompleteBuf->length && Strlastchar(CompleteBuf) != '/')
+ Strcat_char(CompleteBuf, '/');
+ Strcat(CompleteBuf, CFileName);
+ if (*status != CPL_AMBIG) {
+ p = CompleteBuf->ptr;
+ if (cm_mode & CPL_URL) {
+ if (strncmp(p, "file://localhost/", 17) == 0)
+ p = &p[16];
+ else if (strncmp(p, "file:///", 8) == 0)
+ p = &p[7];
+ else if (strncmp(p, "file:/", 6) == 0 && p[6] != '/')
+ p = &p[5];
+ }
+ if (stat(expandPath(p), &st) != -1 && S_ISDIR(st.st_mode))
+ Strcat_char(CompleteBuf, '/');
+ }
+ if (cm_mode & CPL_ON)
+ CompleteBuf = escape_spaces(CompleteBuf);
+ return Str_conv_from_system(CompleteBuf);
+}
+
+static void
+_prev(void)
+{
+ Hist *hist = CurrentHist;
+ char *p;
+
+ if (!use_hist)
+ return;
+ if (strCurrentBuf) {
+ p = prevHist(hist);
+ if (p == NULL)
+ return;
+ }
+ else {
+ p = lastHist(hist);
+ if (p == NULL)
+ return;
+ strCurrentBuf = strBuf;
+ }
+ if (DecodeURL)
+ p = url_unquote_conv(p, 0);
+ strBuf = Strnew_charp(p);
+ CLen = CPos = setStrType(strBuf, strProp);
+ offset = 0;
+}
+
+static void
+_next(void)
+{
+ Hist *hist = CurrentHist;
+ char *p;
+
+ if (!use_hist)
+ return;
+ if (strCurrentBuf == NULL)
+ return;
+ p = nextHist(hist);
+ if (p) {
+ if (DecodeURL)
+ p = url_unquote_conv(p, 0);
+ strBuf = Strnew_charp(p);
+ }
+ else {
+ strBuf = strCurrentBuf;
+ strCurrentBuf = NULL;
+ }
+ CLen = CPos = setStrType(strBuf, strProp);
+ offset = 0;
+}
+
+static int
+setStrType(Str str, Lineprop *prop)
+{
+ Lineprop ctype;
+ char *p = str->ptr, *ep = p + str->length;
+ int i, len = 1;
+
+ for (i = 0; p < ep;) {
+#ifdef USE_M17N
+ len = get_mclen(p);
+#endif
+ if (i + len > STR_LEN)
+ break;
+ ctype = get_mctype(p);
+ if (is_passwd) {
+ if (ctype & PC_CTRL)
+ ctype = PC_ASCII;
+#ifdef USE_M17N
+ if (ctype & PC_UNKNOWN)
+ ctype = PC_WCHAR1;
+#endif
+ }
+ prop[i++] = ctype;
+#ifdef USE_M17N
+ p += len;
+ if (--len) {
+ ctype = (ctype & ~PC_WCHAR1) | PC_WCHAR2;
+ while (len--)
+ prop[i++] = ctype;
+ }
+#else
+ p++;
+#endif
+ }
+ return i;
+}
+
+static int
+terminated(unsigned char c)
+{
+ int termchar[] = { '/', '&', '?', ' ', -1 };
+ int *tp;
+
+ for (tp = termchar; *tp > 0; tp++) {
+ if (c == *tp) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static void
+_editor(void)
+{
+ FormItemList fi;
+ char *p;
+
+ if (is_passwd)
+ return;
+
+ fi.readonly = FALSE;
+ fi.value = Strdup(strBuf);
+ Strcat_char(fi.value, '\n');
+
+ input_textarea(&fi);
+
+ strBuf = Strnew();
+ for (p = fi.value->ptr; *p; p++) {
+ if (*p == '\r' || *p == '\n')
+ continue;
+ Strcat_char(strBuf, *p);
+ }
+ CLen = CPos = setStrType(strBuf, strProp);
+ if (CurrentTab)
+ displayBuffer(Currentbuf, B_FORCE_REDRAW);
+}