Cette application permet à un utilisateur de l'émulateur PC d'Acorn (version multitåches seulement) de pouvoir exécuter des ordres RISC OS sous le prompt DOS. Il s'agit à ce stade d'une réécriture du programme !PC-Gate de Carl DECLERCK (écrit en BASIC). L'application se trouve répartie en deux programmes:
Actuellement, le mode de dialogue entre les deux programmes est basé sur du transfert de fichiers contrôlé à partir de l'environnement DOS en s'appuyant sur les deux utilitaires fournis par Acorn: getfile et putfile.
Il faut d'abord installer la partie cliente de !PCGate, pour cela, il faut copier le fichier PCGATE/EXE du sous-répertoire !PCGate.PC dans un répertoire MS/DOS accessible au sein de la variable d'environnement PATH;
Pour utiliser !PCGate, double-cliquer sur l'icône de !PCGate, ceci installe une icône applicative sur la barre. Lancer alors l'émulateur PC multitåches.
Note: l'ordre de lancement est indifférent. Il est toutefois nécessaire que !PCGate soit lancé avant d'utiliser l'application sous DOS.
Sous le prompt DOS (par ex.: C:\>), taper alors la commande suivante:
C:\> PCGATE -o Status
Après une certaine activité sur disque, le résultat de la requête s'affiche sur l'écran PC.
Le programme appelle directement les programmes getfile et putfile sans passer par le shell COMMAND.COM. Le répertoire contenant les programmes putfile et getfile doit alors être mentionné dans la variable d'environnement DOS ACORN.
De plus, la variable d'environnement TEMP doit être positionnée afin de pouvoir y stocker:
Enfin, l'émulateur PC ne doit pas tourner en mode "Single task", sous peine de faire boucler le programme client PCGATE.EXE dans la phase de retour de fichiers.
Pour le reste, !PCGate reste une application minimaliste avec même pas une petite fenêtre principale.
static void *pchandle = NULL; static BOOL example_initialise(void) { extern void FindPCEmTask(char *, void **); ... alarm_init(); ... event_setmask(wimp_EMPTRLEAVE | wimp_EMPTRENTER | wimp_EMREDRAW); win_add_unknown_event_processor(my_uk_event_p, NULL); FindPCEmTask("PCEm", (void **) &pchandle); if(pchandle!= 0) malarm_set(NULL); event_refresh(pchandle); ... }
BOOL my_uk_event_p(wimp_eventstr *e, void *handle) { switch(e->e) { case wimp_ESEND: case wimp_ESENDWANTACK: switch(e->data.msg.hdr.action) { case wimp_MINITTASK: if(!strncmp(e->data.msg.data.chars+8,"PCEm",4)) { pchandle= (void *) e->data.msg.hdr.task; event_refresh(pchandle); malarm_set(NULL); } break; case wimp_MCLOSETASK: if(e->data.msg.hdr.task == (wimp_t) pchandle) { event_refresh(pchandle= NULL); alarm_removeall(NULL); } } } return(FALSE); }
static void malarm_set(void *handle) { void checkgate(int, void *); int at; if(alarm_anypending(handle)) werr(TRUE, msgs_lookup("MESER1:Internal error code #%02u"),2); at= alarm_timenow() + 500; alarm_set(at, (alarm_handler) checkgate, handle); }
#define TASKMANAGER_ENUMERATETASKS 0x42681 void FindPCEmTask(char *tname,void **handle) { _kernel_swi_regs r; struct { void *handle; char *name; unsigned int memory; int flags; } buffer; r.r[0]= 0; do { r.r[1]= (int) &buffer; r.r[2]= sizeof(buffer); wimpt_noerr((os_error *) _kernel_swi( TASKMANAGER_ENUMERATETASKS, &r, &r)); if((r.r[0] >= 0) && (r.r[2] == 0)) if(!strcmp(buffer.name, tname)) { *handle= buffer.handle; break; } } while(r.r[0] >= 0); }
void mcheck(void *pchandle) { FILE *mfile; char buffer[128], *porder; int c, l; BOOL sortie; if(!fnexists("<Gate$File>")) return; if(fnexists("<Gate$Out>")) if(remove("<Gate$Out>")) return; mfile= fopen("<Gate$File>","rb"); if(!mfile) return; l= 0; c= fgetc(mfile); while(!feof(mfile) && c!= '\n' && c!= '\r') { buffer[l++]= (char) c; c= fgetc(mfile); } fclose(mfile); buffer[l]= '\0'; if(remove("<Gate$File>")) return; if(l!= 0) { sortie= buffer[0]== '-' && (buffer[1] == 'O' || buffer[1] == 'o'); if(sortie) { strcat(buffer, " { > <Gate$Out> }"); porder= buffer+2; } else { sortie= FALSE; if((!strncmp(buffer,"pcquit", 6)) || (!strncmp(buffer,"PCQUIT", 6))) { wimp_msgstr monmess; memset(&monmess, 0, sizeof(monmess)); monmess.hdr.size= 20; wimpt_noerr(wimp_sendmessage(wimp_ESEND, &monmess, (wimp_t) pchandle)); return; } porder= buffer; } (void) wimp_starttask(porder); } if(sortie) { mfile= fopen("<Gate$Out>","ab"); if(!mfile) return; fputc(26, mfile); fclose(mfile); } }
Notons la particularité de déclencher la fin de la tache d'émulation PC "de l'intérieur" (ordre spécifique pcquit).
#define FILE_READINFO 5 static BOOL fnexists(const char *fname) { _kernel_osfile_block fileb; return(_kernel_osfile(FILE_READINFO, fname, &fileb) == 1); }
Comme précisé en introduction, le programme client est écrit en Turbo Pascal 5 et tourne sous MS/DOS.
En étudiant le source, une option de compilation existe (usecommand), qui permet d'appeler le shell COMMAND.COM au lieu d'appler directement les programmes getfile et putfile et de bénéficier des redirections de flux de sortie, hélas, l'inaptitude de celui-ci à traiter convenablement les caractères "<" et > dans les désignations de paramètres m'ont obligé à laisser tomber assez tôt cette option
Améliorations à envisager pour le futur