home *** CD-ROM | disk | FTP | other *** search
- (* ------------------------------------------------------ *)
- (* TREE.PAS *)
- (* (c) 1991 Michael Reiter & TOOLBOX *)
- (* ------------------------------------------------------ *)
- {$A-,B-,D-,E-,F-,I-,L-,N-,O-,R-,S-,V-}
- {$M 65512,0,655360} { STACK wegen Rekursion }
- PROGRAM Tree;
-
- USES
- Crt, Dos, Scroll; { Unit SCROLL aus Toolbox 1/89 }
-
- CONST
- MaxLines = 512;
- Version = ' TREE (c) 1991 M.Reiter & TOOLBOX';
- TreeFileName = 'TREE-';
- TreeFileExt = '.DTA';
- xFullPath : BYTE = 20;
- WriteFile : ShortInt = 0;
- { -1=NICHT schreiben / +1=SCHREIBEN }
- { 0= nur schreiben,wenn File fehlt }
- TYPE
- Str16 = STRING[16];
- EntryTypePtr = ^EntryType;
- EntryType = RECORD
- Name : Str16;
- Level : BYTE;
- Counter : WORD;
- Back : EntryTypePtr;
- Next : EntryTypePtr
- END;
- LineType = ARRAY [1..MaxLines] OF ^STRING;
-
- VAR
- Root : EntryType;
- TreeFPath,
- AktPath,
- OldPath : STRING;
- Level, Drive : BYTE;
- EntryPtr : EntryTypePtr;
- Lines : LineType;
- Counter, Key : WORD;
- TreeFile : FILE OF EntryType;
-
-
- PROCEDURE Help;
- BEGIN
- TextAttr := $07;
- WriteLn
- (' ');
- WriteLn
- (' ChangeSubdir: Cursorgesteuerter Verzeichniswechsel ');
- WriteLn
- (' mit Hilfe eines Verzeichnisbaums. ');
- WriteLn
- (' ');
- WriteLn
- (' Aufruf: TREE [LW:][?][/I±] ');
- WriteLn
- (' LW: Laufwerkangabe (a:, C:, ...) ');
- WriteLn
- (' Bei fehlender Angabe => aktuelles Laufwerk ');
- WriteLn
- (' ?: Diese Hilfe ');
- WriteLn
- (' /I+: Neues Baumfile erzeugen und abspeichern ');
- WriteLn
- (' /I-: KEIN Baumfile abspeichern ');
- WriteLn
- (' ');
- WriteLn
- (' Steuerung des Auswahlbalken mit den Cursortasten. ');
- WriteLn
- (' [Enter]: Wechsel in gewähltes Verzeichnis. ');
- WriteLn
- (' [Esc]: Abbruch ohne Verzeichniswechsel. ');
- WriteLn;
- Halt(0);
- END;
-
- PROCEDURE ErrorMsg(Abbruch : BOOLEAN; Msg : STRING);
- VAR
- TA : BYTE;
- BEGIN
- Window(1, 1, 80, 25);
- TA := TextAttr; TextAttr := $70;
- WriteLn(Version);
- Write(#7#7#7,' *** TREE: ',Msg,' ! ');
- TextAttr := $07; WriteLn;
- IF Abbruch THEN Halt(1)
- ELSE Delay(5000);
- TextAttr := TA;
- END;
-
- PROCEDURE GetParameter;
- VAR
- FN, s : STRING;
- b : BYTE;
- SR : SearchRec;
- BEGIN
- TextAttr := $07; Window(1,1,80,25); ClrScr;
- TextAttr := $0F; WriteLn (Version); TextAttr := $07;
- GetDir(0, OldPath);
- Drive := Ord(OldPath[1]) - 64;
- IF ParamCount = 0 THEN
- Drive := 0
- ELSE
- FOR b := 1 TO ParamCount DO BEGIN
- s := ParamStr(b);
- IF Pos('?', s) <> 0 THEN Help;
- IF (UpCase(s[1]) >='A') AND
- (UpCase(s[1]) <='Z') THEN
- Drive := Ord(UpCase (s[1])) - 64;
- IF (s[1] = '/') AND (UpCase(s[2])= 'I') THEN
- CASE s[3] OF
- '-' : WriteFile := -1;
- '+' : WriteFile := +1;
- ELSE WriteFile := 0
- END;
- END;
- GetDir(Drive, s);
- ChDir(s[1] + ':\');
- IF IOResult <> 0 THEN
- ErrorMsg(TRUE, 'falsche LW-Angabe');
- GetDir(Drive, s);
- FN := TreeFileName + s[1] + TreeFileExt;
- TreeFPath := s[1] + ':\' + FN;
- { Volume-Name holen, wenn vorhanden }
- FindFirst(s + '*.*', VolumeID, SR);
- IF DosError = 0 THEN s := s + ' ' + SR.Name;
- WITH Root DO BEGIN
- Name := s;
- Level := 0;
- Counter := 1;
- Back := NIL;
- Next := NIL;
- END;
- EntryPtr := @Root;
- Level := 0;
- Counter := 1;
- END;
-
- PROCEDURE Anhaengen (s : Str16; l : BYTE; VAR c : WORD);
- { Einhängen eines Elements in doppelt verkettete Liste. }
- VAR
- TempEntry : EntryTypePtr;
- BEGIN
- IF MaxAvail <= SizeOf (EntryType) THEN
- ErrorMsg(TRUE, 'Zu wenig freier Speicher');
- New(TempEntry);
- INC(c);
- WITH TempEntry^ DO BEGIN
- Name := s;
- Level := l;
- Counter := c;
- Back := EntryPtr;
- Next := NIL;
- END;
- EntryPtr^.Next := TempEntry;
- EntryPtr := TempEntry;
- END;
-
- PROCEDURE ScanDirectory(AktPath : STRING; Le : BYTE);
- VAR
- SR : SearchRec;
- BEGIN
- FindFirst(AktPath + '\*.*', Directory, SR);
- WHILE DosError = 0 DO BEGIN
- IF (SR.Attr AND Directory <> 0) THEN
- IF (SR.Name[1] <> '.') THEN BEGIN
- GotoXY(5,12);
- Write(Copy(AktPath + '\' + SR.Name, 1, 74));
- ClrEol;
- { Nur akt. Subdir. merken, nicht ganzen Pfad ! }
- Anhaengen(SR.Name, Le, Counter);
- ScanDirectory(AktPath + '\' + SR.Name, Succ(Le));
- END;
- FindNext(SR);
- END;
- END;
-
- FUNCTION ReadTreeFile : BOOLEAN;
- VAR
- Element : EntryType;
- BEGIN
- Assign(TreeFile, TreeFPath); Reset(TreeFile);
- IF IOResult <> 0 THEN BEGIN
- ErrorMsg(FALSE, 'Fehler beim Öffnen der Baumdatei');
- ReadTreeFile := FALSE; EXIT;
- END;
- Seek(TreeFile, 0);
- WHILE (NOT EoF (TreeFile)) AND (IOResult = 0) DO BEGIN
- Read(TreeFile, Element);
- Anhaengen(Element.Name, Element.Level, Counter);
- END;
- IF (IOResult <> 0) AND (NOT EoF (TreeFile)) THEN BEGIN
- ErrorMsg(FALSE, 'Fehler beim Einlesen der Baumdatei');
- ReadTreeFile := FALSE; EXIT;
- END;
- Close(TreeFile);
- ReadTreeFile := TRUE;
- END;
-
- PROCEDURE WriteTreeFile;
- VAR
- EPtr : EntryTypePtr;
- Cnt : WORD;
- Err : INTEGER;
- BEGIN
- IF (WriteFile = -1) THEN Exit;
- Assign(TreeFile, TreeFPath); Rewrite(TreeFile);
- IF IOResult <> 0 THEN
- ErrorMsg(FALSE, 'Fehler beim Öffnen der Baumdatei');
- EPtr := Root.Next;
- FOR Cnt := 1 TO Counter DO BEGIN
- IF EPtr <> NIL THEN BEGIN
- Write(TreeFile, EPtr^); EPtr := EPtr^.Next
- END;
- Err := IOResult;
- IF Err <> 0 THEN Cnt := Counter
- END;
- IF Err <> 0 THEN
- ErrorMsg(FALSE, 'Fehler beim Schreiben der Baumdatei');
- Close(TreeFile);
- END;
-
- FUNCTION TreeFileFound : BOOLEAN;
- { Gibt TRUE zurück, wenn TREE-File im Root-Verz. steht }
- VAR
- SR : SearchRec;
- BEGIN
- FindFirst(TreeFPath, AnyFile, SR);
- TreeFileFound := (DosError = 0);
- END;
-
- PROCEDURE MakeSubDirList;
- { Diese Routine stellt die Baumstruktur zu Verfügung. }
- { Wenn das TREE-File gefunden wird, werden diesem die }
- { Informationen entnommen, ansonsten wird der Verz.- }
- { baum gescannt und das TREE-File abgespeichert (oder }
- { auch nicht) => Parameter }
- BEGIN
- TextAttr := $0F;
- IF (WriteFile = +1) OR (NOT TreeFileFound) THEN BEGIN
- GotoXY(5,10);
- Write('Scannen der Unterverzeichnisse ... ');
- TextAttr := $07;
- ScanDirectory(Copy(Root.Name, 1, 2), 1);
- WriteTreeFile;
- END ELSE BEGIN
- IF NOT ReadTreeFile THEN BEGIN
- GotoXY(5,10);
- Write('Scannen der Unterverzeichnisse ... ');
- TextAttr := $07;
- ScanDirectory(Copy(Root.Name, 1, 2), 1)
- END;
- END;
- ClrScr;
- END;
-
- PROCEDURE InitLines;
- VAR
- Cnt : WORD;
- BEGIN
- IF Counter > MaxLines THEN Counter := MaxLines;
- FOR Cnt := 1 TO Counter DO Lines[Cnt] := NIL;
- END;
-
- FUNCTION LastDirIn(Le : WORD;
- Step : EntryTypePtr) : BOOLEAN;
- { Gibt TRUE zurück, wenn das akt. Verzeichnis das letzte }
- { Unterverz. dieses Levels in diesem Ast ist. }
- VAR
- Cut, EqualDirFound : BOOLEAN;
- BEGIN
- EqualDirFound := FALSE; Cut := FALSE;
- REPEAT
- Step := Step^.Next;
- IF Step^.Level < Le THEN Cut := TRUE;
- IF Step^.Level = Le THEN EqualDirFound := TRUE
- UNTIL (Step = NIL) OR
- (Step^.Counter = Counter) OR EqualDirFound OR Cut;
- IF Cut OR (NOT EqualDirFound) THEN LastDirIn := TRUE
- ELSE LastDirIn := FALSE;
- END;
-
- PROCEDURE BuildLines;
- { Erstellung der später "sichtbaren" Baumstruktur. }
- { Auf die Zeilen des Baums wird über ein Pointer- }
- { Array zugegriffen => siehe auch SCROLL-Unit }
- VAR
- Line, Space : STRING;
- CurrLevel, w,
- Cnt : WORD;
- Connect : ARRAY [1..25] OF BOOLEAN;
- BEGIN
- InitLines;
- FillChar(Connect, SizeOf(Connect), #0);
- FillChar(Space, 255, #32); Space[0] := #255;
- IF MaxAvail <= 80 THEN
- ErrorMsg(TRUE, 'Zu wenig freier Speicherplatz');
- GetMem(Lines[1], 80);
- Move(Space, Lines[1]^, 255);
- Line := #32 + Root.Name + #32;
- Lines[1]^ := Line;
- Lines[1]^[0] := #79;
- EntryPtr := Root.Next;
- FOR Cnt := 2 TO Succ (Counter) DO BEGIN
- Line := EntryPtr^.Name;
- CurrLevel := EntryPtr^.Level;
- IF LastDirIn(CurrLevel, EntryPtr) THEN BEGIN
- Line := '└─' + Line; Connect[CurrLevel] := FALSE;
- END ELSE BEGIN
- Line := '├─' + Line; Connect[CurrLevel] := TRUE;
- END;
- FOR w := CurrLevel DOWNTO 1 DO BEGIN
- IF (w <> CurrLevel) THEN BEGIN
- IF Connect[w] THEN Line := '│ ' + Line
- ELSE Line := ' ' + Line;
- END;
- END;
- Line := #32 + Line;
- IF Succ(Length(Line)) > xFullPath THEN
- INC(xFullPath, 5);
- IF MaxAvail <= (Length(Line) + 2) THEN
- ErrorMsg(TRUE, 'Zu wenig freier Speicherplatz');
- GetMem(Lines[Cnt], Length(Line) + 2);
- Move(Space, Lines[Cnt]^, Length(Line) + 2);
- Lines[Cnt]^ := Line;
- Lines[Cnt]^[0] := Chr (Succ(Length(Line)));
- EntryPtr := EntryPtr^.Next;
- END;
- END;
-
- { Die beiden nächsten Routinen werden von der Unit SCROLL }
- { aufgerufen und müssen unbedingt im FAR-Modus eingebunden }
- { werden !!! }
-
- {$F+}
- PROCEDURE NormalWrite(Col, Row : BYTE; Index : LongInt);
- { Normal-Ausgabe-Routine der Unit SCROLL }
- BEGIN
- GotoXY (Col, Row); TextAttr := $07;
- Write(Lines[Index]^); ClrEol
- END;
-
- PROCEDURE SelectWrite(Col, Row : BYTE; Index : LongInt);
- { Diese Routine wird von der Unit SCROLL benutzt und }
- { stellt das momentan angewählte Verzeichnis invers dar. }
- { Ferner ermittelt die Routine den kompletten Pfadnamen }
- { und bringt ihn ganz oder teilweise, auf den Bildschirm }
- VAR
- Start, Stop : BYTE;
- AktZeile : STRING;
- EPtr : EntryTypePtr;
-
- FUNCTION GetFullPath(EP : EntryTypePtr) : STRING;
- VAR
- sTemp : STRING;
- eTemp : WORD;
- Stop : BOOLEAN;
- BEGIN
- sTemp := EP^.Name; Stop := FALSE;
- WHILE (NOT Stop) AND (EP^.Back <> @Root) DO BEGIN
- eTemp := EP^.Level;
- REPEAT
- EP := EP^.Back
- UNTIL (EP = NIL) OR (Pred(eTemp) = EP^.Level);
- IF EP <> @Root THEN sTemp := EP^.Name + '\' + sTemp
- ELSE Stop := TRUE;
- END;
- sTemp := Copy(Root.Name, 1, 3) + sTemp;
- GetFullPath := sTemp;
- END;
-
- BEGIN
- AktZeile := Lines[Index]^; Stop := Length(AktZeile);
- WHILE (Stop>0) AND (AktZeile[Stop] = ' ') DO DEC(Stop);
- Start := Stop; INC(Stop);
- WHILE (Start > 0) AND (AktZeile[Start] <> '─') DO
- DEC(Start);
- IF Start = 0 THEN Start := 1;
- TextAttr := $07;
- GotoXY(Col, Row); Write(AktZeile); ClrEol;
- TextAttr := $70; GotoXY(Start, Row); Write (' ');
- GotoXY(Start+1, Row);
- Write(Copy(AktZeile, Start+1, Stop-Start));
- IF Index = 1 THEN AktPath := Copy(Root.Name, 1, 3)
- ELSE BEGIN
- EPtr := Root.Next;
- WHILE(EPtr^.Next <> NIL) AND
- (EPtr^.Counter <> Index) DO EPtr:=EPtr^.Next;
- AktPath := GetFullPath(EPtr)
- END;
- IF Length(AktPath) < (79 - xFullPath) THEN
- AktZeile := AktPath
- ELSE IF (xFullPath < 64) THEN BEGIN
- AktZeile := Copy(AktPath, 1, 3);
- AktZeile := AktZeile + '...';
- Stop := Length(AktPath);
- Start := Stop - (72 - xFullPath);
- WHILE (Start < Stop) AND (AktPath[Start] <> '\') DO
- INC(Start);
- AktZeile := AktZeile +
- Copy(AktPath, Start, Succ(Stop-Start));
- END;
- IF (xFullPath < 64) THEN BEGIN
- GotoXY(xFullPath, WhereY);
- Write(' ', AktZeile); ClrEol;
- END;
- END;
- {$F-}
-
-
- FUNCTION GetScanCode : WORD; INLINE ($31/$C0/$CD/$16);
-
- BEGIN
- GetParameter;
- MakeSubDirList;
- BuildLines;
- SetUpScrollArea(Counter, @NormalWrite, @SelectWrite);
- Key := $4700; { Key = Home }
- RedrawScrollArea;
- REPEAT
- Key := GetScanCode;
- ScrollResponse(Key);
- UNTIL (Key = $011B) OR (Key = $1C0D); { Enter o. ESC }
- HeapPtr := HeapOrg; { aufräumen ... }
- IF Key = $1C0D THEN ChDir (AktPath) { Enter .... }
- ELSE ChDir (OldPath); { ESC .... }
- IF IOResult <> 0 THEN
- ErrorMsg(TRUE,'Verzeichnisname ungültig oder zu lang!');
- TextAttr := $0F; ClrScr; WriteLn (Version);
- TextAttr := $07;
- WriteLn(' ',Counter,' Verzeichnisse gefunden. ')
- END.
- (* ------------------------------------------------------ *)
- (* Ende von TREE.PAS *)
-
-