#include <sys/types.h>
#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];
int len;
int pos;
};
static struct inpline inphist;
struct inpdata
{
struct inpline inp;
int inpmaxlen;
char *inpstring;
int inpstringlen;
int inpmode;
void (*inpfinfunc) __P((char *buf, int len, char *priv));
char *priv;
};
static struct LayFuncs InpLf =
{
InpProcess,
InpAbort,
InpRedisplayLine,
DefClearLine,
DefRewrite,
DefResize,
DefRestore
};
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);
}
void
Input(istr, len, mode, finfunc, data)
char *istr;
int len;
int mode;
void (*finfunc) __P((char *buf, int len, char *data));
char *data;
{
int maxlen;
struct inpdata *inpdata;
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->priv = data;
inp_setprompt(istr, (char *)NULL);
flayer->l_x = inpdata->inpstringlen;
flayer->l_y = 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;
inpdata->inp.buf[inpdata->inp.len + 1] = 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);
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)
{
if (inpdata->inp.len > inpdata->inp.pos)
bcopy(p, p-1, inpdata->inp.len - inpdata->inp.pos);
inpdata->inp.len--;
inpdata->inp.pos--;
p--;
if (!(inpdata->inpmode & INP_NOECHO))
{
struct mchar mc;
mc = mchar_so;
x--;
while (p < inpdata->inp.buf+inpdata->inp.len)
{
mc.image = *p++;
LPutChar(flayer, &mc, x++, INPUTLINE);
}
LPutChar(flayer, &mchar_blank, x, INPUTLINE);
x = inpdata->inpstringlen + inpdata->inp.pos;
LGotoPos(flayer, x, INPUTLINE);
}
}
else if (ch == '\025')
{
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')
{
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 == '\001' || (unsigned char)ch == 0201)
{
LGotoPos(flayer, x -= inpdata->inp.pos, INPUTLINE);
inpdata->inp.pos = 0;
}
else if ((ch == '\002' || (unsigned char)ch == 0202) && inpdata->inp.pos > 0)
{
LGotoPos(flayer, --x, INPUTLINE);
inpdata->inp.pos--;
}
else if (ch == '\005' || (unsigned char)ch == 0205)
{
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)
{
LGotoPos(flayer, ++x, INPUTLINE);
inpdata->inp.pos++;
}
else if (ch == '\020' || (unsigned char)ch == 0220)
{
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;
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 == '\004' || ch == '\003' || ch == '\007' || ch == '\033' ||
ch == '\000' || ch == '\n' || ch == '\r')
{
if (ch != '\004' && ch != '\n' && ch != '\r')
inpdata->inp.len = 0;
inpdata->inp.buf[inpdata->inp.len] = 0;
if (inpdata->inp.len && inpdata->inpmode == 0)
inphist = inpdata->inp;
flayer->l_data = 0;
InpAbort();
*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;
}