2 #include <proto/exec.h>
3 #include <exec/libraries.h>
4 #include <exec/resident.h>
5 #include <exec/memory.h>
7 #include <exec/errors.h>
8 #include <exec/alerts.h>
9 #include <utility/tagitem.h>
10 #include <dos/exall.h>
11 #include <dos/dosasl.h>
12 #include <intuition/intuition.h>
13 #include <proto/dos.h>
14 #include <proto/intuition.h>
15 #include <devices/conunit.h>
20 #include "con_handler_intern.h"
27 #include <aros/debug.h>
29 static char *BSTR2C(BSTR srcs
)
31 UBYTE
*src
= BADDR(srcs
);
34 dst
= AllocVec(src
[0] + 1, MEMF_ANY
);
37 memcpy (dst
, src
+ 1, src
[0]);
41 static WORD
isdosdevicec(CONST_STRPTR s
)
52 #define ioReq(x) ((struct IORequest *)x)
54 static const struct NewWindow default_nw
=
77 32767, /* MaxHeight */
78 WBENCHSCREEN
/* type */
82 static LONG
MakeConWindow(struct filehandle
*fh
)
86 if (fh
->otherwindow
== NULL
) {
87 struct TagItem win_tags
[] =
90 {WA_AutoAdjust
,TRUE
},
91 {WA_PubScreenName
,0 },
92 {WA_PubScreenFallBack
,TRUE
},
96 win_tags
[2].ti_Data
= (IPTR
)fh
->screenname
;
97 D(bug("[contask] Opening window on screen %s, IntuitionBase = 0x%p\n", fh
->screenname
, IntuitionBase
));
98 fh
->window
= OpenWindowTagList(&fh
->nw
, (struct TagItem
*)win_tags
);
100 D(bug("[contask] Using window %p\n", fh
->otherwindow
));
101 fh
->window
= fh
->otherwindow
;
106 D(bug("contask: window opened\n"));
107 fh
->conreadio
->io_Data
= (APTR
)fh
->window
;
108 fh
->conreadio
->io_Length
= sizeof (struct Window
);
110 if (0 == OpenDevice("console.device", CONU_SNIPMAP
, ioReq(fh
->conreadio
), 0))
112 const UBYTE lf_on
[] = {0x9B, 0x32, 0x30, 0x68 }; /* Set linefeed mode */
114 D(bug("contask: device opened\n"));
116 fh
->flags
|= FHFLG_CONSOLEDEVICEOPEN
;
118 fh
->conwriteio
= *fh
->conreadio
;
119 fh
->conwriteio
.io_Message
.mn_ReplyPort
= fh
->conwritemp
;
121 /* Turn the console into LF+CR mode so that both
122 linefeed and carriage return is done on
124 fh
->conwriteio
.io_Command
= CMD_WRITE
;
125 fh
->conwriteio
.io_Data
= (APTR
)lf_on
;
126 fh
->conwriteio
.io_Length
= 4;
128 DoIO(ioReq(&fh
->conwriteio
));
130 } /* if (0 == OpenDevice("console.device", CONU_STANDARD, ioReq(fh->conreadio), 0)) */
133 err
= ERROR_INVALID_RESIDENT_LIBRARY
;
135 if (err
) CloseWindow(fh
->window
);
137 } /* if (fh->window) */
140 D(bug("[contask] Failed to open a window\n"));
141 err
= ERROR_NO_FREE_STORE
;
147 static BOOL
MakeSureWinIsOpen(struct filehandle
*fh
)
151 return MakeConWindow(fh
) == 0;
154 static void close_con(struct filehandle
*fh
)
158 D(bug("[CON] Deleting timer request 0x%p\n", fh
->timerreq
));
161 CloseDevice((struct IORequest
*)fh
->timerreq
);
162 DeleteIORequest((struct IORequest
*)fh
->timerreq
);
165 D(bug("[CON] Deleting timer port 0x%p\n", fh
->timermp
));
166 DeleteMsgPort(fh
->timermp
);
168 if (fh
->flags
& FHFLG_CONSOLEDEVICEOPEN
)
170 D(bug("[CON] Closing console.device...\n"));
171 CloseDevice((struct IORequest
*)fh
->conreadio
);
174 D(bug("[CON] Closing window 0x%p\n", fh
->window
));
176 CloseWindow(fh
->window
);
178 D(bug("[CON] Delete console.device IORequest 0x%p\n", fh
->conreadio
));
179 DeleteIORequest(ioReq(fh
->conreadio
));
181 D(bug("[CON] Delete console.device MsgPort 0x%p\n", fh
->conreadmp
));
182 FreeVec(fh
->conreadmp
);
185 FreeVec(fh
->screenname
);
187 FreeVec(fh
->wintitle
);
189 FreeMem(fh
->pastebuffer
,PASTEBUFSIZE
);
191 CloseLibrary((struct Library
*)fh
->intuibase
);
192 CloseLibrary((struct Library
*)fh
->dosbase
);
194 /* These libraries are opened only if completion was used */
196 CloseLibrary((struct Library
*)fh
->gfxbase
);
198 CloseLibrary(fh
->gtbase
);
203 static struct filehandle
*open_con(struct DosPacket
*dp
, LONG
*perr
)
206 struct filehandle
*fh
;
207 struct DeviceNode
*dn
;
211 dn
= BADDR(dp
->dp_Arg3
);
212 *perr
= ERROR_NO_FREE_STORE
;
213 fh
= AllocVec(sizeof(struct filehandle
), MEMF_PUBLIC
| MEMF_CLEAR
);
217 fh
->timermp
= CreateMsgPort();
218 fh
->timerreq
= (struct timerequest
*)CreateIORequest(fh
->timermp
, sizeof(struct timerequest
));
219 OpenDevice(TIMERNAME
, UNIT_MICROHZ
, (struct IORequest
*)fh
->timerreq
, 0);
221 fh
->intuibase
= (APTR
)OpenLibrary("intuition.library", 0);
222 fh
->dosbase
= (APTR
)OpenLibrary("dos.library", 0);
223 fh
->utilbase
= (APTR
)OpenLibrary("utility.library", 0);
225 fh
->inputbase
= (struct Device
*)FindName(&SysBase
->DeviceList
, "input.device");
229 filename
= BSTR2C((BSTR
)dp
->dp_Arg1
);
231 i
= isdosdevicec(fn
);
235 fh
->contask
= FindTask(0);
237 NEWLIST(&fh
->pendingReads
);
239 /* Create msgport for console.device communication */
240 fh
->conreadmp
= AllocVec(sizeof (struct MsgPort
) * 2, MEMF_PUBLIC
|MEMF_CLEAR
);
244 fh
->conreadmp
->mp_Node
.ln_Type
= NT_MSGPORT
;
245 fh
->conreadmp
->mp_Flags
= PA_SIGNAL
;
246 fh
->conreadmp
->mp_SigBit
= AllocSignal(-1);
247 fh
->conreadmp
->mp_SigTask
= fh
->contask
;
248 NEWLIST(&fh
->conreadmp
->mp_MsgList
);
250 fh
->conwritemp
= fh
->conreadmp
+ 1;
252 fh
->conwritemp
->mp_Node
.ln_Type
= NT_MSGPORT
;
253 fh
->conwritemp
->mp_Flags
= PA_SIGNAL
;
254 fh
->conwritemp
->mp_SigBit
= AllocSignal(-1);
255 fh
->conwritemp
->mp_SigTask
= fh
->contask
;
256 NEWLIST(&fh
->conwritemp
->mp_MsgList
);
259 fh
->conreadio
= (struct IOStdReq
*)CreateIORequest(fh
->conreadmp
, sizeof (struct IOStdReq
));
262 D(bug("contask: conreadio created, parms '%s'\n", fn
));
266 if (parse_filename(fh
, fn
, &fh
->nw
))
268 if (!(fh
->flags
& FHFLG_AUTO
))
270 err
= MakeConWindow(fh
);
280 err
= ERROR_BAD_STREAM_NAME
;
284 DeleteIORequest(ioReq(fh
->conreadio
));
287 } /* if (fh->conreadio) */
290 err
= ERROR_NO_FREE_STORE
;
293 } /* if (fh->conreadmp) */
296 err
= ERROR_NO_FREE_STORE
;
300 fh
->flags
|= FHFLG_RAW
;
310 static void startread(struct filehandle
*fh
)
312 if (fh
->flags
& FHFLG_ASYNCCONSOLEREAD
)
314 fh
->conreadio
->io_Command
= CMD_READ
;
315 fh
->conreadio
->io_Data
= fh
->consolebuffer
;
316 fh
->conreadio
->io_Length
= CONSOLEBUFFER_SIZE
;
317 SendIO((struct IORequest
*)fh
->conreadio
);
318 fh
->flags
|= FHFLG_ASYNCCONSOLEREAD
;
321 static void stopwait(struct filehandle
*fh
, struct DosPacket
*waitingdp
, ULONG result
)
325 AbortIO((struct IORequest
*)fh
->timerreq
);
326 WaitIO((struct IORequest
*)fh
->timerreq
);
327 replypkt(waitingdp
, result
);
331 static void stopread(struct filehandle
*fh
, struct DosPacket
*waitingdp
)
333 struct Message
*msg
, *next_msg
;
335 stopwait(fh
, waitingdp
, DOSFALSE
);
337 ForeachNodeSafe(&fh
->pendingReads
, msg
, next_msg
)
339 struct DosPacket
*dpr
;
341 Remove((struct Node
*)msg
);
342 dpr
= (struct DosPacket
*)msg
->mn_Node
.ln_Name
;
343 replypkt(dpr
, DOSFALSE
);
350 struct DosPacket
*dp
;
352 struct FileHandle
*dosfh
;
354 struct filehandle
*fh
;
356 struct DosPacket
*waitingdp
= NULL
;
358 D(bug("[CON] started\n"));
359 mp
= &((struct Process
*)FindTask(NULL
))->pr_MsgPort
;
361 dp
= (struct DosPacket
*)GetMsg(mp
)->mn_Node
.ln_Name
;
362 D(bug("[CON] startup message received. port=0x%p path='%b'\n", mp
, dp
->dp_Arg1
));
364 fh
= open_con(dp
, &error
);
366 D(bug("[CON] init failed\n"));
369 D(bug("[CON] 0x%p open\n", fh
));
370 replypkt(dp
, DOSTRUE
);
374 ULONG conreadmask
= 1L << fh
->conreadmp
->mp_SigBit
;
375 ULONG timermask
= 1L << fh
->timermp
->mp_SigBit
;
376 ULONG packetmask
= 1L << mp
->mp_SigBit
;
379 sigs
= Wait(packetmask
| conreadmask
| timermask
);
381 if (sigs
& timermask
) {
383 replypkt(waitingdp
, DOSFALSE
);
388 if (sigs
& conreadmask
) {
389 GetMsg(fh
->conreadmp
);
390 fh
->flags
&= ~FHFLG_ASYNCCONSOLEREAD
;
393 stopwait(fh
, waitingdp
, DOSTRUE
);
396 D(bug("IO_READ %d\n", fh
->conreadio
->io_Actual
));
397 fh
->conbuffersize
= fh
->conreadio
->io_Actual
;
398 fh
->conbufferpos
= 0;
399 /* terminate with 0 char */
400 fh
->consolebuffer
[fh
->conbuffersize
] = '\0';
401 if (fh
->flags
& FHFLG_RAW
)
405 for(inp
= 0; (inp
< fh
->conbuffersize
) && (fh
->inputpos
< INPUTBUFFER_SIZE
); )
407 fh
->inputbuffer
[fh
->inputpos
++] = fh
->consolebuffer
[inp
++];
409 fh
->inputsize
= fh
->inputstart
= fh
->inputpos
;
410 HandlePendingReads(fh
);
411 } /* if (fh->flags & FHFLG_RAW) */
415 if (process_input(fh
))
418 * process_input() returns TRUE when EOF was received after the WAIT console
419 * has been closed by the owner.
424 } /* if (fh->flags & FHFLG_RAW) else ... */
428 while ((mn
= GetMsg(mp
))) {
429 dp
= (struct DosPacket
*)mn
->mn_Node
.ln_Name
;
431 D(bug("[CON 0x%p] packet 0x%p:%d 0x%p,0x%p,0x%p\n",
432 fh
, dp
, dp
->dp_Type
, dp
->dp_Arg1
, dp
->dp_Arg2
, dp
->dp_Arg3
));
436 case ACTION_FH_FROM_LOCK
:
437 fl
= BADDR(dp
->dp_Arg2
);
438 if (fl
->fl_Task
!= mp
||
439 fl
->fl_Key
!= (IPTR
)fh
) {
440 replypkt2(dp
, DOSFALSE
, ERROR_OBJECT_NOT_FOUND
);
444 FreeMem(fl
, sizeof(*fl
));
446 case ACTION_FINDINPUT
:
447 case ACTION_FINDOUTPUT
:
448 case ACTION_FINDUPDATE
:
449 dosfh
= BADDR(dp
->dp_Arg1
);
450 dosfh
->fh_Interactive
= DOSTRUE
;
451 dosfh
->fh_Arg1
= (SIPTR
)fh
;
453 fh
->breaktask
= dp
->dp_Port
->mp_SigTask
;
454 D(bug("[CON] Find fh=%x. Usecount=%d\n", dosfh
, fh
->usecount
));
455 replypkt(dp
, DOSTRUE
);
457 case ACTION_COPY_DIR_FH
:
458 fl
= AllocMem(sizeof(*fl
), MEMF_CLEAR
| MEMF_PUBLIC
);
460 replypkt2(dp
, (SIPTR
)BNULL
, ERROR_NO_FREE_STORE
);
464 fl
->fl_Key
= (IPTR
)fh
;
465 replypkt(dp
, (SIPTR
)MKBADDR(fl
));
470 D(bug("[CON] usecount=%d\n", fh
->usecount
));
471 if (fh
->usecount
<= 0)
473 if (fh
->flags
& FHFLG_WAIT
)
475 D(bug("[CON] Delayed close, waiting...\n"));
478 * Bounce all pending read and waits (the same as we do when exiting).
479 * However the process is still around, waiting for EOF input.
480 * Our user has just closed his struct FileHandle and dropped us.
482 stopread(fh
, waitingdp
);
484 fh
->flags
= (fh
->flags
& ~FHFLG_READPENDING
) | FHFLG_WAITFORCLOSE
;
489 replypkt(dp
, DOSTRUE
);
492 if (!MakeSureWinIsOpen(fh
)) {
493 replypkt2(dp
, DOSFALSE
, ERROR_NO_FREE_STORE
);
496 fh
->breaktask
= dp
->dp_Port
->mp_SigTask
;
501 if (!MakeSureWinIsOpen(fh
)) {
502 replypkt2(dp
, DOSFALSE
, ERROR_NO_FREE_STORE
);
505 fh
->breaktask
= dp
->dp_Port
->mp_SigTask
;
507 answer_write_request(fh
, dp
);
509 case ACTION_SCREEN_MODE
:
511 D(bug("ACTION_SCREEN_MODE %s\n", dp
->dp_Arg1
? "RAW" : "CON"));
512 if (dp
->dp_Arg1
&& !(fh
->flags
& FHFLG_RAW
))
514 /* Switching from CON: mode to RAW: mode */
515 fh
->flags
|= FHFLG_RAW
;
516 fh
->inputstart
= fh
->inputsize
;
517 fh
->inputpos
= fh
->inputsize
;
518 HandlePendingReads(fh
);
522 /* otherwise just copy the flags */
524 fh
->flags
|= FHFLG_RAW
;
526 fh
->flags
&= ~FHFLG_RAW
;
528 replypkt(dp
, DOSTRUE
);
531 case ACTION_CHANGE_SIGNAL
:
533 struct Task
*old
= fh
->breaktask
;
535 fh
->breaktask
= (struct Task
*)dp
->dp_Arg2
;
536 replypkt2(dp
, DOSTRUE
, (SIPTR
)old
);
539 case ACTION_WAIT_CHAR
:
541 if (!MakeSureWinIsOpen(fh
)) {
542 replypkt2(dp
, DOSFALSE
, ERROR_NO_FREE_STORE
);
545 if (fh
->inputsize
> 0)
547 replypkt(dp
, DOSTRUE
);
551 LONG timeout
= dp
->dp_Arg1
;
552 LONG sec
= timeout
/ 1000000;
553 LONG usec
= timeout
% 1000000;
555 fh
->timerreq
->tr_node
.io_Command
= TR_ADDREQUEST
;
556 fh
->timerreq
->tr_time
.tv_secs
= sec
;
557 fh
->timerreq
->tr_time
.tv_micro
= usec
;
558 SendIO((struct IORequest
*)fh
->timerreq
);
564 case ACTION_IS_FILESYSTEM
:
565 replypkt(dp
, DOSFALSE
);
567 case ACTION_DISK_INFO
:
569 /* strange console handler features */
570 struct InfoData
*id
= BADDR(dp
->dp_Arg1
);
571 memset(id
, 0, sizeof(struct InfoData
));
572 id
->id_DiskType
= (fh
->flags
& FHFLG_RAW
) ?
573 AROS_MAKE_ID('R','A','W', 0) : AROS_MAKE_ID('C','O','N', 0);
574 id
->id_VolumeNode
= (BPTR
)fh
->window
;
575 id
->id_InUse
= (IPTR
)fh
->conreadio
;
576 replypkt(dp
, DOSTRUE
);
580 /* Yes, DOSTRUE. Check Guru Book for details. */
581 replypkt2(dp
, DOSTRUE
, ERROR_ACTION_NOT_KNOWN
);
584 bug("[CON] unknown action %d\n", dp
->dp_Type
);
585 replypkt2(dp
, DOSFALSE
, ERROR_ACTION_NOT_KNOWN
);
591 D(bug("[CON] 0x%p closing\n", fh
));
594 D(bug("[CON] Cancelling read requests...\n"));
595 stopread(fh
, waitingdp
);
597 if (fh
->flags
& FHFLG_ASYNCCONSOLEREAD
)
599 D(bug("[CON] Aborting console ioReq 0x%p\n", fh
->conreadio
));
601 AbortIO(ioReq(fh
->conreadio
));
602 WaitIO(ioReq(fh
->conreadio
));
605 D(bug("[CON] Closing handle...\n"));
611 D(bug("[CON] Replying packet 0x%p\n", dp
));
612 replypkt(dp
, DOSFALSE
);
615 D(bug("[CON] 0x%p closed\n", fh
));