Das neue ATARI-Jahr fängt sehr gut an. jedenfalls sehr viel besser als das Jahr für Windows 98. Zur Erinnerung: Windows 95 und DirectDraw-DLL ist derzeit Mindestausstattung für gängige Videospiele, Windows 95 ist zu RAM-hungrig für die gängigen Notebooks der 8-16 MB Klasse, und die Wartungsanforderungen an Windows 95 nähern sich langsam denen von UNIX. Die Fehler, die MS in Windows 95 gelassen hat, sollen Drittanbieter durch WinClean, DiskDoktor etc. aus-gleichen. Das bedeutet etwa 500 DM für ein lauffähiges Betriebssystem. Zudem soll nach dem Willen Gates wohl alle 2-3 Jahre ein Windows-Update erworben werden. Natürlich zuzüglich aller nun inkompatibler Systemtools zur Fehlerausbesserung. Wenn Sie also mit dem Gedanken spielen, sich einen PC zur Nutzung aller neuen 3-D-Videospiele zuzulegen, dann brauchen Sie Windows 95, eine 3-D-beschleunigte Videokarte und etwa alle 2 Jahre ein komplettes neues System, weil Prozessor, Systembus, RAM, CD-ROM und Videokarte dann zu langsam für die neuen Spiele sind, denn am besten verkaufen sich eben die Spiele mit der besten Grafik.
ATARI-Besitzer stehen außerhalb dieses Problems der Systemveraltung, denn maximale Hardware-Anforderung der Software ist immer noch der Falcon. Ein Milan würde also auf einen Schlag alle Leistungsbedürfnisse lösen, weil kein Softwarehesteller einen schnelleren Rechner voraussetzt.
Es lohnt sich somit mehr denn je, für ATARI zu entwickeln. Wir werden also im Object C Kurs fortfahren, mit dem geringstem Aufwand die beste Software zu entwickeln, die dann bei Bedarf auch kompatibel zu Windows 95, OS/2, MacOS und sogar Windows 3.x ist, unabhängig davon, ob Herr Gates nun noch etwas von Windows 3.x wissen will oder nicht. Ich meine, die Besitzer von 486er oder 8-16 MB Notebooks werden ihre Rechner nicht wegwerfen, nur weil Windows 95 zu viel RAM und Rechenleistung verschlingt. Möglicherweise werden viele auch LINUX auf ihren "veralteten“ Systemen installieren. Egal, wie die Entscheidung auch aussehen mag, unsere Object C Programme laufen auf praktisch allen Systemen, und zwar ohne Java und somit prozessoroptimiert und in Echtzeit.
Ich hatte zwar gehofft, in dieser Ausgabe einen ersten Screen-Shot eines mit OCC erstellten GEM-Windows aus der CPR Entwicklungsabteilung zu erhalten, aber es gab neue Schwierigkeiten mit Sozobon C. Genau genommen machte Sozobon C Probleme mit umfangreichem C-Precompiler Output und mit Funktionsnamen über 24 Zeichen Länge. Die gute Nachricht dabei ist: Diese Probleme wurden gelöst, und wir werden nicht erst auf Object C 3.0 warten müssen, um in den Genuß von "Incremental Compiling" zu kommen, sondern werden anschließend an die Portierung der GUI-Bibliothek noch vor anderen Betriebssystemen gleich den passenden Object C Compiler OC 2.7 für ATARI erhalten. Object C 2.5 samt HTML-Dokumentation wurde bereits seit einiger Zeit zum "Seidel Softwareservice" geschickt und reicht für Studio-Programme und normale GEM-Programme ohne OCC völlig aus. Dort sollte es also inzwischen eine entsprechende Entwickler-CD mit Sozobon C und Object C geben.
Bitte verwechseln Sie "Incremental Compiling" (IC) nicht mit "Incremental Linking" (IL), denn IL reduziert nur die Linkzeit, während IC versucht, die Anzahl zu übersetzender C-Dateien zu verringern. Weil IC nicht ganz trivial ist, wird es derzeit praktisch nur vom 900,- DM teuren Visual C++ >= v.3.0 angeboten. Durch Object C kann jetzt jeder C-Compiler von IC profitieren, vorausgesetzt, man programmiert in der Sprache Object C. Ein einfaches Beispiel: Nehmen wir an, ein neues Attribut wird für eine Ihrer Klassen benötigt. Bei C++ müßten Sie jetzt alle Quelldateien neu übersetzen, was insbesondere bei Verwendung von Optimizer oder Debugging-Optionen sehr zeitaufwendig ist. Durch das IC des neuen Object C Compilers werden nun aber nur die Dateien übersetzt, die diese Klasse verwenden. Hierdurch kann die Gesamtübersetzungszeit also durchaus um den Faktor 10 verbessert werden, und der Output des Sozobon C-Precompilers verringert sich um etwa 70% auf ein für Sozobon C verträgliches Niveau.
Weil die GUI-Bibliothek OCC noch nicht für ATARI verfügbar ist, die Grundlagen über Object C aber nun doch ziemlich gut gefestigt sein sollten, ist es an der Zeit, praktische Erfahrung zu sammeln und Wissenslücken zu füllen. Natürlich möchte jeder sofort ein OCC-kompatibles GEM-Programm entwickeln, wir wollen uns aber vorerst auf die Programme beschränken, die jeder daheim übersetzen kann. Unabhängig davon ist es ohnehin besser, die Funktionalität eines Programmes etwas von der Benutzeroberfläche zu trennen, um etwa Automatisierungen von Arbeitsabläufen besser vornehmen zu können. Eine kleine Ad ress Verwaltung zu entwickein, scheint für unser Vorhaben sehr geeignet zu sein, denn wir können große Teile des Programmes später in unserem OCC-Programm verwenden. (Siehe Listing 1)
Programmstart durch "ADR_MAIN.M"
/* Datei: adr_main.m */
#include <adr.h>
static Ok start_(int arge, char **argv);
static Ok start_(int arge, char **argv)
{
Obj o_globals = $new(Globals);
$$MainLoop(o_globals, argc, argv);
$free(o_globals);
DONE ;
}
void main(int argc, char **argv);
void main(int argc, char **argv)
(
if (obj_initall_())
{
start_(argc, argv); obj_uninitall_() ;
}
)
Damit wir die Initialisierungen erst einmal erledigt haben, sollte uns die Datei "adr_main.m" gute Dienste leisten. Unser Programm wird nicht besonders groß werden, eine ".i"-Datei "adr.i" sollte uns also genügen. Wir laden also die vom Object C Compiler erzeugte Datei "adr.h". Um unsere Methodendateien kleiner zu halten, laden wir <obj.h> und <d_adr.h> innerhalb ''adr.h'1. Die main-Funktion initialisiert unsere Object C Lauftzeitbibliothek und beginnt unser Programm mit der Funktion "start_()". Leider können wir den Inhalt der sta«^Funktion nicht direkt in die main-Funktion einsetzen, weil alle Object C Sprachbestandteile eine Funktion im Fehlerfall durch "return (FA);" verlassen, was bedeutet, wir können Object C Bestandteile nur in Funktionen des Rückgabetyps "Ok" anwenden. Damit sich diese Ok-Funktionen schon vom Namen her von normalen Funktionen abheben, verwenden wir per Konvention am Ende des Namens einen Unterstrich Unser eigentliches Object C Programm beginnt also in unserer Haupt-Eingabeschleife "MainLoop". Zur Verwaltung globaler Programmdaten erzeugen wir ein Objekt der Klasse "Globals" und geben es am Programmende wieder frei. Wie ferner zu sehen ist, wird eine sog. Ok-Funktion am Ende durch "DONE;" verlassen, was auf return (TR); abgebildet wird. (Siehe Listing 2)
Damit der Object C Compiler eine Datei "adr.h" erzeugen kann und unsere Klassen
"Globals" und "File" kennt, müssen wir natürlich eine entsprechende Datei "adr.i" implementieren. Hier laden wir zunächst die Object C Typ- und Sprach-Definitionen mit #include <obj.h>. Die Datei "d_adr.h" wird alle automatisch vom Object C Comp-ler erzeugten Deklarationen unseres Programmes enthalten und wird zum Schluß geladen. Wir wollen für unser Programm genau ein Objekt der Klasse Globals verwenden, in das wir alle zentralen Daten eintragen. Damit wir problemlos auf diese Daten zugreifen können, deklarieren wir die Variable des Objekthandles (o_glo) und den Objektdatenzeiger (op_glo). Wir können dann beispielsweise durch op_glo->l_addresses auf die Liste der Address-Ob-jekte zugreifen und ’o_glo’ für alle Methoden einsetzen, die ein Objekt der Klasse Globals als Zielobjekt erfordern. Manche unserer Methoden wie $$lnput() benötigen zumindest in der hier vorgestellten ersten Ausbaustufe eigentlich keine Daten aus irgend einem speziellen Objekt, wir übergeben in diesen Fällen einfach o_glo. Ein besserer Stil wäre es natürlich, ein spezielles Objekt o_null der Klasse Null für solche Fälle bereitzustellen. (Siehe Listing 3)
Entsprechend einem normalen C-Programm ist die Methode $$MainLoop() unsere Haupteingabeschleife. Die Methode $$lnput() liefert uns eine Eingabezeichenkette von der Tastatur.
(Siehe Listing 4)
Unser Programm wird in weiteren Ausbaustufen noch mehr Daten im Objekt ’o_glo’ verwalten, wir verwenden also besser eine eigene Datei für den Konstruktor der Klasse Globals. Die Liste ’l_ad-dresses' soll später Objekte der Klasse Address verwalten. ’o_file’ ist die gerade verwendete Adressdatei. (Siehe Listing 5)
Zur Bereitstellung des Dateizugriffes verwenden wir die bas___-Funktionen der Object C Laufzeitbibliothek, wir müssen uns dann nicht mit irgendwelchen Problemen zwischen den Betriebssystemen beschäftigen. Der ’hdl' soll immer dann gültig sein, wenn die Datei des Namens ’name’ geöffnet ist.
Der Grundstock für unser Programm ist jetzt gelegt, in der nächsten Ausbaustufe werden wir dann etwas mehr von den OOP-Vorteilen profitieren.
Listing 2
Klassenbeschreibungen "ADR.I"
/* Datei: adr.i */
#include <obj.h>
$classes Globals, File
$
$dat Globals
List l_addresses;
Obj o_file;
$
$dat File
char name[32];
Hdl hdl;
$
extern Obj o_glo;
extern $ptype(Globals) op_glo;
#include <d_adr.h>
Listing 3
Haupt-Eingabeschleife ”ADR_LOOP.M
/* Datei: adr_loop.m */
#include <adr.h>
#include <stdlib.h>
#include <stdio.h>
$meth MainLoop (Obj obj, int argc, char** argv)
$support(Globals);
$call(obj);
$class Globals
char inp[128];
printf("Welcome to Adress-Manager 1.0!\n\nEnter 'help' for a list of commands.\n\n\n");
do
{
$$Input(obj, inp);
if (EQU(inp, "help") || EQU(inp, "?")) printf("Commands: help/?, quit/exit, info, query, del, new, load, save\n");
if (EQU(inp, "info")) $$DoInfo(obj);
if (EQU(inp, "query")) $$DoQuery(obj);
if (EQU(inp, "load")) $$DoLoad(obj);
if (EQU(inp, "save")) $$DoSave(obj);
if (EQU(inp, "del")) $$DoDel(obj);
if (EQU(inp, "new")) $$DoNew(obj);
} while (!(EQU(inp, "quit") || EQU(inp, "exit")))
$
$meth Input (Obj obj, char* inp)
$support(Globals);
*inp = 0;
if (gets(inp))
{
int len;
/* behebe einen Fehler von Sozobon-gets() */
len = LEN(inp);
if (len > 0)
if (inp[len - 1] < (char)32)
inp[len - 1] - 0;
if (--len > 0)
if (inp [len - 1] < (char)32)
inp[len - 1] =0;
}
$
Listing 4
Globale Variablen "ADR_GLO.M'
/* Datei: adr_glo.m */
Obj oglo;
$ptype(Globals) op glo;
$new Globals ()
o_glo = obj;
op_glo = objp;
..o_file = $new(File);
$newlist(&..l addresses);
$clone
$serr("not supported!");
$free
$free(..o_file);
$freeobjs(..l_addresses);
$freelist(..l_addresses);
$
Listing 5
Dateizugriff "ADR_FILE.M"
/* Datei: adr_file.m */
$new File ()
CLR(..name);
..hdl = 0;
$clone ..hdl = 0;
$f ree if (..hdl) bas___close(..hdl);
?
$meth Open (Obj obj, Bool write, char** name, Bool * success)
$Support(File);
if (LEN(name) >31 ||!*name)
$serr("illegal name!");
*success = TR;
$call(obj);
$class File if (write)
{
if (Ibas___create(name, 0L, 0L, 0))