PofoWiki

Die ultimative Informationsquelle zum ATARI Portfolio

Benutzer-Werkzeuge

Webseiten-Werkzeuge


software:diy:pascal:pascalk

Pascal Programmierkurs

von Torsten Häßer

Teil 1

Vorweg

Als ich vor gut einem halben Jahr meinen Portfolio (im weiteren Verlauf liebevoll Pofi genannt) bekommen habe, war eine der tollsten Dinge an dem kleinen Kasten, daß man nicht nur auf die internen Anwendungen beschränkt war. Nach der ersten RAM-Karte und den ersten Quellen für Pofisoft machte sich dann aber schnell der Wunsch breit, daß man das, was man nicht bekommen konnte ebend selbst schreibt.

Gesagt, getan. Ich war natürlich der Meinung, PC bleibt PC und Programme die für den PC geschrieben sind laufen auch auf dem Pofi. Einschränkungen ergeben sich daher nur aus der Größe des Bildschirms und der Größe der Programme. Was lag da also näher als die Programmiersprache zu benutzen, in der ich auch sonst meinen Unsinn produziere.

Ich suchte also eines meiner alten Listings heraus und feilte ein bißchen an der Bilschirmausgabe herum, um diese dann auf den Pofi zu übertragen. Die Überraschung war nicht schlecht als ich dezent vom Transferprogramm darauf hingewiesen wurde, daß zu wenig Platz auf dem Pofi ist. Wenn man sich einmal den Dimensionssprung vor Augen führt, mit dem wir es hier zu tun haben ist das auch wenig verwunderlich. Unser kleiner Liebling hat nun einmal von Haus aus keine Festplatte und nur 640 KB RAM. Programme, die man vorher für relativ klein gehalten hat, sind aus der Sicht des Pofi regelrechte Speicherriesen.

Nachdem ich also etwas Platz geschaffen hatte, paßte es dann doch noch auf die RAM-Karte. Start … BUM. Ich mußte dann erstmal für eine geraume Zeit die Batterien entfernen, um den Pofi wieder zu beleben ( ein wirklich zäher kleiner Bursche, wenn es darum geht Daten im RAM zu halten ).

Resümee dieser Aktion : Einfache Portierung der Programme ist anscheinend nicht möglich. Na gut. Ich war allerdings dickköpfig genug, um mich nicht so leicht von meinem Vorhaben abbringen zu lassen. Es hat mich dann viel Mühe gekostet an einigermaßen brauchbare Unterlagen zu kommen, die mir bei diesem Problem behilflich sein konnten. Darum geht es also in diesem(n) Artikel(n). Kein Programmierkurs in Pascal. Dafür gibt es genügend andere und bessere Literatur (siehe Anhang). Es geht darum, wie ich Anwendungen schreibe die speziell auf den Portfolio zugeschnitten sind und trotzdem mit einer PC-Hochsprache compiliert werden.

Die ersten Schritte

Grundsätzlich müssen Pascal-Programme für den Pofi also vor allem immer mit dem vorhandenen Speicherplatz vor Augen geschrieben werden. Pascal selber geht bei der Übersetzung des Codes nicht gerade sparsam damit um. Debug-Informationen, Prüfcodes etc., die den Speicherplatz brauchen sind aber für unsere Zwecke sowieso nicht sinnvoll. Denn was nützen mir Daten die der Debugger braucht, wenn ich die Programme ja sowieso nicht auf dem Pofi debugge. Prüfcodes wie etwa Range-Checking und Stack-Checking verbrauchen sehr viel Speicherplatz. Wenn man auf diese Sachen verzichtet, dann läßt sich damit eine Menge Platz sparen und macht unsere Programme damit sehr viel freundlicher für unseren Kleinen. Es ist wirklich erstaunlich, was sich durch geeignete Einstellungen sparen läßt. Wieviel das ausmacht kann man allerdings nicht genau sagen, weil dies natürlich auch auf die Art der Programme bzw. auf die verwendeten Funktionen ankommt.

Ein kleines Beispiel :

PROGRAM DISK_WRITE;
VAR f : TEXT;
BEGIN
	ASSIGN ( f, 'DWRITE.DAT' );
	REWRITE ( f );
	WRITELN ( f, 'Hello World ...' );
	CLOSE ( f );
END.

Dieses Programm ist, wenn man es mit den Voreinstellungen von Pascal compiliert tatsächlich 3,55 KB groß. Nimmt man jetzt alle unnützen Optionen raus ( vor allem natürlich die Option I/O-Checking ), dann kommt man nur noch auf 1,85 KB.

Ich hoffe, das war beeindruckend.

Um die Freude aber wieder ein wenig zu dämpfen :

Grundsätzlich muß man natürlich wissen, daß Programme die man in einer Hochsprache schreibt übersetzt immer recht groß sein werden. Man hat ebend als Programmierer keinen bzw. nur geringen Einfluß darauf, wie der Compiler den Code übersetzt und was er alles dort rein schreibt. Deshalb lohnt sich die Verwendung einer Hochsprache generell nur dann, wenn man recht umfangreiche und komplexe Applikationen schreiben will. Für kleine Tools und Systemprogramme werden die kleinen Basic-Dialekte für den Pofi sicherlich immer geeigneter sein. Es sei denn, man ist ein Bit-Hexer und beherrscht die hohe Kunst der Assemblerprogrammierung … :o)

Ok. Wir wollen also ein umfangreiches Programm verfassen und wir wollen auch die netten und übersichtlichen Strukturen eines Hochsprachenquelltextes nicht vermissen. Was kommen dabei also für Probleme auf uns zu.

Natürlich gibt es ein paar entscheidende Unterschiede zwischen einem normalen PC und dem Pofi. Zum Ansprechen der Hardware sollte man zum Beispiel lieber die Portfolio eigenen BIOS-Serviceroutinen verwenden. Direkte Zugriffe scheitern meist daran, daß die dafür nötigen Adressen ebend nicht kompatibel sind. Teilweise sind auch nicht alle BIOS-Routinen die beim PC bekannt sind im Pofi-BIOS wieder zu finden. Wieder andere Funktionen sind nur für unseren Kleinen extra eingeführt worden. Spezielle bzw. modifizierte Routinen sind zum Beispiel für das Handling der RAM-Karten hinzugekommen. Das hört sich natürlich jetzt an als gäbe es fast nichts, daß man benutzen kann. Die DIP Leute haben das BIOS aber trotzdem so gestaltet, daß alle Programme ( und dazu zählen auch unsere Pascal-Units ) die „sauber“ programmiert sind, sich auch auf unserem Kleinen wohl fühlen. Trotzdem … Was hat das nun für Folgen für unsere Pascal-Programmierung.

Die Units

Tataaaa … Der nächste Hammer. Die Pascal-CRT-Unit kann man leider nicht verwenden. Sie ist verantwortlich für den massiven Absturz, den ich in der Einleitung beschrieben habe. Anscheinend wird hier doch näher an der Hardware gearbeitet als es von außen scheint. Es gibt aber wohl kaum ein DOS-Programm, wenn nicht sogar keines, das nicht Funktionen daraus benötigt. Durch den Wegfall dieser Unit fehlen uns so wichtige Sachen wie Bildschirmlöschen, das Setzen des Cursors, Tastendrücke holen usw. Was bleibt uns also anderes übrig als … selber schreiben !!!

„Oh Gott … was kommt jetzt …“. Grundsätzlich hört sich das natürlich schlimmer an als es ist. Sehen wir uns erst einmal an, was das für Funktionen sind.

CRT.TPU Funktionen und Prozeduren

AssignCrt         	ClrEol
ClrScr            	Delay
DelLine           	GotoXY
HighVideo         	InsLine
KeyPressed        	LowVideo
NormVideo         	NoSound
ReadKey           	Sound
TextBackground 	TextColor
TextMode          	WhereX
WhereY            	Window

Verschiedene Funktionen können wir schon mal ausschließen, da sie auf dem Pofi keinen Wert haben. Wozu brauche ich Routinen zur Änderung der Textfarbe, wenn ich nur ein S/W-LCD-Display habe? Also, was bleibt übrig:

ClrEol		ClrScr		Delay
DelLine		GotoXY		InsLine
KeyPressed	ReadKey		Sound
TextMode	WhereX		WhereY
Window

Ich muß dazu noch bemerken, daß ich die Funktionen ClrEol, InsLine, DelLine und Window in meiner Version der Portfolio-CRT-Unit nicht implementiert habe. Das liegt am einen daran, daß ich diese Funktionen äußerst selten verwende und ich weiterhin zugeben muß, daß die Programmierung der Window-Routine doch einen mittleren Aufwand bedeutet.

Vielleicht werde ich diese Sachen aber zu einem späteren Zeitpunkt noch mit einbauen. Wenn sich aber Leute damit schon beschäftigt haben und eine einigermaßen gute und stabile Lösung darbieten können, wäre ich natürlich dankbar, wenn ich mir diese Mühe sparen könnte … :o)

Wichtig bei der ganzen Sache ist für uns natürlich auch, daß die neuen Funktionen weitgehend aufrufkompatibel zu den gewohnten bleiben. Wir wollen ja schließlich keine neuen Befehle lernen, sondern in gewohnter Weise weiter machen können. Ich hab mich also mal daran gemacht und aus verschiedenen Quellen diese Sachen zusammen gesucht1).

Ich will jetzt auch gar nicht so intensiv darauf eingehen wie die einzelnen Routinen programmiert sind. Viel wichtiger sind hier ein paar grundsätzliche Sachen, die speziell für die Arbeit mit dem Pofi wichtig sind.

Auffallend für Leute, die sich schon einmal näher mit den DOS-Interrupts beschäftigt haben, ist sicherlich, daß beim Pofi der Interrupt $61 eine wichtige Rolle spielt. Wie weiter oben im Text schon erwähnt, fehlen im Pofi-BIOS einige Funktionen. Diesen Mißstand versuchen wir nun mit Hilfe der speziellen Pofi-Funktionen im Int $61 auszugleichen. Die Interrupts $60 ( dieser wird uns im zweiten Teil noch intensiv beschäftigen ) und $61 sind im PC-BIOS unbelegt. Dadurch wird deutlich, daß es ungemein schwierig und aufwendig wird, ein Programm zu schreiben, daß sowohl auf dem Pofi als auch auf dem PC läuft. Leider wird es uns aber kaum erspart bleiben diese Funktionen zu benutzen. Wenn ich also kompatibel programmieren will, dann muß ich alles doppelt schreiben. Andererseits bietet sich hier auch die Möglichkeit an, PC-User davor zu bewahren, unsere Pofi-Programme aus Versehen auf ihrem Rechner zu starten. Sollte der Int $61 also auf 0000:0000 zeigen, dann ist das ein relativ sicheres Zeichen, daß unser Programm keinen Pofi vor sich hat. Sicherheitslücken gibt es natürlich immer. Sollte ein PC-Programm also diesen Interrupt benutzen, dann sehen wir schon wieder alt aus.

Zurück zum eigentlichen Thema. Der Pofi hat bekanntlich drei Textmodi. Unser Pofi beherrscht neben seinem eigenen 40×8 Modus auch noch den zum PC kompatiblen 80×25 Modus. Beim 80×25 Modus wird nun noch zwischen statisch und dynamisch unterschieden. Da der Pofi allerdings nur ein Display von 40×8 Zeichen hat, wirkt in diesem Modus das Display wie eine Art Fenster, das man dann über den eigentlichen Bildschirm von 80×25 Zeichen bewegen muß. Die Umschaltung zwischen diesen Betriebsarten erfolgt nun mit Hilfe der Funktion $0E des Interrupt $61. Die Abfrage des aktuellen Modus wird auch über diese Funktion erledigt. So schön wie der 80×25 Modus vielleicht auch sein mag, aber es ist doch sehr lästig, ständig den gerade sichtbaren Bereich verschieben zu müssen, um alles auf dem Bildschirm verfolgen zu können. Ich empfehle deshalb immer den 40×8 Modus zu benutzen. Eine zweite Besonderheit ist in diesem Zusammenhang auch sicherlich die Tatsache, daß das LCD-Display keine Attribute darstellen kann. Das heißt, daß ich nicht die Möglichkeit habe einen Text zum Beispiel invertiert darzustellen. Aus diesem Grund fallen ja auch ein paar der Funktionen der CRT-Unit für uns weg. Es zeigt aber auch, daß wir uns andere Mittel und Wege suchen müssen, um Menüs und Auswahlbalken zu verwalten und für den Benutzer kenntlich zu machen.

Als weiteren wichtigen Punkt müssen wir uns mit den Routinen KeyPressed und ReadKey beschäftigen. Es gibt drei Funktionen die uns vom BIOS zur Kommuni- kation mit der Tastatur zur Verfügung gestellt werden. Diese Funktionen werden nun über den Interrupt $16 aufgerufen. Wichtig ist nun der Unterschied zwischen den Funktionen $00 und $01. Die Funktion $00 liest ein Zeichen aus dem Tastaturpuffer und falls kein Zeichen vorhanden sein sollte, wird so lange gewartet, bis ein Zeichen vorliegt. Die Funktion $01 hingegen prüft lediglich, ob ein Zeichen im Puffer vorhanden ist und gibt den Wert des Zeichens zurück, ohne es zu löschen. Um das Zeichen zu löschen muß also ein weiteres mal die Funktion $00 aufgerufen werden. So, wo ist nun das Problem dabei? Beim Aufruf von $00 wird ein Timer gestartet, der nach Ablauf einer bestimmten Zeit die berühmte Power-Down-Sequenz einleitet. Mit dieser Selbstabschaltung wird ein nicht unerheblicher Stromspar-Effekt erzielt. Das ist ja genau genommen auch erwünscht. Leider ist es in diesem Stromsparmodus nicht mehr möglich auf eventuelle Hardware-Interrupts der seriellen Schnittstelle zu reagieren. Wenn ich in meinen Programmen also darauf angewiesen bin, bleibt mir nichts anderes übrig, als mir eine eigene Routine zu schreiben, die die Funktion $01 verwendet. Denn hierbei wird die Kontrolle gerade nicht an das BIOS übergeben. Die in der Unit implementierten Funktionen ReadKey und KeyPressed verwenden nun beide die Funktion $01. Dadurch wird aber wie gesagt der Power-Down verhindert, und wenn ein Programm nun lange auf eine Eingabe des Benutzers wartet, dann schaltet sich der Rechner nicht ab. Wem das nicht paßt, sollte diese beiden Funktionen unter Verwendung der $00 Funktion programmieren. Man kann natürlich beide Versionen in die Unit aufnehmen, was allerdings im Wiederspruch zur Maßgabe steht, da diese dann kompatibel zur Orginal CRT-Unit sind.

Soviel also zu diesem Thema. Das soll aber anderweitig noch mal behandelt werden. Abschließend noch ein paar kurze Worte zu den Routinen Sound und Delay. Die Sound-Funktion wird vom Pofi sehr komfortabel über den Interrut $61 ( was auch sonst ) angesprochen. Sie ist nicht aufrufkompatibel, bietet dafür aber auch eine sehr viel bessere Möglichkeit, Sounds auf dem Pofi zu erzeugen. Die Funktion ist aus einer CRT-Unit entnommen, die ich in einem Buch gefunden habe, das sich speziell mit der Programmierung unseres Kleinen auseinandersetzt. Wer irgendwie eine Möglichkeit hat, an dieses Buch heranzukommen, dem möchte ich es wärmstens empfehlen ( alle Quellenangaben sind im Anhang vermerkt ).

Die Delay-Prozedur ist eigentlich nur eine Zählerschleife und deshalb für genaue Zeitmessungen oder Ähnliches vollkommen ungeeignet. Die Werte für die Anzahl der Durchläufe sind reine Erfahrungswerte. Ich halte aber auch mehr Aufwand für nicht nötig, weil mir bisher noch kein Programm eingefallen ist, bei dem es auf einen unheimlich genauen Zeittakt ankommen würde.

So, das war also eine kleine Zusammenfassung der Schwierigkeiten und vor allem auch der Lösungsansätze einiger Probleme. Ich denke, daß nun eine Grundlage geschaffen sein sollte, um endlich auch Programme in Pascal für den Pofi zu stricken. Es gibt natürlich noch hunderte von Details über die Besonderheiten des Pofi zu sagen. Das hat allerdings nicht speziell etwas mit der Pascalprogrammierung zu tun und eignet sich deshalb bestimmt gut als eine Art Grundlagenartikel. Ich will aber diesen Text jetzt nicht einfach so enden lassen. Geplant ist eigentlich so etwas wie ein Kurs. Was soll also voraussichtlich noch unser Thema sein? Vor allem die speziellen Funktion die uns das BIOS noch so zur Verfügung stellt. Für die Insider seien hier nur kurz die PofiMenüs erwähnt, wie sie von den internen Applikationen her bekannt sind.

Ich will mich hier allerdings nicht festlegen. Ich habe diesen Artikel jetzt in den letzten drei Tagen verbrochen. Es gibt also bestimmt noch viele ungeklärte Fragen und auch Verbesserungsvorschläge. Ich bin für Unterstützung, Anregungen und Meckereien sehr dankbar. Also, auf gehts. Auf daß eine wahre Flut an neuen Pofiprogrammen unserem Kleinen nie die Luft ausgehen lassen.

Teil 2

Das AES

Man kann sagen was man will. Aber die Firma ATARI hatte in Ihrer Glanzzeit immer einen Riecher für Sachen, die ihrer Zeit eigentlich weit voraus waren. So wie die ATARI-ST Serie vom Betriebssystem her den damaligen PC's überlegen war, genau so ist das Portfolio-DOS dem damaligen PC-DOS in einem Punkt überlegen. Den Leuten, die schon mal auf anderen Plattformen wie Amiga, Mac oder eben ST's programmiert haben wird der Begriff „AES“ sicherlich etwas sagen.

AES steht für „Application Environment System/Service“. So ein AES stellt dem Programmierer ein Reihe von Routinen zur Verfügung um Menüs, Fenster etc. zu verwalten. Man kann die Verwaltung und Darstellung dieser Dinge ruhig dem Betriebssystem überlassen und kann sich besser auf die eigentliche Aufgabe des zu schreibenden Programms konzentrieren. Nimmt man als Beispiel ein Auswahlmenü, würde der Programmierer das Betriebssytem nur wissen lassen, welche Menüpunkte enthalten sein sollen und gegebenenfalls noch die Position des Menüs. Das Betriebssystem bzw. das AES übernimmt dann die Kontrolle und meldet dem Programm nur zurück, welchen Menüpunkt der User nun ausgewählt hat. Ein weiterer entscheidender Vorteil, den die Nutzung des AES mit sich bringt ist, daß Programme, die es benutzen, alle eine einheitliche Benutzerführung haben. Menübedienung und Aussehen der Menüs sind immer gleich, und der User weiß sofort, wie er es bedienen muß. Noch ein Vorteil ist, daß man es eben nicht selber schreiben muß. Somit wird der Programmkode kürzer und verbraucht weniger Speicherplatz. Was hat das aber mit unserem Pofi zu tun? Die Programmierer von DIP haben ihrem kleinen Schützling nämlich so ein AES mit gegeben. Dieser Teil des Kurses hat nun die Funktionen des AES zum Thema. Natürlich bietet das Portfolio-AES nicht die Möglichkeiten und den Umfang der Fenster- und Menüverwaltung den man von anderen grafischen Benutzerführungen kennt. Aber warten wir mal ab …

Wir kennen alle die Benutzerführung die die internen Anwendungen des Pofi bieten. Die Menüs, die Fenster und die Hinweisboxen. So etwas in eigenen Programmen zu realiesieren ist gar nicht so schwierig. Das Portfolio-AES stellt uns alles Notwendige zur Verfügung. Die Funktionen des AES sind alle durch den Interrupt $60 zu erreichen.

Zuerst aber mal eine kleine Auflistung :

Fn $00 Get version number (of ROMs)
Fn $01 Line Editor
Fn $02 Get current application
Fn $03 Reserved for custom add-ins 	( Funktionen für die Hook-Files, die vom Texteditor aufgerufen werden können )
Fn $08 Screen Save/Restore
Fn $09 Draw box
Fn $0F Menu handling
Fn $10 Box area calculation
Fn $12 Message windows
Fn $14 Error windows

Das ist also unser Werkzeug. Die Funktionen Fn $00 - Fn $03 sind allerdings nicht Thema in diesem Teil des Kurses. Interressant sind hier ohnehin nur der „Line Editor“ und die Funktion, die uns die ROM Versionsnummer verrät. Um ehrlich zu sein, habe ich mich mit dem „Line Editor“ noch nicht so richtig beschäftigt. Das ist der Grund, daß diese Routine noch nicht implementiert ist, und ich sie deshalb noch nicht besprechen kann. Fn $02 und Fn $03 sind für Leute, die Hook-Files schreiben. Von Hook-Files habe ich aber leider auch noch keine Ahnung. Auf jeden Fall sind sie keine „normalen“ Programme wie man sie in Pascal verfassen könnte. Also auch dazu in einem eventuell anderen Teil des Kurses mehr. Nun aber zu dem, was fertig ist. Ich habe die Routinen als Pascal-Unit unter dem Namen PortAES zusammengefaßt. Hier nun eine Beschreibung der Funktion an sich, was sie für Parameter brauchen und wie man sie aus Pascal heraus benutzt.

1.0 Fn $08 Screen Save/Restore

Diese Funktion gibt uns die Möglichkeit, einen Bildschirmbereich zu sichern und ihn auch wieder herzustellen. Im Klartext bedeutet das, daß man eine Kopie des zu sichernden Bereichs in einer Variablen speichert, und sie aus dieser heraus dann auch wieder auf den Bildschirm kopieren kann. Wie natürlich bei allen anderen Routinen müssen vor dem Aufruf noch einige Register gesetzt werden. Durch diese Funktion sind vier verschiedene Subservices realiesier: nur die Characters werden gespeichert, Characters und die gesetzen Attribute werden gespeichert, und das gleiche nochmal für das Zurückschreiben des Pufferinhaltes. Es ist allerdings so, daß das Speichern mit Attributen eigentlich keinen großen Sinn macht, da das LCD-Display des Pofi keine Attributinformationen verarbeitet. Also wären auch nur der Subservice $00 (Save Characters only) und $02 (Restore characters only) von Bedeutung. Als weiteren Parameter braucht die Routine natürlich noch Koordinaten, wo der Bereich liegt, der gesichert werden soll. Die Art der Koordinaten ist die selbe, wie ich sie auch benutze um mit dem GotoXY-Befehl den Cursor auf dem Bildschirm zu platzieren. Die linke-obere Ecke ist also XY(0,0) und die untere-rechte Ecke bei einer „normalen“ Portfolioauflösung XY(39,7). Der letzte und wichtigste Parameter ist die Adresse des Speicherbereichs, ab dem die Routine die Daten ablegen kann. Das wars schon im großen und ganzen. In der Pascal-Unit habe ich daraus nun zwei Prozeduren gemacht.

  1. SaveScreen ( xtl, ytl, xbr, ybr, buffer ) ⇒ die ersten beiden XY-Koordinaten beschreiben die obere-linke Ecke und das zweite Paar die unter-rechte Ecke. In der Variablen „buffer“ werden die gesicherten Daten gespeichert. Hier muß ich eine kleine Einschränkung vornehmen. Die Maximalgröße des zu sichernden Bereichs darf eine Größe von 40×8 Zeichen nicht überschreiten. Warum, weshalb und überhaupt darauf komme ich gleich nochmal.
  2. RestoreScreen ( xtl, ytl, xbr, ybr, buffer ) ⇒ die Daten/Parameter der Prozedur sind genau die gleichen wie in der Save-Routine.

2.0 Fn $09 Draw box

Mit Hilfe dieser Funktion kann ich eine Box bzw. einen Rahmen zeichnen lassen. Die Koordinatenangaben, die den Rahmen positionieren und dimensionieren werden genau wie in der oben beschriebenen Funktion angegeben. Ein zusätzlicher Parameter ist noch erforderlich. Man hat noch zusätzlich die Wahl, ob der Rahmen aus einer einfachen Linie gebildet wird, oder ob es eine Doppel-Linie sein soll. Die Funktion macht nichts anderes, als das, was jeder Programmierer auch mit einem Haufen GotoXY- und Write-Anweisungen machen könnte. Es wird aus dafür vorgesehenen Zeichen einen Rahmen gebildet. Was innerhalb dieses Rahmens liegt, bleibt natürlich unberührt. Logischerweise kann man diesen Rahmen dann auch wieder überschreiben. Kritisch ist das natürlich nur dann, wenn man einen Text dort hinein schreiben will. Eine WriteLn-Anweisung genügt, und schon ist unser schöner Rahmen wieder zerstört. Also eigentlich nichts Besonderes. Aber als Anwendungen könnte man sich vorstellen, mit Hilfe dieser Funktion eine Art von Textfenster zu realiesieren (siehe dazu auch das Demoprogramm). Wenn der Rahmen gezeichnet ist, kann man durch überlegte und positionierte Write-Anweisungen den Rahmen zu einem Fenster machen und einen Fensterkopf sowie weitere Informationen auf dem Rahmen unterbringen.

Die Implementation in der Unit ist denkbar einfach: DrawBox ( xtl, ytl, xbr, ybr, lineType ). In der Variablen lineType wird der Linientyp (was auch sonst …) übergeben.

3.0 Fn $0F Menu handling

Das ist eine der mächtigsten und nützlichsten Funktionen überhaupt. Mit ihrer Hilfe kann man die bekannten Menüs aus den internen Applikationen aufrufen. Das Handling dieser Menüs ist denkbar einfach. Mit ESC kann man sie abbrechen. Durch die Cursor-Tasten kann man zu den einzelnen Menüpunkten springen. Durch drücken des ersten Buchstaben des Menütextes wird der Menüpunkt direkt aufgerufen. Wem das zu kurz war, soll nochmal lesen, oder sich seine Portfolioanleitung schnappen um es sich dort noch mal durchlesen …

In der Unit sieht der Funktionsaufruf folgendermaßen aus:

 => Menu ( xtl, ytl, MenuTitle, MenuText, DefaultsText , selectedItem )

Die Werte für „xtl“ und „ytl“ muß ich sicher nicht weiter erklären. Sie geben die linke-obere Ecke an. Daß das Menü einen Rahmen hat, muß ich sicher nicht auch noch erwähnen. Somit dürfte auch klar sein, daß sich das Koordinatenpaar auf die Ecke des Rahmens bezieht. In diesem Zusammnehang noch gleich eine Warnung. Es hat fatale Auswirkungen auf die Darstellung des Menüs, wenn man es zu groß dimensioniert, oder es über den Rand des aktuellen Bildschirmbereichs hinaus ragt. Das bedeutet, daß ein Menü im Modus 40×8 Zeichen nur maximal sechs Menüeinträge haben kann. Zwei Zeilen gehen uns ja schon durch den Rahmen in der Y-Richtung verloren. Der Text eines Menüs kann in diesem Modus dann nur maximal 36 Zeichen lang sein. Einen Titel/Überschrift kann man dem Menü auch geben. Wie schon gesagt, allerdings auch nur 36 Zeichen lang. In der Variablen „MenuText“ sind die einzelnen Menüeinträge abgelegt. Die Menüpunkte werden aneinander gekettet. Als Trennzeichen fügt man nach jedem Eintrag einfach noch ein Nullzeichen ein. Hier ein kleines

Beispiel:

  MenuText := 'Point #1' + Chr(0) + 'Point #2' + Chr(0) + 'Ende'. 

Die Funktion zerlegt den String dann selbsständig, wobei nach jedem Nullzeichen ein neuer Menüpunkt angefangen wird. Die Variable „DefaultText“ hat noch eine besondere Bedeutung. Der String der an die Variable übergeben wird, ist genauso aufzubauen, wie für MenuText beschrieben. Zu jedem Menüpunkt kann so ein weiterer Eintrag zugeordnet werden. Dieser Eintrag wird dann am rechten Rand des Menüs dargestellt. Wenn man DefaultText folgendermaßen übergibt:

DefaultText := '' + Chr(0) + '20' + Chr(0) + 'bye bye', 

dann würde am rechten Rand in der Zeile, wo der Menüeintrag Ende, steht dann das dazugehörige bye bye auftauchen. Wem das immer noch nicht ganz klar ist, der sollte sich als Beispiel das Menü im Texteditor des Portfolio ansehen. Rechts neben dem Eintrag „Rechter Rand“ steht die eingestellte Zeichenzahl pro Zeile. „echter Rand würde im String MenuText und die Zahl in DefaultsText übergeben. Sinnvoll ist so etwas, wenn man sich ändernde Daten zusätzlich im Menü darstellen will. Man muß sich keine Gedanken um die Position der Daten machen und kann zusätzlich noch den String mit den Menüeinträgen unverändert lassen. Nachdem die Funktion aufgerufen ist, stellt sie das Menü dar und gibt, sobald der User seine Auswahl getroffen hat, in der Variablen selectedItem den ausgewählten Menüpunkt, bzw. ob das Menü ohne Auswahl abgebrochen wurde, zurück. Ich habe die Funktion in Pascal so implementiert, daß sie als Function True zurückliefert, falls eine Wahl getroffen wurde. Sollte das Menü abgebrochen worden sein, dann wird False zurückgeliefert. Grundsätzlich kann man der Funktion auch noch mehr Parameter übergeben. Wem die Implementation nicht ausreicht, kann sicher ohne großen Aufwand diese Parameter nach außen zugänglich machen. Nähere Hinweise dazu sind im Pascal-Quelltext der PortAES-Unit als Komentare eingefügt.

4.0 Fn $10 Box area calculation

Hiermit kann man sich eine Menge Arbeit ersparen. Mit Hilfe dieser Funktion kann man im voraus einige Daten ermitteln, die für das Menühandling oder auch für die später erklärte Funktion Message Windows nötig sind. Die Eingabewerte sind die gleichen wie beim Aufruf von Menu. Der Unterschied ist, daß man als Rückgabedaten die Koordinaten der rechten-unteren Ecke bekommt. Das ist sehr wichtig. Als Programmierer ist man selbst dafür verantwortlich, ob der Bildschirmhintergrund an dem das Menü (oder ähnliches) dargestellt wird, vorher gesichert wurde, bzw. nach Abarbeitung des Menüs auch wieder restauriert wird. Um „Save/Restore-Screen“ zu benutzen, braucht man zwei Koordinatenpaare, die diese Funktion liefert. Ein klein wenig mehr Daten bekommt man schon zurück. Aber sie werden im Moment noch nicht benötigt und sind auch noch nicht implementiert. Auch dazu habe ich Kommentare in den Quelltext der Unit eingebaut. Der Pascal-Aufruf lautet:

=> BoxAreaCalculation ( xtl, ytl, TitleText, MenuText, DefaultsText, xbr, ybr )

5.0 Fn $12 Message windows

Der Funktion wird genau wie bei „Menu“ ein Fenstertitel und der Text, der dargestellt werden soll, übergeben. Falls mehr als eine Zeile im Fenster dargestellt werden soll, so müssen die einzelnen Zeilen, wie bei „Menu“ beschrieben durch ein Nullzeichen getrennt werden. Man braucht nur noch die Position der linken-oberen Ecke angeben, und schon hat man ein tolles Textfenster. Um die Dimension des Fensters zu erfahren, benutzt man „BoxAreacalculation“. Für „DefaultsText“ gibt man dann einfach nichts an. Leider kann man hierbei nicht wählen, ob der Rahmen eine Doppel-Line sein soll oder nicht. Das Fenster ist immer eine Doppel-Line. Wenn die Funktion das Fenster dargestellt hat, wird die Kontrolle wieder an das Programm übergeben. Das bedeutet, daß man selber dafür sorge tragen muß, wie lange das Fenster dargestellt wird oder ob der User erst eine Taste drücken muß.

In der Unit sieht das ganze dann so aus:

=> MessageWindow ( xtl, ytl, WindowTitle, MessageText )

6.0 Fn $14 Error windows

Die „Error Windows“ sind die beste einfachste und schnellste Möglichkeit, um den User zu informieren. Das „Error Window“ sichert den Hintergrund, den es überschreibt, selbst und restauriert ihn auch wieder. Es übernimmt auch die Kommunikation mit dem User. Wenn es dargestellt wurde muß der User erst eine beliebige Taste drücken um es wieder zu beenden. Zusätzlich wird auch noch ein Beep-Ton erzeugt, wenn das Fenster auf dem Bildschirm erscheint. Man kann allerdings einem solchen Fenster keine Titelzeile mitgeben. Für einen mehrzeiligen Text verfährt man genau so wie bei den „Message Windows“. Als Parameter benötigt die Funktion also lediglich die Positionierung in altbekanter Weise und den Text der darzustellen ist. Wirklich stark … was? In der Unit sieht das dann auch recht einfach aus:

⇒ ErrorWindow ( xtl, ytl, ErrorText )

So, das war also die Funktionsbeschreibung. Wenn zur Benutzung der Unit noch irgendwelche Unklarheiten bestehen, schlage ich vor, sich einfach mal den Quelltext des Demoprogramms anzusehen und an sonsten einfach mal probieren.

Gehen wir noch ein klein wenig tiefer ins Detail , was die Implementation der Funktionen in Pascal angeht. Es sollten jetzt aber auch die Leute weiterlesen, die nicht vor haben, an meiner Unit irgenetwas zu verändern …

Ich will das ganze mal an einem Beispiel exemplarisch zeigen. Nehmen wir uns die Funktion Message Windows vor. Bevor ich die Funktion vom Befehl

INTR($60, ___) 

aufrufen lassen kann, muß ich die Parameter vorher in die Prozessorregister geschrieben habe. Der Zugriff auf diese Register erfolgt über einen durch Pascal vorgegeben Recordtyp Namens Registers. Durch diesen Record kann ich alle Register belegen und der INTR-Befehl schreibt den Inhalt dieses Records dann in die Prozessorrrgister und löst den angegeben Software-Interrupt aus. So weit so gut. Die Schwierigkeiten für Pascal-Programmierer ergeben sich erst dann, wenn man Pascal-Datentypen an diese Register übergeben muß. Sehen wir uns mal an, wie die Funktion Fn $12 die Daten haben will:

Ich zitiere aus der Orginalbeschreibung von DIP

Fn 12H  Message Windows
Parameters:		BH		Video page number
		DX		Top left of box
		DS:SI		Message text (double terminated zero)
Returns:		None

Description:		Displays text at DS:SI on the screen in a double line box First line of text
		is taken as the title. This service is used for information messages,
		such as loading, saving etc.

Jetzt steht da, daß die obere-linke Ecke im Register DX eingetragen werden muß. DX kann ich nun aber auch getrennt in High- und Low-Byte belegen. Ich habe nun also zwei Zahlen, die die X- und Y-Position beschreiben. DIP hat nun festgelegt, das Werte für X-Koordinaten immer im Low-Byte und die Y-Koordinaten im High-Byte abzulegen sind.

Das heißt, daß ich DX wie folgt belegen muß: DH := Y-Position und DL := X-Position. Grundsätzlich ist es bei allen Funktionen des Portfolio-AES so, daß die linke-obere Ecke im DX-Register eingetragen werden muß. Wenn die rechte-untere Ecke auch mit übergeben wird, wie bei Save/Restore-Screen z.B., dann wird dieses Koordinatenpaar in das CX-Register geschrieben.

Na gut, das hat uns noch keine Schwierigkeiten bereitet. Wie soll man nun aber seinen Pascal-String an DS:SI übergeben. Und was soll dieser Zusatz double terminated zero bedeuten? Dazu muß man folgendes wissen. Die Routine, die hinter diesem Funktionsaufruf steckt, will die Startadresse des Datenbereichs haben, in dem unser String gespeichert ist. Die Startadresse wird ihr in DS:SI übergeben. Da die Routine aber nun nicht wissen kann, wieviele Zeichen sie ab dieser Adresse lesen soll, fängt sie einfach vorne an, und liest so lange weiter, bis sie zwei Nullzeichen hintereinander liest. Das bedeutet, daß der String am Ende zwei Nullzeichen haben muß, sonst würden Daten gelesen, die überhaupt nichts mehr mit dem String zu tun haben. Ganz zu schweigen davon, daß dann zufällig zwei Nullen hintereinder gelesen werden müßten, damit die Routine überhaupt aufhört. Leider sehen unsere Pascal-Strings nun gar nicht so aus wie der verlangte Datenbereich.

C-Programmierer haben es da einfacher. C verwaltet Strings nämlich genau so wie es hier verlangt wird. Ohne Angabe wieviel Zeichen ein String enthält und am Ende zwei Nullzeichen. Pascal verwaltet Strings ganz anders. In einem Pascal-String ist das erste Zeichen reserviert. Dort steht die Länge des Strings. Pascal-Prozeduren wissen also immer von Anfang an, wieviele Zeichen sie lesen müssen. Eine Write-Anweisung in Pascal stellt das erste Zeichen nicht dar und beginnt mit der Ausgabe des Strings erst ab dem zweiten Zeichen. Es werden dann eben auch nur so viele Zeichen dargestellt, wie die Zahl im ersten Zeichen angibt.

Wieder zurück zum eigentlichen Thema …

Wir müssen also zuerst zwei Nullzeichen an das Ende unseres Strings anfügen. Damit hätten wir die Länge gekennzeichnet. Nun braucht man noch die Startadresse des Strings, weil ab dieser Stelle die Daten gelesen werden. Diese Adresse bekommt man mit dem Pascal-Befehlen SEG und OFS. SEG liefert die Segmentadresse des Datenbereichs zurück und OFS den Offsetwert, ab dem gelsen wird. Der Wert den SEG zurückgibt, wird in DS eingetragen und OFS in SI. Das sehe dann so aus:

DS := SEG(___) und SI := OFS(___) + 1 

Die Addition bei der Zuweisung von SI bewirkt, daß die Adresse die Position des zweiten Zeichens unseres Strings angibt. Mit dem ersten Zeichen kann ich ja nichts anfangen, da Pascal hier die Länge speichert. Durch diese Eingriffe fällt es der Routine überhaupt nicht auf, daß sie es mit einem Pascal- und nicht mit einem C-String zu tun hat. Wie das dann in der Praxis aussieht, findet man in der PortAES-Unit.

Wo wir gerade beim Erklären von internen Sachen der Unit sind, kommen wir auch gleich noch auf die Begründung, warum meine Implementation der Save/Restore-Screen Funktion nur eine Fläche von 40×8 Zeichen sichern kann. Zum Sichern des Bereichs benutzte ich ein Byte-Array, das eine konstante Größe von 320 Byte hat. Ich war der Ansicht, daß dies die einfachste Methode ist. Zum einen sollten Pofi-Programme sowieso nur den 40×8 Zeichen Modus verwenden, um dem User das Herumscrollen des Bildschirmfensters zu ersparen, und zum anderen können Menüs, so wie sie die AES-Unit implementiert, sowieso nicht größer werden als diese 40×8 Zeichen.

Das liegt wieder in den Pascal-Strings begründet. Ein Pascal-String kann maximal 255 Zeichen aufnehmen. Das bedeutet, daß mir für die Datenübergabe an die Menüfunktion auch nicht unendlich viele Zeichen zur Verfügung stehen. Nehmen wir einmal an, ich will ein Menü oder „Message Window“ mit sechs Zeilen darstellen. Ich habe einen Rahmen drumherum also sechs Zeilen plus zwei Zeilen für den Rahmen und ich habe meine acht Zeilen im 40×8 Modus voll. Jetzt sehen diese beiden Funktion vor, daß der Text rechts und links noch ein Leerzeichen bis zum Rahmen Platz haben muß. Also 40 Zeichen minus vier Zeichen macht 36 Zeichen als maximale Zeichenlänge. Die Zeilen müssen durch ein Nullzeichen getrennt sein plus ein weiteres Nullzeichen, um das Stringende zu markieren.

Der Menütitel muß auch im Menütext enthalten sein und durch ein Nullzeichen getrennt sein.

6 x ( 36 + 1 ) = 222 ⇒ 222 + 1 = 223 ⇒ 255 - 223 = 32 - 1 = 31

Zeichen, die noch für den Menütitel übrig bleiben. Das wäre also das maximale Fassungsvermögen, das ein Pascal-String leisten kann. Man muß sich also gut überlegen, wieviel Text so ein Menü hat. Man hätte das ganze sicherlich auch so regeln können, daß diese Begrenzungen nicht bestehen, in dem man einen anderen Datentyp als einen einfachen String benutzt. Der Aufwand, der dabei beim Verwalten ensteht ist aber eigentlich nicht gerechtfertigt, wenn man den Nutzen betrachtet.

Alles in allem sind die Funktionen sowieso für den 40×8 Zeichenmodus konzipiert und ich denke auch, daß dies ohnehin der bevorzugte Modus sein sollte und die Einschränkungen in der Unit deshalb auch nicht besonders schmerzen.

Sollten irgendwelche Informatiker/studenten oder ander wissende Person jetzt sagen, daß das ja jetzt eine völlig ungenaue Beschreibung der Problematik war, stimme ich dem zu. Aber ich wollte ja auch nicht allein die PofoInfo füllen.

Ich habe mich diesmal entschloßen, die Quelltexte der Units und des Demoprogramms mit in den Artikel zu integrieren. Wer zu faul ist alles abzutippen, für den habe ich alle Dateien in einem Archiv zusammen gefaßt und sie in die Pofo-Mailbox gelegt. Wenn ich noch Änderungen vornehme, wird dieses Archiv auch ein Update erfahren. Also, immer mal nachsehen, welches Datum das Archiv hat.

Teil 3

In den letzten beiden Kursteilen ging es um die Grundlagen, die ich brauche, um überhaupt Programme auf dem Portfolio schreiben zu können. In diesem Teil soll es nun um die Praxis gehen.

Vorweg

Bevor wir aber etwas Handfestes anfangen, will ich noch ein paar allgemeine Sachen zur praktischen Seite der Programmierung sagen. Wenn ich nun anfange ein Programm zu schreiben, stehe ich vor zwei Problemen.

  • Wenn ich spezielle Funktionen des Portfolio nutzen will, kann ich die Programme nicht unter einem normalen PC-DOS testen. Ich meine damit die Routinen, die vom Portfolio-AES zur Verfügung gestellt werden. Also wie kann ich meine Programme testen ohne sie jedesmal auf den Portfolio zu überspielen.
  • Aus diesem Problem ergibt sich natürlich auch noch ein zweites. Da ich die Programme nicht auf dem PC laufen lassen kann, kann ich auch nicht die Funktionen zum Debugging nutzen, die mir das PASCAL zur Verfügung stellt.

Ich kann also nicht ein Programm während der Laufzeit kurz unterbrechen, in den Editor zurückkehren und mal kurz ein paar Variableninhalte überprüfen. Also nicht unerhebliche Probleme … oder?

Zumindest das erste Problem läßt sich recht leicht lösen. Ich muß natürlich nicht die Programme erst auf den Portfolio übertragen, um sie laufen zu lassen. Es gibt ein paar, genau genommen drei kleine TSR-Programme, die sich unter einem DOS-Betriebssystem in die Interrupts hängen, bei denen ein Portfolioprogramm seine speziellen Routinen erwartet. Startet man also diese drei kleinen Helfer, kann man ganz beruhigt seine Portfolioprogramme auch auf dem PC los lassen.

Das Problem mit dem Debugging ist damit aber immer noch nicht ganz behoben. Natürlich kann ich jetzt so verfahren, und nach den TSR-Programmen das PASCAL starten. Jetzt muß ich die Programme nicht mehr übersetzen und dann laufen lassen, sondern kann sie direkt vom PASCAL-Editor starten und das Programm über Haltepunkte stoppen und meine Variablenwerte einsehen. Wem das genügt der ist damit natürlich bestens bedient. Nun leben wir aber im Zeitalter von Windows 95 und OS/2 und ich kann nicht einfach nur in einem Single-Task-System arbeiten. Ich zumindest nicht. Ich bin es seit meinem ersten Computer (ein ATARI 1040STFM ) gewohnt, mit Fenstern und der Maus zu arbeiten.

Auf meinem PC läuft Windows 95 (Oh Gott … ich habe mich geoutet) und ich will natürlich auch da weiter alle Programm parallel laufen lassen ohne sie jedesmal neu starten zu müssen. Prinzipiell kann ich allerdings auch unter Windows eine virtuelle DOS-Sitzung starten und die TSR-Programme und den PASCAL- Editor dort hochfahren. Es geht auch so, wenn auch sehr viel schwieriger.

Dann ist da noch die Frage, welches PASCAL nimmt man denn nun. Ich persönlich benutze PASCAL 7.0 (und dann möglichst die Oberfläche unter Windows). Ab dieser PASCAL-Version unterstützt der Editor die farbliche Markierung von Schlüsselwörtern, Strings und solchen Sachen. Ich finde so etwas sehr hilfreich, wenn man einen Quelltext durcharbeitet. Mein letztes Portfolioprogramm hat 1538 Zeilen und ich sage euch, da ist so etwas schon sehr hilfreich. Man könnte meinen, daß ein älteres PASCAL vielleicht besser geeignet ist. Ich kann euch beruhigen. Die übersetzten Programme sind nicht größer oder kleiner als mit neueren Versionen. Natürlich gibt es Unterschiede, die allerdings nur dann gravierend sind, wenn ich Debug-Informationen oder Ähnliches in das übersetzte Programm einbauen lasse. Da diese aber in der endgültigen Version auf dem Portfolio nicht mit drin sind ist es also egal.

Hooks

O.K. … soweit zu unseren Werkzeugen.

Dieser Kursteil soll sich ja mit einem konkreten Beispiel befassen. Es sieht also so aus, daß ich euch ein Programm vorwerfe und anhand dieses Beispiels versuche, die Besonderheiten zu erläutern. Das Programm ist eigentlich kein richtiges Programm. Ich habe lange überlegt, was man denn als Beispiel nehmen könnte. Es mußte etwas speziell für den Portfolio sein, und der Quelltext durfte auch nicht so lang werden, daß ihn die Redaktion aus Platzgründen nicht mit abdruckt. Unser Thema ist also, wir schreiben uns ein Hook-File.

Ups … was ist ein Hook-File. Vielleicht ist es manchen Portfolio-Usern noch nicht aufgefallen, aber die interne Textverarbeitung ist gar nicht so unmodern und statisch wie es auf den ersten Blick aussieht. Was WORD 7.0 seine Module und dem Netscape-Navigator seine Add-In’s sind, sind für Portfolio-User Hook-Files.

Das Geheimnis ist, ich kann vom Texteditor kleine Programme nachladen, die dann irgendwas mit meinem Text anstellen können. Hook-Files müssen immer im Root-Verzeichnis von Laufwerk A liegen, und die Dateiendung .HOO haben. Aufgerufen werden diese netten kleinen Helfer über die Taste F6 aus der Textverarbeitung heraus.

Die Textverarbeitung wird dabei aber nicht beendet und der gerade bearbeitete Text geht verloren. Nein … ich habe vielmehr über spezielle BIOS-Funktionen, die DIP freundlicherweise eingebaut hat, die Möglichkeit, vom Hook-File aus Text einzufügen oder zu erfragen, wo der Cursor gerade steht oder auf welchem Zeichen der Cursor steht, ich kann den Cursor im Text verschieben … und so weiter und so weiter.

Ich kann also von meinem kleinen Hook-File aus den Text komplett bearbeiten. Man sieht also, ich kann wunderbar kleine Zusatzfunktionen für die doch manchmal recht magere Textverarbeitung schreiben. Schreiben wir uns also so eine kleine Funktionserweiterung. Hook-Files sind eigentlich nichts anderes als normale Programme, bei denen man die Endung .EXE durch .HOO ersetzt hat. Hook-Files sind nur als normale Programme recht nutzlos, weil sie ja voraussetzen, das die Textverarbeitung im Hintergrund läuft. Also nennt man sie anders und der Textverarbeitung kann so auch nicht der Fehler unterlaufen, ein nicht für sie bestimmtes Programm zu starten.

Das Problem ist, daß diese Programme recht klein sein müssen. Wenn ich nur einen Standard-Portfolio mit 128kByte RAM habe, und die Textverarbeitung hat auch noch etwas geladen, dann bleibt nicht mehr so viel Platz, um unsere kleinen Helfer unterzubringen. PASCAL ist da auf Grund der Größe, die die übersetzten Programme haben auch nicht die beste Sprache, um so etwas zu realisieren. Wir beweisen aber nun, daß es doch geht.

Quellcode für ein HOOkfile

Program DatumUndUhrzeitHook; { Autor : Torsten H„áler }
 
{$M 1024, 0, 0}
 
Uses PortAES, Dos; { verwendete Units }
 
Function Expandieren ( zahl : Word ) : String;
    Var zahlenString : String;
Begin
     Str( zahl, zahlenString );
     Expandieren := zahlenString;
     If Length( zahlenString ) < 2 Then
        Expandieren := '0' + zahlenString;
End; { Zusatzfunktion um Zahlen in Strings zu wandeln }
 
Procedure SendeString ( wasSenden : String );
    Var reg : Registers;
Begin
     wasSenden := wasSenden + Chr(0);
     reg.ah := $03;
     reg.al := $04;
     reg.es := Seg( wasSenden[1] );
     reg.bx := Ofs( wasSenden[1] );
     Intr( $60, reg );
End; { BIOS-Routine Int 60H Fn 03H Unterfunktin EDHO_INS }
 
Const wochenTage : Array [ 0 .. 6 ] Of String
                   = ( 'So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa' );
 
Const MenueTitel = 'Was einfgen ?';
 
Const MenueText = 'Datum ...       ' + Chr(0) +
                  'Uhrzeit ...     ' + Chr(0) +
                  'Beides ...      ';
 
Var jahr, monat, tag, wochenTag, stunden, minuten, hilf : Word;
    datum, uhrzeit : String;
    puffer : ScreenBufferType;
    auswahl : Byte;
 
Begin
     SaveScreen( 0, 0, 39, 7, puffer );
     GetDate( jahr, monat, tag, wochenTag );
     jahr := jahr Mod 100;
     datum := wochenTage[ wochenTag ] + ' ' +
              Expandieren( tag ) + '.' +
              Expandieren( monat ) + '.' +
              Expandieren( jahr );
     GetTime( stunden, minuten, hilf, hilf );
     uhrzeit := Expandieren( stunden ) + ':' +
                Expandieren( minuten ) + ' Uhr';
     If Menu( 1, 1, MenueTitel, MenueText, Chr(0), auswahl ) Then
        Case auswahl Of
             0 : SendeString( datum );
             1 : SendeString( uhrzeit );
             2 : SendeString( datum + ' / ' + uhrzeit );
        End;
     RestoreScreen( 0, 0, 39, 7, puffer );
End.

Das Hook-File soll, wenn es aufgerufen wird, das aktuelle Datum oder die Uhrzeit oder auch beides als String in den Text einfügen. Die Auswahl, was eingefügt wird, geschieht über eines der üblichen Portfolio-Menüs.

Gehen wir nun den Quelltext langsam durch ...

Wie schon im ersten Teil des Kurses erwähnt, muß ich den Speicherbedarf des Programms so gering wie möglich halten. Das bedeutet, daß ich mir nur soviel Speicher reserviere, wie ich auch benötige. Die Zeile mit der {$M … Anweisung macht den Compiler darauf aufmerksam, daß mein Programm nur 3072 Byte für seinen lokalen Stack reservieren möchte. Ich kann die Bytes für den Stack leider immer nur in 1024er Schritten reservieren. Dadurch kommt diese Zahl zustande. 2048 Bytes führen zu einem Stack-Überlauf also reserviere ich 1024 mehr.

Das Programm benutzt wie schon erwähnt die Menüfunktionen, die vom Portfolio-Bios zur Verfügung gestellt werden. Um diese Menüs aufzurufen, benutze ich die PortAES-Unit aus dem zweiten Kursteil. Die DOS-Unit brauche ich, um die Prozessorregister ansprechen zu können und um das Datum und die Uhrzeit vom System erfragen zu können.

Die kleine Funktion “Expandieren“ wandelt einen numerischen Wert vom Typ “Word“ in einen String um. Wenn der Wert nur einstellig sein sollte, dann wird vorne noch eine Null als ASCII-Zeichen angefügt. Das ist nötig, wenn ich als Anzahl der Minuten nur die Ziffer 6 bekomme, denn ansonsten würde meine Uhrzeit ja 21:6 Uhr lauten. Und das sieht wirklich nicht so schön aus. Zum Umwandeln der Zahl in einen String, benutzt das Programm die PASCAL-Funktion “STR“. Dann wird geprüft, ob die Länge des Strings kleiner als zwei ist und wenn ja, dann wird besagte Null noch vorne angeheftet.

Als Funktion liefert sie den sich ergebenden String direkt zurück. Weil ich diese Funktion mehrere Male benötige, habe ich sie in eine Funktion außerhalb der Hauptschleife platziert. Der PASCAL-Compiler braucht bei der Übersetzung zwar mehr Speicher für den Sprung in eine Subroutine, wenn ich diese aber wirklich öfter brauche, spart es mir doch wieder mehr Speicherplatz, als wenn ich diese Funktion fünf mal in der Hauptschleife unterbringe. Man sollte wirklich aufpassen, was man alles in Unterprogramme steckt. Denn wenn ich die Funktion nur ein- oder zweimal aufrufe, kann es unter Umständen besser sein, als sie zweimal im Hauptprogramm zu platzieren. Außerdem muß ich mir klar machen, daß bei jedem Aufruf eines Unterprogrammes alle Variablen auf dem Stack gesichert werden müssen, damit ihr Inhalt nicht verloren geht. Wenn ich jetzt aus einem Unterprogramm noch ein Unterprogramm aufrufe, kann mein Stackbedarf zu schnell zu groß werden und mein Programm ist dann alles andere als klein. Wer Lust hat, kann das Programm ja mal so umschreiben, daß keine Unterprogramme nötig sind und alles im Hauptprogramm steht. Das übersetzte Programm kann wirklich kleiner sein, als es in dieser Version der Fall ist.

Die Prozedur SendeString ist sozusagen das Herz des Systems. Sie stellt die Schnittstelle zur Textverarbeitung dar. In der Variablen “wasSenden“ wird der Text übergeben, den ich einfügen will. Da ich in dieser Prozedur einen Interrupt aufrufe, muß ich mir eine Variable anlegen, in der ich die Prozessor-Register direkt mit Werten füllen kann. Die DOS-Unit stellt mir einen passenden Datentyp zur Verfügung. Diese Interrupt-Routine ist natürlich nur speziell auf dem Portfolio vorhanden. In “reg.ah“ wird die Funktionsnummer übergeben. Da diese Funktion auch noch andere Unterfunktionen hat, muß ich die Nummer dieser Unterfunktion im AH-Register übergeben. Die Funktion $03 beinhaltet alle Routinen, die von Hook-Files verwendet werden können, um mit der Textverarbeitung zu kommunizieren.

Hier mal eine kleine Auflistung, die aus der Orginalbeschreibung von DIP stammt :

Fn 03H Reserved for CustomAdd-ins

A series of “hooks“ are provided into the Editor to enable users to control the Editor from outside.

There are 6 Editor “hooks“. These enable an application spawned within the Editor to access a limited number of
internal functions which modify the text and environment.
	EDHO_GOTO	Move the cursor position
	EDHO_GET		Get the cursor position
	EDHO_REF		Refresh the screen
	EDHO_LOC		Get location of character at cursor
	EDHO_INS		Insert string into text
	EDHO_DEL		Delete characters from text

Wir benötigen für unsere Zwecke die Unterfunktion EDHO_INS. Die Funktion benötigt die Segmentadresse im ES-Register und die Offsetadresse im BX-Register. Das BIOS erwartet allerdings einen sogenannten C-String, daß heißt einen nullterminierten String. Aus diesem Grund muß ich an meinen PASCAL-String auch noch ein Nullzeichen anhängen. Das bekomme ich durch die Funktion “CHR(0)“ oder indem ich einfache “#0“ anhänge. Der String ist jetzt nullterminiert. Warum ich dann die Adressen in dieser speziellen Form übergeben muß und was das mit den C-Strings genau zu tun hat, habe ich schon mal im zweiten Kursteil erklärt. Also, wenn es noch nicht klar ist, dann dort nachsehen. Gut, wir haben nun also eine Prozedur, der ich einen PASCAL-String mitgebe und die diesen dann an die Textverarbeitung weiterreicht. Super … machen wir uns also an die Bedienoberfläche unseres kleinen Helfers.

Die drei nun folgenden Konstantendeklarationen sind einfach nur eine Hilfe, um im Programm selber einige Wertzuweisungen zu sparen. Es ist ohnehin besser, wenn ich Daten, die sich nie verändern werden als Konstanten in den Quelltext einbringe. Es spart mir unter Umständen wieder einiges an Speicherplatz bei dem später übersetzten Programm. “wochenTage“ ist eine sogenannte typisierte Konstante. Ich kann auf die Elemente wie in einem normalen Array zugreifen. Hier habe ich mir die Strings für die Wochentage abgelegt. Den Wert, den ich später bei der Datumsabfrage zurückbekomme, kann ich sofort als Zugriffsindex auf die Konstante anwenden. Dazu aber weiter unten noch mehr. Die nächsten beiden Konstanten beinhalten meinen Menütitel und den Menütext. Sie sind eigentlich Strings, auch wenn das nicht noch mal extra dransteht. Wichtig ist, daß der String der die Menüpunkte enthält, ein einziger String ist und die Punkte durch ein Nullzeichen voneinander getrennt sein müssen. Auch das habe ich ausführlicher im zweiten Kursteil behandelt.

Nun die globalen Variablen. Die Namen sind so gewählt, daß sie eigentlich aussagekräftig genug sein müßten. In den beiden Strings “datum“ und “uhrzeit“ wird der darzustellende String zusammengestückelt. “puffer“ ist für meine Sicherungskopie des Bildschirms und in “auswahl“ bekomme ich die Wahl des Users zurückgeliefert.

Machen wir uns an das Hauptprogramm. Zuerst einmal bin ich selber dafür verantwortlich, daß wenn ich mein Programm verlasse der Bildschirm so aussieht, wie ich ihn vorgefunden habe. Man muß wissen, daß alle darstellenden Funktionen aus der PortAES-Unit beziehungsweise die BIOS-Routinen des Portfolio einfach auf den Bildschirm schreiben und damit den vorherigen Inhalt zerstören. Eine Ausnahme gibt es, nämlich die Funktion “ErrorWindow“. Hier paßt das BIOS selber auf, daß der Bildschirm restauriert wird. Wie gesagt, ich muß sicher stellen, daß wenn mein Programm beendet ist, der Bildschirm restauriert wird. Das mache ich indem ich den Bildschirminhalt, bevor irgendwelche anderen Aktionen laufen, in meine Variable “puffer“ sichere. Die beiden Funktionen “SaveScreen“ und “RestoreScreen“ aus der PortAES-Unit übernehmen für mich Aufgabe des Sicherns und der Restaurierung. Deshalb sollten diese beiden Funktionen jede meiner Bildschirmaktionen klammern.

Diese Sicherheit hätte ich also. Nun kann ich ganz beruhigt zur Arbeit schreiten. Die beiden Prozeduren “GetDate“ und “GetTime“ sind Standardroutinen aus der PASCAL-Unit : DOS. Mit ihrer Hilfe kann ich das aktuelle Datum und die Uhrzeit erfragen. “GetDate“ gibt mir nicht nur das Datum zurück, sondern meldet mir auch gleichzeitig noch, welchen Wochentag wir haben. Nett … Wenn ich es schon so leicht gemacht bekomme, dann will ich das auch nutzen und den Wochentag in meinem Datumsstring mit anzeigen.

Nun muß man wissen, in welcher Form mir die Prozedur den Wochentag zurückgibt. Der Wochentag ist eine Zahl zwischen 0 und 6. Null bedeutet dabei Sonntag und sechs bedeutet Samstag. Das erklärt, warum die Indizes meiner Wochentagskonstante von 0 bis 6 gehen und warum der Inhalt dann mit “So“ anfängt und nicht mit Montag. Ich kann jetzt, wie oben schon mal erwähnt, den Rückgabewert von “GetDate“ direkt als Index für das Array benutzen.

Es ist natürlich eine Geschmacksfrage wie mein Datum dargestellt wird. Ich mag es, wenn ich zum Beispiel bei der Jahreszahl die “19“ weglassen kann und wenn Tage und Monate mit nur einer Ziffer mit einer führenden Null verschönt werden. Um von der Jahreszahl nur die letzten beiden Ziffern zu bekommen, wende ich einen kleinen Trick an.

Der Rechenausdruck MOD (Modulo) führt eine ganzzahlige Division durch und gibt als Ergebnis den ganzzahligen Rest zurück. Bei “1996 MOD 100“ wäre 100 also 19 mal in 1996 enthalten. “19 mal 100 gleich 1900“ Der ganzzahlige Rest ist also 96. Und schon habe ich nur noch die letzten beiden Ziffern. Dieses Ergebnis schreibe ich mir dann wieder in die Variable “jahr“ zurück, weil ich ja nur das haben will. Die nun folgende vierzeilige Anweisung ist natürlich nur eine Anweisung, die ich der Übersichtlichkeit halber aber in vier Zeilen verteile. Es handelt sich hierbei um eine ganz normale Stringverkettung. Zwischen den einzelnen Angaben werden noch Leerzeichen und Punkte eingebaut. Die Formatierung von einer Zahl in einen String übernimmt die Funktion “Expandieren“. Außerdem wird der String auch noch um die führende Null erweitert falls erforderlich.

Die “GetTime“ Funktion brauche ich nun ja wohl nicht mehr zu erklären. Die Funktion würde mir auch noch die Sekunden und die hundertstel Sekunden zurückgeben. Aber so genau wollte ich die Uhrzeit ja nicht haben. Also kann ich für diese beiden Werte eine Hilfsvariable einsetzen, deren Inhalt nicht beachtet wird. An dieser Stelle noch ein kleiner Hinweis. Es gibt doch einen Unterschied, ob ich die “GetTime“ Funktion auf dem PC aufrufe oder auf dem Portfolio. Auf dem Portfolio bekomme ich keinen korrekten Wert für die hundertstel Sekunden. Das ist auch der Grund, warum Zeitmessungen auf dem Portfolio so schwierig sind.

Gut … meine Ausgabestrings sind also erstellt und formatiert. Nun geht es darum, den User zu fragen, was er denn bitte schön eingefügt haben möchte. Wir lassen ihm ja die Wahl, ob er nur das Datum, nur die Uhrzeit oder vielleicht beides haben möchte. Für diese Auswahl zeigen wir ihm ein Menü.

Ein Portfolio-Menü.

Die Menüfunktion stammt auch wieder aus der PortAES-Unit und ihre Parameter und ihre Benutzung sind im zweiten Kursteil beschrieben. Nur kurz … mit den ersten beiden Zahlenparametern lege ich die linke-obere Ecke des Menüs fest, ich positioniere es also. Wichtig ist, daß die Funktion einen Wahrheitswert zurück liefert, ob eine gültige Auswahl getroffen wurde oder nicht. Sollte der User das Menü mit Escape abgebrochen haben, dann würde die IF-Anweisung und die daraus folgende CASE-Anweisung gar nicht ausgeführt werden und es würde gar nichts passieren. Unser Programm beendet sich sang und klanglos und löst sich nach der Wiederherstellung des Bildschirms in Luft auf. Sollte aber einer der Menüpunkte angewählt werden, dann war das Starten des Programms nicht sinnlos und wir können zeigen, was in uns steckt. Bei drei Menüpunkten kann unser Rückgabewert in “auswahl“ zwischen 0 und 2 liegen. Je nachdem was nun in “auswahl“ steht, sende ich mit Hilfe der EDHO_INS Funktion den passenden String an die Textverarbeitung.

Zum Schluß muß noch der Bildschirm restauriert werden, um die Hinterlassenschaften unseres Menüs zu beseitigen und unser Hook-File wird beendet. Sobald die Textverarbeitung wieder die Kontrolle hat, erscheint wie von Zauberhand unser String.

Noch etwas zur Benutzung dieses Hook-Files. Ab einer bestimmten Größe, die das Programm im geladenen Zustand im Speicher einnimmt, kann es sein, daß das Hook-File nicht mehr geladen wird. Das tritt meist dann auf, wenn noch ein anderes Programm im Hintergrund schlummert. Viele benutzen vielleicht den File-Manager FM.EXE. Starte ich die Textverarbeitung über dieses Programm, dann schafft es die Textverarbeitung nicht mehr das Hook-File nachzuladen. Es ist also meistens besser, wenn man die Textverarbeitung von der DOS-Oberfläche startet. Damit sind diese Schwierigkeiten weitgehend behoben.

So, ich hoffe, daß das nicht zu schwer war. Eigentlich nicht. Man sieht, wie man mit einfachen Mitteln eine Erweiterung für die Textverarbeitung verfassen kann. Denkbar wäre jetzt zum Beispiel mit der EDHO_INS Funktion eine Art von Textbaustein-Verwaltung. Häufig gebrauchte Textinhalte können so auf Knopfdruck einfach eingefügt werden. Vielleicht hat ja der eine oder andere Geschmack daran gefunden, kleine PASCAL-Programme zu erstellen. Vielleicht haben ja auch einige Nichtprogrammierer die den Text gelesen haben, Lust bekommen, selber zu programmieren. Ich kann nur sagen, es ist ein tolles Gefühl, wenn man weiß, daß ein kleines Wunderwerk, das gerade auf dem Bildschirm zu sehen ist, von einem selbst stammt. Jeder Programmierer, egal welche Sprache er benutzt, wird mir zustimmen, welche Faszination davon ausgeht. Und nur um zu zeigen, was man alles programmieren kann, die Programme TELEFONTARIFE und ZETTEL sind von mir. Sie sind in PASCAL geschrieben und mit den PortUnits aus dem zweiten Kursteil erstellt. Und das waren mit Sicherheit nicht die letzten

Falls jemand also anfangen will zu programmieren : Es gibt viele gute Bücher, um den Einstieg selber zu finden und ein Turbo PASCAL 6.0 kann ich schon auf CD gebrannt in jeder Computerabteilung der Kaufhäuser für nicht mal 40,-DM bekommen. Programmierkurs für PASCAL 4

Teil 4

Die Grafikprogrammierung

So … Freunde. Wir haben es nun fast geschafft, die Grundlagen der Pascalprogrammierung auf dem Portfolio zusammenzutragen. Ein Bereich fehlt aber noch. Etwas, daß eigentlich immer dazugehört und was für die meisten Leute das absolut Höchste ist.

Es geht um die Grafikprogrammierung. Ich muß zugeben, daß es mir lieber gewesen wäre, wenn ich mir dieses Thema hätte sparen können. Ich bin zwar auch fasziniert von den Möglichkeiten, trotzdem scheue ich den Aufwand, der damit verbunden ist.

Es gibt zwei mittelgroße Probleme, die uns erst einmal beschäftigen müssen. Ziel eines jeden Kurses war es bisher, am Ende eine Art Prototyp zu haben, auf dem man dann seine eigenen Programme aufbauen kann. Meistens waren das Pascal-Units, die man später einbinden konnte und die einem die Funktionen zur Verfügung gestellt haben. Nun muß man hier sagen, daß gerade die Programmierung von Grafiken recht individuell ist. Meistens sind es ja spezielle Effekte, die man braucht. Gerade dieses Gebiet ist so weitreichend, daß man, wenn man einigermaßen alles abdecken wollte, eine Unit bekommt, die dann eher einer Programmiersprachenerweiterung ähnelt. Also, alles was dieser Kurs machen kann, ist die Grundlagen schaffen. Das heißt, Funktionen, um Linien und Kreise zu zeichnen, Punkte zu setzen und noch ein paar ähnliche Sachen. Das erste Problem ist also der mangelnde Umfang und die Entscheidung, was man bespricht und was nicht.

Leider haben wir aber noch ein viel größeres Problem. Grafikprogrammierung ist grundsätzlich immer eine zeitkritische Angelegenheit. Zwar sind für die meisten Funktionen, wie das Setzen eines Pixels auf dem Bildschirm, keine großen Programmierkünste erforderlich. Wenn Sie aber einen Kreis zeichnen wollen, müssen Sie schon Berechnungen anstellen, an welchen Koordinaten auf dem Bildschirm die Pixel gesetzt werden sollen. Hier liegt nun das große Problem, was auf einem 4,5MHz getakteten Portfolio noch viel schwerer ins Gewicht fällt als auf anderen Systemen. Der Kleine ist nun mal nicht der schnellste Rechner unter der Sonne. Wenn ich nun noch eine Hochsprache wie Pascal verwende, die mit der Anzahl der Befehle, die für eine Funktion ausgeführt werden müssen, sehr hoch ist, bin ich in Bezug auf die Grafik schon auf der Verliererseite. Die einzige Möglichkeit, die uns bleibt, ist die, die zeitkritischen Sachen direkt in Maschinensprache zu verfassen.

Damit wird klar, daß die Grafikunit, die zu diesem Teil des Kurses gehört, größten Teils in Maschinensprache verfaßt ist. Maschinensprache ist aber ja eigentlich nicht unser Thema. Deshalb wird es die meisten von euch nicht interessieren, wenn ich die Maschinensprachteile bespreche. Die Leute, für die der Kurs eigentlich ins Leben gerufen wurde, sind reine Pascal-Programmierer. Jemand, der Maschinensprache beherrscht, braucht die vorgestellte Unit sowieso nicht, da er selber Grafikprogrammierung wahrscheinlich sehr viel besser realisieren kann. Es geht hier also nur darum, dem Programmierer Routinen an die Hand zu geben, damit er die wichtigsten Aufgaben lösen kann.

Ich persönlich bin auch kein großer Assembler Programmierer, das können andere Leute mit Sicherheit besser als ich. Deshalb muß ich zugeben, daß die vorgestellte Unit diesmal auch nicht aus meiner Feder stammt. Ich habe sie aus dem wahrscheinlich einzigen Fachbuch zur Pascal Programmierung auf dem Portfolio entnommen (siehe Anhang). Ich finde diese Unit deshalb für den Kurs vorteilhaft, weil die zur Verfügung gestellten Routinen namens- und aufrufkompatibel zur GRAPH-Unit von Turbo-Pascal sind. Dadurch wird es relativ einfach, bestehende Grafikprogramme für den Portfolio umzuschreiben, da es in den meisten Fällen ausreicht, die Uses Anweisungen auszutauschen.

Folgende Befehle sind in der Unit implementiert :

Arc Bar
Bar3D Box
Circle ClearDevice
CloseGraph DrawPoly
Ellipse FillEllipse
FillPoly FloodFill
GetColor GetPixel
InitGraph Line
LineRel LineTo
MoveRel MoveTo
OutTextXY PieSlice
PutPixwl Rectangle
Sector SetColor
SetFillStyle SetTextStyle
TextPixel

Welche Parameter diese Routinen benötigen, und wie ich sie verwende, kann ich aufgrund der Kompatibilität in der Pascal Hilfe nachlesen. Bei den zwei folgenden Befehlen sind jedoch Abweichungen zu denen der Original Unit notwendig geworden :

Bei OutTextXY können nur ASCII-Codes bis einschließlich 127 ausgegeben werden.

Und der Befehl SetTextStyle besitzt eine etwas andere Aufrufsyntax: Der erste Original-Parameter (font) existiert zwar ebenfalls, hat jedoch keine Wirkung auf den Zeichensatz. Für den Parameter direction sind Werte von 1 bis 12 erlaubt, wobei das Aussehen der Zeichen wie folgt beeinflußt wird.

Nummer Erklärung
1 Zeichen nicht gekippt, keine Kursivschrift
2 Zeichen nicht gekippt, Kursivschrift nach links
3 Zeichen nicht gekippt, Kursivschrift nach rechts
4 Zeichen um 180° gekippt, keine Kursivschrift
5 Zeichen um 180° gekippt, Kursivschrift nach links
6 Zeichen um 180° gekippt, Kursivschrift nach rechts
7 Zeichen um 90° gekippt, keine Kursivschrift
8 Zeichen um 90° gekippt, Kursivschrift nach links
9 Zeichen um 90° gekippt, Kursivschrift nach rechts
10 Zeichen um 270° gekippt, keine Kursivschrift
11 Zeichen um 270° gekippt, Kursivschrift nach links
12 Zeichen um 270° gekippt, Kursivschrift nach rechts

Statt eines weiteren Parameters bei der Original-Unit, der dort die Zeichengröße gemeinsam für x- und y-Richung festlegt, folgen bei der Portfolio-Unit noch zwei, die die Zeichengröße in x- und y-Richtung getrennt festlegen.

Aus Kompatibilitätsgründen wurde die Routine InitGraph original übernommen. Das bedeutet, daß ein Pfadname für einen Grafiktreiber angegeben werden muß. Da die Portfolio-Unit aber gar keinen Treiber benötigt, können Sie eingeben, was Sie wollen.

Mit den oben genannten Grafikbefehlen sollten die meisten Leute schon etwas anfangen können. Einige Befehle, um zum Beispiel Grafiken im PGC Format einzulesen oder abzuspeichern, fehlen hier natürlich. Hierzu existieren aber Beispiele, die ich im Rahmen diese Kursteils jedoch nicht besprechen möchte. Wer sich speziell dafür interessiert, kann von mir gerne Beispiel-Quelltexte bekommen.

Mit dieser Unit haben wir nun Grundlagen für die Grafikprogrammierung auf dem Portfolio geschaffen, die für jemanden ausreichen sollten, der keine Lust und Zeit hat, sich mit der langwierigen Assembler-Umsetzung auseinanderzusetzen. Den Quelltext der Unit abzudrucken ist leider nicht möglich, da ihr Umfang so groß ist, daß es den Rahmen der PofoInfo bei weitem sprengen würde. Das bedeutet nicht, daß man die Unit nicht bekommen kann. Denn der Pascal Kurs ist zusammen mit den Units, die in diesem Rahmen entstanden sind, beim PCD erhältlich.

Auch wenn dieser Teil des Kurses qualitativ und quantitativ nicht mit den vorherigen Teilen mithalten kann, soll er doch den Abschluß des Kurses bilden. Abschluß des Kurses bedeutet, daß mit diesem vierten Teil sämtliche Grundlagen besprochen sein sollten. Das heißt natürlich nicht, daß dies das Ende von Artikeln zum Thema Pascal Progammierung auf dem Portfolio ist, jedoch sollte nun jeder in der Lage sein, diese Grundkenntnisse in eigene Programme umzusetzen. Spezielle Probleme und Sonderfunktionen könnten Inhalt weiterer Artikel sein. An dieser Stelle deshalb noch einmal ein letzter Aufruf an alle, die glauben ,daß wichtige Bereiche nicht besprochen wurden. Eine Email genügt und ich werde mich mit der gewünschten Thematik auseinandersetzen (es sei denn, es betrifft den Bereich Grafik…:o).

Anhang

verwendete Quellen :

  • Portfolio Programmierpraxis
    • Frank Riemenschneider, Michael Schuschk
    • Verlag : Markt&Technik
  • Portfolio Technical Reference Guide
    • DIP
  • Diverse Texte aus diversen Mailboxen

Download

1)
in den Downloads der einzelnen Kurse liegen die Units mit drin
software/diy/pascal/pascalk.txt · Zuletzt geändert: 12/11/2006 00:11 (Externe Bearbeitung)