Source file: /~heha/hs/dos/dosmisc.zip/SRC/SAVECD.ASM

;savecd.asm  heha/stern, Aug. 1997
;	redirect savegame writes for CD games to harddisk dir

	JUMPS
	SMART
	LOCALS
	MODEL	TINY
MAGICFUNC	EQU	1842h		;unused function for CP/M compat.
MAGICCODE	EQU	123Ah
MAGICANS	EQU	7721h

DOS MACRO num
 IFNB <num>
  IF num GT 255
	mov	ax,num
  ELSE
	mov	ah,num
  ENDIF
 ENDIF
	int	21h
ENDM

SES MACRO mem:req,reg:rest
	mov	word ptr mem[0],reg
	mov	word ptr mem[2],es
ENDM

LD MACRO dest:req,src:rest
	push	src
	pop	dest
ENDM

NL	EQU	<13,10>

CODESEG
ComBase:
		org	2Ch
EnvSeg		dw	?
		org	72h
hFileDst	dw	0
FF_CodeAX	dw	?
FF_AttrCX	dw	?
data_0209	dw	?
currfhandle	dw	?
FF_Flag		db	?
EnterLock	db	?
UnlockForExec	db	?
EndOfPath	dw	?
ThePath		db	80h dup (?)
		org	100h
start:		jmp	start_here
DriveRestrict	db	0
fhandletab	db	256 dup (0)
transferbuf	db	1000h dup (?)	;4K für alle Fälle
tbend:
tbfill		dw	?
BufferForFF	db	128 dup (?)

;========================================================================

NewInt21	proc	far
	cmp	ax,MAGICFUNC
	jne	@@fwd
	cmp	bx,MAGICCODE
	jne	@@fwd
	mov	ax,MAGICANS
	mov	bx,cs
	iret
@@fwd:
	cmp	ah,4Bh			; "exec"
	jne	@@fwd2
	cmp	cs:UnlockForExec,1
	jne	@@fwd2
	mov	cs:UnlockForExec,0
	mov	cs:enterlock,1		; unlock
	jmp	loc_13FA		; and continue oldint (= run game)

@@fwd2:
	cmp	cs:enterlock,0		; locked?
	je	loc_13FA		; yes - continue oldint
	mov	cs:enterlock,0		; lock!
	cmp	ah,39h			; "mkdir"
	je	try_mirror_only
	cmp	ah,3Ah			; "rmdir"
	je	try_mirror_only
	cmp	ah,41h			; "unlink"
	je	try_mirror_only
	cmp	ah,3Ch			; "creat"
	je	try_mirror_only
	cmp	ah,3Dh			; "open"
	je	open
	cmp	ah,43h			; "chmod"
	je	try_mirror_then_cd
	cmp	ah,4Bh			; "exec"
	je	exec_mirror_then_cd
	cmp	ah,4Eh			; "findfirst"
	je	findfirst
	cmp	ah,4Fh			; "findnext"
	je	findnext
	cmp	ah,36h			; "df"
	jne	int21cont
diskfree:
	pushf				; Push flags
	 cmp	cs:[DriveRestrict],0
	 jz	@@notest	;mangle always
	 cmp	cs:[DriveRestrict],dl	; this request
	 jnz	@@nomangle
@@notest:
	 mov	dl,cs:ThePath		; default 'C'
	 sub	dl,'@'			; dos drv counted from 1
@@nomangle:
	popf				; Pop flags
int21cont:
	mov	cs:enterlock,1		; release
loc_13FA:
	db	0EAh		;JMP FAR opcode
OldInt21 dd	?

int21exi:
	mov	cs:enterlock,1
	retf	2			; Return far
NewInt21	endp

;====== handle dos functions =====================================

try_mirror_only:
	sti				; Enable interrupts
	call	manglepath
	jc	int21cont
	push	ds dx
	 LD	ds,cs
	 lea	dx,ThePath
	 DOS
	pop	dx ds
	jmp	int21exi
open:
	sti				; Enable interrupts
	call	manglepath
	jc	int21cont
	test	al,7			; access code
	jnz	openw		; if w+
	push	ds dx
	 LD	ds,cs
	 lea	dx,ThePath
	 push	ax
	 DOS
	 jnc	no_openerr
	 pop	ax
	pop	dx ds
	DOS
	jmp	int21exi
no_openerr:
	 pop	dx
	pop	dx ds
	jmp	int21exi
openw:
	test	al,6			; rw
;For read/write access, it's necessary to copy the desired file onto
;config file directory before allowing access to it!
		jnz	loc_1450
		jmp	loc_1450
; never reached
	push	ds dx
	 LD	ds,cs
	 lea	dx,ThePath
	 DOS
	pop	dx ds
	jmp	int21exi
loc_1450:
	push	ds dx
	 LD	ds,cs
	 lea	dx,ThePath	;First check whether local copy exist
	 push	ax cx
	  DOS	4300h			;  get file attrb, nam@ds:dx
	 pop	cx ax
	 jc	@@NotExist
	 DOS			;If exist, open normally
	pop	dx ds
	jmp	int21exi
@@NotExist:
	pop	dx ds
	push	ax
	 DOS	3D00h		; open CD file for read
	 jnc	loc_1476	;success
	inc	sp		;Open even for read fails, report errors
	inc	sp
	jmp	int21exi
loc_1476:
	 mov	cs:currfhandle,ax	;read file handle
	 push	cx bx si
	  lea	bx,fhandletab
seeknext:
	  push	ax
	   mov	al,cs:[bx]
	   or	al,al			; free?
	  pop	ax
	  jz	free_slot_found

	  push	bx
	   mov	si,cs:data_0209		; ??
	   call	stricmp
	  pop	bx
	  jz	loc_14B0
loc_1495:
	  push	ax
	   mov	al,cs:[bx]
	   or	al,al			; Zero ?
	   pushf				; Push flags
	    inc	bx
	   popf				; Pop flags
	  pop	ax
	  jnz	loc_1495
	  jmp	seeknext

free_slot_found:
	 pop	si bx cx
	 mov	ax,cs:currfhandle		; (=0)
	 clc				; Clear carry flag
	inc	sp		;skip pushed AX (OpenMode)
	inc	sp
	jmp	int21exi
loc_14B0:
	 pop	si bx
	 push	ds dx
	  LD	ds,cs
	  lea	dx,ThePath
	  xor	cx,cx			; Zero register
	  DOS	3Ch			;  create/truncate file @ ds:dx
	  jnc	loc_14C9
	 pop	dx ds cx
	inc	sp		;skip pushed CX
	inc	sp
	jmp	int21exi
loc_14C9:
	  mov	hFileDst,ax		; (=0)
@@FileCopy:
	  mov	bx,currfhandle
	  mov	cx,1000h		;sizeof TransferBuf
	  lea	dx,TransferBuf
	  DOS	3Fh			;  read file, cx=bytes, to ds:dx
	  jc	@@CopyEnd
	  or	ax,ax			;EOF reached?
	  jz	@@CopyEnd		;ready!
	  mov	cx,ax
	  mov	bx,hFileDst		; (=0)
	  DOS	40h			;  write file cx=bytes, to ds:dx
	  jc	@@CopyEnd
	  cmp	cx,ax
	  je	@@FileCopy
@@CopyEnd:
	  mov	bx,currfhandle		; (=0)
	  DOS	3Eh			;  close file, bx=file handle
	  mov	bx,hFileDst
	  DOS	3Eh			;  close file, bx=file handle
	  lea	dx,ThePath
	  DOS	3D02h			;  open file, al=mode,name@ds:dx
	 pop	dx ds cx
	inc	sp
	inc	sp
	jmp	int21exi

try_mirror_then_cd:
	sti				; Enable interrupts
	call	manglepath
	jc	int21cont
	push	es bx ds dx cx ax
	 LD	ds,cs
	 lea	dx,ThePath
	 DOS				; try local
	 jnc	@@local_done
	pop	ax cx dx ds bx es
	DOS				; retry on CD
	jmp	int21exi
@@local_done:
	pop	dx dx dx ds bx es
	jmp	int21exi

exec_mirror_then_cd:
	sti				; Enable interrupts
	call	manglepath
	jc	int21cont		; no business on requested drive
	push	es bx ds dx cx ax
	 mov	cs:[UnlockForExec],1
	 LD	ds,cs
	 lea	dx,ThePath
	 DOS				; try local
	 jnc	@@exec_done
	 mov	cs:[UnlockForExec],1
	pop	ax cx dx ds bx es
	DOS				; retry CD
	jmp	int21exi
@@exec_done:
	pop	dx dx dx ds bx es
	jmp	int21exi

findfirst:
	mov	cs:FF_Flag,1
	mov	cs:FF_CodeAX,ax
	mov	cs:FF_AttrCX,cx
	pushf				; Push flags
	 push	es si di
	  cld				; Clear direction
	  mov	si,dx
	  lea	di,BufferForFF
	  LD	es,cs
@@CopyStr:lodsb
	  stosb
	  or	al,al			; Zero ?
	  jnz	@@CopyStr
	 pop	di si es
	popf				; Pop flags
	mov	ax,cs:FF_CodeAX		; (=0)
	call	manglepath
	mov	cs:FF_Flag,0
	mov	cs:[tbfill],offset transferbuf	;reset list
	jc	int21cont
	push	ds dx
	 LD	ds,cs
	 lea	dx,ThePath
	 DOS			;First scan through the cfg dir
	pop	dx ds
hoho:
	jc	OnFnError
	jmp	haha
OnFnError:
	pushf				; Push flags
	 cmp	cs:FF_Flag,0	;Is this the second occurence of CY?
	 je	@@FindInCdDir	;no, find direntries in CD dir
	popf			;yes, report error
	jmp	int21exi
@@FindInCdDir:
	popf				; Pop flags
	mov	cs:FF_Flag,1	;Inhibit recursion
	push	ds cx dx
	 LD	ds,cs
	 lea	dx,BufferForFF
	 mov	cx,cs:FF_AttrCX
	 mov	ax,cs:FF_CodeAX
	 DOS			;Make FindFirst for CD
	pop	dx cx ds
	jc	int21exi
haha:
	call	CheckDoublette
	jnc	int21exi	;okay if allowed to display
	push	ax		;preserve AX
	 DOS	4Fh
	 jc	@@huhu
	pop	ax		;restore AX
	jmp	haha
@@huhu:	inc	sp
	inc	sp
	jmp	OnFnError	;leave error code in AX
findnext:
	DOS
	jmp	hoho

CheckDoublette proc
;PA: CY=1 if filename match detected, OR directory in cfg dir
	pushf
	push	ax bx cx ds si es di
	DOS	2Fh		;get DTA in ES:BX
	LD	ds,es
	LD	es,cs
	lea	si,[bx+30]	;adress of ASCIIZ name portion
	cld
;now: DS:SI=filename, ES:transferbuf=buffer
	cmp	cs:[FF_Flag],0	;Cfg dir?
	jnz	@@CheckPresence
;check if directory other than '.' and '..'
	test	byte ptr [bx+21],10h	;test directory bit
	jz	@@copy			;okay, it's a file
	cmp	byte ptr [si],'.'	;test . or .. directory
	jne	@@excy			;nope, report error
;copy filename portion into buffer
@@copy:
	mov	di,es:[tbfill]
	mov	cx,6
	rep	movsw		;copy 12 bytes
	cmp	di,offset tbend-11
	jnc	@@OvlPrevent	;prevent buffer overrun
	mov	es:[tbfill],di	;new end address
@@OvlPrevent:
	jmp	@@exi
@@CheckPresence:
	lea	di,transferbuf
	mov	cx,12
	jmp	@@foot
@@rep:
	push	si di cx
@@l:	 lodsb			;AL:=DS:[SI]
	 scasb			;ES:[DI]-AL
	 jnz	@@nomatch
	 or	al,al
	 loopnz	@@l
	 jmp	@@match
@@nomatch:
	pop	cx di si
	add	di,cx
@@foot:
	cmp	di,es:[tbfill]
	jc	@@rep
@@exi:
	pop	di es si ds cx bx ax
	popf
	clc
	ret
@@match:
	add	sp,6
@@excy:
	pop	di es si ds cx bx ax
	popf
	stc
	ret
CheckDoublette endp
;--------------------------------------------------------------------------

manglepath	proc	near
;appends the basename of the path given in DS:DX to the mirror path
;returns CY=1 if the specified or current drive doesn't match
	push	si ax
	 pushf
	  cmp	cs:[DriveRestrict],0
	  jz	@@notest	;mangle always
	  mov	si,dx
	  cmp	byte ptr [si+1],':'
	  jnz	@@GetCurDrive
	  mov	al,[si]		;Laufwerksbuchstabe
	  call	upcase
	  sub	al,'@'
	  jmp	@@testdrv
@@GetCurDrive:
	  DOS	19h
	  inc	al
@@testdrv:
	  cmp	cs:[DriveRestrict],al
	  jnz	@@exi		;exiting with carry set
@@notest:
	  push	dx es di
	   LD	es,cs
	   cld
	   mov	si,dx
;scan for last ':/\' in string
@@mem:	   mov	dx,si		;memorize possible string begin
@@scn:	   lodsb
	   cmp	al,':'
	   je	@@mem
	   cmp	al,'/'
	   je	@@mem
	   cmp	al,'\'
	   je	@@mem
	   or	al,al
	   jnz	@@scn
	   mov	si,dx
	   mov	di,es:[EndOfPath]
@@cat:	   lodsb			;append filename
	   stosb
	   or	al,al
	   jnz	@@cat
	  pop	di es dx
	 popf
	 clc			;never fail here
	pop	ax si
	ret
@@exi:
	 popf
	 stc
	pop	ax si
	ret
manglepath	endp


upcase proc
	cmp	al,'a'
	jb	@@e
	cmp	al,'z'
	ja	@@e
	and	al,not 20h
@@e:	ret
upcase endp

;----------------------------------------------------------------------------
; very buggy stricmp(char *si, char *bx) (exits on ne or e)
; returns z=1 if strings equal or *si ends
; I:  si = pt

stricmp	proc	near
	push	ax
	 cld
@@l:	 segcs	lodsb
	 call	upcase
	 xchg	ah,al
	 mov	al,cs:[bx]
	 inc	bx
	 call	upcase
	 or	ax,ax		;both strings terminate?
	 jz	@@e
	 cmp	al,ah		;both chars are equal?
	 jz	@@l
@@e:
	pop	ax
	ret
stricmp	endp

ResEnd:

PreparePath proc
;I:  DS:SI - the desired new directory name (terminated roughly by white space)
;    ES:80h - internal storage area for canonicalised dirname (=command line)
;O:  CY=1: error, AL=DOS error code 2:File not found, 3:Path not found
;    255: Exists as file, 5: permission denied, 0: User abort
;C: CX
;
;Create dir if it doesn't exist (ask user).
;Performs recursive MKDIR if necessary (mkdir -p).
;
	lea	di,ThePath		;where the directory goes to (ES:DI)

	; make ASCIZ string
@@l:	lodsb				;seek for end of string
	stosb
	cmp	al,21h
	jnc	@@l
	dec	di			;onto terminating char
	xor	al,al
	stosb				;terminate string for TrueName
	
	; call truename() - varying behaviour for terminating backslashes!
	push	ds
	 LD	ds,es
	 lea	si,ThePath
	 mov	di,si
	 DOS	60h			;TRUENAME; in-place
	pop	ds
	jc	@@e			;FATAL

	; check if name exists as dir or file (use getattrib)
	push	ds
	 LD	ds,es
	 lea	dx,ThePath
	 DOS	4300h			;GetFAttr
	pop	ds
	jc	@@AskUser		;failed

	; is a directory? (stern)
	test	cl,10h
	stc
	mov	al,255
	jz	@@e			;fatal

@@AppendSlash:
	lea	di,ThePath
	xor	al,al
	mov	cx,0FFFFh		;unlimited search
	repne	scasb			;place DI _after_ the zero byte
	dec	di
	mov	al,es:[di-1]		;last char of string
	cmp	al,'\'			;check for trailing '/\:'
	jz	@@termok
	cmp	al,'/'			;should never occur
	jz	@@termok
	cmp	al,':'			;should never occur
	je	@@termok
	mov	al,'\'
	stosb				;append missing '\'
@@termok:
	mov	es:[EndOfPath],di	;memorize end of string
	clc
@@e:	ret

@@AskUser:
	lea	dx,Ask$			;output a newline
	DOS	9
@@loop:
	DOS	1			;GetChar
	and	al,not 20h		;upcase
	cmp	al,'Y'
	jz	@@permit
	cmp	al,'J'
	jz	@@permit
	cmp	al,'Z'
	jz	@@permit
	cmp	al,'N'			;return zero if aborting (!!)
	jnz	@@loop
	lea	dx,nl$
	DOS	9
	xor	al,al
	stc
	ret
@@permit:
	lea	dx,nl$
	DOS	9
	xor	cx,cx
@@retry:
	push	ds
	 LD	ds,es
	 lea	dx,ThePath
	 DOS	39h
	pop	ds
	jnc	@@fwd			;no error, creation OK
	cmp	al,3
	stc
	jnz	@@e			;error other than 3 - FATAL
	push	cx
	 lea	di,ThePath
	 xor	al,al
	 mov	cx,0FFFFh
	 cld
	 repnz	scasb
	 dec	di			;onto zero!
	 not	cx			;CX=strlen()+1
	 mov	al,'\'
	 std
	 repne	scasb			;strrchr(...,'\')
	 cld
	pop	cx
	stc
	mov	al,5			;evil error
	jne	@@e			;if backslash not found (wrt scasb)
	mov	byte ptr es:[di+1],0	;split string at '\'
	inc	cx			;count repeats
	jmp	@@Retry
@@fwd:	jcxz	@@AppendSlash
@@loo:	lea	di,ThePath
	push	cx
	 xor	al,al
	 mov	cx,0FFFFh
	 repnz	scasb
	 dec	di
	pop	cx
	mov	byte ptr es:[di],'\'
	push	ds
	 LD	ds,es
	 lea	dx,ThePath
	 DOS	39h
	pop	ds
	jc	@@e
	loop	@@loo
	jmp	@@AppendSlash
PreparePath endp

start_here proc
	lea	dx,Copyr$
	DOS	9			;  display char string at ds:dx
	DOS	30h			;  get DOS version number ax
	cmp	al,3
	jae	@@DosVer_OK
	mov	dx,offset EDosVer$
	DOS	9			;  display char string at ds:dx
	DOS	4CFEh			;  exit(-2)
@@DosVer_OK:
	DOS	3521h			;  get intrpt vector 21h in es:bx
	SES	OldInt21,bx
	push	ds
	pop	es
	mov	ch,0			;marker register
	mov	bx,MAGICCODE
	DOS	MAGICFUNC
	cmp	ax,MAGICANS
	jne	@@NotRes
	mov	es,bx			;move segment of resident copy to ES
	or	ch,80h			;mark: resident copy present
	cmp	word ptr OldInt21[0],offset NewInt21
	jne	@@NotRes
	cmp	word ptr OldInt21[2],bx
	jne	@@NotRes
	or	ch,40h			;mark: okay for uninstall
@@notres:
	cld				; Clear direction
	mov	si,81h			;Now parse command line
@@NextChar:
	lodsb				; String [si] to al
	cmp	al,' '
	je	@@NextChar		;skip whitespace
	cmp	al,9
	je	@@NextChar
	cmp	al,13
	je	@@CmdEnd
	cmp	al,'/'
	je	@@opt
	cmp	al,'-'
	je	@@opt
	dec	si			;Something else? - directory name!
	push	cx
	 call	PreparePath
	pop	cx
	jnc	@@CopyEnd
	sub	al,2
	lea	dx,EFile
	jz	PrintExit
	lea	dx,EPath
	dec	al			;3
	jz	PrintExit
	sub	al,5-3			;5
	lea	dx,EAccess
	jz	PrintExit
	sub	al,255-5
	lea	dx,EExistAsFile
	jz	PrintExit
	DOS	4CFFh			;user abort with setting errorlevel
@@opt:
	lodsb
	cmp	al,'?'
	je	@@Usage
	or	al,20h			;lowercase
	cmp	al,'h'
	je	@@Usage
	cmp	al,'u'
	je	DoUninst
	cmp	al,'d'
	je	@@SetDriveRestrict
@@SN_Err:
	lea	dx,ESyntax$
	jmp	PrintExit
@@Usage:
	lea	dx,Usage$
	jmp	PrintExit
@@SetDriveRestrict:
	lodsb
	cmp	al,'='
	jz	@@skipdelim
	cmp	al,':'
	jnz	@@nodelim
@@skipdelim:
	lodsb
@@nodelim:
	sub	al,'+'
	je	@@PokeAL		;poke zero to enable all drives
	add	al,'+'
	cmp	al,'-'			;have "-" as "no drive"
	je	@@PokeAL
	cmp	al,21h
	jc	@@UseCurr
	call	upcase
	sub	al,'A'
	cmp	al,26			;must be 0..25
	jnc	@@SN_Err
	jmp	@@UseDriveAL
@@UseCurr:
	dec	si
	DOS	19h
@@UseDriveAL:
	inc	al			;!!!
@@PokeAL:
	mov	es:[DriveRestrict],al
	lodsb
	cmp	al,':'
	jnz	@@NoSkipColon
	lodsb
@@NoSkipColon:
	cmp	al,21h
	jnc	@@SN_Err
	dec	si
	jmp	@@NextChar
@@CmdEnd:
	test	ch,80h			;Resident copy available?
	jz	@@SN_Err
	lea	dx,AlrRes$
	DOS	9
	mov	al,es:[DriveRestrict]
	lea	dx,All$
	or	al,al
	jz	@@printdrv
	lea	dx,None$
	cmp	al,26
	ja	@@printdrv
	add	al,'A'-1
	mov	dl,al
	mov	ah,2			;use fcn 2 instead of 9
@@printdrv:
	DOS
	lea	dx,AlrRes2$
	DOS	9
	push	ds
	 LD	ds,es
	 lea	dx,ThePath
	 mov	cx,[EndOfPath]
	 sub	cx,dx			;CX=string length
	 mov	bx,1			;stdout
	 DOS	40h
	pop	ds
	lea	dx,AlrRes3$
PrintExit:
	DOS	9			;  display char string at ds:dx
	lea	dx,nl$
	DOS
	DOS	4C00h			;  terminate with al=return code
DoUninst:
	test	ch,80h
	lea	dx,NoRes$
	jz	PrintExit
	test	ch,40h
	lea	dx,CantRemov$
	jz	PrintExit
	push	ds
	 lds	dx,es:[OldInt21]
	 DOS	2521h			;unhook Int21 chain
	pop	ds
	DOS	49h			;free resident copy
	lea	dx,UnInst$
	jmp     PrintExit
@@CopyEnd:
	test	ch,80h
	lea	dx,DirChange$
	jnz	PrintExit
	mov	enterlock,1		;enable ISR
	mov	UnlockForExec,0		;clear exec handling flag
	lea	dx,NewInt21
	DOS	2521h			;  set intrpt vector al to ds:dx
	lea	dx,Install$
	DOS	9			;  display char string at ds:dx
	mov	es,EnvSeg
	DOS	49h			;  release memory block, es=seg
	mov	bx,4			;stdaux
@@cl:	DOS	3eh			;close file handle
	sub	bx,1			;all other stdXXX
	jnc	@@cl
	mov	dx,((offset ResEnd-offset ComBase)+15) shr 4
	DOS	3100h			;  terminate & stay resident
start_here endp

nl$		db	nl,'$'
Copyr$		db	'SaveCD V2.3 (h#s,dino,08/97): $'
AlrRes$		db	'bereits resident, wirksam auf Laufwerk $'
AlrRes2$	db	',',nl,'Spiegelverzeichnis="$'
AlrRes3$	db	'"$'
None$		db	'[kein]$'
All$		db	'[alle]$'
DirChange$	db	'Verzeichnis aktualisiert.$'
UnInst$		db	'erfolgreich entfernt.$'
NoRes$		db	'ist nicht resident!$'
CantRemov$	db	'kann nicht deinstalliert werden!$'
Install$	db	'resident installiert.',nl,'$'
EDosVer$	db	'benötigt mindestens DOS 3.0!$'
ESyntax$	db	'Optionen: [/d[:Laufwerk]] [/u] [Verzeichnis]$'
Usage$		db	'Optionen: [/d[:Laufwerk]] [/u] [Verzeichnis]',nl
		db	'Blended Inhalt von "Verzeichnis" auf "Laufwerk" ein. '
		db	'Laufwerk ist: Buchstabe/"+" für alle (default)/"-" für keines.'
		db	'Ermöglicht das Speichern von Spielständen.$'
Ask$		db	'Verzeichnis existiert nicht - Anlegen [J/N]? $'
EPath		db	'Pfad nicht gefunden!$'
EFile		db	'Datei nicht gefunden!$'
EAccess		db	'Zugriff verweigert!$'
EExistAsFile	db	'angegebener Verzeichnisname existiert als Datei!$'


	END	start
Detected encoding: OEM (CP437)1
Wrong umlauts? - Assume file is ANSI (CP1252) encoded