2 Copyright © 1995-2010, The AROS Development Team. All rights reserved.
5 Filesystem that uses console device for input/output.
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>
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>
32 #include <aros/debug.h>
34 #include "con_handler_intern.h"
36 #include "completion.h"
41 /****************************************************************************************/
43 #define ioReq(x) ((struct IORequest *)x)
45 /****************************************************************************************/
47 static const struct NewWindow default_nw
=
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
));
86 if (iofs
->IOFS
.io_Message
.mn_ReplyPort
->mp_SigTask
== fh
->lastwritetask
)
88 fh
->lastwritetask
= NULL
;
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
;
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
;
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
;
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
]);
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 */
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
;
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
);
189 AddTail((struct List
*)&fh
->pendingWrites
, (struct Node
*)iofs
);
190 fh
->flags
|= FHFLG_WRITEPENDING
;
191 #if !BETTER_WRITE_HANDLING
196 /****************************************************************************************/
198 LONG
MakeConWindow(struct filehandle
*fh
, struct conbase
*conbase
)
202 struct TagItem win_tags
[] =
205 {WA_AutoAdjust
,TRUE
},
206 {WA_PubScreenName
, 0 },
207 {WA_PubScreenFallBack
, TRUE
},
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
);
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)) */
244 err
= ERROR_INVALID_RESIDENT_LIBRARY
;
246 if (err
) CloseWindow(fh
->window
);
248 } /* if (fh->window) */
251 D(bug("[contask] Failed to open a window\n"));
252 err
= ERROR_NO_FREE_STORE
;
258 /****************************************************************************************/
260 VOID
StartAsyncConsoleRead(struct filehandle
*fh
, struct conbase
*conbase
)
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
)
280 D(bug("[contask] Console window handle: 0x%p\n", fh
->window
));
281 if (fh
->window
) return TRUE
;
283 err
= MakeConWindow(fh
, conbase
);
286 iofs
->io_DosError
= err
;
287 ReplyMsg(&iofs
->IOFS
.io_Message
);
291 /* Send first read request to console.device */
293 StartAsyncConsoleRead(fh
, conbase
);
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
;
322 fh
->flags
|= FHFLG_CANREAD
;
323 fh
->canreadsize
= fh
->inputsize
;
327 /****************************************************************************************/
329 static const STRPTR CONCLIP_PORTNAME
= "ConClip.rendezvous";
338 static void do_paste(struct conbase
* conbase
, struct filehandle
* fh
)
340 struct MsgPort replyport
, *port
;
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"));
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
);
367 /* FIXME: Ensure no fields are left uninitialized */
370 sgw
.WorkBuffer
= AllocMem(PASTEBUFSIZE
,MEMF_CLEAR
| MEMF_ANY
);
377 sgw
.EditOp
= EO_BIGCHANGE
;
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
)
404 while((inp
= scan_input(conbase
, fh
, &c
)) != INP_DONE
)
406 D(bug("Input Code: %d\n",inp
));
411 if (fh
->inputpos
> fh
->inputstart
)
414 do_movecursor(conbase
, fh
, CUR_LEFT
, 1);
418 case INP_SHIFT_CURSORLEFT
: /* move to beginning of line */
420 if (fh
->inputpos
> fh
->inputstart
)
422 do_movecursor(conbase
, fh
, CUR_LEFT
, fh
->inputpos
- fh
->inputstart
);
423 fh
->inputpos
= fh
->inputstart
;
427 case INP_CURSORRIGHT
:
428 if (fh
->inputpos
< fh
->inputsize
)
431 do_movecursor(conbase
, fh
, CUR_RIGHT
, 1);
435 case INP_SHIFT_CURSORRIGHT
: /* move to end of line */
437 if (fh
->inputpos
!= fh
->inputsize
)
439 do_movecursor(conbase
, fh
, CUR_RIGHT
, fh
->inputsize
- fh
->inputpos
);
440 fh
->inputpos
= fh
->inputsize
;
444 case INP_CURSORUP
: /* walk through cmd history */
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
);
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
);
465 WORD chars_right
= fh
->inputsize
- 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
);
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
;
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
;
509 if (fh
->inputpos
< fh
->inputsize
)
513 if (fh
->inputpos
== fh
->inputsize
)
515 do_deletechar(conbase
, fh
);
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
);
530 case INP_SHIFT_DELETE
:
531 if (fh
->inputpos
< fh
->inputsize
)
533 fh
->inputsize
= fh
->inputpos
;
534 do_eraseinline(conbase
, fh
);
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
;
551 case INP_ECHO_STRING
:
552 do_write(conbase
, fh
, &c
, 1);
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
;
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
;
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
);
593 if (fh
->inputsize
< INPUTBUFFER_SIZE
)
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
);
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) */
634 if (fh
->inputsize
< INPUTBUFFER_SIZE
)
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
;
655 Signal(fh
->breaktask
, 1L << (12 + inp
- INP_CTRL_C
));
660 /* don't complete hidden things */
661 if (! (fh
->flags
& FHFLG_NOECHO
))
662 Completion(conbase
, fh
);
666 do_paste(conbase
,fh
);
671 } /* while((inp = scan_input(conbase, fh, &c)) != INP_DONE) */
675 /****************************************************************************************/
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
)
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
;
699 STRPTR filename
= iofs
->io_Union
.io_OPEN
.io_Filename
;
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
);
716 D(bug("contask: fh allocated\n"));
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
);
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
));
763 D(bug("contask: conreadio created\n"));
767 if (parse_filename(conbase
, fh
, iofs
, &fh
->nw
))
769 if (!(fh
->flags
& FHFLG_AUTO
))
771 err
= MakeConWindow(fh
, conbase
);
780 err
= ERROR_BAD_STREAM_NAME
;
784 iofs
->IOFS
.io_Unit
= (struct Unit
*)fh
;
788 DeleteIORequest( ioReq(fh
->conreadio
) );
791 } /* if (fh->conreadio) */
794 err
= ERROR_NO_FREE_STORE
;
797 if (!ok
) FreeMem(fh
->conreadmp
, sizeof(struct MsgPort
) * 3);
799 } /* if (fh->conreadmp) */
802 err
= ERROR_NO_FREE_STORE
;
805 if (!ok
) FreeMem(fh
, sizeof (struct filehandle
));
809 err
= ERROR_NO_FREE_STORE
;
811 iofs
->io_DosError
= err
;
813 Signal(param
->parentTask
, param
->initSignal
);
816 D(bug("con task: initialization failed. waiting for parent task to kill me.\n"));
817 /* parent Task will kill us */
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"));
833 /* Send first read request to console.device */
835 StartAsyncConsoleRead(fh
, conbase
);
839 ULONG conreadmask
= 1L << fh
->conreadmp
->mp_SigBit
;
840 ULONG contaskmask
= 1L << fh
->contaskmp
->mp_SigBit
;
841 ULONG timermask
= 1L << timermp
->mp_SigBit
;
844 if (fh
->usecount
== 0)
846 if ((fh
->flags
& FHFLG_EOF
) ||
847 (!(fh
->flags
& FHFLG_WAIT
)))
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
);
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
)))
876 if (iofs
->IOFS
.io_Command
== FSA_WAIT_CHAR
)
878 iofs
->io_Union
.io_WAIT_CHAR
.io_Success
= 0;
879 iofs
->io_DosError
= 0;
882 iofs
->io_DosError
= ERROR_UNKNOWN
;
884 ReplyMsg(&iofs
->IOFS
.io_Message
);
886 /* remove from pending timers list */
890 if (treq1
->next
== treq
)
892 treq1
->next
= treq
->next
;
898 DeleteIORequest((struct IORequest
*)treq
);
902 if (sigs
& contaskmask
)
905 D(bug("contask: recevied contask signal\n"));
906 while((iofs
= (struct IOFileSys
*)GetMsg(fh
->contaskmp
)))
908 switch(iofs
->IOFS
.io_Command
)
911 D(bug("[contask] FSA_CLOSE\n"));
912 close_con(conbase
, iofs
);
916 D(bug("[contask] FSA_READ\n"));
917 if (!MakeSureWinIsOpen(conbase
, iofs
, fh
)) break;
918 con_read(conbase
, iofs
);
922 D(bug("[contask] FSA_WRITE\n"));
923 if (!MakeSureWinIsOpen(conbase
, iofs
, fh
)) break;
924 con_write(conbase
, iofs
);
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
);
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
);
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
);
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;
974 ReplyMsg(&iofs
->IOFS
.io_Message
);
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
;
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
;
992 /* Remove((struct Node *)iofs); */
998 D(bug("CONTASK: AddTail treq=%x\n", (unsigned)treq
));
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
;
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
;
1031 D(bug("CONTASK: treq=0x%p\n", treq
));
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
);
1043 timereq
->next
= NULL
;
1045 if (fh
->flags
& FHFLG_RAW
)
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) */
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 */
1097 /* Break even here (means execute only one request), so that
1098 reads can be handled inbetween */
1102 if (IsListEmpty(&fh
->pendingWrites
)) fh
->flags
&= ~FHFLG_WRITEPENDING
;
1104 ForeachNodeSafe(&fh
->pendingWrites
, iofs
, iofs_next
)
1106 Remove((struct Node
*)iofs
);
1107 answer_write_request(conbase
, fh
, iofs
);
1110 fh
->flags
&= ~FHFLG_WRITEPENDING
;
1112 } /* if ((fh->flags & FHFLG_WRITEPENDING) && (fh->inputpos == fh->inputstart) && (fh->inputsize == 0)) */
1116 /* pending timers cleanup */
1118 struct TimedReq
*treq
, *treq1
;
1120 treq
= timereq
->next
;
1124 AbortIO((struct IORequest
*)treq
);
1125 WaitIO((struct IORequest
*)treq
);
1126 DeleteIORequest((struct IORequest
*)treq
);
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
) );
1147 if (fh
->flags
& FHFLG_CONSOLEDEVICEOPEN
)
1148 CloseDevice((struct IORequest
*)fh
->conreadio
);
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
));