home *** CD-ROM | disk | FTP | other *** search
- (* ----------------------------------------------------------------------- *)
- (* DIRLIB.PAS *)
- (* (c) 1987 Michael Ceol & PASCAL INT. *)
- (* Betriebssystem- und compilerunabhaengige Routinen der Directory-Biblio- *)
- (* thek. Diese rufen wiederum die "low level" Routinen in DIRMT.TUR, *)
- (* DIRMT.PSP bzw. DIRCP.TUR auf, um den eigentlichen Job zu erledigen. *)
-
- (* ein bischen Konvertierung: *)
- (* ----------------------------------------------------------------------- *)
- (* String in eine ASCIIZ-Zeichenfolge konvertieren, wie es von den *)
- (* Betriebssystemen benoetigt wird: *)
- PROCEDURE StrChr (VAR st: Dir_Str; VAR ch: Dir_Chr0);
- VAR i : INTEGER;
- BEGIN
- FOR i := 1 TO Length(st) DO ch[i] := st[i];
- ch[Succ(Length(st))] := Chr(0);
- END;
- (* ----------------------------------------------------------------------- *)
- (* ASCIIZ-Zeichenfolge in einen String konvertieren: *)
- PROCEDURE ChrStr (VAR ch: Dir_Chr0; VAR st: Dir_Str);
- VAR i : INTEGER;
- BEGIN
- i := 1; st := '';
- WHILE ch[i] <> Chr(0) DO BEGIN st := Concat(st,ch[i]); i := Succ(i); END;
- END;
- (* ----------------------------------------------------------------------- *)
- (* Dateinamen aus einem "Dir_Rec" (name[8], ext[3]) in einen gueltigen *)
- (* Dateinamen des Formats "name.ext" konvertieren: *)
- PROCEDURE MakeFileName (VAR direntry: Dir_Rec; VAR filename: Dir_Str);
- VAR i : INTEGER;
- BEGIN
- filename := '';
- WITH direntry DO BEGIN
- FOR i := 1 TO 8 DO (* die aufgefuellten Leerzeichen muessen weg ! *)
- IF name[i] <> ' ' THEN filename := Concat(filename, name[i]);
- IF ext <> ' ' THEN BEGIN (* gibt's Extension ? (3 Leerzeichen) *)
- filename := Concat(filename, '.'); (* ja, Trennpunkt und *)
- FOR i := 1 TO 3 DO (* Extension anfuegen *)
- IF ext[i] <> ' ' THEN filename := Concat(filename, ext[i]);
- END;
- END;
- END;
- (* ----------------------------------------------------------------------- *)
- (* Das Gleiche fuer den i-ten Eintrag eines eingelesenen Directorys: *)
- PROCEDURE MakeDirFileName (index: INTEGER; VAR directory: Dir_Typ;
- VAR filename : Dir_Str);
- BEGIN
- WITH directory DO
- IF (index > 0) AND (index <= num) THEN
- MakeFileName(items[index],filename);
- END;
-
- (* nun zu den Directory-Funktionen: *)
- (* ----------------------------------------------------------------------- *)
- (* Wie in DIR??TYP.PAS erwaehnt, muss die DTA dynamisch verwaltet werden. *)
- (* Man muss VOR Gebrauch der folgenden Funktionen mit "NewDTA" eine eigene *)
- (* DTA erschaffen, und diese mit "DispDTA" wieder freigeben, wenn nicht *)
- (* mehr benoetigt. Der Zeiger auf diese DTA muss aus dem gleichen Grund in *)
- (* einer globalen Variablen gehalten werden: *)
- PROCEDURE NewDirDTA;
- BEGIN New(DirDTA) END;
-
- PROCEDURE DispDirDTA;
- BEGIN Dispose(DirDTA) END;
- (* ----------------------------------------------------------------------- *)
- (* "SetDTA" teilt dem BS eine neue DTA-Adresse mit, "GetDTA" ermittelt die *)
- (* gerade vom BS verwendete DTA-Adresse: *)
- PROCEDURE SetDTA (DTA: DTA_Ptr);
- BEGIN IF DTA <> NIL THEN FSetDTA(DTA) END;
-
- PROCEDURE GetDTA (VAR DTA: DTA_Ptr);
- BEGIN DTA := FGetDTA; END;
- (* ----------------------------------------------------------------------- *)
- (* Den ersten mit der Suchspezifikation "search" (kann auch '*' oder '?' *)
- (* enthalten) und mit dem Attribut uebereinstimmenden Directory-Eintrag *)
- (* suchen. Wird einer gefunden, enthaelt die Variable "DirResult" den Wert *)
- (* 0, ansonsten einen Fehlercode (s. DIRCONST.PAS). Bei Erfolg wird der *)
- (* gefundene Eintrag als Dir-Record ausgegeben: *)
- PROCEDURE DirFirst (search: Dir_Str; attr: INTEGER; VAR entry: Dir_Rec);
- VAR oldDTA : DTA_Ptr; temp : Dir_Chr0; i : INTEGER;
- BEGIN
- (* fuer den Volume-Eintrag eine wirklich exklusive Suche erzwingen: *)
- IF AndInt(attr,DirVol) = DirVol THEN attr := DirVol;
- (* aktuelle DTA sichern und fuer Dir-Funktionen eigene verwenden: *)
- GetDTA(oldDTA); SetDTA(DirDTA);
- StrChr(search,temp); (* Zeichenfolge der Suchspez. zu eine ASCIIZ-Folge. *)
- DirResult := FSFirst(temp, attr); (* Betriebssystem-Aufruf. *)
- DTAtoDirEntry(entry); (* Info aus DTA in unseren Dir-Record bringen *)
- SetDTA(oldDTA); (* wieder alte DTA benutzen lassen *)
- END;
- (* ----------------------------------------------------------------------- *)
- (* den naechsten mit der bei "DirFirst" festgelegten Suchspez. ueberein- *)
- (* stimmenden Eintrag suchen. Fuer "DirResult" gilt oben beschriebenes. *)
- PROCEDURE DirNext (VAR entry: Dir_Rec);
- VAR oldDTA: DTA_Ptr;
- BEGIN
- GetDTA(oldDTA); SetDTA(DirDTA); DirResult := FSNext;
- SetDTA(oldDTA); DTAtoDirEntry(entry);
- END;
- (* ----------------------------------------------------------------------- *)
- (* alle mit Suchspez. uebereinstimmenden Eintraege suchen und in unseren *)
- (* Directory-Puffer in der Reihenfolge des Auftretens eintragen: *)
- PROCEDURE Dir (search: Dir_Str; attr: INTEGER; VAR directory: Dir_Typ);
- VAR entry: Dir_Rec;
- BEGIN
- WITH directory DO BEGIN
- num := 0; DirFirst(search, attr, entry);
- WHILE DirResult = DOSfnok DO BEGIN (* solange kein Fehler auftritt. *)
- num := Succ(num); items[num] := entry; DirNext(entry);
- END;
- END;
- END;
- (* ----------------------------------------------------------------------- *)
- (* gelesenes Verzeichnis nach 'sortkey' sortieren, wobei Unterver- *)
- (* zeichnisse immer an den Anfang gebracht werden: *)
- PROCEDURE SortDir (sortkey: INTEGER; VAR directory: Dir_Typ);
- VAR i, j, p : INTEGER; help : Dir_Rec;
-
- PROCEDURE Swap(i1, i2: INTEGER); (* zwei Eintrage im Directory vertauschen *)
- BEGIN
- WITH directory DO BEGIN
- help := items[i1]; items[i1] := items[i2]; items[i2] := help;
- END;
- END;
-
- (*$A+*) (* Turbo Pascal: rekursiven Code erzeugen! *)
- (* Vergleichsfunktion fuer die Sortierung durch den verf. Shell-Sort: *)
- FUNCTION lower(sortkey, i1, i2: INTEGER): BOOLEAN;
- VAR tmp: ARRAY [1..3] OF Dir_Str;
- BEGIN
- lower := FALSE;
- IF i2 > 0 THEN
- WITH directory DO BEGIN
- (* Strings (Name, Extension, Datum) von Unterverzeichnissen
- kleiner als die von Dateien "machen": *)
- tmp[1] := '!'; tmp[2] := '!';
- IF items[i1].attr = DirDir THEN tmp[1] := ' '; (* ' ' < '!' *)
- IF items[i2].attr = DirDir THEN tmp[2] := ' ';
- CASE sortkey OF
- DirDate: BEGIN
- (* juengste Eintraege (groesstes
- Datum als String) nach vorn: *)
- tmp[3] := tmp[1]; tmp[1] := tmp[2]; tmp[2] := tmp[3];
- tmp[1] := Concat(tmp[1],items[i1].date);
- tmp[2] := Concat(tmp[2],items[i2].date);
- lower := tmp[1] > tmp[2];
- (* notfalls noch Uhrzeit vergleichen: *)
- IF tmp[1] = tmp[2] THEN
- IF items[i1].time > items[i2].time THEN
- lower := TRUE
- (* gut, dann halt noch nach Namen: *)
- ELSE IF items[i1].time = items[i2].time THEN
- lower := lower(DirName,i1,i2)
- END;
- DirSize: BEGIN
- (* die groessten Dateien nach vorn: *)
- (* zwischen Verzeichnis und Datei unterscheiden: *)
- IF (tmp[1] = ' ') OR (tmp[2] = ' ') THEN
- lower := items[i1].size < items[i2].size
- ELSE
- lower := items[i1].size > items[i2].size;
- IF items[i1].size = items[i2].size THEN
- lower := lower(DirName,i1,i2);
- END;
- (* folgendes ist klar, oder ? *)
- DirExt : BEGIN
- tmp[1] := Concat(tmp[1],items[i1].ext,items[i1].name);
- tmp[2] := Concat(tmp[2],items[i2].ext,items[i2].name);
- lower := tmp[1] < tmp[2];
- END;
- ELSE BEGIN
- tmp[1] := Concat(tmp[1],items[i1].name,items[i1].ext);
- tmp[2] := Concat(tmp[2],items[i2].name,items[i2].ext);
- lower := tmp[1] < tmp[2];
- END;
- END;
- END;
- END;
- (*$A-*)
-
- BEGIN (* verfeinerter Shell-Sort, s. 'Sortieren in Modula 2' *)
- WITH directory DO BEGIN
- p := num;
- WHILE p > 1 DO BEGIN
- p := p DIV 2;
- FOR i := 1 TO num-p DO
- IF lower(sortkey,i+p,i) THEN BEGIN
- Swap(i,i+p);
- j := i;
- WHILE (j >= 1+p) AND lower(sortkey,j,j-p) DO BEGIN
- Swap(j,j-p); j := j - p;
- END;
- END;
- END;
- END;
- END;
-
- (* und der neue Stoff mit ein paar kleinen Schmankerln: *)
- (* ----------------------------------------------------------------------- *)
- (* Laufwerknummer als Laufwerkzeichen ausgeben (0 = A, 1 = B, 2 = C usw.): *)
- FUNCTION DriveChar (drive: INTEGER): CHAR;
- BEGIN DriveChar := Chr(Ord('A')+drive); END;
-
- (* Laufwerkzeichen als Laufwerknummer ausgeben (A = 0, B = 1, C = 2 usw.): *)
- FUNCTION DriveNum (drive: CHAR): INTEGER;
- BEGIN DriveNum := Ord(UpCase(drive)) - Ord('A'); END;
- (* ----------------------------------------------------------------------- *)
- (* aktuelles (angemeldetes) Laufwerk ermitteln (0 = A, 1 = B, 2 = C usw.): *)
- FUNCTION GetDrive: INTEGER;
- BEGIN GetDrive := DGetDrive; END;
-
- (* Laufwerk selektieren (anmelden) (A = 0, B = 1, C = 2 usw.): *)
- (* existiert das gewuenschte Laufwerk nicht, ist DirResult = DOSedriv, *)
- (* sonst ist DirResult = DOSfnok. *)
- PROCEDURE ChDrive (drive: INTEGER);
- BEGIN DirResult := DSetDrive(drive); END;
- (* ----------------------------------------------------------------------- *)
- (* Dateinamen z.B. der Form 'a:*.pas' untersuchen. Bei MS-DOS und CP/M *)
- (* wird gleichzeitig der 'DirFCB' initialisiert, was bei TOS entfaellt. *)
- (* nextch zeigt auf das erste, nicht mehr zum Dateinamen gehoerende Zei- *)
- (* chen.
- (* Diese Prozedur sollte nicht fuer Dateinamen mit Pfadangabe genutzt wer- *)
- (* den! *)
- (* result = 0 -> fname ok, result = 1 -> fname enthaelt '*' oder '?', re- *)
- (* sult = 255 -> fname fehlerhaft. *)
- PROCEDURE ParseFileName (fname: Dir_Str; VAR nextch, result: INTEGER);
- VAR temp: Dir_Chr0;
- BEGIN StrChr(fname, temp); FParsName(temp, nextch, result); END;
-
- (* Pfadspezifikation aus 'fname' extrahieren und in 'fpath' zurueckgeben. *)
- (* nextch zeigt auf das erste Zeichen des dem Pfad folgenden Dateinamens *)
- (* in fname: *)
- PROCEDURE FilePath (fname: Dir_Str; VAR fpath: Dir_Str; VAR nextch: INTEGER);
- VAR fn, fp: Dir_Chr0;
- BEGIN StrChr(fname, fn); FGetPath(fn, fp, nextch); ChrStr(fp, fpath); END;
-
- (* In fname angegebene Laufwerkspezifikation in 'drive' zurueckgeben: *)
- (* (0 = A, 1 = B, 2 = C usw.): *)
- FUNCTION FileDrive (fname: Dir_Str): INTEGER;
- VAR i: INTEGER;
- BEGIN
- FileDrive := GetDrive; FilePath(fname,fname,i);
- IF (Length(fname) > 1) AND (fname[2] = ':') THEN
- FileDrive := DriveNum(fname[1]);
- END;
- (* ----------------------------------------------------------------------- *)
- (* aktuelles Verzeichnis ermitteln: *)
- (* Hier unterscheiden sich MS-DOS und TOS etwas: Pfadnamen werden von MS- *)
- (* DOS ohne den ersten, das Wurzel-(Haupt-) Verzeichnis identifizierenten *)
- (* Backslash "\", von TOS aber mit diesem zurueckgegeben. Wir halten uns *)
- (* hier an TOS und lassen von DGetPath das vorangestellte "\"-Zeichen im- *)
- (* mer zurueckgeben, also auch fuer das Wurzelverzeichnis. Nur im Fehler- *)
- (* fall (ungueltiges Laufwerk) wird eine leere Zeichenfolge erwartet. Fuer *)
- (* das Laufwerk gilt: 0 = angemeldetes Laufwerk, 1 = A, 2 = B, 3 = C usw.: *)
- (* (Beschreibung fuer die CP/M-Version von DGetPath und den noch folgenden *)
- (* Knecht-Prozeduren s. bitte DIRCP.TUR.) *)
- PROCEDURE GetDir (drive: INTEGER; VAR path: Dir_Str);
- VAR temp: Dir_Chr0;
- BEGIN
- temp[1] := Chr(0); DirResult := DGetPath(temp, drive); ChrStr(temp, path);
- END;
-
- (* aktuelles Verzeichnis wechseln: *)
- (* wieder ein kleiner Unterschied: TOS erlaubt den Verzeichnis-Wechsel nur *)
- (* fuer das gerade angemeldete Laufwerk, MS-DOS dagegen fuer alle vorhan- *)
- (* denen Laufwerke (Laufwerksangabe in path enthalten). Wir halten uns an *)
- (* MS-DOS, was fuer DSetPath unter TOS etwas mehr Aufwand bedeutet *)
- (* (s. DIRMT.PSP): *)
- PROCEDURE ChDir (path: Dir_Str);
- VAR temp: Dir_Chr0;
- BEGIN StrChr(path, temp); DirResult := DSetPath(temp); END;
-
- (* neues Verzeichnis erzeugen: *)
- (* hier scheinen MS-DOS und TOS im Einklang zu sein, soweit ich festge- *)
- (* stellt habe: *)
- PROCEDURE MkDir (path: Dir_Str);
- VAR temp: Dir_Chr0;
- BEGIN StrChr(path, temp); DirResult := DCreate(temp); END;
-
- (* ein leeres Verzeichnis entfernen: *)
- (* wieder leichte (?) Diskrepanzen: *)
- (* a) TOS mag nur Verzeichnisse der naechsten Ebene loeschen bzw. besteht *)
- (* auf eine vollstaendige Pfadangabe inklusive Laufwerk. MS-DOS erlaubt *)
- (* dagegen auch Teilpfade von einem Unterverzeichnis aus. *)
- (* b) MS-DOS erlaubt nicht, das gerade aktuelle Verzeichnis zu loeschen, *)
- (* sei es auch noch so leer. TOS dagegen ist das schnurz, solange das *)
- (* Verzeichnis leer ist. *)
- (* Wir halten uns an MS-DOS, was fuer a) bei TOS durch das Voranstellen *)
- (* der Zeichen ".\" in DDelete vor den Pfad geloesst wird. b) wird dagegen *)
- (* fuer TOS noch nicht geloesst, was aber auch keine grosse Beeintraech- *)
- (* tigung der Funktionsfaehigkeit mit sich bringt. *)
- PROCEDURE RmDir (path: Dir_Str);
- VAR temp: Dir_Chr0;
- BEGIN StrChr(path, temp); DirResult := DDelete(temp); END;
- (* ----------------------------------------------------------------------- *)
- (* freien Disk-Speicherplatz ermitteln: *)
- (* drive = 0 -> angemeldetes Laufwerk, 1 -> A, 2 -> B usw. MS-DOS und TOS *)
- (* stimmen bei den Ergebnissen von DFree ueberein, CP/M wird davon soft- *)
- (* waremaessig ueberzeugt. Wird ein nicht existierendes Laufwerk ange- *)
- (* sprochen, so sind die Groessen in Info von DFree mit dem Wert -1 zu be- *)
- (* legen, wodurch DiskFree einen sinnlosen Wert von -1 liefert! *)
- FUNCTION DiskFree (drive: INTEGER): REAL;
- VAR Info: DSK_Info;
- BEGIN
- DFree(Info, drive);
- WITH Info DO DiskFree := SectorSize * ClusterSize * FreeCluster;
- END;
- (* ----------------------------------------------------------------------- *)
- (* DIRLIB.PAS *)