Den Gesellenbrief in Sachen Installer haben wir nach den ersten beiden Folgen bereits in der Tasche. Ziel dieses Teils ist die Meisterpr�fung. Wir werden daher nun auch noch die letzten Geheimnisse der vielseitigen Skriptsprache ans Tageslicht bringen.
Die meisten Ausgabefunktionen des Installers wandeln ihre Argumente automatisch in den jeweils erforderlichen Datentyp um, wie man es auch erwartet. Das ist zwar sehr praktisch, bringt aber wenig ein, da man keinerlei M�glichkeit hat, die Formatierung der Ausgabe zu beeinflussen. Deshalb kann der Installer auch mit vielen der in C �blichen Steuerzeichen (Stichwort: �printf�) umgehen. Um dieses Feature zu nutzen, klammert man an beliebiger Stelle einen String (der Steuerzeichen enth�lt) und z�hlt die einzuf�genden Daten danach auf. Einige Beispiele:
("Version %ld" #version) ("Sedezimal 43 = %lx" 43) ("CPU: %s, FPU %s" (database "CPU") (database "FPU")) ("Prozentangabe:%3ld%%" #x)Intern wird die Formatierung mit der Exec-Funktion �RawDoFmt� abgewickelt. Alle dort bekannten Formatierunganweisungen sind damit auch im Installer nutzbar. Die wichtigsten sind �%ld� f�r Dezimalzahlen (das �l� steht f�r 32 Bit), �%lx� f�r sedezimale (auch hexadezimale) Ausgabe und �%s� f�r Strings. Ein einzelnes Prozentzeichen wird mit "%%� erzeugt.
Entlarvt: Manches System mu� sich mit unz�hligen Assigns herumschlagen. Der startup-Befehl f�gt sie in die user-startup ein. |
(trap \<Flags> \<Anweisungen>)
; trap-Demo; �1996 Marcel Bennicke (onerror (message "Fehler konnte nicht abgefangen werden." " Beende Skript!")) (procedure P_Kopieren (copyfiles (prompt "Die Datei RAM:XYZ wird nun kopiert (existiert " "gew�hnlich nicht, es kommt also zu einem DOS-Fehler)") (help "") (source "RAM:") (dest "RAM:t") (choices "XYZ") (confirm) ) ) ; mit trap Fehler abfangen und Typ in #fehler speichern (set #fehler (trap ( (message "Die folgende Anweisung wird einen Fehler " "provozieren. Sie k�nnen auch den Knopf " "�Installation abbrechen� ausprobieren!") (P_Kopieren) (message "Hierhin gelangt man in Fehlerfall nicht") ))) ; war es wirklich ein Fehler? (if #fehler (message "Ein Fehler ist aufgetreten: " (select #fehler "" "Benutzerabbruch" "Speicherplatzmangel" "Skript-Fehler" (cat "DOS-Fehler Nr. " @ioerr) "falsche Parameter") ) ) (message "Hier wird das Skript fortgesetzt. " "Anschlie�end das gleiche nocheinmal aber ohne trap") (P_Kopieren) ; provoziere Fehler (message "Kopieren erfolgreich.") |
Listing 1:Ausnahmebehandlung wie mit Amiga E - einfacher geht es kaum |
Tritt nun eine Fehlfunktion in einer der Anweisungen auf, wird das Skript nicht verlassen, sondern der Installer verzweigt zur n�chsten Anweisung hinter dem Trap-Block. Der Wert des Trap-Ausdrucks ist die Fehlernummer oder Null falls kein Fehler auftrat. Wie man �trap� sinnvoll nutzen kann, ist in Listing 1 zu sehen. Beim Ausprobieren dieser Funktion f�llt jedoch auf, da� sie in der aktuellen Fassung des Installers nicht nur auf die auftretenden Fehler reagierte, sondern stets auf alle Fehlfunktionen. Leider lassen sich mit �trap� nicht restlos alle Fehltritte bereinigen � einige f�hren unweigerlich zum Abbruch der Installationsprozedur. Damit man auch in diesem Fall wenigstens noch Aufr�umarbeiten durchf�hren kann, existiert die Anweisung �onerror�:
(onerror \<Anweisungen>)Sie spezifiziert einen Block von Anweisungen, welche nach einem besonders schweren Fehler auszuf�hren sind. Anschlie�end verl��t der Installer die B�hne. Recht praktisch ist au�erdem, da� sich �onerror� auch mehrmals verwenden l��t, was kontextabh�ngige Fehlerbehandlung erm�glicht.
; Eingaben umlenken; �1996 Marcel Bennicke ; die einfache aber unsch�ne Methode (run "format <>CON:0/10/400/50 DRIVE df0: NAME Leer" (prompt "Formatiere Diskette in Laufwerk DF0:\n") (help "") (confirm) ) ; so geht's besser (textfile (dest "t:in") (append "\n")) (set #name (askstring (prompt "Formatiere Diskette in DF0:. Bitte geben" " Sie den Namen ein:") (help "") (default "Leer") )) (run (cat "format <t:in DRIVE df0: NAME " #name) (prompt "Bitte Legen Sie eine Diskette in das Laufwerk DF0:") (help "") (confirm) ) |
Listing 2: Ein Griff in die Trickkiste des AmigaDOS macht den Formatbefehl wesentlich komfortabler |
; startup-Demo; �1996 Marcel Bennicke (startup "Startup-Demo" (prompt "F�ge einige Zeilen zur user-startup hinzu.") (help "") (command (cat "echo \"Test-Installation\"\n" "Assign XYZ: " @default-dest)) (confirm) ) (run "sys:utilities/Multiview S:user-startup" (prompt "user-startup wird angezeigt...") (help "") (confirm)) |
Listing 3: Der startup-Befehl f�gt Anweisungen in die user-startup ein |
(run \<Programm> [\<Argumente>])startet ein externes AmigaDOS-Programm mit den entsprechenden Argumenten,
(execute \<Skript> [\<Argumente>])f�hrt ein AmigaDOS-Skript aus und
(rexx \<ARexx-Programm> [\<Argumente>])bringt ein ARexx-Programm zur Ausf�hrung (RexxMast mu� aktiv sein). Alle drei Anweisungen akzeptieren die gleichen Optionen, das Ergebnis der jeweiligen Operation wird vom Installer durchgereicht. Sekund�re Resultate werden in der Standardvariablen �@ioerr� gespeichert. So richtig haarig wird es aber erst, wenn ein AmigaDOS-Skript vom Installer zusammengebastelt werden mu� � die Konfiguration der Netzwerksoftware AmiTCP/IP erfolgt auf diese Weise. Auch an solche F�lle dachten die Entwickler und implementierten die Anweisung �textfile�. Mit ihrer Hilfe lassen sich beliebige Textdateien erstellen, indem man einzele Strings � oder gar andere Dateien � Schritt f�r Schritt zu einem Ganzen zusammenf�gt. Mit etwas Geschick erh�lt man so auch ARexx-Skripts, die der Installer selbst aufruft. Alles ist hier m�glich.
Doppelter Boden: Ein Netz, das fehlgeschlagene Aktionen auff�ngt, l��t sich mit der trap-Anweisung aufspannen |
Ein anderes Problem k�nnen externe Programme sein, die ihre Eingaben in einem Shell-Fenster erwarten (zum Beispiel �Format� wartet auf Best�tigung durch <Return>). Ruft man ein solches Programm aus einem Installerskript auf, existiert selbstverst�ndlich keine Konsole, in die der Benutzer etwas eingeben k�nnte. Man kann nun Ein- und Ausgabekanal kurzerhand auf ein neues Fenster umlenken. Das hat allerdings den Nachteil, da� der Nutzer nun mit zwei Schnittstellen, dem Installer und der Konsole, hantieren mu�.
Eleganter ist es, alle Parameter direkt im Installer zu erfragen und anschlie�end nur den Eingabekanal durch eine zuvor angelegte Datei zu ersetzen (Listing 2).
Der Format-Befehl wird sich anschlie�end s�mtliche Eingaben aus der Datei �t:in� abholen. In diesem Fall enth�lt sie nur den Code f�r die <Return>-Taste. Nachteil dieser Methode: Abbruch durch <Ctrl-C>; ist nicht mehr m�glich. Ein sehr wichtiger Befehl ist �startup�. Er klinkt beliebige Programme in den Bootvorgang des Rechners ein, indem er die Datei �s:user-startup�, die das AmigaOS beim Hochfahren abarbeitet, um die entsprechenden Befehlszeilen erweitert. Das ist im �brigen der richtige Ort, um logische Zuweisungen f�r die eigene Applikation anzulegen.
Alle zu einem bestimmten Programm geh�renden Befehle umrahmt startup durch zwei Kommentare. Dadurch kann jeder Abschnitt in der user-startup einer Applikation zugeordnet werden. Installiert man nun dasselbe Programm nocheinmal (zum Beispiel nach einem Update), werden die alten Befehle automatisch durch neue ersetzt.
; Symbolische Variablen und Icons; �1996 Marcel Bennicke (procedure P_Info #d ( (iconinfo (dest #d) (getstack "#stack") (getposition "#x" "#y")) (message "\n\nDas Icon " #d ".info befindet sich an Position " #x "," #y " und ben�tigt " #stack " Bytes Stapelspeicher.") )) (message "�ffnen Sie w�hrend das Skript abgearbeitet wird die " "Schublade \"Sys:Prefs\" und beobachten, was passiert!") (P_Info "sys:prefs/Font") ; Iconname ohne .info ! (working "Vertauche Position des Zeichensatz- und " " Locale-Voreinstellers...") (iconinfo (dest "sys:prefs/Font") (getposition "#xf" "#yf")) (iconinfo (dest "sys:prefs/Locale") (getposition "#xl" "#yl")) (tooltype (dest "sys:prefs/Font") (setposition #xl #yl)) (tooltype (dest "sys:prefs/Locale") (setposition #xf #yf)) (P_Info "sys:prefs/Font") |
Listing 4: Auch mit Icons kann der Installer jonglieren. Dieses Skript vertauscht die Position zweier Piktogramme. |
Das bedeutet, Zugriffe auf deren Inhalte erfolgen nicht direkt unter Angabe eines Bezeichners im Quelltext, vielmehr ergeben sich Variablennamen aus dem aktuellen Inhalt von Strings. Dieses Verhalten ist dem von Zeigern in anderen Sprachen �hnlich. Die Anweisung
(symbolset \<Symbolname> \<Wert> ...)implementiert die beschriebenen Features. Sie funktioniert bis auf die angesprochene Eigenheit exakt wie die normale set-Anweisung und dient dazu, Variablen Werte zuzuweisen. Der Bezeichner der betroffenen Variablen wird durch einen String oder beliebigen anderen Ausdruck (der eine Zeichenkette zum Ergebnis hat) charakterisiert.
(symbolset "#a" 1); =(set #a 1)Zur Anweisung �symbolset� existiert selbstverst�ndlich auch ein Gegenst�ck �symbolval�, welche den Inhalt von Variablen ausliest. Als Argument erwartet die Funktion ebenfalls einen Ausdruck, der den gew�nschten Variablenbezeichner beschreibt:
(symbolval "#a") ; = 1
Der gute Stil | ||||||||||||
|
Vor allem bei Updates bereits installierter Applikationen kommt es darauf an, da� man diese Informationen nicht zerst�rt. Die Funktion �iconinfo� extrahiert alle ben�tigen Daten aus einem Piktogramm und speichert sie in separaten Variablen. Sie ist im �brigen zur Zeit die einzige Funktion, die das mit Hilfe symbolischer Variablen erledigt.
Von gr��erer Bedeutung, als das Extrahieren von Informationen aus einem Icon, ist der umgekehrte Weg. Viele Programmepakete nutzen gleich w�hrend der Installationsprozedur die Gelegenheit, ein paar Konfigurationsdaten -- etwa Pfade zu ben�tigten Dateien -- in den Tooltypes zu speichern. Mit Hilfe der Anweisung �tooltype� lassen sich Piktogrammerkmale ver�ndern, Stack sowie Standardprogramm zuordnen. Beispielsweise der Befehl
(tooltype (dest "ram:SuperPrg") (settooltype "FASTMODE") (settooltype "Level" "2") (settooltype "hungry" "") (setstack 20000) )l�scht im Piktogramm �RAM:SuperPrg.info� das Merkmal �FASTMODE�, erzeugt die zwei Merkmale �LEVEL� (mit dem Wert 2) sowie �HUNGRY� (ohne weitere Parameter) und setzt den Stack auf 20000 Bytes. Sogar die Positionsangaben eines Piktogramms k�nnen manipuliert werden. Es versteht sich von selbst, da� mit dieser Option sehr vorsichtig umzugehen ist. Sie dient vorrangig dazu, die von �iconinfo� gelieferten Koordinaten auf andere Piktogramme zu �bertragen. Listing 4 demonstriert, wie beide Anweisungen zusammenspielen.
; Lokalisiertes Installerskript, �1996 Marcel Bennicke ; eine Sprache mu� ausgew�hlt werden (set #loc 0) ; Englisch ist Standard (if (= @language "deutsch") (set #loc 1)) ; Englische Strings --------------------------------------- (if (= #loc 0) (set #ask-where "Please select installation directory\n" #ask-age "Please enter your age" )) ; Deutsche Strings ---------------------------------------- (if (= #loc 1) (set #ask-where "Bitte w�hlen Sie das Installationsverzeichnis" #ask-age "Bitte geben Sie ihr Alter ein" )) ; hier geht's los ---------------------------------------- (welcome) (message "Dieses Skript spricht Deutsch und Englisch. " "Starten Sie es mit verschiedenen Einstellungen " "im Lokale-Voreinsteller!") (set @default-dest (askdir (prompt #ask-where) (help @askdir-help) (default @default-dest))) (set #age (asknumber (prompt #ask-age) (help @asknumber-help))) |
Listing 5: Selbst lokalisierte Skripts sind kein Problem |
Es ist offensichtlich, da� sich so gleich mehrere Kataloge in ein Skript einbauen lassen und Erweiterungen leicht vorzunehmen sind. Listing 5 zeigt, wie es gemacht wird. Der Installer kennt nur zwei einfache Datentypen: Zahlen und Strings. Zusammen mit symbolischen Variablen und etwas Geschick lassen sich aber auch Arrays implementieren. Der Trick besteht lediglich darin, aus einer Grundzeichenkette (welche quasi den Namen des Arrays darstellt) und einem Index einen neuen Variablennamen zusammenzubasteln:
(set #index 0) (symbolset ("#X%ld" #index) 4)Man erzeugt also f�r jedes Element des Arrays letztlich eine eigene Variable (hier X0, X1...). M�chte man sp�ter den Inhalt auswerten, merkt man gar nicht mehr, wie die Variable erzeugt wurde:
(if (= #X0 4) ...) ; 1. ElementF�r Zugriffe mit variablem Index kann man den gleichen Trick wie oben anwenden:
(select ("X%ld" #i) "0" "1"...)Damit sind wir am Ende unseres Kurses. S�mtliche Befehle und Anweisungen der zuletzt verf�gbaren Version wurden durchleutet, so da� Sie auf eine solide Grundlage zur�ckgreifen k�nnen.
lb |
Anweisungen | ||||||||||||
Externe Programme (execute \<Name> (prompt) (help) (confirm) (safe)) AmigaDOS-Skript ausf�hren
(rexx \<Name> (prompt) (help) (confirm) (safe))
(run \<Name> (prompt) (help) (confirm) (safe))
(startup \<App-Name> (prompt) (help) (confirm) (command))
(textfile (prompt) (help) (dest) (append) (include) (confirm) (safe))
Kontrollanweisungen
(abort [\<Strings>])
(onerror \<Anweisung>)
(exit [\<Strings>])
Verschiedene
(tooltype (prompt) (help) (dest) (settooltype) (setdefaulttool) (setstack) (noposition) (setposition) (confirm) (safe))
|
Funktionen |
(iconinfo (prompt) (help) (dest) (gettooltype) (getstack) (getdefaulttool) (getposition) (confirm) (safe)) (V42.12)
Liefert Informationen �ber ein Piktogramm, dessen Name in �dest� (ohne �.info�) steht. Die Argumente der get... -Optionen sind symbolische Variablen (siehe auch �tooltype�).
(symbolval \
(transcript \ |
� Copyright by MagnaMedia Verlag AG, Haar bei M�nchen
Ver�ffentlichung und Vervielf�ltigung nur mit schriftlicher Genehmigung des Verlags