Home |
8086 Assembler,
|
Zurück zur Assemblerauswahlseite |
|
sh.asm ist ein Übungsprogramm - es ist wunderbar zum Spielen und Lernen geeignet, aber sonst lässt sich damit wenig anfangen. Inhaltlich ist das Übungsprogramm eine leicht zu erweiternde Bedieneroberfläche. Man kann das Programm von der Windows-Oberfläche aus unmittelbar starten und als Bedieneroberfläche benutzen. Jedoch ist bereits in MS-DOS mindestens ein besser geeignetere Befehlsprozessor als Bedieneroberfläche enthalten. Das Programm zeigt beispielhaft, wie ein Kindsprozess geladen und aufgerufen werden kann. Solche Beispiele sind hilfreich, denn nur die Kenntnis der Funktionsweise von Funktion 4Bh des Interrupts 21h ist für die erfolgreiche Programmierung eines Kindsprozessaufrufes unzureichend. Andere Bezeichnungen für Bedieneroberflächen in diesem Zusammenhang sind „Shell“ (englisch Schale, z.B. die Schale einer Nuss oder die Eischale), Befehlsprozessor oder neudeutsch zusammengemischt „Kommandointerpreter“. Unter MS-DOS kommuniziert der Benutzer mit einem Befehlsprozessor wie COMMAND, CMD oder beispielsweise 4DOS. COMMAND und CMD werden von Microsoft mit dem Betriebssystem geliefert, 4DOS ist hier stellvertretend für einen alternativen Befehlsprozessor genannt. Beim Start von MS-DOS wird eine Umgebungsblock (Environment Block) gefüllt. Sein erster Eintrag beginnt mit der Zeichenfolge „COMSPEC=“. Es folgt der Name der Kommandoprozessors mit seinem vollständigen Pfad. Mit dem Kommando „set“ lässt sich der Inhalt des Umgebungsblocks anzeigen. Die Funktion des ursprünglichen Programmes SHELLIn seiner Urausführung unterstützt das Programm genau drei sichtbare parameterlose Kommandos: CLS, DOS und EXIT. Wird ein davon abweichendes Kommando eingetippt, wird dies Kommando an den im Umgebungsblock eingetragenen Befehlsprozessor durchgereicht. Dieser Befehlsprozessor versucht, das Kommando auszuführen und gibt danach die Steuerung wieder an das Programm SHELL zurück.Durchgeführte ÄnderungenDas Quellprogramm in seiner ursprünglichen Fassung[250,Seite 199ff] ist 329 Zeilen lang. Weniger als 150 Zeilen davon sind erhalten geblieben.Quellprogrammteile aus dem ursprünglichen Programm sind im weiter unten dargestellten Listing in durchgängiger Großschrift gehalten. Aus dem Kapitel "Introduction" und der Beschreibung der Funktion 4Bh des Interrupts 21h des oben genannten Buches ergibt sich, dass die Verwendung des im Buch dargestellten ursprünglichen Programmes als Grundgerüst für eigene Programmentwicklungen zulässig (Seite XI: Each entry includes a brief assembly-language program example that you can use as a skeleton for setting up your own calls und Seite 359: Example: See Chapter 10). Die von mir durchgeführten Änderungen, Ergänzungen und Funktionserweiterungen sind daran zu erkennen, dass auch kleine Buchstaben verwendet werden. Die Logik zum Auswerten der Kommandozeile ist gegenüber dem Original nur wenig erweitert worden: Schrägstriche (/ Slash) werden ein Rückstriche (\ Backslash) gewandelt. Auch die Fehlerbearbeitung hat sich - abgesehen von Erweiterungen - nur wenig geändert.
|
title 'sh kleine MS-DOS shell'
.286c
comment #
----------------------------------------
Die Auswertung der angewaehlten Funtion basiert auf dem Programm SHELL.ASM
in Ray Duncan: Advanced MS-DOS'- The Microsoft guide for Assembly Language
and C programmers, Microsoft Press, (c)1986 by Ray Duncan. Das Programm
SHELL.ASM ist dort auf den Seiten 199 - 205 abgedruckt.
Nur die aus SHELL.ASM uebernommene Bestandteile sind in Grosschrift
gehalten.
Fredrik Matthaei, 28.Feb.2011
---------------------------------------- #
STDIN EQU 0 ;Handle Standardeingabe
video equ 10h
dos equ 21h
lparm equ 0080h ;Parameterlaenge
false equ 0
true equ not false
w equ word ptr
b equ byte ptr
tab equ 9
spc equ ' '
cr equ 0dh
lf equ 0ah
escp equ 1bh
int21 macro intnr
ifnb <intnr>
mov ah,intnr
endif
int dos
endm
jmps macro to ;;kurzer sprung
jmp short to
endm
dbl macro text ;;definiert eine zeile
ifb <text>
db cr
else
db text,cr
endif
endm
dbz macro text ;;definiert einen string mit 0 am ende
ifb <text>
db 0
else
db text,0
endif
endm
dblz macro text ;;definiert eine zeile und 0 am ende
ifb <text>
db cr,0
else
db text,cr,0
endif
endm
prstr macro texte ;;print string
call prmsg
dbz <texte>
endm
print_crlf macro
call $print_crlf ;;ausgabe cr lf
endm ;;zum bildschirm
;----------------------------------------------
CSEG SEGMENT PARA PUBLIC 'CODE'
ASSUME CS:CSEG,DS:DATA,SS:STACK
;==============================================
; Vorprogramm
;==============================================
_start:
MOV AX,DATA
MOV DS,AX
;--------------------------------
; Uebernahme von beim Programmstart mitgegebenen Parametern
; in den Eingabebereich inp_buf.
; Geschieht, solange Register ES noch auf den PSP-Bereich zeigt
xor ch,ch ;im PSP auf Adr. 80h steht die Laenge
mov b cl,es:[0080h] ;der Programmaufrufparameter
or cl,ch
jz v10 ;kein Parameter wurde eingegeben
mov si,82h ;ab Adr. 82h steht der Parametertext
mov bx,offset inp_buf
v05:
mov b al,es:[si] ;Parameter zum Eingabepuffer
inc si
mov b ds:[bx],al
inc bx
loopnz v05
mov b merke,1 ;merken Parameteruebernahme
v10:
;--------------------------------
; Erst nach der Parameteruebernahme folgt die Hauptspeicherfreigabe
; und die weitere Programminitialisierung
MOV AX,ES:[002CH] ;Segmentadr. des eigenen Environmentblockes
MOV ENV_SEG,AX
MOV BX,100H ;neue Blockgroesse 100h * 10h Bytes
int21 04ah
JNC v15
MOV si,OFFSET MSG1 ;unable to de-allocate memory
jmps shell_abbruch
v15: ;get the comspec
MOV SI,OFFSET COM_VAR
CALL GET_ENV
JC v25 ;ggf. Fehlermeldung
MOV SI,OFFSET COM_SPEC_dos
v20: MOV AL,ES:[DI] ;COMSPEC-Eintrag des Umgebungsblockes
MOV [SI],AL ;kopieren nach COM_SPEC_dos
INC SI
INC DI
OR AL,AL
JNZ v20
jmps v35
v25: MOV si,OFFSET MSG3 ;hier Fehlermeldung MSG3
;--------------------------------
; Programmabbruch mit Fehlermeldung
shell_abbruch:
call printa ;Fehlermeldung zeigen
MOV AX,4C01H ;Programmende mit Returncode 1
int21
v35: MOV DX,OFFSET h00 ;Set CNTR-C vector
MOV AX,CS
MOV DS,AX
MOV AX,2523H ;eigene Interruptroutine für Interrupt 23h
int21 ;Int 23h ist ein Unterprogramm(!) zur
MOV AX,DATA ;Reaktion auf Break ist Lesen von
MOV DS,AX ;Tastatur
MOV ES,AX
print_crlf ;Ausgabe cr einmalig bei Programmbeginn
cmp b merke,1 ;wurden Parameter uebernommen?
je h05 ;ja: erstes Kommando steht bereit
;nein: lesen von Tastatur
;==============================================
; Hauptprogramm
;==============================================
; Verarbeitung der Kommandoeingabe. Die Kommandos werden
; von Tastatur eingelesen. Lediglich ein einziges Kommando
; kann (muss aber nicht) bei Progrtammstart als Parameter
; mitgegeben werden. Wurde beim Programmstart ein Parameter
; mitgegeben, so hat das Byte "merke" den Inhalt 1 (vergleiche
; die beiden letzten Befehle unmittelbar vor diesem Kommentar).
;
; Der Vektor fuer INT 23h wurde auf das Label h00 umgeleitet -
; somit laesst sich dies Programm nicht per CTRL-C - Tastenkombination
; abbrechen
h00: cmp merke_exit,'!' ;forderte das letzte
jne h01 ;Kommando EXIT an?
JMP exit_cmd ;ja!
h01: prstr <CR,'sh:',3eh>
MOV DX,OFFSET INP_BUF
MOV CX,INP_BUF_LENGTH
MOV BX,STDIN ;Lese von Tastatur
int21 3fh
h05: mov schutzbyte,cr ;Inhalt des Schutzbytes erneuern
MOV SI,OFFSET INP_BUF
MOV CX,INP_BUF_LENGTH
CMP b [SI],cr ;cr kennezeichnet Zeilenende
je h00
;----------------------------------------------
; Verarbeitung des Kommandos. Buchstaben a bis z werden in Grossschrift
; gewandelt, / wird zu \
h10:
cmp b [si],cr
je h17 ;Vorzeitiges Abfrageende bei cr
CMP b [SI],'a' ;Wandlung der Eingabe in Grossschrift
jb h12
CMP b [SI],'z'
ja h12
SUB b [SI],'a'-'A'
h12: cmp b[si],'/'
jne h15 ;/ wird \
mov b[si],'\'
h15: INC SI
LOOP h10
h17:
dec si ;auf Zeichen vor dem cr
cmp b [si],'!' ;wird EXIT angefordert?
jne h18 ;nein
mov merke_exit,'!' ;ja! Merken fuer naechste EXIT-Abfrage bei h00
mov b [si],cr ;! im Eingabestring abschneiden
; Eingabestring in Kommandotabelle suchen
h18: MOV SI,OFFSET COMMANDS
h20: CMP b [SI],0 ;Eintragsende in Kommandotabelle
JE h50 ;erreicht?
MOV DI,OFFSET INP_BUF ;Ueberlesen fuehrende Blanks
h25: CMP b [DI],spc
JNE h30
INC DI
jmps h25
h30: MOV AL,[SI] ;Eintragsende in Kommandotabelle erreicht?
OR AL,AL
JZ h35 ;ja
CMP AL,[DI] ;nein. Dann Eingabezeichen=Kommandotabelle?
JNZ h45 ;nein
INC SI ;ja. Dann ein Zeichen weiter
INC DI
jmps h30
h35: CMP b [DI],CR ;Gleichheit. Ist hier Eingabeende?
JE h40 ;ja
CMP b [DI],spc ;nein. Blank wuerde akzeptiert werden.
JNE h45
h40: CALL W [SI+1] ;Aufruf des zum Kommando passenden Unterprogramms
jmp h00 ;Naechste Kommandoeingabe anfordern
h45: LODSB
OR AL,AL ;in Kommandotabelle auf naechsten Eintrag
JNZ h45
inc si
inc si
jmps h20
; Wenn Eintragsende in Kommandotabelle erreicht
h50: CALL ext ;Send external command an Kommandointerpreter
jmp h00
STK_SEG DW 0 ;SS Sicherung Pointer auf Stacksegment
STK_PTR DW 0 ;SP Sicherung Stackpointer
;----------------------------------------------
; DOS Kommando zum Aufruf des Kommandointerpreters
DOS_CMD:
MOV PAR_CMD_dos,OFFSET NULTAIL
MOV DX,OFFSET COM_SPEC_dos ;Pfad zum auszufuehrenden Programm
MOV BX,OFFSET PAR_BLK_dos
jmps ext5
;----------------------------------------------------
; Uebergabe der Kommandozeile an den Kommandointerpreter falls
; sh.exe das Kommando nicht verarbeiten kann.
;
ext:
MOV AL,CR ;sucht cr im String ES:DI
MOV CX,CMD_TAIL_dos_LENGTH
MOV DI,OFFSET CMD_TAIL_dos+1
CLD
REPNZ SCASB
MOV AX,DI
SUB AX,OFFSET CMD_TAIL_dos+2
MOV CMD_TAIL_dos,AL
MOV PAR_CMD_dos,OFFSET CMD_TAIL_dos
ext5:
MOV DX,OFFSET COM_SPEC_dos ;Pfad zum auszufuehrenden Programm
MOV BX,OFFSET PAR_BLK_dos
call execute
JNC ext9
MOV si,OFFSET MSG2 ;ggf. Fehlermeldung bzgl.
call printa ;Kommandointerpreter
ext9:
ret
;----------------------------------------------
; MS-DOS EXEC-Aufruf zur Ausfuehrung des Kommandointerpreters
; als Kindprozess von SHELL.EXE
; DX und BX wurden vom aufrufenden Programm passend gefuellt.
execute:
PUSH DS
PUSH ES
MOV CS:STK_SEG,SS
MOV CS:STK_PTR,SP
mov ax,4b00h
int21
MOV SS,CS:STK_SEG
MOV SP,CS:STK_PTR
POP ES
POP DS
RET
;----------------------------------------------
; Get the environment information
GET_ENV:
MOV ES,ENV_SEG
XOR DI,DI
GENV1: MOV BX,SI
CMP b ES:[DI],0
JNE genv3
STC
genv2: RET
genv3: MOV AL,[BX]
OR AL,AL
JZ genv2
CMP AL,ES:[DI]
JNE GENV4
INC BX
INC DI
jmps genv3
GENV4: XOR AL,AL
MOV CX,-1
CLD
REPNZ SCASB
jmps GENV1
;==============================================
;Unterprogramme zum Abarbeiten der Kommandos
;==============================================
;----------------------------------------------
;CD Kommando wechselt aktuelles Verzeichnis
;Beim Aufruf zeigt DI auf das Blank hinter CD im Eingabebereich.
;Das Eingabeende wird durch CR markiert.
cd_cmd: mov merke_pwd,0 ;noch keine PWD-Anzeige
cd02: CMP b [DI],spc ;fuehrende blanks ueberlesen
jne cd10
inc di
jmps cd02
cd10: mov b AL,[DI]
cmp AL,cr ;wurde ein Ziel angegeben?
jne cd15
mov si,offset msg5 ;Fehlerhinweis weil keine Zielangabe
jmp printa
;Pruefen auf Laufwerksangabe
cd15: cmp al,'A' ;Buchstabe gefolgt von : ?
jb cd20 ;nein
cmp al,'Z'
ja cd20 ;nein
cmp b [DI+1],':' ;folgt : ?
jne cd20 ;nein
and al,1fh ;ja. Dann Laufwerksbuchstaben
sub al,1 ;wandeln make binary
mov dl,al
int21 0eh ;Funktion select drive
int dos
mov merke_pwd,1
inc di ;Zeiger auf :
inc di ;Zeiger hinter :
cd18: mov al,[di]
cd20: cmp al,cr
jne cd21
jmp cd90 ;es war nur Laufwerkswechsel angefordert
;Pruefen auf ein Verzeichnis zurueck mit ..\
cd21: cmp al,'.'
jne cd50
cmp b [di+1],'.'
jne cd50
cmp b [di+2],'\'
jne cd23
inc di ;Directorwechsel mit ..\ gewuenscht
cd23: inc di ;Directorywechsel mit .. gewuenscht
inc di ;Zeiger hinter ..\
push di
mov dx,offset cd_back ;CD mit .. oder ..\ eine Stufe zurueck
stc
mov ax,713bh ;Funktion change Directory
int dos
mov merke_pwd,1
jnc cd25
call cd80 ;ggf. Fehlerhinweis
cd25:
pop di
jmps cd18 ;nochmal das gleiche?
;Fuer den Aufruf des Vezeichniswechsels muss der Eingabestring mit 0
;statt cr abgeschlossen werden.
cd50: push di
cmp b [di],cr ;hier Stringende?
je cd90 ;dann fertig!
cld ;Suchrichtung aufwaerts
mov cx,inp_buf_length-4 ;-4 wegen a:\ und einmal cr
mov al,cr
; push ds ;diese push/pop-Kombination ist nicht
; pop es ;erforderlich. Registe es steht bereits
repne scasb ;passend
;falls gefunden ist di um 1 Byte zu weit
cmp b es:[di-1],cr ;cx auf 0 oder cr gefunden?
mov b es:[di-1],0 ;Befehlsabfolge wegen Stackausgleich
pop dx ;anfang des Strings fuer CD-Kommando
jne cd80 ;cx auf 0 => Fehlermeldung
stc
mov ax,713bh ;Funktion change Directory
int dos
mov merke_pwd,1
jnc cd90
cd80: mov si,offset msg6 ;Fehlerhinweis CD konnte nicht
call printa ;ausgeführt werden
cd90: cmp merke_pwd,0 ;PWD-Anzeige nach CD-Ausfuehrung
je cd99
call pwd_cmd ;Anzeige aktuelles Directory
cd99: ret
;----------------------------------------------
;CLS Kommando loescht den Bildschirminhalt (ANSI.SYS erforderlich)
CLS_CMD:
mov si, offset cls_str
jmp printa
;----------------------------------------------
;VGA-Karte umschalten auf 25 oder 43 Textzeilen
;Die mit ;### auskommentierten Zeilen betreffen die sogenannte
;Cursoremulation im BIOS. Die Cursoremulation ermoeglicht eine
;unveranderte Darstellung des Cursors auch bei Aenderungen der
;Zeichenmatrix. Die Cursoremulation wird durch Bit 0 des
;Video Display Data Area Info Bytes (0040:0087) ein- oder
;ausgeschaltet. Fuer EGA und VGA ist die Cursoremulation bei
;Systemstart standardmaessig eingeschaltet. Fuer VGA soll dies Bit
;ueber INT 10h Funktion 12h geschaltet werden. Fuer EGA muss es
;durch direkten Zugriff geschaltet werden.
;Unter WINDOWS XP und VISTA scheint dies Bit keinen Einfluss mehr
;zu haben. Deshalb sind die betreffenden Befehle hier
;auskommentiert.
ega25: mov ax,0040h ;25 Textzeilen
;### push ds
;### mov ds,ax
mov ax,3 ;EGA 80 * 25 Text, 16 Farben
int video ;Modus setzen
;### mov bx,0087h ;0040:0087 ist Video-Controller,
;### xor b ds:[bx],01h ;umschalten cursor emulation
mov cx,0d0eh ;Monochromcursor
jmps ega439
ega43:
mov ax,1202h ;Video Funktion 12, Unterfunktion 2
mov bl,30h ;(400 Rasterzeilen setzen)
int video
mov ax,0040h
;### push ds
;### mov ds,ax
mov ax,3 ;80 * 25 color text
int video ;Modus setzen
mov ax,1112h ;Zeichengenerator setzen
xor bx,bx
int video
;### mov bx,0087h ;Video-Controller, Status-Byte 1
;### or b ds:[bx],01h ;enable cursor emulation
mov ax,1200h ;EGA/VGA use alternate print screen
mov bh,20h
int video
mov cx,0708h ;Monochromcursor
ega439: mov ah,1 ;Cursorgroesse setzen
int video
;### pop ds
ret
;----------------------------------------------
; HELP Kommando - zeigt Hilfstext an.
help_cmd:
mov si,offset msg4
jmp printa
;----------------------------------------------
; EXPL Kommando zum Aufruf des Windows-Explorers auf das
; aktuelle Verzeichnis
expl_cmd:
mov par_cmd_expl, offset cmd_tail_expl
MOV DX,OFFSET COM_SPEC_expl ;Pfad zu explorer.exe
MOV BX,OFFSET PAR_BLK_expl
call execute
JNC expl_cmd1
jmp fehler
expl_cmd1:
ret
;----------------------------------------------
; PWD Kommando "Print Current Directory"
pwd_cmd:
int21 19h ;Funktion Get Current Disk
add al,41h ;Laufwerknr. in ASCII wandeln
mov si,offset curlfn-3
mov b ds:[si],al
inc si
mov w ds:[si],5c3ah ;':\'
add si,2 ;si zeigt nun auf curlfn
xor dl,dl ;aktuelles Laufwerk
stc
mov ax,7147h ;get current directory
int21
mov si,offset curlfn-3 ;Anzeige aktuellen Pfad
jmp printa
;----------------------------------------------
;LS Kommando Verzeichnisanzeige aehnlich DIR
;Beim Aufruf zeigt DI auf das Blank hinter dem Kommandowort
;LS im Eingabebereich. Das Eingabeende ist durch CR markiert.
ls_cmd: ;
cmp b [di],spc ;fuehrende blanks ueberlesen
jne ls02
inc di
jmps ls_cmd
ls02: mov b AL,[DI]
cmp AL,cr ;wurde ein Ziel angegeben?
jne ls05 ;ja
mov w es:[di],002ah ;Programmaufruf erfolgte ohne
push di ;Parameter: Wir denken uns einen *
jmps ls20 ;Anfangsadresse der Suchmaske
;di zeigt nun auf den Anfang des eingetippten Parameters
ls05: push di ;Anfangsadresse der Suchmaske
ls06: cmp b [di],cr ;Abfrage auf Parameterende
je ls10
inc di
jmps ls06
;Parameterende erreicht. cr wird 0
ls10: mov b [di],0
DEC di
;wenn als letztes Zeichen ein Backslash steht, dann kommt ein * hinzu!
ls15: cmp b [di],'\'
jne ls20
inc di
mov w es:[di],002ah
ls20: mov cl,5eh ;moegliche Attribute
mov ch,0 ;erforderliche Attribute
pop DX ;Suchmaske ab di
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
ret
fehler2: cmp ax,0002
jne fehler3
mov si, offset msg02
jmps hinweis
fehler3: cmp ax,03
jnz fehler5
mov si,offset msg03
jmps hinweis
fehler5: cmp ax,05
jnz fehler7b
mov si,offset msg05
jmps hinweis
fehler7b:
cmp ax,7bh
jnz fehler7100
mov si, offset msg7b
jmps hinweis
fehler7100:
cmp ax,7100h
jnz fehlerxx
mov si,offset msg7100
jmps hinweis
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 EXIt_CMD
hinweis:
call printa ;Fehlermeldung zeigen
print_crlf ;und weitermachen!
ret
;------------------------
; 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
;------------------------------------
; Unterprogramm erzeugt aus Binaerzahl in dx:ax Dezimalzahl
; und baut sie rueckwaerts ab di im Speicher auf
; Verfahren: Division mit 10d, Rest -> Speicher
int2asc:
xchg bp,dx
mov bx,0ah
mov cl,30h ;'0'
int2asc2:
or bp,bp
jz int2asc4
xchg bp,ax
xor dx,dx
div bx
xchg bp,ax
div bx
or dl,cl
mov [di],dl
dec di
jmps int2asc2
int2asc4:
xor dx,dx ;kurze zahl (dx war 0)
div bx
or dl,cl
mov [di],dl
dec di
or ax,ax
jnz int2asc4
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 ;Attrubut 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
; mov si,offset attrs
; call printa
;------------------------
; 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
;----------------------------------------------
;BYE, EXIT,QUIT Kommando(s) oder ! zum Beenden von sh.exe
EXIT_CMD:
MOV AX,04C00H
int21
;======
;Unterprogrammsammlung (modifiziert uebernommenn aus firm.mac)
;======
;print message following call prmsg and ending with 0
prmsg: pop si
push ds ;sichern ds
push cs
pop ds ;ds zeigt nun auf das Codesegment
call printa
pop ds ;nach Ausgabe ds wieder heretellen
push si ;returnadr.
ret
;druckt die mit si adressierte zeichenkette
;die zeichenkette darf keine steuerzeichen außer cr enthalten
;sie endet mit 0h
printa:
push ax
cld
printa5:
lodsb ;zeichen
or al,al ;ob fertig ?
jz printa7 ;ja
call printchr
jmps printa5
printa7:
pop ax
ret
;----------------------------------------------
;Auskommentierte Testhilfe
;----------------------------------------------
comment #
Testhilfe Hexaanzeige Register cx
push dx
push cx
mov al,ch
call hex_out
pop cx
push cx
mov al,cl
call hex_out
pop cx
pop dx
#
;ausgabe 8 bit zahl (in al) in hexa
hex_out: push ax
shr al,4
call conv
pop ax
conv: and al,0fh
daa
add al,0f0h
adc al,40h
;ausgabe zeichen in al zum bildschirm
printchr:
cmp al,cr ;cr?
je $print_crlf
printchr1:
push cx
push bx
mov dl,al ;Zeichen nach dl
int21 2
pop bx
pop cx
ret
$print_crlf:
mov dl,cr
int21 2
mov dl,lf
int21 2
ret
CSEG ENDS
;==============================================
;Stacksegment
;==============================================
STACK SEGMENT PARA STACK 'STACK'
DW 64 DUP(?)
STACK ENDS
;==============================================
;Datensegment
;==============================================
DATA SEGMENT PARA PUBLIC 'DATA'
COMMANDS: ;Kommandotabelle fuer
dbz '?' ;diesen Kommandointerpreter
dw help_cmd
dbz '\?'
dw help_cmd
dbz '25'
dw ega25
dbz '43'
dw ega43
dbz 'BYE'
DW EXIT_CMD
dbz 'CLS'
DW CLS_CMD
dbz 'CD'
dw cd_cmd
dbz 'DOS'
DW DOS_CMD
dbz 'EXIT'
DW EXIT_CMD
dbz 'EXPL'
dw expl_cmd
dbz 'LS'
dw ls_cmd
dbz 'PWD'
dw pwd_cmd
dbz 'QUIT'
DW EXIT_CMD
DB 0
merke db 0 ;Merker Parameteruebername (0=nein)
merke_exit db 0 ;Merker Exit-Anforderung
merke_pwd db 0 ;Merker PWD-Anzeige (bei CD-Abarbeitung)
COM_VAR DB 'COMSPEC=',0
COM_SPEC_dos DB 80 DUP(0)
NULTAIL DB 0,CR
CMD_TAIL_dos DB 0,' /C '
INP_BUF DB 80 DUP(0)
INP_BUF_LENGTH EQU $-INP_BUF
CMD_TAIL_dos_LENGTH EQU $-CMD_TAIL_dos-1
Schutzbyte db cr ;Soll vor Ueberlauf sachuetzen
;Besondere Directories
cd_home db '\',0 ;Grundbibliothek
cd_back db '..',0 ;eine Stufe zurck
;curdrv db 0 ;Current Drive (Buchstabe), einzusetzen vor curlfn
; db ':\' ;an der Position curlfn - 3
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. Die Bytemuster erleichtern das Testen
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
ENV_SEG DW 0
handle dw 0
;----------------------------------------------
;Bildschirmausgaben zur Fehler- und Hilfsanzeige
msg1: dblz 'Speicherfreigabe nicht moeglich.'
MSG2: dblz 'Befehlsinterpreter konnte nicht aufgerufen werden.'
MSG3: dblz 'Keine COMSPEC-Variable im Umgebungsblock.'
msg4:
dbl 'Befehle:'
dbl '? oder /? Hilfsanzeige wie hier'
dbl '!, BYE, EXIT oder QUIT beendet diese Shell'
dbl '! am Schluss des Befehls beendet diese Shell nach seiner Ausfuehrung.'
dbl ' Beispiel fuer Aufruf mit Standardausgabeumleitung: '
db ' ',3eh
dbl 'hugo.txt sh ls d:\temp\!'
dbl '25 setzt Bildschirmhoehe auf 25 Zeilen'
dbl '43 setzt Bildschirmhoehe auf 43 Zeilen'
dbl 'CD wechselt Verzeichnis und Laufwerk, z.B. CD C:/TEMP\HUGO oder CD ..'
dbl 'CLS loescht den Bildschirminhalt'
dbl 'DOS DOS-Kommandooberflaeche, beenden mit EXIT'
dbl 'EXPL startet Windows-Explorer auf aktuellem Pfad'
dbl 'LS Directory-Anzeige aehnlich DIR'
dblz 'PWD zeigt aktuelles Verzeichnis (Print Working Directory)'
msg5: dblz 'Keine Zielangabe fuer CD!'
msg6: dblz 'CD konnte nicht ausgefuehrt werden!'
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.'
CLS_STR db escp,'[2J',0 ;ANSI.SYS clear screen string.
PAR_BLK_dos: ;Parameterblock fuer DOS-Aufruf (COMSPEC)
DW 0 ;Int 21h Funktion 4BH (execute)
PAR_CMD_dos DW OFFSET CMD_TAIL_dos
DW SEG CMD_TAIL_dos
DD -1
DD -1
par_blk_expl: ;Parameterblock fuer Explorer-Aufruf
DW 0 ;Int 21h Funktion 4BH (execute)
par_cmd_expl DW offset cmd_tail_expl
DW seg cmd_tail_expl
DD -1
DD -1
com_spec_expl: dbz 'C:\WINDOWS\EXPLORER.EXE'
cmd_tail_expl db 8,' /n /e,.',cr
DD -1
DD -1
DATA ENDS
END _start
|