Ein häufiger Typ von UNIX®-Anwendungen ist ein Filter
— ein Programm, das Eingaben von
stdin
liest, sie verarbeitet und das
Ergebnis nach stdout
schreibt.
In diesem Kapitel möchten wir einen einfachen Filter
entwickeln und lernen, wie wir von stdin
lesen und nach stdout
schreiben. Dieser
Filter soll jedes Byte seiner Eingabe in eine hexadezimale Zahl
gefolgt von einem Leerzeichen umwandeln.
Im Datenabschnitt erzeugen wir ein Array mit Namen
hex
. Es enthält die 16 hexadezimalen
Ziffern in aufsteigender Reihenfolge. Diesem Array folgt ein
Puffer, den wir sowohl für die Ein- als auch für die
Ausgabe verwenden. Die ersten beiden Bytes dieses Puffers werden
am Anfang auf 0
gesetzt. Dorthin schreiben
wir die beiden hexadezimalen Ziffern (das erste Byte ist auch
die Stelle an die wir die Eingabe lesen). Das dritte Byte ist
ein Leerzeichen.
Der Code-Abschnitt besteht aus vier Teilen: Das Byte lesen, es in eine hexadezimale Zahl umwandeln, das Ergebnis schreiben und letztendlich das Programm verlassen.
Um das Byte zu lesen, bitten wir das System ein Byte von
stdin
zu lesen und speichern es im ersten
Byte von buffer
. Das System gibt die Anzahl
an Bytes, die gelesen wurden, in EAX
zurück. Diese wird
1
sein, wenn eine Eingabe empfangen wird
und 0
, wenn keine Eingabedaten mehr
verfügbar sind. Deshalb überprüfen wir den Wert
von EAX
. Wenn dieser
0
ist, springen wir zu
.done
, ansonsten fahren wir fort.
Zu Gunsten der Einfachheit ignorieren wir hier die Möglichkeit eines Fehlers.
Die Umwandlungsroutine in eine Hexadezimalzahl liest das
Byte aus buffer
in EAX
, oder genaugenommen nur in
AL
, wobei die übrigen
Bits von EAX
auf null gesetzt
werden. Außerdem kopieren wir das Byte nach EDX
, da wir die oberen vier Bits
(Nibble) getrennt von den unteren vier Bits umwandeln
müssen. Das Ergebnis speichern wir in den ersten beiden
Bytes des Puffers.
Als Nächstes bitten wir das System die drei Bytes in
den Puffer zu schreiben, also die zwei hexadezimalen Ziffern und
das Leerzeichen nach stdout
. Danach
springen wir wieder an den Anfang des Programms und verarbeiten
das nächste Byte.
Wenn die gesamte Eingabe verarbeitet ist, bitten wie das System unser Programm zu beenden und null zurückzuliefern, welches traditionell die Bedeutung hat, dass unser Programm erfolgreich war.
Fahren Sie fort und speichern Sie den Code in eine Datei
namens hex.asm
. Geben Sie danach folgendes
ein (^D
bedeutet, dass Sie die
Steuerungstaste drücken und dann D
eingeben, während Sie Steuerung gedrückt
halten):
%
nasm -f elf hex.asm
%
ld -s -o hex hex.o
%
./hex
Hello, World!
48 65 6C 6C 6F 2C 20 57 6F 72 6C 64 21 0A Here I come!
48 65 72 65 20 49 20 63 6F 6D 65 21 0A ^D
%
Wenn Sie von MS-DOS® zu UNIX®
wechseln, wundern Sie sich vielleicht, warum jede Zeile mit
0A
an Stelle von 0D
0A
endet. Das liegt daran, dass UNIX® nicht die
CR/LF-Konvention, sondern die "new line"-Konvention verwendet,
welches hexadezimal als 0A
dargestellt
wird.
Können wir das Programm verbessern? Nun, einerseits ist
es etwas verwirrend, dass die Eingabe, nachdem wir eine Zeile
verarbeitet haben, nicht wieder am Anfang der Zeile beginnt.
Deshalb können wir unser Programm anpassen um einen
Zeilenumbruch an Stelle eines Leerzeichens nach jedem
0A
auszugeben:
Wir haben das Leerzeichen im Register CL
abgelegt. Das können wir
bedenkenlos tun, da UNIX®-Systemaufrufe im Gegensatz zu denen
von Microsoft® Windows® keine Werte von Registern ändern in
denen sie keine Werte zurückliefern.
Das bedeutet, dass wir CL
nur einmal setzen müssen. Dafür haben wir ein neues
Label .loop
eingefügt, zu dem wir an
Stelle von _start
springen, um das
nächste Byte einzulesen. Außerdem haben wir das Label
.hex
eingefügt, somit können wir
wahlweise ein Leerzeichen oder einen Zeilenumbruch im dritten
Byte von buffer
ablegen.
Nachdem Sie hex.asm
entsprechend der
Neuerungen geändert haben, geben Sie Folgendes ein:
%
nasm -f elf hex.asm
%
ld -s -o hex hex.o
%
./hex
Hello, World!
48 65 6C 6C 6F 2C 20 57 6F 72 6C 64 21 0A
Here I come!
48 65 72 65 20 49 20 63 6F 6D 65 21 0A
^D
%
Das sieht doch schon besser aus. Aber der Code ist ziemlich ineffizient! Wir führen für jeden einzelne Byte zweimal einen Systemaufruf aus (einen zum Lesen und einen um es in die Ausgabe zu schreiben).
Wenn Sie Fragen zu FreeBSD haben, schicken Sie eine E-Mail an
<de-bsd-questions@de.FreeBSD.org>.
Wenn Sie Fragen zu dieser Dokumentation haben, schicken Sie eine E-Mail an
<de-bsd-translators@de.FreeBSD.org>.