revert between 56095 -> 55830 in arch
[AROS.git] / rom / filesys / console_handler / support.c
blobeb969c100aab19795f23df4eb2a2fb76ca88ad2d
1 /*
2 Copyright © 1995-2015, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Support functions for console handler.
6 Lang: english
7 */
9 /****************************************************************************************/
11 #define CYCLIC_HISTORY_WALK 0
13 /****************************************************************************************/
15 #include <proto/exec.h>
16 #include <exec/libraries.h>
17 #include <exec/resident.h>
18 #include <exec/memory.h>
19 #include <exec/io.h>
20 #include <exec/errors.h>
21 #include <exec/alerts.h>
22 #include <utility/tagitem.h>
23 #include <dos/exall.h>
24 #include <dos/dosasl.h>
25 #include <intuition/intuition.h>
26 #include <intuition/sghooks.h>
27 #include <proto/dos.h>
28 #include <proto/intuition.h>
29 #include <proto/input.h>
30 #include <devices/conunit.h>
32 #define SDEBUG 0
33 #define DEBUG 0
34 #include <aros/debug.h>
36 #include <string.h>
37 #include <stdio.h>
38 #include <ctype.h>
40 #include "con_handler_intern.h"
41 #include "support.h"
42 #include "completion.h"
44 #define ioReq(x) ((struct IORequest *)x)
46 void replypkt(struct DosPacket *dp, SIPTR res1)
48 struct MsgPort *mp;
49 struct Message *mn;
51 mp = dp->dp_Port;
52 mn = dp->dp_Link;
53 mn->mn_Node.ln_Name = (char*) dp;
54 dp->dp_Port = &((struct Process*) FindTask(NULL))->pr_MsgPort;
55 dp->dp_Res1 = res1;
56 PutMsg(mp, mn);
58 void replypkt2(struct DosPacket *dp, SIPTR res1, SIPTR res2)
60 dp->dp_Res2 = res2;
61 replypkt(dp, res1);
65 /******************************************************************************************/
67 static const UBYTE up_seq[] = { 'A' };
68 static const UBYTE down_seq[] = { 'B' };
69 static const UBYTE right_seq[] = { 'C' };
70 static const UBYTE left_seq[] = { 'D' };
71 static const UBYTE shift_up_seq[] = { 'T' };
72 static const UBYTE shift_down_seq[] = { 'S' };
73 static const UBYTE shift_right_seq[] = { ' ', '@' };
74 static const UBYTE shift_left_seq[] = { ' ', 'A' };
75 static const UBYTE shift_tab_seq[] = { 'Z' };
76 static const UBYTE help_seq[] = { '?', '~' };
77 static const UBYTE f1_seq[] = { '0', '~' };
78 static const UBYTE f2_seq[] = { '1', '~' };
79 static const UBYTE f3_seq[] = { '2', '~' };
80 static const UBYTE f4_seq[] = { '3', '~' };
81 static const UBYTE f5_seq[] = { '4', '~' };
82 static const UBYTE f6_seq[] = { '5', '~' };
83 static const UBYTE f7_seq[] = { '6', '~' };
84 static const UBYTE f8_seq[] = { '7', '~' };
85 static const UBYTE f9_seq[] = { '8', '~' };
86 static const UBYTE f10_seq[] = { '9', '~' };
87 static const UBYTE paste_seq[] = { '0', ' ', 'v' };
88 static const UBYTE f11_seq[] = { '2', '0', '~' };
89 static const UBYTE f12_seq[] = { '2', '1', '~' };
90 static const UBYTE shift_f1_seq[] = { '1', '0', '~' };
91 static const UBYTE shift_f2_seq[] = { '1', '1', '~' };
92 static const UBYTE shift_f3_seq[] = { '1', '2', '~' };
93 static const UBYTE shift_f4_seq[] = { '1', '3', '~' };
94 static const UBYTE shift_f5_seq[] = { '1', '4', '~' };
95 static const UBYTE shift_f6_seq[] = { '1', '5', '~' };
96 static const UBYTE shift_f7_seq[] = { '1', '6', '~' };
97 static const UBYTE shift_f8_seq[] = { '1', '7', '~' };
98 static const UBYTE shift_f9_seq[] = { '1', '8', '~' };
99 static const UBYTE shift_f10_seq[] = { '1', '9', '~' };
100 static const UBYTE shift_f11_seq[] = { '3', '0', '~' };
101 static const UBYTE shift_f12_seq[] = { '3', '1', '~' };
102 static const UBYTE insert_seq[] = { '4', '0', '~' };
103 static const UBYTE pageup_seq[] = { '4', '1', '~' };
104 static const UBYTE pagedown_seq[] = { '4', '2', '~' };
105 static const UBYTE pause_seq[] = { '4', '3', '~' };
106 static const UBYTE break_seq[] = { '5', '3', '~' };
107 static const UBYTE home_seq[] = { '4', '4', '~' };
108 static const UBYTE end_seq[] = { '4', '5', '~' };
109 static const UBYTE shift_insert_seq[] = { '5', '0', '~' };
110 static const UBYTE shift_pageup_seq[] = { '5', '1', '~' };
111 static const UBYTE shift_pagedown_seq[] = { '5', '2', '~' };
112 static const UBYTE shift_home_seq[] = { '5', '4', '~' };
113 static const UBYTE shift_end_seq[] = { '5', '5', '~' };
115 /* F11, F12, insert, pageup, pagedown, ... seq taken from
116 RKRM: Devices/Console/Reading from the Console Device/Information about the Input Stream */
118 static CONST struct csimatch
120 CONST UBYTE *seq;
121 WORD len;
122 WORD inp;
124 csimatchtable[] =
126 {up_seq , 1, INP_CURSORUP },
127 {down_seq , 1, INP_CURSORDOWN },
128 {right_seq , 1, INP_CURSORRIGHT },
129 {left_seq , 1, INP_CURSORLEFT },
130 {shift_up_seq , 1, INP_SHIFT_CURSORUP },
131 {shift_down_seq , 1, INP_SHIFT_CURSORDOWN },
132 {shift_right_seq , 2, INP_SHIFT_CURSORRIGHT },
133 {shift_left_seq , 2, INP_SHIFT_CURSORLEFT },
134 {shift_tab_seq , 1, INP_SHIFT_TAB },
135 {help_seq , 2, INP_HELP },
136 {f1_seq , 2, INP_F1 },
137 {f2_seq , 2, INP_F2 },
138 {f3_seq , 2, INP_F3 },
139 {f4_seq , 2, INP_F4 },
140 {f5_seq , 2, INP_F5 },
141 {f6_seq , 2, INP_F6 },
142 {f7_seq , 2, INP_F7 },
143 {f8_seq , 2, INP_F8 },
144 {f9_seq , 2, INP_F9 },
145 {f10_seq , 2, INP_F10 },
146 {f11_seq , 3, INP_F11 },
147 {f12_seq , 3, INP_F12 },
148 {shift_f1_seq , 3, INP_SHIFT_F1 },
149 {shift_f2_seq , 3, INP_SHIFT_F2 },
150 {shift_f3_seq , 3, INP_SHIFT_F3 },
151 {shift_f4_seq , 3, INP_SHIFT_F4 },
152 {shift_f5_seq , 3, INP_SHIFT_F5 },
153 {shift_f6_seq , 3, INP_SHIFT_F6 },
154 {shift_f7_seq , 3, INP_SHIFT_F7 },
155 {shift_f8_seq , 3, INP_SHIFT_F8 },
156 {shift_f9_seq , 3, INP_SHIFT_F9 },
157 {shift_f10_seq , 3, INP_SHIFT_F10 },
158 {shift_f11_seq , 3, INP_SHIFT_F11 },
159 {shift_f12_seq , 3, INP_SHIFT_F12 },
160 {insert_seq , 3, INP_INSERT },
161 {pageup_seq , 3, INP_PAGEUP },
162 {pagedown_seq , 3, INP_PAGEDOWN },
163 {pause_seq , 3, INP_PAUSE },
164 {break_seq , 3, INP_BREAK },
165 {home_seq , 3, INP_HOME },
166 {end_seq , 3, INP_END },
167 {shift_insert_seq , 3, INP_SHIFT_INSERT },
168 {shift_pageup_seq , 3, INP_SHIFT_PAGEUP },
169 {shift_pagedown_seq , 3, INP_SHIFT_PAGEDOWN },
170 {shift_home_seq , 3, INP_SHIFT_HOME },
171 {shift_end_seq , 3, INP_SHIFT_END },
172 {paste_seq , 3, INP_PASTE },
173 {0 , 0, 0 }
177 /******************************************************************************************/
179 static UBYTE hex2val(char c)
181 if (c >= '0' && c <= '9')
182 return c - '0';
183 c &= ~0x20;
184 return c - 'A' + 10;
186 /* strtoul() not used because it is much larger and uses .bss
187 * TODO: Sanity checks. */
188 static IPTR string2val(const char *s, WORD len)
190 IPTR v = 0;
192 if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
194 s += 2;
195 while (len-- > 0 && *s)
197 v <<= 4;
198 v |= hex2val(*s);
199 s++;
202 else
204 while (len-- > 0 && *s)
206 v *= 10;
207 v += *s - '0';
208 s++;
211 return v;
214 BOOL parse_filename(struct filehandle *fh, char *filename, struct NewWindow *nw)
216 char *param;
217 UBYTE c;
218 WORD paramid = 1;
219 LONG paramval = 0;
220 BOOL ok = TRUE, done = FALSE, paramok = FALSE;
222 ASSERT_VALID_PTR(fh);
223 ASSERT_VALID_PTR(nw);
225 param = filename;
226 ASSERT_VALID_PTR(param);
228 while (!done)
230 c = *filename++;
232 switch (c)
234 case '0':
235 case '1':
236 case '2':
237 case '3':
238 case '4':
239 case '5':
240 case '6':
241 case '7':
242 case '8':
243 case '9':
244 if (paramid <= 4)
246 paramval *= 10;
247 paramval += c - '0';
249 paramok = TRUE;
250 break;
252 case '\0':
253 done = TRUE;
254 /* fall through */
256 case '/':
257 if (paramok)
259 UWORD paramlen = filename - param - 1;
261 switch (paramid)
263 case 1:
264 nw->LeftEdge = paramval;
265 break;
267 case 2:
268 nw->TopEdge = paramval;
269 break;
271 case 3:
272 nw->Width = paramval;
273 break;
275 case 4:
276 nw->Height = paramval;
277 break;
279 case 5:
280 if ((fh->wintitle = AllocVec(paramlen + 1, MEMF_PUBLIC)))
282 CopyMem(param, fh->wintitle, paramlen);
283 fh->wintitle[paramlen] = '\0';
284 nw->Title = fh->wintitle;
286 break;
288 default:
289 if (!strnicmp(param, "WAIT", paramlen))
291 fh->flags |= FHFLG_WAIT;
293 else if (!strnicmp(param, "CLOSE", paramlen))
295 nw->Flags |= WFLG_CLOSEGADGET;
297 else if (!strnicmp(param, "NOCLOSE", paramlen))
299 nw->Flags &= ~WFLG_CLOSEGADGET;
301 else if (!strnicmp(param, "AUTO", paramlen))
303 fh->flags |= FHFLG_AUTO;
305 else if (!strnicmp(param, "INACTIVE", paramlen))
307 nw->Flags &= ~WFLG_ACTIVATE;
309 else if (!strnicmp(param, "NODEPTH", paramlen))
311 nw->Flags &= ~WFLG_DEPTHGADGET;
313 else if (!strnicmp(param, "NOSIZE", paramlen))
315 nw->Flags &= ~WFLG_SIZEGADGET;
317 else if (!strnicmp(param, "NODRAG", paramlen))
319 nw->Flags &= ~WFLG_DRAGBAR;
321 else if (!strnicmp(param, "NOBORDER", paramlen))
323 nw->Flags |= WFLG_BORDERLESS;
325 else if (!strnicmp(param, "BACKDROP", paramlen))
327 nw->Flags |= WFLG_BACKDROP;
328 nw->Flags &= ~(WFLG_DRAGBAR | WFLG_SIZEGADGET);
330 else if (!strnicmp(param, "SIMPLE", paramlen))
332 /* TODO */
334 else if (!strnicmp(param, "SMART", paramlen))
336 /* TODO */
338 else if (!strnicmp(param, "ALT", paramlen))
340 /* TODO: style "ALT30/30/200/200" */
342 else if (!strnicmp(param, "WINDOW", 6))
344 /* Do we need some sanity checks here? */
345 fh->otherwindow = (struct Window*) string2val(param + 6, paramlen - 6);
347 else if (!strnicmp(param, "SCREEN", 6))
349 if ((fh->screenname = AllocVec(paramlen - 5, MEMF_PUBLIC)))
351 CopyMem(param + 6, fh->screenname, paramlen - 6);
352 fh->screenname[paramlen - 6] = '\0';
355 else if (!strnicmp(param, "BOOT", paramlen)) /* Private parameter */
357 fh->flags |= FHFLG_BOOTCON;
359 break;
361 } /* switch(paramid) */
363 paramok = FALSE;
365 } /* if (paramok) */
367 paramval = 0;
368 paramid++;
369 param = filename;
370 break;
372 default:
373 if (paramid < 5)
375 done = TRUE;
376 ok = FALSE;
378 else
379 paramok = TRUE;
380 break;
382 } /* switch(c) */
384 } /* while (!done) */
386 return ok;
389 /******************************************************************************************/
391 void do_write(struct filehandle *fh, APTR data, ULONG length)
393 fh->conwriteio.io_Command = CMD_WRITE;
394 fh->conwriteio.io_Data = data;
395 fh->conwriteio.io_Length = length;
397 DoIO((struct IORequest *) &fh->conwriteio);
400 /******************************************************************************************/
402 void do_movecursor(struct filehandle *fh, UBYTE direction, UBYTE howmuch)
404 UBYTE seq[6]; /* 9B <N> <N> <N> <dir> <0> */
405 ULONG size;
407 if (howmuch > 0)
409 seq[0] = 0x9B;
411 if (howmuch == 1)
413 seq[1] = direction;
414 size = 2;
416 else
418 sprintf(&seq[1], "%d%c", howmuch, direction);
419 size = strlen(seq);
422 do_write(fh, seq, size);
426 /******************************************************************************************/
428 void do_cursorvisible(struct filehandle *fh, BOOL on)
430 UBYTE seq[4];
431 ULONG size = 0;
433 seq[size++] = 0x9B;
434 if (!on)
435 seq[size++] = '0';
436 seq[size++] = ' ';
437 seq[size++] = 'p';
439 do_write(fh, seq, size);
442 /******************************************************************************************/
444 void do_deletechar(struct filehandle *fh)
446 UBYTE seq[] =
447 { 0x9B, 'P' };
449 do_write(fh, seq, 2);
452 /******************************************************************************************/
454 void do_eraseinline(struct filehandle *fh)
456 UBYTE seq[] =
457 { 0x9B, 'K' };
459 do_write(fh, seq, 2);
462 /******************************************************************************************/
464 void do_eraseindisplay(struct filehandle *fh)
466 UBYTE seq[] =
467 { 0x9B, 'J' };
469 do_write(fh, seq, 2);
471 /******************************************************************************************/
472 static void copy_from_pastebuf(struct filehandle * fh)
474 if (fh->conbufferpos >= fh->conbuffersize && fh->pastebuffer && fh->pastebufferpos < fh->pastebuffersize)
476 ULONG len = CONSOLEBUFFER_SIZE;
477 ULONG pastelen = fh->pastebuffersize - fh->pastebufferpos;
478 if (pastelen < len)
479 len = pastelen;
481 D(bug("Copying %d bytes from paste buffer\n", len));
483 fh->conbufferpos = 0;
484 CopyMem(fh->pastebuffer + fh->pastebufferpos, &fh->consolebuffer, len);
485 fh->conbuffersize = len;
486 fh->pastebufferpos += len;
487 if (fh->pastebufferpos >= fh->pastebuffersize)
489 FreeMem(fh->pastebuffer, PASTEBUFSIZE);
490 fh->pastebuffer = 0;
495 WORD scan_input(struct filehandle *fh, UBYTE *buffer)
497 CONST
498 struct csimatch *match;
499 UBYTE c;
500 WORD result = INP_DONE;
502 copy_from_pastebuf(fh);
504 if (fh->conbufferpos < fh->conbuffersize)
506 c = fh->consolebuffer[fh->conbufferpos++];
507 D(bug("scan_input: check char %d\n", c));
508 switch (c)
510 case 3:
511 case 4:
512 case 5:
513 case 6:
514 result = INP_CTRL_C - 3 + (WORD) c;
515 break;
517 case 8:
518 /* FIXME: Ugh... Race condition, anyone? The qualifier might
519 have changed between the keypress and the time we do this */
520 if (PeekQualifier() & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
522 result = INP_SHIFT_BACKSPACE;
524 else
526 result = INP_BACKSPACE;
528 break;
530 case 9:
531 result = INP_TAB;
532 break;
534 case 10:
535 result = INP_LINEFEED;
536 break;
538 case 12: /* CTRL-L */
539 *buffer = c;
540 result = INP_ECHO_STRING;
541 break;
543 case 13:
544 result = INP_RETURN;
545 break;
547 case 127:
548 if (PeekQualifier() & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
550 result = INP_SHIFT_DELETE;
552 else
554 result = INP_DELETE;
556 break;
558 case 24:
559 result = INP_CONTROL_X;
560 break;
562 case 28: /* CTRL-\ */
563 result = INP_EOF;
564 break;
566 case 0x9B: /* CSI */
567 result = INP_UNKNOWN;
569 match = csimatchtable;
570 for (; match->seq; match++)
572 if (!strncmp(match->seq, &(fh->consolebuffer[fh->conbufferpos]), match->len))
574 result = match->inp;
575 fh->conbufferpos += match->len;
576 break;
579 break;
581 default:
582 /* normal keys */
583 *buffer = c;
584 result = INP_STRING;
585 break;
587 } /* switch(c) */
589 } /* if (fh->conbufferpos < fh->conbuffersize) */
591 D(bug("scan_input: result %d\n", result));
593 return result;
596 /******************************************************************************************/
598 void add_to_history(struct filehandle *fh)
600 BOOL add_to_history = FALSE;
602 fh->inputbuffer[fh->inputsize] = '\0';
604 /* Don't add emptry strings */
605 if (fh->inputbuffer[fh->inputstart] == '\0')
606 return;
608 if (fh->historysize == 0)
610 add_to_history = TRUE;
612 else
614 WORD old_historypos;
616 old_historypos = fh->historypos - 1;
617 if (old_historypos < 0)
618 old_historypos = fh->historysize - 1;
620 if (strcmp(&fh->inputbuffer[fh->inputstart], fh->historybuffer[old_historypos]))
622 /* add to history only if different from last history entry */
624 add_to_history = TRUE;
628 if (add_to_history)
630 if (fh->historysize < CMD_HISTORY_SIZE)
631 fh->historysize++;
633 strcpy(fh->historybuffer[fh->historypos], &fh->inputbuffer[fh->inputstart]);
635 fh->historypos++;
636 if (fh->historypos >= CMD_HISTORY_SIZE)
637 fh->historypos = 0;
640 fh->historyviewpos = fh->historypos;
643 /******************************************************************************************/
645 void history_walk(struct filehandle *fh, WORD inp)
647 if (fh->historysize)
649 #if !CYCLIC_HISTORY_WALK
650 BOOL walk_to_empty_string = FALSE;
651 #endif
652 WORD len;
654 switch (inp)
656 case INP_SHIFT_CURSORUP:
657 fh->historyviewpos = 0;
658 break;
660 case INP_SHIFT_CURSORDOWN:
661 fh->historyviewpos = fh->historysize - 1;
663 break;
665 case INP_CURSORUP:
666 #if CYCLIC_HISTORY_WALK
667 fh->historyviewpos--;
668 if (fh->historyviewpos < 0) fh->historyviewpos = fh->historysize - 1;
669 #else
670 if (fh->historyviewpos != -1)
672 fh->historyviewpos--;
673 if (fh->historyviewpos < 0 && fh->historysize == CMD_HISTORY_SIZE)
674 fh->historyviewpos = CMD_HISTORY_SIZE - 1;
675 if (fh->historyviewpos == fh->historypos)
676 fh->historyviewpos = -1;
678 if (fh->historyviewpos == -1)
679 walk_to_empty_string = TRUE;
680 #endif
681 break;
683 case INP_CURSORDOWN:
684 #if CYCLIC_HISTORY_WALK
685 fh->historyviewpos++;
686 if (fh->historyviewpos >= fh->historysize) fh->historyviewpos = 0;
687 #else
688 if (fh->historyviewpos != fh->historypos)
690 if (fh->historyviewpos == -1 && fh->historysize == CMD_HISTORY_SIZE)
691 fh->historyviewpos = fh->historypos;
692 fh->historyviewpos = (fh->historyviewpos + 1) % CMD_HISTORY_SIZE;
694 if (fh->historyviewpos == fh->historypos)
695 walk_to_empty_string = TRUE;
696 #endif
697 break;
700 if (fh->inputpos > fh->inputstart)
702 do_movecursor(fh, CUR_LEFT, fh->inputpos - fh->inputstart);
705 do_eraseinline(fh);
707 fh->inputsize = fh->inputstart;
708 fh->inputpos = fh->inputstart;
710 #if !CYCLIC_HISTORY_WALK
711 if (!walk_to_empty_string)
713 #endif
714 len = strlen(fh->historybuffer[fh->historyviewpos]);
715 if (len > (INPUTBUFFER_SIZE - fh->inputstart))
717 len = INPUTBUFFER_SIZE - fh->inputstart;
720 if (len > 0)
722 CopyMem(fh->historybuffer[fh->historyviewpos], &fh->inputbuffer[fh->inputstart], len);
724 fh->inputsize += len;
725 fh->inputpos += len;
727 do_write(fh, &fh->inputbuffer[fh->inputstart], len);
730 #if !CYCLIC_HISTORY_WALK
731 } /* if (!walk_to_empty_string) */
732 #endif
734 } /* if (fh->historysize) */
737 /****************************************************************************************/
739 static const STRPTR CONCLIP_PORTNAME = "ConClip.rendezvous";
741 struct MyEditHookMsg
743 struct Message msg;
744 struct SGWork *sgw;
745 WORD code;
748 static void do_paste(struct filehandle * fh)
750 struct MsgPort replyport, *port;
751 struct SGWork sgw;
752 struct MyEditHookMsg msg;
753 struct StringInfo sinfo;
755 if (!(port = FindPort(CONCLIP_PORTNAME)))
757 D(bug("ConClip not running, but we got a ConClip paste request"));
758 return;
761 D(bug("PASTE REQUEST!\n"));
763 memset( &replyport, 0, sizeof( replyport ) );
764 replyport.mp_Node.ln_Type = NT_MSGPORT;
765 replyport.mp_Flags = PA_SIGNAL;
766 replyport.mp_SigBit = SIGB_SINGLE;
767 replyport.mp_SigTask = FindTask(NULL);
768 NEWLIST(&replyport.mp_MsgList);
770 msg.msg.mn_Node.ln_Type = NT_MESSAGE;
771 msg.msg.mn_ReplyPort = &replyport;
772 msg.msg.mn_Length = sizeof(msg);
774 msg.code = 'V';
775 msg.sgw = &sgw;
777 /* FIXME: Ensure no fields are left uninitialized */
779 sgw.Gadget = 0;
780 sgw.WorkBuffer = AllocMem(PASTEBUFSIZE, MEMF_CLEAR | MEMF_ANY);
781 sgw.PrevBuffer = 0;
782 sgw.IEvent = 0;
783 sgw.Code = 'V';
784 sgw.Actions = 0;
785 sgw.LongInt = 0;
786 sgw.GadgetInfo = 0;
787 sgw.EditOp = EO_BIGCHANGE;
788 sgw.BufferPos = 0;
789 sgw.NumChars = 0;
791 /* ConClip only ever looks at MaxChars in StringInfo */
792 sinfo.MaxChars = PASTEBUFSIZE;
793 sgw.StringInfo = &sinfo;
795 SetSignal(0, SIGF_SINGLE);
796 PutMsg(port, &msg.msg);
797 WaitPort(&replyport);
799 D(bug("Pasting %d bytes\n", sgw.BufferPos));
801 if (fh->pastebuffer)
802 FreeMem(fh->pastebuffer, PASTEBUFSIZE);
803 fh->pastebuffer = sgw.WorkBuffer;
804 fh->pastebuffersize = sgw.BufferPos;
805 fh->pastebufferpos = 0;
808 /****************************************************************************************/
810 BOOL process_input(struct filehandle *fh)
812 UBYTE c;
813 WORD inp;
814 while ((inp = scan_input(fh, &c)) != INP_DONE)
816 D(bug("Input Code: %d\n", inp));
818 switch (inp)
820 case INP_CURSORLEFT:
821 if (fh->inputpos > fh->inputstart)
823 fh->inputpos--;
824 do_movecursor(fh, CUR_LEFT, 1);
826 break;
828 case INP_SHIFT_CURSORLEFT: /* move to beginning of line */
829 case INP_HOME:
830 if (fh->inputpos > fh->inputstart)
832 do_movecursor(fh, CUR_LEFT, fh->inputpos - fh->inputstart);
833 fh->inputpos = fh->inputstart;
835 break;
837 case INP_CURSORRIGHT:
838 if (fh->inputpos < fh->inputsize)
840 fh->inputpos++;
841 do_movecursor(fh, CUR_RIGHT, 1);
843 break;
845 case INP_SHIFT_CURSORRIGHT: /* move to end of line */
846 case INP_END:
847 if (fh->inputpos != fh->inputsize)
849 do_movecursor(fh, CUR_RIGHT, fh->inputsize - fh->inputpos);
850 fh->inputpos = fh->inputsize;
852 break;
854 case INP_CURSORUP: /* walk through cmd history */
855 case INP_CURSORDOWN:
856 case INP_SHIFT_CURSORUP:
857 case INP_SHIFT_CURSORDOWN:
858 history_walk(fh, inp);
859 break;
861 case INP_BACKSPACE:
862 if (fh->inputpos > fh->inputstart)
864 do_movecursor(fh, CUR_LEFT, 1);
866 if (fh->inputpos == fh->inputsize)
868 do_deletechar(fh);
870 fh->inputsize--;
871 fh->inputpos--;
873 else
875 WORD chars_right = fh->inputsize - fh->inputpos;
877 fh->inputsize--;
878 fh->inputpos--;
880 do_cursorvisible(fh, FALSE);
881 do_write(fh, &fh->inputbuffer[fh->inputpos + 1], chars_right);
882 do_deletechar(fh);
883 do_movecursor(fh, CUR_LEFT, chars_right);
884 do_cursorvisible(fh, TRUE);
886 memmove(&fh->inputbuffer[fh->inputpos], &fh->inputbuffer[fh->inputpos + 1], chars_right);
890 break;
892 case INP_SHIFT_BACKSPACE:
893 if (fh->inputpos > fh->inputstart)
895 do_movecursor(fh, CUR_LEFT, fh->inputpos - fh->inputstart);
896 if (fh->inputpos == fh->inputsize)
898 do_eraseinline(fh);
900 fh->inputpos = fh->inputsize = fh->inputstart;
902 else
904 WORD chars_right = fh->inputsize - fh->inputpos;
906 do_cursorvisible(fh, FALSE);
907 do_write(fh, &fh->inputbuffer[fh->inputpos], chars_right);
908 do_eraseinline(fh);
909 do_movecursor(fh, CUR_LEFT, chars_right);
910 do_cursorvisible(fh, TRUE);
912 memmove(&fh->inputbuffer[fh->inputstart], &fh->inputbuffer[fh->inputpos], chars_right);
914 fh->inputsize -= (fh->inputpos - fh->inputstart);
915 fh->inputpos = fh->inputstart;
918 break;
920 case INP_DELETE:
921 if (fh->inputpos < fh->inputsize)
923 fh->inputsize--;
925 if (fh->inputpos == fh->inputsize)
927 do_deletechar(fh);
929 else
931 WORD chars_right = fh->inputsize - fh->inputpos;
933 do_cursorvisible(fh, FALSE);
934 do_write(fh, &fh->inputbuffer[fh->inputpos + 1], chars_right);
935 do_deletechar(fh);
936 do_movecursor(fh, CUR_LEFT, chars_right);
937 do_cursorvisible(fh, TRUE);
939 memmove(&fh->inputbuffer[fh->inputpos], &fh->inputbuffer[fh->inputpos + 1], chars_right);
942 break;
944 case INP_SHIFT_DELETE:
945 if (fh->inputpos < fh->inputsize)
947 fh->inputsize = fh->inputpos;
948 do_eraseinline(fh);
950 break;
952 case INP_CONTROL_X:
953 if ((fh->inputsize - fh->inputstart) > 0)
955 if (fh->inputpos > fh->inputstart)
957 do_movecursor(fh, CUR_LEFT, fh->inputpos - fh->inputstart);
959 do_eraseinline(fh);
961 fh->inputpos = fh->inputsize = fh->inputstart;
963 break;
965 case INP_ECHO_STRING:
966 do_write(fh, &c, 1);
967 break;
969 case INP_STRING:
970 if (fh->inputsize < INPUTBUFFER_SIZE)
972 do_write(fh, &c, 1);
974 if (fh->inputpos == fh->inputsize)
976 fh->inputbuffer[fh->inputpos++] = c;
977 fh->inputsize++;
979 else
981 WORD chars_right = fh->inputsize - fh->inputpos;
983 do_cursorvisible(fh, FALSE);
984 do_write(fh, &fh->inputbuffer[fh->inputpos], chars_right);
985 do_movecursor(fh, CUR_LEFT, chars_right);
986 do_cursorvisible(fh, TRUE);
988 memmove(&fh->inputbuffer[fh->inputpos + 1], &fh->inputbuffer[fh->inputpos], chars_right);
989 fh->inputbuffer[fh->inputpos++] = c;
990 fh->inputsize++;
993 break;
995 case INP_EOF:
996 D(bug("[CON] Read EOF (window closing)\n"));
998 if (fh->flags & FHFLG_WAITFORCLOSE)
999 return TRUE;
1001 fh->flags |= FHFLG_EOF;
1002 if (fh->flags & FHFLG_AUTO && fh->window)
1004 if (fh->flags & FHFLG_CONSOLEDEVICEOPEN)
1006 /* Close the device, it will be re-opened if needed */
1007 CloseDevice((struct IORequest *) fh->conreadio);
1008 fh->flags &= ~FHFLG_CONSOLEDEVICEOPEN;
1010 /* Only now close the window itself */
1011 CloseWindow(fh->window);
1012 fh->window = NULL;
1015 /* fall through */
1017 case INP_RETURN:
1018 if (fh->inputsize < INPUTBUFFER_SIZE)
1020 if (inp != INP_EOF)
1022 c = '\n';
1023 do_write(fh, &c, 1);
1024 add_to_history(fh);
1026 fh->inputbuffer[fh->inputsize++] = '\n';
1029 fh->inputstart = fh->inputsize;
1030 fh->inputpos = fh->inputstart;
1032 if (fh->inputsize)
1033 HandlePendingReads(fh);
1035 if ((fh->flags & FHFLG_EOF) && (fh->flags & FHFLG_READPENDING))
1037 struct Message *msg = (struct Message*) RemHead((struct List *) &fh->pendingReads);
1038 struct DosPacket *dp = (struct DosPacket*) msg->mn_Node.ln_Name;
1040 if (dp)
1042 replypkt2(dp, 0, 0);
1043 fh->flags &= ~FHFLG_EOF;
1046 if (IsListEmpty(&fh->pendingReads))
1047 fh->flags &= ~FHFLG_READPENDING;
1050 } /* if (fh->inputsize < INPUTBUFFER_SIZE) */
1051 break;
1053 case INP_LINEFEED:
1054 if (fh->inputsize < INPUTBUFFER_SIZE)
1056 c = '\n';
1057 do_write(fh, &c, 1);
1058 add_to_history(fh);
1060 fh->inputbuffer[fh->inputsize++] = c;
1061 fh->inputstart = fh->inputsize;
1062 fh->inputpos = fh->inputsize;
1064 break;
1066 case INP_CTRL_C:
1067 case INP_CTRL_D:
1068 case INP_CTRL_E:
1069 case INP_CTRL_F:
1070 if (fh->breaktask)
1072 Signal(fh->breaktask, 1L << (12 + inp - INP_CTRL_C));
1074 break;
1076 case INP_TAB:
1077 Completion(fh, FALSE);
1078 break;
1080 case INP_SHIFT_TAB:
1081 Completion(fh, TRUE);
1082 break;
1084 case INP_PASTE:
1085 do_paste(fh);
1086 break;
1088 } /* switch(inp) */
1090 } /* while((inp = scan_input(fh, &c)) != INP_DONE) */
1092 return FALSE;
1095 BOOL answer_write_request(struct filehandle *fh, struct DosPacket *dp)
1097 UBYTE *buffer = (UBYTE*) dp->dp_Arg2;
1098 LONG length = dp->dp_Arg3;
1100 #if RMB_FREEZES_OUTPUT
1101 struct Window *conwindow;
1103 conwindow = ((struct ConUnit *) fh->conwriteio.io_Unit)->cu_Window;
1105 while ((PeekQualifier() & IEQUALIFIER_RBUTTON) && conwindow && (conwindow == IntuitionBase->ActiveWindow))
1107 Delay(2);
1109 #endif
1111 if ((dp->dp_Port->mp_Flags & PF_ACTION) == PA_SIGNAL && dp->dp_Port->mp_SigTask)
1113 fh->lastwritetask = dp->dp_Port->mp_SigTask;
1116 do_write(fh, buffer, length);
1117 replypkt2(dp, length, 0);
1119 return TRUE;
1122 void answer_read_request(struct filehandle *fh, struct DosPacket *dp, ULONG dp_Arg3)
1124 ULONG readlen;
1126 readlen = (fh->inputsize < dp_Arg3) ? fh->inputsize : dp_Arg3;
1128 CopyMem(fh->inputbuffer, (UBYTE*) dp->dp_Arg2, readlen);
1129 CopyMem(fh->inputbuffer + readlen, fh->inputbuffer, fh->inputsize - readlen);
1131 fh->inputsize -= readlen;
1132 fh->inputpos -= readlen;
1133 fh->inputstart -= readlen;
1135 replypkt2(dp, readlen, 0);
1138 void HandlePendingReads(struct filehandle *fh)
1140 if (fh->flags & FHFLG_READPENDING)
1142 struct DosPacket *dp;
1143 struct Message *msg, *next_msg;
1145 ForeachNodeSafe(&fh->pendingReads, msg, next_msg)
1147 Remove((struct Node *) msg);
1148 dp = (struct DosPacket*) msg->mn_Node.ln_Name;
1149 answer_read_request(fh, dp, dp->dp_Arg3);
1151 if (fh->inputsize == 0)
1152 break;
1155 if (IsListEmpty(&fh->pendingReads))
1156 fh->flags &= ~FHFLG_READPENDING;
1159 if (fh->inputsize)
1161 fh->flags |= FHFLG_CANREAD;
1162 fh->canreadsize = fh->inputsize;
1166 void con_read(struct filehandle *fh, struct DosPacket *dp)
1168 if (fh->flags & FHFLG_CANREAD)
1170 ULONG readlen = (fh->canreadsize < dp->dp_Arg3) ? fh->canreadsize : dp->dp_Arg3;
1172 answer_read_request(fh, dp, readlen);
1174 fh->canreadsize -= readlen;
1175 if (fh->canreadsize == 0)
1176 fh->flags &= ~FHFLG_CANREAD;
1179 else
1181 if (fh->flags & FHFLG_EOF)
1183 replypkt2(dp, 0, 0);
1184 fh->flags &= ~FHFLG_EOF;
1186 else
1188 AddTail((struct List *) &fh->pendingReads, (struct Node *) dp->dp_Link);
1189 fh->flags |= FHFLG_READPENDING;