2 Copyright © 1995-2014, The AROS Development Team. All rights reserved.
6 #include <proto/exec.h>
7 #include <exec/libraries.h>
8 #include <exec/resident.h>
9 #include <exec/memory.h>
11 #include <exec/errors.h>
12 #include <exec/alerts.h>
13 #include <utility/tagitem.h>
14 #include <dos/exall.h>
15 #include <dos/dosasl.h>
16 #include <intuition/intuition.h>
17 #include <proto/dos.h>
18 #include <proto/intuition.h>
19 #include <devices/conunit.h>
24 #include "con_handler_intern.h"
31 #include <aros/debug.h>
33 static char *BSTR2C(BSTR srcs
)
35 UBYTE
*src
= BADDR(srcs
);
38 dst
= AllocVec(src
[0] + 1, MEMF_ANY
);
41 memcpy(dst
, src
+ 1, src
[0]);
45 static WORD
isdosdevicec(CONST_STRPTR s
)
57 #define ioReq(x) ((struct IORequest *)x)
59 static const struct NewWindow default_nw
=
82 32767, /* MaxHeight */
83 WBENCHSCREEN
/* type */
87 static LONG
MakeConWindow(struct filehandle
*fh
)
91 if (fh
->otherwindow
== NULL
)
93 struct TagItem win_tags
[] =
96 { WA_AutoAdjust
, TRUE
},
97 { WA_PubScreenName
, 0 },
98 { WA_PubScreenFallBack
, TRUE
},
102 win_tags
[2].ti_Data
= (IPTR
) fh
->screenname
;
103 D(bug("[contask] Opening window on screen %s, IntuitionBase = 0x%p\n", fh
->screenname
, IntuitionBase
));
105 /* Autoadjust doesn't enforce the window's width and height to be larger than
106 minwidth and minheight, so we set it here to avoid crashes in devs/console
107 if a user does e.g. dir >con:0/0/0/0
109 fh
->nw
.Width
= fh
->nw
.Width
> fh
->nw
.MinWidth
? fh
->nw
.Width
: -1;
110 fh
->nw
.Height
= (fh
->flags
& FHFLG_BOOTCON
&& fh
->nw
.Height
== -1) ||
111 fh
->nw
.Height
> fh
->nw
.MinHeight
? fh
->nw
.Height
: fh
->nw
.MinHeight
;
113 fh
->window
= OpenWindowTagList(&fh
->nw
, (struct TagItem
*) win_tags
);
117 D(bug("[contask] Using window %p\n", fh
->otherwindow
));
118 fh
->window
= fh
->otherwindow
;
123 D(bug("contask: window opened\n"));
124 fh
->conreadio
->io_Data
= (APTR
) fh
->window
;
125 fh
->conreadio
->io_Length
= sizeof(struct Window
);
127 if (0 == OpenDevice("console.device", CONU_SNIPMAP
, ioReq(fh
->conreadio
), 0))
129 const UBYTE lf_on
[] =
130 { 0x9B, 0x32, 0x30, 0x68 }; /* Set linefeed mode */
132 D(bug("contask: device opened\n"));
134 fh
->flags
|= FHFLG_CONSOLEDEVICEOPEN
;
136 fh
->conwriteio
= *fh
->conreadio
;
137 fh
->conwriteio
.io_Message
.mn_ReplyPort
= fh
->conwritemp
;
139 /* Turn the console into LF+CR mode so that both
140 linefeed and carriage return is done on
142 fh
->conwriteio
.io_Command
= CMD_WRITE
;
143 fh
->conwriteio
.io_Data
= (APTR
) lf_on
;
144 fh
->conwriteio
.io_Length
= 4;
146 DoIO(ioReq(&fh
->conwriteio
));
148 } /* if (0 == OpenDevice("console.device", CONU_STANDARD, ioReq(fh->conreadio), 0)) */
151 err
= ERROR_INVALID_RESIDENT_LIBRARY
;
154 CloseWindow(fh
->window
);
156 } /* if (fh->window) */
159 D(bug("[contask] Failed to open a window\n"));
160 err
= ERROR_NO_FREE_STORE
;
166 static BOOL
MakeSureWinIsOpen(struct filehandle
*fh
)
170 return MakeConWindow(fh
) == 0;
173 static void close_con(struct filehandle
*fh
)
177 D(bug("[CON] Deleting timer request 0x%p\n", fh
->timerreq
));
180 CloseDevice((struct IORequest
*) fh
->timerreq
);
181 DeleteIORequest((struct IORequest
*) fh
->timerreq
);
184 D(bug("[CON] Deleting timer port 0x%p\n", fh
->timermp
));
185 DeleteMsgPort(fh
->timermp
);
187 if (fh
->flags
& FHFLG_CONSOLEDEVICEOPEN
)
189 D(bug("[CON] Closing console.device...\n"));
190 CloseDevice((struct IORequest
*) fh
->conreadio
);
193 D(bug("[CON] Closing window 0x%p\n", fh
->window
));
195 CloseWindow(fh
->window
);
197 D(bug("[CON] Delete console.device IORequest 0x%p\n", fh
->conreadio
));
198 DeleteIORequest(ioReq(fh
->conreadio
));
200 D(bug("[CON] Delete console.device MsgPort 0x%p\n", fh
->conreadmp
));
201 FreeVec(fh
->conreadmp
);
204 FreeVec(fh
->screenname
);
206 FreeVec(fh
->wintitle
);
208 FreeMem(fh
->pastebuffer
, PASTEBUFSIZE
);
210 CloseLibrary((struct Library
*) fh
->intuibase
);
211 CloseLibrary((struct Library
*) fh
->dosbase
);
213 /* These libraries are opened only if completion was used */
215 CloseLibrary((struct Library
*) fh
->gfxbase
);
217 CloseLibrary(fh
->gtbase
);
222 static struct filehandle
*open_con(struct DosPacket
*dp
, LONG
*perr
)
225 struct filehandle
*fh
;
226 struct DeviceNode
*dn
;
230 dn
= BADDR(dp
->dp_Arg3
);
231 *perr
= ERROR_NO_FREE_STORE
;
232 fh
= AllocVec(sizeof(struct filehandle
), MEMF_PUBLIC
| MEMF_CLEAR
);
236 fh
->intuibase
= (APTR
) OpenLibrary("intuition.library", 0);
237 fh
->dosbase
= (APTR
) OpenLibrary("dos.library", 0);
238 fh
->utilbase
= (APTR
) OpenLibrary("utility.library", 0);
240 fh
->inputbase
= (struct Device
*) FindName(&SysBase
->DeviceList
, "input.device");
243 if (!fh
->intuibase
|| !fh
->dosbase
|| !fh
->utilbase
|| !fh
->inputbase
)
245 CloseLibrary((APTR
) fh
->utilbase
);
246 CloseLibrary((APTR
) fh
->dosbase
);
247 CloseLibrary((APTR
) fh
->intuibase
);
252 fh
->timermp
= CreateMsgPort();
253 fh
->timerreq
= (struct timerequest
*) CreateIORequest(fh
->timermp
, sizeof(struct timerequest
));
254 OpenDevice(TIMERNAME
, UNIT_MICROHZ
, (struct IORequest
*) fh
->timerreq
, 0);
257 filename
= BSTR2C((BSTR
) dp
->dp_Arg1
);
259 i
= isdosdevicec(fn
);
263 fh
->contask
= FindTask(0);
265 NEWLIST(&fh
->pendingReads
);
267 /* Create msgport for console.device communication */
268 fh
->conreadmp
= AllocVec(sizeof(struct MsgPort
) * 2, MEMF_PUBLIC
| MEMF_CLEAR
);
272 fh
->conreadmp
->mp_Node
.ln_Type
= NT_MSGPORT
;
273 fh
->conreadmp
->mp_Flags
= PA_SIGNAL
;
274 fh
->conreadmp
->mp_SigBit
= AllocSignal(-1);
275 fh
->conreadmp
->mp_SigTask
= fh
->contask
;
276 NEWLIST(&fh
->conreadmp
->mp_MsgList
);
278 fh
->conwritemp
= fh
->conreadmp
+ 1;
280 fh
->conwritemp
->mp_Node
.ln_Type
= NT_MSGPORT
;
281 fh
->conwritemp
->mp_Flags
= PA_SIGNAL
;
282 fh
->conwritemp
->mp_SigBit
= AllocSignal(-1);
283 fh
->conwritemp
->mp_SigTask
= fh
->contask
;
284 NEWLIST(&fh
->conwritemp
->mp_MsgList
);
286 fh
->conreadio
= (struct IOStdReq
*) CreateIORequest(fh
->conreadmp
, sizeof(struct IOStdReq
));
289 D(bug("contask: conreadio created, parms '%s'\n", fn
));
293 if (parse_filename(fh
, fn
, &fh
->nw
))
295 if (!(fh
->flags
& FHFLG_AUTO
))
297 err
= MakeConWindow(fh
);
307 err
= ERROR_BAD_STREAM_NAME
;
311 DeleteIORequest(ioReq(fh
->conreadio
));
314 } /* if (fh->conreadio) */
317 err
= ERROR_NO_FREE_STORE
;
320 } /* if (fh->conreadmp) */
323 err
= ERROR_NO_FREE_STORE
;
327 fh
->flags
|= FHFLG_RAW
;
337 static void startread(struct filehandle
*fh
)
339 if (fh
->flags
& FHFLG_ASYNCCONSOLEREAD
)
341 fh
->conreadio
->io_Command
= CMD_READ
;
342 fh
->conreadio
->io_Data
= fh
->consolebuffer
;
343 fh
->conreadio
->io_Length
= CONSOLEBUFFER_SIZE
;
344 SendIO((struct IORequest
*) fh
->conreadio
);
345 fh
->flags
|= FHFLG_ASYNCCONSOLEREAD
;
348 static void stopwait(struct filehandle
*fh
, struct DosPacket
*waitingdp
, ULONG result
)
352 AbortIO((struct IORequest
*) fh
->timerreq
);
353 WaitIO((struct IORequest
*) fh
->timerreq
);
354 replypkt(waitingdp
, result
);
358 static void stopread(struct filehandle
*fh
, struct DosPacket
*waitingdp
)
360 struct Message
*msg
, *next_msg
;
362 stopwait(fh
, waitingdp
, DOSFALSE
);
364 ForeachNodeSafe(&fh
->pendingReads
, msg
, next_msg
)
366 struct DosPacket
*dpr
;
368 Remove((struct Node
*) msg
);
369 dpr
= (struct DosPacket
*) msg
->mn_Node
.ln_Name
;
370 replypkt(dpr
, DOSFALSE
);
374 LONG
CONMain(struct ExecBase
*SysBase
)
377 struct DosPacket
*dp
;
379 struct FileHandle
*dosfh
;
381 struct filehandle
*fh
;
383 struct DosPacket
*waitingdp
= NULL
;
385 D(bug("[CON] started\n"));
386 mp
= &((struct Process
*) FindTask(NULL
))->pr_MsgPort
;
388 dp
= (struct DosPacket
*) GetMsg(mp
)->mn_Node
.ln_Name
;
389 D(bug("[CON] startup message received. port=0x%p path='%b'\n", mp
, dp
->dp_Arg1
));
391 fh
= open_con(dp
, &error
);
394 D(bug("[CON] init failed\n"));
397 D(bug("[CON] 0x%p open\n", fh
));
398 replypkt(dp
, DOSTRUE
);
402 ULONG conreadmask
= 1L << fh
->conreadmp
->mp_SigBit
;
403 ULONG timermask
= 1L << fh
->timermp
->mp_SigBit
;
404 ULONG packetmask
= 1L << mp
->mp_SigBit
;
407 sigs
= Wait(packetmask
| conreadmask
| timermask
);
409 if (sigs
& timermask
)
413 replypkt(waitingdp
, DOSFALSE
);
418 if (sigs
& conreadmask
)
420 GetMsg(fh
->conreadmp
);
421 fh
->flags
&= ~FHFLG_ASYNCCONSOLEREAD
;
424 stopwait(fh
, waitingdp
, DOSTRUE
);
427 D(bug("IO_READ %d\n", fh
->conreadio
->io_Actual
));
428 fh
->conbuffersize
= fh
->conreadio
->io_Actual
;
429 fh
->conbufferpos
= 0;
430 /* terminate with 0 char */
431 fh
->consolebuffer
[fh
->conbuffersize
] = '\0';
432 if (fh
->flags
& FHFLG_RAW
)
436 for (inp
= 0; (inp
< fh
->conbuffersize
) && (fh
->inputpos
< INPUTBUFFER_SIZE
);)
438 fh
->inputbuffer
[fh
->inputpos
++] = fh
->consolebuffer
[inp
++];
440 fh
->inputsize
= fh
->inputstart
= fh
->inputpos
;
441 HandlePendingReads(fh
);
442 } /* if (fh->flags & FHFLG_RAW) */
446 if (process_input(fh
))
449 * process_input() returns TRUE when EOF was received after the WAIT console
450 * has been closed by the owner.
455 } /* if (fh->flags & FHFLG_RAW) else ... */
457 if (fh
->flags
& FHFLG_CONSOLEDEVICEOPEN
) /* device could have been closed */
461 while ((mn
= GetMsg(mp
)))
463 dp
= (struct DosPacket
*) mn
->mn_Node
.ln_Name
;
466 bug("[CON 0x%p] packet 0x%p:%d 0x%p,0x%p,0x%p\n", fh
, dp
, dp
->dp_Type
, dp
->dp_Arg1
, dp
->dp_Arg2
,
471 case ACTION_FH_FROM_LOCK
:
472 fl
= BADDR(dp
->dp_Arg2
);
473 if (fl
->fl_Task
!= mp
|| fl
->fl_Key
!= (IPTR
) fh
)
475 replypkt2(dp
, DOSFALSE
, ERROR_OBJECT_NOT_FOUND
);
479 FreeMem(fl
, sizeof(*fl
));
481 case ACTION_FINDINPUT
:
482 case ACTION_FINDOUTPUT
:
483 case ACTION_FINDUPDATE
:
484 dosfh
= BADDR(dp
->dp_Arg1
);
485 dosfh
->fh_Interactive
= DOSTRUE
;
486 dosfh
->fh_Arg1
= (SIPTR
) fh
;
488 fh
->breaktask
= dp
->dp_Port
->mp_SigTask
;
489 D(bug("[CON] Find fh=%x. Usecount=%d\n", dosfh
, fh
->usecount
));
490 replypkt(dp
, DOSTRUE
);
492 case ACTION_COPY_DIR_FH
:
493 fl
= AllocMem(sizeof(*fl
), MEMF_CLEAR
| MEMF_PUBLIC
);
496 replypkt2(dp
, (SIPTR
) BNULL
, ERROR_NO_FREE_STORE
);
502 fl
->fl_Access
= ACCESS_READ
;
503 fl
->fl_Key
= (IPTR
) fh
;
504 replypkt(dp
, (SIPTR
) MKBADDR(fl
));
507 case ACTION_FREE_LOCK
:
508 fl
= BADDR(dp
->dp_Arg1
);
509 fh
= (struct filehandle
*)fl
->fl_Key
;
511 FreeMem(fl
, sizeof(*fl
));
514 replypkt(dp
, DOSTRUE
);
518 D(bug("[CON] usecount=%d\n", fh
->usecount
));
519 if (fh
->usecount
<= 0)
521 if (fh
->flags
& FHFLG_WAIT
)
523 D(bug("[CON] Delayed close, waiting...\n"));
526 * Bounce all pending read and waits (the same as we do when exiting).
527 * However the process is still around, waiting for EOF input.
528 * Our user has just closed his struct FileHandle and dropped us.
530 stopread(fh
, waitingdp
);
532 fh
->flags
= (fh
->flags
& ~FHFLG_READPENDING
) | FHFLG_WAITFORCLOSE
;
537 replypkt(dp
, DOSTRUE
);
540 if (!MakeSureWinIsOpen(fh
))
542 replypkt2(dp
, DOSFALSE
, ERROR_NO_FREE_STORE
);
545 fh
->breaktask
= dp
->dp_Port
->mp_SigTask
;
550 if (!MakeSureWinIsOpen(fh
))
552 replypkt2(dp
, DOSFALSE
, ERROR_NO_FREE_STORE
);
555 fh
->breaktask
= dp
->dp_Port
->mp_SigTask
;
557 answer_write_request(fh
, dp
);
559 case ACTION_SCREEN_MODE
:
561 D(bug("ACTION_SCREEN_MODE %s\n", dp
->dp_Arg1
? "RAW" : "CON"));
562 if (dp
->dp_Arg1
&& !(fh
->flags
& FHFLG_RAW
))
564 /* Switching from CON: mode to RAW: mode */
565 fh
->flags
|= FHFLG_RAW
;
566 fh
->inputstart
= fh
->inputsize
;
567 fh
->inputpos
= fh
->inputsize
;
568 HandlePendingReads(fh
);
572 /* otherwise just copy the flags */
574 fh
->flags
|= FHFLG_RAW
;
576 fh
->flags
&= ~FHFLG_RAW
;
578 replypkt(dp
, DOSTRUE
);
581 case ACTION_CHANGE_SIGNAL
:
583 struct Task
*old
= fh
->breaktask
;
585 fh
->breaktask
= (struct Task
*) dp
->dp_Arg2
;
586 replypkt2(dp
, DOSTRUE
, (SIPTR
) old
);
589 case ACTION_WAIT_CHAR
:
591 if (!MakeSureWinIsOpen(fh
))
593 replypkt2(dp
, DOSFALSE
, ERROR_NO_FREE_STORE
);
596 if (fh
->inputsize
> 0)
598 replypkt(dp
, DOSTRUE
);
602 LONG timeout
= dp
->dp_Arg1
;
605 LONG sec
= timeout
/ 1000000;
606 LONG usec
= timeout
% 1000000;
608 fh
->timerreq
->tr_node
.io_Command
= TR_ADDREQUEST
;
609 fh
->timerreq
->tr_time
.tv_secs
= sec
;
610 fh
->timerreq
->tr_time
.tv_micro
= usec
;
611 SendIO((struct IORequest
*) fh
->timerreq
);
618 case ACTION_IS_FILESYSTEM
:
619 replypkt(dp
, DOSFALSE
);
621 case ACTION_DISK_INFO
:
623 /* strange console handler features */
624 struct InfoData
*id
= BADDR(dp
->dp_Arg1
);
625 memset(id
, 0, sizeof(struct InfoData
));
627 (fh
->flags
& FHFLG_RAW
) ? AROS_MAKE_ID('R', 'A', 'W', 0) : AROS_MAKE_ID('C', 'O', 'N', 0);
628 id
->id_VolumeNode
= (BPTR
) fh
->window
;
629 id
->id_InUse
= (IPTR
) fh
->conreadio
;
630 replypkt(dp
, DOSTRUE
);
634 /* Yes, DOSTRUE. Check Guru Book for details. */
635 replypkt2(dp
, DOSTRUE
, ERROR_ACTION_NOT_KNOWN
);
638 bug("[CON] unknown action %d\n", dp
->dp_Type
);
639 replypkt2(dp
, DOSFALSE
, ERROR_ACTION_NOT_KNOWN
);
645 D(bug("[CON] 0x%p closing\n", fh
));
648 D(bug("[CON] Cancelling read requests...\n"));
649 stopread(fh
, waitingdp
);
651 if (fh
->flags
& FHFLG_ASYNCCONSOLEREAD
)
653 D(bug("[CON] Aborting console ioReq 0x%p\n", fh
->conreadio
));
655 AbortIO(ioReq(fh
->conreadio
));
656 WaitIO(ioReq(fh
->conreadio
));
659 D(bug("[CON] Closing handle...\n"));
665 D(bug("[CON] Replying packet 0x%p\n", dp
));
666 replypkt(dp
, DOSFALSE
);
669 D(bug("[CON] 0x%p closed\n", fh
));