dos.library: Use fh_Interactive instead of fh_Port alias, for code clarity
[AROS.git] / rom / devs / filesys / console_handler / con_handler.c
blob76b650778e019e066c930199c20a7f525278c957
2 #include <proto/exec.h>
3 #include <exec/libraries.h>
4 #include <exec/resident.h>
5 #include <exec/memory.h>
6 #include <exec/io.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>
18 #include <stddef.h>
19 #include <string.h>
21 #include "con_handler_intern.h"
22 #include "support.h"
24 #undef SDEBUG
25 #undef DEBUG
26 #define SDEBUG 0
27 #define DEBUG 0
28 #include <aros/debug.h>
30 static char *BSTR2C(BSTR srcs)
32 UBYTE *src = BADDR(srcs);
33 char *dst;
35 dst = AllocVec(src[0] + 1, MEMF_ANY);
36 if (!dst)
37 return NULL;
38 memcpy (dst, src + 1, src[0]);
39 dst[src[0]] = 0;
40 return dst;
42 static WORD isdosdevicec(CONST_STRPTR s)
44 UBYTE b = 0;
45 while (s[b]) {
46 if (s[b] == ':')
47 return b;
48 b++;
50 return -1;
53 #define ioReq(x) ((struct IORequest *)x)
55 static const struct NewWindow default_nw =
57 0, /* LeftEdge */
58 0, /* TopEdge */
59 -1, /* Width */
60 -1, /* Height */
61 1, /* DetailPen */
62 0, /* BlockPen */
63 0, /* IDCMP */
64 WFLG_DEPTHGADGET |
65 WFLG_SIZEGADGET |
66 WFLG_DRAGBAR |
67 WFLG_SIZEBRIGHT |
68 WFLG_SMART_REFRESH |
69 WFLG_ACTIVATE,
70 0, /* FirstGadget */
71 0, /* CheckMark */
72 "CON:", /* Title */
73 0, /* Screen */
74 0, /* Bitmap */
75 100, /* MinWidth */
76 100, /* MinHeight */
77 32767, /* MaxWidth */
78 32767, /* MaxHeight */
79 WBENCHSCREEN /* type */
83 static LONG MakeConWindow(struct filehandle *fh)
85 LONG err = 0;
87 struct TagItem win_tags [] =
89 {WA_PubScreen ,0 },
90 {WA_AutoAdjust ,TRUE },
91 {WA_PubScreenName, 0 },
92 {WA_PubScreenFallBack, TRUE },
93 {TAG_DONE }
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 if (fh->window)
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)) */
127 else
129 err = ERROR_INVALID_RESIDENT_LIBRARY;
131 if (err) CloseWindow(fh->window);
133 } /* if (fh->window) */
134 else
136 D(bug("[contask] Failed to open a window\n"));
137 err = ERROR_NO_FREE_STORE;
140 return err;
143 static BOOL MakeSureWinIsOpen(struct filehandle *fh)
145 if (fh->window)
146 return TRUE;
147 return MakeConWindow(fh) == 0;
150 static void close_con(struct filehandle *fh)
152 /* Clean up */
154 if (fh->timerreq) {
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);
163 if (fh->window)
164 CloseWindow(fh->window);
166 DeleteIORequest(ioReq(fh->conreadio));
167 FreeVec(fh->conreadmp);
169 if (fh->screenname)
170 FreeVec(fh->screenname);
171 if (fh->wintitle)
172 FreeVec(fh->wintitle);
173 if (fh->pastebuffer)
174 FreeMem(fh->pastebuffer,PASTEBUFSIZE);
176 CloseLibrary((struct Library*)fh->intuibase);
177 CloseLibrary((struct Library*)fh->dosbase);
178 FreeVec(fh);
181 static struct filehandle *open_con(struct DosPacket *dp, LONG *perr)
183 char *filename, *fn;
184 struct filehandle *fh;
185 struct DeviceNode *dn;
186 LONG err, ok;
187 LONG i;
189 dn = BADDR(dp->dp_Arg3);
190 *perr = ERROR_NO_FREE_STORE;
191 fh = AllocVec(sizeof(struct filehandle), MEMF_PUBLIC | MEMF_CLEAR);
192 if (!fh)
193 return NULL;
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);
202 Forbid();
203 fh->inputbase = (struct Device *)FindName(&SysBase->DeviceList, "input.device");
204 Permit();
206 err = 0;
207 filename = BSTR2C((BSTR)dp->dp_Arg1);
208 fn = filename;
209 i = isdosdevicec(fn);
210 if (i >= 0)
211 fn += i + 1;
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);
219 if (fh->conreadmp)
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));
238 if (fh->conreadio)
240 D(bug("contask: conreadio created\n"));
242 fh->nw = default_nw;
244 if (parse_filename(fh, fn, &fh->nw))
246 if (!(fh->flags & FHFLG_AUTO))
248 err = MakeConWindow(fh);
249 if (!err)
250 ok = TRUE;
252 else
254 ok = TRUE;
257 else
258 err = ERROR_BAD_STREAM_NAME;
260 if (!ok)
262 DeleteIORequest(ioReq(fh->conreadio));
265 } /* if (fh->conreadio) */
266 else
268 err = ERROR_NO_FREE_STORE;
271 } /* if (fh->conreadmp) */
272 else
274 err = ERROR_NO_FREE_STORE;
277 if (dn->dn_Startup)
278 fh->flags |= FHFLG_RAW;
280 if (!ok)
281 close_con(fh);
283 *perr = err;
284 FreeVec(filename);
285 return fh;
288 static void startread(struct filehandle *fh)
290 if (fh->flags & FHFLG_ASYNCCONSOLEREAD)
291 return;
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;
299 LONG CONMain(void)
301 struct MsgPort *mp;
302 struct DosPacket *dp;
303 struct Message *mn;
304 struct FileHandle *dosfh;
305 LONG error;
306 struct filehandle *fh;
307 struct DosPacket *waitingdp = NULL;
309 D(bug("[CON] started\n"));
310 mp = &((struct Process*)FindTask(NULL))->pr_MsgPort;
311 WaitPort(mp);
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);
316 if (!fh) {
317 D(bug("[CON] init failed\n"));
318 goto end;
320 D(bug("[CON] %x open\n", fh));
321 replypkt(dp, DOSTRUE);
323 for(;;)
325 ULONG conreadmask = 1L << fh->conreadmp->mp_SigBit;
326 ULONG timermask = 1L << fh->timermp->mp_SigBit;
327 ULONG packetmask = 1L << mp->mp_SigBit;
328 ULONG sigs;
330 sigs = Wait(packetmask | conreadmask | timermask);
332 if (sigs & timermask) {
333 if (waitingdp) {
334 replypkt(waitingdp, DOSFALSE);
335 waitingdp = NULL;
339 if (sigs & conreadmask) {
340 GetMsg(fh->conreadmp);
341 fh->flags &= ~FHFLG_ASYNCCONSOLEREAD;
342 if (waitingdp) {
343 replypkt(waitingdp, DOSTRUE);
344 AbortIO((struct IORequest *)fh->timerreq);
345 WaitIO((struct IORequest *)fh->timerreq);
346 waitingdp = NULL;
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)
355 LONG inp;
356 /* raw mode */
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) */
364 else
366 /* Cooked mode */
367 /* disable output if we're not suppoed to be echoing */
368 if (fh->flags & FHFLG_NOECHO)
369 fh->flags |= FHFLG_NOWRITE;
370 process_input(fh);
371 /* re-enable output */
372 fh->flags &= ~FHFLG_NOWRITE;
373 } /* if (fh->flags & FHFLG_RAW) else ... */
374 startread(fh);
377 while ((mn = GetMsg(mp))) {
378 dp = (struct DosPacket*)mn->mn_Node.ln_Name;
379 dp->dp_Res2 = 0;
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));
382 error = 0;
383 switch (dp->dp_Type)
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;
391 fh->usecount++;
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);
395 break;
396 case ACTION_END:
397 fh->usecount--;
398 D(bug("[CON] usecount=%d\n", fh->usecount));
399 if (fh->usecount <= 0)
400 goto end;
401 replypkt(dp, DOSTRUE);
402 break;
403 case ACTION_READ:
404 if (!MakeSureWinIsOpen(fh))
405 goto end;
406 fh->breaktask = dp->dp_Port->mp_SigTask;
407 startread(fh);
408 con_read(fh, dp);
409 break;
410 case ACTION_WRITE:
411 if (!MakeSureWinIsOpen(fh))
412 goto end;
413 fh->breaktask = dp->dp_Port->mp_SigTask;
414 startread(fh);
415 answer_write_request(fh, dp);
416 break;
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);
429 else
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);
440 break;
441 case ACTION_CHANGE_SIGNAL:
443 struct Task *old = fh->breaktask;
444 if (dp->dp_Arg2)
445 fh->breaktask = (struct Task*)dp->dp_Arg2;
446 replypkt2(dp, DOSTRUE, (SIPTR)old);
448 break;
449 case ACTION_WAIT_CHAR:
451 if (!MakeSureWinIsOpen(fh))
452 goto end;
453 if (fh->inputsize > 0)
455 replypkt(dp, DOSTRUE);
457 else
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);
467 waitingdp = dp;
469 startread(fh);
471 break;
472 case ACTION_IS_FILESYSTEM:
473 replypkt(dp, DOSFALSE);
474 break;
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);
486 break;
487 case ACTION_SEEK:
488 /* Yes, DOSTRUE. Check Guru Book for details. */
489 replypkt2(dp, DOSTRUE, ERROR_ACTION_NOT_KNOWN);
490 break;
491 default:
492 bug("[CON] unknown action %d\n", dp->dp_Type);
493 replypkt2(dp, DOSFALSE, ERROR_ACTION_NOT_KNOWN);
494 break;
498 end:
499 D(bug("[CON] %x closing\n", fh));
500 if (fh) {
501 struct Message *msg, *next_msg;
502 if (waitingdp) {
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));
518 close_con(fh);
520 replypkt(dp, DOSFALSE);
521 D(bug("[CON] %x closed\n", fh));
522 return 0;