1 /* Copyright (c) 2008, 2009
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)
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>
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
;
46 char buf
[101]; /* text buffer */
47 int len
; /* length of the editible string */
48 int pos
; /* cursor position in editable string */
49 struct inpline
*next
, *prev
;
52 /* 'inphist' is used to store the current input when scrolling through history.
53 * inpline->prev == history-prev
54 * inpline->next == history-next
56 static struct inpline inphist
;
61 int inpmaxlen
; /* 100, or less, if caller has shorter buffer */
62 char *inpstring
; /* the prompt */
63 int inpstringlen
; /* length of the prompt */
64 int inpmode
; /* INP_NOECHO, INP_RAW, INP_EVERY */
65 void (*inpfinfunc
) __P((char *buf
, int len
, char *priv
));
66 char *priv
; /* private data for finfunc */
67 int privdata
; /* private data space */
70 static struct LayFuncs InpLf
=
82 ** Here is the input routine
85 /* called once, after InitOverlayPage in Input() or Isearch() */
90 struct inpdata
*inpdata
;
92 inpdata
= (struct inpdata
*)flayer
->l_data
;
95 inpdata
->inpstringlen
= strlen(p
);
96 inpdata
->inpstring
= p
;
100 if (s
!= inpdata
->inp
.buf
)
101 strncpy(inpdata
->inp
.buf
, s
, sizeof(inpdata
->inp
.buf
) - 1);
102 inpdata
->inp
.buf
[sizeof(inpdata
->inp
.buf
) - 1] = 0;
103 inpdata
->inp
.pos
= inpdata
->inp
.len
= strlen(inpdata
->inp
.buf
);
105 InpRedisplayLine(INPUTLINE
, 0, flayer
->l_width
- 1, 0);
106 flayer
->l_x
= inpdata
->inpstringlen
+ (inpdata
->inpmode
& INP_NOECHO
? 0 : inpdata
->inp
.pos
);
107 flayer
->l_y
= INPUTLINE
;
111 * We dont use HS status line with Input().
112 * If we would use it, then we should check e_tgetflag("es") if
113 * we are allowed to use esc sequences there.
116 * INP_NOECHO == suppress echoing of characters.
117 * INP_RAW == raw mode. call finfunc after each character typed.
118 * INP_EVERY == digraph mode.
121 Input(istr
, len
, mode
, finfunc
, priv
, data
)
125 void (*finfunc
) __P((char *buf
, int len
, char *priv
));
130 struct inpdata
*inpdata
;
137 if (!(mode
& INP_NOECHO
))
139 maxlen
= flayer
->l_width
- 1 - strlen(istr
);
145 LMsg(0, "Width %d chars too small", -len
);
148 if (InitOverlayPage(sizeof(*inpdata
), &InpLf
, 1))
150 inpdata
= (struct inpdata
*)flayer
->l_data
;
151 inpdata
->inpmaxlen
= len
;
152 inpdata
->inpfinfunc
= finfunc
;
153 inpdata
->inp
.pos
= inpdata
->inp
.len
= 0;
154 inpdata
->inp
.prev
= inphist
.prev
;
155 inpdata
->inpmode
= mode
;
156 inpdata
->privdata
= data
;
158 priv
= (char*)&inpdata
->privdata
;
159 inpdata
->priv
= priv
;
160 inpdata
->inpstringlen
= 0;
161 inpdata
->inpstring
= NULL
;
163 inp_setprompt(istr
, (char *)NULL
);
167 erase_chars(inpdata
, from
, to
, x
, mv
)
168 struct inpdata
*inpdata
;
176 if (inpdata
->inp
.len
> to
- inpdata
->inp
.buf
)
177 bcopy(to
, from
, inpdata
->inp
.len
- (to
- inpdata
->inp
.buf
));
182 inpdata
->inp
.pos
-= chng
;
184 inpdata
->inp
.len
-= chng
;
185 if (!(inpdata
->inpmode
& INP_NOECHO
))
188 char *s
= from
< to
? from
: to
;
190 while (s
< inpdata
->inp
.buf
+inpdata
->inp
.len
)
193 LPutChar(flayer
, &mc
, x
++, INPUTLINE
);
196 LPutChar(flayer
, &mchar_blank
, x
++, INPUTLINE
);
197 x
= inpdata
->inpstringlen
+ inpdata
->inp
.pos
;
198 LGotoPos(flayer
, x
, INPUTLINE
);
203 InpProcess(ppbuf
, plen
)
210 struct inpdata
*inpdata
;
211 struct display
*inpdisplay
;
214 inpdata
= (struct inpdata
*)flayer
->l_data
;
215 inpdisplay
= display
;
217 LGotoPos(flayer
, inpdata
->inpstringlen
+ (inpdata
->inpmode
& INP_NOECHO
? 0 : inpdata
->inp
.pos
), INPUTLINE
);
223 x
= inpdata
->inpstringlen
+ inpdata
->inp
.pos
;
228 char *p
= inpdata
->inp
.buf
+ inpdata
->inp
.pos
;
232 if (inpdata
->inpmode
& INP_EVERY
)
234 inpdata
->inp
.buf
[inpdata
->inp
.len
] = ch
;
237 display
= inpdisplay
;
238 (*inpdata
->inpfinfunc
)(inpdata
->inp
.buf
, inpdata
->inp
.len
, inpdata
->priv
);
239 ch
= inpdata
->inp
.buf
[inpdata
->inp
.len
];
242 else if (inpdata
->inpmode
& INP_RAW
)
244 display
= inpdisplay
;
245 (*inpdata
->inpfinfunc
)(&ch
, 1, inpdata
->priv
); /* raw */
249 if (((unsigned char)ch
& 0177) >= ' ' && ch
!= 0177 && inpdata
->inp
.len
< inpdata
->inpmaxlen
)
251 if (inpdata
->inp
.len
> inpdata
->inp
.pos
)
252 bcopy(p
, p
+1, inpdata
->inp
.len
- inpdata
->inp
.pos
);
253 inpdata
->inp
.buf
[inpdata
->inp
.pos
++] = ch
;
256 if (!(inpdata
->inpmode
& INP_NOECHO
))
261 LPutChar(flayer
, &mc
, x
, INPUTLINE
);
263 if (p
< inpdata
->inp
.buf
+inpdata
->inp
.len
)
265 while (p
< inpdata
->inp
.buf
+inpdata
->inp
.len
)
268 LPutChar(flayer
, &mc
, x
++, INPUTLINE
);
270 x
= inpdata
->inpstringlen
+ inpdata
->inp
.pos
;
271 LGotoPos(flayer
, x
, INPUTLINE
);
275 else if ((ch
== '\b' || ch
== 0177) && inpdata
->inp
.pos
> 0)
277 erase_chars(inpdata
, p
-1, p
, x
, 1);
279 else if (ch
== '\025') /* CTRL-U */
281 x
= inpdata
->inpstringlen
;
282 if (inpdata
->inp
.len
&& !(inpdata
->inpmode
& INP_NOECHO
))
284 LClearArea(flayer
, x
, INPUTLINE
, x
+ inpdata
->inp
.len
- 1, INPUTLINE
, 0, 0);
285 LGotoPos(flayer
, x
, INPUTLINE
);
287 inpdata
->inp
.len
= inpdata
->inp
.pos
= 0;
289 else if (ch
== '\013') /* CTRL-K */
291 x
= inpdata
->inpstringlen
+ inpdata
->inp
.pos
;
292 if (inpdata
->inp
.len
> inpdata
->inp
.pos
&& !(inpdata
->inpmode
& INP_NOECHO
))
294 LClearArea(flayer
, x
, INPUTLINE
, x
+ inpdata
->inp
.len
- inpdata
->inp
.pos
- 1, INPUTLINE
, 0, 0);
295 LGotoPos(flayer
, x
, INPUTLINE
);
297 inpdata
->inp
.len
= inpdata
->inp
.pos
;
299 else if (ch
== '\027' && inpdata
->inp
.pos
> 0) /* CTRL-W */
302 while (p
> inpdata
->inp
.buf
&& *p
== ' ')
304 while (p
> inpdata
->inp
.buf
&& *(p
- 1) != ' ')
306 erase_chars(inpdata
, p
, oldp
, x
, 1);
308 else if (ch
== '\004' && inpdata
->inp
.pos
< inpdata
->inp
.len
) /* CTRL-D */
310 erase_chars(inpdata
, p
, p
+1, x
, 0);
312 else if (ch
== '\001' || (unsigned char)ch
== 0201) /* CTRL-A */
314 LGotoPos(flayer
, x
-= inpdata
->inp
.pos
, INPUTLINE
);
315 inpdata
->inp
.pos
= 0;
317 else if ((ch
== '\002' || (unsigned char)ch
== 0202) && inpdata
->inp
.pos
> 0) /* CTRL-B */
319 LGotoPos(flayer
, --x
, INPUTLINE
);
322 else if (ch
== '\005' || (unsigned char)ch
== 0205) /* CTRL-E */
324 LGotoPos(flayer
, x
+= inpdata
->inp
.len
- inpdata
->inp
.pos
, INPUTLINE
);
325 inpdata
->inp
.pos
= inpdata
->inp
.len
;
327 else if ((ch
== '\006' || (unsigned char)ch
== 0206) && inpdata
->inp
.pos
< inpdata
->inp
.len
) /* CTRL-F */
329 LGotoPos(flayer
, ++x
, INPUTLINE
);
332 else if ((prev
= ((ch
== '\020' || (unsigned char)ch
== 0220) && /* CTRL-P */
333 inpdata
->inp
.prev
)) ||
334 (next
= ((ch
== '\016' || (unsigned char)ch
== 0216) && /* CTRL-N */
339 if (inpdata
->inp
.len
&& !(inpdata
->inpmode
& INP_NOECHO
))
340 LClearArea(flayer
, inpdata
->inpstringlen
, INPUTLINE
, inpdata
->inpstringlen
+ inpdata
->inp
.len
- 1, INPUTLINE
, 0, 0);
342 if (prev
&& !inpdata
->inp
.next
)
343 inphist
= inpdata
->inp
;
344 memcpy(&inpdata
->inp
, prev
? inpdata
->inp
.prev
: inpdata
->inp
.next
, sizeof(struct inpline
));
345 if (inpdata
->inp
.len
> inpdata
->inpmaxlen
)
346 inpdata
->inp
.len
= inpdata
->inpmaxlen
;
347 if (inpdata
->inp
.pos
> inpdata
->inp
.len
)
348 inpdata
->inp
.pos
= inpdata
->inp
.len
;
350 x
= inpdata
->inpstringlen
;
351 p
= inpdata
->inp
.buf
;
353 if (!(inpdata
->inpmode
& INP_NOECHO
))
355 while (p
< inpdata
->inp
.buf
+inpdata
->inp
.len
)
358 LPutChar(flayer
, &mc
, x
++, INPUTLINE
);
361 x
= inpdata
->inpstringlen
+ inpdata
->inp
.pos
;
362 LGotoPos(flayer
, x
, INPUTLINE
);
365 else if (ch
== '\003' || ch
== '\007' || ch
== '\033' ||
366 ch
== '\000' || ch
== '\n' || ch
== '\r')
368 if (ch
!= '\n' && ch
!= '\r')
369 inpdata
->inp
.len
= 0;
370 inpdata
->inp
.buf
[inpdata
->inp
.len
] = 0;
372 if (inpdata
->inp
.len
&& !(inpdata
->inpmode
& (INP_NOECHO
| INP_RAW
)))
374 struct inpline
*store
;
376 /* Look for a duplicate first */
377 for (store
= inphist
.prev
; store
; store
= store
->prev
)
379 if (strcmp(store
->buf
, inpdata
->inp
.buf
) == 0)
382 store
->next
->prev
= store
->prev
;
384 store
->prev
->next
= store
->next
;
385 store
->pos
= inpdata
->inp
.pos
;
392 store
= malloc(sizeof(struct inpline
));
393 memcpy(store
, &inpdata
->inp
, sizeof(struct inpline
));
395 store
->next
= &inphist
;
396 store
->prev
= inphist
.prev
;
398 inphist
.prev
->next
= store
;
399 inphist
.prev
= store
;
402 flayer
->l_data
= 0; /* so inpdata does not get freed */
403 InpAbort(); /* redisplays... */
406 display
= inpdisplay
;
407 if ((inpdata
->inpmode
& INP_RAW
) == 0)
408 (*inpdata
->inpfinfunc
)(inpdata
->inp
.buf
, inpdata
->inp
.len
, inpdata
->priv
);
410 (*inpdata
->inpfinfunc
)(pbuf
- 1, 0, inpdata
->priv
);
411 free((char *)inpdata
);
415 if (!(inpdata
->inpmode
& INP_RAW
))
417 flayer
->l_x
= inpdata
->inpstringlen
+ (inpdata
->inpmode
& INP_NOECHO
? 0 : inpdata
->inp
.pos
);
418 flayer
->l_y
= INPUTLINE
;
427 LAY_CALL_UP(LayRedisplayLine(INPUTLINE
, 0, flayer
->l_width
- 1, 0));
432 InpRedisplayLine(y
, xs
, xe
, isblank
)
433 int y
, xs
, xe
, isblank
;
436 struct inpdata
*inpdata
;
438 inpdata
= (struct inpdata
*)flayer
->l_data
;
441 LAY_CALL_UP(LayRedisplayLine(y
, xs
, xe
, isblank
));
444 inpdata
->inp
.buf
[inpdata
->inp
.len
] = 0;
448 r
= inpdata
->inpstringlen
;
454 LPutStr(flayer
, inpdata
->inpstring
+ q
- s
, l
, &mchar_so
, q
, y
);
459 r
+= inpdata
->inp
.len
;
460 if (!(inpdata
->inpmode
& INP_NOECHO
) && v
> 0 && q
< r
)
465 LPutStr(flayer
, inpdata
->inp
.buf
+ q
- s
, l
, &mchar_so
, q
, y
);
471 if (!isblank
&& v
> 0 && q
< r
)
476 LClearArea(flayer
, q
, y
, q
+ l
- 1, y
, 0, 0);
484 if (flayer
&& flayer
->l_layfn
== &InpLf
)