home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / 1988 / 01 / dirlib / dirlib.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1987-11-09  |  18.9 KB  |  372 lines

  1. (* ----------------------------------------------------------------------- *)
  2. (*                              DIRLIB.PAS                                 *)
  3. (*              (c) 1987  Michael Ceol & PASCAL INT.                       *)
  4. (* Betriebssystem- und compilerunabhaengige Routinen der Directory-Biblio- *)
  5. (* thek. Diese rufen wiederum die "low level" Routinen in DIRMT.TUR,       *)
  6. (* DIRMT.PSP bzw. DIRCP.TUR auf, um den eigentlichen Job zu erledigen.     *)
  7.  
  8. (*                       ein bischen Konvertierung:                        *)
  9. (* ----------------------------------------------------------------------- *)
  10. (*    String in eine ASCIIZ-Zeichenfolge konvertieren, wie es von den      *)
  11. (*                     Betriebssystemen benoetigt wird:                    *)
  12. PROCEDURE StrChr (VAR st: Dir_Str; VAR ch: Dir_Chr0);
  13. VAR i : INTEGER;
  14. BEGIN
  15.   FOR i := 1 TO Length(st) DO ch[i] := st[i];
  16.   ch[Succ(Length(st))] := Chr(0);
  17. END;
  18. (* ----------------------------------------------------------------------- *)
  19. (*           ASCIIZ-Zeichenfolge in einen String konvertieren:             *)
  20. PROCEDURE ChrStr (VAR ch: Dir_Chr0;  VAR st: Dir_Str);
  21. VAR i : INTEGER;
  22. BEGIN
  23.   i := 1;  st := '';
  24.   WHILE ch[i] <> Chr(0) DO BEGIN st := Concat(st,ch[i]); i := Succ(i); END;
  25. END;
  26. (* ----------------------------------------------------------------------- *)
  27. (*   Dateinamen aus einem "Dir_Rec" (name[8], ext[3]) in einen gueltigen   *)
  28. (*           Dateinamen des Formats "name.ext" konvertieren:               *)
  29. PROCEDURE MakeFileName (VAR direntry: Dir_Rec; VAR filename: Dir_Str);
  30. VAR i : INTEGER;
  31. BEGIN
  32.   filename := '';
  33.   WITH direntry DO BEGIN
  34.     FOR i := 1 TO 8 DO      (* die aufgefuellten Leerzeichen muessen weg ! *)
  35.       IF name[i] <> ' ' THEN filename := Concat(filename, name[i]);
  36.     IF ext <> '   ' THEN BEGIN       (* gibt's Extension ? (3 Leerzeichen) *)
  37.       filename := Concat(filename, '.');             (* ja, Trennpunkt und *)
  38.       FOR i := 1 TO 3 DO                             (* Extension anfuegen *)
  39.         IF ext[i] <> ' ' THEN filename := Concat(filename, ext[i]);
  40.     END;
  41.   END;
  42. END;
  43. (* ----------------------------------------------------------------------- *)
  44. (*    Das Gleiche fuer den i-ten Eintrag eines eingelesenen Directorys:    *)
  45. PROCEDURE MakeDirFileName (index: INTEGER; VAR directory: Dir_Typ;
  46.                                            VAR filename : Dir_Str);
  47. BEGIN
  48.   WITH directory DO
  49.     IF (index > 0) AND (index <= num) THEN
  50.       MakeFileName(items[index],filename);
  51. END;
  52.  
  53. (*                    nun zu den Directory-Funktionen:                     *)
  54. (* ----------------------------------------------------------------------- *)
  55. (* Wie in DIR??TYP.PAS erwaehnt, muss die DTA dynamisch verwaltet werden.  *)
  56. (* Man muss VOR Gebrauch der folgenden Funktionen mit "NewDTA" eine eigene *)
  57. (* DTA erschaffen, und diese mit "DispDTA" wieder freigeben, wenn nicht    *)
  58. (* mehr benoetigt. Der Zeiger auf diese DTA muss aus dem gleichen Grund in *)
  59. (* einer globalen Variablen gehalten werden:                               *)
  60. PROCEDURE NewDirDTA;
  61. BEGIN  New(DirDTA)  END;
  62.  
  63. PROCEDURE DispDirDTA;
  64. BEGIN  Dispose(DirDTA)  END;
  65. (* ----------------------------------------------------------------------- *)
  66. (* "SetDTA" teilt dem BS eine neue DTA-Adresse mit, "GetDTA" ermittelt die *)
  67. (* gerade vom BS verwendete DTA-Adresse:                                   *)
  68. PROCEDURE SetDTA (DTA: DTA_Ptr);
  69. BEGIN  IF DTA <> NIL THEN FSetDTA(DTA)  END;
  70.  
  71. PROCEDURE GetDTA (VAR DTA: DTA_Ptr);
  72. BEGIN  DTA := FGetDTA;  END;
  73. (* ----------------------------------------------------------------------- *)
  74. (* Den ersten mit der Suchspezifikation "search" (kann auch '*' oder '?'   *)
  75. (* enthalten) und mit dem Attribut uebereinstimmenden Directory-Eintrag    *)
  76. (* suchen. Wird einer gefunden, enthaelt die Variable "DirResult" den Wert *)
  77. (* 0, ansonsten einen Fehlercode (s. DIRCONST.PAS). Bei Erfolg wird der    *)
  78. (* gefundene Eintrag als Dir-Record ausgegeben:                            *)
  79. PROCEDURE DirFirst (search: Dir_Str; attr: INTEGER; VAR entry: Dir_Rec);
  80. VAR oldDTA : DTA_Ptr;  temp : Dir_Chr0;  i : INTEGER;
  81. BEGIN
  82.        (* fuer den Volume-Eintrag eine wirklich exklusive Suche erzwingen: *)
  83.   IF AndInt(attr,DirVol) = DirVol THEN attr := DirVol;
  84.          (* aktuelle DTA sichern und fuer Dir-Funktionen eigene verwenden: *)
  85.   GetDTA(oldDTA);   SetDTA(DirDTA);
  86.   StrChr(search,temp); (* Zeichenfolge der Suchspez. zu eine ASCIIZ-Folge. *)
  87.   DirResult := FSFirst(temp, attr);              (* Betriebssystem-Aufruf. *)
  88.   DTAtoDirEntry(entry);      (* Info aus DTA in unseren Dir-Record bringen *)
  89.   SetDTA(oldDTA);                       (* wieder alte DTA benutzen lassen *)
  90. END;
  91. (* ----------------------------------------------------------------------- *)
  92. (* den naechsten mit der bei "DirFirst" festgelegten Suchspez. ueberein-   *)
  93. (* stimmenden Eintrag suchen. Fuer "DirResult" gilt oben beschriebenes.    *)
  94. PROCEDURE DirNext (VAR entry: Dir_Rec);
  95. VAR oldDTA: DTA_Ptr;
  96. BEGIN
  97.   GetDTA(oldDTA);  SetDTA(DirDTA);  DirResult := FSNext;
  98.   SetDTA(oldDTA);  DTAtoDirEntry(entry);
  99. END;
  100. (* ----------------------------------------------------------------------- *)
  101. (* alle mit Suchspez. uebereinstimmenden Eintraege suchen und in unseren   *)
  102. (* Directory-Puffer in der Reihenfolge des Auftretens eintragen:           *)
  103. PROCEDURE Dir (search: Dir_Str; attr: INTEGER; VAR directory: Dir_Typ);
  104. VAR entry: Dir_Rec;
  105. BEGIN
  106.   WITH directory DO BEGIN
  107.     num := 0;   DirFirst(search, attr, entry);
  108.     WHILE DirResult = DOSfnok DO BEGIN    (* solange kein Fehler auftritt. *)
  109.       IF num = DirSizeMax THEN DirResult := DOSnsmem
  110.       ELSE BEGIN
  111.         num := Succ(num);  items[num] := entry;   DirNext(entry);
  112.       END;
  113.     END;
  114.   END;
  115. END;
  116. (* ----------------------------------------------------------------------- *)
  117. (*    gelesenes Verzeichnis nach 'sortkey' sortieren, wobei Unterver-      *)
  118. (*          zeichnisse immer an den Anfang gebracht werden:                *)
  119. PROCEDURE SortDir (sortkey: INTEGER; VAR directory: Dir_Typ);
  120. VAR i, j, p : INTEGER;  help : Dir_Rec;
  121.  
  122. PROCEDURE Swap(i1, i2: INTEGER); (* zwei Eintrage im Directory vertauschen *)
  123.   BEGIN
  124.     WITH directory DO BEGIN
  125.       help := items[i1]; items[i1] := items[i2]; items[i2] := help;
  126.     END;
  127.   END;
  128.  
  129. (*$A+*)                         (* Turbo Pascal: rekursiven Code erzeugen! *)
  130. (*    Vergleichsfunktion fuer die Sortierung durch den verf. Shell-Sort:   *)
  131. FUNCTION lower(sortkey, i1, i2: INTEGER): BOOLEAN;
  132.   VAR tmp: ARRAY [1..3] OF Dir_Str;
  133.   BEGIN
  134.     lower := FALSE;
  135.     IF i2 > 0 THEN
  136.       WITH directory DO BEGIN
  137.                (* Strings (Name, Extension, Datum) von Unterverzeichnissen
  138.                   kleiner als die von Dateien "machen":                    *)
  139.         tmp[1] := '!';  tmp[2] := '!';
  140.         IF items[i1].attr = DirDir THEN tmp[1] := ' ';        (* ' ' < '!' *)
  141.         IF items[i2].attr = DirDir THEN tmp[2] := ' ';
  142.         CASE sortkey OF
  143.           DirDate: BEGIN
  144.                                           (* juengste Eintraege (groesstes
  145.                                              Datum als String) nach vorn:  *)
  146.                      tmp[3] := tmp[1]; tmp[1] := tmp[2]; tmp[2] := tmp[3];
  147.                      tmp[1] := Concat(tmp[1],items[i1].date);
  148.                      tmp[2] := Concat(tmp[2],items[i2].date);
  149.                      lower := tmp[1] > tmp[2];
  150.                                      (* notfalls noch Uhrzeit vergleichen: *)
  151.                      IF tmp[1] = tmp[2] THEN
  152.                        IF items[i1].time > items[i2].time THEN
  153.                          lower := TRUE
  154.                                         (* gut, dann halt noch nach Namen: *)
  155.                        ELSE IF items[i1].time = items[i2].time THEN
  156.                          lower := lower(DirName,i1,i2)
  157.                    END;
  158.           DirSize: BEGIN
  159.                                        (* die groessten Dateien nach vorn: *)
  160.                           (* zwischen Verzeichnis und Datei unterscheiden: *)
  161.                      IF (tmp[1] = ' ') OR (tmp[2] = ' ') THEN
  162.                        lower := items[i1].size < items[i2].size
  163.                      ELSE
  164.                        lower := items[i1].size > items[i2].size;
  165.                      IF items[i1].size = items[i2].size THEN
  166.                        lower := lower(DirName,i1,i2);
  167.                    END;
  168.                                              (* folgendes ist klar, oder ? *)
  169.         DirExt : BEGIN
  170.                      tmp[1] := Concat(tmp[1],items[i1].ext,items[i1].name);
  171.                      tmp[2] := Concat(tmp[2],items[i2].ext,items[i2].name);
  172.                      lower := tmp[1] < tmp[2];
  173.                    END;
  174.           ELSE     BEGIN
  175.                      tmp[1] := Concat(tmp[1],items[i1].name,items[i1].ext);
  176.                      tmp[2] := Concat(tmp[2],items[i2].name,items[i2].ext);
  177.                      lower := tmp[1] < tmp[2];
  178.                    END;
  179.         END;
  180.       END;
  181.   END;
  182. (*$A-*)
  183.  
  184. BEGIN (* verfeinerter Shell-Sort, s. 'Sortieren in Modula 2' *)
  185.   WITH directory DO BEGIN
  186.     p := num;
  187.     WHILE p > 1 DO BEGIN
  188.       p := p DIV 2;
  189.       FOR i := 1 TO num-p DO
  190.         IF lower(sortkey,i+p,i) THEN BEGIN
  191.           Swap(i,i+p);
  192.           j := i;
  193.           WHILE (j >= 1+p) AND lower(sortkey,j,j-p) DO BEGIN
  194.             Swap(j,j-p);  j := j - p;
  195.           END;
  196.         END;
  197.     END;
  198.   END;
  199. END;
  200.  
  201. (*           und der neue Stoff mit ein paar kleinen Schmankerln:          *)
  202. (* ----------------------------------------------------------------------- *)
  203. (* Laufwerknummer als Laufwerkzeichen ausgeben (0 = A, 1 = B, 2 = C usw.): *)
  204. FUNCTION DriveChar (drive: INTEGER): CHAR;
  205. BEGIN  DriveChar := Chr(Ord('A')+drive);  END;
  206.  
  207. (* Laufwerkzeichen als Laufwerknummer ausgeben (A = 0, B = 1, C = 2 usw.): *)
  208. FUNCTION DriveNum (drive: CHAR): INTEGER;
  209. BEGIN  DriveNum := Ord(UpCase(drive)) - Ord('A');  END;
  210. (* ----------------------------------------------------------------------- *)
  211. (* aktuelles (angemeldetes) Laufwerk ermitteln (0 = A, 1 = B, 2 = C usw.): *)
  212. FUNCTION GetDrive: INTEGER;
  213. BEGIN  GetDrive := DGetDrive;  END;
  214.  
  215. (*       Laufwerk selektieren (anmelden) (A = 0, B = 1, C = 2 usw.):       *)
  216. (* existiert das gewuenschte Laufwerk nicht, ist DirResult = DOSedriv,     *)
  217. (* sonst ist DirResult = DOSfnok.                                          *)
  218. PROCEDURE ChDrive (drive: INTEGER);
  219. BEGIN  DirResult := DSetDrive(drive);  END;
  220. (* ----------------------------------------------------------------------- *)
  221. (* Dateinamen z.B. der Form 'a:*.pas' untersuchen. Bei MS-DOS und CP/M     *)
  222. (* wird gleichzeitig der 'DirFCB' initialisiert, was bei TOS entfaellt.    *)
  223. (* nextch zeigt auf das erste, nicht mehr zum Dateinamen gehoerende Zei-   *)
  224. (* chen.
  225. (* Diese Prozedur sollte nicht fuer Dateinamen mit Pfadangabe genutzt wer- *)
  226. (* den!                                                                    *)
  227. (* result = 0 -> fname ok, result = 1 -> fname enthaelt '*' oder '?', re-  *)
  228. (* sult = 255 -> fname fehlerhaft.                                         *)
  229. PROCEDURE ParseFileName (fname: Dir_Str; VAR nextch, result: INTEGER);
  230. VAR temp: Dir_Chr0;
  231. BEGIN  StrChr(fname, temp);  FParsName(temp, nextch, result);  END;
  232.  
  233. (* Pfadspezifikation aus 'fname' extrahieren und in 'fpath' zurueckgeben.  *)
  234. (* nextch zeigt auf das erste Zeichen des dem Pfad folgenden Dateinamens   *)
  235. (* in fname:                                                               *)
  236. PROCEDURE FilePath (fname: Dir_Str; VAR fpath: Dir_Str; VAR nextch: INTEGER);
  237. VAR fn, fp: Dir_Chr0;
  238. BEGIN StrChr(fname, fn); FGetPath(fn, fp, nextch); ChrStr(fp, fpath); END;
  239.  
  240. (*    In fname angegebene Laufwerkspezifikation in 'drive' zurueckgeben:   *)
  241. (*                       (0 = A, 1 = B, 2 = C usw.):                       *)
  242. FUNCTION FileDrive (fname: Dir_Str): INTEGER;
  243. VAR i: INTEGER;
  244. BEGIN
  245.   FileDrive := GetDrive;  FilePath(fname,fname,i);
  246.   IF (Length(fname) > 1) AND (fname[2] = ':') THEN
  247.     FileDrive := DriveNum(fname[1]);
  248. END;
  249. (* ----------------------------------------------------------------------- *)
  250. (*                   aktuelles Verzeichnis ermitteln:                      *)
  251. (* Hier unterscheiden sich MS-DOS und TOS etwas: Pfadnamen werden von MS-  *)
  252. (* DOS ohne den ersten, das Wurzel-(Haupt-) Verzeichnis identifizierenten  *)
  253. (* Backslash "\", von TOS aber mit diesem zurueckgegeben. Wir halten uns   *)
  254. (* hier an TOS und lassen von DGetPath das vorangestellte "\"-Zeichen im-  *)
  255. (* mer zurueckgeben, also auch fuer das Wurzelverzeichnis. Nur im Fehler-  *)
  256. (* fall (ungueltiges Laufwerk) wird eine leere Zeichenfolge erwartet. Fuer *)
  257. (* das Laufwerk gilt: 0 = angemeldetes Laufwerk, 1 = A, 2 = B, 3 = C usw.: *)
  258. (* (Beschreibung fuer die CP/M-Version von DGetPath und den noch folgenden *)
  259. (* Knecht-Prozeduren s. bitte DIRCP.TUR.)                                  *)
  260. PROCEDURE GetDir (drive: INTEGER; VAR path: Dir_Str);
  261. VAR temp: Dir_Chr0;
  262. BEGIN
  263.   temp[1] := Chr(0); DirResult := DGetPath(temp, drive); ChrStr(temp, path);
  264. END;
  265.  
  266. (*                      aktuelles Verzeichnis wechseln:                    *)
  267. (* wieder ein kleiner Unterschied: TOS erlaubt den Verzeichnis-Wechsel nur *)
  268. (* fuer das gerade angemeldete Laufwerk, MS-DOS dagegen fuer alle vorhan-  *)
  269. (* denen Laufwerke (Laufwerksangabe in path enthalten). Wir halten uns an  *)
  270. (* MS-DOS, was fuer DSetPath unter TOS etwas mehr Aufwand bedeutet         *)
  271. (* (s. DIRMT.PSP):                                                         *)
  272. PROCEDURE ChDir (path: Dir_Str);
  273. VAR temp: Dir_Chr0;
  274. BEGIN  StrChr(path, temp);  DirResult := DSetPath(temp);  END;
  275.  
  276. (*                          neues Verzeichnis erzeugen:                    *)
  277. (* hier scheinen MS-DOS und TOS im Einklang zu sein, soweit ich festge-    *)
  278. (* stellt habe:                                                            *)
  279. PROCEDURE MkDir (path: Dir_Str);
  280. VAR temp: Dir_Chr0;
  281. BEGIN  StrChr(path, temp);  DirResult := DCreate(temp);  END;
  282.  
  283. (*                     ein leeres Verzeichnis entfernen:                   *)
  284. (* wieder leichte (?) Diskrepanzen:                                        *)
  285. (* a) TOS mag nur Verzeichnisse der naechsten Ebene loeschen bzw. besteht  *)
  286. (*    auf eine vollstaendige Pfadangabe inklusive Laufwerk. MS-DOS erlaubt *)
  287. (*    dagegen auch Teilpfade von einem Unterverzeichnis aus.               *)
  288. (* b) MS-DOS erlaubt nicht, das gerade aktuelle Verzeichnis zu loeschen,   *)
  289. (*    sei es auch noch so leer. TOS dagegen ist das schnurz, solange das   *)
  290. (*    Verzeichnis leer ist.                                                *)
  291. (* Wir halten uns an MS-DOS, was fuer a) bei TOS durch das Voranstellen    *)
  292. (* der Zeichen ".\" in DDelete vor den Pfad geloesst wird. b) wird dagegen *)
  293. (* fuer TOS noch nicht geloesst, was aber auch keine grosse Beeintraech-   *)
  294. (* tigung der Funktionsfaehigkeit mit sich bringt.                         *)
  295. PROCEDURE RmDir (path: Dir_Str);
  296. VAR temp: Dir_Chr0;
  297. BEGIN  StrChr(path, temp);  DirResult := DDelete(temp);  END;
  298. (* ----------------------------------------------------------------------- *)
  299. (*                freien Disk-Speicherplatz ermitteln:                     *)
  300. (* drive = 0 -> angemeldetes Laufwerk, 1 -> A, 2 -> B usw. MS-DOS und TOS  *)
  301. (* stimmen bei den Ergebnissen von DFree ueberein, CP/M wird davon soft-   *)
  302. (* waremaessig ueberzeugt. Wird ein nicht existierendes Laufwerk ange-     *)
  303. (* sprochen, so sind die Groessen in Info von DFree mit dem Wert -1 zu be- *)
  304. (* legen, wodurch DiskFree einen sinnlosen Wert von -1 liefert!            *)
  305. FUNCTION DiskFree (drive: INTEGER): REAL;
  306. VAR Info: DSK_Info;
  307. BEGIN
  308.   DFree(Info, drive);
  309.   WITH Info DO  DiskFree := SectorSize * ClusterSize * FreeCluster;
  310. END;
  311. (* ----------------------------------------------------------------------- *)
  312. (* Attribute eines Directory-Eintrages ermitteln (gilt nur fuer Dateinamen *)
  313. (* ohne '*' und ohne '?' sowie fuer Unterverzeichnisse). DirResult ent-    *)
  314. (* haelt wie ueblich einen Fehlercode; bei einem Fehler ist der Funktions- *)
  315. (*                            wert zusaetzlich -1:                         *)
  316. FUNCTION GetFileAttribut (fname: Dir_Str): INTEGER;
  317. VAR temp: Dir_Chr0;  attr: INTEGER;
  318. BEGIN
  319.   DirResult := DOSfnok;  StrChr(fname,temp);  attr := FAttrib(temp,0,attr);
  320.   IF attr < 0 THEN BEGIN   DirResult := attr;  attr := -1;  END;
  321.   GetFileAttribut := attr;
  322. END;
  323.  
  324. (*       Attribute eines Directory-Eintrages (nur Dateien!) setzen:        *)
  325. FUNCTION SetFileAttribut (fname: Dir_Str; attr: INTEGER): INTEGER;
  326. VAR temp: Dir_Chr0;  oldattr: INTEGER;
  327. BEGIN
  328.   oldattr := GetFileAttribut(fname);  StrChr(fname,temp);
  329.   IF DirResult = DOSfnok THEN
  330.     IF (AndInt(attr,DirVol+DirDir) = 0) AND     (* Volumelabel und Direc-  *)
  331.        (AndInt(oldattr,DirVol+DirDir) = 0) THEN (* tories nicht aendern !! *)
  332.          attr := FAttrib(temp,1,attr)
  333.     ELSE attr := -1
  334.   ELSE attr := -1;
  335.   SetFileAttribut := attr;
  336. END;
  337. (* ----------------------------------------------------------------------- *)
  338. (*   die durch 'fname' (kann Laufwerk und Pfad enthalten) spezifizierte    *)
  339. (*                         Datei loeschen:                                 *)
  340. PROCEDURE EraseFile (fname: Dir_Str);
  341. VAR temp: Dir_Chr0;
  342. BEGIN  StrChr(fname,temp);  DirResult := FDelete(temp);  END;
  343. (* ----------------------------------------------------------------------- *)
  344. (*  der in 'oldname' angegebenen Datei den in 'newname' angegebenen neuen  *)
  345. (*  Namen geben. Dabei kann in 'oldname' Laufwerk und Pfad angegeben wer-  *)
  346. (*  den:                                                                   *)
  347. PROCEDURE RenameFile (oldname, newname: Dir_Str);
  348. VAR tempold, tempnew: Dir_Chr0;
  349. BEGIN
  350.   StrChr(oldname,tempold);  StrChr(newname,tempnew);
  351.   DirResult := FRename(0,tempold,tempnew);
  352. END;
  353. (* ----------------------------------------------------------------------- *)
  354. (*              Groesse einer Datei in Bytes ermitteln:                    *)
  355. FUNCTION FileSize (fname: Dir_Str): REAL;
  356. VAR nextch, result: INTEGER;  temp: Dir_Rec; path: Dir_Str; oldDTA: DTA_Ptr;
  357. BEGIN
  358.   FileSize := -1.0;  DirResult := DOSfilnf;  GetDTA(oldDTA);  SetDTA(DirDTA);
  359.               (* Dateinamen von Pfad abtrennen, falls letzterer angegeben: *)
  360.   FilePath(fname, path, nextch);
  361.   path := Copy(fname,nextch,Succ(Length(fname)-nextch));
  362.   ParseFileName(path, nextch, result);            (* Dateiname eindeutig ? *)
  363.   IF result = 0 THEN BEGIN                                         (* ja ! *)
  364.     DirFirst(fname, DirRO+DirHid+DirSys, temp);
  365.     IF DirResult = DOSfnok THEN               (* only for the lonely CP/M: *)
  366.       FileSize := CompFSize;                  (* CompFSize ist dort eine   *)
  367.   END;                                        (* seperate System-Funktion  *)
  368.   SetDTA(oldDTA);
  369. END;
  370. (* ----------------------------------------------------------------------- *)
  371. (*                              DIRLIB.PAS                                 *)
  372.