Workshops / Hintergrundberichte

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

»ARexx-Kurs: Übersicht

1. Einführung in ARexx.

2. Programmstruktur und Ansteuerung von anderen Programmen 3. Ein- und Ausgabe; Funktionen 4. komplexere Programmstrukturen 5. Aufbau von Skripten »

5. Beispiele für die Vernetzung von Programmen

5.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!
(In der HTML-Version benutzen wir natürlich "schickere" Kennzeichnungen)

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!

5.1. Ein ARexx-Skript konzipieren

Mittlerweile haben wir so ziemlich alle ARexx-Befehle durchgemacht, die es gibt. Aber - wie mache ich daraus nun ein sinnvolles ARexx-Skript? Bei vielen Vorhaben ist das gar nicht so einfach, denn manche Programme, die über ARexx anzusteuern sind, haben so ihre Eigenheiten. Ein paar Grundprobleme möchte ich in diesem Kursteil ansprechen und dann noch Skripte vorstellen, die ich selber für den "Hausgebrauch" geschrieben habe.

5.1.1. Wie finde ich die Adresse?

Fast alle ARexx-fähigen Programme bieten die Möglichkeit, ARexx-Skripte über Menü oder sonstwie direkt aus dem Programm heraus zu starten. Dann ist der Port des startenden Programms als ARexx-Port voreingestellt, an den die Befehle geschickt werden sollen. Das sieht dann so aus:
OPTIONS RESULTS
PortName = ADDRESS()

Wenn später ein anderes Programm angesteuert wird und dadurch der Port mit ADRRESS xxx verändert wird, kannst Du anschließend wieder auf das Programm zurückkommen, das das Skript gestartet hat. Und zwar ganz einfach mit

ADDRESS VALUE PortName

PortName ist hier die Variable, in der der Portname des Programms abgelegt wird, das das Skript gestartet hat. Z.B. Wordworth.1 oder YAM etc.

5.1.2. Eigenheiten der einzelnen Programme

Manche Programme haben nicht nur einen einzigen ARexx-Port. Stattdessen öffnen sie für jedes Fenster einen eigenen, z.B. Wordworth und, soweit ich weiß, auch Final Writer. Die werden dann durchnumeriert: Wordworth.1, Wordworth.2 usw.

Dadurch kann man sich nie sicher sein, daß ein bestimmter Port tatsächlich existiert! Es kann ja sein, daß das Fenster (und damit der Port), dem Wordworth.1 zugeordnet wurde, geschlossen wurde. Vielleicht existieren gerade nur Wordworth.3 und Wordworth.5. Wenn ich Wordworth also von außen ansteuern will, ohne daß das Skript aus Wordworth heraus gestartet wurde, ist es ziemlich schwierig, einen richtigen Port zu finden. Ich behelfe mir immer mit der folgenden kleinen Schleife:
options results
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."
quit
end

Übrigens gibt es auch andere Programme, die eine Zahl hintendran hängen, bei der diese Zahl aber etwas anderes bedeutet. Der normale ARexx-Port von GoldEd heißt z.B. GOLDED.1 Hier gibt es nur ein GOLDED.2, wenn GoldEd tatsächlich nochmal neu gestartet wird. Alle Fenster mit unterschiedlichen Texten innerhalb von GoldEd haben dagegen diesen einen ARexx-Port GOLDED.1. Bei GoldEd gibt es noch eine weitere Besonderheit: Der Text muß für den normalen Zugriff gesperrt werden. Dabei muß seit Version 4 von GoldEd auch noch angegeben werden, für welche Version dieses Skript geschrieben wurde. Sinnvoll, da sich der ARexx-Wortschatz von GoldEd beim Sprung von Version 3 auf 4 ziemlich geändert hat. Einzelheiten dazu stehen in der Online-Hilfe zu GoldEd.

Ein Wort noch zu allgemeinen Problemen mit der Ausführung von Programmen: Gerade bei Database Professional (DBPro) habe ich festgestellt, daß es oft genau auf die Schreibweise (groß/klein etc.) ankommt. Oft ist es auch nötig, daß Argumente in Anführungszeichen gesetzt werden. Beachte dabei folgendes: Aus

FINDBASE "Adressen.db"
wird für Database:
FINDBASE Adressen.db

Du mußt stattdessen das Ganze nochmal in Anführungszeichen setzen, da immer die äußersten durch ARexx entfernt werden:

'FINDBASE "Addressen.db"'
Alternativ müßte eigentlich auch gehen:
FINDBASE '"Addressen.db"'
An Database wird dann dieser Text übermittelt:
FINDBASE "Adressen.db"

Kapiert? Ich hoffe es. Das Kapitel mit den Anführungszeichen ist eines der kompliziertesten in der ganzen ARexx-Programmiererei.

Übrigens: Mir ist es auch schon passiert, daß ich einen Befehl genau so eingegeben habe, wie er im Handbuch steht, und es hat trotzdem nicht funktioniert. Das war bei Beckertext III.

5.2. MUIRexx

5.2.1. Kurzeinführung

MUIRexx ist ein ausgesprochen gutes Hilfsmittel, um komplizierteste Bedienoberflächen zu erstellen. Es ist gewissermaßen die Schnittstelle zwischen ARexx und dem "Magic User Interface", kurz: MUI, mit dem inzwischen viele Programme programmiert sind (z.B. YAM, Voyager, STFax,...) MUIRexx ist anders als andere Libraries: Es ist ein eigenes Programm, das über ARexx gesteuert wird und, je nach den Befehlen, die es erhält, ein Fenster mit Schaltflächen, Listern, Texten oder was auch immer aufbaut. Es ist im Aminet erhältlich unter dev/mui und kostet eine Shareware-Gebühr von 15 US-Dollar.

Nun wird das aber nicht einfach über ADDRESS MUIREXX gemacht, sondern jedes erstellte Fenster bekommt einen eigenen ARexx-Port. Am einfachsten schaffst Du das, indem Du mit MUIRexxBuild ein neues Fenster erstellst und dem einen Namen gibst. Ich habe auf diese Weise ein Fenster mit dem Namen "Listen" erstellt, das wird dann über ADDRESS Listen angesteuert. Das Ganze funktioniert so ähnlich wie eine DO... END-Schleife: Erst wird ein Fenster definiert, und darin einzelne Gruppen:

WINDOW
GROUP
GROUP
...
ENDGROUP
ENDGROUP
GROUP
....
ENDGROUP
ENDWINDOW
Das wäre eine typische Grundstruktur für eine Fensterdefinition. Die ganzen Dinge mit diversen Variablen usw. kannst Du dabei weitgehend MUIRexxBuild überlassen, das übrigens selbst eine MUIRexx-Anwendung ist!

5.2.2. Ein Beispiel

Bis jetzt habe ich es immerhin geschafft, ein Fenster aufzubauen, das verschiedene Gruppen enthält. Nur das dazugehörige Programm fehlt noch, das die damit verbundenen Aktionen auch ausführt... Da es hier aber um die Arbeit mit MUIRexx geht, möchte ich das Ganze trotzdem einmal kurz vorstellen. Weitere Beispiele finden sich ja auch im MUIRexx-Ordner. Mein kleines Skript soll mir eigentlich die Verwaltung von Mailinglisten vereinfachen. Das sind so eine Art EMail-Rundschreiben-Gruppen. Ich schicke eine Mail an eine bestimmte Adresse, und diese Mail wird an alle verteilt, die sich in der Mailingliste eingetragen haben. Um in so eine Liste zu kommen, muß man an eine jeweils unterschiedliche Adresse eine Mail schicken, etwa "subscribe PAmiga-list meine-Email- Adresse". Ähnlich mit unsubscribe, wenn man wieder rauswill. Und daneben gibt es noch manche Mailinglisten, bei denen man sich auch kurzzeitig ausklinken kann, ohne sich vollständig zu verabschieden, indem man die Optionen auf NOMAIL setzt, das heißt, ich kriege im Moment keine Mail. Für jede Mailingliste existiert also: Da ich immer wieder mal wechsle, dachte ich mir, es wäre sinnvoll, das über ein Programm zu machen. Dabei wollte ich zunächst aus einer großen Liste (wer die haben will, kann mich anmailen) ein paar Standard-Mailinglisten auswählen können, die dann wiederum einzeln an- und abgeschaltet werden können.

Das dazugehörige Fenster stelle ich mir so vor, daß ich eine Liste der aktuellen (sprich: von mir vorausgewählten) Mailinglisten habe und über "Prefs" weitere dazunehmen kann oder welche herausnehmen kann. In einer Zeile untendrunter soll, sofern vorhanden, eine kurze Beschreibung der Mailingliste stehen, die ich gerade angeklickt habe. ... und so sieht mein Programm dazu aus:

(da einige Programmzeilen sehr lang sind, habe ich die längeren unter ihnen mit zwei Kommentarzeilen eingerahmt. Für viele von Euch ist sonst vermutlich nicht zu erkennen, wo eine Programmzeile unterbrochen ist.

/*Das Folgende ist eine Zeile*/
hier dazwischen steht eine lange Programmzeile
/*bis hier*/

Das folgende Programm wird aus einer Shell heraus wie folgt gestartet:

muirexx:muirexx Listen.rexx PORT Listen
Listen.rexx ist dabei der Name des Skripts.
/* Application created by MUIBuild */

address Listen

MUIA_Listview_DragType = 0x80425cd3 MUIA_List_DragSortable = 0x80426099 MUIV_Listview_DragType_Immediate = 1 TRUE = 1 MUIA_Listview_MultiSelect = 0x80427e08 MUIA_Dropable = 0x8042fbce MUIV_Listview_MultiSelect_Default = 1 MUIA_List_Quiet = 0x8042d8c7 MUIV_List_Insert_Sorted = -2 line = '%s';

/*Diese Variablen wurden von MUIRexxBuild selbstständig eingefügt*/

window COMMAND """quit""" PORT Listen TITLE """Mailinglisten-Verwaltung""" group HORIZ REGISTER LABELS "Aktuelle,Prefs" group ID Aktuell group HORIZ group FRAME text LABEL "Liste der aktuellen Mailinglisten" list ID List1 endgroup group FRAME text LABEL "Status" space radio LABELS "On,Off,Nomail" space endgroup endgroup view ID Help1 STRING "Hilfetext" endgroup group ID Prefs group HORIZ group FRAME /*Das Folgende ist eine Zeile*/ text LABEL "Liste der bekannten Mailinglisten" list ID List2 ATTRS MUIA_Listview_DragType MUIV_Listview_DragType_Immediate MUIA_List_DragSortable TRUE /*bis hier*/ endgroup group FRAME /*Das Folgende ist eine Zeile*/ text LABEL "Aktuelle Liste" list ID List3 ATTRS MUIA_Listview_DragType MUIV_Listview_DragType_Immediate MUIA_List_DragSortable TRUE MUIA_Dropable TRUE /*bis hier*/ endgroup endgroup view ID Help2 STRING "Hilfetext2" endgroup endgroup endwindow

/* bis hierher sollte es ziemlich verständlich sein. */ callhook ID List2 PORT INLINE INCLUDE List3 DROP, COMMAND """options results; address Listen; line='%s'; /*Das Folgende ist eine Zeile*/ 'list ID "List2" INSERT POS "MUIV_List_Insert_Sorted" STRING' line; /*bis hier*/ 'list ID "List3" REMOVE STRING' line; 'list ID "List1" REMOVE STRING' line;""" callhook ID List3 PORT INLINE INCLUDE List2 DROP, COMMAND """options results; address Listen; line='%s'; /*Das Folgende ist eine Zeile*/ 'list ID "List3" INSERT POS "MUIV_List_Insert_Sorted" STRING' line; /*bis hier*/ /*Das Folgende ist eine Zeile*/ 'list ID "List1" INSERT POS "MUIV_List_Insert_Sorted" STRING' line; /*bis hier*/ 'list ID "List2" REMOVE STRING' line;""" callhook ID List1 INCLUDE List1 list ID List1 INSERT STRING "YAM" list ID List1 INSERT STRING "PAmiga" list ID List1 INSERT STRING "I-Amiga" list ID List1 INSERT STRING "TeamAmiga" list ID List1 INSERT STRING "STFax" list ID List3 INSERT STRING "YAM" list ID List3 INSERT STRING "PAmiga" list ID List3 INSERT STRING "I-Amiga" list ID List3 INSERT STRING "TeamAmiga" list ID List2 INSERT STRING "CU-Amiga" list ID List2 INSERT STRING "Voyager" list ID List3 INSERT STRING "STFax"

Ich hoffe, daß der Aufbau des Fensters auch beim Lesen des Quelltextes halbwegs verständlich wird. "REGISTER" sind die Karteikartenreiter am oberen Ende des Fensters. Wenn ich eine Gruppe später nocheinmal weiterverwenden muß, kann ich ihr mit ID einen Namen zuweisen, also z.B. GROUP ID ErsteGruppe.

Schwieriger wird schon die Sache mit Callhook. Hier werden Ereignisse definiert, nach denen irgendeine Aktion stattfinden soll. Also: Wenn ich in "Prefs" einen Listennamen aus dem einen Lister in den anderen ziehe, muß dieser Name natürlich im alten Lister verschwinden und im neuen auftauchen. Da Computer, selbst Amigas, leider nicht intelligent genug sind, muß ich ihm das extra sagen. Das sieht dann so aus:
callhook ID List2 PORT INLINE INCLUDE List3 DROP,
COMMAND """options results;
address Listen;
line='%s';
/*Das Folgende ist eine Zeile*/
'list ID "List2" INSERT POS "MUIV_List_Insert_Sorted"
STRING' line;
/*bis hier*/
'list ID "List3" REMOVE STRING' line;
'list ID "List1" REMOVE STRING' line;"""
Das heißt: Wenn in List2 etwas fallengelassen wird, und zwar aus List3, dann starte ein ARexx-Skript, das den MUIRexx-Task Listen addressiert. In List2 wird der Name der Mailingliste eingefügt (mit %s), in List3 entfernt und ebenso in List1. (Das ist die erste, die man sieht, auf der Seite "Aktuelle".)

Um das Programm zu vervollständigen, fehlen jetzt also nur noch weitere solche Callhooks, die dann erst einmal den jeweils zur Liste gehörigen Hilfetext anzeigen, auf der Seite "Aktuelle" den richtigen Radioknopf für die jeweils angeklickte Liste aktivieren (also ob sie an, aus oder auf NOMAIL gesetzt ist) - und außerdem noch eine Reihe von Knöpfen, um die entsprechenden Befehls-mails loszuschicken, abzubrechen oder eine Übersicht über den aktuellen Stand der Dinge auszugeben. Vielleicht hast Du ja Lust, so etwas zu machen... :)

Anbei mein einfaches Programm, das vier verschiedene Mailinglisten bestellt. So habe ich das bisher gehandhabt:
/* YAM und I-Amiga werden auf MAIL gesetzt, Pamiga und Team Amiga
bestellt*/
/* $VER: 1.0. 23.2.98 */
options results
if ~show("P",YAM) then address command "run Yam:Yam"

address command 'echo >t:Yamtext "SET YAM MAIL"' 'echo >t:Iamigatext "SET I-AMIGA MAIL"' 'echo >t:PAmigatext "SUBSCRIBE PAMIGA-LIST hk0006@wuerzburg.baynet.de"' 'echo >t:TAmigatext "SUBSCRIBE TeamAmiga hk0006@wuerzburg.baynet.de"'

"sys:rexxc/Waitforport YAM"

address YAM mailwrite writemailto "Listserv@tu-clausthal.de" "writeletter t:Yamtext" writequeue mailwrite writemailto "Majordomo@lists.netlink.co.uk" "writeletter t:PAMIGATEXT" writequeue mailwrite writemailto "listserv@listserv.acsu.buffalo.edu" "writeletter t:Iamigatext" writequeue mailwrite writemailto "majordomo@thule.no" "writeletter t:TAMIGATEXT" writequeue address command "delete >NIL: t:yamtext" "delete >NIL: t:?amigatext"

Ich denke, dieses Skript solltest Du inzwischen mit Leichtigkeit verstehen.

5.3. andere Libraries

5.3.1. rexxreqtools.library

Die rexxreqtools.library findet sich, soweit ich weiß, im Aminet.

Sie enthält die Funktionen der reqtools.library, also alle Arten von Requestern. Auch dafür gibt es im Lieferumfang schon ein paar Demos, mit denen man ganz gut weiterarbeiten kann. Ich möchte nur eben vorstellen, wie ich ein Skript beginne, das zuerst nachsieht, ob Wordworth läuft und dann den Requester von Wordworth verwendet, ansonsten aber Rexxreqtools:
options results
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
if ~show("L",rexxreqtools.library) then do
call addlib("rexxreqtools.library", 0, -30, 0)
end
gadtxt= "_Holen|E_nde|_To-Do-Liste|_Cancel"
Anf = upper(rtgetstring(" ","Bitte Textstelle eingeben:","Text
3.0.",gadtxt))
buttonresult=rtresult
end
else do
do i=0 to 5
viewwindow i
end    /* wenn Makro nicht von WW aus aufgerufen wird, ist sonst die
Workbench vorne*/
/* keine Ahnung, wie man herausfinden kann, welches Fenster
existiert.*/
/*Das Folgende ist eine Zeile*/
WizardReq TITLE "Text 3.0." LABEL "Bitte Textstelle eingeben:" TEXTBOX 1
"_Stelle:" BUTTON 1 "_Holen" BUTTON 2 "E_nde" BUTTON 3 "_To-Do-Liste"
BUTTON "-1" "_Cancel"
/*bis hier*/
buttonresult = RESULT
Wizard_GetTextBox 1
Anf = UPPER(RESULT)
end
select
when buttonresult = 2 then do
when buttonresult = -1 then do
etc.
end
Hier hast Du nun also zwei verschieden definierte Requester drin: Einen mit einem Wordworth-Befehl (WizardReq) und einen mit der Rexxreqtools.library (rtgetstring). Gleichzeitig natürlich auch die verschiedenen Möglichkeiten, das Ergebnis des Requesters abzufragen: Bei reqtools wird der eingegebene Text sofort als Variable übergeben. Welcher Knopf gedrückt wurde, kann über die Variable rtresult abgefragt werden. Bei Wordworth steht die Nummer des Knopfs in RESULT, und der eingegebene Text ebenfalls, nachdem der Befehl Wizard_GetTextBox eingegeben wurde. Dabei die Nummer der Textbox nicht vergessen! (hier 1) Es sind nämlich mehrere Textboxen in ein und demselben Requester möglich.

Der "Abbruch"-Knopf hat die Nummer "-1" erhalten, da RESULT ebenfalls -1 enthält, wenn das Schließgadget in der linken oberen Ecke betätigt wird. So haben wir zwei Fliegen mit einer Klappe geschlagen.

5.3.2. rexxtricks.library

Die Rexxtricks.library enthält eine Menge nützlicher Funktionen aus den folgenden Bereichen:

AmigaDOS-Funktionen
SCSI-Funktionen
Clipboard-Funktionen
Listen-Funktionen
Publicscreen-Funktionen
Icon-Funktionen
Sonstige Funktionen

Diese im einzelnen zu erläutern, würde hier zu weit führen. Aber ich wollte einmal auf diese Library aufmerksam machen, denn sie kann oft wirklich nützlich sein. Lies mal die Anleitung, sie ist ziemlich gut!

5.4. Beispiele für die Vernetzung von Programmen

5.4.1. Beckertext und Wordworth

Das Schöne an ARexx ist ja gerade, daß es auch möglich ist, mehrere Programme miteinander zu verknüpfen. Ein kleines Beispiel hatten wir bereits in einem früheren Kursteil: Ein Skript, das Miami und YAM startet, online geht, Post sendet und abholt und wieder offline geht. Das war natürlich relativ simpel.

Beim folgenden Skript kommt immerhin dazu, daß ein bestimmter Text irgendwie zwischen zwei Anwendungen ausgetauscht werden soll. Ich habe es geschrieben, weil ich früher viel mit Beckertext gearbeitet habe, jetzt inzwischen aber Wordworth verwende. Da BT und WW leider kein gemeinsames Clipboard verwenden, Wordworth außerdem keinen "Dazuladen"-Befehl kennt, war es gar nicht so einfach, das zu realisieren. Eigentlich tut dieses Skript nichts anderes, als einen bereits markierten Text aus Beckertext in das aktuelle Wordworth-Dokument an der aktuellen Stelle einzufügen. Und so sieht das Ganze aus:
/*  BT-Text (markierten Block) in WW5 einsetzen - MJ+HK 17.6.96  */
OPTIONS RESULTS
WwPortName = Address()
GetFont
OldFont = Result
GetFontSize
OldFontSize = Result
Address ('bt3')
kopiere
neudok
einsetzen
'asichern "T:BT"'
schliesse
Address Value WwPortName
New
Address Value Result
Open FILENAME "T:BT"
SelectAll
Font NAME OldFont SIZE OldFontSize
Copy
Close FORCE
Address Value WwPortName
Paste
Address Command delete "T:BT"
Also: Das Skript wird aus Wordworth aufgerufen, sonst ist es nicht möglich, das aktuelle Fenster in Wordworth zu bestimmen. Dann wird festgestellt, welche Schriftart an der aktuellen Stelle eingestellt ist, damit auch der neue Text gleich in dieser Schriftart erscheint.

Anschließend setze ich den aktuellen Port auf Beckertext. Warum da die Klammern nötig sind, weiß ich wirklich nicht. So stehts im Handbuch, und nur so funktioniert's auch.

Mit Beckertext ist es nicht möglich, einen Block einzeln abzuspeichern. Also: Neues Dokument öffnen, Block hineinkopieren, Dokument als reinen Text abspeichern. Und jetzt das gleiche rückwärts für Wordworth: Neues Dokument öffnen, mit der richtigen Schrift formatieren, ins "richtige" Dokument kopieren, fertig.

5.4.2. Typisch Multitasking...

Als nächstes möchte ich euch noch ein Skript vorstellen, an dem eine Menge Programme beteiligt sind: Wordworth, GoldEd, Database Pro, YAM. Dieses Skript habe ich geschrieben, um die Texte, die ich schreibe, archivieren, ausdrucken, im Großdruck für meinen Opa ausdrucken, an Freunde in verschiedenen Dateiformaten mailen zu können. Und das alles in einem Aufwasch. :) Selbst wenn Du einige der Programme nicht selbst hast, hoffe ich, daß Du den einen oder anderen Kniff brauchen kannst. Schau's Dir mal an.
/* $VER: 1.1. 19.8.97 - 23.1.98*/
options results
Wordworthport=Address()
/*Das Folgende ist eine Zeile*/
wizardreq title "Ansprache versenden" label "Bitte Nummer der Ansprache
eingeben." textbox 1 "_Nummer:" textbox 2 "In _DB übernehmen (J/N):"
textbox 3 "_Großdruck erstellen (J/N):" textbox 4 "_Mail verschicken (J/N)"
textbox 5 "Anzahl N_ormaldrucke:" Button 1 "_Ok" Button "-1" "_Abbruch"
/*bis hier*/
if result = "-1" then do
exit
end

Wizard_Gettextbox (1) Nummer=Right(Result,3,"0") Wizard_Gettextbox (2) DB=Result

Wizard_Gettextbox (3) Grossdruck=Result

Wizard_Gettextbox (4) Mail=Result

Wizard_Gettextbox (5) Normaldruck=Result

/* bis hierher wird überprüft, welche der Aktionen tatsächlich durchgeführt werden sollen. */ /*Meine Ansprachen sind durchnumeriert, und zwar nach dem Schema 002.Beschreibung */ if Normaldruck="J" then Normaldruck=1 if Normaldruck>0 then do SAVEAS NAME "Text:Wordworth7/Dokumente/Ansprachen/000.TEMP" end /*Wenn ein Ausdruck in der "Normalform" gewünscht ist, muß die Datei zwischengespeichert werden.*/ /*Den tatsächlichen Namen des Textes kann man mit Wordworth leider nicht herausfinden.*/ if DB="J" then do if ~show("P",DataBase) then address command "run Text:DBProV3.1/db" end if Mail="J" then do 'SAVEAS RTF Name T:Ansprache.rtf' 'SAVEAS WORDPERFECT Name T:Ansprache.wpf' if ~show("P",YAM) then address command "run Yam:Yam" end /*Hier werden die jeweils benötigten Programme gestartet:*/ /*DBPRo, falls eine Aufnahme in die Datei gewünscht ist,*/ /*und YAM, falls die Ansprachen per EMail verschickt werden sollen.*/

address command if ~Exists("Text:Wordworth7/Dokumente/Ansprachen/"||Nummer||".kurz") then do /*Das Folgende ist eine Zeile*/ "echo > Text:Wordworth7/Dokumente/Ansprachen/"||Nummer||".kurz" '"Ansprache Nr. '||Nummer||'"' /*bis hier*/ "echo >> Text:Wordworth7/Dokumente/Ansprachen/"||Nummer||".kurz" '"Text: "' "echo >> Text:Wordworth7/Dokumente/Ansprachen/"||Nummer||".kurz" '"Datum: "' "echo >> Text:Wordworth7/Dokumente/Ansprachen/"||Nummer||".kurz" '"Ort: "' "echo >> Text:Wordworth7/Dokumente/Ansprachen/"||Nummer||".kurz" '"Stichworte: "' "echo >> Text:Wordworth7/Dokumente/Ansprachen/"||Nummer||".kurz" '"Beschreibung: "' end /*Hier gebe ich mir selbst ein kleines Formular für eine Kurzbeschreibung vor.*/ /*Der doppelte Pfeil nach echo bewirkt, daß der Text an die bestehende Datei*/ /*angehängt wird.*/ /*Ein Teil davon wird in der Datenbank weiterverwendet, die ganze Datei auf*/ /*jeden Fall mit der entsprechenden Nummer und dem Anhängsel .kurz abgespeichert.*/

"ged Text:Wordworth7/Dokumente/Ansprachen/"||Nummer||".kurz sticky" /*GoldEd wird gestartet, damit ich meine Kurzbeschreibung bearbeiten kann.*/ /*Die Option sticky bewirkt, daß das Skript erst dann weiterläuft, wenn ich*/ /*GoldEd wieder beendet habe.*/ if Mail="J" then do if ~show("P",GOLDED.1) then address command ged "sys:rexxc/Waitforport GOLDED.1" address GOLDED.1 Lock current release 4 'open t:Ansprache.rtf' replace string "ä" by "'8a" all quiet replace string "ö" by "'9a" all quiet replace string "ü" by "'9f" all quiet replace string "ß" by "'a7" all quiet unlock 'save all nolf exit' /* Was soll das nur schon wieder sein? Hier ersetze ich alle ä,ö,ü,ß*/ /* durch die entsprechenden Codierungen, wie sie im RTF-Format eigentlich*/ /* verwendet werden - nur Wordworth macht das leider nicht. Zumindest*/ /* WW6 nicht - ich habe WW7 darauf noch nicht überprüft.*/ address command 'echo >t:Ansprachemailtext "Hallo!"' 'echo >>t:Ansprachemailtext "Anbei eine Ansprache von mir."' 'echo >>t:Ansprachemailtext "Viele Grüße"' 'echo >>t:Ansprachemailtext' 'echo >>t:Ansprachemailtext "Heiko"' 'echo >>t:Ansprachemailtext "Hier die Kurzfassung:"' /*Das Folgende ist eine Zeile*/ 'join t:Ansprachemailtext Text:Wordworth7/Dokumente/Ansprachen/'||Nummer||'.kurz to t:Ansprachemailtext2' /*bis hier*/ "sys:rexxc/Waitforport YAM" address YAM mailwrite /* writemailto "Tscho" "writesubject Ansprache_von_Heiko" "writeletter t:Ansprachemailtext2" writequeue mailwrite*/ writemailto "ThoVo" "writesubject Ansprache_von_Heiko" "writeletter t:Ansprachemailtext2" "writeattach t:Ansprache.rtf" writequeue mailwrite writemailto "Reinhard" "writesubject Ansprache_von_Heiko" "writeletter t:Ansprachemailtext2" "writeattach t:Ansprache.wpf" writequeue end /*OK, jetzt werden die Dateien verschickt. Einmal nur die Kurzbeschreibung,*/ /*einmal als RTF-Datei, einmal als WordPerfect-Datei.*/ if DB="J" then do address DataBase GETFILENAME if Result=0 then do SAVE end 'OPEN Text:DBProV3.1/Aufsätze/Aufsätze.db' 'DEMARKRANGE $F1 "#?"' 'SHOW ALL'

'SETSEARCH FIELD PART'

'SEARCHFIELD $F1' 'SEARCH eig. Anspr.' 'SEARCHFIELD $F2' 'SETSEARCH GREATER' 'SEARCHNEXT ' Nummer if RC=0 then do GETDATA $F1 IF RESULT="EIG. Anspr." THEN DO SCHONDA=1 END END /* Hier wird in DBPro erstmal überprüft, ob nicht schon ein Eintrag für*/ /* diese Ansprache vorhanden ist. Ein neuer wird nur gemacht, wenn diese*/ /* Nummer nicht gefunden wurde. (SCHONDA=0)*/ IF SCHONDA ~=1 THEN DO 'ADD' 'PUTDATA $F1 eig. Anspr.' 'PUTDATA $F2' NUMMER 'PUTDATA $F3 Kuschel, H.' /*Das Folgende ist eine Zeile*/

Erfolg=OPEN("Kurzdatei","Text:Wordworth7/Dokumente/Ansprachen/"||Nummer||". kurz","R") /*bis hier*/ If Erfolg then do Do while ~EOF("Kurzdatei") Zeile=Readln("Kurzdatei") Select when abbrev(Zeile,"Text")=1 then do 'PUTDATA $F4 'substr(Zeile,7) end when abbrev(Zeile,"Datum")=1 then do DatumOrt=substr(Zeile,8) end when abbrev(Zeile,"Ort")=1 then do DatumOrt=DatumOrt||", "||substr(Zeile,6) 'PUTDATA $F7 'DatumOrt end when abbrev(Zeile,"Stichworte")=1 then do 'PUTDATA $F12 'substr(Zeile,13) end Otherwise do NOP end end end end /* Jetzt werden die Daten in die einzelnen Felder meiner Datei geschrieben:*/ /* $F1 ist der Oberbegriff, $F2 die Nummer, $F3 der Autor. Alles andere*/ /* lese ich aus der Kurzdatei, die ich vorhin angelegt habe. Das wird dann*/ /* automatisch an die richtige Stelle geschrieben.*/

'SORT $F1 $F2' 'SAVE' end end /*Sortieren, speichern, Ende.*/ if Grossdruck = "J" then do address value Wordworthport SAVEAS NAME "Text:Wordworth7/Dokumente/Ansprachen/000.GROSSDRUCK" DOCUMENT A4 "2cm" "2cm" "1.67cm" "2.54cm" 1 "2cm" LANDSCAPEOFF CTRLDOWN CURSOR UP SHIFTDOWN CURSOR DOWN FONT SIZE "24pt" PARAGRAPH 0 0 0 FULL AUTO ONEHALF PRINTOPTIONS REVERSE BLACKANDWHITE ODDANDEVENPAGES SAVE PRINT end /*Großdruck, falls gewünscht. Das Dokumentformat muß geändert werden,*/ /*weil ich normalerweise DinA4 quer zweispaltig bevorzuge.*/ /*Durch den ganzen Sermon mit CTRLDOWN etc. wird der gesamte Text*/ /*markiert. Dann stelle ich die Schriftgröße 24pt. ein, ein geeignetes*/ /*Absatzformat, und ab in den Drucker damit. */ If Normaldruck>0 then do address value Wordworthport OPEN FILENAME "Text:Wordworth7/Dokumente/Ansprachen/000.TEMP" FORCE PRINTOPTIONS REVERSE BLACKANDWHITE COLLATE COPIES NORMALDRUCK ODDANDEVENPAGES PRINT end /*Die "normale" Druckvariante kommt nach dem Großdruck, weil sie viel länger*/ /*dauert. Querformat ist ziemlich langsam mit Wordworth. :( */ /*Beachte bei PRINTOPTIONS, daß eine initialisierte Variable drin ist!*/ /*An einer Stelle steht NORMALDRUCK. In dieser Variable ist gespeichert,*/ /*wie viele Ausdrucke ich davon haben will.*/ address command If Mail="J" then do "delete >NIL: t:Ansprache.rtf" "delete >NIL: t:Ansprachemailtex#?" "delete >NIL: t:Ansprache.wpf" If Normaldruck>0 then do "delete >NIL: Text:Wordworth7/Dokumente/Ansprachen/000.TEMP" END /*Ein bißchen aufräumen muß sein. :) */

So, das war ein ziemlich langes Programm. Viele weitere Programme, oft auch kommentierte, findest Du im Aminet, im Verzeichnis util/rexx. Schau Dich ruhig einmal um. Evtl. findest Du dort auch schon das, was Du gerade schreiben wolltest... oder auf jeden Fall gute Anregungen fürs eigene Programmieren.

5.5. Das Ende

Das war der ARexx-Kurs. Geschafft. Ich hoffe, Du hattest Spaß daran, und ich konnte das meiste halbwegs verständlich erklären. Wenn Du Probleme haben solltest, wende Dich an meine Adresse. Ich möchte demnächst den ganzen Kurs ins AmigaGuide-Format umwandeln und dann im Aminet veröffentlichen. Er wird voraussichtlich veröffentlicht unter docs/help/ARexx-Kurs.lha Da ich dabei ein paar AGuide-Kniffe einbauen will, bräuchte ich jemanden, der/die diesen Guide unter AmigaOS 2.x testet. Ich weiß nämlich nicht, wie es da funktioniert. Außerdem suche ich Leute, die mir ein paar Kurzinformationen zu anderen Texteditoren als GoldEd geben können, damit ich auch diese Editoren berücksichtigen kann. Solltest Du Dich hier irgendwo angesprochen fühlen, melde Dich doch bitte mal bei mir. Danke!

Heiko«