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/filesystem.h>
11 #include <dos/exall.h>
12 #include <dos/dosasl.h>
13 #include <intuition/intuition.h>
14 #include <proto/dos.h>
15 #include <proto/intuition.h>
16 #include <devices/conunit.h>
21 #include "con_handler_intern.h"
28 #include <aros/debug.h>
30 static char *BSTR2C(BSTR srcs
)
32 UBYTE
*src
= BADDR(srcs
);
35 dst
= AllocVec(src
[0] + 1, MEMF_ANY
);
38 memcpy (dst
, src
+ 1, src
[0]);
42 static WORD
isdosdevicec(CONST_STRPTR s
)
53 #define ioReq(x) ((struct IORequest *)x)
55 static const struct NewWindow default_nw
=
78 32767, /* MaxHeight */
79 WBENCHSCREEN
/* type */
83 static LONG
MakeConWindow(struct filehandle
*fh
)
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
);
102 D(bug("contask: window opened\n"));
103 fh
->conreadio
->io_Data
= (APTR
)fh
->window
;
104 fh
->conreadio
->io_Length
= sizeof (struct Window
);
106 if (0 == OpenDevice("console.device", CONU_SNIPMAP
, ioReq(fh
->conreadio
), 0))
108 const UBYTE lf_on
[] = {0x9B, 0x32, 0x30, 0x68 }; /* Set linefeed mode */
110 D(bug("contask: device opened\n"));
112 fh
->flags
|= FHFLG_CONSOLEDEVICEOPEN
;
114 fh
->conwriteio
= *fh
->conreadio
;
115 fh
->conwriteio
.io_Message
.mn_ReplyPort
= fh
->conwritemp
;
117 /* Turn the console into LF+CR mode so that both
118 linefeed and carriage return is done on
120 fh
->conwriteio
.io_Command
= CMD_WRITE
;
121 fh
->conwriteio
.io_Data
= (APTR
)lf_on
;
122 fh
->conwriteio
.io_Length
= 4;
124 DoIO(ioReq(&fh
->conwriteio
));
126 } /* if (0 == OpenDevice("console.device", CONU_STANDARD, ioReq(fh->conreadio), 0)) */
129 err
= ERROR_INVALID_RESIDENT_LIBRARY
;
131 if (err
) CloseWindow(fh
->window
);
133 } /* if (fh->window) */
136 D(bug("[contask] Failed to open a window\n"));
137 err
= ERROR_NO_FREE_STORE
;
143 static BOOL
MakeSureWinIsOpen(struct filehandle
*fh
)
147 return MakeConWindow(fh
) == 0;
150 static void close_con(struct filehandle
*fh
)
155 CloseDevice((struct IORequest
*)fh
->timerreq
);
156 DeleteIORequest((struct IORequest
*)fh
->timerreq
);
158 DeleteMsgPort(fh
->timermp
);
160 if (fh
->flags
& FHFLG_CONSOLEDEVICEOPEN
)
161 CloseDevice((struct IORequest
*)fh
->conreadio
);
164 CloseWindow(fh
->window
);
166 DeleteIORequest(ioReq(fh
->conreadio
));
167 FreeVec(fh
->conreadmp
);
170 FreeVec(fh
->screenname
);
172 FreeVec(fh
->wintitle
);
174 FreeMem(fh
->pastebuffer
,PASTEBUFSIZE
);
176 CloseLibrary((struct Library
*)fh
->intuibase
);
177 CloseLibrary((struct Library
*)fh
->dosbase
);
181 static struct filehandle
*open_con(struct DosPacket
*dp
, LONG
*perr
)
184 struct filehandle
*fh
;
185 struct DeviceNode
*dn
;
189 dn
= BADDR(dp
->dp_Arg3
);
190 *perr
= ERROR_NO_FREE_STORE
;
191 fh
= AllocVec(sizeof(struct filehandle
), MEMF_PUBLIC
| MEMF_CLEAR
);
195 fh
->timermp
= CreateMsgPort();
196 fh
->timerreq
= (struct timerequest
*)CreateIORequest(fh
->timermp
, sizeof(struct timerequest
));
197 OpenDevice(TIMERNAME
, UNIT_MICROHZ
, (struct IORequest
*)fh
->timerreq
, 0);
199 fh
->intuibase
= (APTR
)OpenLibrary("intuition.library", 0);
200 fh
->dosbase
= (APTR
)OpenLibrary("dos.library", 0);
201 fh
->utilbase
= (APTR
)OpenLibrary("utility.library", 0);
203 fh
->inputbase
= (struct Device
*)FindName(&SysBase
->DeviceList
, "input.device");
207 filename
= BSTR2C((BSTR
)dp
->dp_Arg1
);
209 i
= isdosdevicec(fn
);
213 fh
->contask
= FindTask(0);
215 NEWLIST(&fh
->pendingReads
);
217 /* Create msgport for console.device communication */
218 fh
->conreadmp
= AllocVec(sizeof (struct MsgPort
) * 2, MEMF_PUBLIC
|MEMF_CLEAR
);
222 fh
->conreadmp
->mp_Node
.ln_Type
= NT_MSGPORT
;
223 fh
->conreadmp
->mp_Flags
= PA_SIGNAL
;
224 fh
->conreadmp
->mp_SigBit
= AllocSignal(-1);
225 fh
->conreadmp
->mp_SigTask
= fh
->contask
;
226 NEWLIST(&fh
->conreadmp
->mp_MsgList
);
228 fh
->conwritemp
= fh
->conreadmp
+ 1;
230 fh
->conwritemp
->mp_Node
.ln_Type
= NT_MSGPORT
;
231 fh
->conwritemp
->mp_Flags
= PA_SIGNAL
;
232 fh
->conwritemp
->mp_SigBit
= AllocSignal(-1);
233 fh
->conwritemp
->mp_SigTask
= fh
->contask
;
234 NEWLIST(&fh
->conwritemp
->mp_MsgList
);
237 fh
->conreadio
= (struct IOStdReq
*)CreateIORequest(fh
->conreadmp
, sizeof (struct IOStdReq
));
240 D(bug("contask: conreadio created\n"));
244 if (parse_filename(fh
, fn
, &fh
->nw
))
246 if (!(fh
->flags
& FHFLG_AUTO
))
248 err
= MakeConWindow(fh
);
258 err
= ERROR_BAD_STREAM_NAME
;
262 DeleteIORequest(ioReq(fh
->conreadio
));
265 } /* if (fh->conreadio) */
268 err
= ERROR_NO_FREE_STORE
;
271 } /* if (fh->conreadmp) */
274 err
= ERROR_NO_FREE_STORE
;
278 fh
->flags
|= FHFLG_RAW
;
288 static void startread(struct filehandle
*fh
)
290 if (fh
->flags
& FHFLG_ASYNCCONSOLEREAD
)
292 fh
->conreadio
->io_Command
= CMD_READ
;
293 fh
->conreadio
->io_Data
= fh
->consolebuffer
;
294 fh
->conreadio
->io_Length
= CONSOLEBUFFER_SIZE
;
295 SendIO((struct IORequest
*)fh
->conreadio
);
296 fh
->flags
|= FHFLG_ASYNCCONSOLEREAD
;
302 struct DosPacket
*dp
;
304 struct FileHandle
*dosfh
;
306 struct filehandle
*fh
;
307 struct DosPacket
*waitingdp
= NULL
;
309 D(bug("[CON] started\n"));
310 mp
= &((struct Process
*)FindTask(NULL
))->pr_MsgPort
;
312 dp
= (struct DosPacket
*)GetMsg(mp
)->mn_Node
.ln_Name
;
313 D(bug("[CON] startup message received. port=%x path='%b'\n", mp
, dp
->dp_Arg1
));
315 fh
= open_con(dp
, &error
);
317 D(bug("[CON] init failed\n"));
320 D(bug("[CON] %x open\n", fh
));
321 replypkt(dp
, DOSTRUE
);
325 ULONG conreadmask
= 1L << fh
->conreadmp
->mp_SigBit
;
326 ULONG timermask
= 1L << fh
->timermp
->mp_SigBit
;
327 ULONG packetmask
= 1L << mp
->mp_SigBit
;
330 sigs
= Wait(packetmask
| conreadmask
| timermask
);
332 if (sigs
& timermask
) {
334 replypkt(waitingdp
, DOSFALSE
);
339 if (sigs
& conreadmask
) {
340 GetMsg(fh
->conreadmp
);
341 fh
->flags
&= ~FHFLG_ASYNCCONSOLEREAD
;
343 replypkt(waitingdp
, DOSTRUE
);
344 AbortIO((struct IORequest
*)fh
->timerreq
);
345 WaitIO((struct IORequest
*)fh
->timerreq
);
348 D(bug("IO_READ %d\n", fh
->conreadio
->io_Actual
));
349 fh
->conbuffersize
= fh
->conreadio
->io_Actual
;
350 fh
->conbufferpos
= 0;
351 /* terminate with 0 char */
352 fh
->consolebuffer
[fh
->conbuffersize
] = '\0';
353 if (fh
->flags
& FHFLG_RAW
)
357 for(inp
= 0; (inp
< fh
->conbuffersize
) && (fh
->inputpos
< INPUTBUFFER_SIZE
); )
359 fh
->inputbuffer
[fh
->inputpos
++] = fh
->consolebuffer
[inp
++];
361 fh
->inputsize
= fh
->inputstart
= fh
->inputpos
;
362 HandlePendingReads(fh
);
363 } /* if (fh->flags & FHFLG_RAW) */
367 /* disable output if we're not suppoed to be echoing */
368 if (fh
->flags
& FHFLG_NOECHO
)
369 fh
->flags
|= FHFLG_NOWRITE
;
371 /* re-enable output */
372 fh
->flags
&= ~FHFLG_NOWRITE
;
373 } /* if (fh->flags & FHFLG_RAW) else ... */
377 while ((mn
= GetMsg(mp
))) {
378 dp
= (struct DosPacket
*)mn
->mn_Node
.ln_Name
;
380 D(bug("[CON %x] packet %x:%d %x,%x,%x\n",
381 fh
, dp
, dp
->dp_Type
, dp
->dp_Arg1
, dp
->dp_Arg2
, dp
->dp_Arg3
));
385 case ACTION_FINDINPUT
:
386 case ACTION_FINDOUTPUT
:
387 case ACTION_FINDUPDATE
:
388 dosfh
= BADDR(dp
->dp_Arg1
);
389 dosfh
->fh_Interactive
= DOSTRUE
;
390 dosfh
->fh_Arg1
= (IPTR
)fh
;
392 fh
->breaktask
= dp
->dp_Port
->mp_SigTask
;
393 D(bug("[CON] Find fh=%x. Usecount=%d\n", dosfh
, fh
->usecount
));
394 replypkt(dp
, DOSTRUE
);
398 D(bug("[CON] usecount=%d\n", fh
->usecount
));
399 if (fh
->usecount
<= 0)
401 replypkt(dp
, DOSTRUE
);
404 if (!MakeSureWinIsOpen(fh
))
406 fh
->breaktask
= dp
->dp_Port
->mp_SigTask
;
411 if (!MakeSureWinIsOpen(fh
))
413 fh
->breaktask
= dp
->dp_Port
->mp_SigTask
;
415 answer_write_request(fh
, dp
);
417 case ACTION_SCREEN_MODE
:
419 LONG wantmode
= dp
->dp_Arg1
? FCM_RAW
: 0;
420 D(bug("ACTION_SCREEN_MODE %s\n", wantmode
? "RAW" : "CON"));
421 if ((wantmode
& FCM_RAW
) && !(fh
->flags
& FHFLG_RAW
))
423 /* Switching from CON: mode to RAW: mode */
424 fh
->flags
|= FHFLG_RAW
;
425 fh
->inputstart
= fh
->inputsize
;
426 fh
->inputpos
= fh
->inputsize
;
427 HandlePendingReads(fh
);
431 /* otherwise just copy the flags */
432 fh
->flags
&= ~(FHFLG_RAW
| FHFLG_NOECHO
);
433 if (wantmode
& FCM_RAW
)
434 fh
->flags
|= FHFLG_RAW
;
435 if (wantmode
& FCM_NOECHO
)
436 fh
->flags
|= FHFLG_NOECHO
;
438 replypkt(dp
, DOSTRUE
);
441 case ACTION_CHANGE_SIGNAL
:
443 struct Task
*old
= fh
->breaktask
;
445 fh
->breaktask
= (struct Task
*)dp
->dp_Arg2
;
446 replypkt2(dp
, DOSTRUE
, (SIPTR
)old
);
449 case ACTION_WAIT_CHAR
:
451 if (!MakeSureWinIsOpen(fh
))
453 if (fh
->inputsize
> 0)
455 replypkt(dp
, DOSTRUE
);
459 LONG timeout
= dp
->dp_Arg1
;
460 LONG sec
= timeout
/ 1000000;
461 LONG usec
= timeout
% 1000000;
463 fh
->timerreq
->tr_node
.io_Command
= TR_ADDREQUEST
;
464 fh
->timerreq
->tr_time
.tv_secs
= sec
;
465 fh
->timerreq
->tr_time
.tv_micro
= usec
;
466 SendIO((struct IORequest
*)fh
->timerreq
);
472 case ACTION_IS_FILESYSTEM
:
473 replypkt(dp
, DOSFALSE
);
475 case ACTION_DISK_INFO
:
477 /* strange console handler features */
478 struct InfoData
*id
= BADDR(dp
->dp_Arg1
);
479 memset(id
, 0, sizeof(struct InfoData
));
480 id
->id_DiskType
= (fh
->flags
& FHFLG_RAW
) ?
481 AROS_MAKE_ID('R','A','W', 0) : AROS_MAKE_ID('C','O','N', 0);
482 id
->id_VolumeNode
= (BPTR
)fh
->window
;
483 id
->id_InUse
= (IPTR
)fh
->conreadio
;
484 replypkt(dp
, DOSTRUE
);
488 /* Yes, DOSTRUE. Check Guru Book for details. */
489 replypkt2(dp
, DOSTRUE
, ERROR_ACTION_NOT_KNOWN
);
492 bug("[CON] unknown action %d\n", dp
->dp_Type
);
493 replypkt2(dp
, DOSFALSE
, ERROR_ACTION_NOT_KNOWN
);
499 D(bug("[CON] %x closing\n", fh
));
501 struct Message
*msg
, *next_msg
;
503 AbortIO((struct IORequest
*)fh
->timerreq
);
504 WaitIO((struct IORequest
*)fh
->timerreq
);
505 replypkt(waitingdp
, DOSFALSE
);
507 ForeachNodeSafe(&fh
->pendingReads
, msg
, next_msg
)
509 struct DosPacket
*dpr
;
510 Remove((struct Node
*)msg
);
511 dpr
= (struct DosPacket
*)msg
->mn_Node
.ln_Name
;
512 replypkt(dpr
, DOSFALSE
);
514 if (fh
->flags
& FHFLG_ASYNCCONSOLEREAD
) {
515 AbortIO(ioReq(fh
->conreadio
));
516 WaitIO(ioReq(fh
->conreadio
));
520 replypkt(dp
, DOSFALSE
);
521 D(bug("[CON] %x closed\n", fh
));