.8086
.MODEL tiny
.CODE
IDEAL
PSPAdr:
Deutsch equ 1 ;Deutsch eingeschaltet
;Ausschalten durch Auskommentierung
org 0e6h
StkOfs dw ?
StkSeg dw ?
MaxFiles dw ? ;Anzahl Datenstze, default 100
MemAX dw ?
AdrFiles dw ?
NameBuf db 11 dup (?) ;ab in die Kommandozeile!
ExecFlag db ?
MemSI dw ?
EndAdr dw ?
start: jmp Start1
RecLng equ 22
;Aufbau des Datensatzes: (Gesamtlnge 16h = 22 Bytes)
;8 Byte Name +0
;3 Byte Typ +8
;1 Byte Angezeigt-Flag +0bh
;2 Byte Such-Zugriffe +0ch
;2 Byte ffnungs-Zugriffe +0eh
;2 Byte Lesezugriffe +10h
;2 Byte Schreibzugriffe +12h
;2 Byte Exec-Zugriffe +14h
NewInt21: pushf
sti
cmp ax,0f748h
jne KennFlt
cmp dx,3abch
jne KennFlt
mov ax,0cba3h
mov dx,cs
popf
iret
KennFlt:
cmp [cs:ExecFlag],1 ;Reentranter Aufruf?
jge ToOldInt21 ;ja-fertig
;Solche Semaphoren haben ihre Tcken, wenn es darum geht, da
;einige DOS-Aufrufe nie oder arg verzgert zurckkehren, und zwar
;die INT 31h, 4Bh und 4Ch, nebenbei auch 00h, wird aber vorher
;herausgefiltert
cmp ah,0fh ;Konsolzugriffe?
jc ToOldInt21 ;ja-fertig
cmp ah,57h ;Sonstige Zugriffe?
jc access ;ja!
ToOldInt21: popf
CallOldInt21: db 0eah ;JMP FAR
OldInt21 dd ? ;geretteter Int21
acctbl: ;Suchtabelle, Aufbau:
;- n Bytes Funktionsnummer
;- 1 Nchste Zugriffsart
;- 0 Ende Tabelle
db 11h,17h,4eh,56h,1 ;Suchen
db 0fh,16h,3ch,3dh,3eh,1 ;ffnen
db 14h,21h,23h,27h,3fh,44h,1 ;Lesen
db 13h,15h,22h,28h,40h,41h,1 ;Schreiben
db 4bh,0 ;Ausfhren (Laden)
access: ;Zugriffs-Zweig
inc [cs:ExecFlag] ;Semaphore Verlegter Stack
mov [cs:stkseg],ss
mov [cs:stkofs],sp ;Ganz sicher gehen
push cs ;(evtl. unntig)
pop ss
mov sp,(offset stkofs) ;Erst DEC, dann PUSH?
push ax
push bx
push cx
push dx
push si
push di
push es
push ds
push cs
pop ds ;Code=Daten
mov [MemAX],bx ;Handle
mov cx,ax ;retten
mov si,offset acctbl
cld
mov bx,0ch ;mit Suche beginnen
sktbl: lodsb
cmp al,1 ;Kennung nchstes BX
jnz sctbl1
add bx,2
sctbl1: cmp ah,al
je acc
or al,al
jnz sktbl
acce: pop ds
pop es
pop di
pop si
pop dx
pop cx
pop bx
pop ax
mov ss,[cs:stkseg]
mov sp,[cs:stkofs]
test1:
cmp ah,3ch
je acchdl ;Bei diesen Funktionen
cmp ah,3dh ;nachher Handlenummer
je acchdl ;abfangen und eintragen
dec [cs:ExecFlag]
jmp ToOldInt21
acchdl: popf
;Alles wie frisch nach dem Aufruf
pushf ;wichtig!!
cli ;???
push cs ;weil nachfolgendes CALL
call CallOldInt21 ;NEAR ist
sti ;ganz wichtig, sonst Verklemmung bei Spielen!!!
pushf
jc reti
push cx
cmp ax,5 ;Standardhandle?
jb popreti ;ignorieren
;Nun Handle eintragen, ax=Handle, [MemSI]=^Record
push si
push di
mov si,[cs:MemSI]
or si,si ;volle Tabelle?
jz fullreti
mov di,offset ImmHandles
mov cx,30
hdlsklp: cmp [word ptr cs:di],0 ;frei?
jz hdlsk1
add di,4
loop hdlsklp
mov di,offset ImmHandles
hdlsk1: mov [cs:di],ax ;Handle-Nummer
mov [cs:di+2],si ;Basisadresse
fullreti: pop di
pop si
popreti: pop cx
reti: dec [cs:ExecFlag]
popf
retf 2
acc: ;Tatschlicher Zugriff
cmp ah,44h ;Gertetreiber
jnz acc1
cmp cl,3
jz acc1
cmp cl,2 ;Schreiben?
jnz acce2a ;Kein Zugriff
add bx,2 ;Richtigen Zugriff einstellen
acc1: ;Wirklicher Zugriff, bx=Ablage von Basis
;[MemAX]=Handle, CX=Funktion, (SP):DX=Name bzw. FCB-Adr.
;ah=Funktion High
;Ausgabe: [MemSI]=Recordzeiger, Record-Eintrag
cmp ah,3dh ;ffnen?
je acch
cmp ah,3ch ;Erstellen?
je acch
cmp ah,4bh ;Execute?
je acch
cmp ah,4eh ;FindFirst?
jne acch2
acch: ;Name suchen
pop ds
push ds
call SetEntry ;ah=Funktionsnummer
acch3: mov [MemSI],si ;DS wieder eigen!
jc acce2a ;Fehler: Tabelle voll
; push ax
; mov ax,0e23h
;Test- int 10h
;zweck pop ax
inc [word ptr bx+si]
jnz acce2a ;Kein berlauf
dec [word ptr bx+si]
acce2a: jmp acce
acch2: mov ax,[MemAX] ;Handle
cmp ax,5 ;Standardhandle?
jb acce2a ;ja
mov di,offset ImmHandles
mov dx,cx
mov cx,30
skhandle: cmp ax,[di]
je fndhandle
add di,4
loop skhandle
jmp short acce2a
fndhandle: cmp dh,3Eh ;Schlieen (Handle)?
jne NoClose
mov [word ptr di],0
NoClose: mov si,[di+2] ;Zugehriges Datenfeld
clc
je acce2a ;bei Close kein Eintrag!
jmp acch3 ;weiter wie normal
;
; Unterprogramme fr Interrupt-Programm
;
SetEntry: ;Namenseintrag finden oder ggf. erstellen
;PE: SI=Programmadresse Namen lesen (zum Unterscheiden
;von FCB- und Handlefunktionen)
; DS:DX - Zeiger auf Dateiname
;PA: CY - Fehler: Tabelle voll, dann SI=0
; SI - Adresse Datensatz
; DS=CS
push cs
call GetEntry
jnc EntryEnd ;gefunden
jz EntryEnd ;Tabelle voll
;NewEntry: ;Neue Datei eintragen
push di
mov si,offset NameBuf ;Namenspuffer
mov cx,11
rep movsb ;einschaufeln
xor ax,ax ;0
stosb
stosw ;Nullen eintragen
stosw
stosw
stosw
stosw
mov [AdrFiles],di
pop si
clc ;Kein Fehler
EntryEnd: ret
GetEntry: ;Sucht Eintrag (FAR-codiert!)
;PA: CY=1 nicht gefunden
; SI=0 und Z=1: Tabelle auerdem voll
cld
push cs
pop es
mov di,offset NameBuf
mov al,' '
mov cx,11
rep stosb ;11 Zeichen mit Space lschen
call NCopy ;ah=Funktionsnummer
push cs
pop ds
cld
mov cx,[MaxFiles]
mov si,ImmFiles
locloop_23:
mov di,offset NameBuf
push cx
push si
mov cx,11
repe cmpsb ;vergleichen
pop si
pop cx
je loc23ret ;Name gefunden, CY=0!
add si,RecLng
loop locloop_23
mov di,[AdrFiles]
cmp di,[EndAdr] ;war voll?
jb loc23ret ;nein-neuer Eintrag
xor si,si ;Z=1
stc ;Fehler
loc23ret: retf
NCopy: ;Dateiname von Handlefunktion oder FCB holen
mov si,dx ;Anfadr. bleibt in ds:dx!
mov cx,11
cmp ah,30h
jb NameCopy ;FCB-Funktion!
;ganz anders
xor ah,ah ;Punkt-Merker
skend0: lodsb ;suchen
or al,al
jnz skend0
skend4: dec si ;*Erst* DEC ist viiel angenehmer!
mov al,[si]
cmp al,'.'
jne skend2 ;Punkt gefunden
or ah,ah ;Punkt war schon mal?
jne skend3
inc ah ;Richtigen Punkt kennzeichnen
mov cx,3
mov di,(offset NameBuf)+8
call PokeNT
skend2: cmp al,':'
je skend3
cmp al,'/'
je skend3
cmp al,'\'
je skend3
cmp si,dx
jne skend4
dec si
skend3: mov cx,8
NameCopy: mov di,offset NameBuf
;hineinlaufen
PokeNT: ;Eintragen Name bzw. Typ (Vorgabe durch cx und di)
;si zeige auf Punkt oder letztes Zeichen der vor-
;hergehenden Pfadangabe
push ax
push si
inc si
pokent1: lodsb
or al,al
jz pntend
cmp al,'.'
jz pntend
call UpCase
stosb
loop Pokent1
pntend: pop si
pop ax
ret
UpCase: ;al:= UpCase(al) ohne hohe Zeichen
cmp al,'a'
jb UpCas1
cmp al,'z'
ja UpCas1
and al,not 20h
UpCas1: ret
InitData: ;Datenstze initialisieren
push ds
pop es ;Zieldatensegment
mov di,offset ImmHandles ;Handlepuffer
mov cx,30 ;Handles max. (fiktiv)
locloop_40: xor ax,ax
stosw ;0000
mov ax,ImmFiles
stosw ;Zeiger auf 1. Element
loop locloop_40 ;30mal fr 4 Bytes = 120 Bytes
mov ax,[MaxFiles]
mov cx,RecLng/2
mul cx
mov cx,ax
xor ax,ax
rep stosw
mov [AdrFiles],ImmFiles
ret
;ͻ
; Hauptprogramm
;ͼ
instcont: ;Fortsetzung Installation
push ax
call InitData
pop dx
mov ax,3100h
int 21h ;TSR dx Paragrafen
ImmHandles: ;Hier beginnen die Tabellen!
ImmFiles equ offset ImmHandles+120
;
;>>> Start-Eintrittspunkt <<<Ĵ
;;
Start1:
mov ah,'S'
call SCANCL
je suppress
mov dx,offset Text1
call OSTRLF ;Meldung ausgeben
suppress: mov ah,'?'
call SCANCL
je help
mov ah,'H'
call SCANCL
jne action
help: mov dx,offset Text4
jmp TextExit ;Hilfe ausgeben
action: mov ax,0f748h ;Installations-Check
mov dx,3abch ;Kennungen
int 21h
cmp ax,0cba3h ;installiert?
jne NewRec
jmp OldRec
;ͻ
; Neuanlage von RECORDER
;ͼ
NewRec: mov es,[2ch] ;Segment Environment
mov ah,49h
int 21h ;ENV-Speicher ab es freigeben
;Zahl auswerten
call GetParAdr ;si:= 81h, cx:= Zeichenzahl
jcxz loc_45 ;kein Parameter: Default=100
xor ax,ax ;ax:= 0 (die Zahl)
locloop_42: mov bl,[si]
sub bl,'0'
jc NoDigit
cmp bl,9
ja NoDigit
mov bh,10
mul bh ;*10
xor bh,bh
add ax,bx
NoDigit: inc si
loop locloop_42
or ax,ax ;0?
jz loc_45 ;wie kein Parameter
cmp ax,2000 ;zuviel?
jbe loc_44
mov ax,2000 ;begrenzen
jmp short loc_44
loc_45: mov ax,100
loc_44: mov [MaxFiles],ax ;setzen
;Interrupts setzen
mov ax,3521h
int 21h ;alter Int21
mov [word ptr OldInt21],bx
mov [word ptr OldInt21+2],es
mov [ExecFlag],0
mov dx,offset Text6 ;Meldung
mov ah,9
int 21h
mov ax,[MaxFiles]
mov bx,RecLng
mul bx ;*RecLng
add ax,ImmFiles ;dazu AnfAdr der Tabelle
mov [EndAdr],ax
push ax
call AXDez ;Bytezahl ausgeben
mov dx,offset Text6a
call OSTRLF ;"Bytes"
pop ax
add ax,0Fh ;aufrunden
mov cl,4
shr ax,cl ;Anzahl Paragrafen berechnen
push ax
push cs
pop es
mov bx,ax ;Erforderliche Paragrafen
cmp bx,(DTA-PSPAdr+0fh)/16 ;Programm lnger?
jc allOK
mov ah,4ah
int 21h ;umndern
jnc allOK
mov dx,offset MemErr
jmp TEXTexit
allOK: mov dx,offset NewInt21
mov ax,2521h
int 21h ;neuer Int21
pop ax
jmp instcont ;nach vorn; dieser Programm-Bereich
;wird von Daten berschrieben
;ͻ
; Aufgenommene Werte ausgeben
;ͼ
OldRec: mov ds,dx ;Fremdes Datensegment!
;Keine Sortierung!
mov ah,'D'
call SCANCL
jnz $+5
jmp ToRem
mov ah,'L'
call SCANCL
je list
mov ah,'S'
call SCANCL
je suppr2
mov dx,offset Text3 ;Tabellenkopf
call OSTRLF ;ausgeben
suppr2: mov cx,[MaxFiles]
mov si,ImmFiles
xor ax,ax ;Zeilenzhler
OutLoop: push cx
push ax
;Summe nach ax bestimmen
xor ax,ax
mov bx,0ch
mov cx,5
summy: add ax,[si+bx]
jnc summy1
mov ax,0ffffh
summy1: add bx,2
loop summy
mov bp,ax ;Letzte Summe fr "Tab. voll!"
or ax,ax
jz nextline
push ax
call NameOut
jc nextlin2
add si,0ch
;si zeigt auf Such-Zahl
mov cx,5 ;Su/f/Le/Sch/Ruf
outnumb: lodsw ;String [si] nach ax
push cx
call AXDez
pop cx
loop outnumb
pop ax
call AXDez ;Summe
call CRLF ;Neue Zeile
pop ax
inc ax
push ax
call pause
jmp short nextline
nextlin2: add si,RecLng
pop ax
nextline: pop ax
pop cx
loop OutLoop
or bp,bp ;Letzter Platz voll?
je nfull ;nein
mov ah,'S' ;Unterdrcken?
call SCANCL
je nfull
mov dx,offset Text2 ;"Tabelle voll"
call OSTRLF
nfull: jmp ToRemove
;##########LIST UNUSED FILES#############
list: mov ah,'S'
call SCANCL
je suppr3
mov dx,offset Text9
call ostrlf
suppr3:
xor ax,ax
push ax
mov [cs:CFS],ds
push ds
push cs
pop ds
mov dx,offset dta
mov ah,1ah ;SetDTA
int 21h
mov dx,offset filename
mov cx,27h ;Alles auer Verzeichnisse u. Labels
mov ah,4eh ;FindFirst
list2: int 21h
jc list3
mov dx,(offset dta)+1eh
;ds:dx zeigt wie gewohnt auf Dateiname
mov ah,35h
db 9ah ;ein CALL FAR
dw offset GetEntry ;ah ist grer als 30h
CFS dw ?
pop ds
jnc list1
mov si,offset NameBuf ;im fremden Segment
call NameOut ;den Namen DX:SI
call CRLF
pop ax
inc ax
push ax
call Pause
list1: push ds
push cs
pop ds
mov ah,4fh
jmp short list2
list3: pop ds
pop ax
;#########################################
ToRemove: mov ah,'R'
call SCANCL
jnz NoDel
ToRem: call InitData ;lschen = initialisieren
NoDel: mov ah,'U'
call SCANCL
jz $+5
jmp DosExit
mov dx,ds ;zum Vergleichen
mov ax,3521h ;Int-Vektor holen
int 21h
cmp bx,offset NewInt21
mov ax,es
jne RemErr
cmp ax,dx
jne RemErr
;nun auch es=ds!
lds dx,[OldInt21] ;selbstmodifizierendes ds!
mov ax,2521h ;Interrupt rcksetzen
int 21h
mov ah,49h ;Speicher freigeben
int 21h
mov dx,offset Text7 ;Alles ok.
jnc TextExit
RemErr: mov dx,offset Text5 ;Deinstallationsfehler
push cs
pop ds
mov cl,4
shr bx,cl
push ax
push bx
mov ah,9
int 21h
;Speicher nach dem beltter absuchen!
mov ah,52h
int 21h ;[ES:BX-4]=1.MCB
mov cx,[es:bx-2]
pop bx
pop ax
add ax,bx ;Segmentadresse (gesucht)
mcb4: mov ds,cx
cmp [byte 0],'M'
je mcb3
cmp [byte 0],'Z'
jne mcbf ;Weder M noch Z: Hase im Pfeffer!
cmp cx,0a000h
jnc mcbf ;nix gefunden (BIOS?)
mcb3: add cx,[3] ;Lnge
inc cx
cmp ax,cx
jnc mcb4 ;Der falsche MCB
;beltter gefunden!
mov si,8
mov cx,9 ;Warum auch immer 9 Zeichen!
mov al,' ' ;(Geht nur so!)
mcb5: call OCHR
lodsb
or al,al ;Ende?
loopnz mcb5
mcbf: mov dx,offset Text5a
call OSTRLF
mov ax,4c01h ;Fehler im Dosexitcode
int 21h
TextExit: call OSTRLF
DosExit: mov ax,4C00h
int 21h ;Ende
;
; Unterprogramme fr Nicht-Interrupt-Teil
;
NameOut: ;Gibt den durch DX:SI adressierten Dateinamen auf #1 aus
;VR: ax,bx,cx,dx
;Aber nur wenn wildcardfrei oder Option w angegeben
;Sonst Carry gesetzt
push si
mov cx,11
NO2: lodsb
cmp al,'?'
je NO1
cmp al,'*'
je NO1
loop NO2
NO3: pop si
mov dx,si ;die Adresse
mov bx,1 ;auf StdOut
mov cx,8 ;8 Zeichen Name
mov ah,40h ;Ausgabe
int 21h
mov al,'.'
call OCHR ;Punkt
mov dx,si
add dx,8 ;Typ ansteuern
mov cx,3 ;3 Zeichen Typ ausgeben
mov ah,40h
int 21h
clc
ret
NO1: mov ah,'W'
call SCANCL
je NO3
pop si
stc
ret
Pause: ;eine List-Pause einfgen
;PE: AX - Zeilenzhler
;VR: AX,CX,DX
mov cl,22 ;fest
div cl
or ah,ah ;Rest
jnz nohalt
push si
mov ah,'P'
call SCANCL
pop si
jne nohalt
push ds
mov ax,cs
mov ds,ax
mov dx,offset Text8
mov ah,9
int 21h ;Pausentext
pop ds
mov ah,8
int 21h ;Tastaturabfrage
or al,al ;Sondertaste?
jnz keypressed
int 21h ;Sondercode abholen
keypressed: mov cx,30 ;30 Spaces reichen dicke
mov al,' '
delline: call OCHR
loop delline
mov al,13
call OCHR
nohalt: ret
SCANCL: ;Durchsuche Parameter nach Buchstaben AH, Zugriff via cs
;PA: Z=1: gefunden
call GetParAdr ;si:= Adr, cx:= Lnge
jcxz scanret ;Kein Parameter, Z=0
scansk: mov al,[cs:si] ;Eignes (!) Segment
call UpCase ;immer gro!
cmp al,ah ;passend?
je scanret ;ja, Z=1
inc si
loop scansk ;weitersuchen
scanret: ret
AXDez: ;AX dezimal vzl ausgeben mit Vornullenunterdrckung
;Es werden konstant 7 Zeichen ausgegeben
;VR: ax,bx,cx,dx
push ax
mov al,' '
call OCHR
mov al,' '
call OCHR
pop ax
xor cx,cx ;Vornullunterdrckung
mov bx,10000
call ODigit ;hinterlt in ax den Rest!
mov bx,1000
call ODigit
mov bx,100
call ODigit
mov bx,10
call ODigit
add al,'0' ;Letzten Rest immer ausgeben
jmp OCHR
ODigit: ;Ziffernausgabe, ax=Zahl, bx=Teiler, cx=Vornull-Flag
xor dx,dx ;High-Teil=0
div bx ;ax:=ax/bx, Rest dx (bx Dezimalzahl?!)
push dx
or cx,ax ;Evtl. Ziffer anmelden
or cx,cx ;Immer noch Vornull?
jnz digit ;Ziffer
mov al,0F0h ;Space
digit:
add al,'0'
push cx
call OCHR
pop cx
pop ax ;Rest
ret
OSTRLF: ;ASCII$-String aus Codesegment mit CRLF ausgeben
push ds
mov ax,cs
mov ds,ax
mov ah,9
int 21h ;ds:dx-ASCII$ ausgeben
pop ds
CRLF: ;CRLF ausgeben
mov al,13
call OCHR
mov al,10
OCHR: ;Zeichen al ausgeben (Marke KC-like!)
mov dl,al
mov ah,2
int 21h ; DOS Zeichen auf StdOut
ret
GetParAdr: ;si:= Kommandzeilenadresse
;cx:= Zeichenzahl (kopierfreundlich)
mov si,80h
mov cl,[cs:si] ;Kommandozeilenzeichenzahl
xor ch,ch ;in CX
inc si ;1. Zeichen
cld
ret
Text1 db ' REC 2.02 (c) 1988 (ZCCPCMTK)',13,10
db ' (c) 1993 haftmann#software ++ Public Domain ++$'
IFDEF Deutsch
;Deutsche Texte
Text2 db 10,'* Tabelle ist voll *$'
Text3 db 10,' Dateiname Suchen ffnen Lesen Schr. Aufruf Summe$'
Text4 db 10,'>> Programm zum Mitschneiden smtlicher Dateizugriffe <<',13,10,10
db 'Parameter bei Installation (Erstaufruf):',13,10
db '[n] - Maximale Dateienzahl als Dezimalzahl (sonst 100)',13,10
db '? oder h - diese Hilfe; es erfolgt KEINE Installation',13,10,10
db 'Parameter bei Wiederaufruf:',13,10
db 'l - Auslisten aller im akt. Directory NICHT genutzten Dateien',13,10
db 'p - Pause nach 22 Zeilen',13,10
db 'r - Liste lschen (nach Anzeige)',13,10
db 'd - Liste lschen',13,10
db 's - Meldungstext unterdrcken',13,10
db 'u - Residentes REC entfernen',13,10
db 'w - "Dateinamen" mit Wildcards ebenfalls anzeigen$'
MemErr db '* Kann REC nicht mit so vielen Dateien (hoch)laden, kein Speicher! *$'
Text5 db '* Kann REC nicht deinstallieren, da das TSR$'
Text5a db ' dies verhindert! *$'
Text6 db '--- Programm resident geladen, Platzbedarf:$'
Text6a db ' Bytes$'
Text7 db '--- REC vom Speicher entfernt$'
Text8 db ' *** Taste drcken! ***',13,'$'
Text9 db ' Liste aller ungenutzten Dateien:$'
ELSE
;Englische Texte, bersetzt vom English-Guru M. Sternberg
Text2 db 10,'* file record table full *$'
Text3 db 10,' filename seek open read write call sum$'
Text4 db 10,'>> TSR program to record file access activities <<',13,10,10
db 'parameters on install (use "-" or "/" or no prefix) :',13,10
db '? or h - just this help screen, (NO installation)',13,10
db '[n] - maximum number of files (optional; defaults to 100)',13,10,10
db 'parameters on recall (query file table database):',13,10
db 'l - list all unused files from current directory',13,10
db 'p - pause after 22 lines',13,10
db 'r - purge file table after displaying',13,10
db 'd - purge file table and no display',13,10
db 's - suppress (c)-messages and table-head (useful for pipes)',13,10
db 'u - uninstall TSR',13,10
db 'w - display also files accessed by wildcards (always recorded)$'
MemErr db '* Cannot install REC: insufficient memory for too many files *$'
Text5 db '* Removal of REC collides with TSR$'
Text5a db ' having hooked INT21h ! *$'
Text6 db '--- TSR loaded using$'
Text6a db ' Bytes$'
Text7 db '--- REC removed from memory$'
Text8 db ' *** press any key ***',13,'$'
Text9 db ' List of unused files:$'
ENDIF
filename db '*.*',0 ;Such-Dateiname
dta:
end start
Detected encoding: UTF-8 | 0
|