Minor fixes to comments.
[AROS.git] / rom / filesys / console_handler / support.c
blobc551b500b110aa8e85a62cb99aaa45060cb68f8d
1 /*
2 Copyright © 1995-2011, 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 /****************************************************************************************/
16 #include <proto/exec.h>
17 #include <exec/libraries.h>
18 #include <exec/resident.h>
19 #include <exec/memory.h>
20 #include <exec/io.h>
21 #include <exec/errors.h>
22 #include <exec/alerts.h>
23 #include <utility/tagitem.h>
24 #include <dos/exall.h>
25 #include <dos/dosasl.h>
26 #include <intuition/intuition.h>
27 #include <intuition/sghooks.h>
28 #include <proto/dos.h>
29 #include <proto/intuition.h>
30 #include <proto/input.h>
31 #include <devices/conunit.h>
33 #define SDEBUG 0
34 #define DEBUG 0
35 #include <aros/debug.h>
37 #include <string.h>
38 #include <stdio.h>
39 #include <ctype.h>
41 #include "con_handler_intern.h"
42 #include "support.h"
43 #include "completion.h"
45 #define ioReq(x) ((struct IORequest *)x)
47 void replypkt(struct DosPacket *dp, SIPTR res1)
49 struct MsgPort *mp;
50 struct Message *mn;
52 mp = dp->dp_Port;
53 mn = dp->dp_Link;
54 mn->mn_Node.ln_Name = (char*)dp;
55 dp->dp_Port = &((struct Process*)FindTask(NULL))->pr_MsgPort;
56 dp->dp_Res1 = res1;
57 PutMsg(mp, mn);
59 void replypkt2(struct DosPacket *dp, SIPTR res1, SIPTR res2)
61 dp->dp_Res2 = res2;
62 replypkt(dp, res1);
66 /******************************************************************************************/
68 static const UBYTE up_seq[] = {'A'};
69 static const UBYTE down_seq[] = {'B'};
70 static const UBYTE right_seq[] = {'C'};
71 static const UBYTE left_seq[] = {'D'};
72 static const UBYTE shift_up_seq[] = {'T'};
73 static const UBYTE shift_down_seq[] = {'S'};
74 static const UBYTE shift_right_seq[] = {' ', '@'};
75 static const UBYTE shift_left_seq[] = {' ', 'A'};
76 static const UBYTE shift_tab_seq[] = {'Z'};
77 static const UBYTE help_seq[] = {'?', '~'};
78 static const UBYTE f1_seq[] = {'0', '~'};
79 static const UBYTE f2_seq[] = {'1', '~'};
80 static const UBYTE f3_seq[] = {'2', '~'};
81 static const UBYTE f4_seq[] = {'3', '~'};
82 static const UBYTE f5_seq[] = {'4', '~'};
83 static const UBYTE f6_seq[] = {'5', '~'};
84 static const UBYTE f7_seq[] = {'6', '~'};
85 static const UBYTE f8_seq[] = {'7', '~'};
86 static const UBYTE f9_seq[] = {'8', '~'};
87 static const UBYTE f10_seq[] = {'9', '~'};
88 static const UBYTE paste_seq[] = {'0', ' ', 'v'};
89 static const UBYTE f11_seq[] = {'2', '0', '~'};
90 static const UBYTE f12_seq[] = {'2', '1', '~'};
91 static const UBYTE shift_f1_seq[] = {'1', '0', '~'};
92 static const UBYTE shift_f2_seq[] = {'1', '1', '~'};
93 static const UBYTE shift_f3_seq[] = {'1', '2', '~'};
94 static const UBYTE shift_f4_seq[] = {'1', '3', '~'};
95 static const UBYTE shift_f5_seq[] = {'1', '4', '~'};
96 static const UBYTE shift_f6_seq[] = {'1', '5', '~'};
97 static const UBYTE shift_f7_seq[] = {'1', '6', '~'};
98 static const UBYTE shift_f8_seq[] = {'1', '7', '~'};
99 static const UBYTE shift_f9_seq[] = {'1', '8', '~'};
100 static const UBYTE shift_f10_seq[] = {'1', '9', '~'};
101 static const UBYTE shift_f11_seq[] = {'3', '0', '~'};
102 static const UBYTE shift_f12_seq[] = {'3', '1', '~'};
103 static const UBYTE insert_seq[] = {'4', '0', '~'};
104 static const UBYTE pageup_seq[] = {'4', '1', '~'};
105 static const UBYTE pagedown_seq[] = {'4', '2', '~'};
106 static const UBYTE pause_seq[] = {'4', '3', '~'};
107 static const UBYTE break_seq[] = {'5', '3', '~'};
108 static const UBYTE home_seq[] = {'4', '4', '~'};
109 static const UBYTE end_seq[] = {'4', '5', '~'};
110 static const UBYTE shift_insert_seq[] = {'5', '0', '~'};
111 static const UBYTE shift_pageup_seq[] = {'5', '1', '~'};
112 static const UBYTE shift_pagedown_seq[] = {'5', '2', '~'};
113 static const UBYTE shift_home_seq[] = {'5', '4', '~'};
114 static const UBYTE shift_end_seq[] = {'5', '5', '~'};
116 /* F11, F12, insert, pageup, pagedown, ... seq taken from
117 RKRM: Devices/Console/Reading from the Console Device/Information about the Input Stream */
119 static CONST struct csimatch
121 CONST UBYTE *seq;
122 WORD len;
123 WORD inp;
125 csimatchtable[] =
127 {up_seq , 1, INP_CURSORUP },
128 {down_seq , 1, INP_CURSORDOWN },
129 {right_seq , 1, INP_CURSORRIGHT },
130 {left_seq , 1, INP_CURSORLEFT },
131 {shift_up_seq , 1, INP_SHIFT_CURSORUP },
132 {shift_down_seq , 1, INP_SHIFT_CURSORDOWN },
133 {shift_right_seq , 2, INP_SHIFT_CURSORRIGHT },
134 {shift_left_seq , 2, INP_SHIFT_CURSORLEFT },
135 {shift_tab_seq , 1, INP_SHIFT_TAB },
136 {help_seq , 2, INP_HELP },
137 {f1_seq , 2, INP_F1 },
138 {f2_seq , 2, INP_F2 },
139 {f3_seq , 2, INP_F3 },
140 {f4_seq , 2, INP_F4 },
141 {f5_seq , 2, INP_F5 },
142 {f6_seq , 2, INP_F6 },
143 {f7_seq , 2, INP_F7 },
144 {f8_seq , 2, INP_F8 },
145 {f9_seq , 2, INP_F9 },
146 {f10_seq , 2, INP_F10 },
147 {f11_seq , 3, INP_F11 },
148 {f12_seq , 3, INP_F12 },
149 {shift_f1_seq , 3, INP_SHIFT_F1 },
150 {shift_f2_seq , 3, INP_SHIFT_F2 },
151 {shift_f3_seq , 3, INP_SHIFT_F3 },
152 {shift_f4_seq , 3, INP_SHIFT_F4 },
153 {shift_f5_seq , 3, INP_SHIFT_F5 },
154 {shift_f6_seq , 3, INP_SHIFT_F6 },
155 {shift_f7_seq , 3, INP_SHIFT_F7 },
156 {shift_f8_seq , 3, INP_SHIFT_F8 },
157 {shift_f9_seq , 3, INP_SHIFT_F9 },
158 {shift_f10_seq , 3, INP_SHIFT_F10 },
159 {shift_f11_seq , 3, INP_SHIFT_F11 },
160 {shift_f12_seq , 3, INP_SHIFT_F12 },
161 {insert_seq , 3, INP_INSERT },
162 {pageup_seq , 3, INP_PAGEUP },
163 {pagedown_seq , 3, INP_PAGEDOWN },
164 {pause_seq , 3, INP_PAUSE },
165 {break_seq , 3, INP_BREAK },
166 {home_seq , 3, INP_HOME },
167 {end_seq , 3, INP_END },
168 {shift_insert_seq , 3, INP_SHIFT_INSERT },
169 {shift_pageup_seq , 3, INP_SHIFT_PAGEUP },
170 {shift_pagedown_seq , 3, INP_SHIFT_PAGEDOWN },
171 {shift_home_seq , 3, INP_SHIFT_HOME },
172 {shift_end_seq , 3, INP_SHIFT_END },
173 {paste_seq , 3, INP_PASTE },
174 {0 , 0, 0 }
178 /******************************************************************************************/
180 static UBYTE hex2val(char c)
182 if (c >= '0' && c <= '9')
183 return c - '0';
184 c &= ~0x20;
185 return c - 'A' + 10;
187 /* strtoul() not used because it is much larger and uses .bss
188 * TODO: Sanity checks. */
189 static IPTR string2val(const char *s, WORD len)
191 IPTR v = 0;
193 if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
194 s += 2;
195 while (len-- > 0 && *s) {
196 v <<= 4;
197 v |= hex2val(*s);
198 s++;
200 } else {
201 while (len-- > 0 && *s) {
202 v *= 10;
203 v += *s - '0';
204 s++;
207 return v;
210 BOOL parse_filename(struct filehandle *fh, char *filename, struct NewWindow *nw)
212 char *param;
213 UBYTE c;
214 WORD paramid = 1;
215 LONG paramval = 0;
216 BOOL ok = TRUE, done = FALSE, paramok = FALSE;
218 ASSERT_VALID_PTR(fh);
219 ASSERT_VALID_PTR(nw);
221 param = filename;
222 ASSERT_VALID_PTR(param);
224 while (!done)
226 c = *filename++;
228 switch(c)
230 case '0':
231 case '1':
232 case '2':
233 case '3':
234 case '4':
235 case '5':
236 case '6':
237 case '7':
238 case '8':
239 case '9':
240 if (paramid <= 4)
242 paramval *= 10;
243 paramval += c - '0';
245 paramok = TRUE;
246 break;
248 case '\0':
249 done = TRUE;
250 /* fall through */
252 case '/':
253 if (paramok)
255 UWORD paramlen = filename - param - 1;
257 switch(paramid)
259 case 1:
260 nw->LeftEdge = paramval;
261 break;
263 case 2:
264 nw->TopEdge = paramval;
265 break;
267 case 3:
268 nw->Width = paramval;
269 break;
271 case 4:
272 nw->Height = paramval;
273 break;
275 case 5:
276 if ((fh->wintitle = AllocVec(paramlen + 1, MEMF_PUBLIC)))
278 CopyMem(param, fh->wintitle, paramlen);
279 fh->wintitle[paramlen] = '\0';
280 nw->Title = fh->wintitle;
282 break;
284 default:
285 if (!strnicmp(param, "WAIT", paramlen))
287 fh->flags |= FHFLG_WAIT;
289 else if (!strnicmp(param, "CLOSE", paramlen))
291 nw->Flags |= WFLG_CLOSEGADGET;
293 else if (!strnicmp(param, "NOCLOSE", paramlen))
295 nw->Flags &= ~WFLG_CLOSEGADGET;
297 else if (!strnicmp(param, "AUTO", paramlen))
299 fh->flags |= FHFLG_AUTO;
301 else if (!strnicmp(param, "INACTIVE", paramlen))
303 nw->Flags &= ~WFLG_ACTIVATE;
305 else if (!strnicmp(param, "NODEPTH", paramlen))
307 nw->Flags &= ~WFLG_DEPTHGADGET;
309 else if (!strnicmp(param, "NOSIZE", paramlen))
311 nw->Flags &= ~WFLG_SIZEGADGET;
313 else if (!strnicmp(param, "NODRAG", paramlen))
315 nw->Flags &= ~WFLG_DRAGBAR;
317 else if (!strnicmp(param, "NOBORDER", paramlen))
319 nw->Flags |= WFLG_BORDERLESS;
321 else if (!strnicmp(param, "BACKDROP", paramlen))
323 nw->Flags |= WFLG_BACKDROP;
324 nw->Flags &= ~(WFLG_DRAGBAR | WFLG_SIZEGADGET);
326 else if (!strnicmp(param, "SIMPLE", paramlen))
328 /* TODO */
330 else if (!strnicmp(param, "SMART", paramlen))
332 /* TODO */
334 else if (!strnicmp(param, "ALT", paramlen))
336 /* TODO: style "ALT30/30/200/200" */
338 else if (!strnicmp(param, "WINDOW", 6))
340 /* Do we need some sanity checks here? */
341 fh->otherwindow = (struct Window*)string2val(param + 6, paramlen - 6);
343 else if (!strnicmp(param, "SCREEN", 6))
345 if ((fh->screenname = AllocVec(paramlen - 5, MEMF_PUBLIC)))
347 CopyMem(param + 6, fh->screenname, paramlen - 6);
348 fh->screenname[paramlen - 6] = '\0';
351 break;
353 } /* switch(paramid) */
355 paramok = FALSE;
357 } /* if (paramok) */
359 paramval = 0;
360 paramid++;
361 param = filename;
362 break;
364 default:
365 if (paramid < 5)
367 done = TRUE;
368 ok = FALSE;
370 else
371 paramok = TRUE;
372 break;
374 } /* switch(c) */
376 } /* while (!done) */
378 return ok;
381 /******************************************************************************************/
384 void do_write(struct filehandle *fh, APTR data, ULONG length)
386 fh->conwriteio.io_Command = CMD_WRITE;
387 fh->conwriteio.io_Data = data;
388 fh->conwriteio.io_Length = length;
390 DoIO((struct IORequest *)&fh->conwriteio);
393 /******************************************************************************************/
395 void do_movecursor(struct filehandle *fh, UBYTE direction, UBYTE howmuch)
397 UBYTE seq[6]; /* 9B <N> <N> <N> <dir> <0> */
398 ULONG size;
400 if (howmuch > 0)
402 seq[0] = 0x9B;
404 if (howmuch == 1)
406 seq[1] = direction;
407 size = 2;
408 } else {
409 sprintf(&seq[1],"%d%c", howmuch, direction);
410 size = strlen(seq);
413 do_write(fh, seq, size);
417 /******************************************************************************************/
419 void do_cursorvisible(struct filehandle *fh, BOOL on)
421 UBYTE seq[4];
422 ULONG size = 0;
424 seq[size++] = 0x9B;
425 if (!on) seq[size++] = '0';
426 seq[size++] = ' ';
427 seq[size++] = 'p';
429 do_write(fh, seq, size);
432 /******************************************************************************************/
434 void do_deletechar(struct filehandle *fh)
436 UBYTE seq[] = {0x9B, 'P'};
438 do_write(fh, seq, 2);
441 /******************************************************************************************/
443 void do_eraseinline(struct filehandle *fh)
445 UBYTE seq[] = {0x9B, 'K'};
447 do_write(fh, seq, 2);
450 /******************************************************************************************/
452 void do_eraseindisplay(struct filehandle *fh)
454 UBYTE seq[] = {0x9B, 'J'};
456 do_write(fh, seq, 2);
458 /******************************************************************************************/
459 static void copy_from_pastebuf(struct filehandle * fh)
461 if (fh->conbufferpos >= fh->conbuffersize &&
462 fh->pastebuffer &&
463 fh->pastebufferpos < fh->pastebuffersize)
465 ULONG len = CONSOLEBUFFER_SIZE;
466 ULONG pastelen = fh->pastebuffersize - fh->pastebufferpos;
467 if (pastelen < len) len = pastelen;
469 D(bug("Copying %d bytes from paste buffer\n",len));
471 fh->conbufferpos = 0;
472 CopyMem(fh->pastebuffer + fh->pastebufferpos,
473 &fh->consolebuffer,
474 len);
475 fh->conbuffersize = len;
476 fh->pastebufferpos += len;
477 if (fh->pastebufferpos >= fh->pastebuffersize) {
478 FreeMem(fh->pastebuffer,PASTEBUFSIZE);
479 fh->pastebuffer = 0;
484 WORD scan_input(struct filehandle *fh, UBYTE *buffer)
486 CONST struct csimatch *match;
487 UBYTE c;
488 WORD result = INP_DONE;
490 copy_from_pastebuf(fh);
492 if (fh->conbufferpos < fh->conbuffersize)
494 c = fh->consolebuffer[fh->conbufferpos++];
495 D(bug("scan_input: check char %d\n",c));
496 switch(c)
498 case 3:
499 case 4:
500 case 5:
501 case 6:
502 result = INP_CTRL_C - 3 + (WORD)c;
503 break;
505 case 8:
506 /* FIXME: Ugh... Race condition, anyone? The qualifier might
507 have changed between the keypress and the time we do this */
508 if (PeekQualifier() & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
510 result = INP_SHIFT_BACKSPACE;
511 } else {
512 result = INP_BACKSPACE;
514 break;
516 case 9:
517 result = INP_TAB;
518 break;
520 case 10:
521 result = INP_LINEFEED;
522 break;
524 case 12: /* CTRL-L */
525 *buffer = c;
526 result = INP_ECHO_STRING;
527 break;
529 case 13:
530 result = INP_RETURN;
531 break;
533 case 127:
534 if (PeekQualifier() & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
536 result = INP_SHIFT_DELETE;
537 } else {
538 result = INP_DELETE;
540 break;
542 case 24:
543 result = INP_CONTROL_X;
544 break;
546 case 28: /* CTRL-\ */
547 result = INP_EOF;
548 break;
550 case 0x9B: /* CSI */
551 result = INP_UNKNOWN;
553 match = csimatchtable;
554 for(;match->seq;match++)
556 if (!strncmp(match->seq, &(fh->consolebuffer[fh->conbufferpos]), match->len))
558 result = match->inp;
559 fh->conbufferpos += match->len;
560 break;
563 break;
565 default:
566 /* normal keys */
567 *buffer = c;
568 result = INP_STRING;
569 break;
571 } /* switch(c) */
573 } /* if (fh->conbufferpos < fh->conbuffersize) */
575 D(bug("scan_input: result %d\n",result));
577 return result;
580 /******************************************************************************************/
582 void add_to_history(struct filehandle *fh)
584 BOOL add_to_history = FALSE;
586 fh->inputbuffer[fh->inputsize] = '\0';
588 /* Don't add emptry strings */
589 if (fh->inputbuffer[fh->inputstart] == '\0') return;
591 if (fh->historysize == 0)
593 add_to_history = TRUE;
595 else
597 WORD old_historypos;
599 old_historypos = fh->historypos - 1;
600 if (old_historypos < 0) old_historypos = fh->historysize - 1;
602 if (strcmp(&fh->inputbuffer[fh->inputstart], fh->historybuffer[old_historypos]))
604 /* add to history only if different from last history entry */
606 add_to_history = TRUE;
610 if (add_to_history)
612 if (fh->historysize < CMD_HISTORY_SIZE) fh->historysize++;
614 strcpy(fh->historybuffer[fh->historypos], &fh->inputbuffer[fh->inputstart]);
616 fh->historypos++;
617 if (fh->historypos >= CMD_HISTORY_SIZE) fh->historypos = 0;
620 fh->historyviewpos = fh->historypos;
623 /******************************************************************************************/
625 void history_walk(struct filehandle *fh, WORD inp)
627 if (fh->historysize)
629 #if !CYCLIC_HISTORY_WALK
630 BOOL walk_to_empty_string = FALSE;
631 #endif
632 WORD len;
634 switch(inp)
636 case INP_SHIFT_CURSORUP:
637 fh->historyviewpos = 0;
638 break;
640 case INP_SHIFT_CURSORDOWN:
641 fh->historyviewpos = fh->historysize - 1;;
642 break;
644 case INP_CURSORUP:
645 #if CYCLIC_HISTORY_WALK
646 fh->historyviewpos--;
647 if (fh->historyviewpos < 0) fh->historyviewpos = fh->historysize - 1;
648 #else
649 if (fh->historyviewpos != -1)
651 fh->historyviewpos--;
652 if (fh->historyviewpos < 0
653 && fh->historysize == CMD_HISTORY_SIZE)
654 fh->historyviewpos = CMD_HISTORY_SIZE - 1;
655 if (fh->historyviewpos == fh->historypos)
656 fh->historyviewpos = -1;
658 if (fh->historyviewpos == -1)
659 walk_to_empty_string = TRUE;
660 #endif
661 break;
663 case INP_CURSORDOWN:
664 #if CYCLIC_HISTORY_WALK
665 fh->historyviewpos++;
666 if (fh->historyviewpos >= fh->historysize) fh->historyviewpos = 0;
667 #else
668 if (fh->historyviewpos != fh->historypos)
670 if (fh->historyviewpos == -1
671 && fh->historysize == CMD_HISTORY_SIZE)
672 fh->historyviewpos = fh->historypos;
673 fh->historyviewpos = (fh->historyviewpos + 1)
674 % CMD_HISTORY_SIZE;
676 if (fh->historyviewpos == fh->historypos)
677 walk_to_empty_string = TRUE;
678 #endif
679 break;
682 if (fh->inputpos > fh->inputstart)
684 do_movecursor(fh, CUR_LEFT, fh->inputpos - fh->inputstart);
687 do_eraseinline(fh);
689 fh->inputsize = fh->inputstart;
690 fh->inputpos = fh->inputstart;
692 #if !CYCLIC_HISTORY_WALK
693 if (!walk_to_empty_string)
695 #endif
696 len = strlen(fh->historybuffer[fh->historyviewpos]);
697 if (len > (INPUTBUFFER_SIZE - fh->inputstart))
699 len = INPUTBUFFER_SIZE - fh->inputstart;
702 if (len > 0)
704 CopyMem(fh->historybuffer[fh->historyviewpos],
705 &fh->inputbuffer[fh->inputstart],
706 len);
708 fh->inputsize += len;
709 fh->inputpos += len;
711 do_write(fh, &fh->inputbuffer[fh->inputstart], len);
714 #if !CYCLIC_HISTORY_WALK
715 } /* if (!walk_to_empty_string) */
716 #endif
718 } /* if (fh->historysize) */
721 /****************************************************************************************/
723 static const STRPTR CONCLIP_PORTNAME = "ConClip.rendezvous";
725 struct MyEditHookMsg
727 struct Message msg;
728 struct SGWork *sgw;
729 WORD code;
732 static void do_paste(struct filehandle * fh)
734 struct MsgPort replyport, *port;
735 struct SGWork sgw;
736 struct MyEditHookMsg msg;
737 struct StringInfo sinfo;
739 if (!(port = FindPort(CONCLIP_PORTNAME))) {
740 D(bug("ConClip not running, but we got a ConClip paste request"));
741 return;
744 D(bug("PASTE REQUEST!\n"));
746 replyport.mp_Node.ln_Type = NT_MSGPORT;
747 replyport.mp_Node.ln_Name = NULL;
748 replyport.mp_Node.ln_Pri = 0;
749 replyport.mp_Flags = PA_SIGNAL;
750 replyport.mp_SigBit = SIGB_SINGLE;
751 replyport.mp_SigTask = FindTask(NULL);
752 NEWLIST(&replyport.mp_MsgList);
754 msg.msg.mn_Node.ln_Type = NT_MESSAGE;
755 msg.msg.mn_ReplyPort = &replyport;
756 msg.msg.mn_Length = sizeof(msg);
758 msg.code = 'V';
759 msg.sgw = &sgw;
761 /* FIXME: Ensure no fields are left uninitialized */
763 sgw.Gadget = 0;
764 sgw.WorkBuffer = AllocMem(PASTEBUFSIZE,MEMF_CLEAR | MEMF_ANY);
765 sgw.PrevBuffer = 0;
766 sgw.IEvent = 0;
767 sgw.Code = 'V';
768 sgw.Actions = 0;
769 sgw.LongInt = 0;
770 sgw.GadgetInfo = 0;
771 sgw.EditOp = EO_BIGCHANGE;
772 sgw.BufferPos = 0;
773 sgw.NumChars = 0;
775 /* ConClip only ever looks at MaxChars in StringInfo */
776 sinfo.MaxChars = PASTEBUFSIZE;
777 sgw.StringInfo = &sinfo;
779 SetSignal(0, SIGF_SINGLE);
780 PutMsg(port, &msg.msg);
781 WaitPort(&replyport);
783 D(bug("Pasting %d bytes\n",sgw.BufferPos));
785 if (fh->pastebuffer) FreeMem(fh->pastebuffer,PASTEBUFSIZE);
786 fh->pastebuffer = sgw.WorkBuffer;
787 fh->pastebuffersize = sgw.BufferPos;
788 fh->pastebufferpos = 0;
792 /****************************************************************************************/
794 BOOL process_input(struct filehandle *fh)
796 UBYTE c;
797 WORD inp;
798 while((inp = scan_input(fh, &c)) != INP_DONE)
800 D(bug("Input Code: %d\n",inp));
802 switch(inp)
804 case INP_CURSORLEFT:
805 if (fh->inputpos > fh->inputstart)
807 fh->inputpos--;
808 do_movecursor(fh, CUR_LEFT, 1);
810 break;
812 case INP_SHIFT_CURSORLEFT: /* move to beginning of line */
813 case INP_HOME:
814 if (fh->inputpos > fh->inputstart)
816 do_movecursor(fh, CUR_LEFT, fh->inputpos - fh->inputstart);
817 fh->inputpos = fh->inputstart;
819 break;
821 case INP_CURSORRIGHT:
822 if (fh->inputpos < fh->inputsize)
824 fh->inputpos++;
825 do_movecursor(fh, CUR_RIGHT, 1);
827 break;
829 case INP_SHIFT_CURSORRIGHT: /* move to end of line */
830 case INP_END:
831 if (fh->inputpos != fh->inputsize)
833 do_movecursor(fh, CUR_RIGHT, fh->inputsize - fh->inputpos);
834 fh->inputpos = fh->inputsize;
836 break;
838 case INP_CURSORUP: /* walk through cmd history */
839 case INP_CURSORDOWN:
840 case INP_SHIFT_CURSORUP:
841 case INP_SHIFT_CURSORDOWN:
842 history_walk(fh, inp);
843 break;
845 case INP_BACKSPACE:
846 if (fh->inputpos > fh->inputstart)
848 do_movecursor(fh, CUR_LEFT, 1);
850 if (fh->inputpos == fh->inputsize)
852 do_deletechar(fh);
854 fh->inputsize--;
855 fh->inputpos--;
856 } else {
857 WORD chars_right = fh->inputsize - fh->inputpos;
859 fh->inputsize--;
860 fh->inputpos--;
862 do_cursorvisible(fh, FALSE);
863 do_write(fh, &fh->inputbuffer[fh->inputpos + 1], chars_right);
864 do_deletechar(fh);
865 do_movecursor(fh, CUR_LEFT, chars_right);
866 do_cursorvisible(fh, TRUE);
868 memmove(&fh->inputbuffer[fh->inputpos], &fh->inputbuffer[fh->inputpos + 1], chars_right);
872 break;
874 case INP_SHIFT_BACKSPACE:
875 if (fh->inputpos > fh->inputstart)
877 do_movecursor(fh, CUR_LEFT, fh->inputpos - fh->inputstart);
878 if (fh->inputpos == fh->inputsize)
880 do_eraseinline(fh);
882 fh->inputpos = fh->inputsize = fh->inputstart;
883 } else {
884 WORD chars_right = fh->inputsize - fh->inputpos;
886 do_cursorvisible(fh, FALSE);
887 do_write(fh, &fh->inputbuffer[fh->inputpos], chars_right);
888 do_eraseinline(fh);
889 do_movecursor(fh, CUR_LEFT, chars_right);
890 do_cursorvisible(fh, TRUE);
892 memmove(&fh->inputbuffer[fh->inputstart], &fh->inputbuffer[fh->inputpos], chars_right);
894 fh->inputsize -= (fh->inputpos - fh->inputstart);
895 fh->inputpos = fh->inputstart;
898 break;
900 case INP_DELETE:
901 if (fh->inputpos < fh->inputsize)
903 fh->inputsize--;
905 if (fh->inputpos == fh->inputsize)
907 do_deletechar(fh);
908 } else {
909 WORD chars_right = fh->inputsize - fh->inputpos;
911 do_cursorvisible(fh, FALSE);
912 do_write(fh, &fh->inputbuffer[fh->inputpos + 1], chars_right);
913 do_deletechar(fh);
914 do_movecursor(fh, CUR_LEFT, chars_right);
915 do_cursorvisible(fh, TRUE);
917 memmove(&fh->inputbuffer[fh->inputpos], &fh->inputbuffer[fh->inputpos + 1], chars_right);
920 break;
922 case INP_SHIFT_DELETE:
923 if (fh->inputpos < fh->inputsize)
925 fh->inputsize = fh->inputpos;
926 do_eraseinline(fh);
928 break;
930 case INP_CONTROL_X:
931 if ((fh->inputsize - fh->inputstart) > 0)
933 if (fh->inputpos > fh->inputstart)
935 do_movecursor(fh, CUR_LEFT, fh->inputpos - fh->inputstart);
937 do_eraseinline(fh);
939 fh->inputpos = fh->inputsize = fh->inputstart;
941 break;
943 case INP_ECHO_STRING:
944 do_write(fh, &c, 1);
945 break;
947 case INP_STRING:
948 if (fh->inputsize < INPUTBUFFER_SIZE)
950 do_write(fh, &c, 1);
952 if (fh->inputpos == fh->inputsize)
954 fh->inputbuffer[fh->inputpos++] = c;
955 fh->inputsize++;
956 } else {
957 WORD chars_right = fh->inputsize - fh->inputpos;
959 do_cursorvisible(fh, FALSE);
960 do_write(fh, &fh->inputbuffer[fh->inputpos], chars_right);
961 do_movecursor(fh, CUR_LEFT, chars_right);
962 do_cursorvisible(fh, TRUE);
964 memmove(&fh->inputbuffer[fh->inputpos + 1], &fh->inputbuffer[fh->inputpos], chars_right);
965 fh->inputbuffer[fh->inputpos++] = c;
966 fh->inputsize++;
969 break;
971 case INP_EOF:
972 D(bug("[CON] Read EOF (window closing)\n"));
974 if (fh->flags & FHFLG_WAITFORCLOSE)
975 return TRUE;
977 fh->flags |= FHFLG_EOF;
978 if (fh->flags & FHFLG_AUTO && fh->window)
980 CloseWindow(fh->window);
981 fh->window = NULL;
984 /* fall through */
986 case INP_RETURN:
987 if (fh->inputsize < INPUTBUFFER_SIZE)
989 if (inp != INP_EOF)
991 c = '\n';
992 do_write(fh, &c, 1);
993 add_to_history(fh);
995 fh->inputbuffer[fh->inputsize++] = '\n';
998 fh->inputstart = fh->inputsize;
999 fh->inputpos = fh->inputstart;
1001 if (fh->inputsize)
1002 HandlePendingReads(fh);
1004 if ((fh->flags & FHFLG_EOF) && (fh->flags & FHFLG_READPENDING))
1006 struct Message *msg = (struct Message*)RemHead((struct List *)&fh->pendingReads);
1007 struct DosPacket *dp = (struct DosPacket*)msg->mn_Node.ln_Name;
1009 if (dp)
1011 replypkt2(dp, 0, 0);
1012 fh->flags &= ~FHFLG_EOF;
1015 if (IsListEmpty(&fh->pendingReads))
1016 fh->flags &= ~FHFLG_READPENDING;
1019 } /* if (fh->inputsize < INPUTBUFFER_SIZE) */
1020 break;
1022 case INP_LINEFEED:
1023 if (fh->inputsize < INPUTBUFFER_SIZE)
1025 c = '\n';
1026 do_write(fh, &c, 1);
1027 add_to_history(fh);
1029 fh->inputbuffer[fh->inputsize++] = c;
1030 fh->inputstart = fh->inputsize;
1031 fh->inputpos = fh->inputsize;
1033 break;
1035 case INP_CTRL_C:
1036 case INP_CTRL_D:
1037 case INP_CTRL_E:
1038 case INP_CTRL_F:
1039 if (fh->breaktask)
1041 Signal(fh->breaktask, 1L << (12 + inp - INP_CTRL_C));
1043 break;
1045 case INP_TAB:
1046 Completion(fh);
1047 break;
1049 case INP_PASTE:
1050 do_paste(fh);
1051 break;
1053 } /* switch(inp) */
1055 } /* while((inp = scan_input(fh, &c)) != INP_DONE) */
1057 return FALSE;
1061 BOOL answer_write_request(struct filehandle *fh, struct DosPacket *dp)
1063 UBYTE *buffer = (UBYTE*)dp->dp_Arg2;
1064 LONG length = dp->dp_Arg3;
1066 #if RMB_FREEZES_OUTPUT
1067 struct Window *conwindow;
1069 conwindow = ((struct ConUnit *)fh->conwriteio.io_Unit)->cu_Window;
1071 while((PeekQualifier() & IEQUALIFIER_RBUTTON) &&
1072 conwindow && (conwindow == IntuitionBase->ActiveWindow))
1074 Delay(2);
1076 #endif
1078 if ((dp->dp_Port->mp_Flags & PF_ACTION) == PA_SIGNAL &&
1079 dp->dp_Port->mp_SigTask)
1081 fh->lastwritetask = dp->dp_Port->mp_SigTask;
1085 do_write(fh, buffer, length);
1086 replypkt2(dp, length, 0);
1088 return TRUE;
1091 void answer_read_request(struct filehandle *fh, struct DosPacket *dp, ULONG dp_Arg3)
1093 ULONG readlen;
1095 readlen = (fh->inputsize < dp_Arg3) ? fh->inputsize : dp_Arg3;
1097 CopyMem(fh->inputbuffer, (UBYTE*)dp->dp_Arg2, readlen);
1098 CopyMem(fh->inputbuffer + readlen, fh->inputbuffer, fh->inputsize - readlen);
1100 fh->inputsize -= readlen;
1101 fh->inputpos -= readlen;
1102 fh->inputstart -= readlen;
1104 replypkt2(dp, readlen, 0);
1107 void HandlePendingReads(struct filehandle *fh)
1109 if (fh->flags & FHFLG_READPENDING)
1111 struct DosPacket *dp;
1112 struct Message *msg, *next_msg;
1114 ForeachNodeSafe(&fh->pendingReads, msg, next_msg)
1116 Remove((struct Node *)msg);
1117 dp = (struct DosPacket*)msg->mn_Node.ln_Name;
1118 answer_read_request(fh, dp, dp->dp_Arg3);
1120 if (fh->inputsize == 0)
1121 break;
1124 if (IsListEmpty(&fh->pendingReads))
1125 fh->flags &= ~FHFLG_READPENDING;
1128 if (fh->inputsize)
1130 fh->flags |= FHFLG_CANREAD;
1131 fh->canreadsize = fh->inputsize;
1135 void con_read(struct filehandle *fh, struct DosPacket *dp)
1137 if (fh->flags & FHFLG_CANREAD)
1139 ULONG readlen = (fh->canreadsize < dp->dp_Arg3) ? fh->canreadsize : dp->dp_Arg3;
1141 answer_read_request(fh, dp, readlen);
1143 fh->canreadsize -= readlen;
1144 if (fh->canreadsize == 0)
1145 fh->flags &= ~FHFLG_CANREAD;
1148 else
1150 if (fh->flags & FHFLG_EOF)
1152 replypkt2(dp, 0, 0);
1153 fh->flags &= ~FHFLG_EOF;
1155 else if (fh->flags & FHFLG_RAW)
1157 replypkt2(dp, 0, 0);
1159 else
1161 AddTail((struct List *)&fh->pendingReads, (struct Node *)dp->dp_Link);
1162 fh->flags |= FHFLG_READPENDING;