1 #include <proto/exec.h>
2 #include <exec/libraries.h>
3 #include <exec/resident.h>
4 #include <exec/memory.h>
6 #include <exec/errors.h>
7 #include <exec/alerts.h>
8 #include <utility/tagitem.h>
10 #include <dos/dosasl.h>
11 #include <intuition/intuition.h>
12 #include <proto/dos.h>
13 #include <proto/intuition.h>
14 #include <devices/conunit.h>
19 #include "con_handler_intern.h"
26 #include <aros/debug.h>
28 static char *BSTR2C(BSTR srcs
)
30 UBYTE
*src
= BADDR(srcs
);
33 dst
= AllocVec(src
[0] + 1, MEMF_ANY
);
36 memcpy(dst
, src
+ 1, src
[0]);
40 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
)
88 struct TagItem win_tags
[] =
91 { WA_AutoAdjust
, TRUE
},
92 { WA_PubScreenName
, 0 },
93 { WA_PubScreenFallBack
, TRUE
},
97 win_tags
[2].ti_Data
= (IPTR
) fh
->screenname
;
98 D(bug("[contask] Opening window on screen %s, IntuitionBase = 0x%p\n", fh
->screenname
, IntuitionBase
));
100 /* Autoadjust doesn't enforce the window's width and height to be larger than
101 minwidth and minheight, so we set it here to avoid crashes in devs/console
102 if a user does e.g. dir >con:0/0/0/0
104 fh
->nw
.Width
= fh
->nw
.Width
> fh
->nw
.MinWidth
? fh
->nw
.Width
: -1;
105 fh
->nw
.Height
= fh
->nw
.Height
== -1 || fh
->nw
.Height
> fh
->nw
.MinHeight
? fh
->nw
.Height
: fh
->nw
.MinHeight
;
107 fh
->window
= OpenWindowTagList(&fh
->nw
, (struct TagItem
*) win_tags
);
111 D(bug("[contask] Using window %p\n", fh
->otherwindow
));
112 fh
->window
= fh
->otherwindow
;
117 D(bug("contask: window opened\n"));
118 fh
->conreadio
->io_Data
= (APTR
) fh
->window
;
119 fh
->conreadio
->io_Length
= sizeof(struct Window
);
121 if (0 == OpenDevice("console.device", CONU_SNIPMAP
, ioReq(fh
->conreadio
), 0))
123 const UBYTE lf_on
[] =
124 { 0x9B, 0x32, 0x30, 0x68 }; /* Set linefeed mode */
126 D(bug("contask: device opened\n"));
128 fh
->flags
|= FHFLG_CONSOLEDEVICEOPEN
;
130 fh
->conwriteio
= *fh
->conreadio
;
131 fh
->conwriteio
.io_Message
.mn_ReplyPort
= fh
->conwritemp
;
133 /* Turn the console into LF+CR mode so that both
134 linefeed and carriage return is done on
136 fh
->conwriteio
.io_Command
= CMD_WRITE
;
137 fh
->conwriteio
.io_Data
= (APTR
) lf_on
;
138 fh
->conwriteio
.io_Length
= 4;
140 DoIO(ioReq(&fh
->conwriteio
));
142 } /* if (0 == OpenDevice("console.device", CONU_STANDARD, ioReq(fh->conreadio), 0)) */
145 err
= ERROR_INVALID_RESIDENT_LIBRARY
;
148 CloseWindow(fh
->window
);
150 } /* if (fh->window) */
153 D(bug("[contask] Failed to open a window\n"));
154 err
= ERROR_NO_FREE_STORE
;
160 static BOOL
MakeSureWinIsOpen(struct filehandle
*fh
)
164 return MakeConWindow(fh
) == 0;
167 static void close_con(struct filehandle
*fh
)
171 D(bug("[CON] Deleting timer request 0x%p\n", fh
->timerreq
));
174 CloseDevice((struct IORequest
*) fh
->timerreq
);
175 DeleteIORequest((struct IORequest
*) fh
->timerreq
);
178 D(bug("[CON] Deleting timer port 0x%p\n", fh
->timermp
));
179 DeleteMsgPort(fh
->timermp
);
181 if (fh
->flags
& FHFLG_CONSOLEDEVICEOPEN
)
183 D(bug("[CON] Closing console.device...\n"));
184 CloseDevice((struct IORequest
*) fh
->conreadio
);
187 D(bug("[CON] Closing window 0x%p\n", fh
->window
));
189 CloseWindow(fh
->window
);
191 D(bug("[CON] Delete console.device IORequest 0x%p\n", fh
->conreadio
));
192 DeleteIORequest(ioReq(fh
->conreadio
));
194 D(bug("[CON] Delete console.device MsgPort 0x%p\n", fh
->conreadmp
));
195 FreeVec(fh
->conreadmp
);
198 FreeVec(fh
->screenname
);
200 FreeVec(fh
->wintitle
);
202 FreeMem(fh
->pastebuffer
, PASTEBUFSIZE
);
204 CloseLibrary((struct Library
*) fh
->intuibase
);
205 CloseLibrary((struct Library
*) fh
->dosbase
);
207 /* These libraries are opened only if completion was used */
209 CloseLibrary((struct Library
*) fh
->gfxbase
);
211 CloseLibrary(fh
->gtbase
);
216 static struct filehandle
*open_con(struct DosPacket
*dp
, LONG
*perr
)
219 struct filehandle
*fh
;
220 struct DeviceNode
*dn
;
224 dn
= BADDR(dp
->dp_Arg3
);
225 *perr
= ERROR_NO_FREE_STORE
;
226 fh
= AllocVec(sizeof(struct filehandle
), MEMF_PUBLIC
| MEMF_CLEAR
);
230 fh
->intuibase
= (APTR
) OpenLibrary("intuition.library", 0);
231 fh
->dosbase
= (APTR
) OpenLibrary("dos.library", 0);
232 fh
->utilbase
= (APTR
) OpenLibrary("utility.library", 0);
234 fh
->inputbase
= (struct Device
*) FindName(&SysBase
->DeviceList
, "input.device");
237 if (!fh
->intuibase
|| !fh
->dosbase
|| !fh
->utilbase
|| !fh
->inputbase
)
239 CloseLibrary((APTR
) fh
->utilbase
);
240 CloseLibrary((APTR
) fh
->dosbase
);
241 CloseLibrary((APTR
) fh
->intuibase
);
246 fh
->timermp
= CreateMsgPort();
247 fh
->timerreq
= (struct timerequest
*) CreateIORequest(fh
->timermp
, sizeof(struct timerequest
));
248 OpenDevice(TIMERNAME
, UNIT_MICROHZ
, (struct IORequest
*) fh
->timerreq
, 0);
251 filename
= BSTR2C((BSTR
) dp
->dp_Arg1
);
253 i
= isdosdevicec(fn
);
257 fh
->contask
= FindTask(0);
259 NEWLIST(&fh
->pendingReads
);
261 /* Create msgport for console.device communication */
262 fh
->conreadmp
= AllocVec(sizeof(struct MsgPort
) * 2, MEMF_PUBLIC
| MEMF_CLEAR
);
266 fh
->conreadmp
->mp_Node
.ln_Type
= NT_MSGPORT
;
267 fh
->conreadmp
->mp_Flags
= PA_SIGNAL
;
268 fh
->conreadmp
->mp_SigBit
= AllocSignal(-1);
269 fh
->conreadmp
->mp_SigTask
= fh
->contask
;
270 NEWLIST(&fh
->conreadmp
->mp_MsgList
);
272 fh
->conwritemp
= fh
->conreadmp
+ 1;
274 fh
->conwritemp
->mp_Node
.ln_Type
= NT_MSGPORT
;
275 fh
->conwritemp
->mp_Flags
= PA_SIGNAL
;
276 fh
->conwritemp
->mp_SigBit
= AllocSignal(-1);
277 fh
->conwritemp
->mp_SigTask
= fh
->contask
;
278 NEWLIST(&fh
->conwritemp
->mp_MsgList
);
280 fh
->conreadio
= (struct IOStdReq
*) CreateIORequest(fh
->conreadmp
, sizeof(struct IOStdReq
));
283 D(bug("contask: conreadio created, parms '%s'\n", fn
));
287 if (parse_filename(fh
, fn
, &fh
->nw
))
289 if (!(fh
->flags
& FHFLG_AUTO
))
291 err
= MakeConWindow(fh
);
301 err
= ERROR_BAD_STREAM_NAME
;
305 DeleteIORequest(ioReq(fh
->conreadio
));
308 } /* if (fh->conreadio) */
311 err
= ERROR_NO_FREE_STORE
;
314 } /* if (fh->conreadmp) */
317 err
= ERROR_NO_FREE_STORE
;
321 fh
->flags
|= FHFLG_RAW
;
331 static void startread(struct filehandle
*fh
)
333 if (fh
->flags
& FHFLG_ASYNCCONSOLEREAD
)
335 fh
->conreadio
->io_Command
= CMD_READ
;
336 fh
->conreadio
->io_Data
= fh
->consolebuffer
;
337 fh
->conreadio
->io_Length
= CONSOLEBUFFER_SIZE
;
338 SendIO((struct IORequest
*) fh
->conreadio
);
339 fh
->flags
|= FHFLG_ASYNCCONSOLEREAD
;
342 static void stopwait(struct filehandle
*fh
, struct DosPacket
*waitingdp
, ULONG result
)
346 AbortIO((struct IORequest
*) fh
->timerreq
);
347 WaitIO((struct IORequest
*) fh
->timerreq
);
348 replypkt(waitingdp
, result
);
352 static void stopread(struct filehandle
*fh
, struct DosPacket
*waitingdp
)
354 struct Message
*msg
, *next_msg
;
356 stopwait(fh
, waitingdp
, DOSFALSE
);
358 ForeachNodeSafe(&fh
->pendingReads
, msg
, next_msg
)
360 struct DosPacket
*dpr
;
362 Remove((struct Node
*) msg
);
363 dpr
= (struct DosPacket
*) msg
->mn_Node
.ln_Name
;
364 replypkt(dpr
, DOSFALSE
);
368 LONG
CONMain(struct ExecBase
*SysBase
)
371 struct DosPacket
*dp
;
373 struct FileHandle
*dosfh
;
375 struct filehandle
*fh
;
377 struct DosPacket
*waitingdp
= NULL
;
379 D(bug("[CON] started\n"));
380 mp
= &((struct Process
*) FindTask(NULL
))->pr_MsgPort
;
382 dp
= (struct DosPacket
*) GetMsg(mp
)->mn_Node
.ln_Name
;
383 D(bug("[CON] startup message received. port=0x%p path='%b'\n", mp
, dp
->dp_Arg1
));
385 fh
= open_con(dp
, &error
);
388 D(bug("[CON] init failed\n"));
391 D(bug("[CON] 0x%p open\n", fh
));
392 replypkt(dp
, DOSTRUE
);
396 ULONG conreadmask
= 1L << fh
->conreadmp
->mp_SigBit
;
397 ULONG timermask
= 1L << fh
->timermp
->mp_SigBit
;
398 ULONG packetmask
= 1L << mp
->mp_SigBit
;
401 sigs
= Wait(packetmask
| conreadmask
| timermask
);
403 if (sigs
& timermask
)
407 replypkt(waitingdp
, DOSFALSE
);
412 if (sigs
& conreadmask
)
414 GetMsg(fh
->conreadmp
);
415 fh
->flags
&= ~FHFLG_ASYNCCONSOLEREAD
;
418 stopwait(fh
, waitingdp
, DOSTRUE
);
421 D(bug("IO_READ %d\n", fh
->conreadio
->io_Actual
));
422 fh
->conbuffersize
= fh
->conreadio
->io_Actual
;
423 fh
->conbufferpos
= 0;
424 /* terminate with 0 char */
425 fh
->consolebuffer
[fh
->conbuffersize
] = '\0';
426 if (fh
->flags
& FHFLG_RAW
)
430 for (inp
= 0; (inp
< fh
->conbuffersize
) && (fh
->inputpos
< INPUTBUFFER_SIZE
);)
432 fh
->inputbuffer
[fh
->inputpos
++] = fh
->consolebuffer
[inp
++];
434 fh
->inputsize
= fh
->inputstart
= fh
->inputpos
;
435 HandlePendingReads(fh
);
436 } /* if (fh->flags & FHFLG_RAW) */
440 if (process_input(fh
))
443 * process_input() returns TRUE when EOF was received after the WAIT console
444 * has been closed by the owner.
449 } /* if (fh->flags & FHFLG_RAW) else ... */
453 while ((mn
= GetMsg(mp
)))
455 dp
= (struct DosPacket
*) mn
->mn_Node
.ln_Name
;
458 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
,
463 case ACTION_FH_FROM_LOCK
:
464 fl
= BADDR(dp
->dp_Arg2
);
465 if (fl
->fl_Task
!= mp
|| fl
->fl_Key
!= (IPTR
) fh
)
467 replypkt2(dp
, DOSFALSE
, ERROR_OBJECT_NOT_FOUND
);
471 FreeMem(fl
, sizeof(*fl
));
473 case ACTION_FINDINPUT
:
474 case ACTION_FINDOUTPUT
:
475 case ACTION_FINDUPDATE
:
476 dosfh
= BADDR(dp
->dp_Arg1
);
477 dosfh
->fh_Interactive
= DOSTRUE
;
478 dosfh
->fh_Arg1
= (SIPTR
) fh
;
480 fh
->breaktask
= dp
->dp_Port
->mp_SigTask
;
481 D(bug("[CON] Find fh=%x. Usecount=%d\n", dosfh
, fh
->usecount
));
482 replypkt(dp
, DOSTRUE
);
484 case ACTION_COPY_DIR_FH
:
485 fl
= AllocMem(sizeof(*fl
), MEMF_CLEAR
| MEMF_PUBLIC
);
488 replypkt2(dp
, (SIPTR
) BNULL
, ERROR_NO_FREE_STORE
);
494 fl
->fl_Key
= (IPTR
) fh
;
495 replypkt(dp
, (SIPTR
) MKBADDR(fl
));
500 D(bug("[CON] usecount=%d\n", fh
->usecount
));
501 if (fh
->usecount
<= 0)
503 if (fh
->flags
& FHFLG_WAIT
)
505 D(bug("[CON] Delayed close, waiting...\n"));
508 * Bounce all pending read and waits (the same as we do when exiting).
509 * However the process is still around, waiting for EOF input.
510 * Our user has just closed his struct FileHandle and dropped us.
512 stopread(fh
, waitingdp
);
514 fh
->flags
= (fh
->flags
& ~FHFLG_READPENDING
) | FHFLG_WAITFORCLOSE
;
519 replypkt(dp
, DOSTRUE
);
522 if (!MakeSureWinIsOpen(fh
))
524 replypkt2(dp
, DOSFALSE
, ERROR_NO_FREE_STORE
);
527 fh
->breaktask
= dp
->dp_Port
->mp_SigTask
;
532 if (!MakeSureWinIsOpen(fh
))
534 replypkt2(dp
, DOSFALSE
, ERROR_NO_FREE_STORE
);
537 fh
->breaktask
= dp
->dp_Port
->mp_SigTask
;
539 answer_write_request(fh
, dp
);
541 case ACTION_SCREEN_MODE
:
543 D(bug("ACTION_SCREEN_MODE %s\n", dp
->dp_Arg1
? "RAW" : "CON"));
544 if (dp
->dp_Arg1
&& !(fh
->flags
& FHFLG_RAW
))
546 /* Switching from CON: mode to RAW: mode */
547 fh
->flags
|= FHFLG_RAW
;
548 fh
->inputstart
= fh
->inputsize
;
549 fh
->inputpos
= fh
->inputsize
;
550 HandlePendingReads(fh
);
554 /* otherwise just copy the flags */
556 fh
->flags
|= FHFLG_RAW
;
558 fh
->flags
&= ~FHFLG_RAW
;
560 replypkt(dp
, DOSTRUE
);
563 case ACTION_CHANGE_SIGNAL
:
565 struct Task
*old
= fh
->breaktask
;
567 fh
->breaktask
= (struct Task
*) dp
->dp_Arg2
;
568 replypkt2(dp
, DOSTRUE
, (SIPTR
) old
);
571 case ACTION_WAIT_CHAR
:
573 if (!MakeSureWinIsOpen(fh
))
575 replypkt2(dp
, DOSFALSE
, ERROR_NO_FREE_STORE
);
578 if (fh
->inputsize
> 0)
580 replypkt(dp
, DOSTRUE
);
584 LONG timeout
= dp
->dp_Arg1
;
585 LONG sec
= timeout
/ 1000000;
586 LONG usec
= timeout
% 1000000;
588 fh
->timerreq
->tr_node
.io_Command
= TR_ADDREQUEST
;
589 fh
->timerreq
->tr_time
.tv_secs
= sec
;
590 fh
->timerreq
->tr_time
.tv_micro
= usec
;
591 SendIO((struct IORequest
*) fh
->timerreq
);
597 case ACTION_IS_FILESYSTEM
:
598 replypkt(dp
, DOSFALSE
);
600 case ACTION_DISK_INFO
:
602 /* strange console handler features */
603 struct InfoData
*id
= BADDR(dp
->dp_Arg1
);
604 memset(id
, 0, sizeof(struct InfoData
));
606 (fh
->flags
& FHFLG_RAW
) ? AROS_MAKE_ID('R', 'A', 'W', 0) : AROS_MAKE_ID('C', 'O', 'N', 0);
607 id
->id_VolumeNode
= (BPTR
) fh
->window
;
608 id
->id_InUse
= (IPTR
) fh
->conreadio
;
609 replypkt(dp
, DOSTRUE
);
613 /* Yes, DOSTRUE. Check Guru Book for details. */
614 replypkt2(dp
, DOSTRUE
, ERROR_ACTION_NOT_KNOWN
);
617 bug("[CON] unknown action %d\n", dp
->dp_Type
);
618 replypkt2(dp
, DOSFALSE
, ERROR_ACTION_NOT_KNOWN
);
624 D(bug("[CON] 0x%p closing\n", fh
));
627 D(bug("[CON] Cancelling read requests...\n"));
628 stopread(fh
, waitingdp
);
630 if (fh
->flags
& FHFLG_ASYNCCONSOLEREAD
)
632 D(bug("[CON] Aborting console ioReq 0x%p\n", fh
->conreadio
));
634 AbortIO(ioReq(fh
->conreadio
));
635 WaitIO(ioReq(fh
->conreadio
));
638 D(bug("[CON] Closing handle...\n"));
644 D(bug("[CON] Replying packet 0x%p\n", dp
));
645 replypkt(dp
, DOSFALSE
);
648 D(bug("[CON] 0x%p closed\n", fh
));