Here are our private virtual DevCon2016 !
I want to write an console handler after writing the ar.console.device , although it is hard because no official RKM example,
and wondering what (ACTION_) is misimplememted.
Because, it works with the command copy on itself, i.e : "copy arCon: to arCon:" shows each line twice (copy itself) but seems _to be slowed_ when I replace copy with a 'type' command : "type arCon: to arCon:".
Also, it can't read (input) correctly with program like ed (UNIX line editing) with redirection like "Ed <arCon: " . It did not work, input seems not to be in ! when I put 'a' append command, return and write text, ending with a line with a period '.' as usual. And '1' or 'p' for printing out !
Perhaps, I'm not implementing ACTION_WAIT_CHAR , the right way ; I though ! But, It is buffering too that I suspect..
Here is the code acom.c : gcc -no-startup-files -o arCon_handler acom.c
The entry in the mountlist is
ArCon:
Handler = arCon_handler
Stack = 10000
...
Code: Select all
/*
* DOSDEVICE.C V1.10 2 November 1987
* ARAB CONSOLE HANDLER 7 October 2017 minus one year !
*
* EXAMPLE DOS DEVICE DRIVER FOR AZTEC.C PUBLIC DOMAIN.
*
* By Matthew Dillon.
*
* Modified for OS4 by Fredrik Wikstrom
*
* Adaptated for a [ar]console handler by Gilles Dridi
*
*/
// variables below belongs to startX() process
short NLo;
UBYTE b[1024], s[1024];
struct window *win;
int _startX(); // entry code for my other ConsoleArabOther to be launch on openning_action, which communicates (input/output) with the [ar]console.device
// Here is the main process _start (without an 'X') handler launched automatically when entering command : "mount arcon: from mountlist"
int _start(int argc, char *argv[]) {
PACKET *packet;
short error;
MSG *msg;
int noquit;
void *tmp;
/*
* Initialize all global variables. SysBase MUST be initialized before
* we can make Exec calls. AbsExecBase is a library symbol
* referencing absolute memory location 4. The DOS library is openned
* for the debug process only.
*/
PROC *DosProc, *OtherProc; /* Our Process, and "(a)com.c" */
DEVNODE *DosNode; /* Our DOS node.. created by DOS for us */
struct FileHandle *fh;
SysBase = *(struct Library **)4;
IExec = (struct ExecIFace *)((struct ExecBase *)SysBase)->MainInterface;
DOSBase = IExec->OpenLibrary("dos.library", 0L);
IDOS = (struct DOSIFace *)IExec->GetInterface(DOSBase, "main", 1, NULL); // As Exec library it is normally always open ...
DosProc = (struct Process *)IExec->FindTask(NULL);
IExec->WaitPort(&DosProc->pr_MsgPort); // Get Startup Packet
msg = IExec->GetMsg(&DosProc->pr_MsgPort);
packet = (PACKET *)msg->mn_Node.ln_Name;
packet->dp_Res1 = DOS_TRUE;
packet->dp_Res2 = 0;
/*
* Loading DosNode->dn_Task causes DOS *NOT* to startup a new
* instance of the device driver for every reference. E.G. if
* you were writing a CON device you would want this field to
* be NULL.
*/
DosNode = BTOC(packet->dp_Arg3);
/*
* Set dn_Task field which tells DOS not to startup a new
* process on every reference.
*/
DosNode->dn_Task = NULL; //&DosProc->pr_MsgPort;
packet->dp_Res1 = DOS_TRUE;
packet->dp_Res2 = 0;
returnpacket(packet, DosProc);
NLo = 0;
top:
finDiff = 0;
noquit = 1;
while(noquit) {
IExec->WaitPort(&(DosProc->pr_MsgPort));
while ( msg = IExec->GetMsg(&(DosProc->pr_MsgPort)) ) {
ubyte *ptr;
packet = (PACKET *)msg->mn_Node.ln_Name;
packet->dp_Res1 = DOS_TRUE;
packet->dp_Res2 = 0;
error = 0;
dbprintf("Packet: %3ld %08lx %08lx %08lx %10s ",
packet->dp_Type,
packet->dp_Arg1, packet->dp_Arg2,
packet->dp_Arg3,
typetostr(packet->dp_Type)
);
switch(packet->dp_Type) {
case ACTION_DIE: /* attempt to die? */
{
noquit = 0; /* try to die */
}
break;
case ACTION_OPENRW: /* FileHandle,Lock,Name Bool */
// break;
case ACTION_OPENOLD: /* FileHandle,Lock,Name Bool */
// break;
case ACTION_OPENNEW: /* FileHandle,Lock,Name Bool */
{
if ( IExec->FindTask("ConsoleArabOther") == NULL ) {
OtherProc = IDOS->CreateNewProcTags(
NP_Entry, _startX,
NP_Name, "ConsoleArabOther",
TAG_DONE);
IDOS->Delay(50); // Hard Hack : to be sure the process is running
// Or ... try something with signals
// IDOS->NotifyDosListChange(NULL, SIGBREAKB_CTRL_E, 0);
// IExec->Wait(SIGBREAKF_CTRL_E);
// IDOS->NotifyProcListChange(NULL, NPLC_END, 0); /* Turn it off */
}
fh=(struct FileHandle*)BADDR(packet->dp_Arg1);
/* Nicht-Interaktives File */
fh->fh_Port=DOS_TRUE;
// fh->fh_Args = (long)fh; // fh_Arg1 !! or = CTOB(fh); ?
}
break;
case ACTION_WAIT_CHAR: /* Timeout, ticks Bool */
if ( NLo ) goto label_ToBeREAD;
//IDOS->Delay(10); // Wait : packet->dp_Arg1 ou 10 or nothing to debug
if ( NLo ) {
label_ToBeREAD: ;//packet->dp_Res1 = DOS_TRUE; // already set at the top
packet->dp_Res2 = (long)1; // line to read (1 for my simple (ar)console handler)
} else {
//packet->dp_Res1 = DOS_FALSE; // done at the end
error = ERROR_ACTION_NOT_KNOWN;
}
break;
case ACTION_READ: /* FHArg1,CPTRBuffer,Length ActLength */
{
ubyte *ptr = (ubyte *)packet->dp_Arg2;
long left = packet->dp_Arg3;
long j = 0;
IExec->Forbid();
if ( NLo ) { // set by the ConsoleArabOther task(ProcessHandler)
while( left--) {
if ( b[j] == '\n' ) { *ptr++ = b[j++]; break; } // j+ not to exit
if ( &b[j] < &b[1024-1] ) *ptr++ = b[j++]; // 1024 size of buffer (it could be a #define MAXBUF 1024)
}
b[0] = 0;
*ptr++ = 0; // Really needed ?
NLo = 0;
} else {
*ptr = 0; j = 1; // We try not to escape ... from polling (see below) ! READ , READ, READ, etc
}
IExec->Permit();
if ( finDiff ) { finDiff = 0; packet->dp_Res1 = 0; } // EOF (finDiff set by ConsoleArabOther when quitting this other process)
else packet->dp_Res1 = j;
} break;
case ACTION_FLUSH: /* writeout bufs, disk motor off */
if ( packet->dp_Arg2 && packet->dp_Arg2 != '\0' ) //packet->dp_Res1 = DOS_TRUE;
; // fall-through WRITE
else {
// packet->dp_Res1 = DOS_TRUE; // GURU book says must always be DOS_TRUE !!
break; // stop here and no error we have Res1 == DOS_TRUE
}
case ACTION_WRITE: /* FHArg1,CPTRBuffer,Length ActLength */
{ UBYTE d[16];
ubyte *ptr = (ubyte *)packet->dp_Arg2;
long left = packet->dp_Arg3;
long left0 = left, j = 0;
short nl = 0;
if ( *ptr == '\0' ) { // nothing to write ! we are (in) polling (see above)
packet->dp_Res1 = left;
break;
}
if ( io == NULL ) break; // don't forget the is set by ConsoleArabOtherTask (ProcessHandler)
while(left--) {
if ( *ptr == '\n' ) { nl = 1; break; }
decale1Tampon(s,k); // shiftBuffer
s[k++] = *ptr++;
}
//s[k] = 0; // note that if we could be inserting text
if ( !(ConsoleMP2 = (struct MsgPort *)CreatePort("Arabe2.Console", 0))) {
break;
}
if ( !(io2 = (struct IOStdReq *)CreateExtIO(ConsoleMP2, (LONG)sizeof(struct IOStdReq)))) {
break;
}
// duplicate from "io" (simple, without io[2] ) used in/by ConsoleArabOtherTask launch when openned
io2->io_Device = io->io_Device;
io2->io_Unit = io->io_Unit;
if ( nl ) { k = 0; while(s[k] != 0) k++; s[k++] = '\n'; s[k] = 0; }
io2->io_Data = (APTR)&s[0];
io2->io_Length = -1;
io2->io_Command = CMD_WRITE;
IExec->DoIO((struct IORequest *)io2);
if ( nl ) { s[0] = k = 0; }
DeleteExtIO(io2);
DeletePort(ConsoleMP2);
packet->dp_Res1 = left0;
} break;
case ACTION_CLOSE: /* FHArg1 Bool:TRUE */
break;
case ACTION_DISK_INFO: /* InfoData Bool:TRUE */
if ( win ) { ((struct InfoData *)packet->dp_Arg1)->id_VolumeNode = (BPTR)win; // win var. from ConsoleArabOtherTask launch at the top
((struct InfoData *)packet->dp_Arg1)->id_InUse = (BPTR)packet;
} else error = ERROR_ACTION_NOT_KNOWN;
break;
case ACTION_INHIBIT: /* Bool Bool */
/* Return success for the hell of it */
break;
case ACTION_RAWMODE: /* Bool(-1:RAW 0:CON) OldState */
case ACTION_SEEK:
case ACTION_EXAMINE_NEXT:
case ACTION_EXAMINE_OBJECT: /* Lock,Fib Bool */
case ACTION_EXAMINE_FH: /* added by F.W */
case ACTION_INFO: /* Lock, InfoData Bool:TRUE */
case ACTION_PARENT: /* Lock ParentLock */
case ACTION_DELETE_OBJECT: /*Lock,Name Bool */
case ACTION_CREATE_DIR: /* Lock,Name Lock */
case ACTION_LOCATE_OBJECT: /* Lock,Name,Mode Lock */
case ACTION_COPY_DIR: /* Lock, Lock */
case ACTION_FREE_LOCK: /* Lock, Bool */
case ACTION_SET_PROTECT:/* -,Lock,Name,Mask Bool */
case ACTION_SET_COMMENT:/* -,Lock,Name,Comment Bool */
case ACTION_RENAME_DISK:
case ACTION_RENAME_OBJECT:/* SLock,SName,DLock,DName Bool */
/*
* A few other packet types which we do not support
*/
case ACTION_MORECACHE: /* #BufsToAdd Bool */
default:
error = ERROR_ACTION_NOT_KNOWN;
break;
}
if (packet) {
if (error) {
dbprintf("ERR=%ld\n", error);
packet->dp_Res1 = DOS_FALSE;
packet->dp_Res2 = error;
} else {
dbprintf("RES=%06lx\n", packet->dp_Res1);
}
returnpacket(packet, DosProc);
}
}
} // while(noquit);
dbprintf("Can we remove ourselves? ");
// Delay(50); /* I wanna even see the debug message! */
IExec->Forbid();
if ( packetsqueued(DosProc) ) // || GetHead((struct List *)&FHBase) || GetHead((struct List *)&LCBase)
//|| GetHead((struct List *)&RFRoot.list))
{
IExec->Permit();
dbprintf(" .. not yet!\n");
goto top; // sorry... can't exit
}
/*
* Causes a new process to be created on next reference
*/
DosNode->dn_Task = FALSE;
/*
* Remove debug process, closedown, fall of the end of the world
* (which is how you kill yourself if a PROCESS. A TASK would have
* had to RemTask(NULL) itself).
*/
//IExec->DropInterface((struct Interface *)IDOS); // normally not to comment
//IExec->CloseLibrary(DOSBase);
}
// Twin process
int _startX() { win = NULL; NLo = 0; b[0] = 0;
...
initialize win-dow open [ar]console.device
...
communicates (input/output : "io" request) with the [ar]console.device
and fills b[1024] and set NLo = NewLineo.
...
}
/*
* PACKET ROUTINES. Dos Packets are in a rather strange format as you
* can see by this and how the PACKET structure is extracted in the
* GetMsg() of the main routine.
*/
void returnpacket(struct DosPacket *packet, struct Process * DosProc) {
struct Message *mess;
struct MsgPort *replyport;
replyport = packet->dp_Port;
mess = packet->dp_Link;
packet->dp_Port = &DosProc->pr_MsgPort;
mess->mn_Node.ln_Name = (char *)packet;
mess->mn_Node.ln_Succ = NULL;
mess->mn_Node.ln_Pred = NULL;
IExec->PutMsg(replyport, mess);
}
/*
* Are there any packets queued to our device?
*/
int packetsqueued (struct Process * DosProc) {
return ((void *)DosProc->pr_MsgPort.mp_MsgList.lh_Head !=
(void *)&DosProc->pr_MsgPort.mp_MsgList.lh_Tail);
}
I think an RKM - console: handler , excerpt or simplified code example on the Amiga wiki will help too.
BEST REGARDS -- DGILLES