\documentstyle[german,dina4,titlepage]{article}

\textwidth13.5cm

\begin{document}

\begin{titlepage}

\title{
	{\Huge \bf ARexxBox}\\
	{\Large \bf ARexx Interface Designer}\\
	{\large Copyright \copyright 1992 by}
}

\author{
	Michael Balzer\\
	\\
	Internet: balzer@heike.informatik.uni-dortmund.de\\
	Zerberus: M.BALZER@AWORLD.ZER\\
	\\
	Wildermuthstraße 18\\
	W-5828 Ennepetal 14\\
	GERMANY
}

\date{\today}

\maketitle

\end{titlepage}

\pagenumbering{roman}
\tableofcontents
\newpage

\pagenumbering{arabic}
\pagestyle{headings}
\parskip1.5ex plus 0.5ex
\parindent0ex

\hyphenation{ARexx-Box sind Com-mand-Shell oder}
\newcommand{\arb}{{\sc ARexxBox}}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% los geht's %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{Rechtliches}

\subsection{Copyright}

\arb\ ist copyright \copyright 1992 by Michael Balzer.  Alle
Rechte vorbehalten.  \arb\ ist Public Domain Software, das heißt
in diesem Fall, daß Gebühren, Bezahlung, Lizenzvergabe o.ä.~
weder für die \arb\ selbst, noch für den von ihr erzeugten Code
notwendig sind.

Gegen Spenden jeglicher Art habe ich (als armer Student :-)
natürlich nichts einzuwenden.

Wenn Sie die \arb\ oder die von ihr erzeugten Routinen und
Verfahren benutzen, um ein ARexx--Interface für ein Programm
(kommerziell, Shareware oder Public Domain) zu erstellen, dann
muß dies in der Dokumentation des Programms oder in dessen
``About''--Requester erwähnt werden.

Außerdem würde ich es sehr begrüßen, wenn Sie mir eine Notiz über
die Verwendung der ARexxBox, die Art des Programms und den
Befehlsumfang des ARexx--Interfaces zukommen lassen könnten
(vorzugsweise per EMail).

\subsection{Verbreitung}

\arb\ ist Public Domain, das heißt sie darf frei kopiert und
weitergegeben werden solange alle Dateien des Originalarchives
unverändert zusammen bleiben.  Die Verbreitung auf elektronischen
Netzen ist erwünscht.

Mit Ausnahme der Verteilung im Rahmen der Commodore Native
Developer's Upgrades und deren elektronischer Äquivalente darf
die ARexxBox {\em nicht} kommerziell vermarktet werden.

Unter den deutschen PD--Autoren gibt es in letzter Zeit
Bemühungen, eine für alle PD--Händler verbindliche Weisung zum
Vertrieb von PD--Software zu erstellen.  Diese Weisung wird sich
vorraussichtlich sowohl auf die Preisgestaltung einzelner Disks
als auch auf die Preisgebung ganzer Sammlungen wie den
Fish-CD-ROMs erstrecken.

Da ich diese Bemühungen (obwohl ich sie teilweise als
ungerechtfertigt betrachte) nicht unterlaufen will, unterstelle
ich hiermit die \arb\ in allen auf Urheberrechtlich geschützte
PD--Software anwendbaren Punkten dieser (noch nicht existenten)
Weisung.

Vorraussichtlich wird durch die Weisung der Vertrieb auf
Disketten zu Preisen von mehr als fünf DM und der Verkauf als
Teil eines CD-ROMs für mehr als 30 (dreißig) DM illegal, so daß
alle betroffenen Händler schon jetzt von einem Vertrieb der \arb\
Abstand nehmen sollten.

\section{Einleitung}

Die Wichtigkeit und Leistungsfähigkeit von ARexx auf dem Amiga
dürfte Ihnen schon klar sein, sonst würden Sie sich
wahrscheinlich nicht dieses Manual durchlesen.  Ich muß Sie also
nur noch davon überzeugen, daß die ARexxBox das richtige Werkzeug
zum Erstellen der ARexx--Anbindung für Ihr Programm/Projekt ist
;-)\footnote{bei {\TeX} bekommt der Smily immer so ein breites
Grinsen, finden Sie nicht auch?  :-)}.

\subsection{Warum ARexxBox?}

ARexxBox (inspiriert von der GadToolsBox von Jan van den Baard)
ist ein Tool, das das Erstellen eines ARexx--Interfaces für ein
Programm extrem erleichtert und vereinfacht.

Die Fähigkeiten in Stichpunkten:

\begin{itemize}

\item Die Syntax und Resultaterzeugung der ARexx--Befehle entspricht
   in allen Punkten den vom Style Guide
   vorgeschlagenen Regeln, z.B.~ werden Argumenttemplates wie bei
   DOS-Befehlen (ReadArgs) benutzt und die Keywords VAR und
   STEM werden automatisch unterstützt.
 
\item Zu jedem Befehl kann eine beliebig große Argumentenliste und
   eine beliebig große Resultatenliste angelegt werden.

\item Für Argumente sind alle ReadArgs()--Templates erlaubt und
   werden {\em automatisch} unterstützt, für Resultate werden die
   optionalen Templates /N und /M unterstützt.

\item Intuitionoberfläche (erstellt mit GadToolsBox :-).
 
\item Erzeugt C--Source: Ein Modul mit den nötigen Grundfunktionen
   und ein Modul mit den Interfaceroutinen, in die nur noch
   der spezifische Code einzusetzen ist.
 
\item Auf Wunsch wird Source für eine CommandShell erzeugt, d.h.
   eine Shell in der die ARexx--Befehle direkt eingegeben und
   ihre Ausgaben betrachtet werden können.
 
\item Die CommandShell kann auch zum Ausführen von Macrodateien
   benutzt werden.
 
\item Ein Programm kann so viele ARexx--Ports und CommandShells
   öffnen, wie das Amiga--Messagepassing--System MessagePorts
   zuläßt.

\item Die vom Style Guide vorgeschlagenen Standard-Kommandos habe
   ich schon für Sie abgetippt. Beispielcode für einige dieser
   Befehle liegt auch bei.

\end{itemize}

\subsection{Systemanforderungen}

Die einzige Bedingung zur Lauffähigkeit sowohl der \arb\ als auch
des erzeugten Codes ist AmigaOS 2.x, d.h.~ mindestens Kickstart
und Workbench 2.04.  An die Hardware werden so gut wie keine
Anforderungen gestellt, \arb\ sollte auf jedem Amiga laufen.

Naja, {\em eine} Anforderung wird gestellt:  Da das
{\arb}--Fenster mehr als 200 Zeilen hoch ist, muß eine
NTSC--MedRes--Workbench im Overscan betrieben werden damit das
Fenster geöffnet werden kann.  Alternativ könnte man auch einen 6
oder 7 Punkte großen Systemfont einstellen...

Sie sollten sich außerdem eine Kopie von Nico Fran\c{c}ois'
reqtools.library besorgen, wenn Sie noch keine haben.

Um den erzeugten Source zu kompilieren benötigen Sie einen
ANSI--C--Compiler der auch Funktionen aus der \verb!amiga.lib!
von Commodore importieren und verarbeiten kann.  Sie benötigen
mindestens Version 37.32 (12.11.91) der \verb!amiga.lib!, um den
erzeugten Code linken zu können.

Die Version 37.32 ist im Native Developer's Upgrade V37.4 (11/91)
enthalten, vielleicht wird sie auch schon bei manchen Compilern
mitgeliefert.

\section{Bedienung des Programms}

An der Bedienung der \arb\ ist absolut nichts ungewöhnliches.
Sie sollten auf Anhieb damit zurechtkommen, wenn Sie jemals mit
einer Amiga--Applikation gearbeitet haben.

\subsection{Eingabe}

Für die Eingabe einer Befehlsdefinition empfiehlt sich folgende
Vorgehensweise:  Taste {\sc N} drücken, Namen des ARexxbefehls
eingeben und mit {\sc Return} bestätigen.  Die \arb\ wandelt den
Namen in Großbuchstaben und unzulässige Zeichen in Underscores
('\_') um und prüft den Namen auf Eindeutigkeit.  Falls schon ein
solcher Befehl existiert kann der Name korrigiert werden.

Danach legen Sie die Argumente fest.  Für jedes Argument drücken
Sie die Taste {\sc E} und geben dann den Namen ein.  Auch dieser
wird auf Eindeutigkeit geprüft.

Genau so verfahren Sie für die Resultatenliste, nur daß das
Shortcut für ein neues bzw.  weiteres Resultatfeld dort die Taste
{\sc W} ist.

Argumente und Resultate können direkt nach der Eingabe oder nach
dem Anwählen per Mausklick in der Liste mit den jeweiligen `up'--
und `do'--Gadgets nach oben bzw.  unten verschoben werden oder
mit der jeweiligen `Remove'--Funktion gelöscht werden.

Die Templateoptionen werden im ReadArgs()--Stil (siehe AutoDocs)
an die Namen angehängt, also zum Beipiel ARG1/K/N oder LISTE/M.
Bei den Resultatfeldern sind nur die Optionen /M für Liste und /N
für numerisch erlaubt.

\subsection{MsgPort Basename}

Der `MsgPort Basename' ist der Default--Basisname für alle von
der Applikation eröffneten ARexx--Ports.  Bei Bedarf (schon
existentem Port unter dem Namen) wird so lange eine höhere Nummer
an den Basisnamen angehängt bis der Port ohne Konflikt geöffnet
werden kann.

Auf jeden Fall sollte aber die Applikation (wie im Demo--Programm
gezeigt) ein Argument bzw.  Tooltype namens ``PORTNAME''
verstehen, damit der Benutzer Einfluß auf die Namensgebung nehmen
kann.  Ein solcher per Argument festgelegter Portname wird zum
neuen Basisnamen und kann auch entsprechend durch eine angehängte
Nummer ergänzt werden.

Der `MsgPort Basename' wird außerdem als Standard--Dateiextension
für von der Applikation gestartete ARexx--Skripten eingesetzt.

\subsection{CommandShell}

Mit diesem Gadget bestimmen Sie, ob bei der Sourcegenerierung
Code für eine CommandShell erzeugt werden soll.  Diese Option
sollte im Normalfall ruhig eingeschaltet sein, da die
CommandShell--Funktionen auch zum Ausführen externer Makros
nützlich sein können.

\subsection{Merge in}

Diese Funktion ergänzt die im Speicher befindliche Kommandoliste
um die ARexx--Kommandos aus dem auszuwählenden {\arb}--File, die
noch nicht in der Liste vorhanden sind.

Dadurch ist es möglich, sich Pakete von ARexx--\-Kom\-man\-dos
für verschiedene Zwecke anzulegen, und diese dann nach Bedarf zu
kombinieren.

\subsection{Print}

Soll eine Dokumentationshilfe sein.  Für jeden Befehl wird der
Name, die Syntax und die Resultate ausgegeben.

Vorschlägen für eine andere und bessere Formatierung gegenüber
bin ich sehr aufgeschlossen.

\subsection{Generate Source}

Hiermit wird der Sourcegenerator gestartet.  Der im FileRequester
eingegebene Name wird um die evtl.  vorhandene Extension ({\tt
.c, .h oder \_rxif.c}) gekürzt, dann wird überprüft, ob schon
eine Datei {\tt {\sl name}\_rxif.c} existiert.

Falls eine solche existiert fragt die \arb\ nach, ob diese
wirklich überschrieben werden soll.  Diese Frage ist wichtig, da
in diesem Modul auch Ihr eigener Code stehen kann, Sie sollten
sie also nicht leichtfertig bestätigen.

Gegebenenfalls kopieren Sie einfach Ihren alten
Interface--Sourcecode in ein anderes File und setzen die
Funktionen nachher einzeln sinnvoll zusammen.

Es werden drei Dateien erzeugt:  {\tt {\sl name}\_rxif.c}, {\tt
{\sl name}.c} und {\tt {\sl name}.h}.

\section{Der generierte Source}

\subsection{Dateien}

\subsubsection{Basismodul}

Das Basismodul wird unter dem Namen {\tt {\sl name}.c}
abgespeichert und sollte nicht editiert werden.  Es enthält die
Routinen zum Senden von ARexx--Befehlen, zur Verwaltung der
Rexx--Hosts, den ARexx--Dispatcher und falls gewünscht die
Funktionen zur CommandShell.

Eine genaue Beschreibung dieser Funktionen finden Sie im
mitgelieferten Dokument \verb!ARexxBox.doc!, welches im
AutoDocs--Format gehalten ist.

\subsubsection{Headerfile}

Das Headerfile wird unter dem Namen {\tt {\sl name}.h}
abgespeichert.  Es enthält die Deklarationen der Basis-- und
Interfacefunktionen sowie die zu den Interface--Routinen
gehörenden Datenstrukturen zur Übergabe der Parameter und
Resultate.

Die Definition \verb!REXX_EXTENSION!\ legt die
Standard--Dateiextension für von Ihrer Applikation gestartete
ARexx--\-Skrip\-ten fest.  D.h.  ein \verb!SendRexxCommand(host,
"test");!\ wird versuchen, das ARexx--Skript
\verb!test.<rexx_extension>!\ zu starten.  Die Extension ist
gleich dem Messageport--Basisnamen, der nach Möglichkeit dem
allgemein verwendeten Projektkürzel (siehe Style Guide)
entsprechen sollte.

Die RexxHost--Struktur enthält einen Zeiger auf den Messageport,
den Portnamen, einen Reply--Zähler für noch ausstehende Replies
vom RexxMaster und einen Zeiger auf eine {\tt RDArgs}--Struktur
für das Parsen der Parameter.  Für jeden neuen Host wird von {\tt
SetupARexxHost()} eine neue Instanz dieser Struktur angelegt, so
daß beliebig viele Hosts eröffnet werden können.

Die Stringvariable \verb!RexxPortBaseName!\ enthält den im
Stringgadget eingegebenen Basisnamen für die Ports.

\subsubsection{Die Datenstrukturen}

Für jede eingegebene ARexx--Funktion wird eine Parameterstruktur
definiert, die zumindest aus den beiden Returncode--Feldern (rc
und rc2) besteht.  Falls das Kommando Argumente entgegennimmt
oder Resultate liefert enthält die Struktur außerdem eine
Unterstruktur `arg' bzw.  eine Unterstruktur `res'.

Die Unterstrukturen enthalten zu jedem Eintrag in der jeweiligen
Liste (Argumente oder Resultate) ein Feld, das den gleichen Namen
wie der Eintrag in der Liste, nur in Kleinbuchstaben (und
natürlich ohne die Templateoptionen) hat.

Wenn also zum Beispiel ein Kommando ein Argument {\tt
FILENAME/A/K} erwartet, dann steht nach dem Parsen der im Aufruf
genannte Filename in {\tt rxd\_struct.arg.filename}.

Für Textparameter wird ein Feld vom Typ \verb!char *!, für
numerische Werte (Option /N) ein Feld vom Typ \verb!long *!
erzeugt.  Boolesche Werte (Option /S oder /T) werden als einfache
\verb!long!--Typen repräsentiert.

Listen (Option /M) werden durch einen Zeiger auf ein Array von
\verb!char *!  bzw.  \verb!long *!  (also \verb!char **!  bzw.
\verb!long **!) repräsentiert.  Die Listen können beliebig lang
sein, das Ende einer Liste wird durch einen NULL--Zeiger
gekennzeichnet.

Die Typgebung und Bedeutung der Felder bei den Resultaten erfolgt
auf genau dieselbe Art und Weise.

\subsubsection{Interfacemodul}

Im Interface--Modul (unter dem Namen {\tt {\sl name}\_rxif.c})
wird für jede definierte ARexx--Funktion ein Funktionsrumpf
erzeugt, in den normalerweise nur noch der spezifische Code
eingesetzt werden muß.

\subsection{Interface--Funktionen}

Jede Interface--Funktion wird drei mal vom Dispatcher aufgerufen,
das erste Mal um den Speicher für die Parameterstruktur
anzufordern und die Defaultwerte dort einzutragen, das zweite Mal
um die eigentliche Aufgabe durchzuführen\footnote{Anm.:  Dieser
Durchlauf findet nur statt, wenn das Parsen der Argumente
fehlerfrei war}, und zum dritten Mal um den Speicher wieder
freizugeben.

Auf diese Art und Weise ist es möglich, eigene lokale Variablen
zu benutzen.  Diese müssen, damit der Code reentrant ist (für
mehrere Hosts gleichzeitig), in die Parameterdatenstruktur mit
eingebunden werden.

Dazu wird einfach eine neue, lokale Struktur definiert, deren
erster Bestandteil eine Instanz der Parameterstruktur ist, also
z.B.:

\begin{verbatim}
void rx_help( ..., struct rxd_help **rxd, ... )
{
    struct myrxd {
        struct rxd_help rxd;
        /* Hier die eigenen lokalen Variablen eintragen */
        ...
    } *rd = (struct myrxd *) *rxd;
    
    ...
}
\end{verbatim}

Welcher Teil einer Interface--Prozedur wann aufgerufen wird geht
eindeutig aus dem erzeugten Code hervor.

\subsection{Resultate}

Die Resultate eines ARexx--Befehls müssen --- falls vorhanden ---
in der Substruktur {\tt res} der {\tt rxd}--Struktur eingetragen
werden.

Die Namen und Datentypen der Felder entsprechen den Namen und
Templateoptionen der Befehlsdefinition, wobei allerdings nur die
Templates /M und /N zugelassen sind.

Es werden also immer {\em Zeiger} auf Daten übergeben, Zeiger auf
Zeichen oder Longs oder Zeiger auf Arrays von solchen Zeigern,
wobei in einem Array ein NULL--Zeiger das Ende markiert.

Die Routinen der \arb\ übernehmen die Formatierung in das nachher
vom Anwender im Befehlsaufruf angegebene Format.  Wenn keines der
beiden Schlüsselworte VAR bzw.~ STEM angegeben wurde, wird das
Resultat im VAR--Format als normales ARexx--Resultat
zurückgegeben, landet also in der allgemeinen ARexx--Variablen
{\tt RESULT}.

Das STEM--Format besteht aus einer Liste von Wertzuweisungen, die
aus jeweils einem Variablennamen und dem dazu gehörenden Wert
bestehen.

Jeder Variablennamen besteht aus dem im Aufruf übergebenen Wort
gefolgt von dem Namen des Resultatfeldes gefolgt von einem Punkt
und dann entweder dem Wort ``count'' oder einer Indexzahl.

Die erste Listeneintragung enthält immer die Zuweisung der Anzahl
der in der Liste enthaltenen Werte an die Stemvariable mit der
Extension ``count''.

Beispiel:  Der Befehl {\tt INHALT} habe ein Resultat {\tt
INHLISTE/M}.  Bei einem ARexx--Aufruf in der Form ``{\tt INHALT
STEM TEST.}'' wird eine Resultatliste der Form

\begin{verbatim}
    TEST.INHLISTE.COUNT = <n>
    TEST.INHLISTE.0 = <erster Eintrag>
    TEST.INHLISTE.1 = <zweiter Eintrag>
    ...
    TEST.INHLISTE.n-1 = <letzter Eintrag>
\end{verbatim}

erzeugt.  Das VAR--Format geht aus dem STEM--Format hervor, indem
einfach alle Listeneinträge durch SPACEs getrennt zu einem String
verkettet werden.

In diesem Zusammenhang muß ich darauf hinweisen, daß für eine
Weiterverarbeitung des VAR--Formats bei Resultatstrings, die
Spaces enthalten, die Strings durch geeignete Quotes begrenzt
sein sollten.  Dies wird {\em nicht} von der \arb\ übernommen, so
daß Sie dafür selbst Sorge tragen müssen.

\subsection{Fehler}

Wenn während der Ausführung eines Kommandos Fehler auftreten,
müssen diese an das aufrufende Programm zurückgegeben werden,
damit dieses entsprechend darauf reagieren kann.

ARexx bietet dazu normalerweise nur die Variable RC, die einen
ganzzahligen Fehlercode enthalten kann, per Konvention im Bereich
0 bis 20.

Die \arb\ bietet hier eine etwas erweiterte Möglichkeit über eine
automatisch generierte weitere Variable namens RC2.  In dieder
Variable können sowohl Fehlercodes als auch Fehlerstrings
(Beschreibungen) zurückgegeben werden, die dann vom
ARexx--Programm abgefragt werden können.

Zur technischen Seite siehe \verb!ARexxBox.doc!.

\subsection{Anbindung an ein Programm}

Im Hauptprogramm müssen nur noch wenige Schritte unternommen
werden, um das ARexx--Interface in Gang zu bringen.

Es müssen die {\tt exec.library}, {\tt dos.library} und die {\tt
rexxsyslib.library} geöffnet werden.  Die ersten beiden werden
normalerweise schon vom Startup-Code des Compilers geöffnet, so
daß nur die Rexx--Library von Hand geöffnet werden muß.

Ein ARexx--Host wird mit {\tt SetupARexxHost()} initialisiert.
Optional kann man einen anderen Basisnamen für den MsgPort
übergeben.  Dann muß man nur noch in die normale
Event-Wait--Behandlung die Abfrage des Portsignals und den Aufruf
des Dispatchers einbauen, und schon läuft die ARexx--Anbindung.

Einer CommandShell wird ein Eingabe--, ein Ausgabe--FileHandle
(nicht notwendigerweise verschieden) und ein Prompt--String
übergeben, dann läuft sie bis EOF.  Es ist z.B.~ auch möglich,
eine CommandShell (mit {\tt dos.library / CreateNewProc}) als
eigenen Prozeß asynchron laufen zu lassen.  Wenn kein
Ausgabe-FileHandle ({\tt NULL}) übergeben wird, erfolgen keine
Ausgaben.

Hier ein (minimales) Beispielprogramm:

\begin{verbatim}
#define HOSTSIG(host) (1L << host->port->mp_SigBit)

void main( int argc, char *argv[] )
{
    struct RexxHost *myhost;
    BPTR fh;

    /* Initialisieren */
    
    if( !(RexxSysBase = OpenLibrary( "rexxsyslib.library", 35 )) )
    {
        printf( "No RexxSysLib\n" );
        exit( 20 );
    }
    
    /* Host eröffnen */
    
    if( !(myhost = SetupARexxHost(NULL)) )
    {
        printf( "No Host\n" );
        exit( 20 );
    }
    
    /* Erst eine CommandShell... */
    
    if( fh = Open( "CON:////CommandShell/AUTO", MODE_NEWFILE ) )
    {
        CommandShell( myhost, fh, fh, "test> " );
        Close( fh );
    }
    else
        printf( "No Console\n" );
    
    /* ...und dann 'richtiger' ARexx-Betrieb */
    
    printf( "Address me on Port %s!\n", myhost->portname );
    printf( "Cancel me with CTRL-C\n" );
    
    while( 1 )
    {
        long s = Wait( SIGBREAKF_CTRL_C | HOSTSIG(myhost) );
        
        if( s == SIGBREAKF_CTRL_C )
            break;
        else
            ARexxDispatch( myhost );
    }
    
    CloseDownARexxHost( myhost );
    CloseLibrary( RexxSysBase );
    exit( 0 );
}
\end{verbatim}

\section{Sonstiges}

Diese Anleitung kann keine detaillierte Einführung in die Sprache
Rexx oder Programmierung von ARexx--Routinen bieten.  Die
zusätzliche Lektüre des ARexx--Kapitels im ``User Interface Style
Guide'' von Commodore und des ``ARexx User's Reference Manual''
von William S.  Hawes ist daher sicher keine schlechte Idee.

Die ARexxBox wurde auf einem Amiga 2000 mit A2630, 7 MB RAM, GVP
Serie II mit Quantum P210S und Seagate ST296N und MultiVision
Flickerfixer plus NEC Multisync 3D entwickelt.

Compiliert wurde das Ganze mit dem Manx Aztec C 5.2a, ich habe
mich halt an das Teil gewöhnt...

\subsection{Danksagungen}

Ich möchte mich hiermit besonders bedanken bei:

\begin{itemize}

\item Meinen aktiven Betatestern: Ralf Kaiser, Garry Glendown,
	Wolfgang Kueting und Stefan Zeiger.

\item Der Amiga--Crew bei Commodore, für den Amiga und AmigaOS Release
	2.  Ich glaube inzwischen nicht mehr, daß es einen Amiga vor
	Release 2 gab.

\item Jan van den Baard, für seine exzellente GadToolsBox, die
	mir als Anregung diente und mir auch bei der Erstellung der
	Oberfläche gute Dienste geleistet hat.

\item Nico Fran\c{c}ois, für seine ReqTools.Library mit ihren
	wirklich Programmierer-- und Anwenderfreundlichen Requestern.

\item William S. Hawes für seine hervorragende Rexx--Portierung.

\end{itemize}

\subsection{Bugreports und Vorschläge}

Ich bitte darum, mir Bugreports und Vorschläge möglichst per
EMail zuzuschicken.

Bei Bugreports bitte {\em immer} die genaue Konfiguration
angeben, den Fehler möglichst {\em detailliert} beschreiben und
versuchen, ihn auf ein {\em minimales} Programm zu reduzieren,
das den Fehler verläßlich reproduziert.

Vorschlägen gegenüber bin ich immer aufgeschlossen.

Michael Balzer

\end{document}
