Forgotten changes that should have been part of the r45368 64-bit fix.
[AROS.git] / rom / filesys / console_handler / con_handler.c
blob41a1298dca3487214588095e83e217775275e698
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/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>
17 #include <stddef.h>
18 #include <string.h>
20 #include "con_handler_intern.h"
21 #include "support.h"
23 #undef SDEBUG
24 #undef DEBUG
25 #define SDEBUG 0
26 #define DEBUG 0
27 #include <aros/debug.h>
29 static char *BSTR2C(BSTR srcs)
31 UBYTE *src = BADDR(srcs);
32 char *dst;
34 dst = AllocVec(src[0] + 1, MEMF_ANY);
35 if (!dst)
36 return NULL;
37 memcpy (dst, src + 1, src[0]);
38 dst[src[0]] = 0;
39 return dst;
41 static WORD isdosdevicec(CONST_STRPTR s)
43 UBYTE b = 0;
44 while (s[b]) {
45 if (s[b] == ':')
46 return b;
47 b++;
49 return -1;
52 #define ioReq(x) ((struct IORequest *)x)
54 static const struct NewWindow default_nw =
56 0, /* LeftEdge */
57 0, /* TopEdge */
58 -1, /* Width */
59 -1, /* Height */
60 1, /* DetailPen */
61 0, /* BlockPen */
62 0, /* IDCMP */
63 WFLG_DEPTHGADGET |
64 WFLG_SIZEGADGET |
65 WFLG_DRAGBAR |
66 WFLG_SIZEBRIGHT |
67 WFLG_SMART_REFRESH |
68 WFLG_ACTIVATE,
69 0, /* FirstGadget */
70 0, /* CheckMark */
71 "CON:", /* Title */
72 0, /* Screen */
73 0, /* Bitmap */
74 100, /* MinWidth */
75 70, /* MinHeight */
76 32767, /* MaxWidth */
77 32767, /* MaxHeight */
78 WBENCHSCREEN /* type */
82 static LONG MakeConWindow(struct filehandle *fh)
84 LONG err = 0;
86 if (fh->otherwindow == NULL) {
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);
99 } else {
100 D(bug("[contask] Using window %p\n", fh->otherwindow));
101 fh->window = fh->otherwindow;
104 if (fh->window)
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)) */
131 else
133 err = ERROR_INVALID_RESIDENT_LIBRARY;
135 if (err) CloseWindow(fh->window);
137 } /* if (fh->window) */
138 else
140 D(bug("[contask] Failed to open a window\n"));
141 err = ERROR_NO_FREE_STORE;
144 return err;
147 static BOOL MakeSureWinIsOpen(struct filehandle *fh)
149 if (fh->window)
150 return TRUE;
151 return MakeConWindow(fh) == 0;
154 static void close_con(struct filehandle *fh)
156 /* Clean up */
158 D(bug("[CON] Deleting timer request 0x%p\n", fh->timerreq));
159 if (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));
175 if (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);
184 if (fh->screenname)
185 FreeVec(fh->screenname);
186 if (fh->wintitle)
187 FreeVec(fh->wintitle);
188 if (fh->pastebuffer)
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 */
195 if (fh->gfxbase)
196 CloseLibrary((struct Library*)fh->gfxbase);
197 if (fh->gtbase)
198 CloseLibrary(fh->gtbase);
200 FreeVec(fh);
203 static struct filehandle *open_con(struct DosPacket *dp, LONG *perr)
205 char *filename, *fn;
206 struct filehandle *fh;
207 struct DeviceNode *dn;
208 LONG err, ok;
209 LONG i;
211 dn = BADDR(dp->dp_Arg3);
212 *perr = ERROR_NO_FREE_STORE;
213 fh = AllocVec(sizeof(struct filehandle), MEMF_PUBLIC | MEMF_CLEAR);
214 if (!fh)
215 return NULL;
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);
224 Forbid();
225 fh->inputbase = (struct Device *)FindName(&SysBase->DeviceList, "input.device");
226 Permit();
228 err = 0;
229 filename = BSTR2C((BSTR)dp->dp_Arg1);
230 fn = filename;
231 i = isdosdevicec(fn);
232 if (i >= 0)
233 fn += i + 1;
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);
241 if (fh->conreadmp)
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));
260 if (fh->conreadio)
262 D(bug("contask: conreadio created, parms '%s'\n", fn));
264 fh->nw = default_nw;
266 if (parse_filename(fh, fn, &fh->nw))
268 if (!(fh->flags & FHFLG_AUTO))
270 err = MakeConWindow(fh);
271 if (!err)
272 ok = TRUE;
274 else
276 ok = TRUE;
279 else
280 err = ERROR_BAD_STREAM_NAME;
282 if (!ok)
284 DeleteIORequest(ioReq(fh->conreadio));
287 } /* if (fh->conreadio) */
288 else
290 err = ERROR_NO_FREE_STORE;
293 } /* if (fh->conreadmp) */
294 else
296 err = ERROR_NO_FREE_STORE;
299 if (dn->dn_Startup)
300 fh->flags |= FHFLG_RAW;
302 if (!ok)
303 close_con(fh);
305 *perr = err;
306 FreeVec(filename);
307 return fh;
310 static void startread(struct filehandle *fh)
312 if (fh->flags & FHFLG_ASYNCCONSOLEREAD)
313 return;
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)
323 if (waitingdp)
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);
347 LONG CONMain(void)
349 struct MsgPort *mp;
350 struct DosPacket *dp;
351 struct Message *mn;
352 struct FileHandle *dosfh;
353 LONG error;
354 struct filehandle *fh;
355 struct FileLock *fl;
356 struct DosPacket *waitingdp = NULL;
358 D(bug("[CON] started\n"));
359 mp = &((struct Process*)FindTask(NULL))->pr_MsgPort;
360 WaitPort(mp);
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);
365 if (!fh) {
366 D(bug("[CON] init failed\n"));
367 goto end;
369 D(bug("[CON] 0x%p open\n", fh));
370 replypkt(dp, DOSTRUE);
372 for(;;)
374 ULONG conreadmask = 1L << fh->conreadmp->mp_SigBit;
375 ULONG timermask = 1L << fh->timermp->mp_SigBit;
376 ULONG packetmask = 1L << mp->mp_SigBit;
377 ULONG sigs;
379 sigs = Wait(packetmask | conreadmask | timermask);
381 if (sigs & timermask) {
382 if (waitingdp) {
383 replypkt(waitingdp, DOSFALSE);
384 waitingdp = NULL;
388 if (sigs & conreadmask) {
389 GetMsg(fh->conreadmp);
390 fh->flags &= ~FHFLG_ASYNCCONSOLEREAD;
391 if (waitingdp)
393 stopwait(fh, waitingdp, DOSTRUE);
394 waitingdp = NULL;
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)
403 LONG inp;
404 /* raw mode */
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) */
412 else
414 /* Cooked mode */
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.
421 dp = NULL;
422 goto end;
424 } /* if (fh->flags & FHFLG_RAW) else ... */
425 startread(fh);
428 while ((mn = GetMsg(mp))) {
429 dp = (struct DosPacket*)mn->mn_Node.ln_Name;
430 dp->dp_Res2 = 0;
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));
433 error = 0;
434 switch (dp->dp_Type)
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);
441 break;
443 fh->usecount--;
444 FreeMem(fl, sizeof(*fl));
445 /* Fallthrough */
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;
452 fh->usecount++;
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);
456 break;
457 case ACTION_COPY_DIR_FH:
458 fl = AllocMem(sizeof(*fl), MEMF_CLEAR | MEMF_PUBLIC);
459 if (fl == BNULL) {
460 replypkt2(dp, (SIPTR)BNULL, ERROR_NO_FREE_STORE);
461 } else {
462 fh->usecount++;
463 fl->fl_Task = mp;
464 fl->fl_Key = (IPTR)fh;
465 replypkt(dp, (SIPTR)MKBADDR(fl));
467 break;
468 case ACTION_END:
469 fh->usecount--;
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);
483 waitingdp = NULL;
484 fh->flags = (fh->flags & ~FHFLG_READPENDING) | FHFLG_WAITFORCLOSE;
486 else
487 goto end;
489 replypkt(dp, DOSTRUE);
490 break;
491 case ACTION_READ:
492 if (!MakeSureWinIsOpen(fh)) {
493 replypkt2(dp, DOSFALSE, ERROR_NO_FREE_STORE);
494 break;
496 fh->breaktask = dp->dp_Port->mp_SigTask;
497 startread(fh);
498 con_read(fh, dp);
499 break;
500 case ACTION_WRITE:
501 if (!MakeSureWinIsOpen(fh)) {
502 replypkt2(dp, DOSFALSE, ERROR_NO_FREE_STORE);
503 break;
505 fh->breaktask = dp->dp_Port->mp_SigTask;
506 startread(fh);
507 answer_write_request(fh, dp);
508 break;
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);
520 else
522 /* otherwise just copy the flags */
523 if (dp->dp_Arg1)
524 fh->flags |= FHFLG_RAW;
525 else
526 fh->flags &= ~FHFLG_RAW;
528 replypkt(dp, DOSTRUE);
530 break;
531 case ACTION_CHANGE_SIGNAL:
533 struct Task *old = fh->breaktask;
534 if (dp->dp_Arg2)
535 fh->breaktask = (struct Task*)dp->dp_Arg2;
536 replypkt2(dp, DOSTRUE, (SIPTR)old);
538 break;
539 case ACTION_WAIT_CHAR:
541 if (!MakeSureWinIsOpen(fh)) {
542 replypkt2(dp, DOSFALSE, ERROR_NO_FREE_STORE);
543 break;
545 if (fh->inputsize > 0)
547 replypkt(dp, DOSTRUE);
549 else
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);
559 waitingdp = dp;
561 startread(fh);
563 break;
564 case ACTION_IS_FILESYSTEM:
565 replypkt(dp, DOSFALSE);
566 break;
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);
578 break;
579 case ACTION_SEEK:
580 /* Yes, DOSTRUE. Check Guru Book for details. */
581 replypkt2(dp, DOSTRUE, ERROR_ACTION_NOT_KNOWN);
582 break;
583 default:
584 bug("[CON] unknown action %d\n", dp->dp_Type);
585 replypkt2(dp, DOSFALSE, ERROR_ACTION_NOT_KNOWN);
586 break;
590 end:
591 D(bug("[CON] 0x%p closing\n", fh));
592 if (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"));
606 close_con(fh);
609 if (dp)
611 D(bug("[CON] Replying packet 0x%p\n", dp));
612 replypkt(dp, DOSFALSE);
615 D(bug("[CON] 0x%p closed\n", fh));
616 return 0;