Navigation
« 

Anonymous




Register
Login
« 
« 

Amiga Future

« 

Community

« 

Knowledge

« 

Last Magazine

The Amiga Future 168 will be released on the 5th May.

The Amiga Future 168 will be released on the 5th May.
The Amiga Future 168 will be released on the 5th May.

The Amiga Future 168 will be released on the 5th May.
More informations

« 

Service

« 

Search




Advanced search

Unanswered topics
Active topics
« 

Social Media

Twitter Amigafuture Facebook Amigafuture RSS-Feed [german] Amigafuture RSS-Feed [english] Instagram YouTube Patreon WhatsApp
« 

Advertisement

Amazon

Patreon

« 

Partnerlinks

ARexx-Kurs Teil 1, 2, 3

Description: Amiga Aktuell Ausgabe 2/98, 3/98 4/98

Categories: [DE] Workshops

Link to this article: Select all

[url=https://www.amigafuture.de/app.php/kb/viewarticle?a=1664&sid=ddf2be19afc95ab8a63c9c09280fb073]Artikeldatenbank - ARexx-Kurs Teil 1, 2, 3[/url]

[b]ARexx-Kurs - Teil 1 (von Heiko Kuschel)[/b]

»0. Zu diesem Kurs
ARexx ist eine mächtige Sprache, die auf dem Amiga viele Möglichkeiten eröffnet. Ich möchte Euch einen Überblick über die Programmiermöglichkeiten geben und bis zum Schluß des Kurses alle Befehle etc. kurz angeschnitten haben. Ich habe vor, den gesamten Kurs am Ende als AmigaGuide-Datei zusammenzufassen, so daß es leicht als Nachschlagewerk verwendet werden kann. Grundlegende Kenntnisse in Amiga-Dos (Shell) und in Programmieren (z.B.: Was ist eine Variable?) werden vorausgesetzt.

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.

1.1. Wie funktioniert ARexx?

ARexx ist eine Interpreter-Sprache. Das bedeutet: Das Programm wird während der Laufzeit von einem Interpreter, dem Programm Rexxmast, in Maschinensprache übersetzt. Anders z.B. die Programmiersprache C oder C++, wo jedes Programm zunächst compiliert (in Maschinensprache übersetzt) werden muß, bevor es lauffähig ist. Vorteil der Interpreter-Sprache: Die Programme sind sofort einsatzfähig. Nachteile: Sie sind relativ langsam, und sie benötigen den Interpreter, um laufen zu können.

Die große Besonderheit an ARexx ist, daß alle Befehle, die der Interpreter nicht versteht, an andere Programme weitergegeben werden können, die eine ARexx-Schnittstelle besitzen. Auf diese Weise kann man Programme "von außen" steuern und verschiedene Programme vernetzen. Wenn ein Programm einen guten ARexx-Port besitzt, sind die Möglichkeiten nahezu unbegrenzt.

1.2. Installation von ARexx

Um ARexx-Programme ausführen zu können, muß Rexxmast gestartet worden sein. Das kann manuell geschehen, indem man auf das Piktogramm in der Schublade System doppelklickt. Besonders praktisch ist es aber, Rexxmast gleich beim Starten des Amiga zu laden. Es verbraucht nur wenig Speicher und, solange es inaktiv ist, keine Rechenzeit. Ziehe dazu einfach das Rexxmast- Piktogramm aus der Schublade System in die Schublade WBStartup. Eine andere Möglichkeit ist, in der User-startup die folgende Zeile hinzuzufügen:

REXXMAST >NIL:

1.3. ARexx-Hilfsprogramme

Die Hilfsprogramme zu ARexx finden sich auf der Workbench im (normalerweise) unsichtbaren Verzeichnis Rexxc. In diesem Verzeichnis findest Du die folgenden Programme (und noch ein paar andere):
RX - startet ein ARexx-Programm (s.u.)
HI - hält alle laufenden ARexx-Programme
sofort an
RXC - beendet Rexxmast
TCO - "Trace Console Open": öffnet
ein Trace-Fenster zur
Fehlersuche im Programm
TCC - "Trace Control Close" - schließt das
Trace-Fenster
TS - "Trace Start" - jeder abgearbeitete Befehl
wird mit Ergebnis ausgegeben.
TE - "Trace End" - beendet das Tracing
WaitForPort - Es wird 10 Sekunden auf den angegebenen
ARexx-Port gewartet.
Dazu später mehr (in einem anderen
Kursteil).

Alle diese Programme werden normalerweise über die Shell gestartet. Das wichtigste Programm ist natürlich RX. Um ein ARexx-Programm mit dem Namen "Test" zu starten, gibst Du in einer Shell einfach ein:



rx Test

Dabei sucht rx zunächst im Verzeichnis Rexx: nach Test, dann auch nach Test.rexx. Die Endung .rexx, die normalerweise an ARexx-Skripte angehängt wird, kann also beim Aufruf mit rx auch weggelassen werden. Vorsicht: Die Länge des Pfades ist begrenzt. Ich weiß leider nicht mehr, wo ich das gelesen habe, und kann daher die genaue Zahl der erlaubten Zeichen nicht sagen. Wenn also ein Aufruf einmal nicht funktioniert, probiere es doch einmal mit einer kürzeren Pfadangabe, indem Du vorher ins entsprechende Verzeichnis wechselst.

Neben diesen Hilfsprogrammen benötigst Du natürlich einen Editor, mit dem Du das Programm schreiben kannst. Dafür eignet sich jeder Texteditor. Ich persönlich benutze GoldEd (Aminet). Zur Not tut's auch Ed, der zum Betriebssystem gehört.
Auch eine Textverarbeitung (Wordworth, Final Writer...) kann benutzt werden, wenn Du darauf achtest, das Programm immer als ASCII-Datei abzuspeichern.

1.4. Das erste Programm

So, die Grundlagen sind Dir nun schon bekannt. Jetzt geht's richtig los. Das erste Programm ist natürlich in jeder Programmiersprache "Hello World". Ein einfaches Programm, das den Text "Hello World" (Hallo Welt) auf dem Bildschirm ausgibt. Jedenfalls habe ich damit bis jetzt noch so gut wie jede Programmiersprache begonnen...

Dazu benötigen wir nur einen Befehl. Er lautet ECHO. Groß- und Kleinschreibung ist bei ARexx egal. eCHo ist dasselbe wie EchO. In diesem Fall ist allerdings auch SAY dasselbe wie ECHO. Beide Befehle sind absolut gleichbedeutend.

--------------------------------
ECHO "Hello World"
--------------------------------


ist schon ein fast vollständiges ARexx-Programm. Wenn Du es allerdings unter dem Namen HelloWorld.rexx abspeicherst und dann aus einer Shell mit "rx HelloWorld.rexx" aufrufst, würde RX sich darüber beschweren mit der Fehlermeldung: Command returned 5/1: Program not found. Das liegt daran, daß RX immer zuerst prüft, ob die Datei mit einem ARexx-Kommentar beginnt. Ein solcher Kommentar wird eingeleitet mit /* und beendet mit */. Ein fertiges Programm sieht also folgendermaßen aus:

--------------------------------
/* Hello World Version 1.0. */
ECHO "Hello World"
--------------------------------


Probier's einfach mal aus! Speichere dazu dieses Programm unter einem beliebigen Namen, z.B. Ram:Test.rexx
Dann startest Du es aus einer Shell mit rx ram:Test.rexx

1.5. Etwas komplizierter: Variablen

Natürlich kann das nicht der ganze Lernerfolg dieses Kursteils sein. Aber schließlich kann man dieses Programm sehr leicht noch etwas komplizierter machen. Wie wäre es mit einem Programm, das genau das ausgibt, was man ihm eingegeben hat? Dazu benötigen wir natürlich eine Variable. Das Schöne an Variablen in ARexx: Es gibt nur eine Art davon. Wir müssen uns nicht mit Long, Integer, Word etc. herumschlagen, noch nicht einmal mit Strings. Jede Variable kann jeden Wert annehmen, egal ob Text oder Zahl.
Der Name einer Variable darf keinen Punkt enthalten und nicht mit einer Ziffer beginnen.


a) Zahl=1.2443

b) Zahl="Das ist eine Zahl, oder etwa nicht?"

Das ist beides möglich. Der Variablentyp wird intern bestimmt und nötigenfalls, wenn irgend möglich, bei weiteren Operationen angepaßt.

c) Zahl=Zahl+Zahl


Das ist allerdings nur im Fall a) möglich! Im Fall b) erhält man die Fehlermeldung: Command returned 10/47: Arithmetic conversion error Zeichenketten werden stattdessen durch das Zeichen || verknüpft (zwei gerade Striche nacheinander).

--------------------------------
Zahl=Zahl||Zahl
ECHO Zahl
--------------------------------


funktioniert im Fall b)
... was wird wohl im Fall a) herauskommen? Probiere es aus! (Vergiß nicht, eine Kommentarzeile an den Anfang zu setzen! Mindestens /**/, das genügt schon.)

... und was steht in einer Variable, der noch kein Wert zugewiesen wurde? Versuche es einmal!

Nun brauchen wir noch einen Befehl, der es uns ermöglicht, den Benutzer nach einer Eingabe zu fragen, und diese Eingabe auch im Programm weiterzuverwerten.
Dieser Befehl heißt PARSE. PARSE ist ein sehr komplexer Befehl, den wir erst in einem weiteren Kursteil eingehender behandeln werden. Heute genügt es zu wissen, daß PARSE PULL [variable] eine Eingabe von stdin (normalerweise dem Konsolenfenster=Shell) erwartet und in [variable] ablegt.
Also:

--------------------------------
/* Hello World Version 1.1. */
ECHO "Gib was ein!"
PARSE PULL Eingabe
ECHO Eingabe
--------------------------------

PULL alleine (ohne PARSE) ist die Abkürzung von PARSE UPPER PULL. Probiere einmal den Unterschied aus!

--------------------------------
/* Hello World Version 1.2. */
ECHO "Gib was ein!"
PULL Eingabe
ECHO Eingabe
--------------------------------

1.6. Strukturanweisungen

Wäre doch schön, wenn unser Programm uns nicht nur einmal nach einer Eingabe fragen würde, sondern beliebig oft, oder? Dafür gibt es den Befehl DO...END. DO steht jeweils am Anfang einer Gruppe von Befehlen, END am Ende, wie der Name schon sagt. Dabei kann DO noch eine ganze Reihe von Bedingungen mitgegeben werden. Das sieht dann folgendermaßen aus:

DO (Bedingungen)
ARexx-Befehle
END




Dieser Abschnitt zwischen DO und END wird intern wie ein einziger Befehl behandelt.

Folgende Bedingungen können dem Befehl DO mitgegeben werden (ich habe jedesmal gleich ein Beispiel dazugenommen):

DO Zaehler=1 TO 10 BY 2 FOR 3
Die Variable Zaehler wird auf den Wert 1 gesetzt und die Schleife durchlaufen.
Am Ende wird sie um 2 erhöht und die Schleife erneut durchlaufen, usw., bis der Wert 10 erreicht ist. Mit FOR kann die maximale Anzahl der Durchläufe festgelegt werden, auch wenn der Endwert noch nicht erreicht ist.


DO FOREVER ist, denke ich, ziemlich klar...

DO UNTIL Eingabe="Ende"
Durchläuft die Schleife, bis die Variable Eingabe den Wert Ende erhält.

DO WHILE Eingabe ~="Ende"
Durchläuft die Schleife, solange die Variable Eingabe nicht den Wert Ende erhält. Die Tilde ist das Negationszeichen in ARexx. ~= bedeutet also so viel wie "nicht gleich".

Mit LEAVE kann die Schleife vorzeitig verlassen werden. Besonders wichtig bei DO FOREVER...

Nun versuche einmal selbst, ein Programm zu schreiben, das so lange nach einer Eingabe fragt, bis Du "Ende" eingibst! Eine mögliche Lösung gibt's dann im zweiten Teil... Viel Spaß!

Das war nun der erste Teil des ARexx-Kurses. Es war mehr ein erstes Herantasten an ARexx, ein Kennenlernen der Strukturen. Nächstes Mal geht's dann richtig rund!

1.7. Zusammenfassung der kennengelernten Befehle

/* */
~ (Negation)
ECHO
SAY
PARSE PULL
PARSE UPPER PULL
(Kurzform: PULL)
DO var=Anfangswert TO Endwert BY Differenzwert FOR MaxDurchläufe
DO FOREVER
DO WHILE
DO UNTIL
END
LEAVE

[b]ARexx-Kurs - Teil 2 (von Heiko Kuschel)[/b]

2. Programmstrukturen und Ansteuerung von externen Programmen

2.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 oder Anregungen und Ideen für weitere Kursteile habt, könnt Ihr Euch gern 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!

****************************************************


2.1. Die "Hausaufgabe" vom letzten Mal
Im letzten Kursteil ging es um Programmschleifen mit dem Befehl DO...END. Wie kann man nun eine Schleife so programmieren, daß sie dann abbricht, wenn man "Ende" eingibt? Dazu gibt es mehrere Möglichkeiten: Mit DO UNTIL, DO WHILE, aber auch mit DO FOREVER.
--------------------------------
/* Hello World Version 1.3.*/
DO UNTIL Eingabe="Ende"
ECHO "Gib was ein!"
PARSE PULL Eingabe
ECHO "Du hast "||Eingabe||" eingegeben."
END
--------------------------------
--------------------------------
/* Hello World Version 1.4.*/
DO WHILE Eingabe~="Ende"
ECHO "Gib was ein!"
PARSE PULL Eingabe
ECHO "Du hast "||Eingabe||" eingegeben."
END
--------------------------------

Die Tilde ~ ist das Negationszeichen in ARexx. ~= heißt soviel wie "ist nicht gleich".
Die zwei senkrechten Striche verknüpfen Zeichenfolgen miteinander. Die Einrückungen sind zwar nicht nötig, erhöhen aber die Übersichtlichkeit.

Wozu nun diese zwei verschiedenen Möglichkeiten, das offenbar gleiche auszudrücken (DO WHILE, DO UNTIL)?
Es gibt einen Unterschied zwischen den beiden:

DO WHILE überprüft die Bedingung am Anfang der Schleife,
DO UNTIL überprüft die Bedingung, wenn ARexx bei END angekommen ist.
Das heißt: mit DO UNTIL wird die Schleife in jedem Fall einmal durchlaufen, mit DO WHILE kann es passieren, daß ARexx sofort nach END weitermacht, falls die Bedingung nicht erfüllt ist.

Kapiert? Wenn nicht, probiere einmal, in beiden Versionen als erste Zeile nach dem Kommentar einzufügen:
--------------------------------
Eingabe="Ende"
--------------------------------

In Hello World 1.4. wird gar nichts passieren! Die Schleife wird übersprungen, denn die Bedingung ist schon erfüllt. Hello World 1.3. dagegen geht brav in die Schleife rein... und bis zum END hat sich der Wert von Eingabe schon wieder verändert.

Jetzt fehlt uns allerdings noch die dritte Möglichkeit, Schleifen zu programmieren: DO FOREVER.
Um hier eine Abfrage machen zu können, brauchen wir aber noch einen neuen Befehl. Wir müssen ARexx ja etwas in der Art mitteilen können: "Wenn Eingabe gleich "Ende" ist, dann verlasse bitte die Schleife. Und wenn nicht, dann gib die Eingabe aus."
Dieser Befehl heißt sinnvollerweise IF... THEN (...ELSE) Nach dem THEN darf allerdings nur ein einziger Befehl stehen! Wie soll man das anstellen? Oft genug muß nach so einer Abfrage doch eine ganze Menge im Programm geregelt werden. Ganz einfach: Im ersten Teil des Kurses habe ich so einen seltsamen Satz geschrieben: "Dieser Abschnitt zwischen DO und END wird intern wie ein einziger Befehl behandelt." Na, kapiert? Jawohl! Wenn nach dem THEN mehrere Befehle folgen sollen, muß vor dem ersten Befehl ein DO und nach dem letzten dieser Befehle ein END stehen.
Heiko Strohmeier hat mir dafür ein Beispiel geliefert. (Danke, Heiko!) Er hat's wagemutig mit DO FOREVER und IF...THEN probiert und das Ganze auch sehr gut gemacht:
--------------------------------
/**/
DO FOREVER
ECHO "Gib Ende für Quit ein"
PARSE PULL Eingabe

IF Eingabe="Ende" THEN
ECHO "Die eingabe war richtig "||Eingabe
LEAVE

IF Eingabe ~="Ende" THEN
ECHO "Die eingabe war falsch "||Eingabe
END
--------------------------------
Das ist schon eine ganze Menge, aber es fehlt
DO... END, um funktionieren zu können. Also:
--------------------------------
/**/
DO FOREVER
ECHO "Gib Ende für Quit ein"
PARSE PULL Eingabe

IF Eingabe="Ende" THEN DO
ECHO "Die Eingabe war richtig "||Eingabe
LEAVE
END

IF Eingabe ~="Ende" THEN DO
ECHO "Die Eingabe war falsch "||Eingabe
END
END
--------------------------------

Übrigens: IF...THEN kann auch noch mit ELSE
(ansonsten) weitergeführt werden. Eine kleine
Änderung des obigen Skripts:
--------------------------------
/**/
DO FOREVER
ECHO "Gib Ende für Quit ein"
PARSE PULL Eingabe

IF Eingabe="Ende" THEN DO
ECHO "Die Eingabe war richtig "||Eingabe
LEAVE
END
ELSE DO
ECHO "Die Eingabe war falsch "||Eingabe
END
END
--------------------------------


****************************************************


2.2. Eine kleine "ARexx-Shell" Aus diesem Skript können wir nun sehr leicht ein Skript machen, das uns die Arbeit mit ARexx sehr erleichtert. Wie wäre es mit einer Art Shell, die ähnlich wie die DOS-Shell der Workbench Befehle direkt interpretiert, wenn man sie eingibt?
Auch dafür gibt es einen Befehl:
INTERPRET Variable
Variable wird dabei als ARexx-Befehl angesehen und direkt ausgeführt.
Also...
--------------------------------
/*Interpreter V1.0.*/
DO FOREVER
PARSE PULL Eingabe
IF Eingabe="Ende" THEN LEAVE
INTERPRET Eingabe
END
--------------------------------

Tip: Speichere dieses Programm irgendwo auf Festplatte, und nimm "rx (Name des Programms)" in Deine HotKey-Liste auf, falls Du ein Programm hast, das andere Programme auf Tastendruck startet!

****************************************************


2.3. Ansteuern von anderen Programmen
2.3.1. ADDRESS

Wir haben zwar noch lange nicht alle Möglichkeiten von ARexx selbst ausgeschöpft. Trotzdem möchte ich schon jetzt darauf eingehen, wie Programme angesteuert werden können, die einen ARexx-Port zur Verfügung stellen. Denn einfache Skripte kannst Du jetzt schon selbst schreiben, und am meisten lernt man meiner Erfahrung nach, wenn man selber was ausprobiert. Und wenn's Probleme gibt... Meine Adresse steht am Anfang des Kurses.

Um ARexx mitzuteilen, welches Programm angesteuert werden soll, benötigen wir den Befehl ADDRESS. Die ARexx-Adresse (ARexx-Port), die dann folgen muß, entnimmst Du der Dokumentation des jeweiligen Programms. Z.B.:
ADDRESS YAM
ADDRESS Wordworth.1
ADDRESS TCALC
ADDRESS GOLDED.1

Eine Liste der vorhandenen Ports erhältst Du mit ECHO SHOW("PORTS") Gib das mal in der ARexx-Shell ein! Der Befehl wird weiter unten genauer erklärt.

Nach dem Befehl ADDRESS YAM werden alle Anweisungen, die ARexx nicht versteht, an die YAM-Schnittstelle weitergeleitet. Wenn nun YAM zufällig einen Befehl haben sollte, der auch als ARexx-Befehl existiert, mußt Du ihn in Anführungszeichen setzen, damit er nicht von ARexx selbst interpretiert wird.

ADDRESS COMMAND hat eine besondere Bedeutung: Damit können Shell-Befehle aufgerufen werden.
--------------------------------
ADDRESS COMMAND DIR
--------------------------------

listet das aktuelle Verzeichnis auf.
--------------------------------
ADDRESS COMMAND
DIR
--------------------------------

hat prinzipiell die gleiche Bedeutung. Im ersten Fall wird aber nur eben schnell der Befehl DIR an COMMAND übergeben, im zweiten Fall wird die Schnittstelle als COMMAND definiert und alle weiteren Befehle an COMMAND geschickt.

Also: Ich habe ein Programm, mit dem ich z.B. YAM steuere. Zwischendurch benötige ich einen einzigen COMMAND-Befehl. Dann schreibe ich ihn direkt hinter ADDRESS COMMAND, und alle folgenden Befehle gehen wieder an YAM.
------------------------ ------------------------
ADDRESS YAM ADDRESS YAM
(Befehle gehen an YAM) (Befehle gehen an YAM)
ADDRESS COMMAND DIR ADDRESS COMMAND
DIR
(Befehle gehen an YAM) (Befehle gehen an COMMAND)
------------------------ ------------------------

(Wenn Du einen proportionalen Zeichensatz installiert hast, wirst Du diesen Vergleich nicht ganz so gut betrachten können. Sorry!)

ADDRESS kann auch noch ein paar Parameter mit auf den Weg bekommen: ADDRESS VALUE Variable

interpretiert Variable als solche und nimmt den Inhalt der Variablen als neuen ARexx-Port. Z.B.:
--------------------------------
Var="YAM"
ADDRESS VALUE Var
--------------------------------

Alle Befehle gehen an YAM.P> ADDRESS ohne weitere Angaben schaltet auf den vorhergehenden ARexx-Port zurück.


****************************************************


2.3.2. SHOW()
Wie kann ich nun aber feststellen, ob ein ARexx-Port wirklich existiert, ob z.B. YAM bereits gestartet ist? Dazu benötige ich wieder den Befehl SHOW(). 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 Buchstabens.

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.
Also:
--------------------------------
YAM-Existiert=SHOW("P",YAM)
--------------------------------

Die dritte Möglichkeit ist die, ein beliebiges Trennzeichen für die Liste anzugeben. Am sinnvollsten ist ein "Wagenrücklauf", was der Return-Taste entspricht. Er hat den ASCII-Code 10 und wird angegeben als D2C(10) (Warum, erkläre ich im nächsten Kursteil.)
--------------------------------
ECHO SHOW("P",,D2C(10))
--------------------------------


****************************************************


2.3.3. WaitForPort
Wenn ein Programm neu gestartet wird, dauert es evtl. eine Weile, bis der ARexx-Port eingerichtet ist. Dafür gibt es den DOS-Befehl sys:rexxc/WaitForPort, der maximal 10 Sekunden wartet, bis der ARexx-Port da ist.

ADDRESS COMMAND sys:rexxc/WaitforPort YAM
wartet auf die Einrichtung des Ports YAM und macht dann weiter.


****************************************************


2.3.4. OPTIONS, RESULT und RC

Jetzt brauchen wir noch die Möglichkeit, Werte aus Programmen in ARexx zu übernehmen. Das geschieht auf folgende Weise:

a)
Ein Befehl wird an ein Programm geschickt, der einen Rückgabewert verlangt. Z.B. den Inhalt einer Zelle in TurboCalc. TurboCalc setzt diesen Befehl in die Variable RESULT (Ergebnis). In ARexx kann mit der Variable RESULT weitergearbeitet werden.

b)
Ein Befehl wird an ein Programm geschickt.
Der Befehl verursacht einen Fehler
Die Variable RC (Return Code - Rückgabecode) wird auf einen definierten
Wert gesetzt, der größer als 0 ist.
Wenn der Befehl anfällig für Fehler ist, kann man nun eine kleine
Fehlerabfrage einbauen: IF RC~=0 THEN...

c) Der Befehl ist so definiert, daß er sein Ergebnis (einen Zahlenwert) in RC ablegt. Das ist meines Erachtens zwar nicht ganz korrekt, aber durchaus nicht unüblich.
Beispiel: ISONLINE in Miami liefert 0 oder 1 in RC, je nachdem, ob Miami online ist oder nicht.

Achtung: Diese Variablen funktionieren nur, wenn vorher die entsprechende Option eingeschaltet wurde! Das geschieht mit:
OPTIONS RESULTS
Was soviel bedeutet wie: Gib mir Ergebnisse von anderen Programmen zurück.

Die anderen Optionen liefere ich am Ende des Kursteils nach. Sie sind jetzt gerade weniger interessant.


****************************************************


2.4. Erste Skripte mit anderen Programmen: Zwei Beispiele 2.4.1. Postholen.rexx
Nun können wir schon ein paar kleine Programme schreiben. Ein Beispiel: Ein Skript, das




nachsieht, ob YAM gestartet ist, wenn nicht, dann YAM startet
das gleiche für Miami
online geht
Post aus der Warteschlange verschickt
Post vom Server holt
nochmal nachschaut, ob inzwischen noch mehr Post eingetroffen ist
YAM schließt, falls keine neue Post eingetroffen ist
offline geht
Miami wieder schließt.


... und so schaut das aus:
(Ich habe die Nummern der einzelnen Schritte in Kommentarzeilen mit ### eingefügt.)
--------------------------------
/* Post abholen mit Miami und YAM */
/* Version 1.0. 9.7.97 Heiko Kuschel */
OPTIONS RESULTS
YAMON=1
MIAMION=1
MIAMIONLINE=0
/*Bis hierher werden nur die Variablen so gesetzt, daß*/
/*YAMON=1: angenommen wird, daß YAM gestartet ist */
/*MIAMION=1: das gleiche für Miami */
/*MIAMIONLINE=0: Miami ist offline */


/* ############ Teil 1 ############ */
if ~show(PORTS, YAM) then do
address command
"run Comm:YAM/YAM"
/*Diese Zeile mußt Du ändern!*/
"sys:rexxc/waitforport YAM"
YAMON=0
end
/* Wenn YAM nicht bereits gestartet ist, dann*/
/* starte es */
/* warte auf den ARexx-Port von YAM */
/* merke dir, daß YAM nicht gestartet war */
/* Natürlich mußt Du den Pfad entsprechend */
/* anpassen. */

/* ############ Teil 2 ############ */
if ~show(PORTS, MIAMI.1) then do
Address command
"run Comm:miami11a/miami"
"sys:rexxc/waitforport MIAMI.1"
MIAMION=0
end
/* Genau wie bei YAM. */

/* ############ Teil 3 ############ */
address Miami.1
isonline
if RC=1 then do
MIAMIONLINE=1
end
else do
ONLINE
end
/*Hier sind zwei Befehle drin, die zum Befehlsschatz */
/*von Miami gehören: */
/*ISONLINE gibt RC=0 oder 1 zurück */
/*ONLINE geht online. */
/*Die Zeile MIAMIONLINE=1 merkt sich, daß Miami schon*/
/*online war. Sonst wird am Ende des Programms u.U. */
/*eine Verbindung unterbrochen, wo doch Dein Browser */
/*gerade 98% einer 3-Megabyte-Datei geladen hatte... */

/* ############ Teil 4 ############ */
address YAM
Mailsendall
/* ############ Teil 5 ############ */
Mailcheck
if RESULT>0 then YAMON=1
/* ############ Teil 6 ############ */
Mailcheck
if RESULT>0 then YAMON=1
/* ############ Teil 7 ############ */
if YAMON=0 then quit
/*Das ist der Teil, in dem eigentlich was passiert. */
/*Mailsendall ist ein YAM-Befehl, der alle anstehenden*/
/*Mails sendet. */
/*Mailcheck holt Post ab und gibt in RESULT die Anzahl*/
/*der Mails zurück. */
/*Wenn mehr als 0 Mails abgeholt wurden, dann wird die*/
/*Variable YAMON auf 1 gesetzt. YAM wird dann am Ende */
/*nicht geschlossen, damit Du die neuen Mails auch */
/*lesen kannst. */

/* ############ Teil 8 ############ */
Address MIAMI.1
if MIAMIONLINE=0 then do
offline
end
/*Wenn Miami vorher nicht online war, */
/*geht es jetzt auch wieder offline. */
/* ############ Teil 9 ############ */
if MIAMION=0 then do
quit
end
/*Und wenn Miami gar nicht gestartet war, */
/*wird es jetzt wieder beendet. */
--------------------------------

Das Ganze funktioniert leider noch nicht mit YAM 2.0., da dort ARexx noch nicht vollständig implementiert ist. Wenn Du das Skript nutzen willst, mußt Du es mit YAM 1.3.x tun.

Achtung: Lasse das Skript nicht unbeaufsichtigt laufen!
Wenn beim Aufbau der Verbindung ein Fehler auftritt, meldet Miami das mit einem Requester und bleibt so lange online, bis Du auf "OK" geklickt hast. Wenn Du erst nach ein paar Stunden zurückkommst, hast Du eine ziemlich hohe Telefonrechnung... Sobald Miami erst mal online ist, vertraue ich selber meinem Skript. (Bei mir dauert das Laden manchmal eine Stunde.)


****************************************************


2.4.2. Dokumente-Drucken.rexx
Da vermutlich nicht alle hier eine Internet-Verbindung haben, noch ein praktisches Beispiel für Wordworth, an dem ich gleichzeitg noch ein paar Dinge zeigen will
. Dieses Skript tut folgendes:


nach einem beliebigen Dokument fragen
fragen, ob noch ein weiteres Dokument gedruckt werden soll Schritte 1-2 wiederholen, bis bei 2. "nein" angeklickt wird
ein Dokument nach dem anderen laden und drucken.


Dazu benötigen wir allerdings noch eine neue Information. Also bitte ich alle, die kein Wordworth haben, trotzdem noch den nächsten Absatz zu lesen! Variablen können in ARexx wie in vielen anderen Sprachen mehrere Dimensionen haben. Das sieht folgendermaßen aus: Name.Nummer - Damit kann man schon eine kleine Datenbank realisieren...

Name.1="Meyer"
Strasse.1="Meyerstraße 11"
Name.2="Hagenbüchel"
Strasse.2="Briefkastenstr. 188"

Kapiert? An den Namen der Variablen wird ein Punkt angehängt, danach kommt eine Zahl. Jeder Name in Verbindung mit jeder Zahl ist eine eigene Variable mit einem eigenen Wert!

Das Schöne in ARexx, im Gegensatz zu den meisten anderen Sprachen, die ich kenne:

Du mußt ARexx nicht von vornherein sagen, welches die höchste Zahl ist. Und man kann auch dem "Stamm" (so heißt der Teil der Variable, den ich als "Name" bezeichnet habe) einen Wert zuweisen, der dann für alle Untervariablen gilt.
Z.B.:
--------------------------------
PLZ.=97280 /*Beachte den Punkt!*/
Zahl=12
echo PLZ.1
echo PLZ.10
echo PLZ.Zahl
echo PLZ.PLZ
--------------------------------

Im letzten Fall wird der Wert der Variablen PLZ.97280 ausgegeben... und der ist auch 97280!
Auch mehrdimensionale Variablen sind möglich: Variable.Zahl.Zahl2

Und nun zu dem Programm. Es ist übrigens mit Dokumentation auch im Aminet zu haben, unter util/rexx/WW-Print.lha

Außerdem sind noch zwei String-Funktionen drin, die eigentlich erst nächstes Mal behandelt werden sollen. Es sind: LASTPOS(Buchstabe,Zeichenkette) gibt die Position des Buchstabens an, an der er zum letzten Mal in einer Zeichenkette auftritt.
--------------------------------
Position=LASTPOS("e","Heiko Kuschel")
ECHO Position
--------------------------------

ergibt 11 LEFT(Zeichenkette,Zahl) ergibt den linken Teil einer Zeichenkette, bis zum xten Zeichen.
--------------------------------
ECHO LEFT("Heiko Kuschel",6)
--------------------------------

ergibt "Heiko"
--------------------------------
/* Wordworth 5 ARexx-Skript zum
Drucken beliebig vieler Dateien */
/* Heiko Kuschel 27. Juni 1996 */
/* basierend auf WW5-Skript von
MJ (Digita) */
/* FREEWARE, falls Digita kein Copyright
beansprucht. */
OPTIONS RESULTS

Nummer=0
Pfad =""
DO forever
Nummer=Nummer+1

RequestFile TITLE "Zu druckendes Dokument wählen..." PATH Pfad
File.Nummer = Result
/*RequestFile ist ein Wordworth-Befehl. Mit der Option PATH kann
wahlweise angegeben werden, welcher Pfad im Requester voreingestellt
sein soll.*/
/*Das Resultat der Abfrage steht in RESULT. RC ist größer 0,
wenn Abbruch */
/*gewählt wurde.*/
/*Dieses Skript geht davon aus, daß es
direkt aus Wordworth gestartet */
/*wurde. Dann ist ADDRESS überflüssig, die Adresse
ist bereits richtig */
/*gesetzt. Da Wordworth für jedes Textfenster einen eigenen
ARexx-Port*/
/*aufmacht, ist es auch ziemlich schwierig herauszufinden,
welchen man */
/*adressieren kann. Wenn ich in WW das erste Fenster schließe,
geht der */
/*ARexx-Port mit dem Namen Wordworth.1 mit flöten.
Dann kann ich natürlich*/
/*nicht einfach ADDRESS Wordworth.1 schreiben.
Ziemlich kompliziert, wie */
/*gesagt. :-( */

Strich=Lastpos("/",File.Nummer)
Pfad=""
if (Strich>0) then Pfad=Left(File.Nummer,(Strich-1))
/*Hier "extrahiere" ich den Pfad des zuletzt
gewählten Dokuments, damit */
/*der Benutzer sich nicht jedesmal durch alle Verzeichnisse und */
/*Unterverzeichnisse durchwühlen muß. Er findet sich
im nächsten*/
/*Requester (wenn weitere Dokumente ausgewählt werden)
wieder im */
/*gleichen Verzeichnis, in dem er bereits war. */
if (RC > 0) THEN Exit
/*Wenn im File-Requester "Abbruch" geklickt wurde, wird
das Programm mit */
/*EXIT vollständig abgebrochen.*/

RequestResponse PROMPT "Möchten Sie ein weiteres Dokument drucken?"
if (RC > 0) THEN leave
/*Frage danach, ob ein weiteres Dokument gedruckt werden
soll. Wenn nein, */
/*wird die DO FOREVER-Schleife mit LEAVE verlassen, wenn
doch, geht's */
/*oben wieder weiter... mit dem Pfad des zuletzt
gewählten Dokuments */
/*als Vorgabe. */

END

New
Address Value Result
/*NEW öffnet ein neues Fenster in Wordworth und
gibt in Result den */
/*ARexx-Port zurück. Jedes Wordworth-Fenster hat
einen eigenen Port: */
/*Wordworth.1, Wordworth.2 usw. */

Do Zaehler=1 to Nummer
Open FILENAME File.Zaehler
Print
end
/*In File.1 steht der Name des ersten zu druckenden
Dokuments, */
/*in File.2 der des zweiten usw. */
Close FORCE

--------------------------------


****************************************************


2.4.3. Hinweise fürs eigene 'rumexperimentieren Leider sind die ARexx-Ports bei manchen Programmen etwas gewöhnungsbedürftig.
Database Professional akzeptiert Befehle offenbar nur in GROSSBUCHSTABEN. Wordworth gibt keinerlei Fehlermeldungen aus, wenn das Programm direkt aus Wordworth gestartet wurde, und ist in der Befehlssyntax sehr pingelig, in der Dokumentation aber sehr dürftig. Beckertext hat einen Befehl, den ich genau so eingegeben habe, wie in der Anleitung beschrieben, nicht akzeptiert. Usw. Da hilft nur eines: Probieren, probieren, probieren. Und "Trace", das unten beschrieben wird.
Schau Dir einfach mal verschiedene ARexx-Skripte an und versuche herauszufinden, was sie machen, und wie sie das machen. Für Wordworth 6 existiert eine überarbeitete (ergänzte und verbesserte) Version der Dokumentation der ARexx-Befehle im Aminet. Verzeichnis: docs/misc/WW6-Germ-ARexx.lha

Wichtig zu wissen ist die Behandlung von Anführungszeichen in ARexx- Skripten.
Wenn Du ein " an das ausführende Programm senden willst, mußt Du es in '' setzen (Linke-Alt-ä).
Wenn Du ein ' an das ausführende Programm senden willst, mußt Du es in "" setzen.
Beide Anführungszeichen sind geeignet, einen Befehl einzuschließen. "END" ist gleichbedeutend mit 'END'. Beides wird an ein externes Programm gesendet.
Vor dem Ausführen einer Zeile entfernt ARexx immer die "äußersten" Anführungszeichen. Aus "END" wird END, das dann an das externe Programm geschickt wird.
--------------------------------
ADDRESS TCALC /*Das ist TurboCalcs Adresse*/
variable="Hallo"
Put Variable /* Fügt den Wert von Variable in die aktuelle Zeile ein*/
"NACHUNTEN()" /* Setzt den Cursor eine Zeile tiefer */
'Put Variable' /* Da Variable mit in Anführungszeichen steht, wird */
/* es als Text interpretiert, nicht als der Name einer*/
/* Variablen. In TurboCalc steht in dieser Zeile VARIABLE */
"NACHUNTEN()"
Put '"Hallo Du da"'
"NACHUNTEN()"
Put '"Ich sage mal '||Variable||' zu dir"'
'NACHUNTEN()'
'Put "Ich sage mal '||Variable||' zu dir"'
--------------------------------


Schau Dir mal mit Trace (vgl. u.) an, was ARexx aus den einzelnen Zeilen macht!


****************************************************


2.5. Trace
"Trace" (Spuren) ist eine Möglichkeit, herauszufinden, was Dein Programm denn nun eigentlich tut.
Es handelt sich im wesentlichen um die schon im ersten Kursteil kurz erwähnten DOS-Programme im Verzeichnis sys:rexxc Du mußt diese Befehle also in eine Shell eingeben, nicht in ein ARexx- Programm! (Dort höchstens mit ADDRESS COMMAND)
TCO Trace Console Open
Öffnet ein eigenes Trace-Fenster
TCC Trace Console Close
schließt das Fenster wieder
TS Trace Start
Ab sofort werden alle Befehle in der Form,
wie sie ARexx interpretiert, ausgegeben. Ergebnisse werden
angezeigt. Der nächste Befehl wird erst nach
Drücken von Return ausgeführt.
TE Trace End
Tracing wird wieder beendet. Für den momentan
ausgeführten Befehl muß im Trace-Fenster
noch einmal Return gedrückt werden.

In der Trace-Console können auch Befehle eingegeben werden, die als Teil des Programms betrachtet werden.
= wiederholt die Ausführung der letzten Zeile -x überspringt die nächsten x Befehle

In der Trace-Console werden vor der Auflistung der abgearbeiteten Befehle folgende Codes vorangestellt:
+++ Befehls- oder Syntaxfehler
>C> erweiterter zusammengesetzter Name
>F> Ergebnis eines Funktionsaufrufs
>L> Sprungmarkenklausel
>O> Ergebnis einer zweistelligen Operation
>P> Ergebnis einer Präfix-Operation
>U> nicht initialisierte Variablen
>V> Wert einer Variablen
>>> Ergebnis eines Ausdrucks
>.> Wert eines "Platzhalter"-Tokens

Es gibt allerdings auch einen Befehl, der innerhalb eines ARexx-Programms angewendet werden kann. Er heißt sinnvollerweise TRACE
und hat eine Menge Optionen:
ALL Zeigt alles an.
BACKGROUND Es findet keine Ablaufverfolgung statt.
Was immer das auch heißt.
COMMANDS Zeigt alles an, was an ein externes
Programm geschickt wird.
ERRORS Zeigt alle Fehler an. (Befehle,
die RC~=0 liefern.)
INTERMEDIATES Zeigt alle Zwischenwerte an.
LABELS Zeigt alle Sprunganweisungen an (
die hatten wir noch nicht).
NORMAL Zeigt alle Befehle an, die den
voreingestellten Schweregrad
(OPTIONS FAILAT x) überschreiten
(RC>=x).
RESULTS Zeigt alle Ergebnisse an.
SCAN Prüft das Skript auf Fehler, ohne
es auszuführen
OFF Aus.
! Schaltet das Versenden von Befehlen
an externe Programme
ab, beim zweiten Aufruf wieder an.
? Entspricht TS in DOS. Nach jedem Befehl
wird gewartet. Nochmal schaltet den
Modus wieder aus.

Es reicht jeweils die Angabe des ersten Buchstabens: TRACE R ? kann auch in Verbindung mit den anderen Optionen verwendet werden: TRACE R?

Außerdem gibt es die Funktion TRACE()

ECHO TRACE()
oder:
Ergebnis=TRACE() ECHO Ergebnis
gibt die momentane Trace-Einstellung aus.
Außerdem können innerhalb der Klammern die gleichen Parameter angegeben werden wie bei TRACE.
ECHO TRACE("A")
setzt Tracing auf All.


****************************************************


2.6. Übersicht über die neuen Befehle und Funktionen
IF...THEN...ELSE
INTERPRET Ausdruck
ADDRESS (VALUE|COMMAND)
Ergebnis=SHOW("C|F|I|L|P",Name,Trennzeichen)
TRACE Optionen
Ergebnis=TRACE()
Ergebnis=LASTPOS(Zeichen,Zeichenkette)
Ergebnis=LEFT(Zeichenkette,Zahl)

OPTIONS [NO] RESULTS die unten genannten Systemvariablen werden
(de-)aktiviert
FAILAT x RC>=x wird als Fehler interpretiert
PROMPT Ausdr.Bei PULL und PARSE PULL wird Ausdr. vorangestellt
[NO] CACHE: Der interne Befehlscache, der die Ausführung von
Schleifen beschleunigt, wird ab- bzw. angestellt.
Normalerweise an.
ohne Parameter werden die Einstellungen wieder zurückgesetzt.

DOS-Befehle:
TCO
TCC
TS
TE
WaitForPort

Systemvariablen:
RESULT
RC

So, das war's für diesmal. Ich hoffe, es ist mir gelungen, Dich ein wenig in die Materie einzuführen. Probiere einfach mal aus, Deine eigenen Skripte zu schreiben! Und im Aminet gibt es ein eigenes Verzeichnis util/rexx, in dem auch viele Skripte darauf warten, von Dir erforscht zu werden. Bitte schreibe mir, wenn Du etwas nicht verstanden hast oder bestimmte Probleme hast. Auch, welche Programme Du programmieren willst, und zu welchem Zweck. Wenn möglich, werde ich darauf eingehen.«


[b]ARexx-Kurs - Teil 3 (von Heiko Kuschel)[/b]

3. Ein- und Ausgabe; Funktionen
3.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!

Anmerkung: In der HTML-Version verwenden wir selbstverständlich entsprechende Formatierungen statt der Zeichenfolgen "***..." und "___...".

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!

3.1. Ein- und Ausgabefunktionen

Heute möchte ich Euch eine ganze Menge Funktionen von ARexx vorstellen. Viele sind sehr ähnlich in Aufbau und Funktion, daher werde ich in diesem Kursteil nicht für jede Funktion ein Beispiel bringen, sondern statt dessen nur ein, zwei jeweils ausführlicher erklären. Es geht heute verstärkt darum, mit Variablen zu "jonglieren", mit dem/der BenutzerIn zu kommunizieren, Ausgaben zu machen usw. Natürlich kennen wir schon einen Befehl zur Ausgabe von Text, nämlich ECHO. Und der für die Eingabe lautet PARSE PULL bzw. PULL. Nur: Damit kann ich überhaupt nicht definieren, wie mein Ein- /Ausgabefenster beschaffen sein soll. Und wenn das ARexx-Skript aus einem Programm heraus gestartet wird, kann es sein, daß überhaupt nichts zu sehen ist, weil die Ausgabe des Skripts irgendwohin geleitet wird (z.B. nach NIL:, das "Nimmerwiedersehen-Gerät"). Und vielleicht muß ich ja auch einmal eine Zeile oder ein Zeichen aus einer Datei lesen...

Für alle diese Fälle gibt es die Möglichkeit, Dateien zu öffnen und zu schließen. Sinnvollerweise mit der Funktion OPEN().

Erfolg=OPEN(Test,"Text:Golded/Amigaaktuell/ARexx-Kurs/03.txt","R")

öffnet diesen Text zum Lesen (R) und weist der Variable Erfolg den Wert 1 zu, wenn die Operation Erfolg hatte, und 0, wenn ein Fehler aufgetreten ist (z.B., weil ich eine Verzeichnisebene ausgelassen habe... :-) ). Die Datei kann jetzt unter dem Namen Test mit anderen Befehlen (keine Angst, die kommen gleich!) angesprochen werden. Das ist der sogenannte logische Dateiname. Es gibt folgende Optionen:
R (Read) - Lesen
W (Write) - Schreiben (Achtung: Eine evtl. vorhandene Datei wird gelöscht!)
A (Append) - Anhängen

So, jetzt haben wir also eine Datei (hoffentlich) erfolgreich geöffnet. Statt einer Datei kann man mit OPEN() auch ein AmigaDos-Device öffnen, z.B. ein Konsolenfenster (CON:, oder für besondere Fälle, s.u., RAW:).

Was können wir mit der geöffneten Datei nun alles anfangen?

Wir können ein oder mehrere Zeichen aus der Datei lesen: Zeichen=READCH(Test,Anzahl) Vorsicht! Die Funktion wartet, bis so viele Zeichen wie angegeben eingetrudelt sind!

Wir können eine ganze Zeile (bis zum nächsten Absatzendezeichen) lesen:
Zeile=READLN(Test)

Das gleiche gibt's natürlich auch zum Schreiben in die Datei:
Ergebnis=WRITECH(Test,"Das hier soll in meine Datei geschrieben werden")
Ergebnis=WRITELN(Test,"Das hier soll in meine Datei geschrieben werden")
Im zweiten Fall wird am Schluß ein Absatzendezeichen angefügt.

Zum besseren Merken:
READ heißt Lesen
WRITE heißt Schreiben.
CH steht für Char, d.h. Zeichen.
LN steht für Line, d.h. Zeile.

Wenn ich nun eine Weile aus der Datei gelesen habe, kann es ja passieren, daß mir irgendwann die Zeichen ausgehen, weil die Datei zu Ende ist. Das kann ich überprüfen, indem ich folgenden Befehl anwende:
Erfolg=EOF(Test)
ergibt 1, wenn das Dateiende erreicht ist, ansonsten 0.

... man kann statt dessen auch die Zeilen zählen, und zwar mit der Funktion
Ergebnis=LINES(Test)
Das gibt allerdings die Zeilen zurück, die im Eingabepuffer stehen, ohne Angabe eines Namens die Anzahl der Zeilen, die in STDIN stehen.

Unter Umständen kann es natürlich auch sinnvoll sein, den Zeiger auf ein anderes Zeichen innerhalb der Datei zu verschieben. Das geht zeichenweise vor sich, man sollte also genau wissen, wie die Datei aufgebaut ist.
NeuePosition=SEEK(Test,Offset,Modus)
Offset bedeutet die Anzahl der Zeichen, die weitergegangen werden soll. Modus kann folgendes sein:
B - Begin
C - Current (momentane Position)
E - End
und besagt, worauf sich der Offset bezieht. Vorsicht mit Offsets, die über das Dateiende hinausgehen!

Wie wäre es, das Ganze nun einmal mit einer Eingabekonsole zu versuchen? Unser gutes altes HelloWorld aus dem ersten Kursteil, aufgepeppt mit einer selber geöffneten Konsole:

/* Hello World Version 1.5.*/

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

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

Es reicht auch, einfach nur CON: einzugeben. Dann kannst Du allerdings Position und Titel des Fensters nicht beeinflussen. Im Unterschied zu CON: gibt RAW: jeden Tastendruck sofort weiter. Es muß nicht erst die Return-Taste gedrückt werden. Auf diese Weise kann man auch abfragen, ob eine bestimmte Taste gedrückt wurde.

3.2. Stringfunktionen

Oft braucht man von einer Zeichenkette nur einen Teil, vielleicht den Vornamen, wo doch der ganze Name in einer Variablen gespeichert ist o.ä. Zur Behandlung von Zeichenketten gibt es in ARexx eine große Anzahl von Funktionen. Zwei davon haben wir schon im letzten Teil kurz angesprochen:

LASTPOS(Buchstabe,Zeichenkette)
gibt die Position des Buchstabens an, an der er zum letzten Mal in einer Zeichenkette auftritt

Position=LASTPOS("e","Heiko Kuschel")
ECHO Position

ergibt 11.
LEFT(Zeichenkette,Zahl) ergibt den linken Teil einer Zeichenkette, bis zum xten Zeichen.

ECHO LEFT("Heiko Kuschel",6)

ergibt "Heiko".

Genauso sind alle anderen Stringfunktionen auch aufgebaut, die ich hier einfach mal aufliste:

ABBREV(Lang,Kurz,Länge)

Testet, ob Kurz eine Abkürzung (abbreviation) von Lang ist. Optional kann auch noch eine Anzahl von Zeichen angegeben werden, bis zu der verglichen werden soll. Liefert 0 (falsch) oder 1 (wahr)

CENTER(Text,Länge,Füllzeichen)
CENTRE(Text,Länge,Füllzeichen)

Liefert einen String, der die in Länge angegebene Zahl von Zeichen hat. Optional kann ein Füllzeichen angegeben werden.
ECHO CENTRE("TesttextTesttext",4)
XTTE
ECHO CENTRE("TesttextTesttext",20)
TESTTEXTTESTTEXT
ECHO CENTRE("TesttextTesttext",20,".")
..TESTTEXTTESTTEXT..
ECHO CENTRE("TesttextTesttext",40,".")
............TESTTEXTTESTTEXT............

COMPRESS(String[,Liste])

Entfernt die in Liste angegebenen Zeichen aus einer Zeichenkette. Wird Liste nicht angegeben, entfernt es alle Leerzeichen.
ECHO COMPRESS("Haeaikgog Kausgchael","ag")

COMPARE(Text1,Text2[,Füllzeichen])

Gibt die erste Stelle zurück, an der sich die beiden Texte unterscheiden. Optional kann angegeben werden, mit welchem Füllzeichen der kürzere der Texte aufgefüllt werden soll, wenn die zwei nicht gleich lang sind. Voreingestellt sind Leerzeichen.

COPIES(Zeichenkette,Anzahl)

Gibt Zeichenkette so oft aus, wie Du willst. Nur negativ darf die Zahl nicht sein.

DATATYPE(Zeichenkette[,Typ])

Gibt NUM als Ergebnis zurück, wenn Zeichenkette eine gültige Zahl ist, ansonsten CHAR. Wird ein Typ angegeben, dann kann auf diesen Typ geprüft werden. Ergebnis ist in diesem Fall 0 oder 1. Folgende Typen gibt's:
Alphanumeric A-Z, a-z, 0-9
Binary Binär-String
Lowercase a-z
Mixed A-Z, a-z
Upper A-Z
Numeric Zahl
Symbol ARexx-Symbol
Whole ganze Zahl
X Hexadezimalstring

DELSTR(Zeichenkette,Pos[,Länge])

Diese Funktion schneidet von Zeichenkette alles ab dem Buchstaben mit der Nummer ab, die in Pos angegeben ist. Wird Länge mit angegeben, so wird ab Pos ein Teilstring "herausgeschnitten".

DELWORD(Zeichenkette, Pos[,Anzahl])

Ähnlich wie DELSTR, nur geht's hier um ganze Wörter.

FIND(Zeichenkette,Worte)

Gibt die Anfangsposition der Worte in der Zeichenkette zurück. 0, wenn nicht gefunden.
ECHO FIND("Heiko Kuschel", "Kuschel")
2

INDEX(Zeichenkette,Muster[,Start])

Sucht nach dem ersten Auftreten von Muster in Zeichenkette und gibt die Position aus. 0, wenn nicht gefunden. Eine Startposition kann auch angegeben werden.
Gleichbedeutend damit ist POS(). INDEX() existiert allerdings nur auf der Amiga-Version von REXX.

INSERT(Quellstring,Zielstring[,Start,Länge,Füllzeichen])

Fügt den Quellstring ab der Startposition in den Zielstring ein. Wenn eine Länge angegeben ist, kann sie auch mit Füllzeichen erreicht werden.
ECHO INSERT("ARexx-Kurs ","Ein ist eine klasse Sache",4)
EIN AREXX-KURS IST EINE KLASSE SACHE
Vorsicht: Die Füllzeichen werden an den Quellstring angehängt:
ECHO INSERT("ARexx-Kurs ","Ein ist eine klasse Sache",4,30,"!")
EIN AREXX-KURS !!!!!!!!!!!!!!!!!!!IST EINE KLASSE SACHE

LASTPOS(Muster, Zeichenkette[,Start])

Wie POS() bzw. INDEX(), nur von hinten.

LEFT(Zeichenkette,Länge[,Füllzeichen])

Gibt den linken Teil der Zeichenkette zurück, der Länge lang ist. Evtl. kann mit Füllzeichen aufgefüllt werden, falls die Zeichenkette kürzer ist als die Zahl, die in Länge steht.

LENGTH(Zeichenkette)

Gibt die Länge in Zeichen zurück

OVERLAY(Quelle, Ziel[,Start,Länge,Füllzeichen])

Damit wird eine Zeichenkette über eine andere gelegt. Im Gegensatz zu INSERT() geht dabei ein Teil des Zielstrings verloren. Das entspricht so ungefähr dem Überschreib-Modus in einem Editor oder einer Textverarbeitung.

POS()
ist gleichbedeutend mit INDEX()

REVERSE(Zeichenkette)
Dreht die Zeichenkette um. Aus ARexx wird xxeRA.

RIGHT(Zeichenkette,Länge[,Füllzeichen])
Wie LEFT(), nur daß der rechte Teil abgeschnitten wird.

SPACE(Zeichenkette, Zahl[,Füllzeichen])

Damit können zwischen einzelnen Wörtern im String beliebig viele Leerzeichen (oder andere Füllzeichen) eingefügt werden.

STRIP(Zeichenkette[,B|L|T,Zeichen])

... und damit kannst Du sie wieder entfernen. Optional können auch nur die vorangestellten oder nachfolgenden (Leer-) Zeichen entfernt werden.
L steht für Leading (vorangestellte)
T steht für Trailing (nachgestellte)
B steht für Both (beides) und ist voreingestellt.

SUBSTR(Zeichenkette,Start[,Länge,Füllzeichen])

Damit kann ein Teilstring aus einer Zeichenkette übernommen werden, und zwar ab Position Start, optional mit angegebener Länge und Füllzeichen.

SUBWORD(Zeichenkette,Start[,Anzahl])

Ähnlich wie SUBSTR(), nur mit ganzen Wörtern.

TRANSLATE(Zeichenkette[,rein,raus,Füllzeichen])

Leider kann dieser Befehl nichts in andere Sprachen übersetzen... aber praktisch kann er trotzdem sein.
Er vergleicht die in raus angegebenen Zeichen mit der Zeichenkette. Findet er eines, ersetzt er es durch das Zeichen, das in rein an gleicher Stelle angegeben ist. Ist rein dafür zu kurz, nimmt er ein Leerzeichen oder das optional angegebene Füllzeichen. Hmmmh. Kapiert? Vielleicht einmal ein Beispiel:
ECHO TRANSLATE("Hioku Kaschil","aeiou","eioua")
HEIKO KUSCHEL
ECHO TRANSLATE("Amiga 1200","60","12")
AMIGA 6000

TRIM(Zeichenkette)

entfernt alle nachgestellten Leerzeichen in der Zeichenkette.

UPPER(Zeichenkette)

Wandelt alles in GROSSBUCHSTABEN um. Als ob ARexx das nicht sowieso schon dauernd tun würde...

VERIFY(Zeichenkette,Liste[,M|N,Startposition])

Überprüft, ob Zeichenkette nur Zeichen aus der Liste enthält. Wenn ja, ist das Ergebnis 0, ansonsten die erste Position, an der ein fremdes Zeichen gefunden wurde. Durch Angabe einer Startposition für die Suche kann man dann auch weiter hinten stehende "falsche" Zeichen finden.
N steht für NOMATCH und ist voreingestellt, d.h., es wird nach Zeichen gesucht, die *nicht* vorkommen.
Mit M (MATCH) wird dann nach Zeichen gesucht, die in der Zeichenkette vorkommen.

WORD(Zeichenkette,x)

Gibt das x-te Wort aus der Zeichenkette aus, oder eine leere Zeichenkette, wenn so viele Wörter gar nicht vorhanden sind.

WORDINDEX(Zeichenkette,Zahl)

Gibt die Position in Zeichen aus, an der das x-te Wort steht.
ECHO WORDINDEX("Das ist ein kleines Beispiel",4)
13
Das heißt: Das vierte Wort beginnt mit dem 13. Buchstaben.

WORDLENGTH(Zeichenkette,Zahl)

Gibt die Länge des an Nummer Zahl stehenden Wortes zurück, oder 0, wenn es nicht so viele Wörter gibt.

WORDS(Zeichenkette)

Liefert natürlich die Anzahl der Wörter.

XRANGE([Start,Ende])

Liefert eine Zeichenkette, die alle ASCII-Codes von Start bis Ende enthält. Voreingestellt ist 0 bis 255.

Uff, das war's. Eine lange, ziemlich trockene Liste. Aber irgendwann muß ich Euch die ganzen Befehle ja mal sagen... Und deswegen geht's jetzt gleich noch weiter:

3.3. mathematische Funktionen

Keine Angst, das sind nicht ganz so viele!

ABS(Zahl)
Gibt den absoluten Wert einer Zahl zurück. Völlig unmathematisch ausgedrückt: Entfernt das Minuszeichen vor der Zahl, wenn eins vorhanden ist

DIGITS()
FORM()
FUZZ()

Diese Funktionen liefern die gerade eingestellten Werte für NUMERIC, der gleich noch besprochen werden soll.

MAX(Zahl1,Zahl2[,Zahl3,...])
liefert die größte dieser Zahlen

MIN(Zahl1,Zahl2[,Zahl3,...])
liefert die kleinste dieser Zahlen

RANDOM([MIN,MAX,STARTWERT])

Liefert eine Zufallszahl, optional kann eine kleinste und größte Zahl angegeben werden. Als voreingestellter Startwert wird die Systemzeit verwendet. Wenn Du immer die gleiche Abfolge von Zufallszahlen haben willst, kannst Du einen Startwert angeben, der statt der Systemzeit verwendet wird.
Anmerkung: Zufallszahlen zu erzeugen, ist mit einem Computer praktisch unmöglich. Denn ein Computer arbeitet mit mathematischen Formeln, und deren Ergebnis ist immer gleich. Deshalb nimmt man eine Formel, bei der die nächste Zahl nicht so ohne weiteres vorhersehbar ist und bei der die Ergebnisse halbwegs gleichmäßig über alle Zahlen verteilt sind, und füttert sie mit einem Startwert, der weitgehend zufällig ist, nämlich der Systemzeit zum Zeitpunkt des ersten Aufrufs dieser Funktion. Wird dagegen immer der gleiche Startwert genommen, kommt auch immer die gleiche Folge von Zahlen heraus. Auch das kann nützlich sein, wenn man einen immer gleichen Ablauf haben will.

RANDU([Startwert])

Wie RANDOM(), nur daß der Rückgabewert immer zwischen 0 und 1 liegt. Die Zahl der Nachkommastellen wird mit NUMERIC DIGITS bestimmt (s.u.).

SIGN(Zahl)

liefert das Vorzeichen der Zahl oder 0 für 0.

TRUNC(Zahl[,Stellen])

Schneidet die Nachkommastellen ab (rundet nicht!). Optional kann eine Anzahl von Nachkommastellen angegeben werden.

Nun brauchen wir noch den NUMERIC-Befehl, der schon ein paar Mal angesprochen wurde. Er hat die folgenden Optionen:

NUMERIC DIGITS Zahl
Stellt ein, wie viele Stellen bei einer numerischen Operation signifikant sind (1-14). Ist die Zahl länger, wird die Exponentialschreibweise verwendet, z.B. 2.122E+3 NUMERIC FUZZ Zahl
Stellt ein, wie viele Stellen (von rechts) bei Vergleichsoperationen *nicht* berücksichtigt werden sollen. NUMERIC FORM (Scientific|Engineering)
Stellt die Form der Exponentialschreibweise ein. Da gibt es einen Unterschied zwischen akademischer und Ingenieursschreibweise, der mir allerdings nicht klar ist.

3.4. Konvertierungen

Jetzt brauchen wir natürlich noch die Möglichkeit, z.B. Zahlen in Zeichenketten zu verwandeln usw.
Dafür gibt es in ARexx ein sehr einfaches System von Funktionen: Jede "Art" von Zeichen hat einen Buchstaben:
B - Binär
C - Character (Buchstaben)
D - Dezimal
X - hexadezimal

... und "2" steht im Englischen manchmal für "to", weil's genauso ausgesprochen wird.

Also:

ECHO B2C("00100010 01101001")
"i

Gibt die Zeichen aus, die im ASCII-Code den hier angegebenen Binärzahlen entsprechen.

Leider sind nicht alle Konvertierungsmöglichkeiten vorhanden, nur die folgenden:
B2C()
C2B()
C2D()
C2X()
D2C()
D2X()
X2C()
X2D()

Bei C2D darf die Zeichenkette, die übergeben wird, maximal 4 Zeichen enthalten. Sie darf auch ein Hex-String, z.B. "FFFF"x oder ein Binärstring, z.B. "0011"b sein.
Optional kann bei C2D() ein Argument angegeben werden:
C2D("FFFF"x,2)
In diesem Fall wird der Binärwert der Zeichenkette als Zweierkomplement von 2 Bytes Länge behandelt. So kann man auch vorzeichenbehaftete Zahlen erzeugen.

Bei D2C(Zahl[,Bytes]) kann ebenfalls ein zusätzlicher Wert angegeben werden. Er bewirkt, daß das Ergebnis die entsprechende Länge hat und entweder links abgeschnitten oder mit "00"x aufgefüllt wird.

Bei D2X() und X2D() kann die Zahl von Nibbles (4 Bits, also 2 Nibbles= 1 Byte) angegeben werden, damit auch negative Zahlen dargestellt werden können.
ECHO X2D("FFE0",4)
-32
ECHO X2D("FFE0",6)
65504
ECHO X2D("FFE0")
65504

3.5. Bitmanipulation

Noch ein paar Funktionen zur Bitmanipulation, mehr der Vollständigkeit halber.
Binärzahlen werden in ARexx folgendermaßen geschrieben: "00010000"b Leerzeichen dürfen nur an den Byte-Grenzen eingefügt werden!

Folgende Funktionen gibt es:

BITAND(BitStr1[,BitStr2,Füllzeichen])

ergibt eine UND-Verknüpfung der Bit-Strings. Die Funktion arbeitet nicht korrekt, wenn die Strings unterschiedlich lang sind, da dann mit Leerzeichen aufgefüllt wird! Dann muß das richtige Füllzeichen gewählt werden, was auch nicht ganz problemlos ist.
ECHO C2B(BITAND("01010001"b,"11101110"b))
01000000

zu UND, ODER etc. vgl. unten!

BITCHG(BitString,Bit)

Invertiert das Bit an der angegebenen Stelle. Gezählt werden die Bits von rechts nach links!

BITCLR(BitString,Bit)

Löscht das angegebene Bit.

BITCOMP(BitStr1,Bitstr2[,Füllzeichen])

Vergleicht die beiden Bitstrings und liefert 0, wenn sie gleich sind, ansonsten die erste Position, an der sie sich unterscheiden. Sind die Strings nicht gleich lang, wird der kürzere am linken Ende mit Füllzeichen aufgefüllt.

BITOR(BitStr1[,BitStr2,Füllzeichen])

ergibt eine ODER-Verknüpfung der Bit-Strings. Ansonsten wie bei BITAND().

BITSET(BitString,Bit)

Setzt das angegebene Bit auf 1.

BITTST(BitString,Bit)

Testet, ob das angegebene Bit gesetzt ist. Liefert 1, wenn ja, sonst 0.

BITXOR(BitStr1[,BitStr2,Füllzeichen])

ergibt eine Exklusiv-ODER-Verknüpfung der Bit-Strings. Ansonsten wie bei BITAND().

Was bedeutet UND-, ODER- etc. Verknüpfung?
Ganz einfach: zwei Bits (also einzelne Speicherstellen) werden miteinander verglichen, und abhängig von ihrem Zustand (0 oder 1) kommt es zu einem Ergebnis. Das geht nach folgender Tabelle:

Bit 1 | 0 1 0 1 | Vergleich
Bit 2 | 0 0 1 1 |
______|________________|____________
UND | 0 0 0 1 | Ergebnis
ODER | 0 1 1 1 |
XODER | 0 1 1 0 |

3.6. Zusammenfassung

So, das war heute eine riesige Fülle von Befehlen. Leider ist dieser Kursteil dadurch etwas trockener geworden als die ersten zwei. Ich hoffe, Ihr verkraftet es und probiert nun selbst ein bißchen herum. Hier noch einmal die Zusammenfassung aller Befehle und Funktionen dieses Kursteils:

Ein-/Ausgabe:

EOF(LogName)
LINES(LogName)
OPEN(LogName,Pfad,"R"|"W"|"A")
READCH(LogName,Anzahl)
READLN(LogName)
SEEK(LogName,Offset,Modus)
WRITECH(LogName,Text)
WRITELN(LogName,Text)

Zeichenketten:

ABBREV(Lang,Kurz,Länge)
CENTER(Text,Länge,Füllzeichen)
CENTRE(Text,Länge,Füllzeichen)
COMPARE(Text1,Text2[,Füllzeichen])
COMPRESS(String[,Liste])
COPIES(Zeichenkette,Anzahl)
DATATYPE(Zeichenkette[,Typ])
DELSTR(Zeichenkette,Pos[,Länge])
DELWORD(Zeichenkette, Pos[,Anzahl])
FIND(Zeichenkette,Worte)
INDEX(Zeichenkette,Muster[,Start])
INSERT(Quellstring,Zielstring[,Start,Länge,Füllzeichen])
LASTPOS(Muster, Zeichenkette[,Start])
LEFT(Zeichenkette,Länge[,Füllzeichen])
LENGTH(Zeichenkette)
OVERLAY(Quelle, Ziel[,Start,Länge,Füllzeichen])
POS()
REVERSE(Zeichenkette)
RIGHT(Zeichenkette,Länge[,Füllzeichen])
SPACE(Zeichenkette, Zahl[,Füllzeichen])
STRIP(Zeichenkette{,B|L|T,Zeichen])
SUBSTR(Zeichenkette,Start[,Länge,Füllzeichen])
SUBWORD(Zeichenkette,Start[,Anzahl])
TRANSLATE(Zeichenkette[,rein,raus,Füllzeichen])
TRIM(Zeichenkette)
UPPER(Zeichenkette)
VERIFY(Zeichenkette,Liste[,M|N,Startposition])
WORD(Zeichenkette,x)
WORDINDEX(Zeichenkette,Zahl)
WORDLENGTH(Zeichenkette,Zahl)
WORDS(Zeichenkette)
XRANGE([Start,Ende])

mathematische Funktionen:

ABS(Zahl)
DIGITS()
FORM()
FUZZ()
MAX(Zahl1,Zahl2[,Zahl3,...])
MIN(Zahl1,Zahl2[,Zahl3,...])
NUMERIC DIGITS Zahl
NUMERIC FORM (Scientific|Engineering)
NUMERIC FUZZ Zahl
RANDOM([MIN,MAX,STARTWERT])
RANDU([Startwert])
SIGN(Zahl)
TRUNC(Zahl[,Stellen])

Konvertierungen:

B2C()
C2B()
C2D()
C2X()
D2C()
D2X()
X2C()
X2D()

Bitmanipulation:

BITAND(BitStr1[,BitStr2,Füllzeichen])
BITCHG(BitString,Bit)
BITCLR(BitString,Bit)
BITCOMP(BitStr1,Bitstr2[,Füllzeichen])
BITOR(BitStr1[,BitStr2,Füllzeichen])
BITSET(BitString,Bit)
BITTST(BitString,Bit)
BITXOR(BitStr1[,BitStr2,Füllzeichen])

So, das war's für heute. Sehr viele Informationen, sehr wenig Beispiele. Dafür haben wir schon fast alles von dem, was ich erst für den nächsten Kursteil geplant hatte, mit behandelt. Nächstes Mal gibt's wieder mehr "richtige" Beispiele, versprochen!«

Weiter gehts hier:

http://www.amigafuture.de/kb.php?mode=article&k=1763