c9624a60fc24a5b251bef8ae93b99c886c543a12
[screen-lua.git] / src / input.c
blobc9624a60fc24a5b251bef8ae93b99c886c543a12
1 /* Copyright (c) 2008
2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Micah Cowan (micah@cowan.name)
5 * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
6 * Copyright (c) 1993-2002, 2003, 2005, 2006, 2007
7 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
8 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
9 * Copyright (c) 1987 Oliver Laumann
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3, or (at your option)
14 * any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program (see the file COPYING); if not, see
23 * http://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
26 ****************************************************************
29 #include <sys/types.h>
30 #include "config.h"
31 #include "screen.h"
32 #include "extern.h"
34 #define INPUTLINE (flayer->l_height - 1)
36 static void InpProcess __P((char **, int *));
37 static void InpAbort __P((void));
38 static void InpRedisplayLine __P((int, int, int, int));
40 extern struct layer *flayer;
41 extern struct display *display;
42 extern struct mchar mchar_blank, mchar_so;
44 struct inpline
46 char buf[101]; /* text buffer */
47 int len; /* length of the editible string */
48 int pos; /* cursor position in editable string */
51 static struct inpline inphist; /* XXX: should be a dynamic list */
54 struct inpdata
56 struct inpline inp;
57 int inpmaxlen; /* 100, or less, if caller has shorter buffer */
58 char *inpstring; /* the prompt */
59 int inpstringlen; /* length of the prompt */
60 int inpmode; /* INP_NOECHO, INP_RAW, INP_EVERY */
61 void (*inpfinfunc) __P((char *buf, int len, char *priv));
62 char *priv; /* private data for finfunc */
63 int privdata; /* private data space */
66 static struct LayFuncs InpLf =
68 InpProcess,
69 InpAbort,
70 InpRedisplayLine,
71 DefClearLine,
72 DefRewrite,
73 DefResize,
74 DefRestore
78 ** Here is the input routine
81 /* called once, after InitOverlayPage in Input() or Isearch() */
82 void
83 inp_setprompt(p, s)
84 char *p, *s;
86 struct inpdata *inpdata;
88 inpdata = (struct inpdata *)flayer->l_data;
89 if (p)
91 inpdata->inpstringlen = strlen(p);
92 inpdata->inpstring = p;
94 if (s)
96 if (s != inpdata->inp.buf)
97 strncpy(inpdata->inp.buf, s, sizeof(inpdata->inp.buf) - 1);
98 inpdata->inp.buf[sizeof(inpdata->inp.buf) - 1] = 0;
99 inpdata->inp.pos = inpdata->inp.len = strlen(inpdata->inp.buf);
101 InpRedisplayLine(INPUTLINE, 0, flayer->l_width - 1, 0);
102 flayer->l_x = inpdata->inpstringlen + (inpdata->inpmode & INP_NOECHO ? 0 : inpdata->inp.pos);
103 flayer->l_y = INPUTLINE;
107 * We dont use HS status line with Input().
108 * If we would use it, then we should check e_tgetflag("es") if
109 * we are allowed to use esc sequences there.
111 * mode is an OR of
112 * INP_NOECHO == suppress echoing of characters.
113 * INP_RAW == raw mode. call finfunc after each character typed.
114 * INP_EVERY == digraph mode.
116 void
117 Input(istr, len, mode, finfunc, priv, data)
118 char *istr;
119 int len;
120 int mode;
121 void (*finfunc) __P((char *buf, int len, char *priv));
122 char *priv;
123 int data;
125 int maxlen;
126 struct inpdata *inpdata;
128 if (!flayer)
129 return;
131 if (len > 100)
132 len = 100;
133 if (!(mode & INP_NOECHO))
135 maxlen = flayer->l_width - 1 - strlen(istr);
136 if (len > maxlen)
137 len = maxlen;
139 if (len < 0)
141 LMsg(0, "Width %d chars too small", -len);
142 return;
144 if (InitOverlayPage(sizeof(*inpdata), &InpLf, 1))
145 return;
146 inpdata = (struct inpdata *)flayer->l_data;
147 inpdata->inpmaxlen = len;
148 inpdata->inpfinfunc = finfunc;
149 inpdata->inp.pos = inpdata->inp.len = 0;
150 inpdata->inpmode = mode;
151 inpdata->privdata = data;
152 if (!priv)
153 priv = (char*)&inpdata->privdata;
154 inpdata->priv = priv;
155 inpdata->inpstringlen = 0;
156 inpdata->inpstring = NULL;
157 if (istr)
158 inp_setprompt(istr, (char *)NULL);
161 static void
162 erase_chars(inpdata, from, to, x, mv)
163 struct inpdata *inpdata;
164 char *from;
165 char *to;
166 int x;
167 int mv;
169 int chng;
170 ASSERT(from < to);
171 if (inpdata->inp.len > to - inpdata->inp.buf)
172 bcopy(to, from, inpdata->inp.len - (to - inpdata->inp.buf));
173 chng = to - from;
174 if (mv)
176 x -= chng;
177 inpdata->inp.pos -= chng;
179 inpdata->inp.len -= chng;
180 if (!(inpdata->inpmode & INP_NOECHO))
182 struct mchar mc;
183 char *s = from < to ? from : to;
184 mc = mchar_so;
185 while (s < inpdata->inp.buf+inpdata->inp.len)
187 mc.image = *s++;
188 LPutChar(flayer, &mc, x++, INPUTLINE);
190 while (chng--)
191 LPutChar(flayer, &mchar_blank, x++, INPUTLINE);
192 x = inpdata->inpstringlen + inpdata->inp.pos;
193 LGotoPos(flayer, x, INPUTLINE);
197 static void
198 InpProcess(ppbuf, plen)
199 char **ppbuf;
200 int *plen;
202 int len, x;
203 char *pbuf;
204 char ch;
205 struct inpdata *inpdata;
206 struct display *inpdisplay;
208 inpdata = (struct inpdata *)flayer->l_data;
209 inpdisplay = display;
211 LGotoPos(flayer, inpdata->inpstringlen + (inpdata->inpmode & INP_NOECHO ? 0 : inpdata->inp.pos), INPUTLINE);
212 if (ppbuf == 0)
214 InpAbort();
215 return;
217 x = inpdata->inpstringlen + inpdata->inp.pos;
218 len = *plen;
219 pbuf = *ppbuf;
220 while (len)
222 char *p = inpdata->inp.buf + inpdata->inp.pos;
224 ch = *pbuf++;
225 len--;
226 if (inpdata->inpmode & INP_EVERY)
228 inpdata->inp.buf[inpdata->inp.len] = ch;
229 if (ch)
231 display = inpdisplay;
232 (*inpdata->inpfinfunc)(inpdata->inp.buf, inpdata->inp.len, inpdata->priv);
233 ch = inpdata->inp.buf[inpdata->inp.len];
236 else if (inpdata->inpmode & INP_RAW)
238 display = inpdisplay;
239 (*inpdata->inpfinfunc)(&ch, 1, inpdata->priv); /* raw */
240 if (ch)
241 continue;
243 if (((unsigned char)ch & 0177) >= ' ' && ch != 0177 && inpdata->inp.len < inpdata->inpmaxlen)
245 if (inpdata->inp.len > inpdata->inp.pos)
246 bcopy(p, p+1, inpdata->inp.len - inpdata->inp.pos);
247 inpdata->inp.buf[inpdata->inp.pos++] = ch;
248 inpdata->inp.len++;
250 if (!(inpdata->inpmode & INP_NOECHO))
252 struct mchar mc;
253 mc = mchar_so;
254 mc.image = *p++;
255 LPutChar(flayer, &mc, x, INPUTLINE);
256 x++;
257 if (p < inpdata->inp.buf+inpdata->inp.len)
259 while (p < inpdata->inp.buf+inpdata->inp.len)
261 mc.image = *p++;
262 LPutChar(flayer, &mc, x++, INPUTLINE);
264 x = inpdata->inpstringlen + inpdata->inp.pos;
265 LGotoPos(flayer, x, INPUTLINE);
269 else if ((ch == '\b' || ch == 0177) && inpdata->inp.pos > 0)
271 erase_chars(inpdata, p-1, p, x, 1);
273 else if (ch == '\025') /* CTRL-U */
275 x = inpdata->inpstringlen;
276 if (inpdata->inp.len && !(inpdata->inpmode & INP_NOECHO))
278 LClearArea(flayer, x, INPUTLINE, x + inpdata->inp.len - 1, INPUTLINE, 0, 0);
279 LGotoPos(flayer, x, INPUTLINE);
281 inpdata->inp.len = inpdata->inp.pos = 0;
283 else if (ch == '\013') /* CTRL-K */
285 x = inpdata->inpstringlen + inpdata->inp.pos;
286 if (inpdata->inp.len > inpdata->inp.pos && !(inpdata->inpmode & INP_NOECHO))
288 LClearArea(flayer, x, INPUTLINE, x + inpdata->inp.len - inpdata->inp.pos - 1, INPUTLINE, 0, 0);
289 LGotoPos(flayer, x, INPUTLINE);
291 inpdata->inp.len = inpdata->inp.pos;
293 else if (ch == '\027' && inpdata->inp.pos > 0) /* CTRL-W */
295 char *oldp = p--;
296 while (p > inpdata->inp.buf && *p == ' ')
297 p--;
298 while (p > inpdata->inp.buf && *(p - 1) != ' ')
299 p--;
300 erase_chars(inpdata, p, oldp, x, 1);
302 else if (ch == '\004' && inpdata->inp.pos < inpdata->inp.len) /* CTRL-D */
304 erase_chars(inpdata, p, p+1, x, 0);
306 else if (ch == '\001' || (unsigned char)ch == 0201) /* CTRL-A */
308 LGotoPos(flayer, x -= inpdata->inp.pos, INPUTLINE);
309 inpdata->inp.pos = 0;
311 else if ((ch == '\002' || (unsigned char)ch == 0202) && inpdata->inp.pos > 0) /* CTRL-B */
313 LGotoPos(flayer, --x, INPUTLINE);
314 inpdata->inp.pos--;
316 else if (ch == '\005' || (unsigned char)ch == 0205) /* CTRL-E */
318 LGotoPos(flayer, x += inpdata->inp.len - inpdata->inp.pos, INPUTLINE);
319 inpdata->inp.pos = inpdata->inp.len;
321 else if ((ch == '\006' || (unsigned char)ch == 0206) && inpdata->inp.pos < inpdata->inp.len) /* CTRL-F */
323 LGotoPos(flayer, ++x, INPUTLINE);
324 inpdata->inp.pos++;
326 else if (ch == '\020' || (unsigned char)ch == 0220) /* CTRL-P */
328 struct mchar mc;
329 mc = mchar_so;
330 if (inpdata->inp.len && !(inpdata->inpmode & INP_NOECHO))
331 LClearArea(flayer, inpdata->inpstringlen, INPUTLINE, inpdata->inpstringlen + inpdata->inp.len - 1, INPUTLINE, 0, 0);
333 inpdata->inp = inphist; /* structure copy */
334 if (inpdata->inp.len > inpdata->inpmaxlen)
335 inpdata->inp.len = inpdata->inpmaxlen;
336 if (inpdata->inp.pos > inpdata->inp.len)
337 inpdata->inp.pos = inpdata->inp.len;
339 x = inpdata->inpstringlen;
340 p = inpdata->inp.buf;
342 if (!(inpdata->inpmode & INP_NOECHO))
344 while (p < inpdata->inp.buf+inpdata->inp.len)
346 mc.image = *p++;
347 LPutChar(flayer, &mc, x++, INPUTLINE);
350 x = inpdata->inpstringlen + inpdata->inp.pos;
351 LGotoPos(flayer, x, INPUTLINE);
354 else if (ch == '\003' || ch == '\007' || ch == '\033' ||
355 ch == '\000' || ch == '\n' || ch == '\r')
357 if (ch != '\n' && ch != '\r')
358 inpdata->inp.len = 0;
359 inpdata->inp.buf[inpdata->inp.len] = 0;
361 if (inpdata->inp.len && !(inpdata->inpmode & (INP_NOECHO | INP_RAW)))
362 inphist = inpdata->inp; /* structure copy */
364 flayer->l_data = 0; /* so inpdata does not get freed */
365 InpAbort(); /* redisplays... */
366 *ppbuf = pbuf;
367 *plen = len;
368 display = inpdisplay;
369 if ((inpdata->inpmode & INP_RAW) == 0)
370 (*inpdata->inpfinfunc)(inpdata->inp.buf, inpdata->inp.len, inpdata->priv);
371 else
372 (*inpdata->inpfinfunc)(pbuf - 1, 0, inpdata->priv);
373 free((char *)inpdata);
374 return;
377 if (!(inpdata->inpmode & INP_RAW))
379 flayer->l_x = inpdata->inpstringlen + (inpdata->inpmode & INP_NOECHO ? 0 : inpdata->inp.pos);
380 flayer->l_y = INPUTLINE;
382 *ppbuf = pbuf;
383 *plen = len;
386 static void
387 InpAbort()
389 LAY_CALL_UP(LayRedisplayLine(INPUTLINE, 0, flayer->l_width - 1, 0));
390 ExitOverlayPage();
393 static void
394 InpRedisplayLine(y, xs, xe, isblank)
395 int y, xs, xe, isblank;
397 int q, r, s, l, v;
398 struct inpdata *inpdata;
400 inpdata = (struct inpdata *)flayer->l_data;
401 if (y != INPUTLINE)
403 LAY_CALL_UP(LayRedisplayLine(y, xs, xe, isblank));
404 return;
406 inpdata->inp.buf[inpdata->inp.len] = 0;
407 q = xs;
408 v = xe - xs + 1;
409 s = 0;
410 r = inpdata->inpstringlen;
411 if (v > 0 && q < r)
413 l = v;
414 if (l > r - q)
415 l = r - q;
416 LPutStr(flayer, inpdata->inpstring + q - s, l, &mchar_so, q, y);
417 q += l;
418 v -= l;
420 s = r;
421 r += inpdata->inp.len;
422 if (!(inpdata->inpmode & INP_NOECHO) && v > 0 && q < r)
424 l = v;
425 if (l > r - q)
426 l = r - q;
427 LPutStr(flayer, inpdata->inp.buf + q - s, l, &mchar_so, q, y);
428 q += l;
429 v -= l;
431 s = r;
432 r = flayer->l_width;
433 if (!isblank && v > 0 && q < r)
435 l = v;
436 if (l > r - q)
437 l = r - q;
438 LClearArea(flayer, q, y, q + l - 1, y, 0, 0);
439 q += l;
444 InInput()
446 if (flayer && flayer->l_layfn == &InpLf)
447 return 1;
448 return 0;