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.
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 ist (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 Fehlerbehandlung hat sich - abgesehen von Erweiterungen - nur wenig geändert.
get_env proc near … Befehle … getenv endpDas mag für Unterprogramme in anderen Segmenten (proc far) gelten. Wenn das Unterprogramm sich jedoch im gleichen Segment wie das Hauptprogramm befindet und wenn außerdem Haupt- und Unterprogramm gemeinsam assembliert werden, ist die Einkleidung in einen Prozedurrahmen für mich nicht einsichtig. Ich habe somit sämtliche Prozedurdeklarationen aus dem Quellprogramm entfernt.
D:\dos\ML\Test>sh /? Befehle: ? oder /? Hilfsanzeige wie hier !, BYE, EXIT oder QUIT beendet diese Shell ! am Schluss des Befehls beendet diese Shell nach seiner Ausfuehrung. Beispiel fuer Aufruf mit Standardausgabeumleitung: >hugo.txt sh ls d:\temp\! 25 setzt Bildschirmhoehe auf 25 Zeilen 43 setzt Bildschirmhoehe auf 43 Zeilen CD wechselt Verzeichnis und Laufwerk, z.B. CD C:/TEMP\HUGO oder CD .. CLS loescht den Bildschirminhalt DOS DOS-Kommandooberflaeche, beenden mit EXIT EXPL startet Windows-Explorer auf aktuellem Pfad LS Directory-Anzeige aehnlich DIR PWD zeigt aktuelles Verzeichnis (Print Working Directory) sh:>
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 zurueck ;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 |