Programmer's Toolbox (5): Argumentexpansion

In der Einleitung zu dieser Artikelserie habe ich ein Beispiel benutzt, um die Erstellung der "Programmer's Toolbox" zu motivieren. Dort sollte das Kopieren mehrerer Dateien einer bestimmten Dateiart (C-Quelldateien) möglichst kurz als Kommandozeile notiert werden, um die Späh- und Klicktechnik des Desk-Top zu umgehen. Zur Anwendung gelangten Muster für Dateinamen:

CP C:\XYZ\*.C A:\

Nun sollen die Mechanismen vorgestellt werden, mit denen diese Dateimuster in konkreten Situationen durch eine oder mehrere Dateien ersetzt werden.

Das Stichwort lautet Argumentexpansion, da während dieses Prozesses so etwas geschieht, wie das Ersetzen des Musters durch konkrete Dateinamen, beispielsweise folgendermassen:

CP C:\XYZ\LS.C C:\XYZ\CP.C C:\XYZ\EXPAND.C A:\

Zusätzlich soll bei der Argumentexpansion auch noch berücksichtigt werden, daß neben Dateien eventuell noch eine weitere Art von Argumenten auftreten kann: Verzeichnisnamen oder Muster für Verzeichnisnamen. Betrachten Sie bitte folgende Kopieranweisung:

CP C:\ORDNER A:\ORDNER

Die Bedeutung dieses Ausdrucks ist offensichtlich das Kopieren des gesamten Verzeichnisses C:\ORDNER auf das Verzeichnis A:\ORDNER. Was hierbei geschehen muß ist eine Art "vertikale" Argumentexpansion, d.h. die Kopieranweisung für das Verzeichnis C:\ORDNER wird ersetzt durch Einzelkopieranweisungen für die Dateien innerhalb des Verzeichnisses. Darüber hinaus können die beiden Ansätze der Expansion auch noch gemischt auftreten:

CP C:\ORDNER C:\XYZ\*.C A:\ORDNER

Anmerkung: Im folgenden wird die Expansion eines Musters in eine Folge von Dateien als horizontale Argumentexpansion bezeichnet. Die (rekursive) Expansion eines Verzeichnisses wird als vertikale Argumentexpansion bezeichnet. Kommandos, die über die Fähigkeit zur vertikalen Argumentexpansion verfügen, werden auch rekursive Kommandos genannt.

In diesem Serienteil sollen nun die Methoden erarbeitet werden, mit deren Hilfe sich die beiden oben beschriebenen Arten von Argumentexpansion funktional abbilden lassen. Unabhängig vom auszuführenden Kommando (oben das Kopieren von Dateien) ist dabei zunächst ein Datentyp anzugeben, der die expandierten Dateiinformationen aufnehmen kann. Wie wir bereits in Abb.1.1 gesehen hatten, können Dateisysteme im Prinzip beliebig tief geschachtelt werden. Deswegen muß auch dieser Datentyp dazu in der Lage sein, beliebig tief geschachtelte Informationen aufzunehmen. Es bietet sich ein rekursiver Datentyp an. Und damit bin ich bereits bei der Programmierung des Moduls EXPAND (Listing 1.10). Die einzige Aufgabe von EXPAND ist die "horizontale" und "vertikale" Argumentexpansion. Der gerade skizzierte rekursive Datentyp ist hier in den Zeilen 26-45 angegeben (DIR_DESC_LIST). Einen Eindruck von seiner Komplexität vermittelt Abb.1.6. Dargestellt ist ein Beispiel für eine konkrete Schachtelung von DIR_DESC_LIST.

Zum Aufbau dieses Datentyps werden die fünf Funktionen built_flist (Zeilen 106-180), concat_flist (Zeilen 182-221), built_dir (Zeilen 248-302), built_dlist (Zeilen 304-321) und expand_dlist (Zeilen 323-384) benutzt. Entsprechend der Hierarchie innerhalb des Datentyps, werden diese unterschiedlichen Funktionen benutzt, um unterschiedliche Bereiche innerhalb des Datentyps aufzubauen. Die oberste Abstraktionsebene ist durch die Funktionen built_dlist und expand_dlist markiert. Mit diesen Funktionen wird ein Objekt des Typs DIR_DESC_LIST erzeugt (built_dlist) oder erweitert (expand_dlist). Bei diesen Vorgängen sind einige Parameter nötig, um anzugeben welche Dateien oder Verzeichnisse in den Datentyp aufgenommen werden. Zusätzlich sind Parameter vorgesehen, um den Aufbau des Datentyps zu beeinflussen. Beide Funktionen besitzen dazu folgende Parametrisierung:

argument Eine Zeichenkette, die das zu expandierende Muster enthält.

all Eine Marke, die dazu führt, daß auch die unsichtbaren Verzeichnisse "." und ".." im Datentyp mit aufgenommen werden oder auch nicht.

dir Eine Marke, die angibt, ob Verzeichnisse durchsucht werden (dir ist FALSE) oder ob nur ihre Dateinamen im durch argument markierten Vaterverzeichnis hinterlegt werden (dir ist TRUE).

rec Eine Marke, die den rekursiven Durchlauf durch sämtliche Verzeichnisse erzwingt.

relation Eine ganze Zahl, die angibt wie Dateien innerhalb der DIR_DESC_LIST sortiert werden. Folgende Werte sind für relation möglich:

0 Dateien werden nicht sortiert. In Folge wird die physikalische Abfolge auf dem Speichermedium als Reihenfolge verwendet.
1 Sortierung nach dem Dateinamen.
2 Sortierung nach dem Modifikationsdatum.

In ihrer Implementierung besitzen beide Funktionen zwar einen identischen Anfang: Durch Aufruf der in der Hierarchie untergeordneten Funktion built_dir wird die Argumentexpansion für die vorgegebenen Parameter durchgeführt (Zeilen 313-320 und 336-344). Wo aber für built_dlist die Arbeit endet, beginnt für expand_dlist erst die eigentliche Aufgabe: Nun ist die errechnete Argumentexpansion in die bereits vorgegebene DIR_DESC_LIST einzufügen. Dabei sind zwei Dinge zu berücksichtigen:

  1. Das Einfügen erfolgt in eine bereits nach Verzeichnisnamen vorsortierte Liste (dlist). Entsprechend ist ein Einfügeverfahren für sortierte Listen zu verwenden (Zeilen 345-382).

  2. Es besteht die Möglichkeit, daß ein Eintrag in der dlist bereits existiert, nichtsdestotrotz aber noch einmal unter anderen Parametern expandiert worden ist. In diesem Fall müssen die beiden Ergebnisse der Expansion zusammengefaßt werden. Dies geschieht mit einem Aufruf der Funktion concat_flist (Zeilen 355-368).

Wenden wir uns nun den tieferen Hierarchieebenen innerhalb der fünf Funktionen zu. Zunächst findet man hier die Funktion built_dir. Sie wird direkt von den beiden vorangehend beschriebenen Funktionen aufgerufen und dient als eine Art Vermittler zwischen built_dlist und expand_dlist und der darunterliegenden Funktion built_flist. Die Vermittlerfunktion besteht dabei in der Aufbereitung der Parameter für die niedrigere Ebene. In built_dir werden dabei insgesamt zwei Aufgaben erfüllt. Zum einen wird der in der oberen Funktionsebene noch als Zahlenwert umschriebene Sortiermodus (relation) durch eine Referenz auf eine Funktion ersetzt (rel, Zeilen 262-272). Zum anderen wird das argument in den Verzeichnisnamen und in den Dateinamen "aufgebrochen". Ein relativer Verzeichnisname wird dabei in sein absolutes Äquivalent expandiert (Zeilen 274-293). Beim Aufruf von built_flist ist noch zu berücksichtigen, daß built_dir auch ohne Muster für einen Dateinamen aufgerufen werden kann. In diesem Fall wird angenommen, daß das komplette Verzeichnis expandiert werden soll. Entsprechend wird das Muster "." angenommen und im built_flist-Aufruf (Zeile 295-296) verwendet. In den übrigen Situationen wird built_flist mit dem ermittelten Dateinamen aufgerufen (Zeile 298-299).

Auf der niedrigsten funktionalen Ebene werden nun direkt Listen von Dateibeschreibungen (FILE_DESC_LIST) betrachtet. Zum Aufbau einer solchen Liste erhält die betreffende Funktion (built_flist) folgende Parameter:

directory Der vollständig expandierte Pfad des Verzeichnisses, das betrachtet werden soll.
filename Das Muster für die auszuwählenden Dateinamen.
all, rec Die beiden Marken, die aus der höheren funktionalen Ebene (built_dir, built_dlist) herabgereicht worden sind.
rel Ein Zeiger auf die Funktion, die den Vergleich von Dateieinträgen vornimmt.

Mit diesem Parametersatz kann die Aufgabe der Argumentexpansion direkt auf die GEMDOS-Funktionen zur Musterexpansion (Fsfirst, Fsnext, Fgetdta und Fsetdta) abgebildet werden. Nach den Einleitungspreliminarien - Setzen des DTA-Puffers; Sichern des alten Arbeitsverzeichnis; Wechseln ins neue Arbeitsverzeichnis (Zeilen 123-127) -, erfolgt dann auch prompt eine Folge von Fsfirst/Fsnext-Aufrufen, die die gewünschten Daten abrufen. Diese GEMDOS-Funktionsaufrufe sind eingebettet in eine größere while-Schleife (Zeilen 131-164), in der auch gleich das Einfügen der ermittelten Ergebnisse in die FILE_DESC_LIST erfolgt. Auch hier findet man wieder das Einfügen in eine sortierte Liste. Im Gegensatz zum Einfügen in die DIR_DESC_LIST wird diesmal jedoch eine parametrisierbare Relation (rel) verwendet, um die unterschiedlichen Sortiermodi zu unterstützen. Die if-Anweisung in den Zeilen 132 und 133 stellt dabei sicher, daß die Auswahl unter den ermittelten Dateinamen gemäß der Marke all erfolgt, d.h. die unsichtbaren Verzeichnisse - "." und ".." - werden nur dann mit in die FILE_DESC_LIST aufgenommen, wenn die Marke all gesetzt ist. Im weiteren Ablauf von Funktion built_flist erfolgt nun, in Abhängigkeit von der Marke rec, der rekursive Aufruf von built_flist, um die "vertikale" Argumentexpansion abzubilden (Zeilen 165-176). Der Rest der Funktion besteht aus dem Rücksetzen des aktuellen Verzeichnisses und des DTA-Puffers auf ihre alten Werte (Zeilen 177-178). Anzumerken bleibt noch, daß der Typ zur Aufnahme der Dateiinformationen (FILE_DESC) gerade der Struktur des DTA-Puffers entspricht. Das Kopieren der Informationen aus dem DTA-Puffer in die FILE_DESC-Struktur kann mithin durch bloße Zuweisung geschehen (Zeile 136).

Es verbleibt die Erläuterung der Funktion concat_flist. Wie bereits gesagt wird concat_flist von expand_dlist aufgerufen, um zwei FILE_DESC_LIST's über demselben Verzeichnis zu verschmelzen. Entsprechend besteht die Funktion concat_flist im wesentlichen aus zwei ineinandergeschachtelten Schleifen, die das Verschmelzen der Listen vornehmen. Die äußere Schleife (Zeilen 191-220) durchläuft dabei die Quelliste (srclist). Diese Liste wird von vorne beginnend abgebaut. Ihre Komponenten werden dabei in der inneren Schleife (Zeilen 198-217) in die Zielliste (destlist) eingefügt. Auch hier wird dazu die parametrisierbare Relation rel verwendet. Sie ist vom aufrufenden Programm vorzugeben.

Mit den gerade diskutierten fünf Funktion ist die Argumentexpansion in der gewünschten Form realisiert. Die restlichen, wenigen Zeilen des Listings 1.10 beschäftigen sich mit der Freigabe des rekursiven Datentyps DIR_DESC_LIST (Zeilen 403-424). Die betreffenden Funktionen - drop_dlist (Zeilen 403-411), drop_dir (Zeilen 413-416) und drop_flist (Zeilen 418-424) - bauen dabei auf die gleiche Weise aufeinander auf, wie ihre drei Namensvettern bei der Argumentexpansion. Allerdings sind die Freigabefunktionen an sich wesentlich einfacher und bedürfen wohl keiner weiteren Erläuterung.

Am Ende dieses Serienteils steht zum zweiten Mal eine Header-Datei. Wie bereits die Funktionen aus ATOM.C, so sollen auch die Funktionen aus Listing 1.10 in dem Modul EXPAND zusammengefaßt werden. Die entsprechenden Typ- und Funktionsdeklarationen werden in der Datei EXPAND.H untergebracht. Sie finden Sie im Listing 1.11 abgedruckt.

Vorausschau

Beim nächsten Mal benutzen wir die Argumentexpansion, um einige weitere Kommandos zu formulieren. Es handelt sich um:

LS - Anzeigen von Dateiinformationen
CP - Dateien kopieren
MV - Dateien bewegen

Besonders LS wird dabei reichhaltige Optionen bereitstellen.

Listings zur Programmer's Toolbox (5)


Dirk Brockhaus
Aus: ST-Computer 11 / 1990, Seite 110

Links

Copyright-Bestimmungen: siehe Über diese Seite