8086 Assembler (MS-DOS):
LS.com: Inhaltsanzeige eines Verzeichnisses mit langen Dateinamen

Hinweis: Ein praktisch funktionsgleiches 32-bit-Programm ist im Abschnitt über den MASM32-SDK beschrieben. Das 32-bit-Programm ist auch in Windows-Versionen ab Windows 7 verwendbar. Das auf dieser Seite für MS-DOS beschriebene 16-bit-Programm lässt sich ab Windows 7 nicht mehr verwenden.
Dies Programm entstand, weil ich eine Verzeichnisanzeige in ein umfangreicheres anderes Programm einbauen wollte. Es ist bewährte Praxis, komplexe Programmaufgaben in möglichst einfacher Umgebung zu erproben. Ist die Lösung gefunden und erprobt, kann sie in das umfangreichere Programm eingebaut werden.

Unter der Bedieneroberfläche der alternativen Bedieneroberfläche 4dos werden die langen Dateinamen in ihrer verkürzten Form angezeigt. Das Programm ls schafft hier Abhilfe. Genau wie das Kommando DIR listet es Dateinamen und Unterverzeichnisse eines Verzeichnisses auf.

Aufgerufen wird es durch Eingabe von
ls [Laufwerk:][Pfad][Dateiname]

Werden weder Laufwerk, Pfad noch Dateiname angegeben, wird das Inhaltsverzeichnis des aktuellen Verzeichnisses gezeigt. Bei Pfad und Dateiname sind Substitutionsangaben wie * oder ? zulässig.

Um eine möglichst große Ähnlichkeit zum Kommando DIR zu erreichen, wird die Eingabe in zwei Fällen modifiziert. Zwei weitere Änderungen verbessern den Bedienkomfort.

  1. Wurde ls ohne Parameter aufgerufen, unterstellt das Programm, dass es mit dem Parameter * aufgerufen wurde.
  2. Wurde als letztes Zeichen der Parameterleiste ein \ eingegeben, so unterstellt das Programm, dass nach dem Bruchstrich ein * folgte.
  3. Steht als letztes Zeichen der Parametereingabe ein Doppelpunkt, so führt das Programm die Inhaltsanzeige des Grundverzeichnisses der vor dem Doppelpunkt spezifizierten Platte durch. LS c: liefert also das Inhaltsverzeichnis von Laufwerk c:. LS : meldet sich dagegen mit einer qualifizierten Fehlernachricht zurück. Sie lautet:
    D:\dos\ML\Test>ls: Die Syntax fuer den Datei- oder Verzeichnisnamen ist falsch. Programmabbruch!
  4. Bruchstriche in der eingegebenen Parameterleiste werden in \ gewandelt.

Die unter 2 genannte Änderung ist ein kleiner Unterschied zu DIR. DIR d:\temp liefert das Inhaltsverzeichnis des Verzeichnisses d:\temp. LS d:\temp dagegen liefert lediglich eine Zeile mit Informationen über das Verzeichnis d:\temp. Erst LS d:\temp\ zeigt das Inhaltsverzeichnis des Verzeichnisses d:\temp.

Zur Ermittlung des Verzeichnisinhalts werden die Funktionen 714Eh und 714Fh des MS-DOS Interrupts 21h herangezogen. Sie melden die Sucherfolge in einem Suchsatz zurück. Im Programmlisting ist seine Feldaufteilung beim Merkmal suchsatz definiert.

Es werden Änderungsdatum und -zeit sowie die Attribute angezeigt. Alle diese Dinge sind etwas knifflig zu programmieren.

Anzeige des Attributbytes

Innerhalb der auszugebenden Zeichenkette msg_satz steht beim Merkmal msg_attrs die Zeichenkette ADSHR. Jeder Buchstabe kennzeichnet ein gesetztes Attribut. Ist das Attribut bei dem anzuzeigenden Datei- oder Verzeichnisnamen nicht gesetzt, wird der entsprechende Buchstabe durch ein Minuszeichen ersetzt. Nach der Anzeige wird die solcherart modifizierte Zeichenkette mit dem Inhalt des Feldes beim Merkmal attrs überschrieben und somit wieder hergestellt. Die Wiederherstellung ist im Programm beim Label ls80 zu finden.

Anzeige von Änderungsdatum und -zeit

Beim Aufruf der Funktionen 714Eh und 714Fh wird durch den Inhalt des SI-Registers diese Information im „alten” DOS-Format angefordert. Somit werden beide Informationen in jeweils einem halben Doppelwort geliefert. Jedes halbe Doppelwort ist in Bitgruppen unterteilt. Für die Anzeige müssen die Bitgruppen entsprechend aufgeteilt und von binär in dezimal und ASCII umgewandelt werden. Die Aufteilung ist:
ElementBitsInhalt des Binärwertes
Tag0…41…31
Monat5…81…12
Jahr9…150…119 Jahreszahl - 1980

Sekunde0…40…29 doppelte Sekunde
Minute5…100…60
Stunde11…150…24

Gewöhnungsbedürftig ist die Anzeige der Datei- oder Verzeichnislänge in hexadezimaler Schreibweise statt in Dezimal. Dadurch wird Platz in der Anzeigezeile auf dem Bildschirm gespart. Es lässt sich auch so gut erkennen, welche Datei besonders groß oder besonders klein ist. Nachfolgend sind ähnliche Anzeigen vom DIR und LS dargestellt. Beide Kommandos wurden unter der Bedieneroberfläche CMD ausgeführt.

D:\dos\ML\Test>dir *asm
 Datenträger in Laufwerk D: ist HP_D
 Volumeseriennummer: 402E-2809

 Verzeichnis von D:\dos\ML\Test

26.02.2011  08:10             6.888 attr.asm
27.01.2011  08:10            19.631 BATC.ASM
13.02.2011  13:20            25.633 DOS.asm
15.02.2011  12:04            12.191 GO_HP.ASM
15.02.2011  12:09            12.279 GO_TBIRD.ASM
26.02.2011  08:10             6.888 LS.ASM
18.02.2011  15:39             4.134 MORE.ASM
26.02.2011  07:45            17.958 sh.asm
23.02.2011  16:07            17.719 shell.asm
17.02.2011  07:43            13.401 shellsav1.asm
18.02.2011  18:46            13.817 shellsav2.asm
06.02.2011  13:41             7.924 tee.asm
12.02.2011  13:36             4.734 test.asm
25.01.2011  04:31             1.751 VERS.ASM
              14 Datei(en),        164.948 Bytes
               0 Verzeichnis(se), 21.212.536.832 Bytes frei

D:\dos\ML\Test>ls *asm
26.02.11 08:10 A---- 00001AE8 attr.asm
27.01.11 08:10 A---- 00004CAF BATC.ASM
13.02.11 13:20 A---- 00006421 DOS.asm
15.02.11 12:04 A---- 00002F9F GO_HP.ASM
15.02.11 12:09 A---- 00002FF7 GO_TBIRD.ASM
26.02.11 08:10 A---- 00001AE8 LS.ASM
18.02.11 15:39 A---- 00001026 MORE.ASM
26.02.11 07:45 A---- 00004626 sh.asm
23.02.11 16:07 A---- 00004537 shell.asm
17.02.11 07:43 A---- 00003459 shellsav1.asm
18.02.11 18:46 A---- 000035F9 shellsav2.asm
06.02.11 13:41 A---- 00001EF4 tee.asm
12.02.11 13:36 A---- 0000127E test.asm
25.01.11 04:31 A---- 000006D7 VERS.ASM

D:\dos\ML\Test>

.MODEL TINY
;======================================
;ls - Directory-Anzeige aehnlich DIR
;======================================
;
FALSE   EQU     0
TRUE    EQU     NOT FALSE

;von den mit true ausgewaehlten Unterprogrammen wird nur
;INT2ASC benoetigt (und zwar bei der Aufbereitung der Jahreszahl)
dump$   equ     false   ;fuer mdump,  rdump
prompt$ equ     false   ;fuer PROMPT, INKJN
intasc$ equ     true    ;fuer INT2ASC, ASC2INT
string$ equ     false   ;fuer CMPSTR, LENSTR, INSTR, MOVSTR

comment #
Programm zum Erproben der Directorysuchfunktionen mit langen Namen.
25.2.2011, Fredrik Matthaei
#
.CODE
        org     100h

_start: jmp     around
        include firm.mac

;------------------------------------
; Datenbereiche und Texte

handle  dw      0

msg02:  dbz     'Datei nicht gefunden.'
msg03:  dbz     'Pfad nicht gefunden.'
msg05:  dbz     'Zugriff verweigert.'
msg7b:  dbz     'Die Syntax fuer den Datei- oder Verzeichnisnamen ist falsch.'
msg7100: dbz    'Funktion 71xx wird nicht unterstuetzt.'
msgxx:  dbz     '=Nicht aufgeschluesselter Fehler.'

attrs   db      "ADSHR"
msg_satz        equ     $
msg_ttmmjj      db      "tt.mm.jj "
msg_hhmm        db      "hh:mm "
msg_attrs       db      "ADSHR "
msg_len         db      "12341234 "
        db      0               ;hier Ausgabeende

;Beschreibung des Suchsatzes
suchsatz equ    $
gef00h  dd      0               ;Attribut lh 00
gef04h  dq      0               ;wann erstellt lh lh 00 00
gef0ch  dq      0               ;wann zuletzt zugegriffen lh lh 00 00
gef14h  dq      0               ;wann zuletzt geaendert lh lh 00 00
gef1ch  dd      0,0             ;Dateigroesse High :Low  00 00 : lh lh
gefres  db      '12345678'      ;reserviert
curlfn  db      260 dup ('0')   ;langer Name
cussfn  db      14 dup ('1')    ;kurzer Name 1111111111111

;------------------------------------
;Hauptprogramm
around:
        mov     si,lparm        ;Laenge des Parameters
        xor     ch,ch
        mov     cl,es:[si]
        inc     si
        or      cx,cx
        jne     ls10            ;Programmaufruf erfolgte mit Parameter

;Programmaufruf erfolgte ohne Parameter: wir denken uns einen *
        dec     si
        inc     cx              ;cx nun auf 1
        mov     es:[si],cx
        inc     si
        mov     w es:[si],002ah

ls10:   add     si,cx           ;si zeigt nun auf cr des eingetippten Parameters
        mov     b es:[si],ch    ;aus diesem cr wird 0

;wenn ein Doppelpunkt als letztes Zeichen eingetippt wurde, dann kommt
;ein Backslash hinzu
        dec     si
        cmp     b es:[si],':'
        jne     ls12
        inc     si
        mov     b es:[si],'\'
;aus / wird \
ls12:   mov     di, lparm+2     ;di zeigt nun auf Parameteranfang
ls13:   cmp     b [di],0
        je      ls15            ;Abfrage auf Parameterende
        cmp     b[di],'/'
        jne     ls14            ;/ wird \
        mov     b[di],'\'
ls14:   inc     di
        jmps    ls13

;wenn als letztes Zeichen ein Backslash steht, dann kommt ein * hinzu!
ls15:   cmp     b es:[si],'\'
        jne     ls20
        inc     si
        mov     w es:[si],002ah

ls20:   mov     cl,5eh  ;moegliche Attribute
        mov     ch,0    ;erforderliche Attribute
        mov     DX,lparm+2      ;Suchmaske ab lparm +2
        mov     si,1            ;altes Datumsformat
        mov     di,offset suchsatz

        stc                     ;Fehlermeldung falls MS-DOS die
        mov     ax,714eh        ;Funktion 71xx nicht unterstuetzt
        int21
        jnc     ls22
        jmps    fehler

ls22:   mov     handle,ax       ;handle sichern
        call    ls50

nochmal:
        mov     si,1    ;altes Datumsformat
        mov     di,offset suchsatz
        mov     bx,handle
        stc                     ;Fehlermeldung falls MS-DOS die
        mov     ax,714fh        ;Funktion 71xx nicht unterstuetzt
        int21
        jnc     ls24
        jmps    fehler

ls24:   call    ls50
        jmps    nochmal

;--------------------------------
;Fehlerbearbeitung und normales Programmende
fehler: cmp     ax,0012h        ;keine weitere Datei gefunden
        jne     fehler2
        jmp     fertig

fehler2: cmp    ax,0002
        jne     fehler3
        mov     si, offset msg02
        jmps    fehler99

fehler3: cmp    ax,03
        jnz     fehler5
        mov     si,offset msg03
        jmps    fehler99

fehler5: cmp    ax,05
        jnz     fehler7b
        mov     si,offset msg05
        jmps    fehler99

fehler7b:
        cmp     ax,7bh
        jnz     fehler7100
        mov     si, offset msg7b
        jmps    fehler99

fehler7100:
        cmp     ax,7100h
        jnz     fehlerxx
        mov     si,msg7100
fehlerxx:
        push    ax
        mov     al,ah
        call    hex_out
        pop     ax
        call    hex_out
        mov     si, offset msgxx

fehler99:
        call    printa                  ;Fehlermeldung zeigen
        prstr   <' Programmabbruch!',cr>
        MOV     AX,4C01H                ;Programmende mit Returncode 1
        int21
        jmp     fertig

;------------------------
; Unterprogramm Aufbereiten und Zeigen der Anzeigezeile
;------------------------------------
; Unterprogramm Wandeln und Abspeichern 8 bit Zahl (in al) in hexa
bin_hex:
        xchg    al,ah
        push    ax
        shr     al,4
        call    binhex5
        pop     ax
binhex5:
        and     al,0fh
        daa
        add     al,0f0h
        adc     al,40h
        mov     ds:[di],al
        inc     di
        ret

;------------------------
; Attribut zum Anzeigetext
ls50:
        mov     cx,6            ;6-mal schieben

        mov     si, offset gef00h
        mov     b al,ds:[si]
        mov     di,offset msg_attrs+4

ls55:   cmp     cx,3            ;Attribut Volume Label ignorieren
        jne     ls60
        rcr     al,1
        jmps    ls70

ls60:   rcr     al,1
        jc      ls65            ;Attribut gesetzt

        mov     b ds:[di],'-'
ls65:   dec     di

ls70:   loop    ls55

;------------------------
; Tag letzte Aenderung zum Anzeigetext
        mov     si,offset gef14h+2
        mov     w ax,ds:[si]
        push    ax
        and     ax,001fh        ;alles ausser Tag ausmaskieren
        mov     bl,10
        div     bl
        or      ax,3030h        ;Wandlung in ASCII
        mov     w msg_ttmmjj,ax

        pop     ax
        push    ax
        sar     ax,9
        and     ax,007fh        ;alles ausser Jahreszahl ausmaskieren
        add     ax,1980         ;Jahreszahl korrigieren
        xor     dx,dx

        mov     di,offset msg_ttmmjj+7
        call    int2asc

        pop     ax
        sar     ax,5
        and     ax,000fh        ;alles ausser Monat ausmaskieren
        div     bl
        or      ax,3030h        ;Wandlung in ASCII
        mov     w msg_ttmmjj+3,ax       ;Monat ueberschreibt Jahrtausend
        mov     b msg_ttmmjj+5,'.'      ;Punkt ueberschreibt Jahrhundert

;------------------------
; Uhrzeit letzte Aenderung zum Anzeigetext

        mov     si,offset gef14h
        mov     w ax,ds:[si]
        push    ax
        sar     ax,5
        and     ax,003fh        ;alles ausser Minuten ausmaskieren
        mov     bl,10
        div     bl
        or      ax,3030h        ;Wandlung in ASCII
        mov     w msg_hhmm+3,ax

        pop     ax
        sar     ax,11
        and     ax,001fh        ;alles ausser Stunden ausmaskieren
        mov     bl,10
        div     bl
        or      ax,3030h        ;Wandlung in ASCII
        mov     w msg_hhmm,ax

;------------------------
; Dateilaenge hexadezimal zum Anzeigetext. Maximal werden 4 GB
; Dateilaenge erkannt.

        mov     di,offset msg_len
        mov     si,offset gef1ch+6      ;Dateilaenge High Word
        mov     ax,ds:[si]
        call    bin_hex
        mov     al,ah
        call    bin_hex
        dec     si
        dec     si
        mov     ax,ds:[si]              ;Dateilaenge Low Word
        call    bin_hex
        mov     al,ah
        call    bin_hex

        mov     si,offset msg_satz +47
        mov     b ds:[si],0             ;Schutzbyte, markiert etwa Zeilenende
        sub     si,47
        call    printa

; langen Dateinamen anzeigen
        mov     si,offset curlfn
        call    printa

        print_crlf

; Inhalt von msg_attrs wieder herstellen
        mov     si,offset attrs
        mov     di,offset msg_attrs
        mov     cx,5            ;5 Bytes Laenge u
ls80:   mov     b al,ds:[si]
        mov     b ds:[di],al
        inc     si
        inc     di
        loop    ls80
        ret

;----------------------------------
; Programmbeendigung
fertig:
        mov     bx,handle       ;Suche beendet, Handle freigeben
        mov     ax,71a1h
        int21

        mov     ax,4c00h        ;Programm beenden
        int21
        END     _start
Letztes Upload: 24.03.2023 um 11:35:12 • Impressum und Datenschutzerklärung