/* Copyright (c) 2008 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de) * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de) * Micah Cowan (micah@cowan.name) * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net) * Copyright (c) 1993-2002, 2003, 2005, 2006, 2007 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de) * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de) * Copyright (c) 1987 Oliver Laumann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program (see the file COPYING); if not, see * http://www.gnu.org/licenses/, or contact Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA * **************************************************************** */ #include #include "config.h" #include "screen.h" #include "extern.h" #define INPUTLINE (flayer->l_height - 1) static void InpProcess __P((char **, int *)); static void InpAbort __P((void)); static void InpRedisplayLine __P((int, int, int, int)); extern struct layer *flayer; extern struct display *display; extern struct mchar mchar_blank, mchar_so; struct inpline { char buf[101]; /* text buffer */ int len; /* length of the editible string */ int pos; /* cursor position in editable string */ }; static struct inpline inphist; /* XXX: should be a dynamic list */ struct inpdata { struct inpline inp; int inpmaxlen; /* 100, or less, if caller has shorter buffer */ char *inpstring; /* the prompt */ int inpstringlen; /* length of the prompt */ int inpmode; /* INP_NOECHO, INP_RAW, INP_EVERY */ void (*inpfinfunc) __P((char *buf, int len, char *priv)); char *priv; /* private data for finfunc */ int privdata; /* private data space */ }; static struct LayFuncs InpLf = { InpProcess, InpAbort, InpRedisplayLine, DefClearLine, DefRewrite, DefResize, DefRestore }; /* ** Here is the input routine */ /* called once, after InitOverlayPage in Input() or Isearch() */ void inp_setprompt(p, s) char *p, *s; { struct inpdata *inpdata; inpdata = (struct inpdata *)flayer->l_data; if (p) { inpdata->inpstringlen = strlen(p); inpdata->inpstring = p; } if (s) { if (s != inpdata->inp.buf) strncpy(inpdata->inp.buf, s, sizeof(inpdata->inp.buf) - 1); inpdata->inp.buf[sizeof(inpdata->inp.buf) - 1] = 0; inpdata->inp.pos = inpdata->inp.len = strlen(inpdata->inp.buf); } InpRedisplayLine(INPUTLINE, 0, flayer->l_width - 1, 0); flayer->l_x = inpdata->inpstringlen + (inpdata->inpmode & INP_NOECHO ? 0 : inpdata->inp.pos); flayer->l_y = INPUTLINE; } /* * We dont use HS status line with Input(). * If we would use it, then we should check e_tgetflag("es") if * we are allowed to use esc sequences there. * * mode is an OR of * INP_NOECHO == suppress echoing of characters. * INP_RAW == raw mode. call finfunc after each character typed. * INP_EVERY == digraph mode. */ void Input(istr, len, mode, finfunc, priv, data) char *istr; int len; int mode; void (*finfunc) __P((char *buf, int len, char *priv)); char *priv; int data; { int maxlen; struct inpdata *inpdata; if (!flayer) return; if (len > 100) len = 100; if (!(mode & INP_NOECHO)) { maxlen = flayer->l_width - 1 - strlen(istr); if (len > maxlen) len = maxlen; } if (len < 0) { LMsg(0, "Width %d chars too small", -len); return; } if (InitOverlayPage(sizeof(*inpdata), &InpLf, 1)) return; inpdata = (struct inpdata *)flayer->l_data; inpdata->inpmaxlen = len; inpdata->inpfinfunc = finfunc; inpdata->inp.pos = inpdata->inp.len = 0; inpdata->inpmode = mode; inpdata->privdata = data; if (!priv) priv = (char*)&inpdata->privdata; inpdata->priv = priv; inpdata->inpstringlen = 0; inpdata->inpstring = NULL; if (istr) inp_setprompt(istr, (char *)NULL); } static void erase_chars(inpdata, from, to, x, mv) struct inpdata *inpdata; char *from; char *to; int x; int mv; { int chng; ASSERT(from < to); if (inpdata->inp.len > to - inpdata->inp.buf) bcopy(to, from, inpdata->inp.len - (to - inpdata->inp.buf)); chng = to - from; if (mv) { x -= chng; inpdata->inp.pos -= chng; } inpdata->inp.len -= chng; if (!(inpdata->inpmode & INP_NOECHO)) { struct mchar mc; char *s = from < to ? from : to; mc = mchar_so; while (s < inpdata->inp.buf+inpdata->inp.len) { mc.image = *s++; LPutChar(flayer, &mc, x++, INPUTLINE); } while (chng--) LPutChar(flayer, &mchar_blank, x++, INPUTLINE); x = inpdata->inpstringlen + inpdata->inp.pos; LGotoPos(flayer, x, INPUTLINE); } } static void InpProcess(ppbuf, plen) char **ppbuf; int *plen; { int len, x; char *pbuf; char ch; struct inpdata *inpdata; struct display *inpdisplay; inpdata = (struct inpdata *)flayer->l_data; inpdisplay = display; LGotoPos(flayer, inpdata->inpstringlen + (inpdata->inpmode & INP_NOECHO ? 0 : inpdata->inp.pos), INPUTLINE); if (ppbuf == 0) { InpAbort(); return; } x = inpdata->inpstringlen + inpdata->inp.pos; len = *plen; pbuf = *ppbuf; while (len) { char *p = inpdata->inp.buf + inpdata->inp.pos; ch = *pbuf++; len--; if (inpdata->inpmode & INP_EVERY) { inpdata->inp.buf[inpdata->inp.len] = ch; if (ch) { display = inpdisplay; (*inpdata->inpfinfunc)(inpdata->inp.buf, inpdata->inp.len, inpdata->priv); ch = inpdata->inp.buf[inpdata->inp.len]; } } else if (inpdata->inpmode & INP_RAW) { display = inpdisplay; (*inpdata->inpfinfunc)(&ch, 1, inpdata->priv); /* raw */ if (ch) continue; } if (((unsigned char)ch & 0177) >= ' ' && ch != 0177 && inpdata->inp.len < inpdata->inpmaxlen) { if (inpdata->inp.len > inpdata->inp.pos) bcopy(p, p+1, inpdata->inp.len - inpdata->inp.pos); inpdata->inp.buf[inpdata->inp.pos++] = ch; inpdata->inp.len++; if (!(inpdata->inpmode & INP_NOECHO)) { struct mchar mc; mc = mchar_so; mc.image = *p++; LPutChar(flayer, &mc, x, INPUTLINE); x++; if (p < inpdata->inp.buf+inpdata->inp.len) { while (p < inpdata->inp.buf+inpdata->inp.len) { mc.image = *p++; LPutChar(flayer, &mc, x++, INPUTLINE); } x = inpdata->inpstringlen + inpdata->inp.pos; LGotoPos(flayer, x, INPUTLINE); } } } else if ((ch == '\b' || ch == 0177) && inpdata->inp.pos > 0) { erase_chars(inpdata, p-1, p, x, 1); } else if (ch == '\025') /* CTRL-U */ { x = inpdata->inpstringlen; if (inpdata->inp.len && !(inpdata->inpmode & INP_NOECHO)) { LClearArea(flayer, x, INPUTLINE, x + inpdata->inp.len - 1, INPUTLINE, 0, 0); LGotoPos(flayer, x, INPUTLINE); } inpdata->inp.len = inpdata->inp.pos = 0; } else if (ch == '\013') /* CTRL-K */ { x = inpdata->inpstringlen + inpdata->inp.pos; if (inpdata->inp.len > inpdata->inp.pos && !(inpdata->inpmode & INP_NOECHO)) { LClearArea(flayer, x, INPUTLINE, x + inpdata->inp.len - inpdata->inp.pos - 1, INPUTLINE, 0, 0); LGotoPos(flayer, x, INPUTLINE); } inpdata->inp.len = inpdata->inp.pos; } else if (ch == '\027' && inpdata->inp.pos > 0) /* CTRL-W */ { char *oldp = p--; while (p > inpdata->inp.buf && *p == ' ') p--; while (p > inpdata->inp.buf && *(p - 1) != ' ') p--; erase_chars(inpdata, p, oldp, x, 1); } else if (ch == '\004' && inpdata->inp.pos < inpdata->inp.len) /* CTRL-D */ { erase_chars(inpdata, p, p+1, x, 0); } else if (ch == '\001' || (unsigned char)ch == 0201) /* CTRL-A */ { LGotoPos(flayer, x -= inpdata->inp.pos, INPUTLINE); inpdata->inp.pos = 0; } else if ((ch == '\002' || (unsigned char)ch == 0202) && inpdata->inp.pos > 0) /* CTRL-B */ { LGotoPos(flayer, --x, INPUTLINE); inpdata->inp.pos--; } else if (ch == '\005' || (unsigned char)ch == 0205) /* CTRL-E */ { LGotoPos(flayer, x += inpdata->inp.len - inpdata->inp.pos, INPUTLINE); inpdata->inp.pos = inpdata->inp.len; } else if ((ch == '\006' || (unsigned char)ch == 0206) && inpdata->inp.pos < inpdata->inp.len) /* CTRL-F */ { LGotoPos(flayer, ++x, INPUTLINE); inpdata->inp.pos++; } else if (ch == '\020' || (unsigned char)ch == 0220) /* CTRL-P */ { struct mchar mc; mc = mchar_so; if (inpdata->inp.len && !(inpdata->inpmode & INP_NOECHO)) LClearArea(flayer, inpdata->inpstringlen, INPUTLINE, inpdata->inpstringlen + inpdata->inp.len - 1, INPUTLINE, 0, 0); inpdata->inp = inphist; /* structure copy */ if (inpdata->inp.len > inpdata->inpmaxlen) inpdata->inp.len = inpdata->inpmaxlen; if (inpdata->inp.pos > inpdata->inp.len) inpdata->inp.pos = inpdata->inp.len; x = inpdata->inpstringlen; p = inpdata->inp.buf; if (!(inpdata->inpmode & INP_NOECHO)) { while (p < inpdata->inp.buf+inpdata->inp.len) { mc.image = *p++; LPutChar(flayer, &mc, x++, INPUTLINE); } } x = inpdata->inpstringlen + inpdata->inp.pos; LGotoPos(flayer, x, INPUTLINE); } else if (ch == '\003' || ch == '\007' || ch == '\033' || ch == '\000' || ch == '\n' || ch == '\r') { if (ch != '\n' && ch != '\r') inpdata->inp.len = 0; inpdata->inp.buf[inpdata->inp.len] = 0; if (inpdata->inp.len && !(inpdata->inpmode & (INP_NOECHO | INP_RAW))) inphist = inpdata->inp; /* structure copy */ flayer->l_data = 0; /* so inpdata does not get freed */ InpAbort(); /* redisplays... */ *ppbuf = pbuf; *plen = len; display = inpdisplay; if ((inpdata->inpmode & INP_RAW) == 0) (*inpdata->inpfinfunc)(inpdata->inp.buf, inpdata->inp.len, inpdata->priv); else (*inpdata->inpfinfunc)(pbuf - 1, 0, inpdata->priv); free((char *)inpdata); return; } } if (!(inpdata->inpmode & INP_RAW)) { flayer->l_x = inpdata->inpstringlen + (inpdata->inpmode & INP_NOECHO ? 0 : inpdata->inp.pos); flayer->l_y = INPUTLINE; } *ppbuf = pbuf; *plen = len; } static void InpAbort() { LAY_CALL_UP(LayRedisplayLine(INPUTLINE, 0, flayer->l_width - 1, 0)); ExitOverlayPage(); } static void InpRedisplayLine(y, xs, xe, isblank) int y, xs, xe, isblank; { int q, r, s, l, v; struct inpdata *inpdata; inpdata = (struct inpdata *)flayer->l_data; if (y != INPUTLINE) { LAY_CALL_UP(LayRedisplayLine(y, xs, xe, isblank)); return; } inpdata->inp.buf[inpdata->inp.len] = 0; q = xs; v = xe - xs + 1; s = 0; r = inpdata->inpstringlen; if (v > 0 && q < r) { l = v; if (l > r - q) l = r - q; LPutStr(flayer, inpdata->inpstring + q - s, l, &mchar_so, q, y); q += l; v -= l; } s = r; r += inpdata->inp.len; if (!(inpdata->inpmode & INP_NOECHO) && v > 0 && q < r) { l = v; if (l > r - q) l = r - q; LPutStr(flayer, inpdata->inp.buf + q - s, l, &mchar_so, q, y); q += l; v -= l; } s = r; r = flayer->l_width; if (!isblank && v > 0 && q < r) { l = v; if (l > r - q) l = r - q; LClearArea(flayer, q, y, q + l - 1, y, 0, 0); q += l; } } int InInput() { if (flayer && flayer->l_layfn == &InpLf) return 1; return 0; }