home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 1998 April A
/
Pcwk4a98.iso
/
PROGRAM
/
PASCAL
/
DUMPING
/
ALTCRT2.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1995-03-24
|
67KB
|
2,228 lines
Unit AltCrt2 ;
{
Copyright (c) 1991-1995 by Oliver Fromme <fromme@rz.tu-clausthal.de>.
Freely usable, freely distributable.
Last edit: 3-Feb-1995 Oliver Fromme
This unit is intended to be used for Borland/Turbo Pascal 7.0.
It provides a lot of utility routines which are very useful in the
everyday life of every Pascal programmer. Once you get used to it,
you'll never want to miss it.
Sorry, all comments are currently in German, but you should be able
to figure out what each of the procs/funcs is good for. If you really
need a translation, ask me and I'll probably translate it.
Important: Do not use both Crt and AltCrt2 at the same time!
}
{$A+,B-,D+,E-,F-,G+,I-,L+,N-,O-,P+,Q-,R-,S-,T-,V+,X+,Y+}
{---------------------------------------------------------------------------}
Interface
Uses Dos,Strings ;
Const EarthExists = True ; {z.B. für `While EarthExists Do' :-) }
EndOfUniverse = False ; {z.B. für `Repeat Until EndOfUniverse' :-) }
EmptyString = '' ;
CrLf = #13#10 ; {Carriage Return + Line Feed}
Type ExText = File ; {Für ExWriteLn/ExReadLn, siehe unten.}
Str2 = String[2] ; {Für die Byte-Hex-Funktionen.}
Str4 = String[4] ; {Für die Word-Hex-Funktionen.}
Str8 = String[8] ; {Für die LongInt-Hex-Funktionen.}
Str10 = String[10] ; {Für die Lead-Funktionen.}
NExtStr = String[12] ; {Für Dateinamen mit Extension.}
Var TextAttr : Byte ; {Wird bei Read/Write ignoriert.}
Var MaxX,MaxY : Word ; {Werden beim Start initialisiert, Zählung
beginnt bei 0. Werden auch bei speziellen
SVGA-Modi richtig gesetzt (z.B. 99/39 im
Modus 100x40 des Tseng-ET4000).}
Var mx,my : Word ; {Enthält die Mauskoordinaten des letzten Aufrufes
von GetMouse, siehe unten.}
{Die folgenden Prozeduren/Funktionen sind funktionell mit denen von
Crt identisch. Man beachte die folgenden Punkte:
- TextAttr wird bei Read/Write ignoriert.
- Aktuelles Window ist stets der ganze Bildschirm.
- Read/Write erfolgt über DOS, d.h. Umleitungen und Pipes sind möglich.
- Alle anderen Bildschirm-Funktionen erfolgen über das BIOS,
d.h. sie funktionieren auch in SVGA-Modi, die das jeweilige VGA-BIOS
unterstützt. TextAttr wird berücksichtigt.
- KeyPressed und ReadKey verwenden Int16, d.h. sie sind systemkonform.
- Delay ist unabhängig von Rechnertyp und Takfrequenz, die Abweichung
beträgt nur wenige Taktzyklen.}
Procedure ClrScr ;
Procedure GotoXY (x,y : Byte) ;
Function WhereX : Byte ;
Function WhereY : Byte ;
Procedure InsLine ;
Procedure DelLine ;
Function KeyPressed : Boolean ;
Function ReadKey : Char ;
Procedure Sound (Hz : Word) ;
Procedure NoSound ;
Procedure Delay (w : Word) ;
{Die folgenden Prozeduren/Funktionen sind im Standard-Crt nicht
implementiert, sind aber ganz brauchbar und gehören thematisch
hierher. TextAttr wird, wo sinnvoll, beachtet.}
Procedure FeedKey (k : Char) ;
{Täuscht den Tastendruck 'k' (ASCII) vor. KeyPressed liefert dann
solange True, bis man den Tastendruck mit ReadKey abgeholt hat.}
Procedure ClrLine ;
{Löscht die Zeile, in der der Cursor steht. Kein Scrolling.
Cursorposition bleibt unverändert.}
Procedure ClrLines (yy1,yy2 : Integer) ;
{Löscht die Zeilen yy1 bis yy2, Zählung beginnt bei 0. Kein Scrolling.
Cursorposition wird an den Anfang der ersten gelöschten Zeile gesetzt.}
Procedure Center (s : String) ;
Procedure LeftAlign (s : String) ;
Procedure RightAlign (s : String) ;
{Diese drei Prozeduren schreiben den angegebenen String zentriert, links-
bzw. rechtsbündig in die aktuelle Bildschirmzeile. Direktzugriff auf
Bildschrimspeicher, funktioniert nur bei Farb-Karten!
TextAttr wird beachtet. Cursorposition bleibt unverändert.}
Procedure ClrKeyBuf ;
{Der Tastaturpuffer wird geleert.}
Function Counter : Word ;
{Für sehr feine Zeitmessungen: Liefert den momentanen Zählerstand
von Timer 0, wird 1.193.180 mal pro Sekunde dekrementiert. Ein
Unterlauf tritt 18,2 mal pro Sekunde auf.
Benötigt nur 29 Taktzyklen (80386, ohne call/ret).}
Function LCounter : LongInt ;
{Dito, für längere, aber genauso feine Zeitmessungen. Ein Unterlauf
tritt genau 1 mal pro Stunde auf. Auch negative Werte möglich.
Benötigt 51 Taktzyklen (80386, ohne call/ret).}
Procedure Beep ;
{Gibt einen Ton von 1000 Hz für 100 ms aus.}
Procedure Buup ;
{Gibt einen Ton von 450-250 Hz für 200 ms aus (z.B. bei Fehler).}
Procedure WaitVerticalRetrace ;
{Wartet darauf, daß der Elektronenstrahl am unteren Bildrand angekommen
ist und zum Bildanfang zurückkehrt. Befindet sich der Elektronenstrahl
bereits auf der Rückkehr, wird bis zum nächsten Bildende gewartet.
Funktioniert sowohl im Text- als auch im Grafikmodus.
Kann z.B. verwendet werden, um Bildschirmaktionen flackerfrei zu
gestalten, oder um die Videofrequenz zu messen.}
Procedure WriteStdErr (Const s : String) ;
{Schreibt s direkt auf den Bildschirm, eine eventuelle Umleitung der
Ausgabe via DOS wird ignoriert.}
{---------------------------------------------------------------------------}
{Die folgenden Prozeduren/Funktionen stammen ursprünglich aus der Unit
AllgUtil. Sie implementieren alle möglichen nützlichen Sachen.}
{Allgemeine/Sonstiges}
Procedure Nothing ; Inline ($90) ; {"Fast" nichts (2 Taktzyklen).}
{Nützlich für Konstrukte wie "While ... Do Nothing".}
Procedure Move (Var Source,Dest ; Count : Word) ;
{Schneller als das Original, da 16-Bit-Transfer verwendet wird.}
Procedure FillByte (Var X ; Count : Word ; Value : Byte) ;
{Entspricht FillChar, ist aber schneller (16-Bit-Transfer).
Value darf nur ein Byte-Typ sein, bei Char-Typen muß man ein
Typecasting Char(...) verwenden.}
Procedure FillWord (Var X ; Count : Word ; Value : Word) ;
Procedure Fill3Byt (Var X ; Count : Word ; Value : LongInt) ;
Procedure FillLong (Var X ; Count : Word ; Value : LongInt) ;
{Dito für 2-, 3- und 4-Byte-Variablen.}
Procedure FillGen (Var X ; Count : Word ; Value : LongInt ; size : Byte) ;
{Dito, allgemeine Version (size = Größe der Variablen in Byte).}
Function Quest (Cond : Boolean ; a,b : LongInt) : LongInt ;
{Entspricht dem "?:"-Operator in C: liefert a, wenn Cond=True, sonst b.}
Function CQuest (Cond : Boolean ; a,b : Char) : Char ;
{Dito für Char-Typen.}
Function SQuest (Cond : Boolean ; Const a,b : String) : String ;
{Dito für String-Typen.}
Function Quest2 (Cond1,Cond0 : Boolean ; a00,a01,a10,a11 : LongInt) : LongInt ;
{Entsprechend für zwei Bedingungen.}
Function LoCase (c : Char) : Char ;
{Wandelt Groß- in Kleinbuchstaben, analog zu UpCase.}
Function UpperCase (Const s : String) : String ;
{Liefert den String in Großbuchstaben.}
Function LowerCase (Const s : String) : String ;
{Liefert den String in Kleinbuchstaben.}
Function IDist (i1,i2,x : LongInt) : LongInt ;
{Abstand von x vom Intervall [i1,i2] (mit i1<=i2).
Es gilt: Diff (a,x) = IDist (a,a,x).}
Function Bound (x,min,max : LongInt) : LongInt ;
Function Max (w1,w2 : LongInt) : LongInt ;
Function Min (w1,w2 : LongInt) : LongInt ;
Function Even (x : LongInt) : Boolean ;
Function ggT (a,b : LongInt) : LongInt ;
Function kgV (a,b : LongInt) : LongInt ;
Function Sgn (x : LongInt) : ShortInt ; {-1, 0, 1}
Function Diff (a,b : LongInt) : LongInt ; {a-b bzw. b-a}
{-Ohne Worte-}
{Utilities für DOS}
Function GetPDir (Const n : String) : DirStr ;
{Liefert Laufwerk+Verzeichnis einer Pfadangabe (incl. "\").}
Function GetRawDir (Const n : String) : DirStr ;
{Liefert das Verzeichnis (ohne Laufwerk und ohne "\").}
Function GetName (Const n : String) : NameStr ;
{Liefert den Namen einer Pfadangabe (ohne Suffix, max. 8 Zeichen).}
Function GetExt (Const n : String) : ExtStr ;
{Liefert den Suffix einer Pfadangabe (incl. ".", max. 4 Zeichen).}
Function GetXt (Const n : String) : ExtStr ;
{Liefert den Suffix einer Pfadangabe (ohne ".", max. 3 Zeichen).}
Function GetNExt (Const n : String) : NExtStr ;
{Liefert Namen+Suffix einer Pfadangabe (max 12 Zeichen).}
Function GetDName (Const n : String) : PathStr ;
{Liefert Verzeichnis+Name einer Pfadangabe (ohne Suffix).}
Function GetDrive (Const n : String) : Str2 ;
{Liefert das Laufwerk einer Pfadangabe, z.B. 'C:'.}
Function ExtPath (Const n,e : String) : PathStr ;
{Liefert n, falls n ein Suffix enthält (auch leer, d.h. "XXX."),
ansonsten n+'.'+e.}
Function NormName (n : NExtStr) : NExtStr ;
{Fügt in einen Dateinamen Leerzeichen (und eventuell einen Punkt) ein,
um ihn auf eine Länge von 12 Zeichen zu bringen.}
Function NormDirn (Const n : NExtStr) : NExtStr ;
{Dito, ersetzt den Punkt aber durch ein Leerzeichen, falls kein Suffix
vorhanden ist, außerdem Sonderbehandlung für '.' und '..'.}
Procedure NormDir (Var d : DirStr) ;
Function fNormDir (Const d : DirStr) : DirStr ;
{Hängt an d nötigenfalls ein '\' an.}
Function NormChDir (d : DirStr) : DirStr ;
{Entfernt ein angehängtes '\', falls nicht das Wurzelverzeichnis gemeint
ist. Dos.ChDir und Exists benötigen diese Form.}
Function WildExpand (n : NExtStr) : NExtStr ;
{Normalisiert (siehe NormName) und expandiert '*' zu '?'.}
Function Matches (n : NExtStr ; Const mask : NExtStr) : Boolean ;
{Liefert True, wenn n der Maske mask entspricht, letztere darf '?',
aber nicht '*' enthalten, und muß die Länge 12 haben (siehe WildExpand).}
Function TempDir : PathStr ;
{Liefert Namen eines Temp-Dirs incl. '\'.}
Type PathProc = Procedure (Dir : DirStr ; Fil : SearchRec) ;
Const Recursive = 1 ;
Function ProcessFiles (Const mask : PathStr ; opt : Word ; job : PathProc)
: LongInt ;
{Führt die Prozedur job für jede Datei aus, die zum Muster mask paßt
(kann '?' und/oder '*' enthalten). Für opt können eine oder mehrere der
folgenden Optionen verwendet werden:
- Recursive: es werden ebenfalls die Inhalte aller Unterverzeichnisse
rekursiv bearbeitet.
Funktionsergebnis ist die Anzahl der bearbeiteten Dateien (= Anzahl
der Aufrufe von job), was natürlich auch 0 sein kann (wenn keine
passenden Dateien gefunden wurden).
Das an die job-Prozedur übergebene Dir endet immer mit einem '\'.}
Function PathEq (n : String) : PathStr ;
{Hängt an n soviele Leerzeichen an, daß es lang ist wie bei
maximaler Ausnutzung der Dateinamenlänge.}
Procedure ChangeDir (d : String) ;
{Wechselt das aktuelle Verzeichnis. Im Gegensatz zu System.ChDir wird aber
nicht das aktuelle Laufwerk gewechselt, falls d eine Laufwerksangabe
enthält, sondern nur das aktuelle Verzeichnis auf dem angegebenen
Laufwerk. Trailing '\' ist egal.}
Function QuietFileSize (Const n : PathStr) : LongInt ;
{Liefert die Größe der Datei in Bytes, ohne daß die Datei geöffnet wird.
Ergebnis ist -1 bei einem Verzeichnis oder Volume Label, -2 bei einem
Fehler (siehe Dos.DosError).}
Function Exists (Const n : String) : Boolean ;
{Liefert True, falls n existiert (File, Verzeichnis, Volume Label).}
Function IsDir (Const n : String) : Boolean ;
{Liefert True, falls n existiert und ein Verzeichnis ist.}
Function IsFile (Const n : String) : Boolean ;
{Liefert True, falls n existiert und eine Datei ist.}
Function IsEmpty (n : DirStr) : Boolean ;
{Liefert True, falls das Verzeichnis n (mit oder ohne abschließenden
"\") leer ist (bis auf "." und "..").}
Function Writeable (d : Char) : Boolean ;
{Liefert True, falls man auf das Laufwerk d schreibend zugreifen kann.
Liefert False, wenn das Laufwerk nicht existiert oder schreibgeschützt
ist (z.B. CD-ROMs).}
Function IsOpenFile (Var f : File) : Boolean ;
{Liefert True, falls die Datei noch offen ist.
Achtung: Assign (f,...) muß ausgeführt sein!}
Function IsOpenText (Var f : Text) : Boolean ;
{Dito für Textfiles.}
{Weitere Utilities zur Ein-/Ausgabe}
Procedure ExWriteLn (Var f : ExText ; s : String) ;
{WriteLn für eine untypisierte Datei (File).
Muß mit Reset/ReWrite (f,1) geöffnet worden sein.}
Procedure ExReadLn (Var f : ExText ; Var s : String) ;
{ReadLn für eine untypisierte Datei (File).
Muß mit Reset/ReWrite (f,1) geöffnet worden sein.}
Function TextFilePos (Var t : Text) : LongInt ;
{FilePos für Text-Dateien.}
Function TextFileSize (Var t : Text) : LongInt ;
{FileSize für Text-Dateien.}
Procedure TextSeek (Var t : Text ; Pos : LongInt) ;
{Seek für Text-Dateien. Diese Prozedur und die vorhergehenden beiden
Funktionen können genauso angewendet werden wie ihre entsprechenden
Gegenstücke für nicht-Text-Dateien (aus der Unit DOS); Fehler können
wie gewohnt mit IOResult abgefragt werden.}
Procedure WaitKey ;
{Wartet auf einen beliebigen Tastendruck.
Der Tastaturpuffer wird vorher und hinterher gelöscht.}
Function GetOption (s : String) : Char ;
{Wartet auf ein Taste, deren ASCII-Code in s enthalten ist.
Das Zeichen wird zurückgegeben und außerdem auf dem Bildschirm
ausgegeben. Kleinbuchstaben werden in Großbuchstaben gewandelt.
Der Tastaturpuffer wird vorher und hinterher gelöscht.}
Function GetQuietOption (s : String) : Char ;
{Dito, ohne Bildschirmausgabe.}
Function GetJaNein : Boolean ;
{Spezialfall: "GetJaNein := GetOption('JN')='J'"}
Function GetYesNo : Boolean ;
{Spezialfall: "GetYesNo := GetOption('YN')='Y'"}
{Noch mehr Utilities für den Bildschirm}
Procedure ScrollUp (x1,y1,x2,y2,nr,at : Byte) ;
{Scrollt das angegebene Rechteck um nr Zeilen nach oben, freiwerdende
Zeile werden mit dem Attribut at gefüllt. Zählung beginnt bei 0.}
Procedure ScrollDown (x1,y1,x2,y2,nr,at : Byte) ;
{Dito, scrollt nach unten.}
Procedure PrintAt (x,y : Integer ; Const s : String ; at : Byte) ;
{Gibt den String s mit dem Attribut at an der Position x/y aus, die
Zählung beginnt bei 1. Verwendet die aktuelle Cursorposition, wenn
x=0 und/oder y=0. Führt auch nötigenfalls ein Scrolling durch.}
Function Tab (n : Integer) : String ;
{Am besten ein Beispiel: "WriteLn ('abc',Tab(20),'xyz')". Die
Zählung beginnt bei 1. Ist die betreffende Position bereits
überschritten, ändert sich nichts (man bekommt einen Leerstring).}
Function LeftEq (Const s : String ; n : Integer) : String ;
{Das Gegenstück zu "WriteLn ('Test':15)": "WriteLn (LeftEq('Test',15))".
Ist der String zu lang, wird rechts abgeschnitten.}
Procedure StringOf (Var s : String ; c : Char ; b : Byte) ;
{Erzeugt einen String, der das Zeichen c b-mal enthält.}
Function fStringOf (c : Char ; b : Byte) : String ;
{Dito, als Funktion.}
Function WordStr (w : Word) : String ;
Function IntStr (i : Integer) : String ;
Function LongStr (l : LongInt) : String ;
{Entsprechen Str als Funktionen, z.B. "WriteLn (LeftEq(WordStr(w),12))".}
Procedure PingCursor ;
{Merkt sich die aktuelle Cursorposition.}
Procedure PongCursor ;
{Setzt den Cursor auf die zuletzt gemerkte Position.}
Function Clock : LongInt ;
{Liefert die Systemzeit (ab Mitternacht) in 1/100 Sekunden, die
Genauigkeit ist aber nur 1/18.2 Sekunden.}
Function TimeIdent : LongInt ;
{Liefert Datum und Uhrzeit DOS-kodiert.}
Function lShl (l : LongInt ; c : Byte) : LongInt ;
Function lShr (l : LongInt ; c : Byte) : LongInt ;
{Shl and Shr fuer LongInts.}
Function MulDiv (m1,m2,d : Word) : Word ;
{(LongInt(m1)*LongInt(m2)) Div d}
Function LongHi (x : LongInt) : Word ;
Function LongLo (x : LongInt) : Word ;
{Liefern Hi- bzw. Lo-Word eines 32-Bit-Wertes.}
Function Hex (l : LongInt) : Str8 ;
{Liefert l als Hexzahl (soviele Stellen wie nötig).}
Function Hex2 (b : Byte) : Str2 ;
{Liefert b als 2stellige Hexzahl.}
Function Hex4 (w : Word) : Str4 ;
{Liefert w als 4stellige Hexzahl.}
Function Hex8 (l : LongInt) : Str8 ;
{Liefert l als 8stellige Hexzahl.}
Function Hex2Dec (Const h : Str8 ; Var l : LongInt) : Boolean ;
{Wandelt eine 0- bis 8-stellige Hexzahl in einen Dezimalwert um.
Ergebnis ist True bei Erfolg, False bei ungültigen Zeichen
(nicht in [0..9,a..f,A..F]). Bei False oder h='' ist l=0.}
Function Lead0 (l : LongInt ; f : Byte) : Str10 ;
{Liefert l mit führenden Nullen, mind. f Stellen.}
Function LeadSpc (l : LongInt ; f : Byte) : Str10 ;
{Liefert l mit führenden Leerzeichen, mind. f Stellen.}
Function Subst (s : String ; Const old,new : String) : String ;
{Ersetzt in s alle Vorkommen von 'old' durch 'new';
'old' und 'new' müssen nicht gleich lang sein.
ACHTUNG: 'new' darf nicht 'old' enthalten! In diesem Fall wird ein
Leerstring geliefert, um eine Endlosrekursion zu vermeiden.}
Procedure DeComment (Const com : String ; Var s : String) ;
{Löscht alles, was nach Kommentarzeichen (einschließlich) in s
folgt, Beispiel: DeComment ('#;%',inputline).}
Procedure Justify (Var s : String) ;
{Entfernt führende und abschließende Spaces, wandelt Tabs in Spaces
um, und komprimiert aufeinanderfolgende Spaces zu einem einzelnen
Space.}
Procedure DeSpace (Var s : String) ;
{Entfernt alle Spaces und Tabs.}
Function PartStr (Const s : String ; c : Char ; x : Integer) : String ;
{Liefert den x-ten Teilstring. Die einzelnen Teilstrings werden durch
'c' getrennt, die Zählung beginnt bei Null. Beipiel:
PartStr('ABC*123*XYZ','*',1) = '123'
Wenn s[1]=c gilt, beginnt die Zählung entsprechend bei 1.
Bei x<0 wird von rechts nach links gezaehlt:
PartStr('ABC*123*XYZ','*',-1) = 'XYZ'}
Function PartCount (Const s : String ; c : Char) : Word ;
{Ermittelt, wieviele Teilstrings s enthält. Mit anderen Worten, das
Ergebnis gibt an, wie oft c in s vorkommt, plus eins; Ausnahme:
bei einem Leerstring (s='') ist das Ergebnis Null.}
Function PartWidth (Const s : String ; c : Char) : Word ;
{Ermittelt die Länge des längsten Teilstrings in s.
Die einzelnen Teilstrings werden durch c getrennt.}
Function PPartStr (s : PChar ; c : Char ; x : Integer ; Dest : PChar) : PChar ;
Function PPartCount (s : PChar ; c : Char) : Word ;
Function PPartWidth (s : PChar ; c : Char) : Word ;
{Dito für Nullterminierte Strings bis 65535 Zeichen Länge.}
Function PPartStart (s : PChar ; c : Char ; x : Integer) : PChar ;
{Ähnlich PPartStr, liefert aber nur Zeiger auf den Anfang des
entsprechenden Teilstrings in `s'. Liefert NIL, wenn Teilstring
nicht enthalten ist oder Länge Null hat.}
Function StrGetMem (Var p : PChar ; Len : Word) : PChar ;
{Belegt Speicher für einen Z-String mit maximaler Länge `Len'
(d.h. Len+1 Bytes) und liefert einen Zeiger darauf in `p' und
als Funktionsergebnis. Im Fehlerfalle (nicht genug Speicher)
NIL.}
Procedure StrFreeMem (Var p : PChar ; Len : Word) ;
{Gibt den Speicher wieder frei und setzt `p' auf NIL.}
Function UpdateCRC32 (InitCRC : LongInt ; Var InBuf ; InLen : Word) : LongInt ;
{Berechnet einen CRC32 von `InLen' Bytes ab `InBuf', basierend auf
`InitCRC'. Der anfängliche CRC32 sollte -1 ($ffffffff) sein, und
der abschließende sollte invertiert werden (Not).
Kompatibel mit ZIP und Zmodem.}
Type PCProc = Procedure (p : Word ; c : Char ; Cursor : Boolean) ;
{Schreibt Zeichen c an Position p (Basis 1), mit Cursor wenn
`Cursor' = True (z.B. invertiert).}
Function EnterString (s : pChar ; maxlen : Word ; PrintChar : PCProc) : Boolean ;
{Eingabe eines Strings (mit Vorgabe) s^ mit maximaler Länge `maxlen',
zum Schreiben wird die Prozedur `PrintChar' benutzt.
Ergebnis is True, wenn Eingabe mit Enter-Taste bestätigt wurde, bzw.
False, wenn mit Esc abgebrochen wurde (s^ unverändert).}
{------ Maus-Funktionen ------}
Function InitMouse : Boolean ;
{Initialisiert den Maustreiber und liefert True, wenn einer
installiert ist. Der Mauszeiger ist noch nicht sichtbar.}
Procedure ResetMouse ;
{Nur Software-Reset.}
Procedure HideMouse ;
{Macht den Mauszeiger unsichtbar.}
Procedure ShowMouse ;
{Macht den Mauszeiger sichtbar.}
Procedure SetFrame (x1,y1,x2,y2 : Word) ;
{Legt den Bereich fest, in dem sich der Mauszeiger bewegen darf.
Zählung beginnt bei 0.}
Function GetMouse : Word ;
{Liefert Tastenstatus: Bit 0 = linke Taste, Bit 1 = rechte Taste,
Bit 2 = mittlere Taste (falls vorhanden).
Ein Aufruf dieser Funktion aktualisiert außerdem die Mauskoordinaten
in mx und my.}
Procedure SetMouse (x,y : Word) ;
{Setzt den Mauszeiger auf die angegeben Position.}
Procedure DefineMickey (Horiz,Vertic : Word) ;
{Hiermit kann man die Auflösung der Maus einstellen, und damit
die Geschwindigkeit des Mauszeigers.}
Procedure GetMickey (Var Horiz,Vertic : Integer) ;
{Liefert den Stand des Bewegungszählers der Maus.}
Procedure WaitButton ;
{Wartet auf das Betätigen einer Maustaste oder einer Taste auf der
Tastatur. Sollte beim Aufruf bereits eine Maustaste gedrückt sein,
wird erst gewartet, bis sie losgelassen wird.
Der Tastaturpuffer wird vorher und hinterher gelöscht.}
Procedure SetMouseCursor (sm,cm : Word) ;
{Schaltet auf Software-Mauscursor um und definiert sein Aussehen:
Der Bildschirm-Wert wird zuerst mit sm AND-verknüpft und dann mit
cm XOR-verknüpft. Das Low-Byte ist jeweils für den Zeichencode
zuständig, das High-Byte für das Attribut.}
Procedure SetMousePointer (Var scm ; hotx,hoty : Integer) ;
{Definiert das Aussehen das Mauspointers im Grafikmodus. scm ist ein
Feld von 16 Screenmask(sm)-Worten und 16 Cursormask(cm)-Worten:
sm=0: cm=0: Schwarz (Farbe 0), cm=1: Weiss (Farbe 15),
sm=1: cm=0: Transparent, cm=1: Invertierend,
hotx und hoty geben die Position des "Hot Spot" an, bezogen auf die
linke obere Ecke des Pointers, sie können Wert von -16 bis 16
annehmen.}
Procedure SetUpdateFrame (x1,y1,x2,y2 : Word) ;
{Definiert einen rechteckigen Bereich, innerhalb dessen ein Update
(oder irgendeine Grafikaktion) stattfindet. Wenn der Mauspointer diesen
Bereich berührt, wird ein HideMouse durchgeführt.
Ein Aufruf von ShowMouse macht diese Prozedur wieder rückgängig (egal,
ob HideMouse durchgeführt wurde oder nicht).
Diese Funktion benötigt unbedingt einen Microsoft-kompatiblen Maustreiber,
bei Genius-Mäusen mindestens Treiberversion 9.06.}
{===========================================================================}
Implementation
Const HexDig : Array [0..15] Of Char = '0123456789abcdef' ;
Var r : Registers ;
Var x1,y1,x2,y2 : Word ;
Var KeyPends : Boolean ;
key : Char ;
Var PingX,PingY : Integer ;
Procedure Video (a,b,c,d : Word) ; Assembler ;
Asm
mov ax,a
mov bx,b
mov cx,c
mov dx,d
push bp
int 10h
pop bp
End {Video} ;
Procedure ClrScr ;
Begin
Video ($0600,TextAttr Shl 8,y1 Shl 8+x1,y2 Shl 8+x2) ;
GotoXY (1,1)
End {ClrScr} ;
Procedure GotoXY (x,y : Byte) ;
Begin
Video ($0200,0,0,Word(Pred(y))Shl 8+Pred(x))
End {GotoXY} ;
Function WhereX : Byte ; Assembler ;
Asm
mov ax,0300h
push bp
int 10h
pop bp
mov al,dl
inc al
End {WhereX} ;
Function WhereY : Byte ; Assembler ;
Asm
mov ax,0300h
push bp
int 10h
pop bp
mov al,dh
inc al
End {WhereY} ;
Function KeyPressed : Boolean ;
Begin
If KeyPends Then Begin
KeyPressed := True ;
Exit
End ;
r.ah := $01 ;
Intr ($16,r) ;
KeyPressed := r.flags And $40=0
End {KeyPressed} ;
Function ReadKey : Char ;
Begin
If KeyPends Then Begin
KeyPends := False ;
ReadKey := Key
End
Else Begin
r.ah := 0 ;
Intr ($16,r) ;
ReadKey := Char(r.al) ;
If r.al=0 Then Begin
KeyPends := True ;
Key := Char(r.ah)
End
End
End {ReadKey} ;
Procedure FeedKey (k : Char) ;
Begin
KeyPends := True ;
Key := k
End {FeedKey} ;
Procedure InsLine ; Assembler ;
Asm
mov ax,0300h
push bp
int 10h
mov ax,0701h
mov bh,TextAttr
xor bl,bl
mov ch,dh
mov cl,Byte Ptr x1
mov dh,Byte Ptr y2
mov dl,Byte Ptr x2
int 10h
pop bp
End {InsLine} ;
Procedure DelLine ; Assembler ;
Asm
mov ax,0300h
push bp
int 10h
mov ax,0601h
mov bh,TextAttr
xor bl,bl
mov ch,dh
mov cl,Byte Ptr x1
mov dh,Byte Ptr y2
mov dl,Byte Ptr x2
int 10h
pop bp
End {DelLine} ;
Procedure ClrLine ; Assembler ;
Asm
mov ax,0300h
push bp
int 10h
mov ax,0600h
mov bh,TextAttr
xor bl,bl
mov ch,dh
mov cl,Byte Ptr x1
mov dl,Byte Ptr x2
int 10h
pop bp
End {DelLine} ;
Procedure ClrLines (yy1,yy2 : Integer) ;
Begin
If yy1=-1 Then
yy1 := y1 ;
If yy2=-1 Then
yy2 := y2 ;
Video ($0600,TextAttr Shl 8,yy1 Shl 8+x1,yy2 Shl 8+x2) ;
GotoXY (1,Succ(yy1))
End {ClrScr} ;
Procedure Center (s : String) ;
Var i,a : Word ;
Begin
a := Succ(MaxX)*Pred(WhereY) Shl 1-2 ;
i := Succ(MaxX-Length(s))Shr 1 ;
Move (s[1],s[Succ(i)],Length(s)) ;
FillChar (s[1],i,32) ;
FillChar (s[Succ(length(s)+i)],Succ(MaxX)-Length(s)-i,32) ;
For i:=1 To Succ(MaxX) Do
MemW[Segb800:a+i Shl 1] := TextAttr Shl 8+Byte(s[i])
End {Center} ;
Procedure LeftAlign (s : String) ;
Var i,a : Word ;
Begin
a := Succ(MaxX)*Pred(WhereY) Shl 1-2 ;
FillChar (s[Succ(length(s))],Succ(MaxX)-Length(s),32) ;
For i:=1 To Succ(MaxX) Do
MemW[Segb800:a+i Shl 1] := TextAttr Shl 8+Byte(s[i])
End {LeftAlign} ;
Procedure RightAlign (s : String) ;
Var i,a : Word ;
Begin
a := Succ(MaxX)*Pred(WhereY) Shl 1-2 ;
i := Succ(MaxX-Length(s)) ;
Move (s[1],s[Succ(i)],Length(s)) ;
FillChar (s[1],i,32) ;
For i:=1 To Succ(MaxX) Do
MemW[Segb800:a+i Shl 1] := TextAttr Shl 8+Byte(s[i])
End {RightAlign} ;
Procedure ClrKeyBuf ;
Begin
While KeyPressed Do
If ReadKey=#0 Then
If ReadKey=#0 Then
End {ClrKeyBuf} ;
Procedure Beep ;
Begin
Sound (1000) ;
Delay (100) ;
NoSound
End {Beep} ;
Procedure Buup ;
Var w : Word ;
Begin
For w := 450 DownTo 250 Do Begin
Sound (w) ;
Delay (1)
End ;
NoSound
End {Buup} ;
Procedure WaitVerticalRetrace ; Assembler ;
Asm
mov dx,03dah
@vr: in al,dx
test al,08h
jnz @vr
@nvr: in al,dx
test al,08h
jz @nvr
End {WaitVerticalRetrace} ;
Procedure WriteStdErr (Const s : String) ;
Var w : Word ;
c : Char ;
Begin
For w:=1 To Length(s) Do Begin
c := s[w] ;
Asm
mov ah,0eh
mov al,c
xor bx,bx
push bp
int 10h
pop bp
End
End
End {WriteStdErr} ;
Procedure Sound (Hz : Word) ;
Var bbb : Byte ;
Begin
If Hz<=18 Then
Exit ;
Hz := $1234dd Div Hz ;
bbb := Port[$61] ;
If bbb And $03=0 Then Begin
Port[$61] := bbb Or $03 ;
Port[$43] := $b6 {Binaer, Modus 3, Lo/Hi-Byte, Counter 2}
End ;
Port[$42] := Lo(Hz) ;
Port[$42] := Hi(Hz)
End {Sound} ;
Procedure NoSound ;
Begin
Port[$61] := Port[$61] And $fc
End {NoSound} ;
Function Counter : Word ; Assembler ;
Asm
in al,$40
mov ah,al
in al,$40
xchg ah,al
End {Counter} ;
Function LCounter : LongInt ; Assembler ;
Asm
pushf
cli
in al,$40
mov ah,al
in al,$40
xchg ah,al
mov dx,Seg0040
mov es,dx
mov dx,Word Ptr es:$006c
not dx
popf
End {Counter} ;
Procedure WaitApprox (w : Word) ;
Begin
While Counter-w<49152 Do
End {WaitApprox} ;
Procedure Delay (w : Word) ;
Var wll : LongInt ;
tm : Word ;
Begin
tm := Counter ;
wll := LongInt(w)*1193 ;
While wll>65535 Do Begin
WaitApprox (tm XOr $8000) ;
WaitApprox (tm) ;
Dec (wll,65536)
End ;
If wll>32767 Then
WaitApprox (tm XOr $8000) ;
WaitApprox (tm-Word(wll))
End {Delay} ;
Procedure Move (Var Source,Dest ; Count : Word) ; Assembler ;
Asm
push ds
mov cx,Count
jcxz @1
lds si,[Source]
les di,[Dest]
cld
test di,1
jz @0
movsb
dec cx
@0: shr cx,1
rep movsw
jnc @1
movsb
@1: pop ds
End {Move} ;
Procedure FillByte (Var X ; Count : Word ; Value : Byte) ; Assembler ;
Asm
mov cx,Count
jcxz @1
mov al,Value
mov ah,al
les di,[X]
cld
test di,1
jz @0
stosb
dec cx
@0: shr cx,1
rep stosw
jnc @1
stosb
@1:
End {FillByte} ;
Procedure FillWord (Var X ; Count : Word ; Value : Word) ; Assembler ;
Asm
mov cx,Count
jcxz @1
mov ax,Value
les di,[X]
cld
test di,1
jz @0
stosb
xchg al,ah
dec cx
jz @2
rep stosw
@2: stosb
jmp @1
@0: rep stosw
@1:
End {FillWord} ;
Procedure Fill3Byt (Var X ; Count : Word ; Value : LongInt) ; Assembler ;
Asm
mov cx,Count
jcxz @1
mov ax,Word Ptr Value
mov bl,Byte Ptr Value+2
les di,[X]
cld
@0: stosw
mov es:[di],bl
inc di
loop @0
@1:
End {Fill3Byt} ;
Procedure FillLong (Var X ; Count : Word ; Value : LongInt) ; Assembler ;
Asm
mov cx,Count
jcxz @1
mov ax,Word Ptr Value
mov bx,Word Ptr Value+2
mov dx,2
les di,[X]
cld
@0: stosw
mov es:[di],bx
add di,dx
loop @0
@1:
End {FillLong} ;
Procedure FillGen (Var X ; Count : Word ; Value : LongInt ; size : Byte) ;
Begin
Case size Of
1 : FillByte (X,Count,Value) ;
2 : FillWord (X,Count,Value) ;
3 : Fill3Byt (X,Count,Value) ;
4 : FillLong (X,Count,Value)
End
End {FillGen} ;
Function Quest (Cond : Boolean ; a,b : LongInt) : LongInt ;
Begin
If Cond Then
Quest := a
Else
Quest := b
End {Quest} ;
Function CQuest (Cond : Boolean ; a,b : Char) : Char ;
Begin
If Cond Then
CQuest := a
Else
CQuest := b
End {CQuest} ;
Function SQuest (Cond : Boolean ; Const a,b : String) : String ;
Begin
If Cond Then
SQuest := a
Else
SQuest := b
End {SQuest} ;
Function Quest2 (Cond1,Cond0 : Boolean ; a00,a01,a10,a11 : LongInt) : LongInt ;
Begin
If Cond1 Then
If Cond0 Then
Quest2 := a11
Else
Quest2 := a10
Else
If Cond0 Then
Quest2 := a01
Else
Quest2 := a00
End {Quest2} ;
Function LoCase (c : Char) : Char ;
Begin
If c In ['A'..'Z'] Then Asm
mov al,c
add al,20h
mov @result,al
End
Else
LoCase := c
End {LoCase} ;
Function UpperCase (Const s : String) : String ;
Var i : Integer ;
Begin
UpperCase[0] := s[0] ;
For i:=1 To Length(s) Do
UpperCase[i] := UpCase(s[i])
End {UpperCase} ;
Function LowerCase (Const s : String) : String ;
Var i : Integer ;
Begin
LowerCase[0] := s[0] ;
For i:=1 To Length(s) Do
LowerCase[i] := LoCase(s[i])
End {LowerCase} ;
Function IDist (i1,i2,x : LongInt) : LongInt ;
Begin
If x<i1 Then
IDist := i1-x
Else
If x>i2 Then
IDist := x-i2
Else
IDist := 0
End {IDist} ;
Function Bound (x,min,max : LongInt) : LongInt ;
Begin
If x<min Then
Bound := min
Else If x>max Then
Bound := max
Else
Bound := x
End {Bound} ;
Function Max (w1,w2 : LongInt) : LongInt ;
Begin
if w1>w2 Then
Max := w1
Else
Max := w2
End {Max} ;
Function Min (w1,w2 : LongInt) : LongInt ;
Begin
if w1<w2 Then
Min := w1
Else
Min := w2
End {Min} ;
Function Even (x : LongInt) : Boolean ;
Begin
Even := Not Odd(x)
End {Even} ;
Function ggT (a,b : LongInt) : LongInt ;
Var c,d : LongInt ;
Begin
d := a Mod b ;
While d<>0 Do Begin
c := b ;
b := d ;
a := c ;
d := a Mod b
End ;
ggT := b
End {ggT} ;
Function kgV (a,b : LongInt) : LongInt ;
Var c : LongInt ;
Begin
c := ggT(a,b) ;
If c<>0 Then
kgV := (a Div c)*b
Else
kgV := 0
End {kgV} ;
Function Sgn (x : LongInt) : ShortInt ; Assembler ;
Asm
xor ax,ax
mov bx,word ptr x+2
test bh,80h
jnz @neg
or bx,word ptr x
jz @z
mov ax,1
jmp @z
@neg: not ax
@z:
End {Sgn} ;
Function Diff (a,b : LongInt) : LongInt ;
Begin
If a<b Then
Diff := b-a
Else
Diff := a-b
End {Diff} ;
Function GetPDir (Const n : String) : DirStr ;
Var Dir : DirStr ;
Name : NameStr ;
Ext : ExtStr ;
Begin
FSplit (n,Dir,Name,Ext) ;
GetPDir := Dir
End {GetPDir} ;
Function GetRawDir (Const n : String) : DirStr ;
Var Dir : DirStr ;
Name : NameStr ;
Ext : ExtStr ;
Begin
FSplit (n,Dir,Name,Ext) ;
GetRawDir := Copy(Dir,3,Length(Dir)-3)
End {GetRawDir} ;
Function GetName (Const n : String) : NameStr ;
Var Dir : DirStr ;
Name : NameStr ;
Ext : ExtStr ;
Begin
FSplit (n,Dir,Name,Ext) ;
GetName := Name
End {GetName} ;
Function GetExt (Const n : String) : ExtStr ;
Var Dir : DirStr ;
Name : NameStr ;
Ext : ExtStr ;
Begin
FSplit (n,Dir,Name,Ext) ;
GetExt := Ext
End {GetExt} ;
Function GetXt (Const n : String) : ExtStr ;
Var Dir : DirStr ;
Name : NameStr ;
Ext : ExtStr ;
Begin
FSplit (n,Dir,Name,Ext) ;
GetXt := Copy(Ext,2,3)
End {GetXt} ;
Function GetNExt (Const n : String) : NExtStr ;
Var Dir : DirStr ;
Name : NameStr ;
Ext : ExtStr ;
Begin
FSplit (n,Dir,Name,Ext) ;
GetNExt := Name+Ext
End {GetNExt} ;
Function GetDName (Const n : String) : PathStr ;
Var Dir : DirStr ;
Name : NameStr ;
Ext : ExtStr ;
Begin
FSplit (n,Dir,Name,Ext) ;
GetDName := Dir+Name
End {GetDName} ;
Function GetDrive (Const n : String) : Str2 ;
Begin
GetDrive := UpperCase(Copy(n,1,2))
End {GetDrive} ;
Function ExtPath (Const n,e : String) : PathStr ;
Var i : Integer ;
Begin
i:=Length(n) ;
While (i>0)And(n[i]<>'.')And(n[i]<>'\') Do
Dec(i) ;
If (i=0)Or(n[i]='\') Then
ExtPath:=n+'.'+e
Else
ExtPath:=n
End {ExtPath} ;
Function NormName (n : NExtStr) : NExtStr ;
Var nam : NameStr ;
ext : ExtStr ;
p : Word ;
Begin
p := Pos('.',n) ;
If p=0 Then Begin
n := n+'.' ;
p := Succ(Length(n))
End ;
FillByte (nam[1],8,32) ;
FillByte (ext[1],3,32) ;
nam := Copy(n,1,Pred(p)) ;
ext := Copy(n,Succ(p),3) ;
nam[0] := #8 ;
ext[0] := #3 ;
NormName := nam+'.'+ext
End {NormName} ;
Function NormDirn (Const n : NExtStr) : NExtStr ;
Var nam : NameStr ;
ext : ExtStr ;
p : Word ;
Begin
If n[1]='.' Then
p := Succ(Length(n))
Else Begin
p := Pos('.',n) ;
If p=0 Then
p := Succ(Length(n))
End ;
FillByte (nam[1],8,32) ;
FillByte (ext[1],3,32) ;
nam := Copy(n,1,Pred(p)) ;
ext := Copy(n,Succ(p),3) ;
nam[0] := #8 ;
ext[0] := #3 ;
If ext=' ' Then
NormDirn := nam+#32+ext
Else
NormDirn := nam+'.'+ext
End {NormDirn} ;
Procedure NormDir (Var d : DirStr) ;
Begin
If d[Length(d)]<>'\' Then
d := d+'\'
End {NormDir} ;
Function fNormDir (Const d : DirStr) : DirStr ;
Begin
If d[Length(d)]<>'\' Then
fNormDir := d+'\'
Else
fNormDir := d
End {fNormDir} ;
Function NormChDir (d : DirStr) : DirStr ;
Begin
If (d[Length(d)]='\') And ((Length(d)<>3) Or (d[2]<>':')) Then
Dec (d[0]) ;
NormChDir := d
End {NormChDir} ;
Function WildExpand (n : NExtStr) : NExtStr ;
Var p : Word ;
Begin {WildExpand}
n := NormName(n) ;
p := Pos('*',n) ;
If (p<>0) And (p<9) Then Begin
For p:=p To 8 Do
n[p] := '?' ;
p := Pos('*',n)
End ;
If p<>0 Then
For p:=p To 12 Do
n[p] := '?' ;
WildExpand := n
End {WildExpand} ;
Function Matches (n : NExtStr ; Const mask : NExtStr) : Boolean ;
Var i : Word ;
Begin
n := NormName(n) ;
Matches := False ;
For i:=1 To 12 Do
If mask[i]<>'?' Then
If mask[i]<>n[i] Then
Exit ;
Matches := True
End {Matches} ;
Function TempDir : PathStr ;
Var t : PathStr ;
Begin
t := GetEnv('TEMP') ;
If t[0]=#0 Then Begin
t := GetEnv('TMP') ;
If t[0]=#0 Then
t := 'C:\'
End ;
If t[Length(t)]<>'\' Then
t := t+'\' ;
TempDir := t
End {TempDir} ;
Function ProcessFiles (Const mask : PathStr ; opt : Word ; job : PathProc) : LongInt ;
Var Search : SearchRec ;
Dir : DirStr ;
NExt : NExtStr ;
Count : LongInt ;
Begin
Count := 0 ;
Dir := GetPDir(mask) ;
NExt := GetNExt(mask) ;
Search.Name := NExt ;
FindFirst (mask,$3f,Search) ;
While DosError=0 Do Begin
job (Dir,Search) ;
Inc (Count) ;
FindNext (Search)
End ;
If opt And Recursive<>0 Then Begin
Search.Name := '*.*' ;
FindFirst (Dir+'*.*',$33,Search) ;
While DosError=0 Do Begin
If (Search.Attr And $10)=$10 Then
If (Search.Name<>'.') And (Search.Name<>'..') Then
Inc (Count,ProcessFiles(Dir+Search.Name+'\'+NExt,opt,job)) ;
FindNext (Search)
End
End ;
ProcessFiles := Count
End {ProcessFiles} ;
Function PathEq (n : String) : PathStr ;
Var slash,i : Integer ;
Begin
slash := 0 ;
For i:=Length(n) DownTo 1 Do
If (n[i]='\') Or (n[i]='\') Then Begin
slash := i ;
Break
End ;
While Length(n)<slash+12 Do
n := n+#32 ;
PathEq := n
End {PathEq} ;
Procedure ChangeDir (d : String) ;
Begin
d := NormChDir(d)+#0 ;
r.ah := $3b ;
r.dx := Ofs(d[1]) ;
r.ds := Seg(d[1]) ;
Intr ($21,r) ;
If r.flags And fcarry <>0 Then
InOutRes := 3
End {ChangeDir} ;
Function QuietFileSize (Const n : PathStr) : LongInt ;
Var s : SearchRec ;
Begin
s.Name := GetNExt(n) ;
FindFirst (n,$3f,s) ;
If DosError<>0 Then
QuietFileSize := -2
Else If s.Attr And $18 <>0 Then
QuietFileSize := -1
Else
QuietFileSize := s.Size
End {QuietFileSize} ;
Function Exists (Const n : String) : Boolean ;
Var f : File ;
a : Word ;
Begin
Assign (f,n) ;
GetFAttr (f,a) ;
Exists := DosError=0
End {Exists} ;
Function IsDir (Const n : String) : Boolean ;
Var f : File ;
a : Word ;
Begin
If n[Length(n)]='\' Then
IsDir := True
Else Begin
Assign (f,n) ;
GetFAttr (f,a) ;
IsDir := (a And $10=$10) And (DosError=0)
End
End {IsDir} ;
Function IsFile (Const n : String) : Boolean ;
Var f : File ;
a : Word ;
Begin
Assign (f,n) ;
GetFAttr (f,a) ;
IsFile := (a And $18=0) And (DosError=0)
End {IsFile} ;
Function IsEmpty (n : DirStr) : Boolean ;
Var s : SearchRec ;
Begin
NormDir (n) ;
s.Name := '*.*' ;
FindFirst (n+'*.*',$3f,s) ;
While (DosError=0)
And ((s.Name='.') Or (s.Name='..') Or (s.Attr And $08=$08)) Do
FindNext (s) ;
IsEmpty := DosError=18
End {IsEmpty} ;
Function Writeable (d : Char) : Boolean ;
Var f : File ;
Begin
Assign (f,d+':\awritest.$$$') ;
ReWrite (f,1) ;
If IOResult<>0 Then
Writeable := False
Else Begin
Close (f) ;
Erase (f) ;
Writeable := IOResult=0
End
End {Writeable} ;
Function IsOpenFile (Var f : File) : Boolean ;
Begin
IsOpenFile := FileRec(f).Mode <> fmClosed
End {IsOpenFile} ;
Function IsOpenText (Var f : Text) : Boolean ;
Begin
IsOpenText := TextRec(f).Mode <> fmClosed
End {IsOpenText} ;
Procedure ExWriteLn (Var f : ExText ; s : String) ;
Begin
s := s+CrLf ;
BlockWrite (f,s[1],Length(s))
End {ExWriteLn} ;
Procedure ExReadLn (Var f : ExText ; Var s : String) ;
Var t : String ;
p : LongInt ;
e : Integer ;
r : Word ;
Begin
p := FilePos(f) ;
BlockRead (f,t[1],255,r) ;
t[0] := Char(r) ;
e := Pos(CrLf,t) ;
If e>0 Then
t[0] := Char(Pred(e)) ;
Seek (f,p+Byte(t[0])+2) ;
s := t
End {ExReadLn} ;
Function TextFilePos (Var t : Text) : LongInt ;
Begin
r.ax := $4201 ;
r.bx := TextRec(t).Handle ;
r.cx := 0 ;
r.dx := 0 ;
Intr ($21,r) ;
If r.flags And fcarry=0 Then
TextFilePos := LongInt(r.dx)*65536+r.ax+TextRec(t).BufPos
-TextRec(t).BufEnd
Else Begin
InOutRes := r.ax ;
TextFilePos := 0
End
End {TextFilePos} ;
Function TextFileSize (Var t : Text) : LongInt ;
Var l : LongInt ;
Begin
If TextRec(t).Mode=fmInput Then Begin
l := TextFilePos(t) ;
r.ax := $4202 ;
r.bx := TextRec(t).Handle ;
r.cx := 0 ;
r.dx := 0 ;
Intr ($21,r) ;
If r.flags And fcarry=0 Then
TextFileSize := LongInt(r.dx)*65536+r.ax
Else Begin
InOutRes := r.ax ;
TextFileSize := 0
End ;
TextSeek (t,l)
End
Else If TextRec(t).Mode=fmOutput Then
TextFileSize := TextFilePos(t)
Else Begin
InOutRes := 1 ;
TextFileSize := 0
End
End {TextFileSize} ;
Procedure TextSeek (Var t : Text ; Pos : LongInt) ;
Var w : Record l,h : Word End Absolute Pos ;
Begin
If TextFilePos(t)=Pos Then
Exit ;
If TextRec(t).Mode=fmOutput Then
Flush (t) ;
TextRec(t).BufPos := 0 ;
TextRec(t).BufEnd := 0 ;
r.ax := $4200 ;
r.bx := TextRec(t).Handle ;
r.cx := w.h ;
r.dx := w.l ;
Intr ($21,r) ;
If r.flags And fcarry<>0 Then
InOutRes := r.ax
End {TextSeek} ;
Procedure WaitKey ;
Begin
ClrKeyBuf ;
While Not KeyPressed Do Nothing ;
ClrKeyBuf
End {WaitKey} ;
Function GetJaNein : Boolean ;
Begin
GetJaNein := GetOption('JN')='J'
End {GetJaNein} ;
Function GetYesNo : Boolean ;
Begin
GetYesNo := GetOption('YN')='Y'
End {GetYesNo} ;
Function GetOption (s : String) : Char ;
Var c : Char ;
Begin
s := UpperCase(s) ;
ClrKeyBuf ;
Repeat
c := ReadKey ;
If c=#0 Then
c := Chr(0*Ord(ReadKey)) ;
c := UpCase(c)
Until Pos(c,s)<>0 ;
WriteLn (c) ;
GetOption := c ;
ClrKeyBuf
End {GetOption} ;
Function GetQuietOption (s : String) : Char ;
Var c : Char ;
Begin
s := UpperCase(s) ;
ClrKeyBuf ;
Repeat
c := ReadKey ;
If c=#0 Then
c := Chr(0*Ord(ReadKey)) ;
c := UpCase(c)
Until Pos(c,s)<>0 ;
GetQuietOption := c ;
ClrKeyBuf
End {GetQuietOption} ;
Procedure ScrollUp(x1,y1,x2,y2,nr,at : Byte) ;
Begin
r.al := nr ;
r.ch := y1 ;
r.cl := x1 ;
r.dh := y2 ;
r.dl := x2 ;
r.bh := at ;
r.ah := 6 ;
Intr ($10,r)
End {ScrollUp} ;
Procedure ScrollDown(x1,y1,x2,y2,nr,at : Byte) ;
Begin
r.al := nr ;
r.ch := y1 ;
r.cl := x1 ;
r.dh := y2 ;
r.dl := x2 ;
r.bh := at ;
r.ah := 7 ;
Intr ($10,r)
End {ScrollDown} ;
Procedure PrintAt(x,y : Integer ; Const s : String ; at : Byte) ;
Var i : Integer ;
Begin
If x<=0 Then x := WhereX ;
If y<=0 Then y := WhereY ;
For i:=1 To Length(s) Do Begin
GotoXY (x,y) ;
r.al := Byte(s[i]) ;
r.bl := at ;
r.bh := 0 ;
r.ah := $09 ;
r.cx := 1 ;
Intr ($10,r) ;
Inc (x)
End
End {PrintAt} ;
{
************
* Anwendungsbeispiel:
* WriteLn ('abc',Tab(20),'xyz') ;
* Offset ist 1. Hat der Cursor die angegebene Spalte schon überschritten,
* wird ein Leerstring übergeben.
************}
Function Tab (n : Integer) : String ;
Var h : String ;
z : Integer ;
Begin
z := n-WhereX ;
If z<1 Then
Tab := ''
Else Begin
FillChar (h[1],z,32) ;
h[0] := Chr(z) ;
Tab := h
End ;
End {Tab} ;
{
**********
* Anwendungsbeispiel:
* WriteLn (LeftEq('abc',20),'xyz') ;
* Im Ergebnisstring ist s linksbündig enthalten. Ist er kürzer als n, so
* wird er mit Spaces aufgefüllt; ist er länger, wird rechts abgeschnit-
* ten. Eine rechtsbündige Ausgabe ist mit der normalen Write-Formatierung
* (per Doppelpunkt) zu erreichen.
**********}
Function LeftEq (Const s : String ; n : Integer) : String ;
Var h : String ;
Begin
If Length(s)=n Then
LeftEq := s
Else
If Length(s)>n Then
LeftEq := Copy(s,1,n)
Else Begin
FillChar (h[1],n,32) ;
h := s ;
h[0] := Chr(n) ;
LeftEq := h
End
End {LeftEq} ;
{StringOf() schreibt in den String s das Zeichen c b-mal.}
Procedure StringOf (Var s : String ; c : Char ; b : Byte) ;
Begin
FillChar (s[1],b,c) ;
s[0] := Char(b)
End {StringOf} ;
Function fStringOf (c : Char ; b : Byte) : String ;
Var s : String ;
Begin
FillChar (s[1],b,c) ;
s[0] := Char(b) ;
fStringOf := s
End {fStringOf} ;
Function WordStr (w : Word) : String ;
Var s : String[5] ;
Begin
Str (w,s) ;
WordStr := s
End {WordStr} ;
Function IntStr (i : Integer) : String ;
Var s : String[6] ;
Begin
Str (i,s) ;
IntStr := s
End {IntStr} ;
Function LongStr (l : LongInt) : String ;
Var s : String[11] ;
Begin
Str (l,s) ;
LongStr := s
End {LongStr} ;
Procedure PingCursor ;
Begin
PingX := WhereX ;
PingY := WhereY
End {PingCursor} ;
Procedure PongCursor ;
Begin
GotoXY (PingX,PingY)
End {PongCursor} ;
Function Clock : LongInt ;
Var h,m,s,s100 : Word ;
Begin
GetTime (h,m,s,s100) ;
Clock := 360000*h+6000*LongInt(m)+100*s+s100
End {Clock} ;
Function TimeIdent : LongInt ;
Var dt : DateTime ;
id : LongInt ;
dummy : Word ;
Begin
GetTime (dt.hour,dt.min,dt.sec,dummy) ;
GetDate (dt.year,dt.month,dt.day,dummy) ;
PackTime (dt,id) ;
TimeIdent := id
End {TimeIdent} ;
Function Hex2 (b : Byte) : Str2 ;
Begin
Hex2[0] := #2 ;
Hex2[1] := HexDig[b Shr 4] ;
Hex2[2] := HexDig[b And 15]
End {Hex2} ;
Function Hex4 (w : Word) : Str4 ;
Begin
Hex4[0] := #4 ;
Hex4[1] := HexDig[Hi(w) Shr 4] ;
Hex4[2] := HexDig[Hi(w) And 15] ;
Hex4[3] := HexDig[Lo(w) Shr 4] ;
Hex4[4] := HexDig[w And 15]
End {Hex4} ;
Function Hex8 (l : LongInt) : Str8 ;
Var w : Record l,h : Word End Absolute l ;
Begin
Hex8[0] := #8 ;
Hex8[1] := HexDig[Hi(w.h) Shr 4] ;
Hex8[2] := HexDig[Hi(w.h) And 15] ;
Hex8[3] := HexDig[Lo(w.h) Shr 4] ;
Hex8[4] := HexDig[w.h And 15] ;
Hex8[5] := HexDig[Hi(w.l) Shr 4] ;
Hex8[6] := HexDig[Hi(w.l) And 15] ;
Hex8[7] := HexDig[Lo(w.l) Shr 4] ;
Hex8[8] := HexDig[w.l And 15]
End {Hex8} ;
Function lShl (l : LongInt ; c : Byte) : LongInt ; Assembler ;
Asm
mov cl,c
cmp cl,16
je @e16
ja @a16
mov ax,Word Ptr l
mov dx,Word Ptr l+2
mov bx,ax
shl ax,cl
shl dx,cl
sub cl,16
neg cl
shr bx,cl
or dx,bx
jmp @z
@e16: mov dx,Word Ptr l
xor ax,ax
jmp @z
@a16: mov dx,Word Ptr l
xor ax,ax
sub cl,16
shl dx,cl
@z:
End {lShl} ;
Function lShr (l : LongInt ; c : Byte) : LongInt ; Assembler ;
Asm
mov cl,c
cmp cl,16
je @e16
ja @a16
mov ax,Word Ptr l
mov dx,Word Ptr l+2
mov bx,dx
shr ax,cl
shr dx,cl
sub cl,16
neg cl
shl bx,cl
or ax,bx
jmp @z
@e16: mov ax,Word Ptr l+2
xor dx,dx
jmp @z
@a16: mov ax,Word Ptr l+2
xor dx,dx
sub cl,16
shr ax,cl
@z:
End {lShr} ;
Function MulDiv (m1,m2,d : Word) : Word ; Assembler ;
Asm
mov ax,m1
mul m2
div d
End {MulDiv} ;
Function LongHi (x : LongInt) : Word ; Assembler ;
Asm
mov ax,Word Ptr x+2
End {LongHi} ;
Function LongLo (x : LongInt) : Word ; Assembler ;
Asm
mov ax,Word Ptr x
End {LongLo} ;
Function Hex2Dec (Const h : Str8 ; Var l : LongInt) : Boolean ;
Var tl : LongInt ;
i : Integer ;
Begin
Hex2Dec := False ;
l := 0 ;
tl := 0 ;
For i:=1 To Length(h) Do
Case UpCase(h[i]) Of
'0'..'9' : tl := lShl(tl,4) Or (Byte(h[i])-Byte('0')) ;
'A'..'F' : tl := lShl(tl,4) Or (Byte(UpCase(h[i]))-Byte('A')+10)
Else
Exit
End ;
Hex2Dec := True ;
l := tl
End {Hex2Dec} ;
Function Hex (l : LongInt) : Str8 ;
Var t : Str8 ;
Begin
t := Hex8(l) ;
While (t[0]>#1) And (t[1]='0') Do
Delete (t,1,1) ;
Hex := t
End {Hex} ;
Function Lead0 (l : LongInt ; f : Byte) : Str10 ;
Var ts : Str10 ;
Begin
Str (l:f,ts) ;
f := 1 ;
While ts[f]=#32 Do Begin
ts[f] := '0' ;
Inc (f)
End ;
Lead0 := ts
End {Lead0} ;
Function LeadSpc (l : LongInt ; f : Byte) : Str10 ;
Var ts : Str10 ;
Begin
Str (l:f,ts) ;
LeadSpc := ts
End {LeadSpc} ;
Function Subst (s : String ; Const old,new : String) : String ;
Var p : Integer ;
Begin
If Pos(old,new)<>0 Then
Subst := ''
Else Begin
p := Pos(old,s) ;
While p<>0 Do Begin
s := Copy(s,1,Pred(p))+new+Copy(s,p+Length(old),255) ;
p := Pos(old,s)
End ;
Subst := s
End
End {Subst} ;
Procedure DeComment (Const com : String ; Var s : String) ;
Var i,p : Integer ;
Begin
For i:=1 To Length(com) Do Begin
p := Pos(com[i],s) ;
If p<>0 Then
Delete (s,p,255)
End
End {DeComment} ;
Procedure Justify (Var s : String) ;
Var i : Integer ;
Begin
{Convert tabs to spaces:}
For i:=1 To Length(s) Do
If s[i]=#9 Then
s[i] := #32 ;
{Delete preceding spaces:}
For i:=1 To Length(s) Do
If s[i]<>#32 Then
Break ;
If i>Length(s) Then Begin
s[0] := #0 ;
Exit
End ;
If i>1 Then
Delete (s,1,Pred(i)) ;
{Delete trailing spaces:}
For i:=Length(s) DownTo 1 Do
If s[i]<>#32 Then
Break ;
If i<Length(s) Then
Delete (s,Succ(i),255) ;
{Compress spaces:}
i:=2 ;
While i<=Length(s)-2 Do Begin
While (s[i]=#32) And (s[Succ(i)]=#32) Do
Delete (s,i,1) ;
Inc (i)
End
End {Justify} ;
Procedure DeSpace (Var s : String) ;
Var p : Byte ;
Begin
p := Pos(#9,s) ;
While p<>0 Do Begin
Delete (s,p,1) ;
p := Pos(#9,s)
End ;
p := Pos(#32,s) ;
While p<>0 Do Begin
Delete (s,p,1) ;
p := Pos(#32,s)
End
End {DeSpace} ;
Function PartStr (Const s : String ; c : Char ; x : Integer) : String ;
Var i,j,p : Word ;
Begin
If x<0 Then Begin
j := 0 ;
For i:=1 To Length(s) Do
If s[i]=c Then
Inc (j) ;
Inc (x,Succ(j))
End ;
i := 1 ;
p := 0 ;
While (i<=Length(s)) And (p<x) Do Begin
If s[i]=c Then
Inc (p) ;
Inc (i)
End ;
If i>Length(s) Then Begin
PartStr := '' ;
Exit
End ;
j := i ;
While (j<=Length(s)) And (p=x) Do Begin
If s[j]=c Then
Inc (p) ;
Inc (j)
End ;
If p>x Then
Dec (j) ;
PartStr := Copy(s,i,j-i)
End {PartStr} ;
Function PartCount (Const s : String ; c : Char) : Word ;
Var w,i : Word ;
Begin
If s[0]=#0 Then Begin
PartCount := 0 ;
Exit
End ;
w := 1 ;
For i:=1 To Length(s) Do
If s[i]=c Then
Inc (w) ;
PartCount := w
End {PartCount} ;
Function PartWidth (Const s : String ; c : Char) : Word ;
Var w,maxw,i : Word ;
Begin
w := 0 ;
maxw := 0 ;
For i:=1 To Length(s) Do
If s[i]=c Then Begin
If w>maxw Then
maxw := w ;
w := 0
End
Else
Inc (w) ;
If w>maxw Then
PartWidth := w
Else
PartWidth := maxw
End {PartWidth} ;
Function PPartStart (s : PChar ; c : Char ; x : Integer) : PChar ;
Var p : Word ;
tp,tp2 : PChar ;
Begin
PPartStart := NIL ;
If (s=NIL) Or (s[0]=#0) Then
Exit ;
If x<0 Then Begin {x in positiven Wert umwandeln}
p := 0 ; {zählt die Parts}
tp := s ;
While True Do Begin
tp := StrScan(tp,c) ;
Inc (p) ;
If tp=NIL Then
Break
Else
Inc (tp)
End ;
Inc (x,p)
End ;
p := 0 ; {zählt die Parts}
tp := s ;
While (p<x) Do Begin
tp := StrScan(tp,c) ;
Inc (p) ;
If tp=NIL Then
Break
Else
Inc (tp)
End ; {tp zeigt auf Trennzeichen+1, oder NIL}
If (tp[0]=#0) Or (tp[0]=c) Then
PPartStart := NIL
Else
PPartStart := tp
End {PPartStart} ;
Function PPartStr (s : PChar ; c : Char ; x : Integer ; Dest : PChar) : PChar ;
Var tp,tp2 : PChar ;
Begin
PPartStr := Dest ;
If Dest=NIL Then
Exit ;
Dest[0] := #0 ;
tp := PPartStart(s,c,x) ;
If tp=NIL Then
Exit ;
tp2 := StrScan(tp,c) ;
If tp2=NIL Then
tp2 := StrEnd(tp) ;
StrLCopy (Dest,tp,tp2-tp)
End {PPartStr} ;
Function PPartCount (s : PChar ; c : Char) : Word ;
Var p : Word ;
Begin
p := 0 ;
If (s=NIL) Or (s[0]=#0) Then Begin
PPartCount := 0 ;
Exit
End ;
While True Do Begin
s := StrScan(s,c) ;
Inc (p) ;
If s=NIL Then
Break
Else
Inc (s)
End ;
PPartCount := p
End {PPartCount} ;
Function PPartWidth (s : PChar ; c : Char) : Word ;
Var w,maxw : Word ;
l : PChar ;
Begin
maxw := 0 ;
If (s=NIL) Or (s[0]=#0) Then Begin
PPartWidth := 0 ;
Exit
End ;
While True Do Begin
l := s ;
s := StrScan(l,c) ;
If s=NIL Then
s := StrEnd(l) ;
w := s-l ;
If w>maxw Then
maxw := w ;
If s[0]=#0 Then
Break
End ;
PPartWidth := maxw
End {PPartWidth} ;
Function StrGetMem (Var p : PChar ; Len : Word) : PChar ;
Begin
If MaxAvail<=Succ(Len) Then
p := NIL
Else
GetMem (p,Succ(Len)) ;
StrGetMem := p
End {StrGetMem} ;
Procedure StrFreeMem (Var p : PChar ; Len : Word) ;
Begin
If p<>NIL Then Begin
FreeMem (p,Succ(Len)) ;
p := NIL
End
End {StrFreeMem} ;
Function UpdateCRC32 (InitCRC : LongInt ; Var InBuf ; InLen : Word) : LongInt ;
External ; {$L CRC32.OBJ}
Function EnterString (s : pChar ; maxlen : Word ; PrintChar : PCProc) : Boolean ;
Const CursorOff = False ;
CursorOn = True ;
Var w,actp : Word ;
Ready,Cancel : Boolean ;
st : String ;
c : Char ;
Begin
st := StrPas(s) ;
For w:=1 To Length(st) Do
PrintChar (w,st[w],CursorOff) ;
actp := Succ(Length(st)) ;
PrintChar (actp,#32,CursorOn) ;
For w:=Succ(actp) To maxlen Do
PrintChar (w,#32,CursorOff) ;
Ready := False ;
Cancel := False ;
ClrKeyBuf ;
Repeat
c := ReadKey ;
If actp>Length(st) Then
PrintChar (actp,#32,CursorOff)
Else
PrintChar (actp,st[actp],CursorOff) ;
Case c Of
#0 : Case ReadKey Of
#75 : If actp>1 Then {left}
Dec (actp) ;
#77 : If actp<=Length(st) Then {right}
Inc (actp) ;
#71 : actp := 1 ; {home}
#79 : actp := Succ(Length(st)) ; {end}
#83 : If actp<=Length(st) Then Begin {delete}
Delete (st,actp,1) ;
For w:=Succ(actp) To Length(st) Do
PrintChar (w,st[w],CursorOff) ;
PrintChar (Succ(Length(st)),#32,CursorOff)
End ;
#115 : If actp>1 Then
Repeat
Dec (actp)
Until (actp=1) Or
(st[actp]<>#32) And (st[actp-1]=#32) ;
#116 : If actp<=Length(st) Then
Repeat
Inc (actp)
Until (actp>Length(st)) Or
(st[actp]<>#32) And (st[actp-1]=#32) ;
Else
Beep ;
ClrKeyBuf
End ;
#8 : If actp>1 Then Begin
Dec (actp) ;
Delete (st,actp,1) ;
For w:=actp To Length(st) Do
PrintChar (w,st[w],w=actp) ;
PrintChar (Succ(Length(st)),#32,CursorOff)
End ;
#13 : Ready := True ;
#27 : Cancel := True
Else
If Length(st)<maxlen Then Begin
st := Copy(st,1,Pred(actp))+c+Copy(st,actp,Succ(Length(st)-actp)) ;
Inc (actp) ;
For w:=Pred(actp) To Length(st) Do
PrintChar (w,st[w],CursorOff)
End
Else Begin
Beep ;
ClrKeyBuf
End
End ;
If actp>Length(st) Then
PrintChar (actp,#32,CursorOn)
Else
PrintChar (actp,st[actp],CursorOn)
Until Ready Or Cancel ;
If Ready Then
StrPCopy (s,st) ;
EnterString := Ready
End {EnterString} ;
{*************************
*** Maus-Funktionen ***
*************************}
Function InitMouse : Boolean ; Assembler ;
Asm
mov ax,3533h
int 21h {get int vector 33h}
xor ax,ax
test bx,bx
jnz @t
mov bx,es
test bx,bx
jz @f
@t: int 33h {ax still 0}
test ax,ax
jz @f {0 = no mouse driver}
mov ax,0001h
@f:
End {InitMouse} ;
Procedure ResetMouse ; Assembler ;
Asm
mov ax,0021h
int 33h
End {ResetMouse} ;
Procedure ShowMouse ; Assembler ;
Asm
mov ax,0001h
int 33h
End {ShowMouse} ;
Procedure HideMouse ; Assembler ;
Asm
mov ax,0002h
int 33h
End {HideMouse} ;
Procedure SetFrame (x1,y1,x2,y2 : Word) ; Assembler ;
Asm
mov ax,0007h
mov cx,x1
mov dx,x2
int 33h
mov ax,0008h
mov cx,y1
mov dx,y2
int 33h
End {SetFrame} ;
Function GetMouse : Word ; Assembler ;
Asm
mov ax,0003h
xor bx,bx
int 33h
mov mx,cx
mov my,dx
mov ax,bx
End {GetMouse} ;
Procedure SetMouse (x,y : Word) ; Assembler ;
Asm
mov ax,0004h
mov cx,x
mov dx,y
int 33h
End {SetMouse} ;
Procedure DefineMickey (Horiz,Vertic : Word) ; Assembler ;
Asm
mov ax,000fh
mov cx,Horiz
mov dx,Vertic
int 33h
End {DefineMickey} ;
Procedure GetMickey (Var Horiz,Vertic : Integer) ; Assembler ;
Asm
mov ax,000bh
int 33h
les di,Horiz
mov es:[di],cx
les di,Vertic
mov es:[di],dx
End {GetMickey} ;
Procedure WaitButton ;
Begin
While GetMouse<>0 Do Nothing ;
ClrKeyBuf ;
While Not KeyPressed And (GetMouse=0) Do Nothing ;
ClrKeyBuf
End {WaitButton} ;
Procedure SetMouseCursor (sm,cm : Word) ; Assembler ;
Asm
mov ax,000ah
xor bx,bx
mov cx,sm
mov dx,cm
int 33h
End {SetMouseCursor} ;
Procedure SetMousePointer (Var scm ; hotx,hoty : Integer) ; Assembler ;
Asm
mov ax,0009h
mov bx,hotx
mov cx,hoty
les dx,scm
int 33h
End {SetMousePointer} ;
Procedure SetUpdateFrame (x1,y1,x2,y2 : Word) ; Assembler ;
Asm
mov ax,0010h
mov cx,x1
mov dx,y1
mov si,x2
mov di,y2
int 33h
End {SetUpdateFrame} ;
Begin
MaxX := Pred(Mem[Seg0040:$004a]) ;
MaxY := Mem[Seg0040:$0084] ;
If (MaxY<24) Or (MaxY>95) Then
MaxY := 24 ;
x1 := 0 ;
y1 := 0 ;
x2 := MaxX ;
y2 := MaxY ;
TextAttr := Mem[SegB800:Succ(MaxY*Succ(MaxX)Shl 1)] ;
KeyPends := False ;
Port[$43] := $34 ; {Binaer, Modus 2, Lo/Hi-Byte, Counter 0}
Port[$40] := 0 ;
Port[$40] := 0
End.