/* $Id: linein.c,v 1.35 2007/05/23 12:14:24 inu Exp $ */ #include "fm.h" #include "local.h" #include "myctype.h" #ifdef USE_MOUSE #ifdef USE_GPM #include #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 #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 && (cm_mode & CPL_URL) ) p = url_decode2(p, NULL); 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 && (cm_mode & CPL_URL) ) p = url_decode2(p, NULL); 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); }