Added pfsdoctor. Includes PFS3 v19 large partition and file size support.
[AROS.git] / rom / filesys / console_handler / support.c
blobcbb2445d93257f0dd1b0ea07f721a11f9406d712
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 /****************************************************************************************/
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 replyport.mp_Node.ln_Type = NT_MSGPORT;
764 replyport.mp_Node.ln_Name = NULL;
765 replyport.mp_Node.ln_Pri = 0;
766 replyport.mp_Flags = PA_SIGNAL;
767 replyport.mp_SigBit = SIGB_SINGLE;
768 replyport.mp_SigTask = FindTask(NULL);
769 NEWLIST(&replyport.mp_MsgList);
771 msg.msg.mn_Node.ln_Type = NT_MESSAGE;
772 msg.msg.mn_ReplyPort = &replyport;
773 msg.msg.mn_Length = sizeof(msg);
775 msg.code = 'V';
776 msg.sgw = &sgw;
778 /* FIXME: Ensure no fields are left uninitialized */
780 sgw.Gadget = 0;
781 sgw.WorkBuffer = AllocMem(PASTEBUFSIZE, MEMF_CLEAR | MEMF_ANY);
782 sgw.PrevBuffer = 0;
783 sgw.IEvent = 0;
784 sgw.Code = 'V';
785 sgw.Actions = 0;
786 sgw.LongInt = 0;
787 sgw.GadgetInfo = 0;
788 sgw.EditOp = EO_BIGCHANGE;
789 sgw.BufferPos = 0;
790 sgw.NumChars = 0;
792 /* ConClip only ever looks at MaxChars in StringInfo */
793 sinfo.MaxChars = PASTEBUFSIZE;
794 sgw.StringInfo = &sinfo;
796 SetSignal(0, SIGF_SINGLE);
797 PutMsg(port, &msg.msg);
798 WaitPort(&replyport);
800 D(bug("Pasting %d bytes\n", sgw.BufferPos));
802 if (fh->pastebuffer)
803 FreeMem(fh->pastebuffer, PASTEBUFSIZE);
804 fh->pastebuffer = sgw.WorkBuffer;
805 fh->pastebuffersize = sgw.BufferPos;
806 fh->pastebufferpos = 0;
809 /****************************************************************************************/
811 BOOL process_input(struct filehandle *fh)
813 UBYTE c;
814 WORD inp;
815 while ((inp = scan_input(fh, &c)) != INP_DONE)
817 D(bug("Input Code: %d\n", inp));
819 switch (inp)
821 case INP_CURSORLEFT:
822 if (fh->inputpos > fh->inputstart)
824 fh->inputpos--;
825 do_movecursor(fh, CUR_LEFT, 1);
827 break;
829 case INP_SHIFT_CURSORLEFT: /* move to beginning of line */
830 case INP_HOME:
831 if (fh->inputpos > fh->inputstart)
833 do_movecursor(fh, CUR_LEFT, fh->inputpos - fh->inputstart);
834 fh->inputpos = fh->inputstart;
836 break;
838 case INP_CURSORRIGHT:
839 if (fh->inputpos < fh->inputsize)
841 fh->inputpos++;
842 do_movecursor(fh, CUR_RIGHT, 1);
844 break;
846 case INP_SHIFT_CURSORRIGHT: /* move to end of line */
847 case INP_END:
848 if (fh->inputpos != fh->inputsize)
850 do_movecursor(fh, CUR_RIGHT, fh->inputsize - fh->inputpos);
851 fh->inputpos = fh->inputsize;
853 break;
855 case INP_CURSORUP: /* walk through cmd history */
856 case INP_CURSORDOWN:
857 case INP_SHIFT_CURSORUP:
858 case INP_SHIFT_CURSORDOWN:
859 history_walk(fh, inp);
860 break;
862 case INP_BACKSPACE:
863 if (fh->inputpos > fh->inputstart)
865 do_movecursor(fh, CUR_LEFT, 1);
867 if (fh->inputpos == fh->inputsize)
869 do_deletechar(fh);
871 fh->inputsize--;
872 fh->inputpos--;
874 else
876 WORD chars_right = fh->inputsize - fh->inputpos;
878 fh->inputsize--;
879 fh->inputpos--;
881 do_cursorvisible(fh, FALSE);
882 do_write(fh, &fh->inputbuffer[fh->inputpos + 1], chars_right);
883 do_deletechar(fh);
884 do_movecursor(fh, CUR_LEFT, chars_right);
885 do_cursorvisible(fh, TRUE);
887 memmove(&fh->inputbuffer[fh->inputpos], &fh->inputbuffer[fh->inputpos + 1], chars_right);
891 break;
893 case INP_SHIFT_BACKSPACE:
894 if (fh->inputpos > fh->inputstart)
896 do_movecursor(fh, CUR_LEFT, fh->inputpos - fh->inputstart);
897 if (fh->inputpos == fh->inputsize)
899 do_eraseinline(fh);
901 fh->inputpos = fh->inputsize = fh->inputstart;
903 else
905 WORD chars_right = fh->inputsize - fh->inputpos;
907 do_cursorvisible(fh, FALSE);
908 do_write(fh, &fh->inputbuffer[fh->inputpos], chars_right);
909 do_eraseinline(fh);
910 do_movecursor(fh, CUR_LEFT, chars_right);
911 do_cursorvisible(fh, TRUE);
913 memmove(&fh->inputbuffer[fh->inputstart], &fh->inputbuffer[fh->inputpos], chars_right);
915 fh->inputsize -= (fh->inputpos - fh->inputstart);
916 fh->inputpos = fh->inputstart;
919 break;
921 case INP_DELETE:
922 if (fh->inputpos < fh->inputsize)
924 fh->inputsize--;
926 if (fh->inputpos == fh->inputsize)
928 do_deletechar(fh);
930 else
932 WORD chars_right = fh->inputsize - fh->inputpos;
934 do_cursorvisible(fh, FALSE);
935 do_write(fh, &fh->inputbuffer[fh->inputpos + 1], chars_right);
936 do_deletechar(fh);
937 do_movecursor(fh, CUR_LEFT, chars_right);
938 do_cursorvisible(fh, TRUE);
940 memmove(&fh->inputbuffer[fh->inputpos], &fh->inputbuffer[fh->inputpos + 1], chars_right);
943 break;
945 case INP_SHIFT_DELETE:
946 if (fh->inputpos < fh->inputsize)
948 fh->inputsize = fh->inputpos;
949 do_eraseinline(fh);
951 break;
953 case INP_CONTROL_X:
954 if ((fh->inputsize - fh->inputstart) > 0)
956 if (fh->inputpos > fh->inputstart)
958 do_movecursor(fh, CUR_LEFT, fh->inputpos - fh->inputstart);
960 do_eraseinline(fh);
962 fh->inputpos = fh->inputsize = fh->inputstart;
964 break;
966 case INP_ECHO_STRING:
967 do_write(fh, &c, 1);
968 break;
970 case INP_STRING:
971 if (fh->inputsize < INPUTBUFFER_SIZE)
973 do_write(fh, &c, 1);
975 if (fh->inputpos == fh->inputsize)
977 fh->inputbuffer[fh->inputpos++] = c;
978 fh->inputsize++;
980 else
982 WORD chars_right = fh->inputsize - fh->inputpos;
984 do_cursorvisible(fh, FALSE);
985 do_write(fh, &fh->inputbuffer[fh->inputpos], chars_right);
986 do_movecursor(fh, CUR_LEFT, chars_right);
987 do_cursorvisible(fh, TRUE);
989 memmove(&fh->inputbuffer[fh->inputpos + 1], &fh->inputbuffer[fh->inputpos], chars_right);
990 fh->inputbuffer[fh->inputpos++] = c;
991 fh->inputsize++;
994 break;
996 case INP_EOF:
997 D(bug("[CON] Read EOF (window closing)\n"));
999 if (fh->flags & FHFLG_WAITFORCLOSE)
1000 return TRUE;
1002 fh->flags |= FHFLG_EOF;
1003 if (fh->flags & FHFLG_AUTO && fh->window)
1005 if (fh->flags & FHFLG_CONSOLEDEVICEOPEN)
1007 /* Close the device, it will be re-opened if needed */
1008 CloseDevice((struct IORequest *) fh->conreadio);
1009 fh->flags &= ~FHFLG_CONSOLEDEVICEOPEN;
1011 /* Only now close the window itself */
1012 CloseWindow(fh->window);
1013 fh->window = NULL;
1016 /* fall through */
1018 case INP_RETURN:
1019 if (fh->inputsize < INPUTBUFFER_SIZE)
1021 if (inp != INP_EOF)
1023 c = '\n';
1024 do_write(fh, &c, 1);
1025 add_to_history(fh);
1027 fh->inputbuffer[fh->inputsize++] = '\n';
1030 fh->inputstart = fh->inputsize;
1031 fh->inputpos = fh->inputstart;
1033 if (fh->inputsize)
1034 HandlePendingReads(fh);
1036 if ((fh->flags & FHFLG_EOF) && (fh->flags & FHFLG_READPENDING))
1038 struct Message *msg = (struct Message*) RemHead((struct List *) &fh->pendingReads);
1039 struct DosPacket *dp = (struct DosPacket*) msg->mn_Node.ln_Name;
1041 if (dp)
1043 replypkt2(dp, 0, 0);
1044 fh->flags &= ~FHFLG_EOF;
1047 if (IsListEmpty(&fh->pendingReads))
1048 fh->flags &= ~FHFLG_READPENDING;
1051 } /* if (fh->inputsize < INPUTBUFFER_SIZE) */
1052 break;
1054 case INP_LINEFEED:
1055 if (fh->inputsize < INPUTBUFFER_SIZE)
1057 c = '\n';
1058 do_write(fh, &c, 1);
1059 add_to_history(fh);
1061 fh->inputbuffer[fh->inputsize++] = c;
1062 fh->inputstart = fh->inputsize;
1063 fh->inputpos = fh->inputsize;
1065 break;
1067 case INP_CTRL_C:
1068 case INP_CTRL_D:
1069 case INP_CTRL_E:
1070 case INP_CTRL_F:
1071 if (fh->breaktask)
1073 Signal(fh->breaktask, 1L << (12 + inp - INP_CTRL_C));
1075 break;
1077 case INP_TAB:
1078 Completion(fh, FALSE);
1079 break;
1081 case INP_SHIFT_TAB:
1082 Completion(fh, TRUE);
1083 break;
1085 case INP_PASTE:
1086 do_paste(fh);
1087 break;
1089 } /* switch(inp) */
1091 } /* while((inp = scan_input(fh, &c)) != INP_DONE) */
1093 return FALSE;
1096 BOOL answer_write_request(struct filehandle *fh, struct DosPacket *dp)
1098 UBYTE *buffer = (UBYTE*) dp->dp_Arg2;
1099 LONG length = dp->dp_Arg3;
1101 #if RMB_FREEZES_OUTPUT
1102 struct Window *conwindow;
1104 conwindow = ((struct ConUnit *) fh->conwriteio.io_Unit)->cu_Window;
1106 while ((PeekQualifier() & IEQUALIFIER_RBUTTON) && conwindow && (conwindow == IntuitionBase->ActiveWindow))
1108 Delay(2);
1110 #endif
1112 if ((dp->dp_Port->mp_Flags & PF_ACTION) == PA_SIGNAL && dp->dp_Port->mp_SigTask)
1114 fh->lastwritetask = dp->dp_Port->mp_SigTask;
1117 do_write(fh, buffer, length);
1118 replypkt2(dp, length, 0);
1120 return TRUE;
1123 void answer_read_request(struct filehandle *fh, struct DosPacket *dp, ULONG dp_Arg3)
1125 ULONG readlen;
1127 readlen = (fh->inputsize < dp_Arg3) ? fh->inputsize : dp_Arg3;
1129 CopyMem(fh->inputbuffer, (UBYTE*) dp->dp_Arg2, readlen);
1130 CopyMem(fh->inputbuffer + readlen, fh->inputbuffer, fh->inputsize - readlen);
1132 fh->inputsize -= readlen;
1133 fh->inputpos -= readlen;
1134 fh->inputstart -= readlen;
1136 replypkt2(dp, readlen, 0);
1139 void HandlePendingReads(struct filehandle *fh)
1141 if (fh->flags & FHFLG_READPENDING)
1143 struct DosPacket *dp;
1144 struct Message *msg, *next_msg;
1146 ForeachNodeSafe(&fh->pendingReads, msg, next_msg)
1148 Remove((struct Node *) msg);
1149 dp = (struct DosPacket*) msg->mn_Node.ln_Name;
1150 answer_read_request(fh, dp, dp->dp_Arg3);
1152 if (fh->inputsize == 0)
1153 break;
1156 if (IsListEmpty(&fh->pendingReads))
1157 fh->flags &= ~FHFLG_READPENDING;
1160 if (fh->inputsize)
1162 fh->flags |= FHFLG_CANREAD;
1163 fh->canreadsize = fh->inputsize;
1167 void con_read(struct filehandle *fh, struct DosPacket *dp)
1169 if (fh->flags & FHFLG_CANREAD)
1171 ULONG readlen = (fh->canreadsize < dp->dp_Arg3) ? fh->canreadsize : dp->dp_Arg3;
1173 answer_read_request(fh, dp, readlen);
1175 fh->canreadsize -= readlen;
1176 if (fh->canreadsize == 0)
1177 fh->flags &= ~FHFLG_CANREAD;
1180 else
1182 if (fh->flags & FHFLG_EOF)
1184 replypkt2(dp, 0, 0);
1185 fh->flags &= ~FHFLG_EOF;
1187 else if (fh->flags & FHFLG_RAW)
1189 replypkt2(dp, 0, 0);
1191 else
1193 AddTail((struct List *) &fh->pendingReads, (struct Node *) dp->dp_Link);
1194 fh->flags |= FHFLG_READPENDING;