OPT OSVERSION=37

MODULE 'dos/dos'

ENUM ERR_NONE,ERR_READARGS,ERR_OPENREAD,ERR_EXAMINEFH,ERR_READ,ERR_READSHORT,
ERR_OPENWRITE,ERR_WRITE,ERR_WRITESHORT

PROC main() HANDLE
	DEF ver,args[4]:ARRAY OF LONG,rdargs=NIL,code,code2,
	fhread=0,fib=0:PTR TO fileinfoblock,infilesize,buffer:PTR TO CHAR,read,
	buffer2:PTR TO CHAR,outfilesize,changes,fhwrite=0,written

	ver:='$VER: nocode 1.0 (7.1.99)'
	args:=[NIL,NIL,NIL,NIL]
	buffer:=NIL
	buffer2:=NIL

	IF (rdargs:=ReadArgs('INFILE/A,OUTFILE,CODE/N/A,REPLACECODE/N',args,NIL))=NIL THEN Raise(ERR_READARGS)
	PrintF('\s\n',ver+6)
	PrintF('--\n')
	IF args[1]=NIL THEN args[1]:=args[0]
	code:=args[2]
	code:=^code
	IF (code2:=args[3]) THEN code2:=^code2
	IF (fhread:=Open(args[0],MODE_OLDFILE))=0 THEN Raise(ERR_OPENREAD)
	NEW fib
	IF (ExamineFH(fhread,fib))=FALSE THEN Raise(ERR_EXAMINEFH)
	infilesize:=fib.size
	END fib
	fib:=0
	NEW buffer[infilesize]
	PrintF('Reading "\s"... ',args[0])
	IF (read:=Read(fhread,buffer,infilesize))=-1 THEN Raise(ERR_READ)
	IF (read<>infilesize) THEN Raise(ERR_READSHORT)
	PrintF('read \d bytes.\n',read)
	Close(fhread)
	fhread:=0
	NEW buffer2[infilesize]
	IF args[3]
		outfilesize:=infilesize
		changes:=replacecode(buffer,buffer2,infilesize,code,code2)
	ELSE
		outfilesize:=removecode(buffer,buffer2,infilesize,code)
	ENDIF
	END buffer
	buffer:=NIL
	IF (fhwrite:=Open(args[1],MODE_NEWFILE))=0 THEN Raise(ERR_OPENWRITE)
	IF args[1]=args[0]
		PrintF('Overwriting "\s"... ',args[1])
	ELSE
		PrintF('Writing "\s"... ',args[1])
	ENDIF
	IF (written:=Write(fhwrite,buffer2,outfilesize))=-1 THEN Raise(ERR_WRITE)
	IF (written<>outfilesize) THEN Raise(ERR_WRITESHORT)
	PrintF('wrote \d bytes.\n\n',written)
EXCEPT DO
	IF fhwrite THEN Close(fhwrite)
	IF buffer2 THEN END buffer2
	IF buffer THEN END buffer
	IF fib THEN END fib
	IF fhread THEN Close(fhread)
	IF rdargs THEN FreeArgs(rdargs)
	SELECT exception
		CASE ERR_READARGS
			PrintF('nocode - Bad commandline arguments (ReadArgs).\n')
		CASE ERR_OPENREAD
			PrintF('Cannot open "\s" for reading (Open).\n',args[0])
		CASE ERR_EXAMINEFH
			PrintF('Cannot examine filehandle (ExamineFH).\n')
		CASE ERR_READ
			PrintF('Cannot read "\s" (Read).\n',args[0])
		CASE ERR_READSHORT
			PrintF('Cannot read "\s" - read data short (Read).\n',args[0])
		CASE ERR_OPENWRITE
			PrintF('Cannot open "\s" for writing (Open).\n',args[1])
		CASE ERR_WRITE
			PrintF('Cannot write "\s" (Write).\n',args[1])
		CASE ERR_WRITESHORT
			PrintF('Cannot write "\s" - written data short (Write).\n',args[1])
		CASE "MEM"
			PrintF('Cannot allocate enough (approx. \d bytes) memory (NEW).\n',Shl(infilesize,1))
	ENDSELECT
ENDPROC

PROC removecode(buffer,buffer2,bufferlen,code)
DEF outfilesize

	PrintF('Removing code \d... ',code)
	MOVE.L buffer,A0 -> buffer 1
	MOVE.L buffer2,A1 -> buffer 2
	MOVE.L A1,A2 -> buffer 2 (to calculate length of stripped file later)
	MOVE.L code,D0 -> cache code in D0
	MOVE.L bufferlen,D1 -> buffer length
	SUBQ.L #1,D1 -> decrement for dbcc
	ADD.L #$10000,D1 -> increment upper word (outerloop must jump to innerloop at least once)
	BRA.S startouterloop
outerloop:
	SWAP D1 -> fetch lower word of counter
innerloop:
	MOVE.B (A0)+,D2 -> next char
	CMP.B D0,D2 -> compare with code
	BEQ.S remove -> = then remove it
	MOVE.B D2,(A1)+ -> <> then copy it into buffer2
remove:
	DBF D1,innerloop
startouterloop:
	SWAP D1 -> fetch upper word of counter
	DBF D1,outerloop
	SUB.L A2,A1 -> subtract original buffer2 address from buffer2
	MOVE.L A1,outfilesize
	PrintF('done (\d characters removed).\n',bufferlen-outfilesize)
ENDPROC outfilesize

PROC replacecode(buffer,buffer2,bufferlen,code,code2)
DEF changes

	PrintF('Replacing code \d with code \d... ',code,code2)
	MOVE.L buffer,A0 -> buffer 1
	MOVE.L buffer2,A1 -> buffer 2
	MOVE.L code,D0 -> cache code in D0
	MOVE.L code2,D3 -> cache code2 in D0
	MOVE.L bufferlen,D1 -> buffer length
	SUBQ.L #1,D1 -> decrement for dbcc
	ADD.L #$10000,D1 -> increment upper word (outerloop must jump to innerloop at least once)
	MOVEQ #0,D4
	BRA.S startouterloop2
outerloop2:
	SWAP D1 -> fetch lower word of counter
innerloop2:
	MOVE.B (A0)+,D2 -> next char
	CMP.B D0,D2 -> compare with code
	BNE.S dontreplace -> <> then leave it unchanged
	MOVE.B D3,D2
	ADDQ.L #1,D4
dontreplace:
	MOVE.B D2,(A1)+ -> copy (possibly replaced) char into buffer2
	DBF D1,innerloop2
startouterloop2:
	SWAP D1 -> fetch upper word of counter
	DBF D1,outerloop2
	MOVE.L D4,changes
	PrintF('done (\d characters replaced).\n',changes)
ENDPROC changes
