Prevent wrongly nulling out the task CTRL C/D/E/F is sent to; the removed code caused...
[AROS.git] / rom / devs / filesys / console_handler / con_task.c
blob7f9d5e892d89a6cf8ddb938cbd8733678a9a576f
1 /*
2 Copyright © 1995-2010, The AROS Development Team. All rights reserved.
3 $Id$
5 Filesystem that uses console device for input/output.
6 */
8 #include <proto/exec.h>
9 #include <exec/libraries.h>
10 #include <exec/resident.h>
11 #include <exec/memory.h>
12 #include <exec/ports.h>
13 #include <proto/alib.h>
14 #include <exec/io.h>
15 #include <exec/errors.h>
16 #include <exec/alerts.h>
17 #include <utility/tagitem.h>
18 #include <dos/filesystem.h>
19 #include <dos/exall.h>
20 #include <dos/dosasl.h>
21 #include <intuition/intuition.h>
22 #include <intuition/sghooks.h>
23 #include <proto/dos.h>
24 #include <proto/intuition.h>
25 #include <devices/conunit.h>
26 #include <devices/timer.h>
28 #undef SDEBUG
29 #undef DEBUG
30 // #define SDEBUG 1
31 #define DEBUG 0
32 #include <aros/debug.h>
34 #include "con_handler_intern.h"
35 #include "support.h"
36 #include "completion.h"
38 #include <string.h>
39 #include <stdio.h>
41 /****************************************************************************************/
43 #define ioReq(x) ((struct IORequest *)x)
45 /****************************************************************************************/
47 static const struct NewWindow default_nw =
49 0, /* LeftEdge */
50 0, /* TopEdge */
51 600, /* Width */
52 300, /* Height */
53 1, /* DetailPen */
54 0, /* BlockPen */
55 0, /* IDCMP */
56 WFLG_DEPTHGADGET |
57 WFLG_SIZEGADGET |
58 WFLG_DRAGBAR |
59 WFLG_SIZEBRIGHT |
60 WFLG_SMART_REFRESH |
61 WFLG_ACTIVATE,
62 0, /* FirstGadget */
63 0, /* CheckMark */
64 "CON:", /* Title */
65 0, /* Screen */
66 0, /* Bitmap */
67 100, /* MinWidth */
68 100, /* MinHeight */
69 32767, /* MaxWidth */
70 32767, /* MaxHeight */
71 WBENCHSCREEN /* type */
75 /****************************************************************************************/
77 static void close_con(struct conbase *conbase, struct IOFileSys *iofs)
79 struct filehandle *fh = (struct filehandle *)iofs->IOFS.io_Unit;
81 EnterFunc(bug("close_con(fh=%p)\n", fh));
83 fh->usecount--;
84 if (fh->usecount > 0)
86 if (iofs->IOFS.io_Message.mn_ReplyPort->mp_SigTask == fh->lastwritetask)
88 fh->lastwritetask = NULL;
91 else
93 iofs->IOFS.io_Unit = NULL;
96 iofs->io_DosError = 0;
97 ReplyMsg(&iofs->IOFS.io_Message);
100 /****************************************************************************************/
102 static void con_read(struct conbase *conbase, struct IOFileSys *iofs)
104 struct filehandle *fh = (struct filehandle *)iofs->IOFS.io_Unit;
106 if (fh->flags & FHFLG_CANREAD)
108 ULONG readlen = (fh->canreadsize < iofs->io_Union.io_READ.io_Length) ? fh->canreadsize :
109 iofs->io_Union.io_READ.io_Length;
110 /* we must correct io_READ.io_Length, because answer_read_request
111 would read until fh->inputsize if possible, but here it is allowed only
112 to read max. fh->canreadsize chars */
114 iofs->io_Union.io_READ.io_Length = readlen;
115 answer_read_request(conbase, fh, iofs);
117 fh->canreadsize -= readlen;
118 if (fh->canreadsize == 0) fh->flags &= ~FHFLG_CANREAD;
121 else
123 if (fh->flags & FHFLG_EOF)
125 iofs->io_Union.io_READ.io_Length = 0;
126 iofs->IOFS.io_Error = 0;
127 iofs->io_DosError = 0;
129 ReplyMsg(&iofs->IOFS.io_Message);
131 fh->flags &= ~FHFLG_EOF;
133 else
135 AddTail((struct List *)&fh->pendingReads, (struct Node *)iofs);
136 fh->flags |= FHFLG_READPENDING;
141 /****************************************************************************************/
143 static void con_write(struct conbase *conbase, struct IOFileSys *iofs)
145 struct filehandle *fh = (struct filehandle *)iofs->IOFS.io_Unit;
147 #if DEBUG
148 EnterFunc(bug("con_write(fh=%p, buf=", fh));
150 int i, len = iofs->io_Union.io_WRITE.io_Length;
151 for (i = 0; i < len; ++i)
152 bug("%c", iofs->io_Union.io_WRITE.io_Buffer[i]);
153 bug(")\n");
155 #endif
157 #if 0
159 /* stegerg: this seems to be wrong */
161 /* Change the task to which CTRL/C/D/E/F signals are sent to
162 the task which sent this write request */
164 /* PARANOIA ^ 3 */
166 if (iofs->IOFS.io_Message.mn_ReplyPort)
167 if ((iofs->IOFS.io_Message.mn_ReplyPort->mp_Flags & PF_ACTION) == PA_SIGNAL)
168 if (iofs->IOFS.io_Message.mn_ReplyPort->mp_SigTask)
170 fh->breaktask = iofs->IOFS.io_Message.mn_ReplyPort->mp_SigTask;
172 #endif
174 /* PARANOIA ^ 3 */
176 if (iofs->IOFS.io_Message.mn_ReplyPort)
177 if ((iofs->IOFS.io_Message.mn_ReplyPort->mp_Flags & PF_ACTION) == PA_SIGNAL)
178 if (iofs->IOFS.io_Message.mn_ReplyPort->mp_SigTask)
180 fh->lastwritetask = iofs->IOFS.io_Message.mn_ReplyPort->mp_SigTask;
183 #if !BETTER_WRITE_HANDLING
184 if ((fh->inputsize - fh->inputstart) == 0)
186 answer_write_request(conbase, fh, iofs);
187 } else {
188 #endif
189 AddTail((struct List *)&fh->pendingWrites, (struct Node *)iofs);
190 fh->flags |= FHFLG_WRITEPENDING;
191 #if !BETTER_WRITE_HANDLING
193 #endif
196 /****************************************************************************************/
198 LONG MakeConWindow(struct filehandle *fh, struct conbase *conbase)
200 LONG err = 0;
202 struct TagItem win_tags [] =
204 {WA_PubScreen ,0 },
205 {WA_AutoAdjust ,TRUE },
206 {WA_PubScreenName, 0 },
207 {WA_PubScreenFallBack, TRUE },
208 {TAG_DONE }
211 win_tags[2].ti_Data = (IPTR)fh->screenname;
212 D(bug("[contask] Opening window on screen %s, IntuitionBase = 0x%p\n", fh->screenname, IntuitionBase));
213 fh->window = OpenWindowTagList(&fh->nw, (struct TagItem *)win_tags);
215 if (fh->window)
217 D(bug("contask: window opened\n"));
218 fh->conreadio->io_Data = (APTR)fh->window;
219 fh->conreadio->io_Length = sizeof (struct Window);
221 if (0 == OpenDevice("console.device", CONU_SNIPMAP, ioReq(fh->conreadio), 0))
223 const UBYTE lf_on[] = {0x9B, 0x32, 0x30, 0x68 }; /* Set linefeed mode */
225 D(bug("contask: device opened\n"));
227 fh->flags |= FHFLG_CONSOLEDEVICEOPEN;
229 fh->conwriteio = *fh->conreadio;
230 fh->conwriteio.io_Message.mn_ReplyPort = fh->conwritemp;
232 /* Turn the console into LF+CR mode so that both
233 linefeed and carriage return is done on
235 fh->conwriteio.io_Command = CMD_WRITE;
236 fh->conwriteio.io_Data = (APTR)lf_on;
237 fh->conwriteio.io_Length = 4;
239 DoIO(ioReq(&fh->conwriteio));
241 } /* if (0 == OpenDevice("console.device", CONU_STANDARD, ioReq(fh->conreadio), 0)) */
242 else
244 err = ERROR_INVALID_RESIDENT_LIBRARY;
246 if (err) CloseWindow(fh->window);
248 } /* if (fh->window) */
249 else
251 D(bug("[contask] Failed to open a window\n"));
252 err = ERROR_NO_FREE_STORE;
255 return err;
258 /****************************************************************************************/
260 VOID StartAsyncConsoleRead(struct filehandle *fh, struct conbase *conbase)
262 if (fh->window)
264 fh->conreadio->io_Command = CMD_READ;
265 fh->conreadio->io_Data = fh->consolebuffer;
266 fh->conreadio->io_Length = CONSOLEBUFFER_SIZE;
268 SendIO(ioReq(fh->conreadio));
270 fh->flags |= FHFLG_ASYNCCONSOLEREAD;
274 /****************************************************************************************/
276 BOOL MakeSureWinIsOpen(struct conbase *conbase, struct IOFileSys *iofs, struct filehandle *fh)
278 LONG err;
280 D(bug("[contask] Console window handle: 0x%p\n", fh->window));
281 if (fh->window) return TRUE;
283 err = MakeConWindow(fh, conbase);
284 if (err)
286 iofs->io_DosError = err;
287 ReplyMsg(&iofs->IOFS.io_Message);
288 return FALSE;
291 /* Send first read request to console.device */
293 StartAsyncConsoleRead(fh, conbase);
295 return TRUE;
299 /****************************************************************************************/
301 VOID HandlePendingReads(struct conbase *conbase, struct filehandle *fh)
303 if (fh->flags & FHFLG_READPENDING)
305 struct IOFileSys *iofs, *next_iofs;
307 ForeachNodeSafe(&fh->pendingReads, iofs, next_iofs)
309 Remove((struct Node *)iofs);
310 answer_read_request(conbase, fh, iofs);
312 if (fh->inputsize == 0) break;
314 } /* ForeachNodeSafe(&fh->pendingReads, iofs, nextiofs) */
316 if (IsListEmpty(&fh->pendingReads)) fh->flags &= ~FHFLG_READPENDING;
320 if (fh->inputsize)
322 fh->flags |= FHFLG_CANREAD;
323 fh->canreadsize = fh->inputsize;
327 /****************************************************************************************/
329 static const STRPTR CONCLIP_PORTNAME = "ConClip.rendezvous";
331 struct MyEditHookMsg
333 struct Message msg;
334 struct SGWork *sgw;
335 WORD code;
338 static void do_paste(struct conbase * conbase, struct filehandle * fh)
340 struct MsgPort replyport, *port;
341 struct SGWork sgw;
342 struct MyEditHookMsg msg;
343 struct StringInfo sinfo;
345 if (!(port = FindPort(CONCLIP_PORTNAME))) {
346 D(bug("ConClip not running, but we got a ConClip paste request"));
347 return;
350 D(bug("PASTE REQUEST!\n"));
352 replyport.mp_Node.ln_Type = NT_MSGPORT;
353 replyport.mp_Node.ln_Name = NULL;
354 replyport.mp_Node.ln_Pri = 0;
355 replyport.mp_Flags = PA_SIGNAL;
356 replyport.mp_SigBit = SIGB_SINGLE;
357 replyport.mp_SigTask = FindTask(NULL);
358 NewList(&replyport.mp_MsgList);
360 msg.msg.mn_Node.ln_Type = NT_MESSAGE;
361 msg.msg.mn_ReplyPort = &replyport;
362 msg.msg.mn_Length = sizeof(msg);
364 msg.code = 'V';
365 msg.sgw = &sgw;
367 /* FIXME: Ensure no fields are left uninitialized */
369 sgw.Gadget = 0;
370 sgw.WorkBuffer = AllocMem(PASTEBUFSIZE,MEMF_CLEAR | MEMF_ANY);
371 sgw.PrevBuffer = 0;
372 sgw.IEvent = 0;
373 sgw.Code = 'V';
374 sgw.Actions = 0;
375 sgw.LongInt = 0;
376 sgw.GadgetInfo = 0;
377 sgw.EditOp = EO_BIGCHANGE;
378 sgw.BufferPos = 0;
379 sgw.NumChars = 0;
381 /* ConClip only ever looks at MaxChars in StringInfo */
382 sinfo.MaxChars = PASTEBUFSIZE;
383 sgw.StringInfo = &sinfo;
385 SetSignal(0, SIGF_SINGLE);
386 PutMsg(port, &msg.msg);
387 WaitPort(&replyport);
389 D(bug("Pasting %d bytes\n",sgw.BufferPos));
391 if (fh->pastebuffer) FreeMem(fh->pastebuffer,PASTEBUFSIZE);
392 fh->pastebuffer = sgw.WorkBuffer;
393 fh->pastebuffersize = sgw.BufferPos;
394 fh->pastebufferpos = 0;
398 /****************************************************************************************/
400 static void process_input(struct conbase * conbase,struct filehandle *fh)
402 UBYTE c;
403 WORD inp;
404 while((inp = scan_input(conbase, fh, &c)) != INP_DONE)
406 D(bug("Input Code: %d\n",inp));
408 switch(inp)
410 case INP_CURSORLEFT:
411 if (fh->inputpos > fh->inputstart)
413 fh->inputpos--;
414 do_movecursor(conbase, fh, CUR_LEFT, 1);
416 break;
418 case INP_SHIFT_CURSORLEFT: /* move to beginning of line */
419 case INP_HOME:
420 if (fh->inputpos > fh->inputstart)
422 do_movecursor(conbase, fh, CUR_LEFT, fh->inputpos - fh->inputstart);
423 fh->inputpos = fh->inputstart;
425 break;
427 case INP_CURSORRIGHT:
428 if (fh->inputpos < fh->inputsize)
430 fh->inputpos++;
431 do_movecursor(conbase, fh, CUR_RIGHT, 1);
433 break;
435 case INP_SHIFT_CURSORRIGHT: /* move to end of line */
436 case INP_END:
437 if (fh->inputpos != fh->inputsize)
439 do_movecursor(conbase, fh, CUR_RIGHT, fh->inputsize - fh->inputpos);
440 fh->inputpos = fh->inputsize;
442 break;
444 case INP_CURSORUP: /* walk through cmd history */
445 case INP_CURSORDOWN:
446 case INP_SHIFT_CURSORUP:
447 case INP_SHIFT_CURSORDOWN:
448 /* no history if we're hidden */
449 if (! (fh->flags & FHFLG_NOECHO))
450 history_walk(conbase, fh, inp);
451 break;
453 case INP_BACKSPACE:
454 if (fh->inputpos > fh->inputstart)
456 do_movecursor(conbase, fh, CUR_LEFT, 1);
458 if (fh->inputpos == fh->inputsize)
460 do_deletechar(conbase, fh);
462 fh->inputsize--;
463 fh->inputpos--;
464 } else {
465 WORD chars_right = fh->inputsize - fh->inputpos;
467 fh->inputsize--;
468 fh->inputpos--;
470 do_cursorvisible(conbase, fh, FALSE);
471 do_write(conbase, fh, &fh->inputbuffer[fh->inputpos + 1], chars_right);
472 do_deletechar(conbase, fh);
473 do_movecursor(conbase, fh, CUR_LEFT, chars_right);
474 do_cursorvisible(conbase, fh, TRUE);
476 memmove(&fh->inputbuffer[fh->inputpos], &fh->inputbuffer[fh->inputpos + 1], chars_right);
480 break;
482 case INP_SHIFT_BACKSPACE:
483 if (fh->inputpos > fh->inputstart)
485 do_movecursor(conbase, fh, CUR_LEFT, fh->inputpos - fh->inputstart);
486 if (fh->inputpos == fh->inputsize)
488 do_eraseinline(conbase, fh);
490 fh->inputpos = fh->inputsize = fh->inputstart;
491 } else {
492 WORD chars_right = fh->inputsize - fh->inputpos;
494 do_cursorvisible(conbase, fh, FALSE);
495 do_write(conbase, fh, &fh->inputbuffer[fh->inputpos], chars_right);
496 do_eraseinline(conbase, fh);
497 do_movecursor(conbase, fh, CUR_LEFT, chars_right);
498 do_cursorvisible(conbase, fh, TRUE);
500 memmove(&fh->inputbuffer[fh->inputstart], &fh->inputbuffer[fh->inputpos], chars_right);
502 fh->inputsize -= (fh->inputpos - fh->inputstart);
503 fh->inputpos = fh->inputstart;
506 break;
508 case INP_DELETE:
509 if (fh->inputpos < fh->inputsize)
511 fh->inputsize--;
513 if (fh->inputpos == fh->inputsize)
515 do_deletechar(conbase, fh);
516 } else {
517 WORD chars_right = fh->inputsize - fh->inputpos;
519 do_cursorvisible(conbase, fh, FALSE);
520 do_write(conbase, fh, &fh->inputbuffer[fh->inputpos + 1], chars_right);
521 do_deletechar(conbase, fh);
522 do_movecursor(conbase, fh, CUR_LEFT, chars_right);
523 do_cursorvisible(conbase, fh, TRUE);
525 memmove(&fh->inputbuffer[fh->inputpos], &fh->inputbuffer[fh->inputpos + 1], chars_right);
528 break;
530 case INP_SHIFT_DELETE:
531 if (fh->inputpos < fh->inputsize)
533 fh->inputsize = fh->inputpos;
534 do_eraseinline(conbase, fh);
536 break;
538 case INP_CONTROL_X:
539 if ((fh->inputsize - fh->inputstart) > 0)
541 if (fh->inputpos > fh->inputstart)
543 do_movecursor(conbase, fh, CUR_LEFT, fh->inputpos - fh->inputstart);
545 do_eraseinline(conbase, fh);
547 fh->inputpos = fh->inputsize = fh->inputstart;
549 break;
551 case INP_ECHO_STRING:
552 do_write(conbase, fh, &c, 1);
553 break;
555 case INP_STRING:
556 if (fh->inputsize < INPUTBUFFER_SIZE)
558 do_write(conbase, fh, &c, 1);
560 if (fh->inputpos == fh->inputsize)
562 fh->inputbuffer[fh->inputpos++] = c;
563 fh->inputsize++;
564 } else {
565 WORD chars_right = fh->inputsize - fh->inputpos;
567 do_cursorvisible(conbase, fh, FALSE);
568 do_write(conbase, fh, &fh->inputbuffer[fh->inputpos], chars_right);
569 do_movecursor(conbase, fh, CUR_LEFT, chars_right);
570 do_cursorvisible(conbase, fh, TRUE);
572 memmove(&fh->inputbuffer[fh->inputpos + 1], &fh->inputbuffer[fh->inputpos], chars_right);
573 fh->inputbuffer[fh->inputpos++] = c;
574 fh->inputsize++;
577 break;
579 case INP_EOF:
580 fh->flags |= FHFLG_EOF;
581 if (fh->flags & FHFLG_AUTO && fh->window)
583 if (fh->flags & FHFLG_CONSOLEDEVICEOPEN)
584 CloseDevice((struct IORequest *)fh->conreadio);
585 fh->flags &= ~FHFLG_CONSOLEDEVICEOPEN;
586 CloseWindow(fh->window);
587 fh->window = NULL;
590 /* fall through */
592 case INP_RETURN:
593 if (fh->inputsize < INPUTBUFFER_SIZE)
595 if (inp != INP_EOF)
597 c = '\n';
598 do_write(conbase, fh, &c, 1);
600 /* don't put hidden things in the history */
601 if (! (fh->flags & FHFLG_NOECHO))
602 add_to_history(conbase, fh);
604 fh->inputbuffer[fh->inputsize++] = '\n';
607 fh->inputstart = fh->inputsize;
608 fh->inputpos = fh->inputstart;
610 if (fh->inputsize) HandlePendingReads(conbase, fh);
612 if ((fh->flags & FHFLG_EOF) && (fh->flags & FHFLG_READPENDING))
614 struct IOFileSys *iofs = (struct IOFileSys *)RemHead((struct List *)&fh->pendingReads);
616 if (iofs)
618 iofs->io_Union.io_READ.io_Length = 0;
619 iofs->IOFS.io_Error = 0;
620 iofs->io_DosError = 0;
622 ReplyMsg(&iofs->IOFS.io_Message);
624 fh->flags &= ~FHFLG_EOF;
627 if (IsListEmpty(&fh->pendingReads)) fh->flags &= ~FHFLG_READPENDING;
630 } /* if (fh->inputsize < INPUTBUFFER_SIZE) */
631 break;
633 case INP_LINEFEED:
634 if (fh->inputsize < INPUTBUFFER_SIZE)
636 c = '\n';
637 do_write(conbase, fh, &c, 1);
639 /* don't put hidden things in the history */
640 if (! (fh->flags & FHFLG_NOECHO))
641 add_to_history(conbase, fh);
643 fh->inputbuffer[fh->inputsize++] = c;
644 fh->inputstart = fh->inputsize;
645 fh->inputpos = fh->inputsize;
647 break;
649 case INP_CTRL_C:
650 case INP_CTRL_D:
651 case INP_CTRL_E:
652 case INP_CTRL_F:
653 if (fh->breaktask)
655 Signal(fh->breaktask, 1L << (12 + inp - INP_CTRL_C));
657 break;
659 case INP_TAB:
660 /* don't complete hidden things */
661 if (! (fh->flags & FHFLG_NOECHO))
662 Completion(conbase, fh);
663 break;
665 case INP_PASTE:
666 do_paste(conbase,fh);
667 break;
669 } /* switch(inp) */
671 } /* while((inp = scan_input(conbase, fh, &c)) != INP_DONE) */
675 /****************************************************************************************/
677 struct TimedReq
679 struct timerequest req;
680 struct IOFileSys *iofs;
681 struct TimedReq *next;
684 AROS_UFH3(VOID, conTaskEntry,
685 AROS_UFHA(STRPTR, argstr, A0),
686 AROS_UFHA(ULONG, arglen, D0),
687 AROS_UFHA(struct ExecBase *, SysBase, A6)
690 AROS_USERFUNC_INIT
692 struct conTaskParams *param = (struct conTaskParams *)FindTask(NULL)->tc_UserData;
694 struct conbase *conbase = param->conbase;
696 struct filehandle *fh;
697 struct IOFileSys *iofs = param->iofs;
698 #if DEBUG
699 STRPTR filename = iofs->io_Union.io_OPEN.io_Filename;
700 #endif
701 LONG err = 0;
703 BOOL ok = FALSE;
705 struct MsgPort *timermp = NULL;
706 struct TimedReq *timereq = NULL;
707 struct Library *TimerBase = NULL;;
708 const LONG treqsize = sizeof(struct TimedReq);
710 D(bug("conTaskEntry: taskparams = %x conbase = %x iofs = %x filename = \"%s\"\n",
711 param, conbase, iofs, filename));
713 fh = AllocMem(sizeof (struct filehandle), MEMF_PUBLIC | MEMF_CLEAR);
714 if (fh)
716 D(bug("contask: fh allocated\n"));
718 fh->usecount = 1;
720 /* if iofs->IOFS.io_Unit equals 1 it means that we have to start in RAW mode */
721 if (iofs->IOFS.io_Unit)
722 fh->flags |= FHFLG_RAW;
724 fh->contask = FindTask(NULL);
725 fh->breaktask = param->parentTask;
727 NEWLIST(&fh->pendingReads);
728 NEWLIST(&fh->pendingWrites);
730 /* Create msgport for console.device communication
731 and for app <-> contask communication */
732 fh->conreadmp = AllocMem(sizeof (struct MsgPort) * 3, MEMF_PUBLIC|MEMF_CLEAR);
733 if (fh->conreadmp)
736 D(bug("contask: mem for conreadmp, conwritemp and contaskmp allocated\n"));
738 fh->conreadmp->mp_Node.ln_Type = NT_MSGPORT;
739 fh->conreadmp->mp_Flags = PA_SIGNAL;
740 fh->conreadmp->mp_SigBit = AllocSignal(-1);
741 fh->conreadmp->mp_SigTask = fh->contask;
742 NEWLIST(&fh->conreadmp->mp_MsgList);
744 fh->conwritemp = fh->conreadmp + 1;
746 fh->conwritemp->mp_Node.ln_Type = NT_MSGPORT;
747 fh->conwritemp->mp_Flags = PA_SIGNAL;
748 fh->conwritemp->mp_SigBit = AllocSignal(-1);
749 fh->conwritemp->mp_SigTask = fh->contask;
750 NEWLIST(&fh->conwritemp->mp_MsgList);
752 fh->contaskmp = fh->conwritemp + 1;
754 fh->contaskmp->mp_Node.ln_Type = NT_MSGPORT;
755 fh->contaskmp->mp_Flags = PA_SIGNAL;
756 fh->contaskmp->mp_SigBit = AllocSignal(-1);
757 fh->contaskmp->mp_SigTask = fh->contask;
758 NEWLIST(&fh->contaskmp->mp_MsgList);
760 fh->conreadio = (struct IOStdReq *)CreateIORequest(fh->conreadmp, sizeof (struct IOStdReq));
761 if (fh->conreadio)
763 D(bug("contask: conreadio created\n"));
765 fh->nw = default_nw;
767 if (parse_filename(conbase, fh, iofs, &fh->nw))
769 if (!(fh->flags & FHFLG_AUTO))
771 err = MakeConWindow(fh, conbase);
772 if (!err) ok = TRUE;
774 else
776 ok = TRUE;
779 else
780 err = ERROR_BAD_STREAM_NAME;
782 if (ok)
784 iofs->IOFS.io_Unit = (struct Unit *)fh;
786 else
788 DeleteIORequest( ioReq(fh->conreadio) );
791 } /* if (fh->conreadio) */
792 else
794 err = ERROR_NO_FREE_STORE;
797 if (!ok) FreeMem(fh->conreadmp, sizeof(struct MsgPort) * 3);
799 } /* if (fh->conreadmp) */
800 else
802 err = ERROR_NO_FREE_STORE;
805 if (!ok) FreeMem(fh, sizeof (struct filehandle));
807 } /* if (fh) */
808 else
809 err = ERROR_NO_FREE_STORE;
811 iofs->io_DosError = err;
813 Signal(param->parentTask, param->initSignal);
814 if (err)
816 D(bug("con task: initialization failed. waiting for parent task to kill me.\n"));
817 /* parent Task will kill us */
818 Wait(0);
821 timermp = CreateMsgPort();
822 timereq = (struct TimedReq *)CreateIORequest(timermp, treqsize);
823 timereq->iofs = NULL;
824 timereq->next = NULL;
826 OpenDevice(TIMERNAME, UNIT_MICROHZ, (struct IORequest *)timereq, 0);
827 TimerBase = (struct Library *)timereq->req.tr_node.io_Device;
829 D(bug("con task: initialization okay. entering main loop.\n"));
831 /* Main Loop */
833 /* Send first read request to console.device */
835 StartAsyncConsoleRead(fh, conbase);
837 for(;;)
839 ULONG conreadmask = 1L << fh->conreadmp->mp_SigBit;
840 ULONG contaskmask = 1L << fh->contaskmp->mp_SigBit;
841 ULONG timermask = 1L << timermp->mp_SigBit;
842 ULONG sigs;
844 if (fh->usecount == 0)
846 if ((fh->flags & FHFLG_EOF) ||
847 (!(fh->flags & FHFLG_WAIT)))
849 break;
853 if (fh->flags & FHFLG_WRITEPENDING) D(bug("Write Pending\n"));
854 D(bug("inputpos %ld and inputstart %ld\n",fh->inputpos,fh->inputstart));
855 /* Dont wait if a write is pending and a write really can be done */
856 if ((fh->flags & FHFLG_WRITEPENDING))
858 sigs = CheckSignal(conreadmask | contaskmask | timermask);
860 else
862 D(bug("contask: waiting for sigs 0x%x\n",
863 conreadmask | contaskmask | timermask));
864 sigs = Wait(conreadmask | contaskmask | timermask);
867 if (sigs & timermask)
869 struct TimedReq *treq, *treq1;
871 D(bug("contask: received timer signal 0x%x\n", sigs));
872 while ((treq = (struct TimedReq *)GetMsg(timermp)))
874 iofs = treq->iofs;
876 if (iofs->IOFS.io_Command == FSA_WAIT_CHAR)
878 iofs->io_Union.io_WAIT_CHAR.io_Success = 0;
879 iofs->io_DosError = 0;
881 else
882 iofs->io_DosError = ERROR_UNKNOWN;
884 ReplyMsg(&iofs->IOFS.io_Message);
886 /* remove from pending timers list */
887 treq1 = timereq;
888 while (treq1->next)
890 if (treq1->next == treq)
892 treq1->next = treq->next;
893 break;
895 treq1 = treq1->next;
898 DeleteIORequest((struct IORequest *)treq);
902 if (sigs & contaskmask)
904 /* FSA messages */
905 D(bug("contask: recevied contask signal\n"));
906 while((iofs = (struct IOFileSys *)GetMsg(fh->contaskmp)))
908 switch(iofs->IOFS.io_Command)
910 case FSA_CLOSE:
911 D(bug("[contask] FSA_CLOSE\n"));
912 close_con(conbase, iofs);
913 break;
915 case FSA_READ:
916 D(bug("[contask] FSA_READ\n"));
917 if (!MakeSureWinIsOpen(conbase, iofs, fh)) break;
918 con_read(conbase, iofs);
919 break;
921 case FSA_WRITE:
922 D(bug("[contask] FSA_WRITE\n"));
923 if (!MakeSureWinIsOpen(conbase, iofs, fh)) break;
924 con_write(conbase, iofs);
925 break;
927 case FSA_CHANGE_SIGNAL:
928 D(bug("[contask] FSA_CHANGE_SIGNAL\n"));
929 fh->breaktask = iofs->io_Union.io_CHANGE_SIGNAL.io_Task;
930 ReplyMsg(&iofs->IOFS.io_Message);
931 break;
933 case FSA_CONSOLE_MODE:
934 D(bug("[contask] FSA_CONSOLE_MODE\n"));
936 LONG wantmode = iofs->io_Union.io_CONSOLE_MODE.io_ConsoleMode;
938 if (wantmode & FCM_RAW && ! (fh->flags & FHFLG_RAW))
940 /* Switching from CON: mode to RAW: mode */
942 fh->flags |= FHFLG_RAW;
944 fh->inputstart = fh->inputsize;
945 fh->inputpos = fh->inputsize;
947 HandlePendingReads(conbase, fh);
950 else
952 /* otherwise just copy the flags */
953 fh->flags &= ~(FHFLG_RAW | FHFLG_NOECHO);
954 if (wantmode & FCM_RAW)
955 fh->flags |= FHFLG_RAW;
956 if (wantmode & FCM_NOECHO)
957 fh->flags |= FHFLG_NOECHO;
961 ReplyMsg(&iofs->IOFS.io_Message);
962 break;
964 case FSA_WAIT_CHAR:
965 D(bug("[contask] FSA_WAIT_CHAR\n"));
967 struct IFS_WAIT_CHAR *wc;
968 wc = &iofs->io_Union.io_WAIT_CHAR;
970 if (fh->inputsize > 0)
972 iofs->io_DosError = 0;
973 wc->io_Success = 1;
974 ReplyMsg(&iofs->IOFS.io_Message);
976 else
978 struct TimedReq *treq, *treq1;
979 struct IORequest *ioreq;
980 LONG sec = wc->io_Timeout / 1000000;
981 LONG usec = wc->io_Timeout % 1000000;
983 ioreq = CreateIORequest(timermp, treqsize);
984 treq = (struct TimedReq *)ioreq;
985 *treq = *timereq;
987 treq->req.tr_node.io_Command = TR_ADDREQUEST;
988 treq->req.tr_time.tv_secs = sec;
989 treq->req.tr_time.tv_micro = usec;
990 treq->iofs = iofs;
991 treq->next = NULL;
992 /* Remove((struct Node *)iofs); */
994 treq1 = timereq;
995 while (treq1->next)
996 treq1 = treq1->next;
997 treq1->next = treq;
998 D(bug("CONTASK: AddTail treq=%x\n", (unsigned)treq));
1000 SendIO(ioreq);
1003 break;
1004 } /* switch(iofs->IOFS.io_Command) */
1006 } /* while((iofs = (struct IOFileSys *)GetMsg(fh->contaskmp))) */
1008 } /* if (sigs & contaskmask) */
1010 if (sigs & conreadmask)
1012 struct TimedReq *treq, *treq1;
1013 UBYTE c;
1014 WORD inp;
1016 /* console.device read request completed */
1017 D(bug("contask: received console device signal\n"));
1019 GetMsg(fh->conreadmp);
1021 fh->conbuffersize = fh->conreadio->io_Actual;
1022 fh->conbufferpos = 0;
1024 /* terminate with 0 char */
1025 fh->consolebuffer[fh->conbuffersize] = '\0';
1027 /* notify FSA_WAIT_CHAR callers */
1028 treq = timereq->next;
1029 while (treq)
1031 D(bug("CONTASK: treq=0x%p\n", treq));
1033 treq1 = treq->next;
1034 iofs = treq->iofs;
1035 AbortIO((struct IORequest *)treq);
1036 WaitIO((struct IORequest *)treq);
1037 DeleteIORequest((struct IORequest *)treq);
1038 iofs->io_Union.io_WAIT_CHAR.io_Success = 1;
1039 iofs->io_DosError = 0;
1040 ReplyMsg(&iofs->IOFS.io_Message);
1041 treq = treq1;
1043 timereq->next = NULL;
1045 if (fh->flags & FHFLG_RAW)
1047 /* raw mode */
1049 for(inp = 0; (inp < fh->conbuffersize) && (fh->inputpos < INPUTBUFFER_SIZE); )
1051 fh->inputbuffer[fh->inputpos++] = fh->consolebuffer[inp++];
1054 fh->inputsize = fh->inputstart = fh->inputpos;
1056 HandlePendingReads(conbase, fh);
1058 } /* if (fh->flags & FHFLG_RAW) */
1059 else
1061 /* Cooked mode */
1063 /* disable output if we're not suppoed to be echoing */
1064 if (fh->flags & FHFLG_NOECHO)
1065 fh->flags |= FHFLG_NOWRITE;
1067 process_input(conbase,fh);
1069 /* re-enable output */
1070 fh->flags &= ~FHFLG_NOWRITE;
1072 } /* if (fh->flags & FHFLG_RAW) else ... */
1074 /* wait for next input from console.device */
1076 StartAsyncConsoleRead(fh, conbase);
1078 } /* if (sigs & conmask) */
1080 /* pending writes ? */
1082 if ((fh->flags & FHFLG_WRITEPENDING))
1084 /* FIXME: If fg->inputpos != fh->inputstart, it means there are
1085 things on the command line buffer. When we return to the prompt, we need to make sure these gets written out again */
1087 struct IOFileSys *iofs, *iofs_next;
1089 #if BETTER_WRITE_HANDLING
1090 ForeachNodeSafe(&fh->pendingWrites, iofs, iofs_next)
1092 if (answer_write_request(conbase, fh, iofs) != 0)
1094 /* Write was done only partly */
1095 break;
1097 /* Break even here (means execute only one request), so that
1098 reads can be handled inbetween */
1099 break;
1102 if (IsListEmpty(&fh->pendingWrites)) fh->flags &= ~FHFLG_WRITEPENDING;
1103 #else
1104 ForeachNodeSafe(&fh->pendingWrites, iofs, iofs_next)
1106 Remove((struct Node *)iofs);
1107 answer_write_request(conbase, fh, iofs);
1110 fh->flags &= ~FHFLG_WRITEPENDING;
1111 #endif
1112 } /* if ((fh->flags & FHFLG_WRITEPENDING) && (fh->inputpos == fh->inputstart) && (fh->inputsize == 0)) */
1114 } /* for(;;) */
1116 /* pending timers cleanup */
1118 struct TimedReq *treq, *treq1;
1120 treq = timereq->next;
1121 while (treq)
1123 treq1 = treq->next;
1124 AbortIO((struct IORequest *)treq);
1125 WaitIO((struct IORequest *)treq);
1126 DeleteIORequest((struct IORequest *)treq);
1127 treq = treq1;
1131 CloseDevice((struct IORequest *)timereq);
1132 DeleteIORequest((struct IORequest *)timereq);
1133 DeleteMsgPort(timermp);
1135 if (fh->flags & FHFLG_ASYNCCONSOLEREAD)
1137 /* Abort all pending requests */
1138 if (!CheckIO( ioReq(fh->conreadio) ))
1139 AbortIO( ioReq(fh->conreadio) );
1141 /* Wait for abort */
1142 WaitIO( ioReq(fh->conreadio) );
1145 /* Clean up */
1147 if (fh->flags & FHFLG_CONSOLEDEVICEOPEN)
1148 CloseDevice((struct IORequest *)fh->conreadio);
1150 if (fh->window)
1151 CloseWindow(fh->window);
1153 DeleteIORequest( ioReq(fh->conreadio) );
1154 FreeMem(fh->conreadmp, sizeof (struct MsgPort) * 3);
1156 if (fh->screenname) FreeVec(fh->screenname);
1157 if (fh->wintitle) FreeVec(fh->wintitle);
1158 if (fh->pastebuffer) FreeMem(fh->pastebuffer,PASTEBUFSIZE);
1160 FreeMem(fh, sizeof (struct filehandle));
1163 AROS_USERFUNC_EXIT