Cast (ew!) to avoid warning (s/b void*, though).
[screen-lua.git] / src / input.c
blob207557a8c6dbc806b1f9fb2ad86361119a86621d
1 /* Copyright (c) 1993-2002
2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Copyright (c) 1987 Oliver Laumann
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program (see the file COPYING); if not, write to the
18 * Free Software Foundation, Inc.,
19 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
21 ****************************************************************
24 #include <sys/types.h>
25 #include "config.h"
26 #include "screen.h"
27 #include "extern.h"
29 #define INPUTLINE (flayer->l_height - 1)
31 static void InpProcess __P((char **, int *));
32 static void InpAbort __P((void));
33 static void InpRedisplayLine __P((int, int, int, int));
35 extern struct layer *flayer;
36 extern struct display *display;
37 extern struct mchar mchar_blank, mchar_so;
39 struct inpline
41 char buf[101]; /* text buffer */
42 int len; /* length of the editible string */
43 int pos; /* cursor position in editable string */
46 static struct inpline inphist; /* XXX: should be a dynamic list */
49 struct inpdata
51 struct inpline inp;
52 int inpmaxlen; /* 100, or less, if caller has shorter buffer */
53 char *inpstring; /* the prompt */
54 int inpstringlen; /* length of the prompt */
55 int inpmode; /* INP_NOECHO, INP_RAW, INP_EVERY */
56 void (*inpfinfunc) __P((char *buf, int len, char *priv));
57 char *priv; /* private data for finfunc */
58 int privdata; /* private data space */
61 static struct LayFuncs InpLf =
63 InpProcess,
64 InpAbort,
65 InpRedisplayLine,
66 DefClearLine,
67 DefRewrite,
68 DefResize,
69 DefRestore
73 ** Here is the input routine
76 /* called once, after InitOverlayPage in Input() or Isearch() */
77 void
78 inp_setprompt(p, s)
79 char *p, *s;
81 struct inpdata *inpdata;
83 inpdata = (struct inpdata *)flayer->l_data;
84 if (p)
86 inpdata->inpstringlen = strlen(p);
87 inpdata->inpstring = p;
89 if (s)
91 if (s != inpdata->inp.buf)
92 strncpy(inpdata->inp.buf, s, sizeof(inpdata->inp.buf) - 1);
93 inpdata->inp.buf[sizeof(inpdata->inp.buf) - 1] = 0;
94 inpdata->inp.pos = inpdata->inp.len = strlen(inpdata->inp.buf);
96 InpRedisplayLine(INPUTLINE, 0, flayer->l_width - 1, 0);
97 flayer->l_x = inpdata->inpstringlen + (inpdata->inpmode & INP_NOECHO ? 0 : inpdata->inp.pos);
98 flayer->l_y = INPUTLINE;
102 * We dont use HS status line with Input().
103 * If we would use it, then we should check e_tgetflag("es") if
104 * we are allowed to use esc sequences there.
106 * mode is an OR of
107 * INP_NOECHO == suppress echoing of characters.
108 * INP_RAW == raw mode. call finfunc after each character typed.
109 * INP_EVERY == digraph mode.
111 void
112 Input(istr, len, mode, finfunc, priv, data)
113 char *istr;
114 int len;
115 int mode;
116 void (*finfunc) __P((char *buf, int len, char *priv));
117 char *priv;
118 int data;
120 int maxlen;
121 struct inpdata *inpdata;
123 if (len > 100)
124 len = 100;
125 if (!(mode & INP_NOECHO))
127 maxlen = flayer->l_width - 1 - strlen(istr);
128 if (len > maxlen)
129 len = maxlen;
131 if (len < 0)
133 LMsg(0, "Width %d chars too small", -len);
134 return;
136 if (InitOverlayPage(sizeof(*inpdata), &InpLf, 1))
137 return;
138 inpdata = (struct inpdata *)flayer->l_data;
139 inpdata->inpmaxlen = len;
140 inpdata->inpfinfunc = finfunc;
141 inpdata->inp.pos = inpdata->inp.len = 0;
142 inpdata->inpmode = mode;
143 inpdata->privdata = data;
144 if (!priv)
145 priv = (char*)&inpdata->privdata;
146 inpdata->priv = priv;
147 inpdata->inpstringlen = 0;
148 inpdata->inpstring = NULL;
149 if (istr)
150 inp_setprompt(istr, (char *)NULL);
153 static void
154 erase_chars(inpdata, from, to, x, mv)
155 struct inpdata *inpdata;
156 char *from;
157 char *to;
158 int x;
159 int mv;
161 int chng;
162 ASSERT(from < to);
163 if (inpdata->inp.len > to - inpdata->inp.buf)
164 bcopy(to, from, inpdata->inp.len - (to - inpdata->inp.buf));
165 chng = to - from;
166 if (mv)
168 x -= chng;
169 inpdata->inp.pos -= chng;
171 inpdata->inp.len -= chng;
172 if (!(inpdata->inpmode & INP_NOECHO))
174 struct mchar mc;
175 char *s = from < to ? from : to;
176 mc = mchar_so;
177 while (s < inpdata->inp.buf+inpdata->inp.len)
179 mc.image = *s++;
180 LPutChar(flayer, &mc, x++, INPUTLINE);
182 while (chng--)
183 LPutChar(flayer, &mchar_blank, x++, INPUTLINE);
184 x = inpdata->inpstringlen + inpdata->inp.pos;
185 LGotoPos(flayer, x, INPUTLINE);
189 static void
190 InpProcess(ppbuf, plen)
191 char **ppbuf;
192 int *plen;
194 int len, x;
195 char *pbuf;
196 char ch;
197 struct inpdata *inpdata;
198 struct display *inpdisplay;
200 inpdata = (struct inpdata *)flayer->l_data;
201 inpdisplay = display;
203 LGotoPos(flayer, inpdata->inpstringlen + (inpdata->inpmode & INP_NOECHO ? 0 : inpdata->inp.pos), INPUTLINE);
204 if (ppbuf == 0)
206 InpAbort();
207 return;
209 x = inpdata->inpstringlen + inpdata->inp.pos;
210 len = *plen;
211 pbuf = *ppbuf;
212 while (len)
214 char *p = inpdata->inp.buf + inpdata->inp.pos;
216 ch = *pbuf++;
217 len--;
218 if (inpdata->inpmode & INP_EVERY)
220 inpdata->inp.buf[inpdata->inp.len] = ch;
221 if (ch)
223 display = inpdisplay;
224 (*inpdata->inpfinfunc)(inpdata->inp.buf, inpdata->inp.len, inpdata->priv);
225 ch = inpdata->inp.buf[inpdata->inp.len];
228 else if (inpdata->inpmode & INP_RAW)
230 display = inpdisplay;
231 (*inpdata->inpfinfunc)(&ch, 1, inpdata->priv); /* raw */
232 if (ch)
233 continue;
235 if (((unsigned char)ch & 0177) >= ' ' && ch != 0177 && inpdata->inp.len < inpdata->inpmaxlen)
237 if (inpdata->inp.len > inpdata->inp.pos)
238 bcopy(p, p+1, inpdata->inp.len - inpdata->inp.pos);
239 inpdata->inp.buf[inpdata->inp.pos++] = ch;
240 inpdata->inp.len++;
242 if (!(inpdata->inpmode & INP_NOECHO))
244 struct mchar mc;
245 mc = mchar_so;
246 mc.image = *p++;
247 LPutChar(flayer, &mc, x, INPUTLINE);
248 x++;
249 if (p < inpdata->inp.buf+inpdata->inp.len)
251 while (p < inpdata->inp.buf+inpdata->inp.len)
253 mc.image = *p++;
254 LPutChar(flayer, &mc, x++, INPUTLINE);
256 x = inpdata->inpstringlen + inpdata->inp.pos;
257 LGotoPos(flayer, x, INPUTLINE);
261 else if ((ch == '\b' || ch == 0177) && inpdata->inp.pos > 0)
263 erase_chars(inpdata, p-1, p, x, 1);
265 else if (ch == '\025') /* CTRL-U */
267 x = inpdata->inpstringlen;
268 if (inpdata->inp.len && !(inpdata->inpmode & INP_NOECHO))
270 LClearArea(flayer, x, INPUTLINE, x + inpdata->inp.len - 1, INPUTLINE, 0, 0);
271 LGotoPos(flayer, x, INPUTLINE);
273 inpdata->inp.len = inpdata->inp.pos = 0;
275 else if (ch == '\013') /* CTRL-K */
277 x = inpdata->inpstringlen + inpdata->inp.pos;
278 if (inpdata->inp.len > inpdata->inp.pos && !(inpdata->inpmode & INP_NOECHO))
280 LClearArea(flayer, x, INPUTLINE, x + inpdata->inp.len - inpdata->inp.pos - 1, INPUTLINE, 0, 0);
281 LGotoPos(flayer, x, INPUTLINE);
283 inpdata->inp.len = inpdata->inp.pos;
285 else if (ch == '\027' && inpdata->inp.pos > 0) /* CTRL-W */
287 char *oldp = p--;
288 while (p > inpdata->inp.buf && *p == ' ')
289 p--;
290 while (p > inpdata->inp.buf && *(p - 1) != ' ')
291 p--;
292 erase_chars(inpdata, p, oldp, x, 1);
294 else if (ch == '\004' && inpdata->inp.pos < inpdata->inp.len) /* CTRL-D */
296 erase_chars(inpdata, p, p+1, x, 0);
298 else if (ch == '\001' || (unsigned char)ch == 0201) /* CTRL-A */
300 LGotoPos(flayer, x -= inpdata->inp.pos, INPUTLINE);
301 inpdata->inp.pos = 0;
303 else if ((ch == '\002' || (unsigned char)ch == 0202) && inpdata->inp.pos > 0) /* CTRL-B */
305 LGotoPos(flayer, --x, INPUTLINE);
306 inpdata->inp.pos--;
308 else if (ch == '\005' || (unsigned char)ch == 0205) /* CTRL-E */
310 LGotoPos(flayer, x += inpdata->inp.len - inpdata->inp.pos, INPUTLINE);
311 inpdata->inp.pos = inpdata->inp.len;
313 else if ((ch == '\006' || (unsigned char)ch == 0206) && inpdata->inp.pos < inpdata->inp.len) /* CTRL-F */
315 LGotoPos(flayer, ++x, INPUTLINE);
316 inpdata->inp.pos++;
318 else if (ch == '\020' || (unsigned char)ch == 0220) /* CTRL-P */
320 struct mchar mc;
321 mc = mchar_so;
322 if (inpdata->inp.len && !(inpdata->inpmode & INP_NOECHO))
323 LClearArea(flayer, inpdata->inpstringlen, INPUTLINE, inpdata->inpstringlen + inpdata->inp.len - 1, INPUTLINE, 0, 0);
325 inpdata->inp = inphist; /* structure copy */
326 if (inpdata->inp.len > inpdata->inpmaxlen)
327 inpdata->inp.len = inpdata->inpmaxlen;
328 if (inpdata->inp.pos > inpdata->inp.len)
329 inpdata->inp.pos = inpdata->inp.len;
331 x = inpdata->inpstringlen;
332 p = inpdata->inp.buf;
334 if (!(inpdata->inpmode & INP_NOECHO))
336 while (p < inpdata->inp.buf+inpdata->inp.len)
338 mc.image = *p++;
339 LPutChar(flayer, &mc, x++, INPUTLINE);
342 x = inpdata->inpstringlen + inpdata->inp.pos;
343 LGotoPos(flayer, x, INPUTLINE);
346 else if (ch == '\003' || ch == '\007' || ch == '\033' ||
347 ch == '\000' || ch == '\n' || ch == '\r')
349 if (ch != '\n' && ch != '\r')
350 inpdata->inp.len = 0;
351 inpdata->inp.buf[inpdata->inp.len] = 0;
353 if (inpdata->inp.len && !(inpdata->inpmode & (INP_NOECHO | INP_RAW)))
354 inphist = inpdata->inp; /* structure copy */
356 flayer->l_data = 0; /* so inpdata does not get freed */
357 InpAbort(); /* redisplays... */
358 *ppbuf = pbuf;
359 *plen = len;
360 display = inpdisplay;
361 if ((inpdata->inpmode & INP_RAW) == 0)
362 (*inpdata->inpfinfunc)(inpdata->inp.buf, inpdata->inp.len, inpdata->priv);
363 else
364 (*inpdata->inpfinfunc)(pbuf - 1, 0, inpdata->priv);
365 free((char *)inpdata);
366 return;
369 if (!(inpdata->inpmode & INP_RAW))
371 flayer->l_x = inpdata->inpstringlen + (inpdata->inpmode & INP_NOECHO ? 0 : inpdata->inp.pos);
372 flayer->l_y = INPUTLINE;
374 *ppbuf = pbuf;
375 *plen = len;
378 static void
379 InpAbort()
381 LAY_CALL_UP(LayRedisplayLine(INPUTLINE, 0, flayer->l_width - 1, 0));
382 ExitOverlayPage();
385 static void
386 InpRedisplayLine(y, xs, xe, isblank)
387 int y, xs, xe, isblank;
389 int q, r, s, l, v;
390 struct inpdata *inpdata;
392 inpdata = (struct inpdata *)flayer->l_data;
393 if (y != INPUTLINE)
395 LAY_CALL_UP(LayRedisplayLine(y, xs, xe, isblank));
396 return;
398 inpdata->inp.buf[inpdata->inp.len] = 0;
399 q = xs;
400 v = xe - xs + 1;
401 s = 0;
402 r = inpdata->inpstringlen;
403 if (v > 0 && q < r)
405 l = v;
406 if (l > r - q)
407 l = r - q;
408 LPutStr(flayer, inpdata->inpstring + q - s, l, &mchar_so, q, y);
409 q += l;
410 v -= l;
412 s = r;
413 r += inpdata->inp.len;
414 if (!(inpdata->inpmode & INP_NOECHO) && v > 0 && q < r)
416 l = v;
417 if (l > r - q)
418 l = r - q;
419 LPutStr(flayer, inpdata->inp.buf + q - s, l, &mchar_so, q, y);
420 q += l;
421 v -= l;
423 s = r;
424 r = flayer->l_width;
425 if (!isblank && v > 0 && q < r)
427 l = v;
428 if (l > r - q)
429 l = r - q;
430 LClearArea(flayer, q, y, q + l - 1, y, 0, 0);
431 q += l;
436 InInput()
438 if (flayer && flayer->l_layfn == &InpLf)
439 return 1;
440 return 0;