5.1 Bibliothek: Allgemeines                                                5 -   1
________________________________________________________


5.1  Allgemeines  zur  Bibliothek


Funktionsbersicht

Bevor  Sie  weiterblttern  und  womglich  von  der  Funktionsvielfalt  der  ber
einhundert Module erschlagen werden, geben wir Ihnen eine kleine bersicht.

Einige Module kennen Sie sicher schon aus Ihrem Modula-2 Buch:

   - InOut      zur Ein-/Ausgabe ber Tastatur und Bildschirm,
   - Terminal   ebenso (aber nur auf TOS-Bildschirm ohne GEM!)
   - Mathlib0   mit mathematischen Funktionen fr REALs/LONGREALs,
   - Strings    zum Arbeiten mit Zeichenketten und
   - Storage   um NEW und DISPOSE verwenden zu knnen.

Wenn Sie Neueinsteiger in Modula-2 sind, reicht es aus, wenn Sie sich erst
einmal nur mit diesen Modulen beschftigen.

Fr Fortgeschrittene folgt eine bersicht weiterer ntzlicher Module:

Dateifunktionen:
    Files, Text, NumberIO, Binary, Directory.

Grafik (GEM)
    AES...,   VDI...,    GEM...,    ObjHandler,    EventHandler,    TextWindows,
    WindowBase, WindowLists, EasyGEM0, EasyGEM1.

String/Zahlen-Umwandlung:
    Convert, StrConv, Strings, FuncStrings.

Tastatur- und Zeichenauswertung:
    Characters, Keyboard.

Programmkontrolle:
    Loader, ModCtrl, PrgCtrl.

Diverse Hilfsfunktionen
    SysUtil0      - Variablenvergleiche, -lschen, -lopieren, Bit-Funktionen
    SysUtil1       - Speicherzugriffe aller Art, auch im Supervisormodus
    SysUtil2      - SetJump/LongJump (wie in C), Supervisormodus
    Clock         - Datums-/Zeitbestimmung
    TimeConvert  - Datums-/Zeit-Ein- und Ausgabe
    Lists          - Verwaltung allgemeiner Listen
    RandomGen   - Zufallszahlenerzeugung

Alle Module sind jeweils in ihren Definitionstexten (s. Anhang) dokumentiert!
5.1 Bibliothek: Allgemeines                                                5 -  2
________________________________________________________


bersicht der vorhandenen Module

Folgende Megamax-Module stehen Ihnen incl. Quelltexten zur Verfgung
(Ordner MOS):

GEMDebug    - Hilfsmodul zum schrittweisen Ausfhren v. Modula-Programmen
TOSDebug    - wie GEMDebug, aber mit TOS- statt Fensterausgabe

GEMError    - Treibermodul zum Abfangen v. Laufzeitfehlern (komfortabel)
SimpleError  - Wie GEMError, nur einfacher (siehe Kapitel 2.6 ber Linker)
GEMScan     - Hilfsmodul zum Anzeigen v. Laufzeitfehlern

GEMIO       - Treibermodul zur Ausgabe von InOut in ein GEM-Window
TOSIO        - Treibermodul zur Ausgabe von InOut ber BIOS-Routinen
GEMDOSIO   - Treibermodul zur Ausgabe von InOut ber GEMDOS-Routinen

M2Init        - Initialisierungsmodul fr alle gelinkten Programme
MM2Shell     - Die Shell zum Selbstverndern
MOSConfig   - Konfiguationsvariablen fr Loader, ErrBase, InOut usw.

Von folgenden Modulen haben Sie die Codeversionen erhalten (Ordner IMP):

ArgCV        - Auswertung der Argumentzeile (Command-Line)
ArgCVIO      - Auswertung der Argumentzeile mit E/A-Umleitungsmglichkeit
Binary        - Dateisystem: E/A fr Binrdaten, Seek, FileSize
BinOps        - Vergleichsfunktionen fr jeweils zwei Werte
BIOS         - BIOS-Funktionen
Block         - Sehr schnelles Lschen und Kopieren groer Datenbereiche
Calls          - Aufruf von Modula-fremden Routinen (z.B. Betriebssystem)
Characters   - ASCII-Konstanten und Funktionen zum Auswerten von Zeichen
Clock         - Zeit- und Datumsbestimmung
Compressions- Datenkomprimierung
Console       - Wie Terminal, jedoch Ausgabe ber GEMDOS statt BIOS
Convert       - Umwandlung Zahlen <-> Strings (siehe auch StrConv)
Directory     - Lschen u. Umbenennen v. Dateien, Directory-Hilfsfunktionen
EasyExceptions - Komfortables Abfangen von Laufzeitfehlern
ErrBase      - Grundmodul zum Abfangen von allgemeinen Laufzeitfehlern
Excepts       - Abfangen der Exceptions des Prozessors (680x0)
FastStrings   - Alternatives Strings-Modul
FileBase      - Dateisystem: Fehlerbehandlung und Device-Treiber
FileNames    - Zusammensetzen und Analysieren von Datei- und Pfadnamen
Files          - Dateisystem: ffnen und Schlieen v. Dateien
FPUSupport   - Fr Benutzung der FPU in Accessories und Coroutinen
FuncStrings   - Komfortablere String-Funktionen (Pascal-hnlich)
GEMDOS     - GEMDOS-Funktionen
HdlError      - Spezielles Modul zum Abfangen von allg. Laufzeitfehlern
InOut         - Standard Ein- und Ausgabe
InOutBase    - Modul fr InOut-Treiber (z.B. GEMIO, TOSIO, GEMDOSIO)
5.1 Bibliothek: Allgemeines                                                5 -  3
________________________________________________________


KbdCtrl       - Direkte Tastaturabfrage/-kontrolle
Keyboard     - Auswertung von Tasten mit sog. Scan-Codes
LibFiles       - Verwaltung von Library-Dateien
Lists          - Verwaltung doppelt verketteter Listen
Loader        - Ausfhren von Programmen, auch mit Load-Time-Linking
MathLib0     - Mathematische Grundfunktionen f. REAL-Zahlen
ModCtrl       - Modulverwaltung, Prozeduren als Proze starten
MOSGlobals  - System-globale Konstanten und TYPE-Definitionen
NumberIO    - Dateisystem: E/A von Zahlen in Textform
Paths         - Dateien-Suchfunktionen
PathEnv       - Directory-Umgebung: HomePath und File-Selector
PathCtrl      - Verwaltung von Pfadliste f. Paths-Modul
PrgCtrl       - Programm-/Prozekontrolle (siehe auch ResCtrl)
RandomGen   - Zufallszahlenbestimmung
ResCtrl       - Modulkontrolle (siehe auch PrgCtrl)
ResourceHandler - komfortable Prozekontrolle (setzt auf PrgCtrl, ResCtrl auf)
Runtime       - Laufzeitfunktionen, automatisch vom Compiler importiert
Storage       - Speicherverwaltung
StorBase     - Systemnahes Modul zur Speicherverwaltung
StrConv      - Erweiterte Zahlenumwandlungsfunktionen zu Convert
StringEditor  - Allg. Funktion zur komfortablen Eingabe einer Textzeile.
Strings       - String-Funktionen (siehe auch FastStrings, FuncStrings)
SysCtrl       - Hilfsroutinen fr den Scanner (Module GEMError, GEMScan)
SysInfo       - Ermittelt Prozessortype, Koprozessor, TOS-Version
SysTypes     - Definition v. Systemtypen
SysUtil0      - Hilfsfunktionen zum Lschen v. Variablen, Vergleichen usw.
SysUtil1       - Speicherzugriffe aller Art, auch im Supervisormodus
SysUtil2      - SetJump/LongJump (wie in C), Super-Funktion
SysVars      - Systemvariablen des TOS
TermBase    - Treibermodul zu Terminal
Terminal      - InOut-Treiber f. TOS-Bildschirm (BIOS-Ein-/Ausgaben)
Text          - Dateisystem: E/A von Textdaten
                                           < >
TimeConvert  - Umwandlung Zeit/Datum  -  Text (s. Clock)
UserBreak    - Ermglicht Abbrechen von Programmen ber Tastatur
UserTrace    - Alternative zu Debug
VT52         - Escape-Sequenzen des VT-52-Emulators (f. Textausgaben)
XBIOS        - XBIOS-Funktionen
XBRA         - Bequeme XBRA-Installation
5.1 Bibliothek: Allgemeines                                                5 -  4
________________________________________________________


AES...        - AES-Funktionen des GEM
VDI...         - VDI-Funktionen des GEM
EasyGEM0    - Allgemeine GEM-Hilfsfunktionen
EasyGEM1    - Bequemer Aufruf des Datei-Selektors und der Clipboard-Funk~
                 tionen (Klemmbrett, Scrap-Directory)
EventHandler - Zentrale Verwaltung aller Events des GEM fr das MOS
FastGEM0    - Teils optimierte VDI-Funktionen
FileManagement - Shell-Funktionen: Kopieren, Lschen usw.
GEMEnv      - Verwaltung der GEM-Umgebung
GEMGlobals   - Definitionen globaler GEM-Strukturen
GrafBase     - Grafische Hilfsfunktionen
KbdEvent     - Synchronisiert Tastenereignisse mit Sondertasten (Shift usw.)
LineA         - Line A-Funktionen des TOS.
ObjHandler    - Komfortabler Zugriff auf GEM-Objektbume
TextWindows - Komfortable Fensterverwaltung fr Textausgaben
WindowBase  - Allgemeines Fenster-Kontrollmodul
WindowLists  - Verwaltet automatisch Textzeilen in einem Fenster

Die  folgenden  Module  sind  nicht  dokumentiert,  da  sie  nur  systemintern
verwendet werden und nderungen vorbehalten sind:

GEMShare    - GEM-Systemmodul
InOutFile      - Hilfsmodul fr InOut
MOSCtrl      - Grundmodul fr alle Programme
ModBase      - Hilfsmodul fr Loader & ModBase
SFP004       - Verwaltung f. evtl. vorhandenen Mathe-Koprozessor (68881)
SystemError  - Programmabbruch bei fatalen Fehlern (Speichermangel usw)

Module, die nicht zum MOS gehren und jederzeit von uns oder Ihnen gendert
werden knnen:

MM2ShellRsc - GEM-Resource-Konstanten, mit NRSC  ASH.PRG zu erzeugen.
                                                         _
                 Wollen Sie die Shell erweitern, drfen Sie natrlich dabei auch
                 eine neue Resource-Datei erzeugen und verwenden, denn sie
                 wird nur  von  der  Shell  importiert,  auf  deren  Quelltext  Sie
                 ebenfalls Zugriff haben.
ShellMsg      - Hilfsmodul zur Kommunikation zw. Shell, Compiler und Linker.
                 Achtung - greifen Sie nicht in Ihren normalen Anwendungen
                 darauf zu! Erstens  sind  die  Werte  in  gelinkten  Programme
                 nicht  mehr  initialisiert  (weil  das  nur  die  Modula-Shell  tut),
                 zweitens  behalten  wir  uns  jederzeit  nderungen  daran  vor,
                 so  da  Sie  dann  Versionskonflikte  oder  andere  Probleme
                 bekommen.
5.1 Bibliothek: Allgemeines                                                5 -  5
________________________________________________________


Beispielprogramme (im DEMO-Ordner - Dokumentation in den Quelltexten)

AccDemo     - einfache Accessory-Demo
AsmDemo    - Beispiele fr Aufruf der TOS-Funktionen in Assembler
Dhrystone    - Verbreitetes Testprogramm fr Compiler-Qualitt (Codeerz.)
ExcDemo     - Demonstriert Anwendung des Moduls Excepts
ExcTest      - Demonstriert Anwendung des Moduls Exceptions
Hatschi       - Demonstration von Coroutinen, auch als Interrupts
InitPath       - Hilfsmodul zum Initialisieren einer Pfadliste f. Paths-Funktionen
KbdTest      - Residentes Programm f. Tastaturmakros (KbdCtrl, ModCtrl)
LocalModules - Zeigt die mglichen Import-/Export-Verhltnisse
Sieve         - Auch ein Testprogramm fr Compiler-Qualitt (Codeerzeugung)
TextDemo    - Demoprogramm fr die VDI-Textausgabe
Tiefe          - Sind/waren Sie auch ein MAD-Fan?
WdwLists     - Zeigt Anwendung von WindowLists


Hilfsprogramme (im UTILITY-Ordner - Dokumentation in den Quelltexten)

CompInit      - Ermglicht es, den Compiler als gelinktes Programm zu starten,
                 z.B. vom GEM-Desktop aus, um mehr Speicher frei zu haben.
CmpFiles      - Kann mehrere Dateien in zwei Verzeichnissen vergleichen
Decode       - Dekodiert Dateien
DelFiles       - Lscht mehrere Dateien auf einmal
DoSysInfo    - Zeigt Systeminformationen an (TOS-Version, Scrap-Dir usw.)
Encode       - Kodiert (komprimiert) Dateien
ExecMod      - Damit  kann  jedes  noch  ungelinkte  Programmodul  auch  vom
                 Desktop gestartet werden
GPA          - Ermittelt die Adresse von Prozeduren der Module im Speicher
LibManager   - Anlegen und Bearbeiten von Library-Dateien
LinkInit       - Ermglicht es, den Linker als gelinktes Programm zu starten,
                 z.B. vom GEM-Desktop aus, um mehr Speicher frei zu haben
ModLoad      - Ein  nettes  Programm,  das  die  Mchtigkeit  von  Megamax
                 Modula (speziell des Loaders) mal so richtig ausnutzt
ModList       - hnlich Alternate-R in der Shell, aber ausfhrlicher
ModTrace     - Residentes  Programm.  Zeigt  alle  Module  an,  die  durch
                 Loadtime-Linking in der Shell geladen werden
Monitor       - Erlaubt den Aufruf des Templemon beim Programmstart.
PathEdit      - Prfen und ndern der Pfadlisten in der Shell
SetTime      - Sorgt immer fr korrekt  eingestellte  Zeit/Datum.  Unbedingt
                 bersetzen, linken und in den AUTO-Ordner kopieren (s. auch
                 Kapitel 2.7), wenn keine Uhr im Rechner vorhanden ist!
ShowKeys    - "Quick-And-Dirty"-Programm,  das  alle  Tasteninformationen
                 anzeigt (auch Scan-Codes), benutzt Keyboard & KbdCtrl.
Time          - Anzeigen und Einstellen von Datum und Zeit
Timer         - komplexere Accessory-Demo
5.1 Bibliothek: Allgemeines                                                5 -  6
________________________________________________________


Allgemeine Hinweise zu den Modulen

Die Systemmodule, Programmkontrollmodule, Dateimodule sowie einige weitere
Module bilden zusammen das "Modula Operating System", kurz MOS genannt.

Sys-Funktionen

In einigen Modulen finden sich Prozeduren, deren Namen mit Sys beginnen. Sie
ergnzen immer hnliche Prozeduren  ohne  diesen  Prefix.  Beispiel:  SysOpen
neben Open und SysAlloc neben ALLOCATE. Wo immer dies auftritt, erzeugen
die Prozeduren Resourcen (z.B. Dateien, Speicherbereiche), die normalerweise
sptestens bei Beendigung des Programms (Proze) wieder freigegeben werden
sollen. Damit  nichts  verloren  geht,  wenn  ein  Programm  nicht  selbst  dafr
sorgt, bei Programmende alles wieder freizugeben bzw. zu schlieen, wird dies
automatisch von den Modulen des MOS durchgefhrt. Nun gibt es Flle, wo
dies nicht erwnscht ist. Z.B. ist es mglich, ber  globale  Variablen  eines
anderen  Programms  (Proze)  Speicher  anzufordern,  der  beim  Enden  des
Programms,  das  den  Speicher  anforderte,  nicht  automatisch  freigegeben
werden soll. In diesem Fall wre der Speicher mit SysAlloc statt ALLOCATE
anzufordern. Die Sys... Funktionen sorgen also allgemein dafr, da die damit
angelegten  Resourcen  nicht  bei  Programmende  automatisch  freigegeben
werden.  Sie  knnen  dann  nur  durch  den  expliziten  Aufruf  der  jeweils
zugehrigen Freigabeprozedur freigegeben werden (z.B. Close, DEALLOCATE).

Wichtig ist die Anwendung solcher Sys-Funktionen vor allem bei Programmen,
die resident bleiben (z.B. mit Hilfe der Funktion InstallModule aus ModCtrl) und
bei Accessories. Bei Accessories sollten immer, wenn mglich, Sys-Funktionen
verwendet werden, da es sonst aufgrund eines Konzeptionsfehlers vom TOS
z.B.  passieren  kann,  da  ein  im  ACC  angeforderter  Speicherbereich  bei
Beendigung  eines  vom  Desktop  gestarteten  Programms  wieder  freigegeben
wird, was dann zum Totalabsturz des Rechners fhren kann.

Systemfunktionen

Es sind einige Funktionen in den Quelltexten als systemzugehrig oder intern
ausgewiesen.  Solche  Funktionen  drfen  in  keinem  Fall  von  Ihnen  ohne
ausdrcklichen Hinweis von unserer Seite verwendet werden. Auch wenn Sie
glauben, zu wissen, was die Funktionen im einzelnen tun - wir mssen Sie
warnen, wir haben da schon bse berraschungen erlebt! Teilweise behalten
wir uns auch vor, diese Funktionen in spteren Versionen intern fr andere
Zwecke zu mibrauchen.
5.1 Bibliothek: Allgemeines                                                5 -  7
________________________________________________________


bertragung (Portierung) von Modula-2 Programmen fremder Systeme

Wenn Sie Programme von anderen Modula-2 Systemen  bernehmen  wollen,
knnen Programmnderungen notwendig werden. Zum einen ist es mglich, da
hardwarespezifische Zugriffe stattfinden. Hier mag eine Anpassung schwierig
sein, und wir knnen Ihnen dabei leider nicht helfen. Dann kommt es vor, da
andere Modula-2 Compiler Datentypen in anderen Formaten verarbeiten und es
dabei  z.B.  bei  Typanpassungen  zu  verschiedenen  Ergebnissen  kommt.  Das
grte  Problem  liegt  aber  meistens  in  der  Verwendung  unterschiedlicher
Library-Funktionen. Hierzu einige Hinweise:

Strings

Da Herr Wirth nicht das Format von Zeichenketten festlegte, sind mehrere
Formate mglich. Hufig, wie auch bei Megamax Modula, beginnt das erste
Zeichen eines Strings im ersten Element eines ARRAY  0..n  OF CHAR. Die
Zeichenkette, die in solch einem Feld steht, kann entweder das gesamte Feld
ausfllen oder durch ein Null-Zeichen (0C) begrenzt werden. Die Lnge einer
Zeichenkette ist also gleich der Position des ersten Null-Zeichens des Strings
oder gleich der Feldelementanzahl. Es gibt Systeme, die den gesamten unbe~
nutzten Rest des Strings mit Null-Zeichen fllen; bei Megamax Modula ge~
schieht dies nicht - alle Zeichen nach  einem  Null-Zeichen  in  einem  String
werden ignoriert.

Es ist theoretisch auch mglich, da das erste Element eines Strings immer
die  Lnge  der  gltigen  folgenden  Zeichen  enthlt.  Dann  beginnt  das  erste
Zeichen  einer  Zeichenkette  beim  zweiten  Feldelement,  ein  abschlieendes
Zeichen  ist  unntig.  Diesem  Stringformat  werden  Sie  wahrscheinlich  nicht
begegnen, hchstens, wenn Sie Pascal-Programme bernehmen. In diesem Fall
mssen Sie beachten, da sich bei indiziertem Zugriff auf Stringelemente die
Positionen der Zeichen alle um Eins verschieben.

Die Funktionen in einem Strings-Modul sind nicht normiert. Einige Standard~
funktionen finden sich jedoch in jeder Modula-2 Implementation. Dazu zhlen
Pos, Assign, Delete, Insert, Concat (Concatenate) und Length. Letztere wird
sicher nie Probleme bereiten, bei den anderen ergeben sich bis zu drei Unter~
schiede zu anderen  Systemen:  die  Reihenfolge  von  Parametern,  die  Anzahl
derselben und das Verhalten bei Fehlern (Megamax Modula liefert einen BOOLEAN-
Wert, der Fehler anzeigt, andere Systeme stoppen das Programm durch einen
Laufzeitfehler). Das einfachste ist, sich ein Hilfsmodul zu erstellen, das die
bentigten Funktionen mit den Parametern des fremden Systems exportiert und
die Megamax-Strings-Funktionen darber aufruft.
5.1 Bibliothek: Allgemeines                                                5 -  8
________________________________________________________


Bildschirm E/A (Ein-/Ausgabe)

Unsere WriteHex-Routinen geben das '$'-Zeichen selbst mit aus. Wenn Sie
das strt, knnen Sie statt dessen die WriteNum-Routinen verwenden, die kein
Zeichen voranstellen und auch mit Leerzeichen statt mit Nullen linksseits fllen
knnen.

Die Megamax-Module Terminal, TextWindows, Text und InOut geben Zeichen,
die mit Read eingelesen wurden, nur wieder auf den Bildschirm aus, wenn sie
keine Steuerzeichen, sondern sichtbare Zeichen  sind.  Dies  hat  sich  in  der
Praxis  bewhrt.  Programme  fr  fremde  Modula-2  Systeme  knnten  davon
abhngig sein, da jedes eingelesene Steuerzeichen auf den Bildschirm wieder
ausgegeben wird, da dies ursprnglich so vorgeschlagen wurde. In diesem Fall
behelfen Sie sich am besten ebenfalls mit einer Hilfsfunktion, die z. B. wie
folgt aussieht:

  PROCEDURE Read ( VAR c: CHAR );
    BEGIN
      InOut.Read ( c );
      IF c <= 37C  (* hchstwertiges Steuerzeichen *) THEN
        Write ( c )  (* Steuerzeichen ausgeben *)
      END
    END Read;

Sie knnen aber auch das Modul Console verwenden - dies gibt jedes einge~
gebene Zeichen gleich wieder aus, aber hat auch noch andere Eigenheiten, die
Sie am besten im Definitionsmodul nachlesen.

hnlich verhlt es sich mit ReadString bei TextWindows, Console und Terminal.
Bei Eingabeende mit der "Return"-Taste bleibt der Cursor hinter dem einge~
gebenen Text stehen anstatt, in die folgende Zeile vorzurcken. Sollte dies
stren, kann hnlich wie beim obigen Beispiel eine Hilfsprozedur ReadString
deklariert werden, die nach dem entsprechenden Aufruf in Terminal, Console
bzw. TextWindows WriteLn nachfolgend aufruft.

Umgekehrt gibt ReadString aus InOut am Ende immer CR/LF aus (springt also
in die nchste Zeile). Ist dies unerwnscht, kann es generell durch Entfernen
des WriteLn-Aufrufs in der entsprechenden Funktion in GEMIO, GEMDOSIO
oder TOSIO verhindert werden  (nach  der  nderung  mu  das  Treibermodul
nicht nur neu bersetzt, sondern auch in die Shell neu eingelinkt werden, damit
sich die nderung bemerkbar macht).
5.1 Bibliothek: Allgemeines                                                5 -  9
________________________________________________________


Auch  verhalten  sich  die  Readstring-Funktionen  vieler  Modula-Systeme  beim
Eingeben sehr unterschiedlich. Manche erlauben die Eingabe einer  beliebigen
Zeile bis zum Drcken von Return, andere beenden schon  bei  der  Eingabe
eines  Leerzeichen  oder  lesen  zwar  auf  einmal  eine  ganze  Zeile  ein,  die
folgenden  ReadString-Aufrufe  liefern  aber  immer  nur  Wort-Fragmente,  die
durch eingegebene Leerzeichen getrennt sind.

Wir haben deshalb jeweils zwei Funktionen in Terminal und TextWindows dafr
vorgesehen.  Da  diese  Module  als  whlbare  Ein-/Ausgabetreiber  fr  InOut
verwendbar sind und durch die Konfigurationsmodule GEMIO und TOSIO, die
wir im Quelltext mitliefern, beliebig an InOut adaptierbar sind, brauchen sie
selbst nur zwei Grundfunktionen zu bieten:

* ReadFromLine liest eine Zeile mitsamt aller Control-Codes; bei Dateien wird
  gelesen,  bis  das  Zeilenende  erreicht  oder  der  String  gefllt  ist,  bei
  interaktiver Eingabe kann so lange korrigiert werden,  bis  sie  mit  Return
  abgeschlossen wird. Es gibt hier auch noch die  Funktion  ReadString,  die
  lediglich noch vorhanden ist, damit Megamax-Programme, die fr die alte
  System-Version  Eins,  in  der  es  noch  kein  ReadFromLine  gab,  ohne
  nderungen  weiterhin  bersetzbar  bleiben.  ReadString  sollte  hier  aber
  berhaupt  nicht  mehr  verwendet  werden,  sondern,  je  nach  Bedarf,
  ReadToken oder ReadFromLine (Normallfall).

* ReadToken ermglicht lediglich die Eingabe eines Wortes - sobald ein Leer-
  oder Control-Zeichen (also auch Return) eingegeben wird, kehrt ReadToken
  zurck.

InOut greift nun ber ein Treibermodul (z.B. GEMIO, TOSIO, GEMDOSIO) auf
diese Funktionen zu. Dazu bietet es ebenfalls die Funktionen  ReadFromLine,
ReadToken  und  ReadString:  Wie  sich  diese  Funktionen  verhalten,  wird  im
Treibermodul bestimmt. So ist es  mglich,  ReadString  entweder  direkt  auf
ReadToken oder ReadFromLine abzubilden, oder  mit  Hilfe  von  ReadFromLine
eine gepufferte Eingabe zu realisieren, die auch bei Read-Aufrufen aus der
gepufferten Zeile liest. Das soll Sie aber nicht verwirren, deshalb sparen wir
uns nun weitere Erklrungen - verstehen Sie es einfach  so:  Benutzen  Sie
mglichst nur ReadFromLine/ReadToken (egal, ob aus Terminal, TextWindows
oder InOut importiert) - wenn Sie einmal mit dem bertragen eines Modula-
Programms von oder zu einem anderen System konfrontiert werden, werden
Sie  diese  Unterschiede  erkennen  und  dann  auch  durchschauen,  welche
nderungen Sie an den Treibermodulen vornehmen mssen.

Wie schon erwhnt, sind also ggf. die Treiber GEMIO oder TOSIO fr die
Konfiguration  der   InOut-Funktionen   verantwortlich:   Die   unterschiedlichen
Konfigurationen mssen durch abgewandelte Versionen der Module GEMIO und
TOSIO erstellt werden. So knnte man ein JPI IO erstellen, um die TopSpeed-
                                                _
IO-Module nachzubilden, eine  HM2 IO  fr  Hnisch-Modula-Programme  usw.
                                     _
Solch ein Modul mu dann als erstes Modul im Hauptprogramm - also vor
5.1 Bibliothek: Allgemeines                                                5 - 10
________________________________________________________


InOut - importiert werden. Dies wird brigens auch empfohlen, wenn Sie bei
normalen Megamax-Programmen, die InOut verwenden, die Ausgaben nicht in
ein Fenster bekommen wollen: Schreiben Sie einfach

  IMPORT TOSIO; (*$E MOS *)

vor den InOut-Import. Dann wird erstens das TOSIO-Modul, wie beim Linken,
als InOut-Treiber verwendet, zweitens wird die Endung MOS erzeugt, was fr
einen TOS-Bildschirm (Textcursor, keine Maus) beim Starten sorgt.

Bereits  in  Planung  ist  ein  komfortableres  Konzept  fr  die  nchste  Shell-
Version: Dann knnen Sie fr jedes Modul individuell die Umgebung dauerhaft
bestimmen, also seine Stack-Gre, die einzubindenden Treiber (sowohl fr's
Starten  mit  Load-Time-Linking  als  auch  beim  festen  Linken)  und  andere
ntzliche Konfigurationen, die von auen bestimmbar sein sollten.

Wenn Sie brigens eigene Konfigurations- oder InOut-Treibermodule (z.B. fr
andere Modula-Systeme) erstellt haben, senden Sie sie doch im Rahmen des
MEMOX-Service (s. Kapitel 1.5) an Application Systems! Damit helfen Sie nicht
nur  den  anderen  Megamax-Anwendern  (auch  uns,  damit  wir  uns  anderen
Dingen widmen knnen, bei denen Sie uns nicht helfen knnten), sondern Sie
erhalten dafr ja auch Beitrge anderer Anwender.


Hinweise zu den Quelltexten

Um Ihnen als Anwender die Mglichkeit zu geben, den Dialog mit dem Modula-
System  nach  Ihren  Wnschen  optimal  zu  gestalten,  haben  wir  die  dafr
zustndigen Module im Sourcetext mitgeliefert.  Die  interessantesten  Module
sind  im  folgenden  aufgefhrt,  es  lohnt  sich  aber  auch,  sich  die  anderen
Sourcetexte (siehe UTILITY-, DEMO- und MOS-Ordner) einmal anzusehen.


MM2SHELL.M

Dies ist die Modula-2 Shell, das Desktop des Modula-Systems. Sie knnen
sie beliebig verndern und erweitern. Auerdem lassen sich darin viele Bei~
spiele fr Programmieranwendungen finden, z. B. Zugriff auf GEM-Funktionen,
Aufruf von Programmen oder Dateizugriffe. Dazu gehren auch die  Dateien
MM2SHELL.RSC und MM2SHELL.RSD, die mit Hilfe des Resource Construction
Programms  (RCP)  verndert  werden  knnen.  Beachten  Sie,  da  nach  dem
ndern der Resource  mit  dem  RCP  beim  neuen  Abspeichern  zwei  Dateien
MM2SHELL.D  und  MM2SHELL.I  erzeugt  werden,  die  die  Konstanten  der
GEM-Objekte enthalten und von der Shell importiert werden. Allerdings mssen
die  Modulnamen  in  den  beiden  Quelltexten  dazu  erst  von  Mm2shell  in
Mm2shellRsc umbenannt werden!
5.1 Bibliothek: Allgemeines                                                5 -  11
________________________________________________________


GEMError.I & SimpleError.I

Diese Module werden bei Bedarf beim Linken von Programmen als Treiber mit
eingebunden. Sie sorgen fr das Abfangen und Anzeigen aller Laufzeitfehler.
Zudem enthalten sie die  Texte  fr  Systemmeldungen,  die  nach  Belieben  in
Englisch oder auch Esperanto bersetzt werden knnen.


MOSConfig.I

Hierin sind  globale  Variable  enthalten,  die  von  verschiedenen  MOS-Modulen
verwendet  werden.  Im  Sourcetext  knnen  die  Voreinstellungen  nach  Ihren
Preferenzen  verndert  werden,  z.  B.  Datumsformat  (fr  Funktionen  aus
TimeConvert) oder Zahlendarstellungsformate (fr REAL-Darstellungen).


Bedienung der Ein-/Ausgabefunktionen

Viele Funktionen der Megamax-Bibliothek bieten auch in der Benutzung ber~
durchschnittlichen Komfort, verglichen mit anderen Entwicklungssystemen auf
Microcomputern.

Besonders offensichtlich  ist  das  beispielsweise  bei  Verwendung  des  InOut-
Moduls durch das StdIO-Fenster, in dem die Ausgaben geschehen. Wartet das
Programm auf eine Eingabe, macht es dauernd Ausgaben oder benutzt andere
GEM-Funktionen, so da die Event-Abfrage vom GEM regelmig aktiviert wird
(beispielsweise  ist  dies  auch  durch  regelmige  Aufrufe  der  Prozedur
FlushEvents aus dem Modul  EventHandler  zu  erreichen).  Das  Fenster  kann
bewegt, in seiner Gre verndert und der Ausschnitt mit der Maus bestimmt
werden.

Weniger offensichtlich sind da schon die Editiermglichkeiten bei Benutzung der
Funktionen ReadString, ReadFromLine und ReadToken. Nicht nur, da mit der
Taste Backspace Korrekturen mglich sind, auch viele andere Tasten haben
eine Funktion:

    Return                Beendet Eingabe
    Enter                 Wie Return
    Undo                 Bricht Eingabe ab (liefert Leerstring)
    <
     -                    Cursor nach links
     >
    -                     Cursor nach rechts
             <
    Control  -            Zum Zeilenbeginn
              >
    Control -             Zum Zeilenende
    Insert                Ein Leerzeichen an Cursorposition einfgen
    Backspace            Zeichen vor Cursor lschen
    Delete                Zeichen unter Cursor lschen
    Esc                   Zeile lschen
    Clr (Shift-Home)     Wie Esc
    Home                 Zeile ab Cursor lschen
5.1 Bibliothek: Allgemeines                                                5 - 12
________________________________________________________


Ein weiteres Geheimnis, das nur diejenigen bisher erkannten, die die Doku~
mentation zu den Funktionen in Convert aufmerksam gelesen haben, wollen wir
nun lften:

Die Convert-Funktionen zum Umwandeln von Zeichenfolgen in Zahlen erlauben,
da  die  Werte  mit  einem  "$"-  oder  "%"-Zeichen  angefhrt  werden.  Dies
bewirkt dann eine Interpretation des Wertes als hexadezimale bzw. als binre
Zahl.  Da  alle  Funktionen  des  Megamax-Systems,  die  Texte  in  irgendeiner
Weise in Zahlen umwandeln, letztlich auf dieses Convert-Modul zurckgreifen
(wozu haben wir uns schlielich fr Modula-2 entschieden?!), knnen Sie also
auch bei einem ReadCard-Aufruf statt "21" nun "$15" oder gar "%100000101"
eingeben!


Diverse Hinweise zu den Bibliotheken

GEMDOSIO- und TOSIO-Ausgabe

Geschehen die Ein-/Ausgaben ber das Modul InOut, kann bekanntlich beim
Linken durch die Linker-Optionen bestimmt  werden,  ob  GEMDOSIO,  TOSIO
oder GEMIO verwendet werden  soll.  Bei  Modulen,  die  mit  Loadtime-Linking
unter der Shell gestartet werden, ist diese Wahl nicht so einfach mglich.
Normalerweise  wird  die  Konfiguration  verwendet,  mit  der  die  Shell  gelinkt
wurde:  mit  GEMIO.  Der  GEMDOS-  oder  TOSIO-Treiber  kann  dennoch
verwendet werden: Schreiben Sie folgendes in eine Zeile vor dem InOut-Import
im betreffenden Programm:
  IMPORT TOSIO; (*$E MOS *) (bzw. GEMDOSIO statt TOSIO)
Damit  wird  beim  Starten  des  Programms  automatisch  der  TOS-Modus
aktiviert.  Zu  beachten  ist  jedoch,  da  beim  Linken  der  Import  aus  dem
Programm  wieder  entfernt  werden  mu,  wenn  dort  ein  anderes  IO-Modul
eingelinkt werden soll.

Speicheranforderung mit ALLOCATE (Storage-Modul)

Dem  kommenden  ISO-Standard  fr  Modula  nach  wird  ALLOCATE  keinen
Laufzeitfehler auslsen, wenn kein Speicher mehr verfgbar ist, sondern den
Zeiger mit NIL beschreiben.

Zweitens  drfen  Sie  nie  davon  ausgehen,  da  der  angeforderte  Speicher
gelscht, d.h. mit Null-Bytes gefllt, ist. Beachten Sie auch, da die globalen
Variablen bei Megamax Modula-2 zwar mit Null-Werten vorbesetzt  werden,
nach  PIM  und  dem  ISO-Standard  dies  aber  nicht  gefordert  ist,  Sie  bei
Portierung Ihrer Module demnach damit rechnen mssen, da dies auf einem
anderen Compiler/Rechner auch nicht der Fall ist.
5.1 Bibliothek: Allgemeines                                                5 - 13
________________________________________________________


Verwendung von AES- und VDI-Funktionen (Maus-Funktionen und FormAlert)

Sie sollten bei GEM-Programmen darauf achten, niemals auf VDI-Funktionen
zurckzugreifen, wenn entsprechende Funktionen im AES vorhanden sind. Denn
dort, wo das AES eigene Funktionen auf das VDI "aufsetzt", hat letztendlich
auch  das  AES  die  Kontrolle,  und  Sie  knnen  unliebsame  Seiteneffekte
hervorrufen, wenn Sie das AES durch direktes Anwenden des VDI umgehen.

Beliebtes Beispiel ist die Kontrolle der Maus: Es gibt die VDIInput-Prozeduren
ShowMouse  und  HideMouse  sowie  GrafMouse  in  AESGraphics.  Hier  hat
demnach das AES Vorrang. Wird ein Programm vom Desktop gestartet, wird
die Maus ber GrafMouse eingeschaltet. Wenn Sie nun in Ihrem Programm die
Maus mit HideMouse abschalten, verschwindet sie zwar, das AES erfhrt aber
nichts davon, denkt also, sie sei noch sichtbar. Kommt nun eine AES-Funktion
zum Zuge, die die Maus einschalten will, beispielsweise GrafMouse oder auch
FormAlert  (diese  Funktion  versucht  selbststndig,  die  die  Maus  immer
einzuschalten), geht das AES davon aus, die Maus sei sichtbar und teilt dem
VDI deshalb auch nicht mit, die wirklich einzuschalten. Der Effekt: Die Maus
ist nicht zu sehen. Fazit: Lassen Sie die Finger von Show- und HideMouse!

Der richtige Gebrauch der UpdateWindow-Funktion...

    ... bei der Accessory-Initialisierung

Bei der Programmierung eines jeden Accessories sollten Sie folgende Regel
beachten: Zuerst der Aufruf von InitGem, danach RegisterAccessory und - dies
ist  besonders  wichtig  -  UpdateWindow  (TRUE).  Erst  dann  drfen  eine
GEM-Resource-Datei nachgeladen, Speicher angefordert und andere Betriebs~
systemressourcen "geffnet"  werden.  Am  Ende  der  Initialisierung,  also  vor
dem Event-Aufruf, mu  dann  noch  der  Aufruf  von  UpdateWindow  (FALSE)
nachgeholt  werden!  Siehe  dazu  beispielsweise  das  Demo-Programm  Timer
(UTILITY-Ordner).

Wird  das  nicht  beachtet,  knnen  u.U.  schon  whrend  der  Initialisierung
Task-Wechsel zu anderen Accessories und insbesondere ein GEM-Programm
per Autostart-Option gestartet werden und so dann die im  Kapitel  zu  den
Sys-Funktionen beschriebenen Fehler auftreten. (Ein ausfhrlicher Artikel dazu
findet sich im ST-Magazin 11/90 auf Seite 68. Ein Dank an Laurenz Prner,
der darin diese GEM-"Macke" aufgedeckt hat!)

    ... bei Timer-Events mit GEMDOS-Aufrufen

Bekanntlich ist UpdateWindow dann zu benutzen, wenn Sie Manipulationen am
Bildschirm  vornehmen,  also  bei  Benutzung  bestimmter  AES-  und  VDI-
Funktionen.  Ansonsten,  z.B.  bei  GEMDOS-  und  BIOS-Funktionen,  wird  dies
allgemein nicht fr ntig gehalten. Das ist aber leider falsch! Wenn nmlich
aus bestimmten Grnden dabei eine Alert-Box erscheint, knnen Accessories,
5.1 Bibliothek: Allgemeines                                                5 - 14
________________________________________________________



die  auf  einen  Timer-Event  warten,  zum  Zuge  kommen.  Diese  wiederum
knnten  einen  GEMDOS-Aufruf  ttigen.  Wenn  aber  gerade  die  Haupt~
anwendung selbst einen GEMDOS-Aufruf vornahm, ergibt das einen unerlaubten
Wiedereintritt ins GEMDOS, die Folge ist ein Absturz des Rechners.

Wie  kann  es  dazu  kommen?  Die  besagte  Alert-Box  erscheint,  wenn  eine
Funktion  aufgerufen  wird,  die  den  Critical  Error  Handler  aufruft,  weil
beispielsweise keine Disk im Laufwerk  steckt  oder  weil  sie  nicht  gelesen/
beschrieben werden kann. Die FormAlert-Routine des GEM verhindert in diesen
Fllen aber  nicht,  da  Timer-Events  ausgewertet  werden  und  so  kann  ein
Accessory zum Zuge kommen. Der eigentliche Fehler passiert aber erst dann,
wenn  das  Accessory  einen  Wiedereintritt  ins  GEMDOS  vornimmt.  Dies  ist
praktisch immer der Fall, wenn der Critical Error Handler aktiviert wurde, weil
dann ja meist gerade ein Diskzugriff ber die GEMDOS-Funktionen erfolgt.

Was  ist  also  zu  tun?  Wenn  Sie  Timer-Events  behandeln,  mssen  Sie
whrenddessen   auch   alle   evtl.   vorkommenden   GEMDOS-Aufrufe   durch
UpdateWindow einklammern! Da Sie bei Verwendung der Modula-Bibliotheks~
funktionen sich dessen u.U. nicht sicher sein knnen, klammern Sie am besten
die ganze Timer-Event-Behandlung entsprechend ein.

Sie knnen den Fehler brigens leicht probeweise hervorrufen: Nehmen Sie das
Timer-Accessory (UTILITY-Ornder) und entfernen Sie aus der Event-Schleife,
in der die Zeit neu ausgegeben wird, die UpdateWindow-Aufrufe. Installieren
Sie dann das Accessory, wie dort angegeben. Wenn Sie nun einen Diskfehler
erzeugen, indem Sie z.B. Laufwerk A: ohne eine Disk darin ffnen, werden Sie
eine Alert-Box erhalten  und  die  Uhr  wird  whrenddessen  weiterlaufen.  Bei
Besttigung  der  Alert-Box  erhalten  Sie  dann  einen  Systemabsturz  (das
Timer-Modul ruft ber das Clock-Modul indirekt eine GEMDOS-Funktion auf,
die die aktuelle Zeit ermittelt).

Die FPU und Accessories

Die Entwickler von Atari empfehlen, die FPU in Accessories nicht zu benutzen.
Der Grund dafr liegt darin, da im TOS keine Funktionen vorgesehen sind, die
das  Benutzen  der  FPU  von  mehreren  GEM-Tasks  (Hauptprogramm  und
Accessories)  regelt.  Wenn  beispielsweise  die  Register  der  FPUmit  Werten
belegt sind, und dann ein anderes Accessory zum Zuge kme und auch die
FPU benutzt, wrde sie wahrscheinlich die Register-Werte berschreiben. So
denkt Atari.

Wir  haben  zur  Lsung  das  Modul  FPUSupport  geschaffen.  Das  bietet
Funktionen  zum  Retten  und  Restaurieren  des  gesamten  FPU-Status  incl.
Register und sonstiger Einstellungen (z.B. Rundungsmodus). Wollen Sie also in
einem Accessory die FPU benutzen, sehen Sie sich dieses  Modul  an.  Dort
finden Sie die weiteren Hinweise.
5.2 Bibliothek: Programme, Module und Prozesse                         5 - 15
________________________________________________________


5.2  Programme,  Module  und  Prozesse


Das Modulkonzept

Als Programme werden im Folgenden alle die Dateien bezeichnet, die z.B. vom
Desktop aus direkt ausgefhrt werden knnen. Als Module werden die vom
Modula-2 Compiler erzeugten Code-Dateien bezeichnet.

Auch Compiler fr andere Sprachen erzeugen in der Regel nicht sofort aus~
fhrbare Dateien.  Statt  dessen  mssen  diese  Dateien  mit  weiteren,  schon
compilierten Dateien (die die "importierten" Funktionen und Variablen enthal~
ten),  zusammengelinkt  (gebunden)  werden.  Das  TOS  (Betriebssystem  des
Atari)  bietet  nun  eine  Funktion,  mit  der  solche  Programme  geladen  und
gestartet werden knnen. Diese wird z.B. aktiviert, wenn man eine Programm~
datei auf dem Desktop doppelt anklickt. Aber auch ein gestartetes Programm
kann wiederum ein weiteres aufrufen.

Im MOS (Modula-2 Betriebssystem) gibt es eine Funktion, die in der gleichen
Weise  Module  zum  Ausfhren  laden  kann.  Das  Dazuladen  und  Linken  der
importierten Module wird dabei automatisch  erledigt.  Dabei  werden  nur  die
importierten Module nachgeladen, die sich noch nicht im  Speicher  befinden.
Schon  vorhandene  Module  werden  ganz  einfach  von  den  neuen  Modulen
mitbenutzt.

Damit man die Ladefunktion des MOS  berhaupt  benutzen  kann,  mu  erst
einmal  ein  Programm  gestartet  werden,  das  diese  Funktion  enthlt.  Die
Funktion kann sich nur in  einem  Programm  der  herkmmlich  gelinkten  Art
befinden, und das Programm mu ber die TOS-Ausfhrungsfunktion gestartet
werden. Ein solches Programm besteht aus mehreren Modulen, die dann aber
alle schon als vorhanden registriert werden, so da, wenn dann ein anderes
Modul  gestartet  werden  soll,  die  im  Programm  vorhandenen  Module  mit~
verwendet werden knnen (shared code).

Praktisch sieht das also z.B. so aus: Man hat ein Hauptprogramm H1, das die
Module U1, U2 und U3 importiert. Dieses Programm soll vom normalen Desktop
aus gestartet werden knnen. Dazu wird es mit dem Linker gebunden.

Wenn das gelinkte Programm dann durch Doppelklick gestartet wird, befinden
sich die Module H1, U1 U2 und U3 im Speicher. Enthalte U1 nun die MOS-
Funktion zum Starten weiterer Module. Dann kann z.B. in H1 programmiert
worden sein, ein Modul H2 nachzustarten. H2 importiert auerdem U2 und U4.
Wenn es nun  ber  die  MOS-Ausfhrungsfunktion  gestartet  wird,  wird  das
Modul U4 nachgeladen. Die importierten Prozeduren aus U2 werden aus dem
schon vorhandenen Modul mitverwendet, lediglich die Variablen werden bei U2
ein weiteres Mal angelegt.
5.2 Bibliothek: Programme, Module und Prozesse                         5 - 16
________________________________________________________


Wenn man das gleiche unter TOS anstellen wollte, nmlich, da ein Programm
ein zweites nachstartet, mten beide Programme mit jeweils allen bentigten
Modulen gelinkt sein, was bedeuten wrde, da das erste Programm aus H1,
U1, U2 und U3 bestnde und das Nachgeladene aus H2, U2 und U4. Somit
wrde ein Modul zwangslufig doppelt im Speicher vorliegen, was unntigen
Speicherplatz verbruchte.

Das  automatische  Linken  beim  Ausfhren  macht  sich  besonders  bei  der
mitgelieferten Modula-Shell positiv bemerkbar. Whrend die Shell durch viele
importierte  Module  ziemlich  viel  Speicher  belegt,  belegen  viele  Modula-
Programme,  die  von  der  Shell  aus  gestartet  werden,  kaum  zustzlichen
Speicher,  da  meistens  schon  alle  bentigten  Module  von  der  Shell  zur
Verfgung gestellt werden knnen.

Ein weiterer Vorteil liegt darin, da durch gemeinsame Benutzung von Variablen
mehrere nacheinander gestarteten Module Daten bermitteln knnen. Z.B. wird
das Modul ShellMsg von der Shell und dem Compiler importiert. Dadurch kann
der Compiler, bevor er  endet,  in  den  dort  deklarierten  Variablen  z.B.  den
Namen der erzeugten Codedatei oder bei einem Fehler den Fehlertext ablegen,
und die Shell kann diese Daten dann weiterverwenden. Diese Option (shared
data) mu allerdings erst ber eine besondere Compiler-Direktive ($Y, s. Kap.
3.4) angewhlt werden.


Vom Modul zum gelinkten Programm

Die gesamten MOS-Funktionen wurden so konzipiert, da ein Programm erst
als Modul unter der Modula-Shell getestet werden kann und am Ende, falls
dies  vonnten  ist,  mglichst  ohne  nderungen  mit  all  seinen  importierten
Modulen zu einem Programm zusammengelinkt werden kann, das dann  vom
Desktop aus gestartet werden kann. In wenigen Fllen mu jedoch eine Anpas~
sung des zu linkenden Programms durchgefhrt werden.

Wenn  das  von  der  Shell  gestartete  Modul  mit  SetChain  einen  Nachfolger
bestimmt, kann dies nicht mehr geschehen, wenn das diese Funktion aufrufen~
de Modul gelinkt ist und bers TOS gestartet wird. Denn das Nachladen des
Folgeprogramms kann nur vom Aufrufer erledigt werden, und das  TOS  als
Aufrufer lt dies nicht  zu.  Solange  das  Modul  von  der  Shell  mittels  der
Loader-Funktion CallModule gestartet wird, kann diese Funktion nach Ende des
ersten Moduls das nchste nachstarten. Wenn Sie nun also  ein  Programm
geschrieben haben, das aus mehreren, sich abwechselnd nachladenden Modulen
besteht, sollten die Module nie gelinkt werden. Statt dessen sollten Sie ein
Hilfsmodul erstellen, das gelinkt wird und vom Desktop gestartet werden kann.
Es importiert lediglich die Funktion CallModule und startet  damit  das  erste
Modul. Dieses Modul kann dann wiederum andere mittels SetChain nachstarten,
da ja bei Modulende immer zum Hilfsprogramm zurckgekehrt wird.
5.2 Bibliothek: Programme, Module und Prozesse                         5 - 17
________________________________________________________


Allerdings kann auch die Funktion ShellWrite (Modul AESMisc) benutzt werden,
um vom Desktop gestartete Programme - hnlich SetChain - zu verketten.

Ein  Fehler,  der  hufiger  vorkommt,  entsteht  nur  bei  optimiertem  Linken:
Whrend  der  Loader  jedes  importierte  Modul  vollstndig  einbindet  und
initialisiert, kann der optimierende Linker Module ganz entfernen, obwohl sie
importiert  werden.  Dies  passiert  beispielsweise,  wenn   sie   ein   Modul
importieren, ohne Prozeduren oder Variablen daraus zu benutzen. Initialisiert
das  Modul  in  seinem  Krper  Daten  importierter  Module,  wrden  diese
Anweisungen beim optimierten Linken verschwinden.

Dieser Effekt kann leicht daran erkannt werden, da beim Linken solch ein
Modul erst im Fenster angezeigt, dann aber wieder gelscht wird. In diesem
Fall braucht das Modul lediglich mit der Direktive B+ bersetzt werden, am
besten, indem gleich zu Beginn des Moduls (*$B+*) eingefgt wird.

Zur  Sicherheit  kann  auch  erstmal  das  Programm  nicht-optimiert  gelinkt
oder generell  durch  Eintragen  von  -B  in  der  Compiler-Direktiven-Zeile  der
Shell jedes Ihrer Module entsprechend bersetzt werden.

Wenn Sie diese Sonderflle bercksichtigen, ist ein Modul, das unter der Shell
lief, auch als "eigenstndiges" Programm lauffhig. Es stellt sich jedoch die
Frage,  was  passieren  soll,  wenn  wider  Erwarten  doch  noch  Fehler  im
Programm  auftreten.  Unter  der  Shell  werden  automatisch  Fehleranzeigen
ausgelst. Die Funktionen sind dazu  von  der  Shell  installiert  worden.  Auch
solche Funktionen mssen beim Linken extra eingebunden werden. Es gibt hier
einmal die Mglichkeit, das Modul GEMError einzubinden, das auch von der
Shell zur Fehlerbehandlung importiert wird. Wem das zuviel ist, der kann die
abgespeckte  Version  SimpleError  verwenden  oder  einen  der  mitgelieferten
Quelltexte modifizieren: Wenn die Variablen von FileBase unverndert bleiben,
werden  Dateien  bei   Programmende   immer   ohne   Meldung   automatisch
geschlossen, Fehler immer ignoriert, und die Files-Funktion GetStateMsg liefert
immer einfach eine Fehlernummer statt des passenden Textes. Also kann man,
falls man sich seines Dateiumgangs sicher ist, die FileBase-Operationen aus
dem eigenen GEMError entfernen.

Bei  den  Laufzeitfehlern  sollte  man  zumindest  eine  einfache  Fehlermeldung
weiterhin vornehmen, denn wenn die Fehler nicht abgefangen werden, gibt es
hchstens diese hlichen Bomben, und das Programm terminiert sofort, ohne
da man feststellen kann, was passiert ist.

ber die Laufzeitfehlerbehandlung  existiert  ein  ausfhrliches  Kapitel  zu  den
Modulen Excepts, ErrBase, HdlError und EasyExceptions.
5.2 Bibliothek: Programme, Module und Prozesse                         5 - 18
________________________________________________________


Ein Sonderfall ist die Verwendung des Moduls InOut. Unter der Shell werden
Ausgaben ber dieses Modul in einem Window  dargestellt.  InOut  importiert
selbst nicht das dafr verwendete Modul TextWindows,  sondern  InOutBase.
Unter der Shell sind allerdings die TextWindows-Funktionen darauf zugewiesen.
Wenn ein Programm, das InOut benutzt, gelinkt wird, mu ein Konfigurations~
modul mit eingebunden werden, das diese Prozedurvariablen initialisiert. Dazu
stehen  wahlweise  GEMIO,  TOSIO  oder  GEMDOSIO  zur  Verfgung.  GEMIO
importiert TextWindows und weist dessen Funktionen auf die Prozedurvariablen
in InOutBase zu, eben wie dies auch in der Shell geschieht. TOSIO dagegen
verwendet statt dessen die Funktionen aus Terminal fr InOut und GEMDOSIO
verwendet das Console-Modul, soda auch Ein-Ausgabeumlenkung von auen
mglich ist, beispielsweise durch die Benutzung von Command-Line-Shells. Das
bewirkt,  da  ein  Programm,  das  TOSIO  oder  GEMDOSIO  statt  GEMIO
eingebunden  hat,  die  Ausgaben  nicht  auf  ein  Window  ttigt,  sondern  den
gesamten Bildschirm dafr verwendet. In  diesem  Fall  sollten  keine  anderen
GEM-Funktionen verwendet und das gelinkte Programm mit der Endung ".TOS"
statt ".PRG" benannt werden.

Sie knnen vor dem Linken eines Programm durch Aufruf der Linker-Optionen
bestimmen, ob Sie GEMIO, GEMDOSIO oder TOSIO einbinden wollen. Ersteres
ist in der Anwendung optisch sicher schner, die anderen bentigen wegen
sparsamerer Importe weniger Speicherplatz.

Wenn Sie in dem zu linkenden Programm InOut nicht verwenden, brauchen Sie
GEMIO, GEMDOSIO bzw. TOSIO auch nicht einzubinden. Wenn Sie vergessen,
eines der Module einzubinden, obwohl InOut benutzt wird, erhalten Sie, wenn
Sie das Programm dann starten,  eine  Fehlermeldung  mit  dem  Text  "InOut
driver is missing!".


Prozesse

Wenn ein Programm unter TOS gestartet wird (also z.B. vom Desktop aus),
richtet das TOS dafr einen Proze ein (Der Prozebegriff ist nicht mit den
Modula-2 Coroutinen zu verwechseln!). In der Praxis bedeutet dies, da sich
das TOS merkt, da ein neues Programm gestartet wurde und von nun an
bestimmte   Systemresourcen   (z.B.   Speicheranforderungen,   Dateizugriffe)
diesem  Proze/Programm  zugeordnet  werden.  Wenn  das  Programm/der
Proze  endet,  knnen  alle  Systemresourcen  des  Programms  erkannt  und
notfalls freigegeben werden (z.B. belegter Speicher wieder freigegeben, offene
Dateien geschlossen).

Gegenber  einem  einfachen  Unterprogramm  hat  ein  Proze  auerdem  den
Vorteil, da er sich zu (fast) jeder Zeit und an jeder Programmstelle beenden
kann und die Ausfhrung dann immer hinter der Programmstelle fortgefhrt
wird, die den Proze gestartet hat (wie bei einem Unterprogrammaufruf).
5.2 Bibliothek: Programme, Module und Prozesse                         5 - 19
________________________________________________________


Jeder  Proze  erhlt  eine  Basepage.  Dies  ist  ein  Speicherbereich  von  256
Bytes, in denen bestimmte Daten angelegt werden, die der Proze ganz privat
bentigt (hnlich dem Workspace bei Modula-Coroutinen). Darin wird z.B. eine
Textzeile abgelegt, die der Aufrufer bergeben hat (z.B. die Argumentzeile bei
".TTP"-Programmen) und die offenen Dateien registriert.

Wenn ein Programm / Proze endet, kann es dem Aufrufer eine Nachricht in
Form einer INTEGER-Zahl (-32768 bis 32767) liefern. Es ist sinnvoll, negative
Werte zu liefern, wenn ein Fehler im aufgerufenen Programm auftrat, und Null,
wenn nichts Besonderes zu melden ist.

Im MOS (Modula Operating System) gibt es zwei Mglichkeiten, einen Proze
zu starten. Entweder man startet ein Programm oder Modul mit der Funktion
CallModule aus dem Modul Loader oder man startet ein Unterprogramm als
Proze mit CallProcess aus ModCtrl. Solch ein Proze kann dann auf zwei
Arten  zu  Ende  gefhrt  werden.  Entweder  luft  das  Programm  bzw.  das
Unterprogramm  bis  zum  Ende  durch  oder  es  wird  auf  irgend  eine  Weise
TermProcess  aus  PrgCtrl  aufgerufen.  Bei  normaler  Beendigung  wird  als
Ergebnis des Prozesses eine Null ber CallModule bzw. CallProcess geliefert,
bei  Aufruf  von  TermProcess  kann  ein  selbst  gewhlter  Ergebniswert  (die
INTEGER-Zahl) bergeben werden.

TermProcess wird z.B.  automatisch  ausgefhrt,  wenn  ein  Programm  durch
einen Laufzeitfehler unterbricht und bei der dann angezeigten Fehlermeldung
"Quit" oder "Abbruch" angewhlt wird. Als Ergebniswert wird dann an  den
CallModule-   bzw.   CallProcess-Aufrufer   die   Laufzeitfehlernummer   (s.
MOSGlobals) geliefert.

CallModule  kann  sowohl  normale  Programme  als  auch  die  vom  Compiler
erzeugten, ungelinkten Module starten. Wird  ein  Modula-2  Modul  gestartet,
werden alle importierten Module, die sich noch nicht im  Speicher  befinden,
nachgeladen.  Wenn  der  Proze  endet,  werden  alle  nicht  mehr  bentigten
Module  wieder  freigegeben,  d.h.,  da  der  von  ihnen  belegte  Speicherplatz
wieder fr neue Daten frei wird.

Wenn man erreichen will, da nicht bei jedem Programmaufruf mit CallModule
das Programm bzw. die Module erneut geladen werden, kann man sie mit der
Funktion LoadModule aus Loader einmal laden. Sie bleiben dann so lange im
Speicher, bis UnLoadModule aufgerufen wird oder das Programm endet, das
das Modul Loader importierte (z.B. die Shell).

Ein gestartetes Modul kann mit SetChain aus Loader selbst bestimmen, da
nach dem eigenen Ablauf nicht zum Aufrufer zurckgekehrt sondern erstmal
ein anderes Programm gestartet wird. Dies Nachstarten kann aber nur von
ungelinkten Modulen aus geschehen - nach dem Ablauf eines eigenstndigen
Programms ist ja der Loader des MOS nicht mehr aktiv.
5.2 Bibliothek: Programme, Module und Prozesse                         5 - 20
________________________________________________________


Es gibt Anwendungen, bei denen es darauf ankommt,  ein  Programm  nach~
trglich und dauerhaft einzubinden. Dies kommt meist vor bei "Treibern" (z.B.
RAMdisk-Programme)  und  Monitoren  (Programme,  die  z.B.  ber  andere
Prozesse  wachen).  Solche  Programme  installieren  Funktionen  auf  Vektoren
bzw. Prozedurvariablen,  die  von  dem  Programm,  in  das  sie  sich  einlinken,
exportiert werden. Im MOS gibt es viele Mglichkeiten fr solche Programme,
z.B.  knnen  ber  die  Treibervariablen  in  FileBase  oder  TermBase  andere
Ein-/Ausgabefunktionen   eingebunden   oder   kurzzeitig   Konfigurationen   in
MOSConfig gendert werden.

Beispielsweise  soll  erreicht  werden,  da  alle  Module,  die  der  Loader  ldt,
angezeigt  werden.  Dazu  exportiert  das  Modul  Loader  die  Prozedurvariable
Loading,  die  bei  jedem  Modulladen  aufgerufen  wird.  Es  gibt  nun  zwei
Mglichkeiten. Entweder erweitert man die Shell um eine Funktion, die auf die
Loader-Variable  zugewiesen  wird  und  die  Ausgabe  der  geladenen  Module
durchfhrt. Will man aber sich die nderung in der Shell ersparen, mu man
ein kleines Programm erstellen, das dies bernimmt. Die Ausgabefunktion darf
aber nur so lange auf Loading zugewiesen sein, wie das Modul im Speicher
steht. Will man zurck in die Shell, um Module zu starten, damit die Funktion
sie  anzeigen  kann,  endet  aber  das  Programm  und  wird  wieder  aus  dem
Speicher entfernt.

Die Lsung bietet die Funktion InstallModule aus ModCtrl. Sie bewirkt, da das
Modul, das die Funktion aufruft, mitsamt seiner importierten Module resident
im Speicher bleibt, bis ModCtrl selbst aus dem Speicher verschwindet (also
wenn z.B. die Shell abluft).

Wenn  also  das  Modul  vor  dem  Zuweisen  der  Loading-Variable  erst
InstallModule aufruft und dann der Proze beendet wird, bleibt die Ausgabe~
prozedur weiterhin aufrufbar.

Damit das Modul sich auch wieder freigeben und die Ausgabefunktion abmelden
kann, gibt es die Mglichkeit, ein  solches  Modul  erneut  per  CallModule  zu
starten. Das Modul kann dann mit FirstModuleStart (aus ModCtrl) erfragen, ob
dies der erste Aufruf des Moduls ist, um so zu ermitteln, ob das Modul schon
resident  war.  Ist  dies  der  Fall,  gibt  es  sich  einfach  wieder  frei  (mit
ReleaseModule).
5.2 Bibliothek: Programme, Module und Prozesse                         5 - 21
________________________________________________________


Hier das vollstndige Beispielprogramm:

    MODULE ShowMods;

    FROM  SYSTEM  IMPORT  ADDRESS,  ADR;  IMPORT  ModCtrl,  Loader,
       AESForms, Strings, MOSGlob;

    VAR workSpace: MemArea; oldLoading: Loader.LoadingProc;

    PROCEDURE  remove;
      BEGIN
        (* Wiederherstellen des alten Wertes: *)
        Loader.Loading:= oldLoading;
      END remove;

    PROCEDURE show ( modName, fileName: ARRAY OF CHAR;
                         codeAddr: ADDRESS; codeLen: LONGCARD;
                         varAddr: ADDRESS; varLen: LONGCARD );
      VAR s: Strings.String; ok: BOOLEAN; button: CARDINAL;
      BEGIN
        (* Hier wird jedes geladene Modul ausgegeben *)
        Strings.Concat (' 0  Lade ', fileName, s, ok);
        Strings.Append (s, '   OK  ', ok);
        AESForms.FormAlert (1, s, button);
          (* GEM ist bereits durch die Shell initialisiert *)
      END show;

    BEGIN
      IF ModCtrl.FirstModuleStart () THEN
        (* Beim 1.Start wird die Ausgabefunktion eingerichtet. *)
        workSpace.bottom:= NIL; (* der normale Stack reicht aus*)
        ModCtrl.InstallModule (remove, workSpace);
        oldLoading:= Loader.Loading; (* Retten des alten Wertes *)
        Loader.Loading:= show     (* Zuweisen der neuen Prozedur *)
      ELSE
        (* Beim wiederholten Start wird alles entfernt. *)
        remove;  (* Wiederherstellen des alten 'Loading'-Wertes *)
        ModCtrl.ReleaseModule
      END
    END ShowMods.


Im UTILITY-Ordner befindet sich ein entsprechendes Modul ModTrace.
5.2 Bibliothek: Programme, Module und Prozesse                         5 - 22
________________________________________________________


Modul- und Prozekontrolle

Es gibt Anwendungen, die nicht einfach ohne weiteres beendet werden drfen,
sondern  bei  denen  Einstellungen,  die  whrend  eines  Prozesses  verndert
wurden, wieder rckgngig gemacht werden mssen. Werden z.B. Interrupts
verwendet, drfen die Interruptvektoren nach Prozeende nicht "in die Wste"
zeigen, weil sonst ein Systemabsturz mglich wre. Da es mglich ist, da ein
Proze unbeabsichtigt, z.B. durch einen Fehler, beendet wird, kann mit der
Funktion CatchProcessTerm aus PrgCtrl eine Prozedur installiert werden, die
automatisch   bei   Beendigung   des   eigenen   Prozesses   aufgerufen   wird.
Genaugenommen wird die Prozedur dann ausgefhrt, wenn der Proze endet,
in  dem  der  CatchProcessTerm-Aufruf  erfolgte.  Werden  mehrere  solcher
Prozeduren whrend eines Prozesses angemeldet, werden sie beim Prozeende
in entgegengesetzter Anmeldungsreihenfolge aufgerufen (letztes zuerst).

Module wie Files oder Storage sorgen automatisch dafr, da offen gebliebene
Dateien oder belegter Speicher freigegeben wird, wenn der Proze beendet
wird, unter dem die Dateien geffnet oder der Speicher angefordert wurde.
Damit  solche  Funktionen  ber  Beginn  und  Ende  eines  Prozesses  Bescheid
wissen, gibt es im Modul PrgCtrl die Funktion SetEnvelope zur Anmeldung einer
Prozedur, die bei Prozebeginn und -ende aufgerufen wird.

Im  Files-Modul  wird  beispielsweise  eine  globale  Variable,  die  das  aktuelle
Prozelevel bestimmt, verwaltet. Sie wird mit Hilfe der SetEnvelope-Funktion
bei jedem Prozebeginn erhht und bei jedem Prozeende wieder verringert.
Die Files.Open-Funktion merkt sich nun fr jede geffnete Datei den Wert des
Prozelevels. Bei Prozeende wird, bevor das Prozelevel heruntergesetzt wird,
erst  jede  offene  Datei  geschlossen,  die  unter  dem  gerade  zu  beendenden
Prozelevel erffnet wurde.

Werden  Module  erstellt,  die  Resourcen  (z.B.  Listen,  Speicher,  Dateien)
verwalten knnen oder selber Resourcen anlegen oder globale Vektoren (z.B.
Interrupts  oder  TRAPs)  oder  andere  globale  Einstellungen  vornehmen,  und
sollen diese Module auch in Programmen verwendet werden knnen, die sich
speicher-resident  machen  (mit   InstallModule),   darf   zum   automatischen
Schlieen bei Programmende nicht CatchProcessTerm, sondern CatchRemoval
aus  SysCtrl  verwendet  werden!  Siehe  dazu  auch  die  Definitionstexte  von
PrgCtrl,  SysCtrl,  ResourceHandler  sowie  das  Demo-Modul  SysLibDemo  im
DEMO-Ordner.
5.2 Bibliothek: Programme, Module und Prozesse                         5 - 23
________________________________________________________


Programm- und Prozeinformationen, Base Page und Argumentzeile

Um zu erfahren, welche Module bei einem  Programmstart  geladen  werden,
wurde bereits die Verwendung der Funktion Loading weiter oben beschrieben.
Um die Informationen ber die augenblicklich geladenen Module zu erhalten,
gibt es in ModCtrl die Funktion ModQuery. Ihr wird eine Prozedur bergeben,
die wiederholt mit den Informationen ber alle im Speicher befindlichen Module
aufgerufen  wird.  Ein  Beispielprogramm  namens  ModList  befindet  sich  im
DEMO-Ordner.

Wenn man mit einem Debugger oder Maschinensprachemonitor von CallModule
gestartete  Prozesse  tracen  (schrittweise  verfolgen)  mchte,  kann  man  die
Loader-Variable Monitor auf eine Prozedur zuweisen, die das Monitorprogramm
oder den Debugger aktiviert. Die Monitor-Prozedur wird immer direkt vor dem
Aufruf des von CallModule zu startenden Moduls ausgefhrt. Die Behandlung
der Monitor-Variablen kann in derselben Weise wie bei dem Beispielprogramm
fr die Loading-Variable (s.o.) geschehen. Ein Beispielprogramm Monitor wird
mitgeliefert (UTILITY-Ordner).

Den Zeiger auf die Basepage jedes Prozesses erhlt man mit der Funktion
GetBasePageAddr aus PrgCtrl. Fr den Normalanwender ist daraus  nur  die
Argumentzeile interessant, die bei CallModule angegeben oder beim Start eines
Programms von der Shell bestimmt werden kann. Fr den Zugriff darauf bietet
sich jedoch besser das Modul ArgCV an. Der Aufruf der dortigen Prozedur
InitArgCV  lst  die  Argumentzeile  gleich  in  einzelne  Argumente  auf,  und
ArgCVIO erlaubt es zustzlich, die Ein-/Ausgaben ber InOut umzuleiten, falls
das Programm als TTP-Anwendung vom Desktop gestartet werden soll: Um
z.B. die Eingabe von  der  Datei  "BATCH.TXT"  zu  ermglichen,  kann  in  der
Argumentzeile "<BATCH.TXT" angegeben werden. Fr Ausgabeumleitung kann
">" oder ">>" verwendet werden: ">" bestimmt eine neue Datei, whrend ">>"
das Anfgen an eine bestehende Datei ermglicht. Soll die Umlenkung auch
schon vom aufrufenden Programm (z.B. Command-Shell) mglich sein, mu das
Console-Modul, z.B. durch den InOut-Treiber GEMDOSIO, verwendet werden.
Der Desktop (und z.Zt. auch die Megamax-Shell)  prfen  die  Argumentzeile
nicht auf Umlenkungsanweisungen und deshalb ist es hier  ggf.  erforderlich,
ArgCVIO zu verwenden.

Mit  Accessory  aus  PrgCtrl  kann  ermittelt  werden,  ob  ein  Programm  als
Accessory (mit Suffix ".ACC") gestartet wurde.

Das Modul MOSCtrl ist fr den Normalanwender tabu. Es stellt die grund~
legenden Funktionen und Daten fr die  MOS-Prozekontrolle  zur  Verfgung
und ist nur fr die MOS-internen Module bestimmt.
5.2 Bibliothek: Programme, Module und  Leerseiten                       5 - 24
________________________________________________________
5.3 Bibliothek: Laufzeitfehler-Behandlung                                  5 - 25
________________________________________________________


5.3  Laufzeitfehler-Behandlung


Was sind Laufzeitfehler ?

Laufzeitfehler knnen unter mehreren Umstnden eintreten. Z. B. kann eine
Variable einen ungltigen Wert erhalten, eine Division durch Null erfolgen oder
ein Pointerzugriff mit einem uninitialisierten Pointer durchgefhrt werden.

Nun ist es in den meisten Fllen zu aufwendig, solchen Fehlern programm~
technisch zuvorzukommen. Man mte z. B. vor jeder Berechnung mit Zahlen
prfen, ob die Ergebnisse nicht ungltig werden. Statt dessen knnen solche
Prfungen automatisch vom Mikroprozessor und vom Code, den der Compiler
erzeugt, vorgenommen werden. Der Vorteil liegt darin, da der Programmierer
sich nicht selbst um die vielfltigen Prfungen kmmern mu. Der Nachteil ist,
da die vom Prozessor oder vom Spezialcode des Compilers erkannten Fehler
alle eine Standard-Fehlerbehandlung durchlaufen, anstatt individuell behandelt zu
werden.

Aus diesem Grund ist es ntig, sich beim Programmieren Gedanken darber zu
machen, ob absehbar mgliche Fehler vorher erkannt werden sollen, um darauf
dann direkt zu reagieren, oder ob es ausreicht, nach einer Berechnung etc. zu
erkennen, da berhaupt ein Fehler aufgetreten war.

Dazu ein Beipiel. Folgende Berechnung sei durchzufhren:

  lsung:= a * b + c DIV ( d * e );

Wenn  die  Variablen  a  bis  e  alle  mglichen  Werte  annehmen  knnen,  sind
mehrere Fehler mglich:

  - Ein berlauf tritt bei der Multiplikation von a * b auf.
  - Ein berlauf tritt bei der Multiplikation von d * e auf.
  - Ein berlauf tritt bei der Addition von d * e und c DIV d * e auf.
  - Eine Division durch Null tritt auf, weil d oder e Null ist.

Wenn es darauf ankommt, herauszufinden, welche Variable einen illegalen Wert
hat, mu dies in aufwendiger Weise vor der Berechnung geprft werden. Ist
dagegen  nur  wichtig,  zu  erfahren,  ob  berhaupt  ein  gltige  Lsung  dabei
entsteht, reicht es aus, die automatische Fehlererkennung darber wachen zu
lassen.

Die  automatische  Fehlererkennung  liefert  lediglich  die  Information,  da  ein
Fehler auftrat und was der Anla fr den Fehler war. Fr das Beispiel oben
wird  im  Fehlerfalle  nur  bermittelt,  da  entweder  ein  berlauf  oder  eine
Division durch Null den Fehler auslste.
5.3 Bibliothek: Laufzeitfehler-Behandlung                                  5 - 26
________________________________________________________


Fehlergruppen

Laufzeitfehler kann man in vier Gruppen (Ursachen) aufteilen:

  - Exceptions: Dies sind Fehler, die der Mikroprozessor erkennt,  z.  B.  16
    Bit-Division durch Null oder Zugriff auf nicht vorhandenen Speicherbereich.
    Der  Prozessor  hat  dafr  an  festen  Systemadressen  Sprungvektoren
    vorgesehen, die in einem solchen Fehlerfalle angesprungen werden. Es ist
    nicht  mglich,  die  Erkennung  der  Fehler  durch  den  Prozessor  zu
    unterbinden.

  - Soft-Fehler:  Dazu  zhlen  alle  Fehler,  die  durch  extra  programmierte
    Abfragen  erkannt  werden.  Solche  Abfragen  werden  z.B.  vom  Compiler
    erzeugt (wenn nicht die Option (*$R-*) eingestellt ist) und stehen auch in
    vielen  der  mitgelieferten  Library-Module.  Sie  werden  alle  ber  eine
    erzwungene Exception-Auslsung gemeldet.

  - Raise-Funktionen: Damit knnen Sie selbst Fehlermeldungen auslsen. Dies
    ist  z.  B.  sinnvoll,  wenn  Sie  ein  Modul  mit  mathematischen  Funktionen
    programmieren. Dann knnen Sie selbst Fehlerabfragen durchfhren  und
    ggf. die Funktion RaiseError aus dem Modul ErrBase aufrufen, um einen
    normalen Laufzeitfehler zu simulieren.

  - Dateifehler: Das Dateisystem des MOS prft in vielen Fllen nach, ob Sie
    einen vorher aufgetretenen Fehler, z. B. einen Lesefehler, erkannt haben.
    Ist dies nicht der Fall, wird eine Fehlermeldung ausgelst.

Die ersten drei Gruppen knnen, da sie alle gleichartige Fehler melden, von
einer einzigen Funktion behandelt werden. Sie werden im Folgenden "allgemeine
Laufzeitfehler" genannt. Die Dateifehler treten unter anderen Umstnden auf
und mssen auch anders behandelt werden.

Darber hinaus fat das Modul EasyExceptions alle diese Fehler zusammen und
ermglicht auf eine hheren Ebene eine  sehr  komfortable  Fehlerbehandlung.
Dazu mehr am Ende dieses Kapitels.
5.3 Bibliothek: Laufzeitfehler-Behandlung                                  5 - 27
________________________________________________________


Allgemeine Laufzeitfehler

Die Fehler der ersten  beiden  Gruppen  (s.o.)  werden  auf  dem  selben  Weg
gemeldet: ber Exceptions. Mit dem Modul Excepts knnen diese und auch alle
anderen Exceptions abgefangen werden. (Tritt eine Exception auf, die nicht
abgefangen wird, blitzen nur kurz ein paar hliche Bomben auf dem Atari-
Bildschirm auf.) Das Modul bietet die Funktion InstallExc, mit der eine Prozedur
angemeldet werden kann, die bei Eintritt einer der anzugebenden Exceptions
aufgerufen  wird.  Wird  bei  einer  Exception  die  Prozedur  dann  aufgerufen,
bekommt sie Werte aller Prozessorregister vor der Exception bergeben. Sie
kann dann entscheiden, ob sie selbst reagieren will. Wenn ja, kann sie z. B.
eine Fehlermeldung anzeigen. Danach kann sie die Prozessorregister ndern
und mit RETURN FALSE erreichen, da die Prozessorregister zurckgeladen
werden und das unterbrochene Programm fortgefhrt wird. Wenn sie  nicht
reagieren will, kehrt sie mit RETURN TRUE zurck, und es wird vom Modul
Excepts  die  Prozedur  aufgerufen,  die  vor  dem  InstallExc-Aufruf  fr  die
Exception angemeldet war. Diese Prozedur kann dann genauso verfahren.

Mit der Prozedur RaiseExc aus Excepts knnen Sie eine Exception an  der
Stelle simulieren, von der der Aufruf geschieht.

Wird das Modul ErrBase eingebunden, ruft es automatisch InstallExc auf und
fngt alle Exceptions, die von Modula-Programmen ausgelst werden knnen,
ab. Es exportiert eine Prozedurvariable, die bei einer solchen Exception oder
bei Aufruf der dortigen Funktion RaiseError aufgerufen wird. Von Anwender~
programmen sollte diese globale Variable aber in der Regel nicht verwendet
werden, um Fehler abzufangen.

Statt dessen gibt es  noch  ein  weiteres  Modul,  HdlError,  das  eine  interne
Prozedur auf die Prozedurvariable aus ErrBase zuweist. Dieses Modul bietet
nun die komfortablen Funktionen zum Abfangen und Behandeln der allgemeinen
Laufzeitfehler.

CatchErrors aus HdlError erlaubt es, Prozeduren anzumelden, die bei jedem
allg.  Laufzeitfehler  aufgerufen  werden.  Die  Prozedur  bekommt  bei  einem
Laufzeitfehler  die  Fehlernummer  (alle  Fehlernummern  sind  in  MOSGlobals
definiert  und  erklrt),  einen  optionalen  Text,  die  Prozessordaten  von  der
Exception, die Information, ob das Programm noch fortgefhrt werden kann,
und  die  Angabe,  ob  die  fehlerauslsende  Routine  oder  ihr  Aufrufer  als
Verursacher  gilt.  Der  Text  kann  v.  A.  bei  RaiseError  als  zustzliche
Information  neben  der  Fehlernummer  bergeben  werden.  Bei  vom  Compiler
erzeugten Fehlermeldungen oder bei Exceptions ist der Text immer leer. Wird
die Prozedur aufgerufen, hat sie in der Regel drei Mglichkeiten:
5.3 Bibliothek: Laufzeitfehler-Behandlung                                  5 - 28
________________________________________________________


  - Sie will den Fehler nicht speziell behandeln. Dann verlt sie die Funktion
    mit  RETURN  TRUE.  Waren  noch  weitere,  ltere  CatchErrors-Aufrufe
    erfolgt,  werden  nun  deren  angemeldete  Prozeduren  in  gleicher  Weise
    aufgerufen. Ist keine weitere 'call'-Funktion vorhanden, wird das Programm
    mit der Fehlernummer als "Exitcode" (siehe PrgCtrl.TermProcess) beendet.

  - Sie hat den Fehler behandelt und mchte erreichen, da das Programm
    hinter der Fehlerauslsung fortfahren kann. Dazu mu sie die Funktion mit
    FALSE verlassen. Dies sollte in der Regel  nur  getan  werden,  wenn  es
    durch eines der Argumente, die der Prozedur bergeben wurden, erlaubt
    wird. Vorsicht: Bei Busfehlern und Adrefehlern kann das Programm nicht
    ohne nderung der Prozessorregister fortfahren !

  - Der Fehler wurde erkannt, und das Programm soll abgebrochen werden.
    Dann ist TermProcess aus PrgCtrl aufzurufen.

Diese Wahlmglichkeit hat nun riesige Vorteile. Stellen Sie sich vor, Sie haben
eine Prozedur, die eine Berechnung durchfhrt. Sie soll ein Ergebnis liefern,
das anzeigt,  ob  die  Berechnung  fehlerfrei  verlief.  Da  nun  damit  gerechnet
werden  mu,  da  darin  ein  Laufzeitfehler  auftreten  kann,  wird  vor  der
Berechnung mit CatchErrors eine Hilfsfunktion installiert. Tritt danach irgendein
Fehler auf, wird die Funktion als erstes aufgerufen, und sie kann entscheiden,
ob der Fehler in der Berechnung entstanden oder ein ganz anderer Fehler ist.
Je nachdem setzt sie ein Fehlerflag und lt die Berechnung zu Ende laufen,
oder sie lt den auerordentlichen Fehler von der zuvor installierten Fehler~
behandlung  bearbeiten  (dies  fhrt  dann  normalerweise  zum  Anzeigen  des
Fehlers von der Standard-Fehlerbehandlung der Shell/GEMError).
5.3 Bibliothek: Laufzeitfehler-Behandlung                                  5 - 29
________________________________________________________


Hier ein Bespielprogramm:

    VAR fehlerAufgetreten: BOOLEAN;

    PROCEDURE fehler (     nummer       : INTEGER;
                                text         : ARRAY OF CHAR;
                                verursacher: ErrBase.ErrResp;
                                abbruch     : RtnCond,
                           VAR excDaten    : Excepts.ExcDesc ): BOOLEAN;
      BEGIN
        IF nummer = MOSGlob.DivByZero THEN
          fehlerAufgetreten:= TRUE;
          RETURN FALSE  (* -> Programm fortfhren *)
        ELSE
          RETURN TRUE   (* -> Fehlermeldung weiterleiten *)
        END
      END fehler;

    PROCEDURE modulo ( a,b: CARDINAL; VAR c: CARDINAL; VAR ok: BOOLEAN );
        (* Berechnet den Modulo-Wert v. 'a' und 'b' und liefert die *)
        (* Lsung in 'c'. Bei einen Fehler ('b'=0) ist 'ok' FALSE,  *)
        (* sonst TRUE.                                                          *)
      VAR stack: ARRAY  1..1000  OF CARDINAL; (* 2 KB Stack reichen *)
           wsp: MOSGlob.MemArea;
      BEGIN
        fehlerAufgetreten:= FALSE;
        wsp.bottom:= ADR ( stack );
        wsp.length:= SIZE ( stack );
        CatchErrors ( fehler, wsp );       (* Fehlerroutine anmelden *)
        (* Jetzt kann gerechnet werden: *)
        c:= a - (a DIV b) * b;
        (* Das reicht. *)
        ReleaseCatcher ( fehler );         (* Fehlerroutine abmelden *)
        ok:= NOT fehlerAufgetreten
      END modulo;

In diesem Beispielprogramm wre es natrlich einfacher und schneller, b mit
Null  zu  vergleichen.  Erst  in  komplexeren  Berechnungen  lohnt  sich  das
Verfahren. Aber mathematische Berechnungen sind nicht das einzige, bei dem
Fehler in dieser Weise vorteilhaft abgefangen werden knnen.
5.3 Bibliothek: Laufzeitfehler-Behandlung                                  5 - 30
________________________________________________________


Wenn nach dem Erkennen des Laufzeitfehlers im obigen Beispiel die fehlerher~
vorrufende Routine nicht weiter ausgefhrt werden darf, sondern gleich aus
modulo zurckgekehrt werden soll, kann die Funktion so abgendert werden,
da die Berechnung selbst in einer Unterfunktion durchgefhrt und diese dann
mit CallProcess aus ModCtrl aufgerufen wird. In fehler mu dann TermProcess
mit einem Wert ungleich Null statt "RETURN FALSE" aufgerufen werden. Statt
ber die globale Variable fehlerAufgetreten kann dann ber den exitCode von
CallProcess ein aufgetretener Fehler erkannt werden.

Genauso bietet sich CatchErrors an, wenn einfach verhindert werden soll, da
Laufzeitfehler  an  den  Anwender  mit  einer  Bildschirmmeldung  gelangen  und
dadurch das Programm unterbrochen wird. Bei Berechnungen mit CARDINAL-
und INTEGER-Werten reicht es in der Regel, dem Compiler durch die Option
(*$R-*) im Quelltext mitzuteilen, keine Prfungen vorzunehmen. Aber z. B. bei
Benutzung von REAL-Werten werden vorcompilierte Funktionen aus dem Modul
Runtime  importiert,  die  immer  Fehlerprfungen  vornehmen.  Hier  kann  im
Zweifelsfall nur mit CatchErrors sichergestellt werden, da das Programm die
Kontrolle behlt.

Ein weiteres Beispiel fr die Fehlerbehandlung von Laufzeitfehlern ist das Modul
GEMError,  das  Sie  als  Quelltext  erhalten  haben.  Es  ist  z.B.  in  die  Shell
eingebunden und fngt als letztes Modul alle Fehler ab und zeigt sie an. Ein
gelinktes  Programm  sollte  immer  in  irgendeiner  Weise  evtl.  auftretende
Laufzeitfehler abfangen. Am einfachsten ist es, dazu GEMError einzubinden,
was normalerweise auch geschieht.


Dateifehler

Im Kapitel ber das Dateisystem wird beschrieben, wie es dazu kommen kann,
da eine  Fehlermeldung  fr  Dateifehler  ausgelst  werden  kann.  Das  Modul
FileBase enthlt die Prozedurvariable HandleError, die aufgerufen wird, wenn
ein Dateifehler gemeldet werden soll. Wenn sie unverndert bleibt, werden alle
Dateifehlermeldungen ignoriert.

Das Modul GEMError weist auf HandleError eine Routine zu, die den Fehler
anzeigt, dem Anwender bei einem Fehler ber den Grund und die Programm~
stelle informiert und ihm die Mglichkeit bietet, das Programm zu beenden,
fortzufhren oder den  Editor  aufzurufen,  um  die  Fehlerposition  anzuzeigen.
Dazu wird von HandleError die Dateifehlernummer  und  die  Dateivariable,  in
deren Datei der Fehler auftrat, bergeben. Zustzlich wird noch ein Argument
bergeben, das die Adresse der Prozedur  im  Speicher  angibt,  an  der  der
Dateifehler erkannt wurde.
5.3 Bibliothek: Laufzeitfehler-Behandlung                                  5 - 31
________________________________________________________


In FileBase findet sich auerdem die Prozedurvariable CloseFile. Sie wird bei
Programm-/Prozeende fr jede unter dem Proze erffnete und noch offen
gebliebene  Datei  aufgerufen.  Wird  sie  nicht  verndert,  wird  jede  offen
gebliebene Datei automatisch geschlossen. GEMError zeigt jedoch alle offenen
Dateien an und bietet die Mglichkeit, Disk-Dateien, die mit Create angelegt
wurden, zu lschen. Dies ist von Vorteil, wenn ein Programm, das eine Datei
erzeugt, durch einen Laufzeitfehler beendet wird. Oft ist dann die erzeugte
Datei unvollstndig und kann gelscht werden.


Fehlerbehandlung mit dem Modul EasyExceptions

Dieses  Modul  ermglicht  nicht  nur  die  Abfrage  von  Laufzeitfehlern,  eigene
Fehler knnen auf einfache Weise selbst ausgelst werden, und die Funktion, in
der der Fehler auftrat, kann auf bequeme Weise wieder verlassen werden.

Kernstck der Fehlerkontrolle ist die Funktion Call. Als erstes Argument erhlt
sie die Prozedur, die die eigentliche Operation durchfhren soll. Call nimmt alle
notwendigen Installationen fr die Fehlerabfrage vor (ber HdlError.CatchErrors)
und  sieht  auerdem  einen  zentralen  Rcksprung  fr  alle  Fehler  vor.  Dann
startet Call die eigentliche Prozedur. Kehrt die Prozedur ohne Fehler zurck,
liefert Call einen Wert, der den fehlerfreien Ablauf anzeigt. Tritt dagegen ein
Fehler  auf,  wird  die  Prozedur  sofort  abgebrochen  und  Call  liefert  einen
Fehlerwert.

Die  Fehler  knnen  nicht  nur  durch  die  bereits  erwhnten  Mglichkeiten
(RaiseError, CPU-Exception, Soft-Error, Dateifehler), sondern auch ber die
Raise-Funktion aus EasyExceptions gemeldet werden. Die Raise-Funktion hat
einen  entscheidenden  Vorteil  gegenber  RaiseError:  Sie  erhlt  nicht  eine
INTEGER-Zahl, die vorher festgelegt werden mu, sondern einen opaque-Wert,
welcher vorher ber die Funktion New des Moduls angefordert werden mu.
So knnen mehrere Funktionen unabhngig voneinander  eigene  Fehler-Werte
mit New anfordern. Damit ist gewhrleistet, da es keine berschneidungen
bei  den  Werten  gibt.  Die  Module,  die  eigene  Fehler  ber  Raise  auslsen
knnen,  mssen  lediglich  Variablen  oder  Funktionen  exportieren,  die  die
angeforderten Werte liefern, damit ein Vergleich mglich ist.

Ein Beispielmodul fr die Anwendung von EasyExceptions findet sich im DEMO-
Ordner unter dem Namen EXCTEST.M.
5.3 Bibliothek: Laufzeitfehler-Behandlung                                  5 - 32
________________________________________________________


Fehlerbehandlung in Accessories

Gerade Accessories sollten auf mgliche oder auch unerwartete Laufzeitfehler
vorbereitet sein: Sollte ein Accessory tatschlich einmal unkontrolliert  einen
Laufzeitfehler auslsen, ist der Atari aufgrund der drftigen Konzeption seiner
Accessory-Verwaltung zum Stillstand verurteilt: Nichts geht mehr.

Also berlegen Sie es sich gut: Wenn Sie ein Accessory programmieren und
dies einen Fehler macht, wenn Sie gerade in der Hauptanwendung, z.B. einer
Textverarbeitung, richtig viele Daten eingegeben haben, ist es doch sicher sehr
rgerlich, da Ihre Daten nicht wegen einem Fehler in der Textverarbeitung,
sondern  wegen  einem   eigentlich   unbeteiligten   Programm   das   Nirwana
aufgesucht haben, oder?

Da  Sie  ein  vorsichtiger  Mensch  sind  -  schlielich  haben  Sie  sich  ja  fr
Modula-2 und nicht fr C entschieden, freut es Sie natrlich besonders, da
wir Sie auch hier nicht im Stich lassen: Verwenden Sie einfach die Funktion
Call aus EasyExceptions, wie dies z.B. im DEMO-Modul AccDemo gezeigt wird.
Die Funktionen aus HdlError knnen Sie hier nicht benutzen - sie haben in
Accessories ohne weiteres keine Wirkung.
5.4 Bibliothek: Dateisystem                                               5 - 33
________________________________________________________


5.4  Dateisystem

Das Dateisystem ermglicht Ein-/Ausgaben von Texten und anderen Daten auf
Disk (Floppies, Harddisks). Zudem lt es Textein-/ausgaben auf "sequentielle"
Einheiten (Device, z. B. Bildschirm, Tastatur, Drucker, Midi-Schnittstelle) zu.

Zum Dateisystem gehren die folgenden Module:
    - Files       ffnen und Schlieen von Dateien.
    - Binary     Nicht-textuelle Ein-/Ausgabe von Daten auf Diskdateien.
    - Text       Textuelle Ein-/Ausgabe auf beliebige Dateien.
    - NumberIO  Ein-/Ausgabe von Zahlen in Textform auf beliebige Dateien.
    - InOut      Ein-/Ausgabe von Text und Zahlen auf eine Standarddatei.



Dateimodi

Es gibt zwei verschiedene Modi, um auf eine Datei zuzugreifen. Die beiden
unterscheiden sich grundstzlich in der Absicht, was fr eine Art von Daten
bearbeitet werden soll. Entweder wird beabsichtigt, nur normal lesbaren Text
ein- und auszugeben oder, es sollen Daten (ggf. incl. Text), die in der vom
Rechner verschlsselten Form vorliegen, in einer Datei gespeichert werden.

Beispiel: Eine Zahl kann in zwei Formen vorliegen, entweder als String, damit
sie auf dem Bildschirm anzeigbar ist, oder als rechnerkodierter Wert, z. B. in
einer CARDINAL-Variable. Nur in der rechnerinternen Form (binr) kann mit
ihr  gerechnet  werden,  nur  die  Textform  ist  fr  den  Anwender  lesbar.
Funktionen wie WriteCard wandeln die in binrer Form bergebene Zahl zur
Ausgabe erst in einen String um (fr Umwandlungen von binr dargestellten
Zahlen in Strings und umgekehrt gibt es die Module Convert und StrConv).

Zurck zu den zwei Dateimodi. Binre Daten zu speichern, spart Platz und
Zeit. Solche kodierten Daten drfen aber nur in Diskdateien abgelegt, nicht
jedoch z.B. auf Bildschirm oder Drucker ausgegeben werden.

Soll  dagegen  ausschlielich  Text  (also  auch  Zahlen  in  Textform)  ein-  und
ausgegeben werden, ist das Medium frei whlbar.
5.4 Bibliothek: Dateisystem                                               5 - 34
________________________________________________________


ffnen einer Datei

Um auf eine Datei zugreifen zu knnen, mu man einen Zugriff darauf anmel~
den. Dies kann mit Open oder Create aus Files geschehen. Dabei wird ein Na~
me bergeben, der die anzusprechende Datei bezeichnet. Der Name kann dabei
sowohl ein Disk-Dateiname sein, z. B. "A:ADRESS.DAT", als auch, wenn man
den rein textuellen Modus whlt, der Name eines sequentiellen Devices. Hierzu
gehren:
  - "CON:"  fr  Bildschirmausgabe  und  Tastatureingabe  mit  gleichzeitiger
              Bildschirmanzeige (mit "Echo"),
  - "KBD:"   fr Tastatureingabe ohne Echo,
  - "AUX:"   fr Ein- und Ausgabe ber die serielle Schnittstelle,
  - "PRN:"   fr Ausgabe auf den Druckerport,
  - "MIDI:"  fr Ein- und Ausgabe ber den Midi-Port und
  - weitere  selbstdefinierte  Namen  fr  eigene  Devices,  die  ber  die  Unit-
              Variablen in FileBase konfiguriert werden knnen (s.u.).

Beim ffnen wird auerdem der Zugriffsmodus angegeben. Fr den binren
Zugriff kann writeOnly (nur Schreiben auf Datei), readOnly (nur Lesen) oder
readWrite(Lesen und Schreiben) angegeben werden. Fr textuellen Zugriff ist
readSeqTxt (nur Lesen), writeSeqTxt (nur Schreiben) oder appendSeqTxt (nur
Schreiben, bei Diskdateien neue Daten an vorhandene Daten anhngen).

Der Unterschied zwischen Open und Create: Open ffnet stets eine vorhande~
ne Datei, whrend Create versucht, eine neue Datei (bei Diskzugriff) anzule~
gen. Bei Zugriff auf sequentielle Devices, die ja stets schon vorhanden sind,
sind Open und Create gleichbedeutend.

Create hat noch einen zustzlichen Parameter, der bestimmt, was passieren
soll, wenn schon eine Diskdatei unter dem angegebenen Namen existiert. Ist
dieser Parameter noReplace, heit das, da in diesem Fall die vorhandene Datei
erhalten bleibt und ein Fehler geliefert wird. Ist dagegen replaceOld angegeben,
wird eine eventuell schon vorhandene Diskdatei gelscht.

Dazu einige Anwendungsbeispiele:

  -  Wenn der Zugriffsmodus readOnly oder readSeqTxt ist, wird grundstzlich
     Open verwendet.

  -  Wird textuell geschrieben mit dem Modus writeSeqTxt oder appendSeqTxt,
     ist meist Create zu verwenden.

  -  Wird eine vorhandene Diskdatei mit Open im Modus readWrite, writeOnly
     oder  writeSeqTxt  geffnet,  berschreiben  neu  ausgegebene  Daten  die
     alten von Beginn der Datei an.
5.4 Bibliothek: Dateisystem                                               5 - 35
________________________________________________________


Bei Open und Close wird als erster Parameter eine Variable vom TypeFile(aus
Files) erwartet. Diese Variable wird dann von den Funktionen initialisiert und ist
bei weiteren Dateioperationen stets als erstes Argument anzugeben, um damit
die geffnete Datei zu identifizieren. Wenn man also zwei Dateien gleichzeitig
offen haben will, mu man auch zwei Variablen vom Type File deklarieren und
je eine fr jede Datei verwenden.


Ein-/Ausgabe von Daten

Beim ffnen einer Diskdatei wird ein Dateizeiger angelegt, der zu Beginn auf
das erste Datum der Datei zeigt, sofern sie nicht leer ist. Ausnahme: Wenn
der Modus appendSeqTxt ist, zeigt er hinter das  Ende  der  Datei.  Werden
Daten  gelesen  oder  geschrieben,  geschieht  dies  immer  ab  der  aktuellen
Zeigerposition aufwrts, und der Zeiger wird dabei automatisch erhht. Wird
eine Datei auf ein sequentielles Device geffnet, werden die Textdaten alle in
Folge gelesen oder geschrieben.

Werden  Daten  am  Ende  einer  Diskdatei  geschrieben,  wird  die  Datei
automatisch um die erforderliche Datenmenge verlngert.

Fr  Binrdateien  knnen  alle  Funktionen  aus  den  Modulen  Binary,  Text
(Ausnahme:  EOL)  und  NumberIO  verwendet  werden.  In  Binary  gibt  es
Funktionen zum Schreiben von beliebigen Daten. So schreibt z. B. WriteWord
beliebige Daten mit Word-Lnge in eine Datei, z. B. CARDINAL-, INTEGER-
oder  Aufzhlungstyp-Variablen.  Mit  WriteBlock  knnen  beliebige  Daten~
strukturen  geschrieben  werden,  z.B.  RECORDs  und  ARRAYs.  WriteBytes
erlaubt es, eine Adresse und die Lnge eines Datenbereichs zum Schreiben zu
bestimmen. Ebenso gibt es passende Read...-Funktionen zum Dateilesen.

In Binary gibt es weiterhin die Funktion FileSize, die die aktuelle Lnge einer
Datei in Bytes liefert. Die aktuelle Position des Dateizeigers kann mit FilePos
ermittelt und mit Seek neu gesetzt werden. Seek bietet sich  vor  allem  in
Kombination mit dem Zugriffsmodus readWrite an, um in einer Datei, die aus
vielen  gleichartigen,  hintereinandergereihten  Datenfeldern  besteht,  einzelne
Daten herauszugreifen oder zu  verndern.  Wenn  mit  Seek  der  Dateizeiger
hinter  das  aktuelle  Dateiende  positioniert  wird,  wird  die  Datei  automatisch
entsprechend erweitert.

Die Module Text und NumberIO enthalten Funktionen zur Textein-/ausgabe, wie
sie auch in InOut und Terminal vorkommen. Die Funktionen, bis auf EOL aus
Text, drfen sowohl im  Text-  als  auch  im  Binrmodus  verwendet  werden.
Allerdings  funktioniert  die  Behandlung  des  Dateiendes  in  den  beiden  Modi
unterschiedlich.
5.4 Bibliothek: Dateisystem                                               5 - 36
________________________________________________________


Dateiende-Behandlung

Mittels der Funktion EOF  kann  ermittelt  werden,  ob  aus  einer  Datei  noch
weitere Daten gelesen werden knnen und ob ein Fehler aufgetreten ist.

Whrend im Textmodus nach Erreichen des Dateiendes die Dateioperationen
unbedingt beendet werden mssen (da nichts anderes mehr funktioniert), kann
im  Binrmodus,  falls  mit  writeOnly  oder  readWrite  geffnet  wurde,  am
Dateiende geschrieben oder auch mit Seek eine andere Position in der Datei
erreicht werden.

Auch ist die Funktion EOF  im  Binrmodus  jederzeit  aufrufbar,  whrend  im
Textmodus dies nur erlaubt ist, wenn die Datei mit readSeqTxt - jedoch nicht
mit writeSeqTxt oder appendSeqTxt - geffnet wurde.

Im Binrmodus zeigt EOF dann das Dateiende an, wenn der Dateizeiger genau
auf das Ende der Datei zeigt. So kann also schon vor einem Lesezugriff mit
dieser Funktion ermittelt werden, ob berhaupt noch Daten vorhanden sind.

Im Textmodus gibt es nicht unbedingt einen Dateizeiger, denn der existiert ja
nur bei Diskdateien, aber nicht bei sequentiellen Devices. Deshalb erfolgt hier
die  Dateiendeerkennung  auf  eine  andere  Weise,  und  zwar  mit  einem
bestimmten  Dateiendezeichen.  Die  Lesefunktionen  prfen  jedes  gelesene
Zeichen. Ist es das Dateiendezeichen, ist automatisch das Dateiende erreicht.
Daraus folgt, da erst ein Zeichen gelesen werden mu, bevor das Dateiende
erkannt werden kann.

Bei Textdateien auf Disk wird zustzlich berprft, ob der  Dateizeiger  das
Dateiende erreicht hat, damit es keine  Probleme  gibt,  wenn  eine  Diskdatei
gelesen wird, die kein Dateiendezeichen enthlt.

Es gibt zwei Gruppen von Lesefunktionen, bei denen diese Unterschiede beach~
tet werden mssen. Auf der einen Seite die Read-Funktion, auf der anderen
die ReadString-Funktion und die Funktionen aus NumberIO.

Die Read-Funktion ist leicht durchschaubar. Im Textmodus mu nach einem
Lesezugriff geprft werden, ob das Dateiende erreicht ist. In dem Fall ist das
gelesene Zeichen nicht mehr zu verwenden, denn es ist lediglich das Ende~
kennzeichen.

Bei ReadString ist der erhaltene String verwendbar, es ist lediglich das Ende~
kennzeichen nicht darin enthalten. Bei den Lesefunktionen aus NumberIO ist die
Zahl gltig, sofern deren success-Argument TRUE ist.
5.4 Bibliothek: Dateisystem                                               5 - 37
________________________________________________________


Als Beispiel je eine Leseschleife fr den Binr- und den Textmodus:

  (* Fr Binrdateien *)
  WHILE NOT Files.EOF (f) DO  (* EOF schon vor Zugriff bekannt *)
    Text.Read (f, ch);
    Verarbeite (ch)
  END;

  (* Fr Textdateien *)
  LOOP
    Text.Read (f, ch);
    IF Files.EOF (f) THEN EXIT END;
                                  (* EOF wird erst nach Lesen erkannt *)
    Verarbeite (ch)          (* 'ch' nur gltig, wenn kein EOF    *)
  END;

Bei Dateien, die zum textuellen Lesen erffnet sind, ist auerdem die Funktion
EOL benutzbar. Sie signalisiert, wenn ein Zeilentrennzeichen gelesen wurde,
das  Dateiende  erreicht  oder  ein  Fehler  aufgetreten  ist.  Ebenso  wie  das
Dateiende  kann  auch  das  Zeilenende  erst  nach  dem  Lesezugriff  erkannt
werden und, bei Read ist dann ebenfalls das erhaltene Zeichen zu verwerfen.

Das Zeilentrennzeichen ist ein einzelnes CR (15C) oder ein CR mit einem direkt
folgenden  LF.  Das   Anwenderprogramm   braucht   also   nicht   selbst   zu
unterscheiden, ob die Eingabe z. B. von Tastatur kommt, wo normalerweise
allein mit CR die Zeile begrenzt wird, oder von einer Datei, die meist (nicht
immer) mit CR und LF eine Zeile abschliet. Das eventuelle LF-Zeichen nach
einem CR kann beim textuellen Lesen nicht erhalten werden.

Es folgt ein Programmbeispiel fr textuelles Lesen einer Datei mit Read:
5.4 Bibliothek: Dateisystem                                               5 - 38
________________________________________________________


  MODULE TestPrg;

  IMPORT Files, InOut;

  PROCEDURE LeseUndDruckeText (textname: ARRAY OF CHAR);

    PROCEDURE MeinFehlerTest (f: Files.File);
      VAR msg: ARRAY  0..31  OF CHAR;
      BEGIN
        IF Files.State (f) < 0 THEN            (* ernster Fehler ? *)
          Files.GetStateMsg (Files.State (f), msg);
                                                      (* Fehlertext holen *)
          Files.ResetState (f);               (* Fehler rcksetzen *)
          InOut.WriteLn;
          InOut.WriteString (msg);        (* Fehlertext anzeigen *)
        END
      END MeinFehlerTest;

    VAR  f: Files.File;  ch: CHAR;

    BEGIN
      Files.Open (f, textname, Files.readSeqTxt);
      IF Files.State (f) >= 0 THEN
        LOOP
          Text.Read (f, ch);
          IF Text.EOL (f) THEN                   (* Zeichen ungltig *)
            IF Text.EOF (f) THEN
              MeinFehlerTest (f);                          (* Fehler ? *)
              EXIT                                (* Auf jeden Fall Ende *)
            ELSE
              InOut.WriteLn                               (* Zeilenende *)
            END
          ELSE
            InOut.Write (ch);       (* gelesenes Zeichen ausgeben *)
          END
        END;
        Files.Close (f)
      END
    END LeseUndDruckeText;

  BEGIN (* of main *)
    LeseUndDruckeText ("KBD:");         (* Eingabe von Tastatur *)
    LeseUndDruckeText ("A:TEST.TXT")   (* Eingabe v. Diskdatei *)
  END TestPrg.
5.4 Bibliothek: Dateisystem                                               5 - 39
________________________________________________________


Die Leseschleife kann auch noch eleganter programmiert werden:

      LOOP
        Text.Read (f, ch);
        CASE State (f) OF (* siehe Kap. ber Fehlerbehandlung *)
          MOSGlobals.fOK : InOut.Write (ch)| (* Zeichen ausg. *)
          MOSGlobals.fEOL: InOut.WriteLn|       (* Zeilenende *)
          MOSGlobals.fEOF: EXIT                      (* Dateiende *)
        ELSE
          MeinFehlerTest (f);EXIT
        END
      END;

Wie aus dem Beispiel ersichtlich ist, mssen Zeilenbegrenzer (CR und/oder LF)
ber die Funktion EOL abgefragt werden. Dazu mu vorher ein  Lesezugriff
erfolgt sein. Das gleiche gilt fr die Dateiende-Erkennung. Liefert die Funktion
EOF TRUE, dann kann mit Hilfe der Funktion State erkannt werden, ob das
Dateiende  (State(f)>=0)  erreicht  wurde  oder  ob  ein  Fehler  aufgetreten  ist
(State(f)<0).

Als letztes Beispiel die Read-Routine angepat fr ReadString:

      VAR s:ARRAY  0..9  OF CHAR;

      ...

      LOOP
        Text.ReadString (f,s);
        InOut.WriteString (s);
        (* Der String ist auf jeden Fall *)
        (* brauchbar, ggf. ist er leer.  *)
        IF  Text.EOL  (f)  THEN
          IF Files.EOF (f) THEN (* Entweder Fehler o. Dateiende *)
            MeinFehlerTest (f); (* Fehler ? *)
            EXIT                     (* Auf jeden Fall Ende *)
          ELSE                       (* Zeilenende: *)
            InOut.WriteLn
          END
        END
      END;
5.4 Bibliothek: Dateisystem                                               5 - 40
________________________________________________________


Diverse Dateifunktionen (Modul "Files")

Am Ende aller Zugriffe auf eine Datei sollte sie mit Close geschlossen werden.
Vor  allem  bei  Diskdateien,  die  beschrieben  wurden,  ist  dies  unbedingt
erforderlich. Wenn Sie dies vergessen, wird bei Modulen, die von der Shell
gestartet  wurden  oder  in  die  das  Modul  GEMError  eingebunden  ist,  bei
Prozeende eine Meldung angezeigt, die auf offen verbliebene Dateien hinweist
und sie ordnungsgem schliet.

Ist  ein  fataler  Fehler  aufgetreten  und  will  man  bereits  erzeugte  Daten
verwerfen,  kann  Remove  statt  Close  aufgerufen  werden.  Dann  werden
Diskdateien,  die  mit  Create  erzeugt  wurden,  wieder  gelscht,  mit  Open
geffnete Dateien werden normal, wie mit Close, geschlossen.

Mit SetEOFMode kann ausschlielich bei Textdateien bestimmt werden, ob und
mit  welchem  Zeichen  das  Dateiende  erkannt  werden  soll.  GetEOFMode
ermittelt die augenblickliche Einstellung fr eine offene Datei. Normalerweise
wird beim Lesen des blichen ASCII-Zeichens "ETX" (32C, $1A) das Dateiende
erkannt.

Flush  wird  nur  bei  Ausgabedateien  bentigt.  Es  sorgt  fr  eine  unbedingte
Speicherung bzw. bermittelung der ausgegebenen Daten. Denn es ist mglich,
da die ausgegebenen Daten zuerst in einem rechnerinternen Speicherbereich
gesammelt werden, bevor sie auf Disk geschrieben oder z. B. ber die serielle
Schnittstelle ausgegeben  werden,  damit  eine  hhere  Ausgabegeschwindigkeit
erreicht  werden  kann.  Nur  nach  dem  Aufruf  von  Flush  oder  Close  ist
sichergestellt, da die Daten ihr Ziel erreicht haben. Normalerweise werden
also die Daten in einem normalen Ablauf immer ankommen, nur gibt es Flle, in
denen dies zu einem bestimmten Zeitpunkt gesichert sein mu. Mit anderen
Worten: Wenn Sie nicht wissen, wofr diese Funktion gut ist, dann werden Sie
sie auch nicht brauchen. Mir fllt noch etwas ein: Beispielsweise wartet Flush
bei  einer  Datei,  die  auf  "AUX:"  geffnet  ist,  bis  alle  Daten  des  Seriell-
Datenpuffers ausgegeben sind.

SetDateTimeund  GetDateTime  setzen  bzw.  erfragen  die  Zeitangabe  einer
Datei. Bei nicht-Diskdateien wird SetDateTime ignoriert und bei GetDateTime
ein Null-Datum geliefert.

Mit GetFileName kann man den Namen, mit dem eine Datei erffnet wurde,
ermitteln. Ist die Datei nicht offen, wird ein Leername geliefert.
5.4 Bibliothek: Dateisystem                                               5 - 41
________________________________________________________


Fehlerbehandlung im Dateisystem

Selbstverstndlich  sollte  man  nach  Aufruf  jeder  Dateibearbeitungsfunktion
eventuell aufgetretene Fehler prfen. Dies geschieht durch Aufruf der Funktion
State,  die  einen  INTEGER-Wert  liefert.  Liefert  sie  einen  negativen  Wert,
bedeutet  dies,  da  bei  der  letzten  Dateioperation  ein  Fehler  auftrat.  Die
Fehlernummer entspricht den TOS-Fehlernummern. Des weiteren erzeugen die
MOS-Funktionen eigene Fehlernummern, die daran erkennbar sind, da sie alle
niedriger  als  -127  sind.  Alle  Fehlernummern  sind  im  Modul  MOSGlobals
definiert und kurz erklrt.

Wird  nun  aus  Nachlssigkeit  beim  Programmieren  ein  aufgetretener  Fehler
beim Dateizugriff nicht abgefragt und somit nicht erkannt, wird, sofern das
Modul GEMError vorhanden ist, beim nchsten Aufruf einer Dateibehandlungs~
funktion  das  laufende  Programm  unterbrochen  und  eine  Fehlermeldung
angezeigt, woraufhin das Programm beendet oder fortgefhrt  werden  kann,
wahlweise mit Ignorieren des Fehlers, so da er weiterhin  bestehen  bleibt,
oder  mit  Rcksetzen  des  Fehlers,  damit  weitere  Dateifunktionen  nicht
wiederholt den Fehler anzeigen.

Solange Sie nur kleine Programme entwickeln, reicht es auch aus, nur dort
Fehlerabfragen zu programmieren, wo stndig mit Fehlern gerechnet werden
mu:  z.  B.  nach  dem  ffnen  einer  Datei,  um  zu  erfahren,  ob  die  Datei
vorhanden  ist,  oder  vor  allem  nach  Close,  da  hier  die  automatische
Fehlermeldung nicht mehr zuschlagen kann. Dagegen ist es ganz legitim und
auch  bequemer,  in  schnell  geschriebenen  Programmen  Fehlerabfragen  und
-meldungen nach Lese- und Schreiboperationen dem MOS zu berlassen.

Die automatische Fehlerprfung wird von allen  Dateifunktionen  durchgefhrt,
auer Open, Create, EOF, EOL, State, ResetState, GetStateMsg, GetFileName,
SetEOFMode und GetEOFMode.

Die folgenden Funktionen des Dateisystems knnen keine Fehler auslsen. Nach
Aufruf dieser Funktionen ist es also nicht nicht notwendig, zu prfen, ob ein
Fehler aufgetreten ist: EOF, EOL, FileSize, FilePos, SetEOFMode, GetEOFMode,
GetFileName, State, ResetState und GetStateMsg.

Wird ein Fehler vom Programm erkannt, mu es zuerst den Fehler mit der
Funktion ResetState rcksetzen, damit es nicht zu einer Fehlermeldung beim
nchsten Aufruf einer Dateifunktion kommt.
5.4 Bibliothek: Dateisystem                                               5 - 42
________________________________________________________


Die Funktion State liefert demnach einen positiven  Wert,  wenn  bisher  kein
Fehler aufgetreten ist. In der Regel wird eine Null geliefert, jedoch kann es
auch vorkommen, da ein Wert grer Null erhalten  wird.  Dies  signalisiert
dann besondere Zustnde. Z. B. erhlt man den Wert Drei, wenn Close fr
eine bereits geschlossene Datei aufgerufen wurde, denn dies ist kein Fehler,
aber es kann auf der anderen Seite auch interessant sein. Auerdem kann der
Wert Eins oder Zwei geliefert werden, wenn ein Zeilenende oder das Dateiende
erreicht worden ist. Dies kann dadurch die Verwendung von EOF und  EOL
ersetzen.

Im allgemeinen empfiehlt sich daher, nach einer Dateioperation Fehler daran zu
erkennen, ob die Funktion State einen positiven oder negativen Wert liefert,
und nicht daran, ob State den Wert Null liefert!


Zusammenfassung der Unterschiede zwischen Binr- und Textmodus

Binrdateien (readOnly, writeOnly, readWrite):
    -  Es darf nur auf Disk (Floppies, Harddisks oder andere Random Access
       Devices) zugegriffen werden.
    -  Die Funktion EOF liefert schon vor einem Zugriff, ob der Dateizeiger am
       Dateiende steht.
    -  Die  Funktion  EOL  darf  nicht  verwendet  werden.

Textdateien  (readSeqTxt, writeSeqTxt, appendSeqTxt):
    - Es drfen keine  Funktionen  aus  Binary  (Dateizeigeroperationen,  byte-
       weises Lesen/Schreiben, Dateilngenermittlung) verwendet werden.
    - Die Funktion EOF darf nicht auf Dateien angewandt  werden,  die  zur
       Ausgabe erffnet wurden. Sie liefert erst nach einem Lesezugriff, ob
       noch weitere Daten folgen.
5.4 Bibliothek: Dateisystem                                               5 - 43
________________________________________________________


Das Modul InOut

Die  Funktionen  in  diesem  Modul  vereinfachen  die  Dateiein-/ausgabe.  Man
braucht sich um die Fehlerabfragen und die Besonderheiten der Dateibehand~
lung nicht zu kmmern. Normalerweise ist immer je eine Datei fr Ein- und
Ausgabe ber Tastatur und Bildschirm (Textwindow) geffnet. Es stehen alle
blichen Funktionen fr textuelle Ein- und Ausgaben zur Verfgung. Da alle
Ein-/Ausgaben auf jeweils eine Standarddatei gehen, braucht bei den Funktionen
keine Dateikennung (File-Variable) bergeben zu werden.

Mit RedirectInput und RedirectOutputkann eine Datei bestimmt werden, auf die
die folgenden Ein- oder Ausgaben gelenkt werden. Letztere Funktion hat neben
dem Dateinamen einen weiteren Parameter, der bestimmt, ob die Datei mit
writeSeqTxt oder appendSeqTxt geffnet werden soll.

OpenInput und OpenOutput geben auf dem Bildschirm einen Text aus, der dazu
auffordert, einen Dateinamen einzugeben. Tritt beim ffnen der Datei dann ein
Fehler auf, wird eine Fehlermeldung ausgegeben und man hat die Wahl, ob die
Dateibestimmung wiederholt werden soll. Bei OpenOutput hat man weiterhin die
Mglichkeit, durch Eingabe eines ">" vor dem Dateinamen zu bestimmen, da
die folgenden Daten an die angegebene Diskdatei angefgt werden sollen. Wird
dies nicht bestimmt, darf die Ausgabedatei nicht schon bestehen, sonst erfolgt
eine Fehlermeldung.

Alle vier Funktionen signalisieren ber die Variable Done, ob das ffnen der
Datei funktionierte. Wenn ein Fehler auftrat oder ein Leerstring bei OpenInput/
Output eingegeben wurde, erfolgen die weiteren Ein-/Ausgaben ber Tastatur
bzw.  Bildschirm.  Done  ist  dann  FALSE.  War  vor  Aufruf  einer  der  vier
Funktionen  bereits  Ein-/Ausgabe  umgelenkt,  wird  die  alte  Datei  zuerst
geschlossen.

Die Ein- oder Ausgabeumleitung knnen Sie auch vom Anwender bestimmen
lassen, indem Sie das Modul ArgCVIO importieren und die darin enthaltene
Funktion InitArgCVaufrufen. Wenn Sie dann das Programm starten, knnen Sie
als Argumentzeile z. B. ">PRN:" angeben, um die Ausgaben auf den Drucker zu
leiten, oder "<IN.TXT >>OUT.TXT", damit die Eingaben aus der Datei "IN.TXT"
geholt und die Ausgaben an die Datei "OUT.TXT" angefgt werden.

CloseInput  und  CloseOutput  oder  ein  Fehler  whrend  des  Dateizugriffs
 schlieen die betroffene Datei und lenken die Ein- bzw. Ausgabe wieder auf
Tastatur bzw. Bildschirm.

Done zeigt nach den Zahleneingabefunktionen an, ob  der  eingegebene  Wert
gltig ist. termCH enthlt nach denselben Funktionen oder nach ReadString das
Zeichen, durch das die Zahlen- oder Texteingabe beendet wurde.
5.4 Bibliothek: Dateisystem                                               5 - 44
________________________________________________________


Konfiguration eigener Unittreiber

Im Modul FileBase ist ein Array namens UnitDriver deklariert. Jedes der Feld~
elemente enthlt einen Namen, Prozedurvariablen und weitere Daten fr ein
ber das Dateisystem ansprechbares sequentielles Device (Unit).

Das erste Feld z. B. enthlt den Unitnamen "CON:" und die Informationen, da
diese Unit sowohl Ein- als auch Ausgaben zult. Dazu sind auf die Prozedur~
variablen fr zeichenweise Ein- und Ausgabe Hilfsprozeduren zugewiesen, die
die Zeichen ber die BIOS-Funktionen des TOS weiterleiten. Weitere Felder
sind fr "AUX:", "PRN:", "KBD:" und "MIDI:" initialisiert. Erfreulicherweise sind
auch noch sieben freie Felder vorgesehen.

Diese Initialisierungen werden immer vom FileBase-Modul vorgenommen. Es ist
nun aber mglich, die Ein-/Ausgabefunktionen der bestehenden Units zu ndern
oder auch weitere Units in die freien Feldern einzutragen. Sollten Sie  bei~
spielsweise verbesserte Routinen fr die serielle Schnittstelle erstellt haben,
knnen Sie Ihre eigenen Prozeduren gegen die Standardroutinen austauschen,
ohne da Programme, die die serielle  Schnittstelle  ber  das  Modula-Datei~
system mit "AUX:" ansprechen, gendert werden mssen.

Wie Sie Ihre Routinen resident einbinden, erfahren Sie am Ende des Kapitels
ber Prozesse.
5.5 Bibliothek: Grafikdarstellung im Atari ST                              5- 45
________________________________________________________


5.5  Grafikdarstellung  im  Atari  ST


Alles, was auf dem Bildschirm zu sehen ist, wird im Speicher des Rechners
durch ein Bitraster reprsentiert. Dieses Bitraster belegt 32 kByte und ist in
planes, was soviel wie Bitebene bedeutet, unterteilt. Aus der Anzahl der Bit~
ebenen lt sich leicht die Zahl der gleichzeitig (ohne Tricks)  darstellbaren
Farben errechnen. Es ist

                                                   Anzahl der Bitebenen
                            Zahl der Farben = 2
                                                                            .


Beim ST kommen normalerweise drei verschiedene Modi vor:

hohe Auflsung: Es ist nur eine Bitebene vorhanden, woraus sich die Anzahl
                  1
der Farben zu 2   = 2 ergibt. Dieser Modus wird auch monochrome (schwarz/
weie) Darstellung genannt und erlaubt es, 640 x 400 einzelne Pixel (Bildpunkte)
anzusteuern;

                                                                       2
mittlere Auflsung: Zwei Bitebenen stehen zur Verfgung, was zu 2   = 4 ver~
schiedenen Farben fhrt. Bei dieser Darstellungsart knnen noch 640 x 200
Pixel benutzt werden. Das heit jede Bitebene ist 640 Pixel breit und 200 Pixel
hoch;

                                                                            4
niedrige Auflsung: Das Raster wird in vier Bitebenen aufgeteilt, wobei 2   = 16
Farben erlaubt sind. Allerdings hat eine Bitebene dann nur noch 320 x 200
Punkte.

Bei den mehrfarbigen Darstellungsmodi kann jede Farbe aus einer Palette von
512 verschiedenen Farben ausgewhlt werden.


Da der Atari ST keinen speziellen Textmodus besitzt, mu auch Schrift durch
ein Bitmuster reprsentiert werden. Dafr  existieren  verschiedene  Zeichen~
stze (fonts), die das Aussehen der einzelnen Schriftzeichen festlegen. Ist ein
Zeichensatz unproportional, so besitzen alle Zeichen die  gleiche  Breite.  Bei
einem proportionalen Font knnen zwei verschiedene Zeichen  hingegen  auch
unterschiedliche  Breite  haben  (Dieser  Text  wurde  zum  Beispiel  mit  einem
proportionalen Zeichensatz geschrieben). Das Betriebssystem stellt drei unpro~
portionale, sogenannte Systemfonts, zur Verfgung. Deren Ausmae betragen
6 x 6, 8 x 8 und 8 x 16 Pixel. Der 6 x 6 Zeichensatz wird normalerweise fr
die  Beschriftung  von  Icons  (Piktogrammen)  verwendet.  Die  beiden  anderen
dienen der allgemeinen Darstellung von Schrift, wobei der 8 x 16 Font fr die
5.5 Bibliothek: Grafikdarstellung im Atari ST                              5- 46
________________________________________________________


hohe und der 8 x 8 Font fr die mittlere und niedrige Auflsung gedacht ist.
Daraus errechnet man sofort, da bei hoher und mittlerer Auflsung 80 x 25
und bei niedriger 40 x 25 Zeichen angezeigt werden knnen. Bei der Darstel~
lung von Schrift mu zwischen den Ausmaen des eigentlichen Zeichens und
denen der Zeichenzelle (auch Zeichenbox) unterschieden werden. Die  Gre
der Zeichenzelle eines Zeichens des 8 x 16 Fonts betrgt eben genau 8 x 16
Pixel, die Gre des Zeichens selber, zum Beispiel eines kleingeschriebenen i,
ist in der Regel aber geringer. Eine Zeichenzelle wird durch einige horizontale
Linien unterteilt, von denen die wichtigste die base line (Grundlinie) ist, welche
bestimmt, in welcher Hhe die Zeichen ohne Unterlngen aufliegen.
5.6 Bibliothek: Die Line A-Routinen                                        5- 47
________________________________________________________


5.6  Die  Line  A-Routinen

Die Line A-Routinen stellen eine Sammlung von grafischen Grundfunktionen dar.
Der Name der Routinen leitet sich von der Art und Weise ihres Aufrufes ab.
Sie werden nmlich durch Opcodes der Form $Axxx aufgerufen, die im 68000
eine Ausnahmebehandlung (Exception) auslsen.

Dieser Aufruf auf Maschinenebene mu vom Modula-Programmierer natrlich
nicht mehr durchgefhrt werden. Statt dessen importiert er die entsprechen~
den Prozeduren aus dem Modul LineA. Da ein Groteil der Parameter (zum
Beispiel Schreibmodus und Farbe) entsprechend einem $Axxx-Aufruf in einem
globalen Variablenbereich, den sogenannten Line A-Variablen, definiert werden
mu, gehrt das Modul noch zu den Low-Level-Modulen. Aus diesem Grund
wird auch die Benutzung der komplexeren und komfortableren  VDI-Routinen
empfohlen. Nur in Sonderfllen sollte auf die Line A-Funktionen zurckgriffen
werden - keinesfalls  sollten  VDI-  und  Line  A-Aufrufe  in  einem  Programm
vermischt  werden,  da  dies  zu  Inkompatibilitten  in  folgenden  Grafik~
erweiterungen (z.B. Ganzseitenbildschirm, hher auflsende Farbgrafik) fhren
kann. Zur Entscheidungshilfe sei auf die Fachliteratur verwiesen (z.B. das Atari
ST Profibuch aus dem Sybex-Verlag). Die genaue Beschreibung der Routinen
steht im Anhang B. Hier sollen  nur  noch  die  verwendeten  Datenstrukturen
erklrt werden.


Der Font-Header

Die Muster aller Zeichen eines Zeichensatzes liegen in einem einzigen, aus ei~
ner Bitebene bestehenden Bitraster. Dort sind die Zeichen nebeneinander an~
geordnet, woraus folgt, da die Breite des Rasters genau die Summe aller
Zeichenbreiten ist. Eine Zeile des Bitrasters wird auch als Scan-Zeile bezeich~
net. Die Anzahl der Scan-Zeilen entspricht der Hhe einer Zeichenbox, also
der maximalen Hhe eines Zeichens.

Um die Breite eines einzelnen Zeichens zu ermitteln, geht man folgendermaen
vor: Man zieht vom ASCII-Wert des fraglichen Zeichens den ASCII-Wert des
ersten darstellbaren Zeichens (siehe minADE) ab. Die erhaltene Zahl stellt ei~
nen Feldindex fr die Character-Offset-Tabelle dar. Aus dieser liest man den
indizierten und den darauf folgenden Wert. Subtrahiert man nun den ersten
von dem zweiten erhaltenen Wert, so ergibt sich das gewnschte Ergebnis.
Auerdem entspricht der indizierte Wert auch der x-Koordinate des Zeichens
innerhalb des Bitrasters, welches die Font-Daten enthlt.

Die Horizontale-Offset-Tabelle wird, falls vorhanden, wie die Character-Offset-
Tabelle indiziert und enthlt einen vorzeichenbehafteten Wert, um den das Zei~
chen bei der Ausgabe verschoben werden soll. Der Font-Header ist in Form
eines Verbundes (FontHeader) definiert. Die Verbund-Komponeten haben fol~
gende Bedeutung:
5.6 Bibliothek: Die Line A-Routinen                                        5- 48
________________________________________________________


Bezeichner           Bedeutung

id                     Identifikationsnummer des Zeichensatzes
size                  Gre des Fonts in Punkt (Ma aus der Satztechnik)
name                 Name des Zeichensatzes
minADE               Niedrigster im Zeichensatz enthaltener ASCII-Wert
maxADE              Hchster im Zeichensatz enthaltener ASCII-Wert
topToBase            Abstand zwischen top line und base line
ascentToBase        Abstand zwischen ascent line und base line
halfToBase           Abstand zwischen half line und base line
descentToBase       Abstand zwischen descent line und base line
bottomToBase        Abstand zwischen bottom line und base line
maxCharWidth        Maximale Zeichenbreite
maxBoxWidth         Maximale Breite einer Zeichenzelle
leftOffset             Linker Offset fr Kursivschrift
rightOffset           Rechter Offset fr Kursivschrift
thickening            Anzahl der Pixel, um die ein einzelnes Zeichen bei der
                      Darstellung fetter Schrift verbreitert werden soll
underLineH           Hhe des Striches fr Unterstreichungen, in Pixel
lightMask             Maske zur Erzeugung aufgehellter Schrift
                      (normalerweise $5555)
skewMask            Maske zur Erzeugung schrger (kursiver) Zeichen
                      (normalerweise $5555)
flags                  Die einzelnen Bits haben folgende Bedeutung:
                      Bit 0 -- Zeigt an, da der Header zum Systemzeichen~
                                satz gehrt
                      Bit 1  -- Zeigt an, da die Horizontale-Offset-Tabelle
                                benutzt wird
                      Bit 2 -- Zeigt an, da die Font-Daten im 68000-Format
                                (Low/High Byte) vorliegen, sonst im Intel-For~
                                mat (High/Low Byte)
                      Bit 3 -- Zeigt an, da alle Zeichen des Fonts gleich breit
                                sind (also keine Proportionalschrift)

horOffsetTab         Zeiger  auf  die  Horizontale-Offset-Tabelle  (falls  diese
                      vorhanden ist)
charOffsetTab        Zeiger auf die Character-Offset-Tabelle
fontData              Zeiger auf das Bitraster, das die Bitmuster der Zeichen
                      enthlt
formWidth            Breite einer Scan-Zeile, also die Summe aller Zeichen~
                      breiten
formHeight           Anzahl der Scan-Zeilen
next                  Zeiger auf den Font-Header des nchsten Zeichensatzes
5.6 Bibliothek: Die Line A-Routinen                                        5- 49
________________________________________________________


Die Line A-Variablen

Die Line A-Variablen dienen zur bergabe der Parameter an die Line A-Routi~
nen. Welche Variablen von einer Routine ausgewertet werden, ist bei der Be~
schreibung der betreffenden Prozedur angegeben (Siehe Anhang B).

Es folgt eine Erklrung aller Line A-Variablen. Die Variablen sind in einem Ver~
bund mit dem Bezeichner LineAVars zusammengefat, der folgende Struktur
hat:

Bezeichner           Bedeutung

planes                Gibt die Anzahl der benutzten Bitebenen an. Wird von je~
                      der Routine, auer BitBlockTransfer, ausgewertet
bytesPerLine          Anzahl der Bytes einer Bildschirmzeile (Scan-Zeile). Wird
                      von jeder Routine, auer BitBlockTransfer,ausgewertet
contrl                 Zeiger auf das CONTRL-Array
intin                  Zeiger auf das INTIN-Array
ptsin                  Zeiger auf das PTSIN-Array
intout                 Zeiger auf das INTOUT-Array
ptsout                Zeiger auf das PTSOUT-Array
plane1                Gibt an, welchen Wert das Bit der ersten Bitebene beim
                      Setzen eines Punktes erhalten soll
plane2                Gibt an, welchen Wert das Bit der zweiten Bitebene beim
                      Setzen eines Punktes erhalten soll
plane3                Gibt an, welchen Wert das Bit der dritten Bitebene beim
                      Setzen eines Punktes erhalten soll
plane4                Gibt an, welchen Wert das Bit der vierten Bitebene beim
                      Setzen eines Punktes erhalten soll
lastLine               Wird beim Zeichnen von Linien ausgewertet und besagt,
                      ob  die  zu  zeichnende  Linie  Teil  eines  im  EXCLUSIV-
                      ODER-Schreibmodus gezeichneten Polygonzuges ist. TRUE
                      bedeutet "Linie vollstndig zeichnen"
lineMask              Bitmuster fr das Zeichnen von Linien
writingMode          Gibt an, in welchem Schreibmodus gezeichnet werden soll.
                      Siehe auch GrafBase.WritingMode
p                     Erster Punkt
q                     Zweiter Punkt
patternPtr            Zeigt auf das zu verwendende Fllmuster. Ein Fllmuster
                      besteht aus einer oder mehreren Bitebenen, die immer 16
                      Bit (also ein Wort) breit sind.
patternMask          Gibt an, wie viele Zeilen eine Bitebene des Fllmusters
                                                                           n
                      besitzt. Sinnvoll sind nur Zahlen, die sich durch 2   (n >
                      0) dar-stellen lassen.
multiFill               Ist diese Variable gesetzt, so besteht das Fllmuster aus
                      mehreren Bitebenen, sonst nur aus einer.
5.6 Bibliothek: Die Line A-Routinen                                        5- 50
________________________________________________________


clipping               Gibt an, ob der folgende Rechteckbereich als Ausgabebe~
                      grenzung benutzt werden soll. In diesem Fall werden alle
                      Punkte, die ausserhalb dieses Bereichs zu liegen kom~
                      men, unterdrckt.
minClip               Linker, oberer Punkt des Begrenzungsrechtecks
maxClip               Rechter, unterer Punkt des Begrenzungsrechtecks
scaleAcc             Dient  als  Startwert  fr  den  Schriftvergrerungs- und
                      verkleinerungsalgorithmus. Sollte bei gesetztem scale-Flag
                      (Siehe unten) mit $8000 vorbesetzt werden.
scaleFactor           Gibt den Vergrerungs- oder Verkleinerungsfaktor  an.
                      Dabei gilt fr die
                      Vergrerung: $0000 - Normale Gre
                                         .
                                         .       Entsprechende Zwischengren
                                         .
                                      $FFFF  - Doppelte Gre
                      Verkleinerung: $0000 - Keine Gre (Schrumpfung auf
                                         .                      einen Punkt)
                                         .      Entsprechende Zwischengren
                                         .
                                      $FFFE  - Normale Gre
scaleMode
                      Gibt an ob vergrert oder verkleinert werden soll. Ist
                       Bit 0 gesetzt, so wird vergrert, sonst wird verkleinert
monoStatus          Zeigt an, da die Zeichen einheitliche Breite haben. Ist
                      bei proportionalen Fonts nicht der Fall
source                Linke, obere Ecke des Zeichens im Bitraster des Fonts
dest                  Linke, obere Ecke des Zeichens auf dem Bildschirm
width                 Breite des Zeichens
height                Hhe des Zeichens
formBase             Zeiger auf den Anfang der Font-Daten (Bitraster des Fonts)
formWidth            Breite einer Scan-Zeile im Bitraster des Fonts (Angabe
                      in Bytes)
style                  Flags fr spezielle Texteffekte. Es bedeutet:
                      Bit 0 -- Fette Darstellung der Schrift
                      Bit 1 -- Aufgehellte Darstellung der Schrift
                      Bit 2 -- Schrgstellen der Schrift (Kursive Darstellung)
                      Bit 3 -- Unterstreichen der Schrift
                      Bit 4 -- Umrahmte Darstellung der Schrift
lightMask             Maske zum aufgehellten Darstellen der Schrift
skewMask            Maske fr kursive Schrift
weight                Anzahl der Bits, um die fette Schrift verbreitert werden
                      soll
rightOff              Rechter Offset fr kursive Schrift
leftOff                Linker Offset fr kursive Schrift
5.6 Bibliothek: Die Line A-Routinen                                        5- 51
________________________________________________________


scale                 Zeigt an, ob Schrift in ihren Ausmaen verndert werden
                      soll
chup                  Gibt den Winkel zwischen der Zeichengrundlinie (base line)
                      und  der  horizontalen  Koordinatenachse,  entgegen  dem
                      Uhrzeigersinn  an.  Dabei  bedeutet  (Zwischenwerte  sind
                      nicht mglich):
                          0  -- Normale  Darstellung
                        900  -- Drehung um 90 Grad
                      1800  -- Drehung um 180 Grad
                      2700  -- Drehung um 270 Grad
textFg                Vordergrundfarbe fr die Textdarstellung
scratchArea          Zeiger auf einen Speicherbereich, der bei der Vergrer~
                      ung/Verkleinerung von Schrift und fr Texteffekte ver~
                      wendet wird
scratchOff2          Offset fr den obigen Zeiger, falls sowohl eine Gren~
                      nderung als auch Texteffekte erwnscht sind

Zu den beiden vorangegangenen Variablen ist folgendes zu sagen. Beim Durch~
fhren einer Grennderung von Schrift werden

                              Breite                       2
                            8         5
                 Hhe * (  -------   + 2)  * ( Faktor   +  1)
                            8         5
                                 8

Bytes von den Line A Routinen bentigt.

Es stehen Hhe und Breite fr die Ausmae der Zeichenzelle im Originalzu~
stand (in Pixel). Faktor gibt den Vergrerungsfaktor an (Faktor = 1.5 bedeutet
zum Beispiel eine Vergrerung um das Anderthalbfache). x steht fr die
Gau-Klammer, also den Wert von x mit abgehackten Nachkommastellen. Fr
Texteffekte gilt die folgende Formel, das Resultat sind wieder die bentigten
Bytes:

                            Breite
                         8         5
               Hhe * (  -------   + 2)
                         8         5
                               8

Nur sind mit Hhe und Breite diesmal die Ausmae des Zeichens nach der An~
wendung der Effekte gemeint.

Werden nur die Texteffekte oder nur die Grennderung genutzt, so gengt
es, scratchArea auf einen gengend groen Speicherbereich weisen zu lassen.
Werden beide kombiniert angewandt, so mu der von scratchArea markierte
Bereich die Summe beider Formeln an Bytes umfassen und in scratchOff2 die
Anzahl der Bytes fr die Grennderung stehen (es drfen nur gerade Werte
verwendet werden).
5.6 Bibliothek: Die Line A-Routinen                                        5- 52
________________________________________________________


textBg                Hintergrundfarbe fr die Textdarstellung
copyTrans            Zeigt an, da  die  Routine  CopyRasterForm  transparent
                      kopieren soll, sonst kopiert sie berdeckend


Der Deskriptor fr BitBlockTransfer

Der Deskriptor enthlt alle Parameter, die fr die Ausfhrung eines BitBlock
Transfer ntig sind. Die Definition hat den Bezeichner BBTDeskriptor und ent~
hlt folgende Verbund-Komponenten:

Bezeichner           Bedeutung

w                     Breite des Quellbereichs in Pixeln
h                     Hhe des Quellbereichs in Pixeln
destPlanes            Anzahl der Bitebenen (des Zielbereichs)
setBitCol             Farbe fr im Quellbereich gesetzte Bits, allerdings nicht
                      als Farbindex, sondern als Bitmuster, in dem jeweils ein
                      Bit fr eine Bitebene steht (Bit 0 entspricht erster Bit~
                      ebene)
unsetBitCol           Farbe fr im Quellbereich ungesetzte Bits. Format  wie
                      oben.

                      Verknpfungsart fr Planes, bei denen das
mode00              setBitCol-Bit und das unsetBitCol-Bit gleich Null ist
mode01               setBitCol-Bit gleich Null und das unsetBitCol-Bit Eins ist
mode10               setBitCol-Bit gleich Eins und das unsetBitCol-Bit Null ist
mode11               setBitCol-Bit gleich Eins und das unsetBitCol-Bit Eins ist

Die sechs letzten Variablen sind nur fr transparente Kopiervorgnge relevant.
Beim deckenden Kopieren wird setBitCol und unsetBitCol auf Null gesetzt und
die zu benutzende Verknpfungsart in mode00 eingetragen.

Hinweis:   Zu den Verknpfungsarten siehe GrafBase.BitOperation.

sourceStart          Startpunkt des Quellbereichs in Pixeln
sourceAddr           Anfangsadresse des Quellbereichs (nicht des Quellrasters)
sourceInc             Schrittweite  im  Quellbereich  in  Byte  (normalerweise:
                      Anzahl der Bitebenen des Quellbereichs * 2)
sourceWidth          Breite einer Scan-Zeile des Quellrasters in Bytes
sourceWidth2        Bei transparenter Kopie gleich Null, sonst gleich source~
                      Width
destStart             Startpunkt des Zielbereichs in Pixeln
destAddr             Anfangsadresse des Zielbereichs (nicht des Zielrasters)
destInc               Schrittweite im Zielbereich in Byte
                      (normalerweise: Anzahl der Bitebenen des Zielbereichs * 2)
5.6 Bibliothek: Die Line A-Routinen                                        5- 53
________________________________________________________


destWidth            Breite einer Scan-Zeile des Zielrasters in Bytes
destWidth2           Bei transparenter Kopie gleich Null,  sonst  gleich  dest~
                      Width
patternPtr            Zeiger auf ein Fllmuster, das whrend des Kopiervor~
                      gangs als Maske verwendt wird (Ist er NIL, so wird un~
                      maskiert kopiert.)
patternWidth         Breite einer Zeile des Fllmusters in Byte (Der aktuelle
                      Algorithmus  scheint  Probleme  mit  dieser  Variable  zu
                      haben und nimmt evtl. immer eine Breite von 2 Byte an)
patPlaneOff           Null bedeutet, da das Fllmuster nur eine Bitebene be~
                      sitzt, sonst steht hier Zahl der Bytes fr eine Bitebene.
patternEnd           Anzahl der Zeilen des Fllmusters (alle Bitebene zusam~
                      men) multipliziert mit patternWidth
scratch               Bereich, der von der Kopierroutine als Variablenspeicher
                      benutzt wird. Mu nicht initialisiert werden.
5.7 Bibliothek: GEM                                                        5- 54
________________________________________________________


5.7  GEM

GEM steht fr Graphics Environment Manager und ist schlicht und ergreifend
die  auf  dem  Atari  ST  implementierte  grafische  Benutzeroberflche.  Dem
Programmierer stellt sie ein umfangreiches Paket an Routinen zur Verfgung,
das sowohl Dialog-, Fenster-, Menverwaltung und hnliches umfat als auch
Prozeduren   enthlt,   die   eine   einheitliche   Schnittstelle   zur   Benutzung
verschiedener  Ein-  und  Ausgabegerte  bilden.  Das  GEM  besteht  aus  zwei
groen Bibliotheken, dem VDI und dem AES.


VDI

Das VDI (Virtual Device Interface) umfat allgemeine Ein- und Ausgabeopera~
tionen, deren Benutzung von der aktuellen Implementierung der Routinen relativ
unabhngig ist.

Theoretisch  kann  man  zwischen  zwei  verschiedenen  Koordinatensystemen
whlen. Im

NDC (Normalisierte Gertekoordinaten)-System liegt der Ursprung (0, 0) in der
linken  unteren,  Ecke  und  die  rechte  obere  Ecke  besitzt  die  Koordinaten
(32767, 32767). Dieses System hat den Vorteil einer allgemeinen Verwend~
barkeit, es ist aber im aktuellen TOS nicht implementiert;

RC (Raster Koordinaten)-System ist der Ursprung (0, 0) die linke, obere Ecke,
und die Koordinaten der rechten unteren Ecke hngen von der Auflsung des
Ausgabegertes  ab;  sie  betragen  beispielsweise  auf  dem  monochromen
Bildschirm (639, 399).

Bei jedem Aufruf einer VDI-Prozedur mu als erster Parameter eine Gerte~
kennung (GEMEnv.DeviceHandle) bergeben werden. Diese Kennung teilt dem
VDI mit, auf welchem Gert die Ein- oder Ausgabe stattfinden soll. Meist ist
dies  die  Kennung  fr  eine  virtuelle  Bildschirmarbeitsstation  (virtual  screen
workstation). Dies bewirkt eine ganz normale Ausgabe auf den Bildschirm. Wie
erhlt man nun solch eine Kennung? Dafr gibt es zwei Mglichkeiten. Erstens
kann  man  die  Routine  GEMEnv.InitGem  aufrufen  und  meldet  sich  dadurch
sowohl  beim  VDI  als  auch  beim  AES  an.  Auerdem  erhlt  man,  falls  die
Anmeldung  glckt,  auch  noch  eine  Kennung  fr  eine  virtuelle  Bildschirm~
arbeitsstation, mit deren Hilfe man nun auf den Bildschirm zugreifen kann. Die
zweite  Mglichkeit  besteht  in  einem  Aufruf  von  GEMEnv.OpenDevice.  Diese
Mglichkeit  sollte  aber  erst  fr  das  zweite  und  folgende  Gerte  benutzt
werden.

Ist man mit allen Arbeiten auf dem Gert fertig, so sollte dies mit GEMEnv.
CloseDevice geschlossen werden. Eine Beschreibung der Funktionsweise und
Parameter der einzelnen VDI-Prozeduren findet man im Anhang B.
5.7 Bibliothek: GEM                                                        5- 55
________________________________________________________


AES

Das AES (Application Environment Services) untersttzt eine Anwendung, das
heit  ein  vom  Benutzer  gestartetes  Programm,  bei  der  Verwaltung  von
Fenstern, Dialogboxen, Mens und hnlichem. Auerdem ermglicht es teilweise
eine quasiparallele Abarbeitung mehrerer Prozesse. Dies sind einerseits bis zu
sechs  Desk-Accessories  und  andererseits  die  aktuelle  Anwendung.  Da  die
Datenstrukturen und Funktionen des AES zum Teil recht komplex sind, sollen
sie im Folgenden einzeln betrachtet werden.


Das Konzept der GEM-Resourcen

Als Resource einer Anwendung bezeichnet man die Objekte, die zur Kommuni~
kation mit der Auenwelt dienen. Dies knnen zum Beispiel Dialogboxen oder
Menzeilen  sein.  Die  GEM-Resourcen  befinden  sich  in  der  Regel  in  einem
Resource-File, das durch den Suffix .RSC  kenntlich  gemacht  wird.  Erzeugt
wird dieses File mit einem Resource Construction Set  (Siehe  auch  Anhang
C.2).  Allerdings  ist  es  auch  mglich,  die  Resourcen  zur  Laufzeit  von
Programmen selber erstellen oder ndern zu lassen (siehe Modul ObjHandler).


Verwaltung der GEM-Resourcen

Liegt ein Resource-File vor, so sollte dies whrend der Initialisierung der An~
wendung  mit  AESResources.LoadResource  geladen  werden.  Mit  Hilfe  von
AESResources.ResourceAddr und der Resource-Indizes knnen jetzt die Adressen
der einzelnen Objektbume und anderer Strukturen (siehe auch Abschnitt ber
Objektbume) ermittelt werden. Die Resource-Indizes kennt eine Anwendung
durch das Importieren des Definitonsmoduls, das vom Resource Construction
Set beim Speichern der Resource erzeugt wird. Die Indizes sind in dem Modul
als Konstanten deklariert. Die Bezeichner dieser Konstanten entsprechen de~
nen, die whrend der Erstellung der einzelnen Objekte im Resource Construc~
tion Set eingegeben wurden. Wenn eine Resource nicht mehr gebraucht wird,
sollte ihr Speicherplatz durch AESResources.FreeResource freigegeben werden.


Die Struktur des Objektbaumes

Eine Resource besteht im wesentlichen aus Objektbumen. Diese dienen sowohl
zur Beschreibung von Dialogformularen und Menzeilen, als auch zum Erstellen
eigener Desktopoberflchen. Der Objektbaum und alle seine Elemente sind im
Modul GEMGlobals definiert.
5.7 Bibliothek: GEM                                                        5- 56
________________________________________________________


ACHTUNG:    Da die Typdefinitionen von Modula  und  C  (Muttersprache  des
               GEM) teilweise nicht kompatibel sind, sind die Objektdeklarationen
               oft  sehr  allgemein  gehalten.  Zum  Beispiel  ist  Object.type  als
               CARDINAL  deklariert,  obwohl  weiter  oben  ein  Typ  ObjType
               definiert  wurde,   der   ja   eigentlich   als   Wertebereich   fr
               Object.type dienen soll. Der Grund dafr  ist  einfach,  da  die
               Ordinalzahlen  fr  die  Objekttypen  erst  bei  20  anfangen,  ein
               Modula-Aufzhlungstyp  aber  bei  Null  beginnt.  Das  ist  alles
               ungefhrlich,  solange  ausschlielich  die  Routinen  der  GEM-
               Bibliotheksmodulen  zum  Verarbeiten  der  Objekte  verwendet
               werden (Dort werden alle Typwandlungen und -transformationen
               automatisch  durchgefhrt).  Sobald  man  aber  direkt  auf  die
               Objektstruktur zugreifen will, sollte man sich vorher ber  die
               interne  Darstellung  von  Variablen  durch  den  Modula-Compiler
               und das GEM informieren.

Der Baum ist ein Feld (Array) aus Objekten (Object) und wird mit Hilfe eines
Zeigers (PtrObjTree) referenziert. Der Baumindex eines Objektes  ist  nichts
weiter als nur der Feldindex innerhalb des Baumes. Ein Objekt ist ein Verbund,
der aus einer allgemeinen Objektbeschreibung (Stellung im Baum, Gre etc.)
und  eventuell  noch  einem  Zeiger  auf  eine  typabhngige  Objektspezifikation
besteht. Dieser Verbund enthlt folgende Elemente:

Bezeichner           Bedeutung

next                  Index  des  rechten  Nachbarobjektes,  entspricht  dem
                      nchsten Objekt der Nachfolgerliste (Das rechteste Ob~
                      jekt einer Nachfolgerliste enthlt den Index Vorgngers)
head                  Kopf (linkestes Objekt) der Nachfolgerliste des Objekts
tail                   Ende (rechtestes Objekt) der Nachfolgerliste des Objektes

Ist eine der drei vorausgegangenen Variablen gleich NoObject, so existiert das
bezeichnete Objekt nicht. Das bedeutet fr head und tail, da das Objekt keine
Nachfolgerliste und somit auch keine Nachfolger besitzt. Und fr next, da
weder Nachbarn noch ein Vorgnger existieren, das heit das Objekt ist die
Wurzel des Baumes.

type                  Gibt an, von welchem Typ das Objekt ist
flags                  Gibt die Flags des Objektes an
state                 Bestimmt den Objektstatus
spec                  Enthlt die typabhnige Objektbeschreibung
space                 Gibt den vom Objekt belegten Rechteckbereich an. Dabei
                      ist zu beachten, da die Position relativ zum Vorgnger~
                      objekt angegeben wird. Nur die Koordinaten des Wurzel~
                      objektes sind absolute Bildschirmkoordinaten.
5.7 Bibliothek: GEM                                                        5- 57
________________________________________________________


Folgende Objekttypen werden untersttzt:

Bezeichner           Bedeutung

boxObj                Stellt ein geflltes Rechteck dar. Die Objektspezifikation
                      gibt Farbe und Randstrke an.
textObj               Steht  fr  einen  Schriftzug.  Objektspezifikation  ist  ein
                      Zeiger auf eine TEdInfo-Struktur.
boxTextObj           Stellt eine Kombination der beiden vorangegangenen Ob~
                      jekttypen dar. Spezifikation wie bei textObj.
imageObj
                      Es wird ein Bitmuster dargestellt.  Spezifikation  ist  ein
                      Zeiger auf einen BitBlock-Verbund.
progDefObj           Selbstdefinierbares  Objekt.  Spezifikation  ist  ein  Zeiger
                      auf  eine  ApplBlock-Struktur.  Nheres  zu  diesem  Typ
                      kann  im  Definitionsmodul  von  ObjHandler  nachgelesen
                      werden.
iBoxObj               Dies ist ein Rechteck, von dem nur der Rahmen sichtbar
                      ist. Hat  dieser  die  Strke  Null,  so  ist  es  unsichtbar.
                      Objektspezifikation  entspricht  boxObj.  Dieser  Objekttyp
                      wird   meist   zum   Zusammenfassen   von   mehreren
                      Unterobjekten benutzt.
buttonObj             Solche Objekte werden in der Regel als Knopf in Dialog~
                      boxen benutzt. Es wird ein Text zentriert in einem wei
                      gefllten Rechteck ausgegeben. Die Spezifikation ist ein
                      Zeiger auf eine Zeichenkette.
boxCharObj           Entspricht boxObj, nur wird innerhalb des Rechteckes ein
                      Zeichen zentriert dargestellt. In der Spezifikation befindet
                      sich zustzlich noch der ASCII-Wert des Zeichens.
stringObj             Stellt  die  Zeichenkette  dar,  auf  die  die  Spezifikation
                      zeigt.  Wird  fr  die  Eintrge  in  den  Pull-Down-Mens
                      verwendet.
fTextObj              Entspricht textObj, doch ist der Text hier edierbar.
fBoxTextObj          Wie fTextObj, doch wird der Text innerhalb eines gefll~
                      ten Rechtecks dargestellt.
iconObj               Beschreibt ein Piktogramm (Icon). Dieses besteht aus ei~
                      nem maskierten Bitmuster, einer Bildunterschrift und ei~
                      nem Zeichen. Spezifikation ist ein Zeiger auf einen Icon~
                      Block-Verbund.
titleObj               Entspricht  stringObj,  wird  allerdings  fr  die  Mentitel
                      verwendet.
5.7 Bibliothek: GEM                                                        5- 58
________________________________________________________


Es folgen die Objektflags:

Bezeichner           Bedeutung

selectFlg              Zeigt an, da das Objekt bei einem Dialog durch einen
                      Mausklick angewhlt werden kann
defaultFlg             Besitzt ein Objekt  dieses  Flag,  so  wird  es  angewhlt,
                      wenn whrend eines Dialoges die <Return>-Taste bettigt
                      wird.  Das  Flag  sollte  pro  Dialogformular  nur  einmal
                      vorkommen.
selectExitFlg          Bestimmt, da der Dialog abgebrochen wird, sobald das
                       so gekennzeichnete Objekt angewhlt wird.
editFlg                Zeigt an, da das Objekt einen edierbaren Text enthlt.
radioButFlg           Kennzeichnet eine Gruppe von Objekten, von denen immer
                      nur  eines  gleichzeitig  angewhlt  sein  kann.  Wird  ein
                      zweites angeklickt, so wird das erste wieder deselektiert.
                      Die Elemente der Gruppe mssen denselben  Vorgnger
                      besitzen.
lastObjFlg             Bestimmt das letzte Objekt eines Baumes, also das mit
                      dem grten Objektindex.
touchExitFlg          Wird auf einem solchen Objekt whrend des Dialoges der
                      Mausknopf gedrckt,  so  wird  der  Dialog  beendet.  Der
                      Knopf mu im Gegensatz zu selectExitObj nicht wieder
                      losgelassen werden.
hideTreeFlg
                      Das so gekennzeichnete Objekt und all seine Nachfolger
                      werden   von    einem    AESObjects.DrawObject    oder
                      AESObjects.FindObject ignoriert.
indirectFlg            Besagt,  da  Object.spec  nicht  die  wirkliche  Objektbe~
                      schreibung, sondern nur einen Zeiger auf sie enthlt.

Folgende Objektzustnde sind mglich:

Bezeichner           Bedeutung
selectObj             Das Objekt wird invers dargestellt und gilt somit als an~
                      gewhlt
crossObj             Es wird ein Kreuz durch das Objekt gezeichnet
checkObj             Das Objekt wird mit einem Hacken versehen
disableObj            Das Objekt wird aufgehellt. Bezeichnet nicht anwhlbare
                      Objekte
outlineObj             Es wird ein Rahmen um das Objekt gezeichnet
shadowObj            Das Objekt erhlt beim Zeichnen einen Schatten.

Die Objektspezifikation enthlt grundstzlich eine von zwei Strukturen. Entwe~
der ist sie ein Zeiger auf die eigentliche Beschreibung (zum Beispiel TEdInfo),
oder sie enthlt die Objektfarbe und die Randdicke des Objektes. Letzteres ist
5.7 Bibliothek: GEM                                                        5- 59
________________________________________________________


bei boxObj und iBoxObj der Fall, auerdem gilt es auch fr boxCharObj, nur
wird hier zustzlich noch der ASCII-Wert des Zeichens angegeben. Die Rand~
strke kann Werte zwischen -128 und 127 annehmen, dabei wchst der Rand
bei positiven Werten nach innen und bei negativen nach auen. Bei Objekten
vom Typ boxObj, iBoxObj, box CharObj und bei Objekten, die einen Zeiger auf
eine TEdInfo-Struktur als Spezifikation besitzen, besteht die Objektfarbe aus
folgenden Komponenten: Randfarbe, Farbe fr den Text, Schreibmodus fr die
Darstellung von Text (ist entweder deckend oder transparent), Fllmuster und
Fllfarbe. Es existieren 8 verschiedenen Fllmuster, dabei stehen die Werte
von 1 bis 6 fr Punktmuster, die mit steigendem Wert immer dunkler werden.
0 bedeutet keine Fllung und 7 vollstndiges Fllen mit der Fllfarbe.

Jetzt fehlt nur noch die Beschreibung fr die einzelnen Objektspezifikationen.


Die TEdInfo-Struktur

dient zur Beschreibung von edierbarem und nicht edierbarem Text. Ist der Text
nicht edierbar, so werden tmpltPtr und validPtr nicht ausgewertet.

Bezeichner           Bedeutung

textPtr               Zeiger auf die Zeichenkette, die den aktuellen Text ent~
                      hlt
tmpltPtr              Zeiger auf die Zeichenkette, die die Textmaske enthlt.
                      Der aktuelle Text wird dort in die Maske eingesetzt, wo
                      diese das '  '-Zeichen enthlt. Die dadurch erzeugte Zei~
                                  _
                      chenkette wird auf dem Bildschirm dargestellt
validPtr               Zeiger  auf  die  Zeichenkette,  die  bestimmt,  welche
                      Zeichen eingegeben werden drfen. Dabei stehen folgende
                      Character fr die jeweils beschriebene Zeichenmenge:
                      9  -- Erlaubt die Ziffern von 0 bis 9
                      A -- Erlaubt alle Grobuchstaben von A bis Z und das
                             Leerzeichen
                      a  -- Erlaubt Gro- und Kleinbuchstaben und das Leer-
                             zeichen
                      F  -- Erlaubt Filenamen  mit den Sonderzeichen "?", "*"
                             und ":"
                      P  -- Erlaubt Pfadnamen mit "", "?", "*" und ":"
                      p  -- Erlaubt Pfadnamen mit "", ":"
                      X  -- Erlaubt alle Zeichen
font                  Bestimmt den zu verwendenden Zeichensatz
                      (StandardFont oder SmallFont)
res1                  Reserviert fr zuknftige Anwendungen
just                   Bestimmt die Textausrichtung
color                 Bestimmt Farbe und hnliches (siehe obige Beschreibung
                      der Objektfarbe)
5.7 Bibliothek: GEM                                                        5- 60
________________________________________________________


res2                  Reserviert fr zuknftige Anwendungen
thickness             Randstrke
textLen               Maximallnge  des  aktuellen  Textes  (abschlieende  Null
                      mitzhlen)
tmpltLen              Lnge der Textmaske (abschlieende Null mitzhlen)


Die IconBlock-Struktur

bestimmt das Aussehen  von  Piktogrammen.  Das  Aussehen  des  eigentlichen
Bildchens wird durch zwei Bitmuster bestimmt, die Maske und die Daten. Dies
dient dazu, da der Hintergrund nicht durchscheinen kann und das Objekt auch
im  invertierten  Zustand  anstndig  aussieht.  Die  Maske  wird  normalerweise
benutzt, um den Hintergrund dort zu lschen, wo er nicht erwnscht ist; die
Daten bestimmen dann das eigentliche Aussehen des Icons.

Bezeichner           Bedeutung

mask                 Zeiger auf das Bitmuster der Maske
data                  Zeiger auf das Bitmuster der Daten
text                  Zeiger auf die Zeichenkette der Bildunterschrift
color                 Die 4 hchstwertigen Bits enthalten den Farbindex fr die
                      gesetzten Datenbits, den Schriftzug und das Zeichen. Die
                      4 niederwertigen Bits geben den Farbindex fr die ge~
                      setzten Maskenbits und den Texthintergrund an
oneChar              ASCII-Wert des im Icon dargestellten Zeichens, ist er
                      gleich 0C, so wird nichts dargestellt
charPos              Position des Zeichens relativ zur Objektposition
iconFrame            Ausmae des Bitmusters. Die Position ist relativ zu der
                      des Objektes, auerdem sollte die Breite ein Vielfaches
                      von 16 sein
textFrame            Ausmae des Schriftzuges. Positionsangabe ist relativ


Die BitBlock-Struktur

beschreibt ein einfaches Bitmuster.

Bezeichner           Bedeutung

data                  Zeiger auf das Bitmuster
bytes                 Breite des Bitmusters in Byte, dieser Wert mu gerade
                      sein
h                     Hhe des Musters in Pixeln
x                     Horizontaler Offset, der es erlaubt, jedes beliebige Bit an
                      den linken Rand zu setzen
y                     Vertikaler Offset
5.7 Bibliothek: GEM                                                        5- 61
________________________________________________________


color                 Farbindex fr das Bitmuster


Die ApplBlock-Struktur

beschreibt ein selbstdefinierbares Objekt. Dies geschieht, indem eine Prozedur
angegeben wird, die das Objekt wahlweise zeichnet oder seinen Status ndert.
Der Prozedur kann ein 32 bit breiter Parameter bergeben werden, der das
Aussehen des Objektes nher beschreibt. Will man solch ein Objekt ohne die
Routinen des Moduls ObjHandler benutzen, so hat man darauf zu achten, da
zum Zeitpunkt des Aufrufs  der  Zeichenprozedur  die  Registerbelegung  nicht
mehr den Modulakonventionen entspricht.

Bezeichner           Bedeutung

code                  Startadresse  der  Zeichenprozedur.  Die  Prozedur  be~
                      kommt beim Aufruf einen Zeiger auf einen ParmBlock-
                      Verbund bergeben.
parm                 Parameter fr die Prozedur


Das Konzept der AES-Menuleisten

Die Menuleisten werden mit Hilfe eines Objektbaumes dargestellt und sollten
mit dem Resource Construction Set erstellt werden. Die Routinen zum Benut~
zen der Pull-Down-Menus finden sich in dem Modul AESMenus. Die wichtigste
von ihnen ist MenuBar, mit ihr werden die Menus aktiviert und auch wieder
ausgeschaltet. Ein aktives Menu kann vom Anwender mit der Maus bedient
werden. Wird ein Menupunkt angewhlt, so erhlt man ein Nachrichtenereignis
mit der Kennung AESEvents.menuSelected.


Accessories

Accessories werden mit Hilfe der Prozedur AESMenus.RegisterAcc beim AES
angemeldet. Nach der Anmeldung erscheint der Titel des Accessory's in jedem
Menu und kann damit vom Benutzer angewhlt werden. Wird es selektiert, so
wird ihm eine Nachricht mit der Kennung AESEvents.accOpen gesendet, dabei
bergibt das AES zur Kontrolle die bei der Anmeldung erhaltene Accessory-
Kennung.
5.7 Bibliothek: GEM                                                        5- 62
________________________________________________________


Das Konzept der AES-Fenster

Fenster dienen zum Darstellen von Informationen, sie sind in ihrer Gre und
Position frei vernderbar und drfen sich auch berlappen (Alle Prozeduren zur
Fensterbehandlung  findet  man  in  AESWindows).  Welche  Bedienungselemente
(Schieber,  Titelzeile  etc.)  ein  Fenster  besitzt,  wird  von  dem  Anwendungs~
programm whrend der Anforderung einer Fensterkennung mit CreateWindow
festgelegt. Erhlt die Anwendung eine Kennung ungleich NoWindow, so war die
Anforderung  erfolgreich,  und  diese  Kennung  mu  dann  immer  als  erster
Parameter bei allen  Funktionen  angegeben  werden,  die  auf  diesem  Fenster
arbeiten  sollen.  Wird  ein  Fenster  nicht  mehr  bentigt,  so  sollte  die
Fensterkennung mit DeleteWindow freigegeben werden.

Soll  das  Fenster  nun  auf  dem  Bildschirm  dargestellt  werden,  so  mu
OpenWindow aufgerufen werden. Es ist nun sichtbar, und die Anwendung mu
dafr sorgen, da, sobald das AES eine entsprechende Nachricht schickt, der
Fensterinhalt erneuert wird. Soll das Fenster wieder verschwinden, so wird
dies  dem  AES  mittels  Close  Window  mitgeteilt.  Mit  OpenWindow  kann  es
daraufhin jederzeit wieder sichtbar gemacht werden, und der Ablauf beginnt
von Neuem. Wird ein Fenster geffnet, in seiner Gre verndert oder ein
darberliegendes  Fenster  verschoben,  so  kann  es  passieren,  da  pltzlich
sichtbar werdende Fensterinhalte der Neuzeichnung  (redraw)  bedrfen.  Eine
solches  Ereignis  veranlat  das  AES,  eine  Nachricht  zur  Neuzeichnung
AESEvents.windRedraw   zu   schicken.   Wird   diese   von   der   Anwendung
empfangen, so wird im Regelfall ein Aktualisieren des Fensters angekndigt und
der Mauszeiger versteckt. Jetzt wird die Rechteckliste vom AES geholt und
der angegebene Bereich neu gezeichnet. Schluendlich  wird  der  Mauszeiger
wieder sichtbar gemacht und das Ende der Neuzeichnung gemeldet.

Die folgende Prozedur soll dies verdeutlichen; sie geht davon aus, da dev eine
virtuelle Bildschirmarbeitsstation (siehe VDI) ist. Ihr wird die Fensterkennung
(handle) und der neuzuzeichende Bereich (frame) bergeben.
5.7 Bibliothek: GEM                                                        5- 63
________________________________________________________


PROCEDURE RedrawFrame (handle:CARDINAL;
                              frame:GrafBase.Rectangle);

VAR     clip : GrafBase.Rectangle;

BEGIN
               (* Fllattribute fr 'Bar' bestimmen *)

  VDIAttributes.SetFillType (dev, VDIAttributes.solidFill);
  VDIAttributes.SetFillColor (dev, GrafBase.white);

               (* Aktualisierung ankndigen und Mauszeiger aus *)

  UpdateWindow  (TRUE);
  AESGraphics.GrafMouse (AESGraphics.mouseOff, NIL);

               (* 1. Element der Reckteckliste holen *)

  clip:=WindowRectList (handle, firstElem);

  WHILE clip.w # 0 DO      (* 'w = 0' kennzeichnet Listenende *)

               (*  Schnittbereich ermitteln und
                *  Ausgabebereich beschrnken
                *)
     clip:=GrafBase.ClipRect (frame, clip);
     VDIControls.SetClipping (dev, clip);

     VDIOutputs.Bar (dev, clip);  (* Bereich mit Wei fllen *)

         (*  Hier knnen noch andere Sachen gezeichnet werden *)

                (* Nchstes Element der Rechteckliste holen *)

     clip:=WindowRectList (handle, nextElem);

  END;

  VDIControls.DisableClipping (dev);        (* Clipping aus *)

               (* Mauszeiger ein und Aktualisierungsende melden *)
  AESGraphics.GrafMouse (AESGraphics.mouseOn, NIL);
  UpdateWindow (FALSE);
END RedrawFrame;
5.7 Bibliothek: GEM                                                        5- 64
________________________________________________________


Die Funktion der anderen (Fenster betreffenden) Nachrichten kann im Definitions~
modul AESEvents und im Abschnitt ber Ereignisse nachgelesen werden.

Neben den oben beschriebenen Fenstern existiert noch ein weiteres. Es ist das
Desktop-Fenster, welches die Kennung DeskHandle besitzt. Neuzeichnungen des
Desktops mssen nicht von der Anwendung durchgefhrt werden, sie sind Auf~
gabe des AES. Dies hat natrlich den Nachteil, da das Aussehen des Desk~
tops im wesentlichen immer gleich ist. Dieser Nachteil wurde dadurch ausge~
schaltet, da es mglich ist, einen beliebigen Objektbaum mit SetNewDesk als
Desktopoberflche zu benutzen.

Bei allen Aufgaben, die von der Gre des Desktops abhngen, sollten eben
diese Ausmae durch einen Aufruf von WindowSize (DeskHandle, workSize)
ermittelt werden.  Es  wird  die  Bildschirmgre,  abzglich  der  Menuzeile,  in
Pixeln geliefert.


Das Konzept der AES-Ereignisse

Die Ereignisse stellen meist Aktionen des Anwenders dar und werden mit den
Routinen des Moduls AESEvents berwacht. Es existiert die Mglichkeit, die
Ereignisse entweder einzeln oder zusammen  zu  berwachen.  Letzteres  ge~
schieht durch MultiEvent und wird meist benutzt. Dabei stehen die folgenden
Ereignisse zur Auswahl:

keyboard -- Das Tastatur-Ereignis tritt ein, sobald eine Taste gedrckt wird.
Als  Ergebnis  wird  sowohl  der  IBM-Scan-Code  der  Taste  als  auch  deren
ASCII-quivalent, falls vorhanden, geliefert (siehe GEMGlobals.GemChar).

mouseButton -- Ein Mausknopf-Ereignis tritt auf, sobald eine vorher bestimmte
Kombination  der  Maustasten  gedrckt  ist.  Die  Maske  bestimmt,  welche
Mauskpfe bercksichtigt werden sollen (Ist sie die leere Menge, so tritt das
Ereignis  auf  alle  Flle  ein).  Der  Status  bestimmt  nun,  welche  Knpfe  der
Maske  gedrckt  sein  mssen,  damit  das  Ereignis  auftritt.  Auerdem  kann
angegeben  werden,  auf  bis  zu  wie  viele  solche  sich  schnell  wiederholende
Zustnde  gewartet  werden  soll  (Anzahl  der  Mausklicks).  Die  minimale
Wiederholgeschwindigkeit  kann  mit  SetDClickSpeed  eingestellt  werden.  Als
Ergebnis liefert dieses Ereignis die Position der Maus, die zur Zeit gedrckten
Maustasten und Sondertasten der Tastatur und auerdem, wie oft der Zustand
der Maustasten eingetreten ist (Mausklicks).

firstRect, secondRect -- Ein Maus-Ereignis tritt auf, sobald sich der Mauszei~
ger innerhalb oder auerhalb eines bestimmten Rechteckbereichs befindet. Als
Ergebnis erhlt man die Position des Zeigers, die gedrckten Mausknpfe und
Sondertasten der Tastatur (Dies sind <Alternate>, <Control> und  die  beiden
<Shift>-Tasten).
5.7 Bibliothek: GEM                                                        5- 65
________________________________________________________


timer -- Das Zeitgeber-Ereignis erfllt zwei verschiedene Funktionen. Erstens
kann die Anwendung es dazu nutzen, nach einer  gewissen  Zeitspanne  eine
Meldung zu erhalten, und zweitens knnen damit andere Prozesse Rechenzeit
zugeteilt  bekommen.  Letzteres  nutzt  im  aktuellen  Betriebssystem  aber  nur
Accessories etwas.

message  --  Nachrichten-Ereignisse  dienen  zur  Kommunikation  mit  anderen
Prozessen, in der Regel dem AES oder einem Accessory. Ein solches Ereignis
fllt ein varianten Verbund vom Typ MessageBuffer, der im ersten Wort immer
die Art der Nachricht, im zweiten die Applikationsnummer des Senders und im
dritten die Anzahl der Bytes, die ber die 16 Standardbytes hinausgehen, ent~
hlt.

Der Bezeichner fr die Applikations-Identifikationsnummer endet immer auf Id
und der fr die ber 16 hinausgehenden Bytes auf Rmd (siehe MessageBuffer).

Es existieren folgende Nachrichtentypen:

unspecMessage  --  Bezeichnet  eine  nicht  vom  AES,  sondern  von  einer
beliebigen anderen Anwendung kommende Nachricht. In uMsgData steht  der
Anfang  der  Nachricht,  deren  Format  vom  Sender  abhngt.  Mglicherweise
folgen noch mehr als die 16 normalen Bytes, die dann mit AESMisc.ApplRead
gelesen werden mssen.

menuSelected -- Diese Nachricht wird gesendet, nachdem der Anwender einen
Eintrag in einem Menu angewhlt hat. In selTitle steht der Index des Titels, in
dem sich der Menupunkt befindet, und in selItem steht der Index des Eintrags.
Der Menutitel mu vom Programm mit AESMenus.NormalTitle wieder normal
dargestellt werden.

windRedraw  --  Diese  Nachricht  besagt,  da  ein  Fensterausschnitt  neu
gezeichnet werden mu (siehe auch Abschnitt ber Fenster). Dabei steht in
rdrwHdl die Kennung des Fensters, welches aktualisiert werden soll, und in
rdrwFrame der neu zu zeichnende Rechteckbereich.

windTopped  --  Eine  Nachricht  dieser  Art  zeigt  an,  da  ein  Fenster  vom
Anwender angeklickt wurde und es deshalb noch oben gebracht werden soll.
Dadurch  wird  es  aktiv,  das  heit,  seine  Randelemente  werden  dargestellt.
topHdl enthlt die Kennung des angewhlten Fensters.

windClosed -- Solch eine Nachricht wird gesendet, nachdem der Anwender auf
die Schliebox (links oben) eines Fensters geklickt hat. Daraufhin sollte das
Fenster mit der Kennung clsHdl geschlossen werden.

windFulled -- Diese Nachricht besagt, da die Vergrerungsbox (rechts oben)
des Fensters, mit der Kennung fullHdl, angeklickt wurde. Das Fenster sollte
nun in seiner Maximalgre dargestellt werden.
5.7 Bibliothek: GEM                                                        5- 66
________________________________________________________


windArrowed -- Es wird mitgeteilt, da der Benutzer auf einen Scroll-Pfeil
oder  einen  Schieber  geklickt  hat,  und  da  der  Inhalt  des  entsprechende
Fensters (arrwHdl) jetzt verschoben werden sollte, wie es arrwMode angibt.

windHSlid -- Besagt, da der Schieber des Fensters mit der Kennung hSldHdl
in  die  von  horPos  spezifizierte  Position  gebracht  wurde.  Der  Inhalt  des
Fensters sollte daraufhin entsprechend verndert werden. Die Positionsangabe
erfolgt in Promille (siehe auch  WSliderValue)  und  gilt  fr  den  horizontalen
Schieber.

windVSlid  --  Entspricht  windHSlid,  allerdings  ist  die  Angabe  nun  fr  den
vertikalen  Schieber  gedacht.  Die  Kennung  ist  vSldHdl  und  vertPos  ist  die
Position.

windSized -- Diese Nachricht wird gesendet, nachdem der Benutzer die Gre
eines  Fensters  verndert  hat.  In  sizeHdl  steht  die  Fensterkennung  und  in
sizeFrame  befinden  sich  die  neuen  Fensterausmae.  Zum  Zeitpunkt  dieser
Nachricht  hat  das  Fenster  noch  die  alte  Gre,  die  neue  mu  erst  noch
gesetzt werden.

windMoved  --  Zeigt  an,  da  das  Fenster,  welches  die  Kennung  moveHdl
besitzt, verschoben wurde. Die neue Position, die erst noch gesetzt werden
mu, steht in moveFrame.

windNewTop -- Solch eine Nachricht wird gesendet, nachdem das Fenster mit
der Kennung nwTpHdl nach oben gebracht wurde.

accOpen  --  Diese  Nachricht  erhlt  ein  Accessory,  nachdem  der  ihm
zugeordnete  Menutitel  angewhlt  wurde.  Die   Identifikationsnummer   des
Accessories wird in aOpnMId geliefert. aOpnVoid dient nur als Platzhalter.

accClose -- Hiermit wird einem Accessory mitgeteilt, da es vom Bildschirm
verschwinden mu. Dieser Fall kann eintreten, falls die laufende Anwendung
terminiert, der Bildschirm gelscht wird oder die AES-Fensterbibliothek  neu
initialisiert wird.


Mit Hilfe der AESMisc.ApplWrite-Routine kann einer Anwendung eine Nachricht
bermittelt werden. Damit diese korrekt ankommt, mu die Applikationsnummer
des Empfngers angegeben werden und dieser mu auf ein Nachrichtenereignis
warten. Die Applikationsnummer einer Anwendung kann mit Hilfe von AESMisc.
ApplFind ermittelt werden. Das  erste  Wort  der  Nachricht  sollte  den  Wert
unspecMessage besitzen, das zweite die Identifikationsnummer  des  Senders
und das dritte die  Lnge  der  Nachricht  minus  16  Byte,  falls  die  Gesamt~
nachricht lnger als 16 Byte ist.
5.7 Bibliothek: GEM                                                        5- 67
________________________________________________________


MEGA-GEM oder 'Eine Modula-Anpassung des GEM'

Die  vorliegende  GEM-Bibliothek  ist  nicht  einfach  eine  Konvertierung  der
bekannten  C-Vorlagen,  sondern  sie  pat  GEM  an  Modula  an  und  nicht
umgekehrt. Dies hat den Nachteil, da alte Programme nicht ganz so einfach
zu bernehmen sind, bietet dafr aber die Vorteile,

-- da  die  Programme  sehr  viel  bersichtlicher  werden,  da  erstens  die
    Namensgebung  aussagekrftiger  ist  und  zweitens  sinnvolle  Verbunde
    geschaffen wurden, so da die Prozeduren weniger Parameter besitzen und
    zum Beispiel bei der Beschreibung eines Punktes nicht mehr die x- und die
    y-Komponente  getrennt  deklariert  werden  mssen,  sondern  eine  einzige
    Variable vom Typ Point ausreicht;

-- da ein Programm, das whrend der Testphase abstrzt, ohne sich vorher
    beim GEM abzumelden, nicht gleich das gesamte System mit sich reit,
    sondern  die  erforderlichen  Abmeldungen  automatisch  von  der  Bibliothek
    ausgefhrt werden;

-- da der Benutzer sich  an  die  Programmierung  selbstdefinierter  Objekte
    oder Interruptvektoren wagen kann, ohne  erst  einmal  die  Innereien  des
    Rechners und die Funktionsweise des Mikroprozessors zu studieren;

-- da Fehler im Programm frhzeitig vom Laufzeitsystem erkannt werden,
    weil eine Variable den Bereich eines Aufzhlungstypen verlassen hat (was
    oft das Neubooten des Rechners erspart);

-- da die Programmierung einfach komfortabler geworden ist.

Wie oben erwhnt, wird bei der Terminierung eines Programmes, egal ob diese
gewollt  oder  ungewollt  ist,  dafr  gesorgt,  da  eventuell  noch  ausstehende
Abmeldungen  beim  GEM  durchgefhrt  werden.  Dies  beinhaltet  zum  Beispiel
auch, noch aktive Fenster zu schlieen und abzumelden oder den Mauszeiger
wieder sichtbar zu machen. Dabei werden nur solche Aktionen aufgehoben, die
unter der Modulkennung des terminierenden Moduls vorgenommen wurden. Da
es  aber  Modulen  gibt,  bei  denen  diese  automatische  Abmeldung  nicht
gewnscht  ist,  zum  Beispiel  residente  oder  Systemmodulen,  gibt  es  die
Mglichkeit, sich mit GEMEnv.SysInitGem anzumelden und damit eine Kennung
zu erhalten, die vor der Abmeldung geschtzt ist. Die An-  und  Abmeldung
geschieht in der Regel folgendermaen:
5.7 Bibliothek: GEM                                                        5- 68
________________________________________________________


IMPORT GEMEnv;
FROM GEMGlobals IMPORT RC;

VAR      dev      : GEMEnv.DeviceHandle;
         gemHdl  : GEMEnv.GemHandle;
         success : BOOLEAN;

BEGIN
     (*  Anmelden.  Gleichzeitig erhlt man in 'dev' die Gerte-
      *                 kennung fr eine virtuelle Arbeitsstation.
      *)

  GEMEnv.InitGem (RC, dev, success);
  IF success THEN (* Falls Anmeldung erfolgreich war, dann ...*)

                                     (* Eigene GEM-Kennung ermitteln *)

     gemHdl:=GEMEnv.CurrGemHandle ();
          .
          .                         (* Hauptprogramm ausfhren *)
          .
     GEMEnv.ExitGem (gemHdl); (* Abmelden *)

  ELSE

     (*  User mitteilen,
      *  da Anmeldung beim GEM
      *  nicht erfolgreich war.
      *)

  END;
END ... .


Der Aufruf von InitGem ersetzt die Einzelaufrufe zur Anmeldung beim AES
(appl init) und das  ffnen  einer  "virtual  workstion"  (v opnvwk)  beim  VDI.
     _                                                      _
Wenn  Sie  aber  keine  VDI-Funktionen  aufzurufen  haben  -  das  kommt
beispielsweise oft bei Accessories vor - knnen Sie mit GemEnv.InitApplication
nur die AES-Anmeldung durchfhren. Mit GemEnv.OpenDevice knnen Sie dann
immer noch nachtrglich das ffnen der des Bildschirms beim VDI nachholen.
Mehr dazu im Definitionstext von GemEnv.
5.7 Bibliothek: GEM                                                        5- 69
________________________________________________________


Zur Fehlerbehandlung ist folgendes zu sagen. Tritt zum Beispiel ein Fehler auf,
weil ein ARRAY OF CHAR bergeben wurde, das zu wenig Elemente enthlt, so
wird ein ganz normaler Laufzeitfehler  ausgelst,  in  diesem  Fall  ein  'String
Overflow'. Tritt der Fehler aber innerhalb einer ROM-Routine des GEM auf, so
meldet diese den Fehler in der Regel mit Hilfe eines INTEGER-Wertes. Dieser
Wert wird nicht direkt an das aufrufende Modul weitergeleitet, sondern der
Fehler  mu  von  diesem  durch  den  Aufruf  von  GEMEnv.GemError  erkannt
werden.  Ist  dies  geschehen,  so  kann  der  eigentliche  INTEGER-Wert  mit
GEMEnv.ErrorNumber  ermittelt  werden.  Tritt  ein  Fehler  auf,  der  nicht  mit
GemError abgefragt wird, so wird eine Fehlerroutine ausgefhrt. Nheres dazu
im Defintionsmodul GEMEnv (Anhang B).

Die Aufteilung der einzelnen Routinen auf die Module entspricht der logischen
Anordnung  innerhalb  des  GEM.  Lediglich  die  Routinen  des  "Application
Manager", des "File Selector Manager", des "Scrap Manager" und des "Shell
Manager" sind in AESMisc zusammengefat, da diese "Manager" sehr wenig
Routinen  enthalten.  Auerdem  befinden  sich  alle  Initialisierungsroutinen  in
GEMEnv. Die Namen sind normalerweise an die orginal C-Namen angelehnt, so
da sich ein GEM-gewohnter Programmierer innerhalb kurzer Zeit zurecht~
finden sollte.


Eine Stufe ber GEM

Ein Grund fr eine Benutzeroberflche nach Art des GEM ist wohl, da sich
der Programmierer einer Anwendung nicht mehr mit den Details der Ein- und
Ausgabe befassen mu. In diesem Bereich ist der Schu beim GEM ein wenig
nach hinten losgegangen. Der Programmautor mu zwar nicht unbedingt wissen
wieviele Pixel zur Laufzeit auf dem Bildschirm vorhanden sind, doch ist er oft
mit  der  Bedienung  des  GEM  so  beschftigt,  da  er  fr  sein  eigentliches
Problem kaum noch Zeit hat.

Um  diesen  Makel  ein  wenig  zu  beheben,  gibt  es  sieben  Module,  die  den
Umgang mit GEM ein wenig erleichtern sollen. Als erstes soll der ObjHandler
erwhnt werden. Dieses Modul ermglicht es, die Objektbume auf einer Ebene
zu  bearbeiten,  auf  der  es  nicht  ntig  ist,  genau  ber  die  Abbildung  der
Struktur im Speicher informiert zu sein. Es gengt, die einzelnen Objektbaum~
elemente  und  ihre  Funktion  zu  kennen.  Auch  die  Typwandlungen  und
-transformationen werden fr die einzelnen Variablen selbstndig durchgefhrt
(siehe auch Abschnitt ber Objektbume). Sozusagen als kleines Bonbon ist es
mit dem ObjHandler auch sehr einfach, die Mglichkeit der selbstdefinierbaren
GEM-Objekte zu nutzen.

Das zweite Modul heit EventHandler und nimmt dem Programmierer einen Teil
der  immer  wiederkehrenden  Tipparbeit  bei  der  Ereignisverwaltung  ab.  Es
werden fr jedes Ereignis einfach Prozeduren angemeldet, deren Verwaltung
vom EventHandler bernommen wird. Tritt nun ein Ereignis auf, so werden die
5.7 Bibliothek: GEM                                                        5- 70
________________________________________________________


zugehrigen Prozeduren mit den entsprechenden Parametern aufgerufen. Dabei
gibt es auch die Mglichkeit, Prozeduren anzumelden, die den Ereignisstrom
aller Module, die diese GEM-Bibliothek benutzen, berwachen und filtern knnen.

Des weiteren gibt es das Modul TextWindows, das, wie der Name schon sagt,
die Verwaltung von Textfenstern bernimmt. Ein solches Textfenster wird von
dem   Anwendungsprogramm   wie   ein   ganz   gewhnlicher   Textbildschirm
behandelt,  das  heit  die  Prozeduren  entsprechen  denen  von  Terminal.  Alle
Operationen, wie das Reagieren auf Mausoperationen des Anwenders und das
Neuzeichnen  des  Fensterinhaltes  werden  von  TextWindows  automatisch
durchgefhrt. Als kleines Extra ist es damit mglich, einzelne Zeichen vom
Benutzer mit Hilfe des Mauszeigers anwhlen zu lassen. So kann man z.B.
Textbereiche aus einem Fenster herausziehen lassen oder sie markieren.

Ein weiteres Modul trgt den Namen EasyGEM0 und enthlt eine Reihe von
Routinen, die bei der GEM-Programmierung des fteren gebraucht werden. Die
Programmierung von Dialogboxen wird durch Routinen untersttzt, die eine Box
darstellen,  einzelne  Objekte  animieren  und  die  Box  zum  Schlu  wieder
entfernen. Einfache Dialoge knnen sogar mit einem einzigen Prozeduraufruf
abgehandelt  werden.  Auerdem  gibt  es  Prozeduren,  die  die  Objekte  von
Dialogboxen mit Startwerten vorbelegen und die Ergebnisse auslesen.

EasyGEM1  stellt  Funktionen  zum  Verwalten  eines  Clipboards  und  einen
komfortablen Aufruf der Dateiauswahlbox (FileSelector) zur Verfgung.

Das Modul WindowBase dient zum Verwalten von Fenstern beliebigen Inhalts.
Das Verhalten und der  Inhalt  der  Fenster  wird  durch  eine  Reihe  von  frei
whlbaren  Prozedurvariablen  bestimmt.  Die  gesamte  Fensterverwaltung  ist
dabei  weitgehend  automatisiert  worden,  so  da  das  Programmieren  von
Fenstern mglichst einfach  und  ohne  zuviel  Programmieraufwand  geschehen
kann.  Dennoch  wurde  darauf  geachtet,  da  dem  Anwender  gegenber  den
AES-Fenstern mglichst keine Gestaltungsmglichkeiten verschlossen wurden.
Auch die Systemmodule WindowLists und TextWindows bauen auf WindowBase
auf.

WindowLists verwaltet Listen in einem Fenster, dies nutzt die  Modula-Shell
zum Beispiel fr ihre Directory-Fenster. Das  Modul  kann  immer  verwendet
werden,  wenn  eine  Liste  gleichartiger  Daten  zeilenweise  in  einem  Fenster
dargestellt werden soll, dabei wird jedem Datum eine Zeile zugeordnet.


Und ganz unten...

Wollen  Sie  selbst  AES-  oder  VDI-Funktionen  aufrufen,  entweder  weil  Sie
selbst die Kontrolle haben wollen oder weil eine neue GEM-Funktion in unserer
GEM-Bibliothek noch nicht zur Verfgung steht, benutzen Sie dazu das Modul
GEMBase (s. DEMO-Ordner: AESDemo & VDIDemo).
