Der Computeruser, der ĂŒber sich ewig das Damoklesschwert des Stromausfalls oder des 'Daten auf Disk X defekt?â sieht, lĂ€sst natĂŒrlich bei jedem Abspeichern das alte File irgendwie umbenennen und ĂŒberschreibt es selbstverstĂ€ndlich nicht. Aber, wenn nach arbeitsreicher Nacht alles geklappt hat und man die diversen BAK-, DUP-, SBK- etc. Files nicht mehr benötigt?
Grund fĂŒr das 1. Utility: âDelBakâ. Und dann doch der Frust: Die wichtigste Datei wurde nicht korrekt abgespeichert, das Backup-File natĂŒrlich gelöscht. Aber irgendwo auf der Platte war doch noch eine alte Version! Nur wo? Schon mal durch âzig Ordner durchgeklickt? Womit wir beim 2.Utility wĂ€ren: âFindâ.
DelBak sucht auf einem Laufwerk nach allen Dateien mit den Endungen BAK (1st Word, GFA-BASIC etc.), DUP (Tempus) und SBK (Signum). Diese werden dem Benutzer jeweils auf dem Bildschirm angezeigt, der sie dann mit beliebiger Taste auĂer n/N löschen kann. Das zu durchsuchende Laufwerk muĂ beim Programmstart (âDELBAK.TTPâ) als Argument ĂŒbergeben werden.
Beispiel:
delbak d sucht alle Backups auf Laufwerk D
Find sucht, wieder auf einem vorgegebenen Laufwerk, nach Dateien, deren Name den ĂŒbergebenen String enthĂ€lt.
Beispiel:
find d delbak findet (in unserem Fall) die Dateien delbak.m, delbak.mtp und delbak.ttp.
Es werden jeweils alle passenden Dateien zusammen mit dem jeweiligen Suchpfad ausgegeben.
Zur Programmierung
Beide Utilities entstanden nach demselben Muster, was man auch an der Ă€hnlichen Programmstruktur erkennen kann. Sie sind aber doch unterschiedlich genug, um beide abzudrucken, da eine ErklĂ€rung der nötigen Umbauten zuviel Platz einnehmen wĂŒrde.
Kernpunkt der beiden Programme ist die Routine DirQuery. Im Prinzip ist sie eine Zusammenfassung der beiden GEMDOS-Routinen Fsfirst und Fsnext, wobei bei jeder Ăbereinstimmung eines Directory-Eintrags mit dem vorgegebenen Pattern und den Fileattributen eine vom Programmierer festgelegte Prozedur aufgerufen wird. Diese Prozedur (in unserem Programmen wĂ€re das TestIfBAK bzw. TestIfFound) erhĂ€lt als Parameter den Pfadnamen des gefundenen Eintrags sowie einen Record, der den Eintrag nĂ€her beschreibt. Dieser Record entspricht der Datenstruktur, die von Fsfirst/Fsnext zurĂŒckgeliefert wird.
Die Argumentzeilenauswertung gestaltet sich (dank einem guten Library-Modul) recht einfach: Mit InitArgCV wird die Anzahl der Argumenten+ in die Variable ArgC gelegt, ArgV ist ein Array von Pointern, welche auf die einzelnen Argumentstrings zeigen. ArgV[0] ist dabei immer leer (unter UNIX steht hier der Name des aufgerufenen Programms), DelBak muĂ daher auf 2 âArgumenteâ testen, Find auf 3. Finden die beiden Programme nicht die richtige Anzahl Argumente vor, geben sie einen kurzen Text mit der Syntax des Aufrufs aus.
Wenn einem Megamax-Modulisten der Import aus Fast-Strings spanisch vorkommt: Es ist zwar kein Standardmodul (Àtsch), aber auf zwei Arten erhÀltlich:
- Ăber die MAUS-Mailbox [0251/80... (kein Witz!)], im öffentlichen Programmteil nachsehen (MM2FSTRI.ARC).
- Auf das nÀchste Update warten.
Das Modul selbst stammt von Thomas Tempelmann (Danke!!) und erfĂŒllt in etwa die gleichen Aufgaben wie das standardmĂ€Ăige Stringmodul, allerdings viel schneller (keine Fehlerkontrolle, VAR-Parameter). Wenn man also nicht in der Lage ist, das FastStrings-Modul zu bekommen, kann man auch das normale verwenden.
Beim Linken mĂŒssen auĂer M2INIT keine Module dazugelinkt werden. Wenn man zu den GlĂŒcklichen gehört, die bereits einen optimierenden Linker besitzen, erhĂ€lt man zwei wirklich kleine (< 5kB) Programme in Modula-2!! Viele mögen sich fragen, ob man das Ende eines solchen Programmes in Modula-2 ĂŒberhaupt erlebt. Nun, man tut es. Das Suchen auf einer 8 MByte-Partition (FĂŒllungsgrad ca. 50%) dauerte etwa 8s! Wenn man da keinen Geschwindigkeitsrausch bekommt ...
(*************************************************
* TITEL : DelBak *
* ZWECK : Löscht Backup-Dateien *
* AUTOREN : (c) 1988 WuSeL-Soft *
* Martin Wunderli & Patrick Seemann *
* DATUM : 01.09.1988 : Version 1.0 *
* SPRACHE : MODULA-2 (MEGAMAX MODULA V1.0) *
* Compilerversion 3.6a *
************************************************)
(*$E MTP *)
MODULE DelBak;
FROM ArgCV IMPORT
(* TYPES *) ArgStr, PtrArgStr,
(* PROCS *) InitArgCV;
FROM Directory IMPORT
(* TYPES *) FileAttr, FileAttrSet, DirEntry, DirQueryProc, Drive,
(* PROCS *) DirQuery, Delete, DefaultDrive, StrToDrive, SetDefaultDrive;
FROM FastStrings IMPORT
(* PROCS *) Append, Assign, Pos;
FROM Terminal IMPORT
(* PROCS *) WriteString, WriteLn, Write, Read;
TYPE str4 = ARRAY [0..3] OF CHAR;
VAR Result : INTEGER;
Pattern : ArgStr;
NewDrive,
BAK, DUP, SBK : str4;
James : CHAR;
ArgC : CARDINAL;
ArgV : ARRAY [0..1] OF PtrArgStr;
AktDrive : Drive;
(************************************************)
PROCEDURE TestIfBAK ( (* in *) Pfad : ARRAY OF CHAR;
(* in *) Entry : DirEntry): BOOLEAN;
VAR NeuerPfad : ArgStr;
BEGIN
IF (subdirAttr IN Entry.attr) THEN
IF NOT(Entry.name[0] = THEN
Assign (Pfad, NeuerPfad);
Append (Entry.name,NeuerPfad);
Append (Pattern, NeuerPfad);
DirQuery (NeuerPfad,FileAttrSet{subdirAttr},TestIfBAK,Result);
END (* IF *);
ELSE
IF (Pos (BAK,Entry.name) >= 0) OR
(Pos (DUP,Entry.name) >= 0) OR
(Pos (SBK,Entry.name) >= 0) THEN
Write (" ");
WriteString (Pfad);
WriteString (Entry.name);
WriteString (" Löschen (_/N)? ");
Read (James);
IF CAP(James) <> "N" THEN
Assign (Pfad, NeuerPfad);
Append (Entry.name,NeuerPfad);
Delete (NeuerPfad,Result);
END (* IF *);
WriteLn;
END (* IF *);
END (* IF *);
RETURN TRUE
END TestIfBAK;
(************************************************)
BEGIN
Pattern := "\*.*":
NewDrive := "X:";
BAK := ".BAK";
DUP := ".DUP";
SBK := ".SBK";
InitArgCV (ArgC, ArgV);
IF ArgC = 2 THEN
AktDrive := DefaultDrive();
NewDrive[0] := CAP(ArgV[1]^[0]);
SetDefaultDrive (StrToDrive (NewDrive));
DirQuery (Pattern, FileAttrSet{subdirAttr}, TestIfBAK, Result);
SetDefaultDrive (AktDrive);
ELSE
WriteString (" Usage: delbak <drive>");
WriteLn;
END (* IF *);
END DelBak.
DelBak Programm
(*************************************************
* TITEL : Find *
* ZWECK : Findet eine Datei auf dem ĂŒber- *
* gegebenen Laufwerk *
* AUTOREN : (c) 1988 WuSeL-Soft *
* Martin Wunderli & Patrick Seemann*
* DATUM : 01.09.1988 : Version 1.0 *
* SPRACHE : MODULA-2 (MEGAMAX MODULA V1.0) *
* Compilerversion 3.6a *
************************************************)
(*$E MTP *)
MODULE Find;
FROM ArgCV IMPORT
(* TYPES *) ArgStr, PtrArgStr,
(* PROCS *) InitArgCV;
FROM Directory IMPORT
(* TYPES *) FileAttr, FileAttrSet, DirEntry, DirQueryProc, Drive,
(* PROCS *) DirQuery, Delete, DefaultDrive, StrToDrive, SetDefaultDrive;
FROM FastStrings IMPORT
(* PROCS *) Append, Assign, Length, Pos;
FROM Terminal IMPORT
(* PROCS *) WriteString, WriteLn, Read;
TYPE str4 = ARRAY [0..3] OF CHAR;
VAR Result : INTEGER;
Pattern, File : ArgStr;
NewDrive : str4;
ArgC, i : CARDINAL;
ArgV : ARRAY [0..2] OF PtrArgStr;
AktDrive : Drive;
James : CHAR;
(*************************************************
PROCEDURE TestlfFound ( (* in *) Pfad : ARRAY OF CHAR;
(* in *) Entry : DirEntry): BOOLEAN;
VAR NeuerPfad : ArgStr;
BEGIN
IF (subdirAttr IN Entry.attr) THEN
IF NOT(Entry.name[0] = THEN
Assign (Pfad, NeuerPfad);
Append (Entry.name,NeuerPfad);
Append (Pattern, NeuerPfad);
DirQuery (NeuerPfad,FileAttrSet{subdirAttr}, TestIfFound, Result);
END (* IF *);
ELSE
IF (Pos (File, Entry.name) >= 0) THEN
WriteString (" Found: ") ;
WriteString (Pfad);
WriteString (Entry.name);
WriteLn;
END (* IF *);
END (* IF *);
RETURN TRUE
END TestIfFound;
(************************************************)
BEGIN
NewDrive := "X:";
Pattern := "\*.*";
InitArgCV (ArgC, ArgV);
IF ArgC = 3 THEN
AktDrive := DefaultDrive();
NewDrive[0] := CAP(ArgV[1]^[0]);
SetDefaultDrive (StrToDrive (NewDrive));
FOR i := 0 TO Length (ArgV[2]^) DO
File [i] := CAP (ArgV[2]^[i]);
END (* FOR i *);
DirQuery (Pattern, FileAttrSet{subdirAttr}, TestIfFound, Result);
SetDefaultDrive (AktDrive);
ELSE
WriteString ("Usage: find <drive> <filename>");
WriteLn;
END (* IF *);
WriteString ("Bitte Taste drĂŒcken!");
Read (James);
END Find.
Find Programm