Suivez-nous sur X
|
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
ALL
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z
|
|
A propos d'Obligement
|
|
David Brunet
|
|
|
|
Programmation : Amiga E - programmer ARexx
(Article écrit par Yann Armand et Pierre Girard et extrait d'Amiga News - février 1996)
|
|
Il y a de grandes chances pour que vous connaissiez tous ARexx. Pour ceux qui ne se souviennent pas, voici un petit rappel.
ARexx est un langage de programmation simple à utiliser et qui permet de communiquer avec les programmes prévus à cet effet.
Il permet notamment d'ajouter des fonctions personnelles aux logiciels par le biais de scripts (des sortes de macro-commandes
en plus puissant). En théorie, l'Amiga était déjà capable de faire communiquer les tâches entre elles par l'intermédiaire des
ports de message Exec. Cependant, il n'y avait pas de standard de communication. Et ARexx est arrivé ! Mais quel est l'intérêt
de programmer ARexx ?
C'est simple : prenez un petit script ARexx qui ouvre une fenêtre de requête sous GoldEd. Ça va vite, même si le programme est
interprété. Mais si vous voulez, par exemple, chercher un mot spécifique dans un dictionnaire avec une énorme boucle WHILE,
vous pouvez aller prendre un café en attendant.
Eh oui, le problème d'ARexx, c'est la vitesse. En utilisation normale, celle-ci est tout à fait convenable. Mais notre optique
à nous est de ne pas être ralenti par l'interpréteur.
Nous vous livrons donc ce mois-ci la méthode pour qu'un petit programme (le nôtre) puisse communiquer avec un logiciel
quelconque, tout en ne connaissant que les commandes que ce logiciel met à la disposition d'ARexx et en se substituant à
l'interpréteur (RexxMast).
Les ports de messages
Pour programmer ARexx, il faut au minimum avoir quelques notions sur les ports de messages. Ils servent à recevoir des messages,
à intercepter des événements. C'est ainsi qu'une fenêtre possède un port de message qui intercepte les événements Intuition
lorsque ceux-ci surviennent (déplacement...). La gestion d'un port peut paraître ardue à première vue, mais quelques commandes
de la bibliothèque Exec se chargent de tout contrôler.
Les commandes de gestion des ports
La première chose à faire est de déterminer si notre port existe déjà grâce à la fonction FindPort('nom').
Attention : cette commande doit toujours être encadrée du couple Forbid()-Permit() coupant le multitâche. Le port n'existant pas,
il faut le créer grâce à la fonction CreateMsgPort() qui nous renvoie une structure MsgPort. Il faut ensuite appeler la
fonction AddPort() afin d'ajouter le nouveau port à la liste des ports publics (pour que les autres tâches puissent y avoir
accès). Dans l'ordre inverse, il nous faudra sortir le port de la liste des ports publics (RemPort) puis l'effacer
(DeleteMsgPort) avant la sortie du programme.
Les messages ARexx
Les tâches communiquent par ARexx en s'envoyant des objets de type rexxmsg. Ceux-ci contiennent un objet node exec standard,
le type d'action ARexx demandé, le nom de la commande sous forme d'une chaîne de caractères, deux champs results (chaînes) et
l'adresse du port de message pour la réponse.
Envoi du message ARexx
En cadeau ce mois-ci, voici une superbe procédure qui va vous permettre d'envoyer des commandes ARexx à vos programmes préférés.
La commande se déclare comme suit :
PROC sendrexxcmd(hostname,replyport: PTR TO mp, command, flags, result)
|
. hostname, est le nom du port Arexx appelé.
. replyport, l'adresse du port sur lequel doit se faire la réponse.
. command, est la chaîne de caractères décrivant la commande.
. retour, est l'adresse de la chaîne de caractères dans laquelle sera stocké le résultat.
Il nous faut créer un objet rexxmsg. Une fois remplis ces champs, nous l'expédions à la tâche-cible (hostname), qui nous répondra
sur notre port de message(replyport).
Bon allez, on explique
On commence par allouer l'objet rexxmsg. Cela se fait presque tout seul grâce à CreateRexxMsg auquel nous donnons comme arguments
notre port de message ainsi que son nom.
On crée ensuite la chaîne d'arguments (CreateArgstring). Et là, tout le monde se demande pourquoi on fait un CopyMem alors
qu'il suffirait d'écrire :
rxmsg.args={rexx_command}
|
On atteint ici une des limites de l'Amiga E. En effet, rxmsg.args est déclaré dans le module "rexx/storage" comme une substructure.
C'est donc, pour le compilateur, le label d'une substructure dont il ne connaît pas le contenu. Il pourrait faire ainsi des
erreurs de typage pour toute instruction d'affectation. Par contre, nous, nous savons que c'est un tableau de 16 pointeurs sur
des chaînes de caractères. Nous posons donc dans la première case du tableau (le premier argument) l'adresse de la chaîne
d'arguments que nous venons de créer. Nous continuons en définissant le type d'action ARexx. C'est une commande (RXCOMM)
avec d'éventuels flags (drapeaux), le plus souvent utilisé étant RXFF_RESULT qui demande un résultat sous forme d'une chaîne
de caractères.
Comme nous sommes des fanatiques du Shell, nous définissons stdin et stdout avec Input() et Output() ce qui permettra à notre
programme d'utiliser des pipes, vous savez "dir | more".
Et là, on envoie le message ! Attention, quand on fait ce genre de chose, il faut s'assurer que les ports ne vont pas changer
pendant l'opération (Forbid-Permit). Ensuite, on cherche l'adresse du port grâce à son nom (FindPort()) et on envoie avec
PutMsg(...).
Enfin, on attend une réponse (WaitPort, GetMsg). La tâche-cible nous a renvoyé notre message dans lequel elle a rempli les
deux champs result :
- result1 pour la réussite de l'action (0), sinon un code de retour standard ARexx.
- result2 pour la chaîne de résultat, si elle a été demandée.
Notez dans vos cahiers pour le mois prochain que vous avez à modifier la procédure pour qu'elle traite le cas où rxmsg.result1
est différent de 0, c'est-à-dire quand il y a une erreur. Il nous suffit pour finir de recopier result2 dans la chaîne
servant au retour (StrCopy), de nettoyer le message (ClearRexxMsg) et de désallouer la mémoire (DeleteRexxMsg).
Voili, voilou, c'est fini. Si vous ne possédez pas CygnusEd (commercial), vous pouvez utiliser GoldEd avec par exemple :
sendrexxcmd('GOLDED.1',replyport,'QUERY FILE', RXFF_RESULT,nom).
|
Le mois prochain, nous verrons peut-être une application de cette routine. Tchao.
MODULE 'exec/ports','exec/nodes','exec/lists'
MODULE 'rexxsyslib','rexx/rxslib','rexx/storage','rexx/errors'
MODULE 'dos/dos'
/************************* main ***********************/
PROC main() HANDLE
DEF replyport:PTR TO mp
DEF node:PTR TO ln
DEF nom[64]:STRING
IF (rexxsysbase:=OpenLibrary('rexxsyslib.library',0))=NIL THEN Raise(0)
->Creation du port public
Forbid()
IF FindPort('Rexx_Comp')=0
IF replyport:=CreateMsgPort()
node:=replyport.ln
node.name:='Rexx_Comp'
node.pri:=0
AddPort(replyport)
ENDIF
ELSE
Raise()
ENDIF
Permit()
->Recherche du port 'rexx_ced'
Forbid()
IF FindPort('rexx_ced') THEN WriteF('Port "rexx_ced" Trouvé')
ELSE WriteF('Port "rexx_ced" introuvable')
Permit()
->Envoi de commande a cygnus
sendrexxcmd('rexx_ced',replyport,'STATUS 21',RXFF_RESULT,nom)
WriteF('Le fichier ouvert sous cygnus est ',nom)
->Fermeture des MsgPorts et des Libraries
RemPort(replyport)
DeleteMsgPort(replyport)
CloseLibrary(rexxsysbase)
EXCEPT
WriteF('error')
ENDPROC
/****************** sendrexxcmd **********************/
PROC sendrexxcmd(hostname,replyport:PTR TO mp,command,flags,retour)
DEF rxmsg:PTR TO rexxmsg
DEF replymsg:PTR TO rexxmsg
DEF rexx_command:LONG
DEF hostport:PTR TO mp
DEF node:PTR TO ln
-> Creation du message AREXX
node:=replyport.ln
IF (rxmsg:=CreateRexxMsg(replyport,NIL,node.name))=NIL THEN Raise(0)
IF rexx_command:=CreateArgstring(command,EstrLen(command))
CopyMem({rexx_command},rxmsg.args,4)
rxmsg.action:=RXCOMM OR flags
rxmsg.stdin:=Input()
rxmsg.stdout:=Output()
-> Envoi du message
Forbid()
hostport:=FindPort(hostname)
IF hostport THEN PutMsg(hostport,rxmsg)
Permit()
-> Recuperation du resultat
WaitPort(replyport)
replymsg:=GetMsg(replyport)
ELSE
WriteF('Problème d''envoi de commande Arexx')
ENDIF
StrCopy(retour,replymsg.result2,ALL)
ClearRexxMsg(rxmsg,16)
DeleteRexxMsg(rxmsg)
ENDPROC
|
|