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;
- (* ----------------------------------------------------------------------- *)
- (* 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;
- (* ----------------------------------------------------------------------- *)
- (* DIRLIB.PAS *)