CONTENTS | PREV | NEXT

Workshops / Hintergrundberichte
-------------------------------

1. ARexx-Kurs - Teil 4 (von Heiko Kuschel)

»ARexx-Kurs: Übersicht

1. Einführung in ARexx
    - Wie funktionierts?
    - Was brauche ich?
    - Installation
    - ein erstes kleines Programm
    - Ein- und Ausgabe
    - do...end

2. Programmstruktur und Ansteuerung von anderen Programmen
    - if
    - do...end
    - address
    - Tracing

3. Ein- und Ausgabe; Funktionen
    - Ein- und Ausgabe
    - Stringfunktionen
    - mathematische Funktionen
    - Konvertierungsfunktionen
    - Bitmanipulation

4. komplexere Programmstrukturen
    - Operatoren
    - Procedure
    - Libraries
    - sonstiges

5. Beispiele für die Vernetzung von Programmen
    - Wordworth
    - GoldEd
    - Database Professional
    - YAM
    - Miami
    - usw.

Änderungen vorbehalten. Spezielle Wünsche werden, wenn möglich, gerne 
aufgenommen.«


»4. Programmstrukturen und Systemfunktionen
4.0. Vorbemerkungen
Hier wiederhole ich für Quereinsteiger noch einmal einen Teil der
Vorbemerkungen, die ich zum ganzen Kurs gemacht habe.

Der Kurs wird als reine Text-Datei angefertigt, da auch Amiga aktuell u.a. 
in ASCII-Form verschickt wird. Um den Text etwas zu gliedern, habe ich 
daher ein paar "Textmarker" eingefügt.

********** unterteilt einzelne Abschnitte

__________ bezeichnet Beginn und Ende eines ARexx-Programms. Die Striche 
gehören nicht zum Programm!
ARexx-Befehle werden in diesem Kurs immer GROSS geschrieben, obwohl das
eigentlich nicht nötig ist. Auf diese Weise kann man sie aber leichter 
erkennen.

Ich hoffe, daß diese Regelung den Kurs etwas leserlicher macht.

Wenn Ihr spezielle Fragen habt, etwas nicht verstanden habt oder Anregungen 
und Ideen für weitere Kursteile habt, könnt Ihr euch gerne an mich wenden.
Ich selbst benutze folgende ARexx-fähige Programme und kann daher auf deren
Programmierung kurz eingehen, wenn das gewünscht wird:
Wordworth, GoldEd, Database Professional, YAM, Miami, Voyager, TurboCalc.

Hier meine Kontaktadresse:

Heiko Kuschel
Lehmgrubenweg 13
97280 Remlingen
E-Mail: hk0006@wuerzburg.baynet.de

Und jetzt... viel Spaß mit ARexx!

****************************************************
4.1. Operatoren
Ein schwierig klingendes Wort für eine Sache, die wir zum Teil schon ganz
selbstverständlich angewendet haben. Operatoren sind einfach die Zeichen, 
die zwei Variablen oder sonstige Ausdrücke auf irgendeine Art verknüpfen. 
Also z.B. ein simples +. Das Problem ist nur: Wie sollen diese Operatoren 
abgearbeitet werden, wenn mehrere in einem Ausdruck vorhanden sind? Aus 
Mathe kennst Du sicher noch "Punkt vor Strich": Erst mal und geteilt durch, 
dann plus und minus. In ARexx gibt es eine ganze Prioritätenliste der 
Operatoren, und auch hier gibt es welche, die wie Plus und Minus die 
gleiche Priorität haben. Diese Liste sieht folgendermaßen aus:

Operator    Pri.    Beschreibung
~           8       logisches "nicht"
+           8       als Präfix zur Konvertierung
-           8       Präfix
**          7       Potenzierung 2**6 meint "2 hoch 6"
*           6       Multiplikation
%           6       ganzzahlige Division
/           6       Division
//          6       Rest der Division
-           5       Subtraktion
+           5       Addition
Leerz.      4       Verkettung mit Leerzeichen
||          4       direkte Verkettung
~==         3       absolut ungleich
==          3       absolut gleich
~=          3       ungleich
=           3       gleich
>=          3       größer/gleich
>           3       größer
<=          3       kleiner/gleich
<           3       kleiner
&           2       logisches UND
|           1       logisches ODER
&&          1       logisches exklusiv ODER

Ich denke, es sollte kein Problem sein, diese Liste anzuwenden. Besonders
interessant finde ich, daß es gleich extra Operatoren für eine ganzzahlige 
Division gibt, ebenso wie für den Rest bei einer solchen Operation.

****************************************************
4.2. Programmstruktur
Bis jetzt haben wir nur Programme geschrieben, die mehr oder weniger von 
oben nach unten abgearbeitet wurden. Je komplexer Programme werden, desto 
wichtiger ist es aber, auch noch Überblick zu behalten. Deshalb gibt es in 
so gut wie allen Programmiersprachen die Möglichkeit, ein Programm in 
Unterabschnitte aufzuteilen, die dann (z.B. über einen aussagekräftigen 
Namen) aufgerufen werden.
Das Hauptprogramm ist dann oft nur noch dazu da, die Unterprogramme in der
richtigen Reihenfolge aufzurufen.

Der erste dafür notwendige Befehl lautet CALL.
CALL kann auf verschiedene Arten verwendet werden:

1. Aufruf einer ARexx-Funktion. Das Ergebnis wird in RESULT abgelegt
--------------------------------
CALL OPEN(Dateiname usw.)
ECHO RESULT
--------------------------------
ist gleichbedeutend mit
--------------------------------
Ergebnis=OPEN(Dateiname usw.)
ECHO Ergebnis
--------------------------------

2. Aufruf externer ARexx-Programme
Andere ARexx-Programme können mit CALL "rexx:MeinProg.rexx" gestartet 
werden.

3. Mit CALL kann in ein Unterprogramm verzweigt werden.
Das ist jetzt der Punkt, der für uns im Moment am interessantesten ist. Die
Unterprogramme werden alle mit Namen versehen. Dieser Name wird einfach in 
die erste Zeile einer Unterroutine geschrieben und ein Doppelpunkt 
angehängt. Die letzte Zeile der Unterroutine enthält dann ein RETURN (Kehre 
zurück). Nochmal ein Beispiel mit "HelloWorld" gefällig?
--------------------------------
/* Hello World Version 1.6.*/

CALL Fensteroeffnen
CALL FrageundAntwort
EXIT

Fensteroeffnen:
Erfolg=OPEN(Fenster,'CON:20/20/620/100/Hello World 1.6./CLOSE',R)
IF ~Erfolg THEN ECHO "Fehler!"
RETURN

FrageundAntwort:
DO WHILE Eingabe~="Ende"
  Erfolg=WRITELN(Fenster,"Gib was ein!")
  Eingabe=READLN(Fenster)
  Erfolg=WRITELN(Fenster,"Du hast "||Eingabe||" eingegeben.")
END
RETURN
--------------------------------

Beachte, wieviel kürzer und damit übersichtlicher selbst bei diesem Mini-
Programm das Hauptprogramm geworden ist!

Übrigens: So ganz nebenbei habe ich hier den Befehl EXIT eingefügt. Er 
beendet das ARexx-Skript. Soll das Skript an das aufrufende Programm einen 
Wert zurückgeben, kann man den auch definieren, z.B. EXIT 10. Wenn ein 
Skript einfach irgendwo aufhört und kein Befehl mehr nachfolgt, sieht der 
Interpreter das als EXIT 0 an. Der Rückgabewert, der normalerweise für 
Fehlermeldungen benutzt wird, ist dann 0.

Jetzt wäre es natürlich noch schön, wenn man sich bei der Erstellung der
Unterprogramme nicht immer darum kümmern müßte, welche Variablen im 
Hauptprogramm oder in anderen Unterprogrammen bereits verwendet wurden. 
Dann ist es z.B. sehr leicht möglich, einzelne Programmteile in anderen 
Skripten wiederzuverwerten, ohne irgend etwas daran verändern zu müssen. 
Und natürlich ist auch das möglich. Neben der einfachen Form von 
Unterprogrammen, wie wir sie gerade eingeführt haben, gibt es auch noch 
sogenannte Procedures, die völlig unabhängig vom Hauptprogramm arbeiten. 
Variablen im Hauptprogramm werden nicht verändert, außer man sagt es
ausdrücklich. So eine Procedure wird durch den Befehl PROCEDURE definiert. 
Sie endet mit dem Befehl RETURN, bei dem noch angegeben werden kann, ob der 
Wert einer Variable in RESULT abgelegt werden soll.

--------------------------------
/* Hello World Version 1.7.*/

CALL Fensteroeffnen
CALL FrageundAntwort
EXIT

Fensteroeffnen:
Erfolg=OPEN(Fenster,'CON:20/20/620/100/Hello World 1.6./CLOSE',R)
IF ~Erfolg THEN ECHO "Fehler!"
RETURN

FrageundAntwort:
DO WHILE Result~="Ende"
  CALL Eingabefrage
  CALL Ausgabe
END
RETURN

Eingabefrage:
 Erfolg=WRITELN(Fenster,"Gib was ein!")
RETURN

Ausgabe: PROCEDURE
 Eingabe=READLN(Fenster)
 Erfolg=WRITELN(Fenster,"Du hast "||Eingabe||" eingegeben.")
RETURN Eingabe
--------------------------------

Die Variable Eingabe existiert nur noch in der Prozedur Ausgabe! Versuche 
einmal herauszufinden, was diese Variable innerhalb des Hauptprogramms für 
einen Wert enthält!
(Noch nicht benutzte Variablen enthalten ihren eigenen Namen in 
Großschrift... nur so als kleiner Hinweis.)
Hinter PROCEDURE kann man nun auch noch angeben, welche Variablen aus dem
Hauptprogramm im Unterprogramm doch bekannt sein sollen.
Das sieht dann z.B. so aus:
Unterprogramm: PROCEDURE EXPOSE Variable Nocheine Unddiedritte Undsoweiter

An dieser Stelle möchte ich nun noch einen Befehl nachtragen, der 
eigentlich schon ein wenig früher sinnvoll gewesen wäre. Aber auch hier 
kann er gute Dienste leisten. Wenn nun abhängig von dem, was der Benutzer 
eingeben will, verschiedene Dinge ausgeführt werden sollen, dann kann man 
dafür natürlich lauter einzelne IF...THEN-Abfragen machen. Aber was tun, 
wenn ich 20 solcher Abfragen habe, und als letztes will ich eine Aktion für 
alles, was noch nicht extra abgefragt wurde?
Also z.B.: Wenn der Benutzer "ich" eingegeben hat, schreibe "Hallo Heiko!". 
Wenn der Benutzer "Schafkopf" eingegeben hat, schreibe "Wenz", usw. Und 
wenn er gar nichts von den Sachen eingibt, sondern was ganz anderes, dann 
schreibe "Wie kreativ! :-)"
Dafür gibt es den Befehl SELECT...END. Das schaut dann folgendermaßen aus:
--------------------------------
SELECT
    WHEN Eingabe="ich" THEN DO
        Erfolg=WRITELN(Fenster,"Hallo Heiko!")
        END
    WHEN Eingabe="Schafkopf" THEN DO
        Erfolg=WRITELN(Fenster,"Wenz!")
        END
    OTHERWISE DO
        Erfolg=WRITELN(Fenster,"Wie kreativ!")
        END
END
--------------------------------
Die Angabe von OTHERWISE ist notwendig, sonst gibt's eine Fehlermeldung!

****************************************************
4.3. Systemfunktionen

Die Systemfunktionen geben weitgehende Kontrolle über computerinterne 
Dinge. Sie werden wie alle Funktionen in ARexx entweder aufgerufen mit 
Ergebnis=Funktion(), oder aber, wie wir in diesem Kursteil gesehen haben, 
mit CALL Funktion(). Vorsicht! Manche sind schon sehr speziell, Du solltest 
wissen, was Du damit anstellst.

ADDLIB(Name,Priorität[,Offset,Version])
Hiermit lassen sich externe Bibliotheken (Libraries) in ARexx einbinden, 
die weitere Befehle zur Verfügung stellen. Solche Bibliotheken befinden 
sich normalerweise im Verzeichnis LIBS: und haben die Endung .library. Für 
ARexx sind leider meistens spezielle Abwandlungen dieser Libraries nötig. 
Im Aminet gibt es aber eine ganze Reihe sehr guter Libraries, z.B. 
rexxtricks.library, rexxsupport.library, rexxreqtools.library und andere. 
Wie diese im einzelnen arbeiten, kann ich hier kaum erklären, das würde zu 
weit führen. Die Befehle, die die Libraries zur Verfügung stellen, sind 
normalerweise gut dokumentiert. ARexx schaut dann bei Befehlen, die 
unbekannt sind, zunächst einmal in den angemeldeten Bibliotheken nach, ob 
dort der entsprechende Befehl zu finden ist. Erst dann wird versucht, über 
den ARexx-Port ein Programm zu finden, das diesen Befehl versteht.
Die Priorität gibt an, in welcher Reihenfolge in den Bibliotheken gesucht 
werden soll. Hoher Wert meint zuerst suchen. Gültig sind Werte zwischen 100 
und -100. Offset ist die Einsprungadresse für die QUERY-Funktion der 
Bibliothek. Ist normalerweise -30 und muß angegeben werden, damit alles 
funktioniert. Mit Version kann noch eine Versionsnummer der Bibliothek 
angegeben werden. Ist die Version der gefundenen Bibliothek kleiner, wird 
sie nicht akzeptiert.
Ein Beispiel, für das Du natürlich die rexxreqtools.library installiert 
haben mußt:

--------------------------------
IF ~SHOW("L",rexxreqtools.library) THEN DO
CALL ADDLIB("rexxreqtools.library", 0, -30, 0)
END
gadtxt= "_Weiter|_Cancel"
Eingabe = rtgetstring(" ","Bitte einen Text eingeben:","Hello World 
1.8.",gadtxt)
KnopfGedrückt=rtresult
--------------------------------
... oder in unser Hello World eingebaut, das mittlerweile gigantische 
Ausmaße annimmt:

--------------------------------
/* Hello World Version 1.8.*/
IF ~SHOW("L",rexxreqtools.library) THEN DO
  CALL ADDLIB("rexxreqtools.library", 0, -30, 0)
END
gadtxt= "_Weiter|_Cancel"
CALL Fensteroeffnen
CALL FrageundAntwort
EXIT

Fensteroeffnen:
Erfolg=OPEN(Fenster,'CON:20/20/620/100/Hello World 1.8./CLOSE',R)
IF ~Erfolg THEN ECHO "Fehler!"
RETURN

FrageundAntwort:
DO WHILE (Eingabe~="Ende")&(KnopfGedrueckt~="0")
  Eingabe = rtgetstring("","Bitte einen Text eingeben:","Hello World 
1.8.",gadtxt)
  KnopfGedrueckt=rtresult
  Erfolg=WRITELN(Fenster,"Du hast "||Eingabe||" eingegeben.")
END
RETURN
--------------------------------
Ich möchte hier darauf verzichten, rexxreqtools zu erklären. Schau Dir 
dieses kleine Beispiel und die zu rexxreqtools gehörige Anleitung an und 
probiere ein wenig herum damit.

Jetzt geht's erst mal weiter mit den Systemfunktionen:
ADDRESS()
ergibt den Namen des ARexx-Ports, an den im Moment die externen Befehle 
geschickt werden. Oft sinnvoll am Anfang eines Programms. Die einzige 
Möglichkeit, um z.B. bei einem aus Wordworth gestarteten Programm zu 
erfahren, wie denn nun der ARexx-Port tatsächlich heißt (Wordworth.1, 
Wordworth.2 usw.).

DATE(Option[,Datum,I|S])
Gibt die aktuelle Zeit als Zeichenkette zurück. Diese kann weitgehend durch
Optionen verändert werden (auf I|S komme ich gleich zu sprechen).
Diese Möglichkeiten gibt es, wobei T für Tag, M für Monat und J für Jahr 
steht:
Century      Tage seit Beginn des Jahrhunderts
Days         Tage seit Beginn des Jahres
European     TT/MM/JJ
Internal     Systemtage (seit dem 1.1.1978)
Julian       JJTTT (Tage seit Beginn des Jahres)
Month        englischer Monatsname
Normal       TT MMM JJJJ
Ordered      JJ/MM/TT
Sorted       JJJJMMTT
USA          MM/TT/JJ
Weekday      der Wochentag

Es reicht jeweils der erste Buchstabe als Angabe.

Durch Angabe des I oder S kann ein Datum, das im Internal- oder Sorted-
Format vorliegt, in jedes beliebige andere umgewandelt werden:
SAY DATE("E",19960428,"S")
Ein winziges Beispiel: Ein kleines Programm, das ich einmal täglich 
automatisch aufrufen ließ und das mir den aktuellen Stand meiner Hausarbeit 
auf die Diskette Hausarbeit_BAK: kopierte, und zwar jedesmal in ein neues 
Verzeichnis, das als Namen das aktuelle Datum hatte:
--------------------------------
/*Sicherheitskopie für Hausarbeit*/
Address Command
Datum=DATE("Sorted")
makedir "Hausarbeit_BAK:"Datum
copy "Text:BT-III/Texte/(Hausarbeit|Literaturverzeichnis).TXT 
Hausarbeit_BAK:"Datum
--------------------------------

ERRORTEXT()
Gibt eine kurze Beschreibung zu jeder Fehlernummer aus, die in ARexx 
auftreten kann.

EXPORT(Addresse[,String,Länge,Füllzeichen])
Hiermit kann der Inhalt eines String an eine 4-Byte-Adresse geschrieben 
werden. Der Speicher muß vorher reserviert werden! (Siehe GETSPACE)

FREESPACE([Addresse,Länge])
Gibt die mit GETSPACE reservierten Speicherbereiche wieder frei. Bei 
Verwendung der Argumente arbeitet die Funktion nicht ganz fehlerfrei. Sie 
wird am Ende des Programms sowieso ausgeführt, also vielleicht einfach 
weglassen, wenn Du nicht gerade 180 MB Speicher reserviert hast. Und wenn, 
dann besser ohne die Argumente, denn FREESPACE weiß, welcher Speicher ihm 
gehört.

GETCLIP(Name)
Liest eine Zeichenkette aus dem Clipboard.

GETSPACE(Länge)
Gibt einen Zeiger auf einen freien Speicherbereich zurück.

HASH(String)
Gibt den Hashwert des übergebenen Strings zurück. Das ist so eine Art 
Prüfsumme: Alle ASCII-Werte werden addiert, und das unterste Byte der Summe 
zurückgegeben.

IMPORT(Adresse[,Länge])
Liest Daten aus einem Speicherbereich. Ohne Angabe einer Länge wird bis zum
nächsten "00"x gelesen.

PRAGMA(Option[,Wert])
Damit kann man einige Einstellungen des Programms verändern bzw. abfragen. 
Folgende Optionen sind möglich (es reicht wieder die Angabe des ersten 
Buchstabens):
 Directory  gibt das aktuelle Verzeichnis des Programms zurück.
 ID         Zeiger auf die TaskControlBlock-Struktur
 Priority   Damit kann dem Prozeß eine andere TaskPriority gegeben werden.
            Vorsicht: REXXMAST hat 4! Nicht höher gehen!
            Werte zwischen -128 und 127 sind theoretisch möglich, normal    
            ist der Bereich von etwa -5 bis +3.
 Window     Damit kann der WindowPointer des Tasks verändert werden. Für    
            "Wert" können die Schlüsselworte "Null" oder "Workbench"        
            stehen.
 *          Der in Wert angegebene logische Name wird als aktueller *-      
            Console-Handler eingestellt.

REMLIB()
Entfernt eine Library wieder.

SETCLIP(Name[,Wert])
Setzt einen Eintrag in der Clipliste. Ohne Angabe eines Wertes wird der 
Eintrag gelöscht. Der Rückgabewert ist boolsch (0 oder 1).

SHOW(Option[,Name,Trennzeichen])
Option muß angegeben werden. Es gibt die folgenden Möglichkeiten:
  Clip      : alle Einträge in der Clip-Liste
  Files     : eine Liste der offenen logischen Dateinamen
  Internal  : die interne Port-Liste
  Libraries : die geöffneten Bibliotheken
  Ports     : die allgemeinen PublicMessagePorts, zu denen auch die
              ARexx-Ports gehören.
Es reicht jeweils die Angabe des ersten Buchstaben.

Wird ein Name angegeben, dann ändert SHOW() seine Funktion. Es gibt 1 
zurück, wenn der unter Name angegebene Port gefunden wurde, und 0, wenn er 
nicht gefunden wurde.
Beispiele im zweiten Kursteil unter 2.3.2

SOURCELINE([Zeile])
Liefert ohne Wertangabe die Zahl aller Zeilen im aktuellen Skript. Mit 
Angabe einer Nummer liefert es einen String, in dem die Zeile mit der 
entsprechenden Nummer steht.

STORAGE(Addresse[,String,Länge,Füllzeichen])
Schreibt den angegebenen String direkt in den Speicher. Ganz ohne Parameter
übergibt die Funktion den freien Systemspeicher.

SYMBOL(Name)
Damit kann getestet werden, ob es sich bei Name um ein gültiges ARexx-
Symbol (z.B. eine Variable) handelt. Folgende Rückgabewerte sind möglich:
BAD     war nichts: kein ARexx-Symbol.
LIT     es handelt sich um ein uninitialisiertes Symbol (eine Variable, der  
        noch kein Wert zugewiesen wurde).
VAR     Eine Variable, der ein Wert zugewiesen wurde.

TIME([Option])
Ähnlich wie DATE(), nur für die Uhrzeit. Folgende Optionen gibt es:
Civil     [h]h:mmxx (xx meint am oder pm)
Elapsed   Sekunden und Hundertstelsekunden seit der letzten Abfrage
Hours     Stunden seit Mitternacht
Minutes   Minuten seit Mitternacht
Normal    hh:mm:ss
Reset     wie Elapsed, löscht aber danach den Timer.
Seconds   Sekunden seit Mitternacht

TRACE(Option)
Gibt die aktuelle Trace-Einstellung zurück oder ändert je nach Option diese
Einstellung.

VALUE(Name)
Gibt den Inhalt einer Variablen zurück. Das ist dann nötig, wenn der 
Variablenname selbst eine Variable ist:
a="Hoppla, ist das kompliziert"
b="a"
SAY VALUE(a)
SAY VALUE("a")
SAY VALUE(b)

****************************************************
4.4. Ein paar Tips am Rande
Hier möchte ich noch schnell ein paar Tips loswerden, die dem einen oder 
der anderen von Euch vielleicht helfen können.

4.4.1. Start mit Piktogramm
Ein Piktogramm für ein ARexx-Skript ist mit den entsprechenden Programmen 
schnell erstellt. Es sollte vom Typ "Projekt" sein und als Standardprogramm 
einfach RX eingetragen haben. Dann steht einem Start per Doppelklick nicht 
mehr viel im Weg (außer vielleicht Programmfehlern...)

4.4.2. Start aus AmigaGuide
hier gibt einen Link mit dem Wort "hier". Ein Klick 
darauf startet das Skript "hier.rexx". Allerdings mußt Du für Ausgabe von 
Daten selber sorgen. ECHO funktioniert nicht so einfach. Aber Du hast ja 
inzwischen gelernt, wie man Fenster öffnet usw.

4.4.3. Anführungszeichen
Anführungszeichen sind eine heikle Geschichte in ARexx. Es gibt die zwei 
Arten ' (Alt-ä) und ". Beide sind völlig gleichbedeutend. Bei der 
Interpretation wird immer das äußerste Paar weggenommen. Aus "'" wird ' und 
umgekehrt. Und aus "Name" wird Name, was für ARexx ein gültiges Symbol 
(eine Variable!) ist! Im Endeffekt hilft hier nur 'rumprobieren und vor 
allem Tracen. Wenn was nicht funktioniert, mach mal noch ein paar 
Anführungszeichen außenherum. Beachte außerdem Groß- und Kleinschreibung! 
Außerhalb von Anführungszeichen macht ARexx so ziemlich alles
GROSS.

4.4.4. MUIRexx
MUIRexx ist ein Programm, das eine Schnittstelle zwischen ARexx und MUI 
(Magic User Interface) bildet. Es ist sehr leistungsfähig. Ich bin selber 
im Moment noch dabei, es zu verstehen, und hoffe, daß ich nächsten Monat 
ein kleines Programm damit präsentieren kann. Probiert's mal aus! Ebenfalls 
im Aminet erhältlich, genauso wie MUI.

4.4.5. Wordworth finden
Das ist gar nicht so einfach, denn jedes Fenster öffnet einen eigenen Port! 
Es gibt zwar auch noch den Port mit dem Namen WordworthLives, was 
wahrscheinlich bedeuten soll: Wenn dieser Port existiert, dann ist auch 
Wordworth aktiv. Aber sicher bin ich mir da nicht. Meine Lösung ist nicht 
sehr elegant, das muß ich zugeben. Aber sie funktioniert:

--------------------------------
DO Num = 1 to 20
        WwPort = "WORDWORTH." || Num
        IF SHOW(PORTS, WwPort) THEN DO
                Address Value WwPort
                leave Num
        end
end
if num=21 then do
    echo "Wordworth nicht gefunden! Programm endet."
    exit
    end
--------------------------------

So, das waren nun fast alle ARexx-Befehle, die es gibt. Im nächsten und 
letzten Kursteil werde ich einige wenige Befehle noch nachtragen und vor 
allem ein paar kleine Beispiele dafür geben, was mit ARexx alles möglich 
ist. Wer dafür Ideen oder fertige Skripte hat: Ich bin für Vorschläge und 
Unterstützung offen!
Ein kurzes persönliches Wort an diejenigen, die im Lauf des letzten Monats 
an mich geschrieben haben: Leider war ich im April sehr wenig zu Hause und 
hatte dann sehr viel zu tun, so daß ich noch nicht dazu gekommen bin, auf 
alles zu antworten. Ich werde aber alles noch beantworten! Vielen Dank für 
Eure Geduld.


****************************************************
4.5. Zusammenfassung der neuen Befehle

ADDLIB(Name,Priorität[,Offset,Version])
ADDRESS()
CALL
DATE(Option[,Datum,I|S])
ERRORTEXT()
EXIT
EXPORT(Addresse[,String,Länge,Füllzeichen])
FREESPACE([Addresse,Länge])
GETCLIP(Name)
GETSPACE(Länge)
HASH(String)
IMPORT(Adresse[,Länge])
PRAGMA(Option[,Wert])
PROCEDURE (EXPOSE)
REMLIB()
RETURN
SETCLIP(Name[,Wert])
SHOW(Option[,Name,Trennzeichen])
SOURCELINE([Zeile])
STORAGE(Addresse[,String,Länge,Füllzeichen])
SYMBOL(Name)
TIME([Option])
TRACE(Option)
VALUE(Name)                                                               «